From e43dd6f60c6fd862060cb08ed19197c6b7a25800 Mon Sep 17 00:00:00 2001 From: h-fournier Date: Tue, 19 Mar 2024 11:26:00 +0100 Subject: [PATCH 01/41] Add reserves as NewReserve type as Reserve type already existed --- src/libs/antares/study/area/list.cpp | 79 ++++++++++++++- .../study/include/antares/study/area/area.h | 4 + .../include/antares/study/area/newReserves.h | 96 +++++++++++++++++++ .../antares/study/parts/common/cluster_list.h | 18 ++++ .../study/parts/common/cluster_list.cpp | 64 +++++++++++++ 5 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 src/libs/antares/study/include/antares/study/area/newReserves.h diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index 57b2a2dcb2..d656c1cce0 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -31,6 +31,7 @@ #include "antares/study/parts/parts.h" #include "antares/study/parts/load/prepro.h" #include +#include #define SEP IO::Separator @@ -778,6 +779,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, area.spreadSpilledEnergyCost = 0.; bool ret = true; + IniFile ini; // DSM, Reserves, D-1 buffer.clear() << study.folderInput << SEP << "reserves" << SEP << area.id << ".txt"; @@ -842,6 +844,74 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, } } + // Reserves + { + buffer.clear() << study.folderInput << SEP << "reserves" << SEP << area.id << SEP + << "reserves.ini"; + if (!ini.open(buffer)) + return false; + ini.each( + [&](const IniFile::Section& section) + { + AreaReserve tmpReserve; + int type = -1; + for (auto* p = section.firstProperty; p; p = p->next) + { + CString<30, false> tmp; + tmp = p->key; + tmp.toLower(); + + if (tmp == "name") + { + // Check that this reserve does not already exist + if (area.newReserves.contains(p->value)) + { + logs.warning() + << area.name << ": reserve name already exists for reserve " + << section.name; + continue; + } + else + { + tmpReserve.name = p->value; + } + } + else if (tmp == "failure-cost") + { + if (!p->value.to(tmpReserve.failureCost)) + { + logs.warning() + << area.name << ": invalid failure cost for reserve " << section.name; + } + } + else if (tmp == "spillage-cost") + { + if (!p->value.to(tmpReserve.spillageCost)) + { + logs.warning() + << area.name << ": invalid spillage cost for reserve " << section.name; + } + } + else if (tmp == "type") + { + if (p->value == "up") + type = 0; + else if (p->value == "down") + type = 1; + else + logs.warning() + << area.name << ": invalid type for reserve " << section.name; + } + } + if (type == 0) + area.newReserves.areaReservesUp[tmpReserve.name] = tmpReserve; + else if (type == 1) + area.newReserves.areaReservesDown[tmpReserve.name] = tmpReserve; + else + logs.warning() << area.name << ": invalid type for reserve " << section.name; + }); + } + // Solar { if (area.solar.prepro) // Prepro @@ -937,6 +1007,10 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, // In adequacy mode, all thermal clusters must be in 'mustrun' mode if (study.usedByTheSolver && study.parameters.mode == SimulationMode::Adequacy) area.thermal.list.enableMustrunForEveryone(); + + buffer.clear() << study.folderInput << SEP << "thermal" << SEP << "clusters" << SEP + << area.id << SEP << "reserves.ini"; + ret = area.thermal.list.loadReserveParticipations(area, buffer) && ret; } // Short term storage @@ -954,6 +1028,10 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, { buffer.clear() << study.folderInput << SEP << "renewables" << SEP << "series"; ret = area.renewable.list.loadDataSeriesFromFolder(study, buffer) && ret; + + buffer.clear() << study.folderInput << SEP << "renewables" << SEP << "clusters" << SEP + << area.id << SEP << "reserves.ini"; + ret = area.renewable.list.loadReserveParticipations(area, buffer) && ret; } // Adequacy patch @@ -962,7 +1040,6 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, // Nodal Optimization buffer.clear() << study.folderInput << SEP << "areas" << SEP << area.id << SEP << "optimization.ini"; - IniFile ini; if (!ini.open(buffer)) return false; diff --git a/src/libs/antares/study/include/antares/study/area/area.h b/src/libs/antares/study/include/antares/study/area/area.h index b6baf3f4d3..96314e820e 100644 --- a/src/libs/antares/study/include/antares/study/area/area.h +++ b/src/libs/antares/study/include/antares/study/area/area.h @@ -34,6 +34,7 @@ #include "ui.h" #include "constants.h" #include "antares/study/filter.h" +#include namespace Antares { @@ -293,6 +294,9 @@ class Area final : private Yuni::NonCopyable double spreadSpilledEnergyCost = 0.; //@} + /// \name NewRerserves structure to keep track of the added reserves + NewReserves newReserves; + //! \name Output filtering //@{ //! Print results for the area in the simulation synthesis diff --git a/src/libs/antares/study/include/antares/study/area/newReserves.h b/src/libs/antares/study/include/antares/study/area/newReserves.h new file mode 100644 index 0000000000..81131d53a7 --- /dev/null +++ b/src/libs/antares/study/include/antares/study/area/newReserves.h @@ -0,0 +1,96 @@ +/* +** 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 . +*/ +#ifndef __ANTARES_LIBS_STUDY_NEW_RESERVES_H__ +#define __ANTARES_LIBS_STUDY_NEW_RESERVES_H__ + +#include +#include +#include +#include +#include + +/// @brief Represents an area reserve using it's name, it's failure cost and it's spillage cost +struct AreaReserve +{ + std::string name; + float failureCost = 0; + float spillageCost = 0; +}; + +/// @brief Stores all the Reserves in two vectors for the up and down reserves +struct NewReserves +{ + std::map areaReservesUp; + std::map areaReservesDown; + + /// @brief Check if the reserve name already exist in both the up and down reserves + /// @param name + /// @return true if the reserve already existed + bool contains(std::string name) + { + return areaReservesUp.contains(name) || areaReservesDown.contains(name); + } + + /// @brief Get a reserve from both the up and down reserves using its name + /// @param name + /// @return an optional of the reserve reference if the reserve was found, and a nullopt + /// otherwise + std::optional> getReserveFromName(std::string name) + { + if (areaReservesUp.contains(name)) + { + return areaReservesUp.at(name); + } + else if (areaReservesDown.contains(name)) + { + return areaReservesDown.at(name); + } + return std::nullopt; + } +}; + +/// @brief Represents the cluster reserve participation to a given reserve +struct ClusterReserveParticipation +{ + AreaReserve& clusterReserve; + float maxPower = 0; + float participationCost = 0; + + ClusterReserveParticipation(AreaReserve& reserve, float power, float cost) : + clusterReserve(reserve), maxPower(power), participationCost(cost) + { + } + + ClusterReserveParticipation& operator=(const ClusterReserveParticipation& other) + { + // Check for self-assignment + if (this != &other) + { + // Copy the values from the other object + clusterReserve = other.clusterReserve; + maxPower = other.maxPower; + participationCost = other.participationCost; + } + return *this; + } +}; + +#endif // __ANTARES_LIBS_STUDY_LINKS_H__ \ No newline at end of file diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h index 40a083be83..75e97b1e4c 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h @@ -25,6 +25,7 @@ #include "../../fwd.h" #include +#include #include #include @@ -127,6 +128,14 @@ class ClusterList bool loadDataSeriesFromFolder(Study& study, const AnyString& folder); + /// @brief Load the reserve participation. For each entry, it checks if the reserve has been + /// added to area.newReserves, if not then log the name of the reserve that has not been found. + /// @tparam ClusterT Type of the Cluster list + /// @param area Reference to area + /// @param file File to read the reserve participations entries + /// @return false if the file opening failed, true otherwise + bool loadReserveParticipations(Area& area, const AnyString& folder); + bool saveDataSeriesToFolder(const AnyString& folder) const; virtual bool saveToFolder(const AnyString& folder) const = 0; @@ -149,6 +158,12 @@ class ClusterList void addToCompleteList(std::shared_ptr cluster); void sortCompleteList(); + /// @brief Add the reserve participation to the current clusterReservesParticipations map + /// @param name the name of the reserve to add + /// @param reserveParticipation the reserve participation to add + void addReserveParticipation(std::string name, + ClusterReserveParticipation reserveParticipation); + protected: std::vector> allClusters_; @@ -159,6 +174,9 @@ class ClusterList private: bool alreadyInAllClusters(std::string clusterName); + /// @brief Stores the reserves Participations for each reserve, the key is the name of the + /// reserve + std::map clusterReservesParticipations; }; // class ClusterList } // namespace Data diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index 818fa9a85f..eacad58c91 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -130,6 +130,14 @@ void ClusterList::sortCompleteList() std::ranges::sort(allClusters_, [](const auto a, const auto b) { return a->id() < b->id(); }); } +template +void ClusterList::addReserveParticipation( + std::string name, + ClusterReserveParticipation reserveParticipation) +{ + clusterReservesParticipations.emplace(name, reserveParticipation); +} + template unsigned int ClusterList::enabledCount() const { @@ -256,6 +264,62 @@ bool ClusterList::loadDataSeriesFromFolder(Study& s, [&](auto c) { return c->loadDataSeriesFromFolder(s, folder); }); } +template +bool ClusterList::loadReserveParticipations(Area& area, const AnyString& file) +{ + IniFile ini; + if (!ini.open(file)) + return false; + ini.each( + [&](const IniFile::Section& section) + { + std::string tmpName; + float tmpMaxPower = 0; + float tmpParticipationCost = 0; + for (auto* p = section.firstProperty; p; p = p->next) + { + CString<30, false> tmp; + tmp = p->key; + tmp.toLower(); + + if (tmp == "name") + { + tmpName = p->value; + } + else if (tmp == "max-power") + { + if (!p->value.to(tmpMaxPower)) + { + logs.warning() + << area.name << ": invalid max power for reserve " << section.name; + } + } + else if (tmp == "participation-cost") + { + if (!p->value.to(tmpParticipationCost)) + { + logs.warning() + << area.name << ": invalid participation cost for reserve " << section.name; + } + } + } + if (area.newReserves.getReserveFromName(tmpName).has_value()) + { + ClusterReserveParticipation tmpReserveParticipation{ + area.newReserves.getReserveFromName(tmpName).value().get(), + tmpMaxPower, + tmpParticipationCost}; + + area.thermal.list.addReserveParticipation(tmpName, tmpReserveParticipation); + } + else + { + logs.warning() << area.name << ": does not contains this reserve " << section.name; + } + }); + return true; +} + template void ClusterList::retrieveTotalCapacityAndUnitCount(double& total, uint& unitCount) const { From 1272341483a157e9cc476b9bad0a8f6f3d0de6bd Mon Sep 17 00:00:00 2001 From: h-fournier Date: Fri, 22 Mar 2024 09:34:57 +0100 Subject: [PATCH 02/41] A clusterReserveParticipation is now associated to a cluster and not a list of clusters. Save is not yet supported, only load. --- src/libs/antares/study/area/list.cpp | 89 ++++++++----------- .../include/antares/study/area/newReserves.h | 3 +- .../antares/study/parts/common/cluster.h | 11 +++ .../antares/study/parts/common/cluster_list.h | 14 ++- .../antares/study/parts/common/cluster.cpp | 8 ++ .../study/parts/common/cluster_list.cpp | 37 ++++---- 6 files changed, 86 insertions(+), 76 deletions(-) diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index 7ea8b4218d..10911ab324 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -853,62 +853,55 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, ini.each( [&](const IniFile::Section& section) { - AreaReserve tmpReserve; - int type = -1; - for (auto* p = section.firstProperty; p; p = p->next) + if (area.newReserves.contains(section.name)) { - CString<30, false> tmp; - tmp = p->key; - tmp.toLower(); - - if (tmp == "name") + logs.warning() << area.name << ": reserve name already exists for reserve " + << section.name; + } + else + { + AreaReserve tmpReserve; + int type = -1; + for (auto* p = section.firstProperty; p; p = p->next) { - // Check that this reserve does not already exist - if (area.newReserves.contains(p->value)) - { - logs.warning() - << area.name << ": reserve name already exists for reserve " - << section.name; - continue; - } - else + CString<30, false> tmp; + tmp = p->key; + tmp.toLower(); + + if (tmp == "failure-cost") { - tmpReserve.name = p->value; + if (!p->value.to(tmpReserve.failureCost)) + { + logs.warning() << area.name << ": invalid failure cost for reserve " + << section.name; + } } - } - else if (tmp == "failure-cost") - { - if (!p->value.to(tmpReserve.failureCost)) + else if (tmp == "spillage-cost") { - logs.warning() - << area.name << ": invalid failure cost for reserve " << section.name; + if (!p->value.to(tmpReserve.spillageCost)) + { + logs.warning() << area.name << ": invalid spillage cost for reserve " + << section.name; + } } - } - else if (tmp == "spillage-cost") - { - if (!p->value.to(tmpReserve.spillageCost)) + else if (tmp == "type") { - logs.warning() - << area.name << ": invalid spillage cost for reserve " << section.name; + if (p->value == "up") + type = 0; + else if (p->value == "down") + type = 1; + else + logs.warning() + << area.name << ": invalid type for reserve " << section.name; } } - else if (tmp == "type") - { - if (p->value == "up") - type = 0; - else if (p->value == "down") - type = 1; - else - logs.warning() - << area.name << ": invalid type for reserve " << section.name; - } + if (type == 0) + area.newReserves.areaReservesUp.emplace(section.name, tmpReserve); + else if (type == 1) + area.newReserves.areaReservesDown.emplace(section.name, tmpReserve); + else + logs.warning() << area.name << ": invalid type for reserve " << section.name; } - if (type == 0) - area.newReserves.areaReservesUp[tmpReserve.name] = tmpReserve; - else if (type == 1) - area.newReserves.areaReservesDown[tmpReserve.name] = tmpReserve; - else - logs.warning() << area.name << ": invalid type for reserve " << section.name; }); } @@ -1028,10 +1021,6 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, { buffer.clear() << study.folderInput << SEP << "renewables" << SEP << "series"; ret = area.renewable.list.loadDataSeriesFromFolder(study, buffer) && ret; - - buffer.clear() << study.folderInput << SEP << "renewables" << SEP << "clusters" << SEP - << area.id << SEP << "reserves.ini"; - ret = area.renewable.list.loadReserveParticipations(area, buffer) && ret; } // Adequacy patch diff --git a/src/libs/antares/study/include/antares/study/area/newReserves.h b/src/libs/antares/study/include/antares/study/area/newReserves.h index 81131d53a7..937d263fae 100644 --- a/src/libs/antares/study/include/antares/study/area/newReserves.h +++ b/src/libs/antares/study/include/antares/study/area/newReserves.h @@ -30,7 +30,6 @@ /// @brief Represents an area reserve using it's name, it's failure cost and it's spillage cost struct AreaReserve { - std::string name; float failureCost = 0; float spillageCost = 0; }; @@ -53,7 +52,7 @@ struct NewReserves /// @param name /// @return an optional of the reserve reference if the reserve was found, and a nullopt /// otherwise - std::optional> getReserveFromName(std::string name) + std::optional> getReserveByName(Yuni::ShortString256 name) { if (areaReservesUp.contains(name)) { diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster.h b/src/libs/antares/study/include/antares/study/parts/common/cluster.h index 1752a44706..3eccfd2629 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster.h @@ -26,6 +26,7 @@ #include #include #include "../../fwd.h" +#include #include #include @@ -104,6 +105,12 @@ class Cluster bool saveDataSeriesToFolder(const AnyString& folder) const; bool loadDataSeriesFromFolder(Study& s, const AnyString& folder); + /// @brief Add the reserve participation to the current clusterReservesParticipations map + /// @param name the name of the reserve to add + /// @param reserveParticipation the reserve participation to add + void addReserveParticipation(std::string name, + ClusterReserveParticipation reserveParticipation); + uint unitCount = 0; bool isEnabled() const { return enabled; } @@ -140,6 +147,10 @@ class Cluster private: virtual unsigned int precision() const = 0; + /// @brief Stores the reserves Participations for each reserve, the key is the name of the + /// reserve + std::map clusterReservesParticipations; + }; } // namespace Data } // namespace Antares diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h index 75e97b1e4c..27bf0a247c 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -157,12 +158,10 @@ class ClusterList unsigned int allClustersCount() const; void addToCompleteList(std::shared_ptr cluster); void sortCompleteList(); - - /// @brief Add the reserve participation to the current clusterReservesParticipations map - /// @param name the name of the reserve to add - /// @param reserveParticipation the reserve participation to add - void addReserveParticipation(std::string name, - ClusterReserveParticipation reserveParticipation); + /// @brief Get the cluster from the vector allClusters_ using it's name + /// @param clusterName + /// @return nullopt if no clusters found else a pointer to the cluster + std::optional> getClusterByName(std::string clusterName); protected: std::vector> allClusters_; @@ -174,9 +173,6 @@ class ClusterList private: bool alreadyInAllClusters(std::string clusterName); - /// @brief Stores the reserves Participations for each reserve, the key is the name of the - /// reserve - std::map clusterReservesParticipations; }; // class ClusterList } // namespace Data diff --git a/src/libs/antares/study/parts/common/cluster.cpp b/src/libs/antares/study/parts/common/cluster.cpp index ed73548706..f6388590a9 100644 --- a/src/libs/antares/study/parts/common/cluster.cpp +++ b/src/libs/antares/study/parts/common/cluster.cpp @@ -99,6 +99,14 @@ bool Cluster::loadDataSeriesFromFolder(Study& s, const AnyString& folder) } #undef SEP + +void Cluster::addReserveParticipation( + std::string name, + ClusterReserveParticipation reserveParticipation) +{ + clusterReservesParticipations.emplace(name, reserveParticipation); +} + void Cluster::invalidateArea() { if (parentArea) diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index eacad58c91..31ff4ef091 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -108,6 +108,18 @@ void ClusterList::storeTimeseriesNumbers(Solver::IResultWriter& writer } } +template +std::optional> ClusterList::getClusterByName( + std::string clusterName) +{ + auto it = std::find_if(allClusters_.begin(), + allClusters_.end(), + [&](const auto& cluster) { return cluster->id() == clusterName; }); + + return (it != allClusters_.end()) ? std::optional>(*it) + : std::nullopt; +} + template bool ClusterList::alreadyInAllClusters(std::string clusterId) { @@ -130,14 +142,6 @@ void ClusterList::sortCompleteList() std::ranges::sort(allClusters_, [](const auto a, const auto b) { return a->id() < b->id(); }); } -template -void ClusterList::addReserveParticipation( - std::string name, - ClusterReserveParticipation reserveParticipation) -{ - clusterReservesParticipations.emplace(name, reserveParticipation); -} - template unsigned int ClusterList::enabledCount() const { @@ -273,7 +277,7 @@ bool ClusterList::loadReserveParticipations(Area& area, const AnyStrin ini.each( [&](const IniFile::Section& section) { - std::string tmpName; + std::string tmpClusterName; float tmpMaxPower = 0; float tmpParticipationCost = 0; for (auto* p = section.firstProperty; p; p = p->next) @@ -282,9 +286,9 @@ bool ClusterList::loadReserveParticipations(Area& area, const AnyStrin tmp = p->key; tmp.toLower(); - if (tmp == "name") + if (tmp == "cluster-name") { - tmpName = p->value; + tmpClusterName = p->value; } else if (tmp == "max-power") { @@ -303,14 +307,17 @@ bool ClusterList::loadReserveParticipations(Area& area, const AnyStrin } } } - if (area.newReserves.getReserveFromName(tmpName).has_value()) + if (area.newReserves.getReserveByName(section.name).has_value() + && area.thermal.list.getClusterByName(tmpClusterName).has_value()) { ClusterReserveParticipation tmpReserveParticipation{ - area.newReserves.getReserveFromName(tmpName).value().get(), + area.newReserves.getReserveByName(section.name).value().get(), tmpMaxPower, tmpParticipationCost}; - - area.thermal.list.addReserveParticipation(tmpName, tmpReserveParticipation); + area.thermal.list.getClusterByName(tmpClusterName) + .value() + .get() + ->addReserveParticipation(section.name, tmpReserveParticipation); } else { From 8909410baa79a105818569c6db5f6fc6aac24096 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Mon, 25 Mar 2024 15:22:29 +0100 Subject: [PATCH 03/41] Added the loading of reserve chronicles as time series --- src/libs/antares/study/area/area.cpp | 10 ++++++++++ src/libs/antares/study/area/list.cpp | 14 ++++++++++++-- .../study/include/antares/study/area/newReserves.h | 13 +++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/libs/antares/study/area/area.cpp b/src/libs/antares/study/area/area.cpp index 038d120f60..0aaa8cdd2b 100644 --- a/src/libs/antares/study/area/area.cpp +++ b/src/libs/antares/study/area/area.cpp @@ -70,6 +70,16 @@ Area::~Area() { logs.debug() << " :: destroying area " << name; + // freeing memory from reserves + for (auto const& [key, val] : newReserves.areaReservesUp) + { + delete val.need; + } + for (auto const& [key, val] : newReserves.areaReservesDown) + { + delete val.need; + } + // Delete all links clearAllLinks(); diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index 10911ab324..fa0cc6a8de 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -861,6 +861,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, else { AreaReserve tmpReserve; + std::string file_name = NewReserves::toFilename(section.name); int type = -1; for (auto* p = section.firstProperty; p; p = p->next) { @@ -895,12 +896,21 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, << area.name << ": invalid type for reserve " << section.name; } } + buffer.clear() << study.folderInput << SEP << "reserves" << SEP << area.id << SEP + << file_name << ".txt"; + TimeSeries::numbers tsnum; + Antares::Data::TimeSeries* tmp_need = new TimeSeries(tsnum); + ret = (*tmp_need).loadFromFile(buffer, false) && ret; + tmpReserve.need = tmp_need; if (type == 0) - area.newReserves.areaReservesUp.emplace(section.name, tmpReserve); + area.newReserves.areaReservesUp[section.name] = tmpReserve; else if (type == 1) - area.newReserves.areaReservesDown.emplace(section.name, tmpReserve); + area.newReserves.areaReservesDown[section.name] = tmpReserve; else + { logs.warning() << area.name << ": invalid type for reserve " << section.name; + delete tmp_need; + } } }); } diff --git a/src/libs/antares/study/include/antares/study/area/newReserves.h b/src/libs/antares/study/include/antares/study/area/newReserves.h index 937d263fae..4d65882fcb 100644 --- a/src/libs/antares/study/include/antares/study/area/newReserves.h +++ b/src/libs/antares/study/include/antares/study/area/newReserves.h @@ -26,12 +26,14 @@ #include #include #include +#include /// @brief Represents an area reserve using it's name, it's failure cost and it's spillage cost struct AreaReserve { float failureCost = 0; float spillageCost = 0; + Data::TimeSeries* need; }; /// @brief Stores all the Reserves in two vectors for the up and down reserves @@ -64,6 +66,17 @@ struct NewReserves } return std::nullopt; } + + /// @brief Returns lower case, no space string + /// @param name + /// @return A string usable for file naming + static std::string toFilename(std::string name) + { + std::string file_name = name; + std::replace(file_name.begin(), file_name.end(), ' ', '_'); + std::transform(file_name.begin(), file_name.end(), file_name.begin(), ::tolower); + return file_name; + } }; /// @brief Represents the cluster reserve participation to a given reserve From f455f4de763408c53b46e76dcc30071cf2139b47 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Thu, 28 Mar 2024 12:29:51 +0100 Subject: [PATCH 04/41] Loading reserves into the problem hebdo Added getting data from cluster reserves with key reserves name --- src/libs/antares/study/area/list.cpp | 7 ++- .../antares/study/parts/common/cluster.h | 17 ++++++ .../antares/study/parts/common/cluster.cpp | 24 ++++++++ .../sim_structure_probleme_economique.h | 32 +++++++++++ .../simulation/sim_calcul_economique.cpp | 56 +++++++++++++++++++ 5 files changed, 134 insertions(+), 2 deletions(-) diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index fa0cc6a8de..c7fbe0b86f 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -895,6 +895,9 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, logs.warning() << area.name << ": invalid type for reserve " << section.name; } + else + logs.warning() + << area.name << ": invalid key " << tmp << " in file " << buffer; } buffer.clear() << study.folderInput << SEP << "reserves" << SEP << area.id << SEP << file_name << ".txt"; @@ -903,9 +906,9 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, ret = (*tmp_need).loadFromFile(buffer, false) && ret; tmpReserve.need = tmp_need; if (type == 0) - area.newReserves.areaReservesUp[section.name] = tmpReserve; + area.newReserves.areaReservesUp.emplace(section.name, tmpReserve); else if (type == 1) - area.newReserves.areaReservesDown[section.name] = tmpReserve; + area.newReserves.areaReservesDown.emplace(section.name, tmpReserve); else { logs.warning() << area.name << ": invalid type for reserve " << section.name; diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster.h b/src/libs/antares/study/include/antares/study/parts/common/cluster.h index 3eccfd2629..b586cfb395 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster.h @@ -140,6 +140,23 @@ class Cluster */ Matrix<> modulation; + /*! + ** \brief Returns true if cluster participates in a reserve with this name + */ + bool isParticipatingInReserve(std::string name); + + /*! + ** \brief Returns max power for a reserve if participating, -1 otherwise + */ + float reserveMaxPower(std::string name); + + /*! + ** \brief Returns participating cost for a reserve if participating, -1 otherwise + */ + float reserveCost(std::string name); + + + protected: Data::ClusterName pName; Data::ClusterName pID; diff --git a/src/libs/antares/study/parts/common/cluster.cpp b/src/libs/antares/study/parts/common/cluster.cpp index f6388590a9..992aa607ac 100644 --- a/src/libs/antares/study/parts/common/cluster.cpp +++ b/src/libs/antares/study/parts/common/cluster.cpp @@ -107,6 +107,30 @@ void Cluster::addReserveParticipation( clusterReservesParticipations.emplace(name, reserveParticipation); } +bool Cluster::isParticipatingInReserve(std::string name) +{ + if (clusterReservesParticipations.contains(name)) + return true; + else + return false; +} + +float Cluster::reserveMaxPower(std::string name) +{ + if (clusterReservesParticipations.contains(name)) + return clusterReservesParticipations.at(name).maxPower; + else + return -1; +} + +float Cluster::reserveCost(std::string name) +{ + if (clusterReservesParticipations.contains(name)) + return clusterReservesParticipations.at(name).participationCost; + else + return -1; +} + void Cluster::invalidateArea() { if (parentArea) diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index 11ace389d9..a511a8e11c 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -257,6 +257,35 @@ struct PDISP_ET_COUTS_HORAIRES_PAR_PALIER }; +struct RESERVE_PARTICIPATION +{ + float maxPower=-1; + float participationCost=-1; +}; + +struct AREA_RESERVE +{ + std::vector AllReservesParticipation; // Vector size is number of thermal clusters in this area + std::vector need; // Vector size is number of hours in year + float failureCost = 0; + float spillageCost = 0; +}; + + +//Vector size is number of reserves up or down +struct AREA_RESERVES_VECTOR +{ + std::vector areaReservesUp; + std::vector areaReservesDown; +}; + +//Vector size is number of areas, contains all the reserves +struct ALL_AREA_RESERVES +{ + std::vector thermalAreaReserves; + //other types of reserves to be implemented here +}; + struct PALIERS_THERMIQUES { int NombreDePaliersThermiques; @@ -516,12 +545,15 @@ struct PROBLEME_HEBDO std::vector PaliersThermiquesDuPays; std::vector CaracteristiquesHydrauliques; + ALL_AREA_RESERVES allReserves; + uint32_t NumberOfShortTermStorages = 0; // problemeHebdo->ShortTermStorage[areaIndex][clusterIndex].capacity; std::vector<::ShortTermStorage::AREA_INPUT> ShortTermStorage; /* Optimization problem */ uint32_t NbTermesContraintesPourLesCoutsDeDemarrage = 0; + uint32_t NbTermesContraintesPourLesReserves = 0; std::vector DefaillanceNegativeUtiliserPMinThermique; std::vector DefaillanceNegativeUtiliserHydro; std::vector DefaillanceNegativeUtiliserConsoAbattue; diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 65039953de..f909c897c1 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -283,6 +283,7 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, auto& pbPalier = problem.PaliersThermiquesDuPays[i]; unsigned int clusterCount = area.thermal.list.enabledAndNotMustRunCount(); pbPalier.NombreDePaliersThermiques = clusterCount; + AREA_RESERVES_VECTOR areaReserves; for (auto cluster : area.thermal.list.each_enabled_and_not_mustrun()) { @@ -309,9 +310,64 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, ? pbPalier.PmaxDUnGroupeDuPalierThermique[cluster->index] : cluster->minStablePower; pbPalier.NomsDesPaliersThermiques[cluster->index] = cluster->name().c_str(); + } + for (auto const& [key, val] : area.newReserves.areaReservesUp) + { + AREA_RESERVE areaReservesUp; + areaReservesUp.failureCost = val.failureCost; + areaReservesUp.spillageCost = val.spillageCost; + if (val.need->timeSeries.width > 0) + { + for (int indexSeries = 0; indexSeries < val.need->timeSeries.height; indexSeries++) + { + areaReservesUp.need.push_back(val.need->timeSeries.entry[0][indexSeries]); + } + } + for (auto cluster : area.thermal.list.each_enabled_and_not_mustrun()) + { + RESERVE_PARTICIPATION reserveParticipation; + if (cluster->isParticipatingInReserve(key)) + { + reserveParticipation.maxPower = cluster->reserveMaxPower(key); + reserveParticipation.participationCost = cluster->reserveCost(key); + } + areaReservesUp.AllReservesParticipation.push_back(reserveParticipation); + } + + areaReserves.areaReservesUp.push_back(areaReservesUp); + } + + for (auto const& [key, val] : area.newReserves.areaReservesDown) + { + AREA_RESERVE areaReservesDown; + areaReservesDown.failureCost = val.failureCost; + areaReservesDown.spillageCost = val.spillageCost; + if (val.need->timeSeries.width > 0) + { + for (int indexSeries = 0; indexSeries < val.need->timeSeries.height; indexSeries++) + { + areaReservesDown.need.push_back(val.need->timeSeries.entry[0][indexSeries]); + } + } + for (auto cluster : area.thermal.list.each_enabled_and_not_mustrun()) + { + RESERVE_PARTICIPATION reserveParticipation; + if (cluster->isParticipatingInReserve(key)) + { + reserveParticipation.maxPower = cluster->reserveMaxPower(key); + reserveParticipation.participationCost = cluster->reserveCost(key); + } + areaReservesDown.AllReservesParticipation.push_back(reserveParticipation); + } + + areaReserves.areaReservesDown.push_back(areaReservesDown); + } + + NombrePaliers += clusterCount; + problem.allReserves.thermalAreaReserves.push_back(areaReserves); } problem.NombreDePaliersThermiques = NombrePaliers; From 70ea5bdb8ecaccc5dfaecb5f37733d7557b67f86 Mon Sep 17 00:00:00 2001 From: h-fournier Date: Tue, 2 Apr 2024 11:45:51 +0200 Subject: [PATCH 05/41] New naming + internal review --- src/libs/antares/study/CMakeLists.txt | 1 + src/libs/antares/study/area/area.cpp | 10 ---- src/libs/antares/study/area/list.cpp | 28 +++++----- .../study/include/antares/study/area/area.h | 6 +-- .../{newReserves.h => capacityReservation.h} | 53 +++++++++++-------- .../antares/study/parts/common/cluster.h | 24 ++++----- .../antares/study/parts/common/cluster_list.h | 4 +- .../study/parts/common/cluster_list.cpp | 14 ++--- .../sim_structure_probleme_economique.h | 10 ++-- .../simulation/sim_calcul_economique.cpp | 36 ++++++------- 10 files changed, 86 insertions(+), 100 deletions(-) rename src/libs/antares/study/include/antares/study/area/{newReserves.h => capacityReservation.h} (55%) diff --git a/src/libs/antares/study/CMakeLists.txt b/src/libs/antares/study/CMakeLists.txt index 5e559be2c8..2b6e8de248 100644 --- a/src/libs/antares/study/CMakeLists.txt +++ b/src/libs/antares/study/CMakeLists.txt @@ -38,6 +38,7 @@ source_group("study\\scenario builder" FILES ${SRC_MATRIX}) set(SRC_AREAS include/antares/study/area/constants.h include/antares/study/area/area.h + include/antares/study/area/capacityReservation.h include/antares/study/area/area.hxx include/antares/study/area/scratchpad.h area/scratchpad.cpp diff --git a/src/libs/antares/study/area/area.cpp b/src/libs/antares/study/area/area.cpp index 0aaa8cdd2b..038d120f60 100644 --- a/src/libs/antares/study/area/area.cpp +++ b/src/libs/antares/study/area/area.cpp @@ -70,16 +70,6 @@ Area::~Area() { logs.debug() << " :: destroying area " << name; - // freeing memory from reserves - for (auto const& [key, val] : newReserves.areaReservesUp) - { - delete val.need; - } - for (auto const& [key, val] : newReserves.areaReservesDown) - { - delete val.need; - } - // Delete all links clearAllLinks(); diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index c7fbe0b86f..9419716cdd 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -31,7 +31,7 @@ #include "antares/study/parts/parts.h" #include "antares/study/parts/load/prepro.h" #include -#include +#include #define SEP IO::Separator @@ -849,19 +849,23 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, buffer.clear() << study.folderInput << SEP << "reserves" << SEP << area.id << SEP << "reserves.ini"; if (!ini.open(buffer)) + { + logs.warning() << study.folderInput << SEP << "reserves" << SEP << area.id << SEP + << "reserves.ini"; return false; + } ini.each( [&](const IniFile::Section& section) { - if (area.newReserves.contains(section.name)) + if (area.allCapacityReservations.contains(section.name)) { logs.warning() << area.name << ": reserve name already exists for reserve " << section.name; } else { - AreaReserve tmpReserve; - std::string file_name = NewReserves::toFilename(section.name); + CapacityReservation tmpCapacityReservation; + std::string file_name = AllCapacityReservations::toFilename(section.name); int type = -1; for (auto* p = section.firstProperty; p; p = p->next) { @@ -871,7 +875,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, if (tmp == "failure-cost") { - if (!p->value.to(tmpReserve.failureCost)) + if (!p->value.to(tmpCapacityReservation.failureCost)) { logs.warning() << area.name << ": invalid failure cost for reserve " << section.name; @@ -879,7 +883,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, } else if (tmp == "spillage-cost") { - if (!p->value.to(tmpReserve.spillageCost)) + if (!p->value.to(tmpCapacityReservation.spillageCost)) { logs.warning() << area.name << ": invalid spillage cost for reserve " << section.name; @@ -901,19 +905,13 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, } buffer.clear() << study.folderInput << SEP << "reserves" << SEP << area.id << SEP << file_name << ".txt"; - TimeSeries::numbers tsnum; - Antares::Data::TimeSeries* tmp_need = new TimeSeries(tsnum); - ret = (*tmp_need).loadFromFile(buffer, false) && ret; - tmpReserve.need = tmp_need; + ret = tmpCapacityReservation.need.loadFromFile(buffer, false) && ret; if (type == 0) - area.newReserves.areaReservesUp.emplace(section.name, tmpReserve); + area.allCapacityReservations.areaCapacityReservationsUp.emplace(section.name, tmpCapacityReservation); else if (type == 1) - area.newReserves.areaReservesDown.emplace(section.name, tmpReserve); + area.allCapacityReservations.areaCapacityReservationsDown.emplace(section.name, tmpCapacityReservation); else - { logs.warning() << area.name << ": invalid type for reserve " << section.name; - delete tmp_need; - } } }); } diff --git a/src/libs/antares/study/include/antares/study/area/area.h b/src/libs/antares/study/include/antares/study/area/area.h index 96314e820e..ca393db528 100644 --- a/src/libs/antares/study/include/antares/study/area/area.h +++ b/src/libs/antares/study/include/antares/study/area/area.h @@ -34,7 +34,7 @@ #include "ui.h" #include "constants.h" #include "antares/study/filter.h" -#include +#include namespace Antares { @@ -294,8 +294,8 @@ class Area final : private Yuni::NonCopyable double spreadSpilledEnergyCost = 0.; //@} - /// \name NewRerserves structure to keep track of the added reserves - NewReserves newReserves; + /// \name AllCapacityReservations structure to keep track of the added capacity reservations + AllCapacityReservations allCapacityReservations; //! \name Output filtering //@{ diff --git a/src/libs/antares/study/include/antares/study/area/newReserves.h b/src/libs/antares/study/include/antares/study/area/capacityReservation.h similarity index 55% rename from src/libs/antares/study/include/antares/study/area/newReserves.h rename to src/libs/antares/study/include/antares/study/area/capacityReservation.h index 4d65882fcb..08161c6b2f 100644 --- a/src/libs/antares/study/include/antares/study/area/newReserves.h +++ b/src/libs/antares/study/include/antares/study/area/capacityReservation.h @@ -27,42 +27,47 @@ #include #include #include +#include -/// @brief Represents an area reserve using it's name, it's failure cost and it's spillage cost -struct AreaReserve +/// @brief Represents an area capacity reservation using it's name, it's failure cost and it's spillage cost +struct CapacityReservation { - float failureCost = 0; - float spillageCost = 0; - Data::TimeSeries* need; + CapacityReservation() : failureCost(0), spillageCost(0), need(timeseriesNumbers) {} + float failureCost; + float spillageCost; + Antares::Data::TimeSeries need; + +private: + Matrix timeseriesNumbers; }; -/// @brief Stores all the Reserves in two vectors for the up and down reserves -struct NewReserves +/// @brief Stores all the Capacity reservations in two vectors for the up and down reserves +struct AllCapacityReservations { - std::map areaReservesUp; - std::map areaReservesDown; + std::map areaCapacityReservationsUp; + std::map areaCapacityReservationsDown; - /// @brief Check if the reserve name already exist in both the up and down reserves + /// @brief Check if the capacity reservation name already exist in both the up and down reserves /// @param name - /// @return true if the reserve already existed + /// @return true if the capacity reservation already existed bool contains(std::string name) { - return areaReservesUp.contains(name) || areaReservesDown.contains(name); + return areaCapacityReservationsUp.contains(name) || areaCapacityReservationsDown.contains(name); } - /// @brief Get a reserve from both the up and down reserves using its name + /// @brief Get a capacity reservation from both the up and down reserves using its name /// @param name - /// @return an optional of the reserve reference if the reserve was found, and a nullopt + /// @return an optional of the capacity reservation reference if the reserve was found, and a nullopt /// otherwise - std::optional> getReserveByName(Yuni::ShortString256 name) + std::optional> getReserveByName(Yuni::ShortString256 name) { - if (areaReservesUp.contains(name)) + if (areaCapacityReservationsUp.contains(name)) { - return areaReservesUp.at(name); + return areaCapacityReservationsUp.at(name); } - else if (areaReservesDown.contains(name)) + else if (areaCapacityReservationsDown.contains(name)) { - return areaReservesDown.at(name); + return areaCapacityReservationsDown.at(name); } return std::nullopt; } @@ -82,12 +87,14 @@ struct NewReserves /// @brief Represents the cluster reserve participation to a given reserve struct ClusterReserveParticipation { - AreaReserve& clusterReserve; + std::reference_wrapper capacityReservation; float maxPower = 0; float participationCost = 0; - ClusterReserveParticipation(AreaReserve& reserve, float power, float cost) : - clusterReserve(reserve), maxPower(power), participationCost(cost) + ClusterReserveParticipation(std::reference_wrapper reserve, + float power, + float cost) : + capacityReservation(reserve), maxPower(power), participationCost(cost) { } @@ -97,7 +104,7 @@ struct ClusterReserveParticipation if (this != &other) { // Copy the values from the other object - clusterReserve = other.clusterReserve; + capacityReservation = other.capacityReservation; maxPower = other.maxPower; participationCost = other.participationCost; } diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster.h b/src/libs/antares/study/include/antares/study/parts/common/cluster.h index b586cfb395..ec2f772c43 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster.h @@ -26,7 +26,7 @@ #include #include #include "../../fwd.h" -#include +#include #include #include @@ -105,9 +105,9 @@ class Cluster bool saveDataSeriesToFolder(const AnyString& folder) const; bool loadDataSeriesFromFolder(Study& s, const AnyString& folder); - /// @brief Add the reserve participation to the current clusterReservesParticipations map - /// @param name the name of the reserve to add - /// @param reserveParticipation the reserve participation to add + //! @brief Add the reserve participation to the current clusterReservesParticipations map + //! @param name the name of the reserve to add + //! @param reserveParticipation the reserve participation to add void addReserveParticipation(std::string name, ClusterReserveParticipation reserveParticipation); @@ -140,19 +140,13 @@ class Cluster */ Matrix<> modulation; - /*! - ** \brief Returns true if cluster participates in a reserve with this name - */ + //! \brief Returns true if cluster participates in a reserve with this name bool isParticipatingInReserve(std::string name); - /*! - ** \brief Returns max power for a reserve if participating, -1 otherwise - */ + //! \brief Returns max power for a reserve if participating, -1 otherwise float reserveMaxPower(std::string name); - /*! - ** \brief Returns participating cost for a reserve if participating, -1 otherwise - */ + //! \brief Returns participating cost for a reserve if participating, -1 otherwise float reserveCost(std::string name); @@ -164,8 +158,8 @@ class Cluster private: virtual unsigned int precision() const = 0; - /// @brief Stores the reserves Participations for each reserve, the key is the name of the - /// reserve + //! @brief Stores the reserves Participations for each reserve, the key is the name of the + //! reserve std::map clusterReservesParticipations; }; diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h index 27bf0a247c..88fb7764ee 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h @@ -25,7 +25,7 @@ #include "../../fwd.h" #include -#include +#include #include #include @@ -130,7 +130,7 @@ class ClusterList const AnyString& folder); /// @brief Load the reserve participation. For each entry, it checks if the reserve has been - /// added to area.newReserves, if not then log the name of the reserve that has not been found. + /// added to area.allCapacityReservations, if not then log the name of the reserve that has not been found. /// @tparam ClusterT Type of the Cluster list /// @param area Reference to area /// @param file File to read the reserve participations entries diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index 31ff4ef091..64a0d528a5 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -307,17 +307,13 @@ bool ClusterList::loadReserveParticipations(Area& area, const AnyStrin } } } - if (area.newReserves.getReserveByName(section.name).has_value() - && area.thermal.list.getClusterByName(tmpClusterName).has_value()) + auto reserve = area.allCapacityReservations.getReserveByName(section.name); + auto cluster = area.thermal.list.getClusterByName(tmpClusterName); + if (reserve && cluster) { ClusterReserveParticipation tmpReserveParticipation{ - area.newReserves.getReserveByName(section.name).value().get(), - tmpMaxPower, - tmpParticipationCost}; - area.thermal.list.getClusterByName(tmpClusterName) - .value() - .get() - ->addReserveParticipation(section.name, tmpReserveParticipation); + reserve.value(), tmpMaxPower, tmpParticipationCost}; + cluster.value().get()->addReserveParticipation(section.name, tmpReserveParticipation); } else { diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index a511a8e11c..722b67267e 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -263,10 +263,10 @@ struct RESERVE_PARTICIPATION float participationCost=-1; }; -struct AREA_RESERVE +struct CAPACITY_RESERVATION { - std::vector AllReservesParticipation; // Vector size is number of thermal clusters in this area - std::vector need; // Vector size is number of hours in year + std::vector AllReservesParticipation;//!< Vector size is number of thermal clusters in this area + std::vector need;//!< Vector size is number of hours in year float failureCost = 0; float spillageCost = 0; }; @@ -275,8 +275,8 @@ struct AREA_RESERVE //Vector size is number of reserves up or down struct AREA_RESERVES_VECTOR { - std::vector areaReservesUp; - std::vector areaReservesDown; + std::vector areaCapacityReservationsUp; + std::vector areaCapacityReservationsDown; }; //Vector size is number of areas, contains all the reserves diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index f909c897c1..b68012e8c0 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -313,16 +313,16 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, } - for (auto const& [key, val] : area.newReserves.areaReservesUp) + for (auto const& [key, val] : area.allCapacityReservations.areaCapacityReservationsUp) { - AREA_RESERVE areaReservesUp; - areaReservesUp.failureCost = val.failureCost; - areaReservesUp.spillageCost = val.spillageCost; - if (val.need->timeSeries.width > 0) + CAPACITY_RESERVATION areaCapacityReservationsUp; + areaCapacityReservationsUp.failureCost = val.failureCost; + areaCapacityReservationsUp.spillageCost = val.spillageCost; + if (val.need.timeSeries.width > 0) { - for (int indexSeries = 0; indexSeries < val.need->timeSeries.height; indexSeries++) + for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) { - areaReservesUp.need.push_back(val.need->timeSeries.entry[0][indexSeries]); + areaCapacityReservationsUp.need.push_back(val.need.timeSeries.entry[0][indexSeries]); } } for (auto cluster : area.thermal.list.each_enabled_and_not_mustrun()) @@ -333,22 +333,22 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, reserveParticipation.maxPower = cluster->reserveMaxPower(key); reserveParticipation.participationCost = cluster->reserveCost(key); } - areaReservesUp.AllReservesParticipation.push_back(reserveParticipation); + areaCapacityReservationsUp.AllReservesParticipation.push_back(reserveParticipation); } - areaReserves.areaReservesUp.push_back(areaReservesUp); + areaReserves.areaCapacityReservationsUp.push_back(areaCapacityReservationsUp); } - for (auto const& [key, val] : area.newReserves.areaReservesDown) + for (auto const& [key, val] : area.allCapacityReservations.areaCapacityReservationsDown) { - AREA_RESERVE areaReservesDown; - areaReservesDown.failureCost = val.failureCost; - areaReservesDown.spillageCost = val.spillageCost; - if (val.need->timeSeries.width > 0) + CAPACITY_RESERVATION areaCapacityReservationsDown; + areaCapacityReservationsDown.failureCost = val.failureCost; + areaCapacityReservationsDown.spillageCost = val.spillageCost; + if (val.need.timeSeries.width > 0) { - for (int indexSeries = 0; indexSeries < val.need->timeSeries.height; indexSeries++) + for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) { - areaReservesDown.need.push_back(val.need->timeSeries.entry[0][indexSeries]); + areaCapacityReservationsDown.need.push_back(val.need.timeSeries.entry[0][indexSeries]); } } for (auto cluster : area.thermal.list.each_enabled_and_not_mustrun()) @@ -359,10 +359,10 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, reserveParticipation.maxPower = cluster->reserveMaxPower(key); reserveParticipation.participationCost = cluster->reserveCost(key); } - areaReservesDown.AllReservesParticipation.push_back(reserveParticipation); + areaCapacityReservationsDown.AllReservesParticipation.push_back(reserveParticipation); } - areaReserves.areaReservesDown.push_back(areaReservesDown); + areaReserves.areaCapacityReservationsDown.push_back(areaCapacityReservationsDown); } From 28208e6689e532891cf1e3e633859fd8dedc73da Mon Sep 17 00:00:00 2001 From: sylvmara Date: Mon, 8 Apr 2024 17:31:50 +0200 Subject: [PATCH 06/41] Adding the first constraint (16bis) and counting the number of reservation constraints in the problem --- .../antares/study/parts/common/cluster.h | 2 + .../study/parts/thermal/cluster_list.h | 2 + .../include/antares/study/runtime/runtime.h | 1 + .../antares/study/parts/common/cluster.cpp | 4 + .../study/parts/thermal/cluster_list.cpp | 10 ++ src/libs/antares/study/runtime/runtime.cpp | 1 + src/solver/optimisation/CMakeLists.txt | 5 + .../optimisation/LinearProblemMatrix.cpp | 6 +- .../constraints/ConstraintBuilder.cpp | 16 +++ .../optimisation/constraints/PMaxReserve.cpp | 40 +++++++ .../constraints/ReserveParticipationGroup.cpp | 80 +++++++++++++ .../constraints/constraint_builder_utils.cpp | 3 +- .../solver/optimisation/LinearProblemMatrix.h | 3 + .../constraints/ConstraintBuilder.h | 17 +++ .../optimisation/constraints/PMaxReserve.h | 33 ++++++ .../constraints/ReserveParticipationGroup.h | 41 +++++++ .../solver/optimisation/opt_rename_problem.h | 11 ++ .../opt_alloc_probleme_a_optimiser.cpp | 1 + ...truction_variables_reserves_thermiques.cpp | 110 ++++++++++++++++++ .../opt_decompte_variables_et_contraintes.cpp | 23 ++++ ...gestion_des_bornes_reserves_thermiques.cpp | 88 ++++++++++++++ .../optimisation/opt_rename_problem.cpp | 35 ++++++ .../variables/VariableManagement.cpp | 20 ++++ .../variables/VariableManagement.h | 10 ++ .../sim_structure_probleme_economique.h | 7 ++ .../simulation/sim_alloc_probleme_hebdo.cpp | 4 + .../simulation/sim_calcul_economique.cpp | 10 +- 27 files changed, 578 insertions(+), 5 deletions(-) create mode 100644 src/solver/optimisation/constraints/PMaxReserve.cpp create mode 100644 src/solver/optimisation/constraints/ReserveParticipationGroup.cpp create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h create mode 100644 src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp create mode 100644 src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster.h b/src/libs/antares/study/include/antares/study/parts/common/cluster.h index ec2f772c43..8b5b5be24a 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster.h @@ -149,6 +149,8 @@ class Cluster //! \brief Returns participating cost for a reserve if participating, -1 otherwise float reserveCost(std::string name); + //! \brief Returns the number of reserves linked to this cluster + unsigned int reservesCount(); protected: diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h index 5bd3cda4e5..d29479e02f 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h @@ -123,6 +123,8 @@ class ThermalClusterList : public ClusterList unsigned int enabledAndMustRunCount() const; unsigned int enabledAndNotMustRunCount() const; + unsigned int reservesCount() const; + private: // Give a special index to enbled and not must-run THERMAL clusters void rebuildIndex() const; diff --git a/src/libs/antares/study/include/antares/study/runtime/runtime.h b/src/libs/antares/study/include/antares/study/runtime/runtime.h index 93f4946875..20e6177c71 100644 --- a/src/libs/antares/study/include/antares/study/runtime/runtime.h +++ b/src/libs/antares/study/include/antares/study/runtime/runtime.h @@ -105,6 +105,7 @@ class StudyRuntimeInfos //! Total uint thermalPlantTotalCount; uint thermalPlantTotalCountMustRun; + uint capacityReservationCount = 0; uint shortTermStorageCount = 0; diff --git a/src/libs/antares/study/parts/common/cluster.cpp b/src/libs/antares/study/parts/common/cluster.cpp index 992aa607ac..d71261c421 100644 --- a/src/libs/antares/study/parts/common/cluster.cpp +++ b/src/libs/antares/study/parts/common/cluster.cpp @@ -131,6 +131,10 @@ float Cluster::reserveCost(std::string name) return -1; } +unsigned int Cluster::reservesCount(){ + return clusterReservesParticipations.size(); +} + void Cluster::invalidateArea() { if (parentArea) diff --git a/src/libs/antares/study/parts/thermal/cluster_list.cpp b/src/libs/antares/study/parts/thermal/cluster_list.cpp index 4dcfb584ed..7224253963 100644 --- a/src/libs/antares/study/parts/thermal/cluster_list.cpp +++ b/src/libs/antares/study/parts/thermal/cluster_list.cpp @@ -24,6 +24,7 @@ #include "antares/study/study.h" #include #include +#include namespace // anonymous { @@ -87,6 +88,15 @@ unsigned int ThermalClusterList::enabledAndMustRunCount() const return std::ranges::count_if(allClusters_, [](auto c) { return c->isEnabled() && c->isMustRun(); }); } +unsigned int ThermalClusterList::reservesCount() const +{ + return std::accumulate(allClusters_.begin(), + allClusters_.end(), + 0, + [](int total, const std::shared_ptr cluster) + { return total + cluster->reservesCount(); }); +} + bool ThermalClusterList::loadFromFolder(Study& study, const AnyString& folder, Area* area) { assert(area && "A parent area is required"); diff --git a/src/libs/antares/study/runtime/runtime.cpp b/src/libs/antares/study/runtime/runtime.cpp index 5b38abf987..38e87098f4 100644 --- a/src/libs/antares/study/runtime/runtime.cpp +++ b/src/libs/antares/study/runtime/runtime.cpp @@ -89,6 +89,7 @@ static void StudyRuntimeInfosInitializeAllAreas(Study& study, StudyRuntimeInfos& // statistics r.thermalPlantTotalCount += area.thermal.list.enabledAndNotMustRunCount(); r.thermalPlantTotalCountMustRun += area.thermal.list.enabledAndMustRunCount(); + r.capacityReservationCount += area.thermal.list.reservesCount(); r.shortTermStorageCount += area.shortTermStorage.count(); } diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index 082f391b89..57cbf5abef 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -37,6 +37,7 @@ set(RTESOLVER_OPT opt_decompte_variables_et_contraintes_couts_demarrage.cpp opt_init_minmax_groupes_couts_demarrage.cpp opt_nombre_min_groupes_demarres_couts_demarrage.cpp + opt_construction_variables_reserves_thermiques.cpp include/antares/solver/optimisation/opt_export_structure.h opt_export_structure.cpp include/antares/solver/optimisation/base_weekly_optimization.h @@ -126,6 +127,8 @@ set(RTESOLVER_OPT constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp include/antares/solver/optimisation/constraints/MinDownTime.h constraints/MinDownTime.cpp + include/antares/solver/optimisation/constraints/PMaxReserve.h + constraints/PMaxReserve.cpp include/antares/solver/optimisation/ProblemMatrixEssential.h ProblemMatrixEssential.cpp @@ -156,6 +159,8 @@ set(RTESOLVER_OPT constraints/FinalStockGroup.cpp include/antares/solver/optimisation/constraints/AbstractStartUpCostsGroup.h constraints/AbstractStartUpCostsGroup.cpp + include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h + constraints/ReserveParticipationGroup.cpp include/antares/solver/optimisation/constraints/PMinMaxDispatchableGenerationGroup.h constraints/PMinMaxDispatchableGenerationGroup.cpp include/antares/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnitsGroup.h diff --git a/src/solver/optimisation/LinearProblemMatrix.cpp b/src/solver/optimisation/LinearProblemMatrix.cpp index e4b6a9fc11..10ca4a07f9 100644 --- a/src/solver/optimisation/LinearProblemMatrix.cpp +++ b/src/solver/optimisation/LinearProblemMatrix.cpp @@ -39,7 +39,8 @@ LinearProblemMatrix::LinearProblemMatrix(PROBLEME_HEBDO* problemeHebdo, minMaxHydroPowerGroup_(problemeHebdo, builder), maxPumpingGroup_(problemeHebdo, builder), areaHydroLevelGroup_(problemeHebdo, builder), - finalStockGroup_(problemeHebdo, builder) + finalStockGroup_(problemeHebdo, builder), + reserveParticipationGroup_(problemeHebdo, builder) { constraintgroups_ = {&group1_, &bindingConstraintDayGroup_, @@ -49,7 +50,8 @@ LinearProblemMatrix::LinearProblemMatrix(PROBLEME_HEBDO* problemeHebdo, &minMaxHydroPowerGroup_, &maxPumpingGroup_, &areaHydroLevelGroup_, - &finalStockGroup_}; + &finalStockGroup_, + &reserveParticipationGroup_}; } void LinearProblemMatrix::Run() diff --git a/src/solver/optimisation/constraints/ConstraintBuilder.cpp b/src/solver/optimisation/constraints/ConstraintBuilder.cpp index f36b7651c5..49e75d230f 100644 --- a/src/solver/optimisation/constraints/ConstraintBuilder.cpp +++ b/src/solver/optimisation/constraints/ConstraintBuilder.cpp @@ -49,6 +49,22 @@ ConstraintBuilder& ConstraintBuilder::DispatchableProduction(unsigned int index, return *this; } +ConstraintBuilder& ConstraintBuilder::ClusterReserveUpParticipation(unsigned int index, + double coeff, + int offset, + int delta){ + AddVariable(variableManager_.ClusterReserveUpParticipation(index, hourInWeek_, offset, delta), coeff); + return *this; +} + +ConstraintBuilder& ConstraintBuilder::ClusterReserveDownParticipation(unsigned int index, + double coeff, + int offset, + int delta){ + AddVariable(variableManager_.ClusterReserveDownParticipation(index, hourInWeek_, offset, delta), coeff); + return *this; +} + ConstraintBuilder& ConstraintBuilder::NumberOfDispatchableUnits(unsigned int index, double coeff) { AddVariable(variableManager_.NumberOfDispatchableUnits(index, hourInWeek_), coeff); diff --git a/src/solver/optimisation/constraints/PMaxReserve.cpp b/src/solver/optimisation/constraints/PMaxReserve.cpp new file mode 100644 index 0000000000..97fd5e8d82 --- /dev/null +++ b/src/solver/optimisation/constraints/PMaxReserve.cpp @@ -0,0 +1,40 @@ +#include "antares/solver/optimisation/constraints/PMaxReserve.h" + +void PMaxReserve::add(int pays, int reserve, int cluster, int pdt, bool isUpReserve) +{ + if (!data.Simulation) + { + // 16 bis + // constraint : P - M * B <= 0 + + CAPACITY_RESERVATION capacityReservation + = isUpReserve + ? data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp[reserve] + : data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown[reserve]; + + RESERVE_PARTICIPATION reserveParticipation + = capacityReservation.AllReservesParticipation[cluster]; + + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1.0) + .NumberOfDispatchableUnits(cluster, -reserveParticipation.maxPower) + .lessThan(); + + if (builder.NumberOfVariables() > 0) + { + ConstraintNamer namer(builder.data.NomDesContraintes); + const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; + namer.UpdateTimeStep(hourInTheYear); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + namer.PMaxReserve(builder.data.nombreDeContraintes, + reserveParticipation.clusterName, + capacityReservation.reserveName); + } + builder.build(); + } + else + { + builder.data.NbTermesContraintesPourLesReserves += 1; + builder.data.nombreDeContraintes++; + } +} diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp new file mode 100644 index 0000000000..9033162a19 --- /dev/null +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -0,0 +1,80 @@ +/* +** 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 . +*/ + +#include "antares/solver/optimisation/constraints/ReserveParticipationGroup.h" + +PMaxReserveData ReserveParticipationGroup::GetPMaxReserveDataFromProblemHebdo() +{ + return {.Simulation = simulation_, .areaReserves = problemeHebdo_->allReserves}; +} + +/** + * @brief build MinDownTime constraints with + * respect to default order + */ +void ReserveParticipationGroup::BuildConstraints() +{ + auto data = GetPMaxReserveDataFromProblemHebdo(); + PMaxReserve pMaxReserve(builder_, data); + + for (int pdt = 0; pdt < problemeHebdo_->NombreDePasDeTempsPourUneOptimisation; pdt++) + { + // Adding constraints for ReservesUp and ReservesDown + for (uint32_t pays = 0; pays < problemeHebdo_->NombreDePays; pays++) + { + auto areaReservesUp + = data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp; + uint32_t reserve = 0; + for (const auto& areaReserveUp : areaReservesUp) + { + uint32_t cluster = 0; + for (const auto& clusterReserveParticipation : + areaReserveUp.AllReservesParticipation) + { + if (clusterReserveParticipation.maxPower >= 0) + { + pMaxReserve.add(pays, reserve, cluster, pdt, true); + } + cluster++; + } + reserve++; + } + + auto areaReservesDown + = data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown; + reserve = 0; + for (const auto& areaReserveDown : areaReservesDown) + { + uint32_t cluster = 0; + for (const auto& clusterReserveParticipation : + areaReserveDown.AllReservesParticipation) + { + if (clusterReserveParticipation.maxPower >= 0) + { + pMaxReserve.add(pays, reserve, cluster, pdt, false); + } + cluster++; + } + reserve++; + } + } + } +} \ No newline at end of file diff --git a/src/solver/optimisation/constraints/constraint_builder_utils.cpp b/src/solver/optimisation/constraints/constraint_builder_utils.cpp index bca0b9ffeb..327c28e7b8 100644 --- a/src/solver/optimisation/constraints/constraint_builder_utils.cpp +++ b/src/solver/optimisation/constraints/constraint_builder_utils.cpp @@ -44,5 +44,6 @@ ConstraintBuilderData NewGetConstraintBuilderFromProblemHebdoAndProblemAResoudre problemeHebdo->NomsDesPays, problemeHebdo->weekInTheYear, problemeHebdo->NombreDePasDeTemps, - problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage}; + problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage, + problemeHebdo->NbTermesContraintesPourLesReserves}; } diff --git a/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h b/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h index b90c6d5f77..315f3a0260 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h @@ -32,6 +32,7 @@ #include "constraints/MaxPumpingGroup.h" #include "constraints/AreaHydroLevelGroup.h" #include "constraints/FinalStockGroup.h" +#include "constraints/ReserveParticipationGroup.h" #include @@ -54,4 +55,6 @@ class LinearProblemMatrix : public ProblemMatrixEssential MaxPumpingGroup maxPumpingGroup_; AreaHydroLevelGroup areaHydroLevelGroup_; FinalStockGroup finalStockGroup_; + ReserveParticipationGroup reserveParticipationGroup_; + }; \ No newline at end of file diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h index 0cea003029..2b999dc75b 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h @@ -54,6 +54,7 @@ class ConstraintBuilderData const uint32_t& weekInTheYear; const uint32_t& NombreDePasDeTemps; uint32_t& NbTermesContraintesPourLesCoutsDeDemarrage; + uint32_t& NbTermesContraintesPourLesReserves; }; /*! \verbatim @@ -100,6 +101,16 @@ class ConstraintBuilder int offset = 0, int delta = 0); + ConstraintBuilder& ClusterReserveUpParticipation(unsigned int index, + double coeff, + int offset = 0, + int delta = 0); + + ConstraintBuilder& ClusterReserveDownParticipation(unsigned int index, + double coeff, + int offset = 0, + int delta = 0); + ConstraintBuilder& NumberOfDispatchableUnits(unsigned int index, double coeff); ConstraintBuilder& NumberStoppingDispatchableUnits(unsigned int index, double coeff); @@ -279,4 +290,10 @@ struct StartUpCostsData { const std::vector& PaliersThermiquesDuPays; bool Simulation; +}; + +struct ReserveParticipationData +{ + bool Simulation; + ALL_AREA_RESERVES& areaReserves; }; \ No newline at end of file diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h new file mode 100644 index 0000000000..e596dfb649 --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h @@ -0,0 +1,33 @@ +#pragma once +#include "ConstraintBuilder.h" + +struct PMaxReserveData +{ + bool Simulation; + ALL_AREA_RESERVES& areaReserves; +}; + +/*! + * represent 'ReserveParticipation' Constraint type + */ +class PMaxReserve : private ConstraintFactory +{ +public: + PMaxReserve(ConstraintBuilder& builder, PMaxReserveData& data) : + ConstraintFactory(builder), data(data) + { + } + + /*! + * @brief Add variables to the constraint and update constraints Matrix + * @param pays : area + * @param reserve : capacity reservation + * @param isUpReserve : true if ReserveUp, false if ReserveDown + * @param cluster : global index of the cluster + * @param pdt : timestep + */ + void add(int pays, int reserve, int cluster, int pdt, bool isUpReserve); + +private: + PMaxReserveData& data; +}; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h new file mode 100644 index 0000000000..18559bc7bf --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h @@ -0,0 +1,41 @@ +/* + * 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 . + */ + +#pragma once +#include "ConstraintGroup.h" +#include "PMaxReserve.h" + +/** + * @brief Group of MinDownTime constraints + * + */ + +class ReserveParticipationGroup : public ConstraintGroup +{ +public: + using ConstraintGroup::ConstraintGroup; + + void BuildConstraints() override; + +private: + bool simulation_ = false; + PMaxReserveData GetPMaxReserveDataFromProblemHebdo(); +}; \ No newline at end of file diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h index 2e37cc0daa..54cbe560dd 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h @@ -66,6 +66,10 @@ class Namer void SetThermalClusterElementName(unsigned int variable, const std::string& variableType, const std::string& clusterName); + void SetThermalClusterReserveElementName(unsigned int variable, + const std::string& elementType, + const std::string& clusterName, + const std::string& reserveName); unsigned int timeStep_ = 0; std::string origin_; @@ -79,6 +83,12 @@ class VariableNamer : public Namer public: using Namer::Namer; void DispatchableProduction(unsigned int variable, const std::string& clusterName); + void ParticipationOfUnitsToReserve(unsigned int variable, + const std::string& clusterName, + const std::string& reserveName); + void ParticipationOfRunningUnitsToReserve(unsigned int variable, + const std::string& clusterName, + const std::string& reserveName); void NODU(unsigned int variable, const std::string& clusterName); void NumberStoppingDispatchableUnits(unsigned int variable, const std::string& clusterName); void NumberStartingDispatchableUnits(unsigned int variable, const std::string& clusterName); @@ -140,6 +150,7 @@ class ConstraintNamer : public Namer void NbUnitsOutageLessThanNbUnitsStop(unsigned int constraint, const std::string& clusterName); void NbDispUnitsMinBoundSinceMinUpTime(unsigned int constraint, const std::string& clusterName); void MinDownTime(unsigned int constraint, const std::string& clusterName); + void PMaxReserve(unsigned int constraint, const std::string& clusterName, const std::string& reserveName); void PMaxDispatchableGeneration(unsigned int constraint, const std::string& clusterName); void PMinDispatchableGeneration(unsigned int constraint, const std::string& clusterName); void ConsistenceNODU(unsigned int constraint, const std::string& clusterName); diff --git a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp index a5f218258d..faee234823 100644 --- a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp +++ b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp @@ -124,6 +124,7 @@ static void optimisationAllocateProblem(PROBLEME_HEBDO* problemeHebdo, const int NbTermes += 101; /* constraint expressing final level as a sum of stock layers */ NbTermes += problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage; + NbTermes += problemeHebdo->NbTermesContraintesPourLesReserves; logs.info(); logs.info() diff --git a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp new file mode 100644 index 0000000000..958b8c3f9d --- /dev/null +++ b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp @@ -0,0 +1,110 @@ +/* +** 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 . +*/ + +#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" + +#include "antares/solver/simulation/sim_extern_variables_globales.h" + +#include "antares/solver/optimisation/opt_fonctions.h" +#include "antares/solver/optimisation/opt_rename_problem.h" + +#include + +void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermiques( + PROBLEME_HEBDO* problemeHebdo, + bool Simulation) +{ + const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; + + int NombreDePasDeTempsPourUneOptimisation + = problemeHebdo->NombreDePasDeTempsPourUneOptimisation; + int& NombreDeVariables = ProblemeAResoudre->NombreDeVariables; + VariableNamer variableNamer(ProblemeAResoudre->NomDesVariables); + + for (int pdt = 0; pdt < NombreDePasDeTempsPourUneOptimisation; pdt++) + { + variableNamer.UpdateTimeStep(problemeHebdo->weekInTheYear * 168 + pdt); + auto& CorrespondanceVarNativesVarOptim + = problemeHebdo->CorrespondanceVarNativesVarOptim[pdt]; + + for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) + { + variableNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); + auto areaReserves = problemeHebdo->allReserves.thermalAreaReserves[pays]; + int index = 0; + const PALIERS_THERMIQUES& PaliersThermiquesDuPays + = problemeHebdo->PaliersThermiquesDuPays[pays]; + for (const auto& areaReserveUp : areaReserves.areaCapacityReservationsUp) + { + int clusterIndex = 0; + for (const auto& clusterReserveParticipation : + areaReserveUp.AllReservesParticipation) + { + if (clusterReserveParticipation.maxPower >= 0) + { + const auto& clusterName + = PaliersThermiquesDuPays.NomsDesPaliersThermiques[clusterIndex]; + if (!Simulation) + { + CorrespondanceVarNativesVarOptim + .clusterReserveUpParticipationIndex[index] + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.ParticipationOfUnitsToReserve( + NombreDeVariables, clusterName, areaReserveUp.reserveName); + index++; + clusterIndex++; + } + NombreDeVariables++; + } + } + } + index = 0; + for (const auto& areaReserveDown : areaReserves.areaCapacityReservationsDown) + { + int clusterIndex = 0; + for (const auto& clusterReserveParticipation : + areaReserveDown.AllReservesParticipation) + { + if (clusterReserveParticipation.maxPower >= 0) + { + const auto& clusterName + = PaliersThermiquesDuPays.NomsDesPaliersThermiques[clusterIndex]; + if (!Simulation) + { + CorrespondanceVarNativesVarOptim + .clusterReserveDownParticipationIndex[index] + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.ParticipationOfUnitsToReserve( + NombreDeVariables, clusterName, areaReserveDown.reserveName); + index++; + clusterIndex++; + } + NombreDeVariables++; + } + } + } + } + } +} diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp index 0f4c196745..65797dfeb3 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp @@ -251,6 +251,29 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* } } + //Reserves + for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) + { + for (auto vectorReserveUp : + problemeHebdo->allReserves.thermalAreaReserves[pays].areaCapacityReservationsUp) + { + for (auto clusterUp : vectorReserveUp.AllReservesParticipation) + { + if (clusterUp.maxPower != -1) + ProblemeAResoudre->NombreDeContraintes += nombreDePasDeTempsPourUneOptimisation; + } + } + for (auto vectorReserveDown : + problemeHebdo->allReserves.thermalAreaReserves[pays].areaCapacityReservationsDown) + { + for (auto clusterDown : vectorReserveDown.AllReservesParticipation) + { + if (clusterDown.maxPower != -1) + ProblemeAResoudre->NombreDeContraintes += nombreDePasDeTempsPourUneOptimisation; + } + } + } + if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) { OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(problemeHebdo); diff --git a/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp new file mode 100644 index 0000000000..71bf8f484f --- /dev/null +++ b/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp @@ -0,0 +1,88 @@ +/* +** 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 . +*/ + +#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" + +#include "variables/VariableManagement.h" +#include "variables/VariableManagerUtils.h" +#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_donnees.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" +#include "antares/solver/optimisation/opt_fonctions.h" + +using namespace Yuni; + +void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( + PROBLEME_HEBDO* problemeHebdo, + const int PremierPdtDeLIntervalle, + const int DernierPdtDeLIntervalle) +{ + const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; + std::vector& Xmin = ProblemeAResoudre->Xmin; + std::vector& Xmax = ProblemeAResoudre->Xmax; + + for (int pdtHebdo = PremierPdtDeLIntervalle, pdtJour = 0; pdtHebdo < DernierPdtDeLIntervalle; + pdtHebdo++, pdtJour++) + { + const CORRESPONDANCES_DES_VARIABLES& CorrespondanceVarNativesVarOptim + = problemeHebdo->CorrespondanceVarNativesVarOptim[pdtJour]; + + for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) + { + const PALIERS_THERMIQUES& PaliersThermiquesDuPays + = problemeHebdo->PaliersThermiquesDuPays[pays]; + auto areaReserves = problemeHebdo->allReserves.thermalAreaReserves[pays]; + + int index = 0; + for (const auto& areaReserveUp : areaReserves.areaCapacityReservationsUp) + { + for (const auto& clusterReserveParticipation : + areaReserveUp.AllReservesParticipation) + { + if (clusterReserveParticipation.maxPower >= 0) + { + int var = CorrespondanceVarNativesVarOptim + .clusterReserveUpParticipationIndex[index]; + Xmin[var] = 0; + Xmax[var] = LINFINI_ANTARES; + } + index++; + } + } + index = 0; + for (const auto& areaReserveDown : areaReserves.areaCapacityReservationsUp) + { + for (const auto& clusterReserveParticipation : + areaReserveDown.AllReservesParticipation) + { + if (clusterReserveParticipation.maxPower >= 0) + { + int var = CorrespondanceVarNativesVarOptim + .clusterReserveUpParticipationIndex[index]; + Xmin[var] = 0; + Xmax[var] = LINFINI_ANTARES; + } + index++; + } + } + } + } +} diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index 4f8e77bd64..e734e9b885 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -89,11 +89,39 @@ void Namer::SetThermalClusterElementName(unsigned int variable, BuildName(elementType, location, TimeIdentifier(timeStep_, HOUR)), variable); } +void Namer::SetThermalClusterReserveElementName(unsigned int variable, + const std::string& elementType, + const std::string& clusterName, + const std::string& reserveName) +{ + const auto location = LocationIdentifier(area_, AREA) + SEPARATOR + "ThermalCluster" + "<" + + clusterName + ">" + SEPARATOR + "Reserve" + "<" + reserveName + ">"; + + targetUpdater_.UpdateTargetAtIndex( + BuildName(elementType, location, TimeIdentifier(timeStep_, HOUR)), variable); +} + void VariableNamer::DispatchableProduction(unsigned int variable, const std::string& clusterName) { SetThermalClusterElementName(variable, "DispatchableProduction", clusterName); } +void VariableNamer::ParticipationOfUnitsToReserve(unsigned int variable, + const std::string& clusterName, + const std::string& reserveName) +{ + SetThermalClusterReserveElementName( + variable, "ParticipationOfUnitsToReserve", clusterName, reserveName); +} + +void VariableNamer::ParticipationOfRunningUnitsToReserve(unsigned int variable, + const std::string& clusterName, + const std::string& reserveName) +{ + SetThermalClusterReserveElementName( + variable, "ParticipationOfRunningUnitsToReserve", clusterName, reserveName); +} + void VariableNamer::NODU(unsigned int variable, const std::string& clusterName) { SetThermalClusterElementName(variable, "NODU", clusterName); @@ -336,6 +364,13 @@ void ConstraintNamer::MinDownTime(unsigned int constraint, const std::string& cl SetThermalClusterElementName(constraint, "MinDownTime", clusterName); } +void ConstraintNamer::PMaxReserve(unsigned int constraint, + const std::string& clusterName, + const std::string& reserveName) +{ + SetThermalClusterReserveElementName(constraint, "PMaxReserve", clusterName, reserveName); +} + void ConstraintNamer::PMaxDispatchableGeneration(unsigned int constraint, const std::string& clusterName) { diff --git a/src/solver/optimisation/variables/VariableManagement.cpp b/src/solver/optimisation/variables/VariableManagement.cpp index de7a18388f..830d9b214f 100644 --- a/src/solver/optimisation/variables/VariableManagement.cpp +++ b/src/solver/optimisation/variables/VariableManagement.cpp @@ -43,6 +43,26 @@ int& VariableManager::DispatchableProduction(unsigned int index, return CorrespondanceVarNativesVarOptim_[pdt].NumeroDeVariableDuPalierThermique[index]; } +int& VariableManager::ClusterReserveUpParticipation(unsigned int index, + unsigned int hourInWeek, + int offset, + int delta) +{ + auto pdt = GetShiftedTimeStep(offset, delta, hourInWeek); + + return CorrespondanceVarNativesVarOptim_[pdt].clusterReserveUpParticipationIndex[index]; +} + +int& VariableManager::ClusterReserveDownParticipation(unsigned int index, + unsigned int hourInWeek, + int offset, + int delta) +{ + auto pdt = GetShiftedTimeStep(offset, delta, hourInWeek); + + return CorrespondanceVarNativesVarOptim_[pdt].clusterReserveDownParticipationIndex[index]; +} + int& VariableManager::NumberOfDispatchableUnits(unsigned int index, unsigned int hourInWeek, int offset, diff --git a/src/solver/optimisation/variables/VariableManagement.h b/src/solver/optimisation/variables/VariableManagement.h index d989e59539..c3aee23e39 100644 --- a/src/solver/optimisation/variables/VariableManagement.h +++ b/src/solver/optimisation/variables/VariableManagement.h @@ -22,6 +22,16 @@ class VariableManager int offset = 0, int delta = 0); + int& ClusterReserveUpParticipation(unsigned int index, + unsigned int hourInWeek, + int offset = 0, + int delta = 0); + + int& ClusterReserveDownParticipation(unsigned int index, + unsigned int hourInWeek, + int offset = 0, + int delta = 0); + int& NumberOfDispatchableUnits(unsigned int index, unsigned int hourInWeek, int offset = 0, diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index 722b67267e..d85ab6a357 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -45,6 +45,9 @@ struct CORRESPONDANCES_DES_VARIABLES std::vector NumeroDeVariableDuPalierThermique; + std::vector clusterReserveUpParticipationIndex; + std::vector clusterReserveDownParticipationIndex; + std::vector NumeroDeVariablesDeLaProdHyd; std::vector NumeroDeVariablesDePompage; @@ -261,6 +264,8 @@ struct RESERVE_PARTICIPATION { float maxPower=-1; float participationCost=-1; + + std::string clusterName; }; struct CAPACITY_RESERVATION @@ -269,6 +274,8 @@ struct CAPACITY_RESERVATION std::vector need;//!< Vector size is number of hours in year float failureCost = 0; float spillageCost = 0; + + std::string reserveName; }; diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index fecb3af268..95a2501614 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -173,6 +173,10 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, .assign(linkCount, 0); variablesMapping.NumeroDeVariableCoutExtremiteVersOrigineDeLInterconnexion .assign(linkCount, 0); + variablesMapping.clusterReserveUpParticipationIndex + .assign(study.runtime->capacityReservationCount, 0); + variablesMapping.clusterReserveDownParticipationIndex + .assign(study.runtime->capacityReservationCount, 0); variablesMapping.NumeroDeVariableDuPalierThermique .assign(study.runtime->thermalPlantTotalCount, 0); diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index b68012e8c0..9b9db93698 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -318,6 +318,7 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, CAPACITY_RESERVATION areaCapacityReservationsUp; areaCapacityReservationsUp.failureCost = val.failureCost; areaCapacityReservationsUp.spillageCost = val.spillageCost; + areaCapacityReservationsUp.reserveName = key; if (val.need.timeSeries.width > 0) { for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) @@ -332,8 +333,10 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, { reserveParticipation.maxPower = cluster->reserveMaxPower(key); reserveParticipation.participationCost = cluster->reserveCost(key); + reserveParticipation.clusterName = cluster->name(); + areaCapacityReservationsUp.AllReservesParticipation.push_back( + reserveParticipation); } - areaCapacityReservationsUp.AllReservesParticipation.push_back(reserveParticipation); } areaReserves.areaCapacityReservationsUp.push_back(areaCapacityReservationsUp); @@ -344,6 +347,7 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, CAPACITY_RESERVATION areaCapacityReservationsDown; areaCapacityReservationsDown.failureCost = val.failureCost; areaCapacityReservationsDown.spillageCost = val.spillageCost; + areaCapacityReservationsDown.reserveName = key; if (val.need.timeSeries.width > 0) { for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) @@ -358,8 +362,10 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, { reserveParticipation.maxPower = cluster->reserveMaxPower(key); reserveParticipation.participationCost = cluster->reserveCost(key); + reserveParticipation.clusterName = cluster->name(); + areaCapacityReservationsDown.AllReservesParticipation.push_back( + reserveParticipation); } - areaCapacityReservationsDown.AllReservesParticipation.push_back(reserveParticipation); } areaReserves.areaCapacityReservationsDown.push_back(areaCapacityReservationsDown); From 95d3ff1a0072fd861d88c785c9681e8d64af55f7 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Thu, 11 Apr 2024 12:26:11 +0200 Subject: [PATCH 07/41] Implementation of the linear problem matrix for the reserves, for cohesive count of solver reserve constraints --- .../study/parts/common/cluster_list.cpp | 8 +- .../optimisation/LinearProblemMatrix.cpp | 6 +- .../LinearProblemMatrixReserves.cpp | 33 +++++++ .../constraints/ReserveParticipationGroup.cpp | 10 +++ .../solver/optimisation/LinearProblemMatrix.h | 2 - .../LinearProblemMatrixReserves.h | 43 +++++++++ .../constraints/ReserveParticipationGroup.h | 11 ++- .../solver/optimisation/opt_fonctions.h | 2 +- .../opt_decompte_variables_et_contraintes.cpp | 24 +---- ...mpte_variables_et_contraintes_reserves.cpp | 34 +++++++ .../simulation/sim_calcul_economique.cpp | 90 ++++++++++--------- 11 files changed, 184 insertions(+), 79 deletions(-) create mode 100644 src/solver/optimisation/LinearProblemMatrixReserves.cpp create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrixReserves.h create mode 100644 src/solver/optimisation/opt_decompte_variables_et_contraintes_reserves.cpp diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index 64a0d528a5..ca6ca4df35 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -288,7 +288,7 @@ bool ClusterList::loadReserveParticipations(Area& area, const AnyStrin if (tmp == "cluster-name") { - tmpClusterName = p->value; + TransformNameIntoID(p->value, tmpClusterName); } else if (tmp == "max-power") { @@ -317,7 +317,11 @@ bool ClusterList::loadReserveParticipations(Area& area, const AnyStrin } else { - logs.warning() << area.name << ": does not contains this reserve " << section.name; + if (!reserve) + logs.warning() << area.name << ": does not contains this reserve " << section.name; + if (!cluster) + logs.warning() << area.name << ": does not contains this cluster " + << tmpClusterName; } }); return true; diff --git a/src/solver/optimisation/LinearProblemMatrix.cpp b/src/solver/optimisation/LinearProblemMatrix.cpp index 10ca4a07f9..e4b6a9fc11 100644 --- a/src/solver/optimisation/LinearProblemMatrix.cpp +++ b/src/solver/optimisation/LinearProblemMatrix.cpp @@ -39,8 +39,7 @@ LinearProblemMatrix::LinearProblemMatrix(PROBLEME_HEBDO* problemeHebdo, minMaxHydroPowerGroup_(problemeHebdo, builder), maxPumpingGroup_(problemeHebdo, builder), areaHydroLevelGroup_(problemeHebdo, builder), - finalStockGroup_(problemeHebdo, builder), - reserveParticipationGroup_(problemeHebdo, builder) + finalStockGroup_(problemeHebdo, builder) { constraintgroups_ = {&group1_, &bindingConstraintDayGroup_, @@ -50,8 +49,7 @@ LinearProblemMatrix::LinearProblemMatrix(PROBLEME_HEBDO* problemeHebdo, &minMaxHydroPowerGroup_, &maxPumpingGroup_, &areaHydroLevelGroup_, - &finalStockGroup_, - &reserveParticipationGroup_}; + &finalStockGroup_}; } void LinearProblemMatrix::Run() diff --git a/src/solver/optimisation/LinearProblemMatrixReserves.cpp b/src/solver/optimisation/LinearProblemMatrixReserves.cpp new file mode 100644 index 0000000000..4f1bdfe630 --- /dev/null +++ b/src/solver/optimisation/LinearProblemMatrixReserves.cpp @@ -0,0 +1,33 @@ +/* +** 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 . +*/ +#include "antares/solver/optimisation/LinearProblemMatrixReserves.h" +using namespace Antares::Data; + +LinearProblemMatrixReserves::LinearProblemMatrixReserves(PROBLEME_HEBDO* problemeHebdo, + bool Simulation, + ConstraintBuilder& builder) : + ProblemMatrixEssential(problemeHebdo), + simulation_(Simulation), + reserveParticipationGroup_(problemeHebdo, simulation_, builder) +{ + constraintgroups_ + = {&reserveParticipationGroup_}; +} \ No newline at end of file diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp index 9033162a19..c00b0a0f7e 100644 --- a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -21,6 +21,16 @@ #include "antares/solver/optimisation/constraints/ReserveParticipationGroup.h" + +ReserveParticipationGroup::ReserveParticipationGroup(PROBLEME_HEBDO* problemeHebdo, + bool simulation, + ConstraintBuilder& builder) : +AbstractStartUpCostsGroup(problemeHebdo,simulation,builder) +{ + this->simulation_ = simulation; +} + + PMaxReserveData ReserveParticipationGroup::GetPMaxReserveDataFromProblemHebdo() { return {.Simulation = simulation_, .areaReserves = problemeHebdo_->allReserves}; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h b/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h index 315f3a0260..145b7fc4b1 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h @@ -32,7 +32,6 @@ #include "constraints/MaxPumpingGroup.h" #include "constraints/AreaHydroLevelGroup.h" #include "constraints/FinalStockGroup.h" -#include "constraints/ReserveParticipationGroup.h" #include @@ -55,6 +54,5 @@ class LinearProblemMatrix : public ProblemMatrixEssential MaxPumpingGroup maxPumpingGroup_; AreaHydroLevelGroup areaHydroLevelGroup_; FinalStockGroup finalStockGroup_; - ReserveParticipationGroup reserveParticipationGroup_; }; \ No newline at end of file diff --git a/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrixReserves.h b/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrixReserves.h new file mode 100644 index 0000000000..885746649e --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrixReserves.h @@ -0,0 +1,43 @@ +/* +** 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 . +*/ +#pragma once +#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" +#include "constraints/ConstraintGroup.h" +#include "ProblemMatrixEssential.h" +#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" +#include "constraints/ReserveParticipationGroup.h" + +#include + +using namespace Antares::Data; + +class LinearProblemMatrixReserves : public ProblemMatrixEssential +{ +public: + explicit LinearProblemMatrixReserves(PROBLEME_HEBDO* problemeHebdo, + bool Simulation, + ConstraintBuilder& builder); + +private: + bool simulation_ = false; + ReserveParticipationGroup reserveParticipationGroup_; +}; \ No newline at end of file diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h index 18559bc7bf..5431c2dc05 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h @@ -20,19 +20,22 @@ */ #pragma once +#include "AbstractStartUpCostsGroup.h" #include "ConstraintGroup.h" #include "PMaxReserve.h" /** - * @brief Group of MinDownTime constraints + * @brief Group of reserve constraints * */ -class ReserveParticipationGroup : public ConstraintGroup +class ReserveParticipationGroup : public AbstractStartUpCostsGroup { public: - using ConstraintGroup::ConstraintGroup; - + using AbstractStartUpCostsGroup::AbstractStartUpCostsGroup; + ReserveParticipationGroup(PROBLEME_HEBDO* problemeHebdo, + bool simulation, + ConstraintBuilder& builder); void BuildConstraints() override; private: diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h index 4a3e4a3690..87b3569646 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h @@ -26,7 +26,6 @@ #include "adequacy_patch_csr/hourly_csr_problem.h" #include "opt_period_string_generator_base.h" #include "antares/study/parameters/adq-patch-params.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams; @@ -117,6 +116,7 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireCoutsDeDemarrage(PROB void OPT_InitialiserLesCoutsLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, const int, const int); void OPT_InitialiserLeSecondMembreDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, int, int); void OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(PROBLEME_HEBDO*); +void OPT_DecompteDesVariablesEtDesContraintesReserves(PROBLEME_HEBDO*); void OPT_InitialiserNombreMinEtMaxDeGroupesCoutsDeDemarrage(PROBLEME_HEBDO*); void OPT_AjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO*); double OPT_SommeDesPminThermiques(const PROBLEME_HEBDO*, int, uint); diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp index 65797dfeb3..eb180bd780 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp @@ -252,31 +252,11 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* } //Reserves - for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) - { - for (auto vectorReserveUp : - problemeHebdo->allReserves.thermalAreaReserves[pays].areaCapacityReservationsUp) - { - for (auto clusterUp : vectorReserveUp.AllReservesParticipation) - { - if (clusterUp.maxPower != -1) - ProblemeAResoudre->NombreDeContraintes += nombreDePasDeTempsPourUneOptimisation; - } - } - for (auto vectorReserveDown : - problemeHebdo->allReserves.thermalAreaReserves[pays].areaCapacityReservationsDown) - { - for (auto clusterDown : vectorReserveDown.AllReservesParticipation) - { - if (clusterDown.maxPower != -1) - ProblemeAResoudre->NombreDeContraintes += nombreDePasDeTempsPourUneOptimisation; - } - } - } - + //OPT_DecompteDesVariablesEtDesContraintesReserves(problemeHebdo); if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) { OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(problemeHebdo); + OPT_DecompteDesVariablesEtDesContraintesReserves(problemeHebdo); } return mxPaliers; diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes_reserves.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes_reserves.cpp new file mode 100644 index 0000000000..409d76f548 --- /dev/null +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes_reserves.cpp @@ -0,0 +1,34 @@ +/* +** 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 . +*/ + +#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_extern_variables_globales.h" +#include "antares/solver/optimisation/LinearProblemMatrixReserves.h" +#include "antares/solver/optimisation/constraints/constraint_builder_utils.h" + +#include "antares/solver/optimisation/opt_fonctions.h" + +void OPT_DecompteDesVariablesEtDesContraintesReserves(PROBLEME_HEBDO* problemeHebdo) +{ + auto builder_data = NewGetConstraintBuilderFromProblemHebdo(problemeHebdo); + ConstraintBuilder builder(builder_data); + LinearProblemMatrixReserves(problemeHebdo, true, builder).Run(); +} diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 9b9db93698..1fbf060ec5 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -312,63 +312,65 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, pbPalier.NomsDesPaliersThermiques[cluster->index] = cluster->name().c_str(); } - - for (auto const& [key, val] : area.allCapacityReservations.areaCapacityReservationsUp) + if (study.parameters.unitCommitment.ucMode + != Antares::Data::UnitCommitmentMode::ucHeuristicFast) { - CAPACITY_RESERVATION areaCapacityReservationsUp; - areaCapacityReservationsUp.failureCost = val.failureCost; - areaCapacityReservationsUp.spillageCost = val.spillageCost; - areaCapacityReservationsUp.reserveName = key; - if (val.need.timeSeries.width > 0) + for (auto const& [key, val] : area.allCapacityReservations.areaCapacityReservationsUp) { - for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) + CAPACITY_RESERVATION areaCapacityReservationsUp; + areaCapacityReservationsUp.failureCost = val.failureCost; + areaCapacityReservationsUp.spillageCost = val.spillageCost; + areaCapacityReservationsUp.reserveName = key; + if (val.need.timeSeries.width > 0) { - areaCapacityReservationsUp.need.push_back(val.need.timeSeries.entry[0][indexSeries]); + for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) + { + areaCapacityReservationsUp.need.push_back(val.need.timeSeries.entry[0][indexSeries]); + } } - } - for (auto cluster : area.thermal.list.each_enabled_and_not_mustrun()) - { - RESERVE_PARTICIPATION reserveParticipation; - if (cluster->isParticipatingInReserve(key)) + for (auto cluster : area.thermal.list.each_enabled_and_not_mustrun()) { - reserveParticipation.maxPower = cluster->reserveMaxPower(key); - reserveParticipation.participationCost = cluster->reserveCost(key); - reserveParticipation.clusterName = cluster->name(); - areaCapacityReservationsUp.AllReservesParticipation.push_back( - reserveParticipation); + RESERVE_PARTICIPATION reserveParticipation; + if (cluster->isParticipatingInReserve(key)) + { + reserveParticipation.maxPower = cluster->reserveMaxPower(key); + reserveParticipation.participationCost = cluster->reserveCost(key); + reserveParticipation.clusterName = cluster->name(); + areaCapacityReservationsUp.AllReservesParticipation.push_back( + reserveParticipation); + } } - } - - areaReserves.areaCapacityReservationsUp.push_back(areaCapacityReservationsUp); - } - for (auto const& [key, val] : area.allCapacityReservations.areaCapacityReservationsDown) - { - CAPACITY_RESERVATION areaCapacityReservationsDown; - areaCapacityReservationsDown.failureCost = val.failureCost; - areaCapacityReservationsDown.spillageCost = val.spillageCost; - areaCapacityReservationsDown.reserveName = key; - if (val.need.timeSeries.width > 0) + areaReserves.areaCapacityReservationsUp.push_back(areaCapacityReservationsUp); + } + for (auto const& [key, val] : area.allCapacityReservations.areaCapacityReservationsDown) { - for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) + CAPACITY_RESERVATION areaCapacityReservationsDown; + areaCapacityReservationsDown.failureCost = val.failureCost; + areaCapacityReservationsDown.spillageCost = val.spillageCost; + areaCapacityReservationsDown.reserveName = key; + if (val.need.timeSeries.width > 0) { - areaCapacityReservationsDown.need.push_back(val.need.timeSeries.entry[0][indexSeries]); + for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) + { + areaCapacityReservationsDown.need.push_back(val.need.timeSeries.entry[0][indexSeries]); + } } - } - for (auto cluster : area.thermal.list.each_enabled_and_not_mustrun()) - { - RESERVE_PARTICIPATION reserveParticipation; - if (cluster->isParticipatingInReserve(key)) + for (auto cluster : area.thermal.list.each_enabled_and_not_mustrun()) { - reserveParticipation.maxPower = cluster->reserveMaxPower(key); - reserveParticipation.participationCost = cluster->reserveCost(key); - reserveParticipation.clusterName = cluster->name(); - areaCapacityReservationsDown.AllReservesParticipation.push_back( - reserveParticipation); + RESERVE_PARTICIPATION reserveParticipation; + if (cluster->isParticipatingInReserve(key)) + { + reserveParticipation.maxPower = cluster->reserveMaxPower(key); + reserveParticipation.participationCost = cluster->reserveCost(key); + reserveParticipation.clusterName = cluster->name(); + areaCapacityReservationsDown.AllReservesParticipation.push_back( + reserveParticipation); + } } - } - areaReserves.areaCapacityReservationsDown.push_back(areaCapacityReservationsDown); + areaReserves.areaCapacityReservationsDown.push_back(areaCapacityReservationsDown); + } } From 85ec9fbd75ee1260ab3597376ddd84a2ba58fd42 Mon Sep 17 00:00:00 2001 From: h-fournier Date: Tue, 16 Apr 2024 13:31:06 +0200 Subject: [PATCH 08/41] Add variables to take into account the participation to reserves from units not running --- .../constraints/ConstraintBuilder.cpp | 8 +++---- .../optimisation/constraints/PMaxReserve.cpp | 6 ++++- .../constraints/ConstraintBuilder.h | 4 ++-- ...truction_variables_reserves_thermiques.cpp | 23 ++++++++++++++++--- .../variables/VariableManagement.cpp | 14 +++++------ .../variables/VariableManagement.h | 4 ++-- .../sim_structure_probleme_economique.h | 4 ++-- .../simulation/sim_alloc_probleme_hebdo.cpp | 4 ++-- 8 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/solver/optimisation/constraints/ConstraintBuilder.cpp b/src/solver/optimisation/constraints/ConstraintBuilder.cpp index 49e75d230f..823916b44a 100644 --- a/src/solver/optimisation/constraints/ConstraintBuilder.cpp +++ b/src/solver/optimisation/constraints/ConstraintBuilder.cpp @@ -49,19 +49,19 @@ ConstraintBuilder& ConstraintBuilder::DispatchableProduction(unsigned int index, return *this; } -ConstraintBuilder& ConstraintBuilder::ClusterReserveUpParticipation(unsigned int index, +ConstraintBuilder& ConstraintBuilder::RunningClusterReserveParticipation(unsigned int index, double coeff, int offset, int delta){ - AddVariable(variableManager_.ClusterReserveUpParticipation(index, hourInWeek_, offset, delta), coeff); + AddVariable(variableManager_.RunningClusterReserveParticipation(index, hourInWeek_, offset, delta), coeff); return *this; } -ConstraintBuilder& ConstraintBuilder::ClusterReserveDownParticipation(unsigned int index, +ConstraintBuilder& ConstraintBuilder::ClusterReserveParticipation(unsigned int index, double coeff, int offset, int delta){ - AddVariable(variableManager_.ClusterReserveDownParticipation(index, hourInWeek_, offset, delta), coeff); + AddVariable(variableManager_.ClusterReserveParticipation(index, hourInWeek_, offset, delta), coeff); return *this; } diff --git a/src/solver/optimisation/constraints/PMaxReserve.cpp b/src/solver/optimisation/constraints/PMaxReserve.cpp index 97fd5e8d82..e2cd6c3f64 100644 --- a/src/solver/optimisation/constraints/PMaxReserve.cpp +++ b/src/solver/optimisation/constraints/PMaxReserve.cpp @@ -5,7 +5,11 @@ void PMaxReserve::add(int pays, int reserve, int cluster, int pdt, bool isUpRese if (!data.Simulation) { // 16 bis + // Participation to the reserve is bounded for a cluster // constraint : P - M * B <= 0 + // P : Participation power + // M : Number of running units in the cluster + // B : Maximum accessible power if each unit running on the cluster for the reserve CAPACITY_RESERVATION capacityReservation = isUpReserve @@ -16,7 +20,7 @@ void PMaxReserve::add(int pays, int reserve, int cluster, int pdt, bool isUpRese = capacityReservation.AllReservesParticipation[cluster]; builder.updateHourWithinWeek(pdt) - .DispatchableProduction(cluster, 1.0) + .RunningClusterReserveParticipation(cluster, 1.0) .NumberOfDispatchableUnits(cluster, -reserveParticipation.maxPower) .lessThan(); diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h index 2b999dc75b..4c620eb4ca 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h @@ -101,12 +101,12 @@ class ConstraintBuilder int offset = 0, int delta = 0); - ConstraintBuilder& ClusterReserveUpParticipation(unsigned int index, + ConstraintBuilder& RunningClusterReserveParticipation(unsigned int index, double coeff, int offset = 0, int delta = 0); - ConstraintBuilder& ClusterReserveDownParticipation(unsigned int index, + ConstraintBuilder& ClusterReserveParticipation(unsigned int index, double coeff, int offset = 0, int delta = 0); diff --git a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp index 958b8c3f9d..adc911411e 100644 --- a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp @@ -64,8 +64,17 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi = PaliersThermiquesDuPays.NomsDesPaliersThermiques[clusterIndex]; if (!Simulation) { + // For running units in cluster CorrespondanceVarNativesVarOptim - .clusterReserveUpParticipationIndex[index] + .runningClusterReserveParticipationIndex[index] + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.ParticipationOfRunningUnitsToReserve( + NombreDeVariables, clusterName, areaReserveUp.reserveName); + + // For all units in cluster (off units can participate to the reserves) + CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex[index] = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; @@ -78,7 +87,6 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi } } } - index = 0; for (const auto& areaReserveDown : areaReserves.areaCapacityReservationsDown) { int clusterIndex = 0; @@ -91,8 +99,17 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi = PaliersThermiquesDuPays.NomsDesPaliersThermiques[clusterIndex]; if (!Simulation) { + // For running units in cluster CorrespondanceVarNativesVarOptim - .clusterReserveDownParticipationIndex[index] + .runningClusterReserveParticipationIndex[index] + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.ParticipationOfRunningUnitsToReserve( + NombreDeVariables, clusterName, areaReserveDown.reserveName); + + // For all units in cluster (off units can participate to the reserves) + CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex[index] = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; diff --git a/src/solver/optimisation/variables/VariableManagement.cpp b/src/solver/optimisation/variables/VariableManagement.cpp index 830d9b214f..96d63be4e8 100644 --- a/src/solver/optimisation/variables/VariableManagement.cpp +++ b/src/solver/optimisation/variables/VariableManagement.cpp @@ -43,24 +43,24 @@ int& VariableManager::DispatchableProduction(unsigned int index, return CorrespondanceVarNativesVarOptim_[pdt].NumeroDeVariableDuPalierThermique[index]; } -int& VariableManager::ClusterReserveUpParticipation(unsigned int index, +int& VariableManager::RunningClusterReserveParticipation(unsigned int index, unsigned int hourInWeek, int offset, int delta) { auto pdt = GetShiftedTimeStep(offset, delta, hourInWeek); - return CorrespondanceVarNativesVarOptim_[pdt].clusterReserveUpParticipationIndex[index]; + return CorrespondanceVarNativesVarOptim_[pdt].runningClusterReserveParticipationIndex[index]; } -int& VariableManager::ClusterReserveDownParticipation(unsigned int index, - unsigned int hourInWeek, - int offset, - int delta) +int& VariableManager::ClusterReserveParticipation(unsigned int index, + unsigned int hourInWeek, + int offset, + int delta) { auto pdt = GetShiftedTimeStep(offset, delta, hourInWeek); - return CorrespondanceVarNativesVarOptim_[pdt].clusterReserveDownParticipationIndex[index]; + return CorrespondanceVarNativesVarOptim_[pdt].clusterReserveParticipationIndex[index]; } int& VariableManager::NumberOfDispatchableUnits(unsigned int index, diff --git a/src/solver/optimisation/variables/VariableManagement.h b/src/solver/optimisation/variables/VariableManagement.h index c3aee23e39..29e6d2d3fe 100644 --- a/src/solver/optimisation/variables/VariableManagement.h +++ b/src/solver/optimisation/variables/VariableManagement.h @@ -22,12 +22,12 @@ class VariableManager int offset = 0, int delta = 0); - int& ClusterReserveUpParticipation(unsigned int index, + int& RunningClusterReserveParticipation(unsigned int index, unsigned int hourInWeek, int offset = 0, int delta = 0); - int& ClusterReserveDownParticipation(unsigned int index, + int& ClusterReserveParticipation(unsigned int index, unsigned int hourInWeek, int offset = 0, int delta = 0); diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index d85ab6a357..380f7e67fd 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -45,8 +45,8 @@ struct CORRESPONDANCES_DES_VARIABLES std::vector NumeroDeVariableDuPalierThermique; - std::vector clusterReserveUpParticipationIndex; - std::vector clusterReserveDownParticipationIndex; + std::vector runningClusterReserveParticipationIndex; + std::vector clusterReserveParticipationIndex; std::vector NumeroDeVariablesDeLaProdHyd; diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index 95a2501614..adc3c71aab 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -173,9 +173,9 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, .assign(linkCount, 0); variablesMapping.NumeroDeVariableCoutExtremiteVersOrigineDeLInterconnexion .assign(linkCount, 0); - variablesMapping.clusterReserveUpParticipationIndex + variablesMapping.runningClusterReserveParticipationIndex .assign(study.runtime->capacityReservationCount, 0); - variablesMapping.clusterReserveDownParticipationIndex + variablesMapping.clusterReserveParticipationIndex .assign(study.runtime->capacityReservationCount, 0); variablesMapping.NumeroDeVariableDuPalierThermique From 199b78e404656a0490c14ec568a1beb2a875b27d Mon Sep 17 00:00:00 2001 From: h-fournier Date: Wed, 17 Apr 2024 17:28:55 +0200 Subject: [PATCH 09/41] Implement equation 17 bis --- src/solver/optimisation/CMakeLists.txt | 5 + .../constraints/POutCapacityThreasholds.cpp | 112 ++++++++++++++++++ .../constraints/ReserveParticipationGroup.cpp | 88 +++++++++----- .../constraints/POutCapacityThreasholds.h | 32 +++++ .../constraints/ReserveParticipationGroup.h | 2 + .../solver/optimisation/opt_rename_problem.h | 2 + .../optimisation/opt_rename_problem.cpp | 12 ++ .../sim_structure_probleme_economique.h | 5 +- 8 files changed, 226 insertions(+), 32 deletions(-) create mode 100644 src/solver/optimisation/constraints/POutCapacityThreasholds.cpp create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/constraints/POutCapacityThreasholds.h diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index 57cbf5abef..94f017bbf5 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -35,6 +35,7 @@ set(RTESOLVER_OPT opt_gestion_second_membre_couts_demarrage.cpp opt_gestion_second_membre_couts_demarrage.cpp opt_decompte_variables_et_contraintes_couts_demarrage.cpp + opt_decompte_variables_et_contraintes_reserves.cpp opt_init_minmax_groupes_couts_demarrage.cpp opt_nombre_min_groupes_demarres_couts_demarrage.cpp opt_construction_variables_reserves_thermiques.cpp @@ -129,11 +130,15 @@ set(RTESOLVER_OPT constraints/MinDownTime.cpp include/antares/solver/optimisation/constraints/PMaxReserve.h constraints/PMaxReserve.cpp + include/antares/solver/optimisation/constraints/POutCapacityThreasholds.h + constraints/POutCapacityThreasholds.cpp include/antares/solver/optimisation/ProblemMatrixEssential.h ProblemMatrixEssential.cpp include/antares/solver/optimisation/LinearProblemMatrixStartUpCosts.h LinearProblemMatrixStartUpCosts.cpp + include/antares/solver/optimisation/LinearProblemMatrixReserves.h + LinearProblemMatrixReserves.cpp include/antares/solver/optimisation/LinearProblemMatrix.h LinearProblemMatrix.cpp include/antares/solver/optimisation/QuadraticProblemMatrix.h diff --git a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp new file mode 100644 index 0000000000..cf5ab8db94 --- /dev/null +++ b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp @@ -0,0 +1,112 @@ +#include "antares/solver/optimisation/constraints/POutCapacityThreasholds.h" + +void POutCapacityThreasholds::add(int pays, int cluster, int pdt) +{ + if (!data.Simulation) + { + // 17 bis + // Power output remains within limits set by minimum stable power and maximum capacity threasholds + // l * M + Sum(P^on_re-) <= P <= u * M - Sum(P^on_re+) + // l : minimum stable power output when running + // u : maximum stable power output when running + // M : number of running units in cluster θ + // P^on_re- : Participation of running units in cluster θ to Down reserves + // P^on_re+ : Participation of running units in cluster θ to Up reserves + // P : Power output from cluster θ + + // 17 bis (1) : l * M + Sum(P^on_re-) - P <= 0 + { + builder.updateHourWithinWeek(pdt) + .NumberOfDispatchableUnits( + cluster, data.thermalClusters[pays].pminDUnGroupeDuPalierThermique[cluster]) + .DispatchableProduction(cluster, -1); + + for (const auto& capacityReservation : + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown) + { + for (const auto& reserveParticipations : + capacityReservation.AllReservesParticipation) + { + if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + builder.RunningClusterReserveParticipation(cluster, 1); + } + } + + builder.lessThan(); + + if (builder.NumberOfVariables() > 0) + { + ConstraintNamer namer(builder.data.NomDesContraintes); + const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; + namer.UpdateTimeStep(hourInTheYear); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + namer.POutCapacityThreasholdInf( + builder.data.nombreDeContraintes, + data.thermalClusters[pays].NomsDesPaliersThermiques[cluster]); + } + builder.build(); + } + + // 17 bis (2) : P - u * M + Sum(P^on_re+) <= 0 + { + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1) + .NumberOfDispatchableUnits( + cluster, -data.thermalClusters[pays].PmaxDUnGroupeDuPalierThermique[cluster]); + + for (const auto& capacityReservation : + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp) + { + for (const auto& reserveParticipations : + capacityReservation.AllReservesParticipation) + { + if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + builder.RunningClusterReserveParticipation(cluster, 1); + } + } + + builder.lessThan(); + + if (builder.NumberOfVariables() > 0) + { + ConstraintNamer namer(builder.data.NomDesContraintes); + const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; + namer.UpdateTimeStep(hourInTheYear); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + namer.POutCapacityThreasholdSup( + builder.data.nombreDeContraintes, + data.thermalClusters[pays].NomsDesPaliersThermiques[cluster]); + } + builder.build(); + } + } + else + { + // Lambda that count the number of reserves that the cluster is participating to + auto countReservesFromCluster + = [cluster](const std::vector& reservations) + { + int counter = 0; + for (const auto& capacityReservation : reservations) + { + for (const auto& reserveParticipations : + capacityReservation.AllReservesParticipation) + { + if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + counter++; + } + } + return counter; + }; + + int nbConstraintsToAdd + = countReservesFromCluster( + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp) + + countReservesFromCluster( + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown); + + builder.data.NbTermesContraintesPourLesReserves += nbConstraintsToAdd; + + builder.data.nombreDeContraintes += nbConstraintsToAdd; + } +} diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp index c00b0a0f7e..8a371780f5 100644 --- a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -36,54 +36,82 @@ PMaxReserveData ReserveParticipationGroup::GetPMaxReserveDataFromProblemHebdo() return {.Simulation = simulation_, .areaReserves = problemeHebdo_->allReserves}; } +POutReserveData ReserveParticipationGroup::GetPOutReserveDataFromProblemHebdo() +{ + return {.Simulation = simulation_, + .areaReserves = problemeHebdo_->allReserves, + .thermalClusters = problemeHebdo_->PaliersThermiquesDuPays}; +} + /** * @brief build MinDownTime constraints with * respect to default order */ void ReserveParticipationGroup::BuildConstraints() { - auto data = GetPMaxReserveDataFromProblemHebdo(); - PMaxReserve pMaxReserve(builder_, data); - - for (int pdt = 0; pdt < problemeHebdo_->NombreDePasDeTempsPourUneOptimisation; pdt++) { - // Adding constraints for ReservesUp and ReservesDown - for (uint32_t pays = 0; pays < problemeHebdo_->NombreDePays; pays++) + auto data = GetPMaxReserveDataFromProblemHebdo(); + PMaxReserve pMaxReserve(builder_, data); + + for (int pdt = 0; pdt < problemeHebdo_->NombreDePasDeTempsPourUneOptimisation; pdt++) { - auto areaReservesUp - = data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp; - uint32_t reserve = 0; - for (const auto& areaReserveUp : areaReservesUp) + // Adding constraints for ReservesUp and ReservesDown + for (uint32_t pays = 0; pays < problemeHebdo_->NombreDePays; pays++) { - uint32_t cluster = 0; - for (const auto& clusterReserveParticipation : - areaReserveUp.AllReservesParticipation) + auto areaReservesUp + = data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp; + uint32_t reserve = 0; + for (const auto& areaReserveUp : areaReservesUp) { - if (clusterReserveParticipation.maxPower >= 0) + uint32_t cluster = 0; + for (const auto& clusterReserveParticipation : + areaReserveUp.AllReservesParticipation) { - pMaxReserve.add(pays, reserve, cluster, pdt, true); + if (clusterReserveParticipation.maxPower >= 0) + { + // 16 bis + pMaxReserve.add(pays, reserve, cluster, pdt, true); + } + cluster++; } - cluster++; + reserve++; } - reserve++; - } - auto areaReservesDown - = data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown; - reserve = 0; - for (const auto& areaReserveDown : areaReservesDown) - { - uint32_t cluster = 0; - for (const auto& clusterReserveParticipation : - areaReserveDown.AllReservesParticipation) + auto areaReservesDown + = data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown; + reserve = 0; + for (const auto& areaReserveDown : areaReservesDown) { - if (clusterReserveParticipation.maxPower >= 0) + uint32_t cluster = 0; + for (const auto& clusterReserveParticipation : + areaReserveDown.AllReservesParticipation) { - pMaxReserve.add(pays, reserve, cluster, pdt, false); + if (clusterReserveParticipation.maxPower >= 0) + { + pMaxReserve.add(pays, reserve, cluster, pdt, false); + } + cluster++; } - cluster++; + reserve++; + } + } + } + } + { + auto data = GetPOutReserveDataFromProblemHebdo(); + POutCapacityThreasholds pOutCapacityThreasholds(builder_, data); + + for (int pdt = 0; pdt < problemeHebdo_->NombreDePasDeTempsPourUneOptimisation; pdt++) + { + for (uint32_t pays = 0; pays < problemeHebdo_->NombreDePays; pays++) + { + const PALIERS_THERMIQUES& PaliersThermiquesDuPays + = problemeHebdo_->PaliersThermiquesDuPays[pays]; + for (int cluster = 0; cluster < PaliersThermiquesDuPays.NombreDePaliersThermiques; + cluster++) + { + pOutCapacityThreasholds.add(pays, cluster, pdt); } - reserve++; } } } diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/POutCapacityThreasholds.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/POutCapacityThreasholds.h new file mode 100644 index 0000000000..304fa69187 --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/POutCapacityThreasholds.h @@ -0,0 +1,32 @@ +#pragma once +#include "ConstraintBuilder.h" + +struct POutReserveData +{ + bool Simulation; + ALL_AREA_RESERVES& areaReserves; + std::vector thermalClusters; +}; + +/* + * represent 'POutCapacityThreasholds' Constraint type + */ +class POutCapacityThreasholds : private ConstraintFactory +{ +public: + POutCapacityThreasholds(ConstraintBuilder& builder, POutReserveData& data) : + ConstraintFactory(builder), data(data) + { + } + + /*! + * @brief Add variables to the constraint and update constraints Matrix + * @param pays : area + * @param cluster : global index of the cluster + * @param pdt : timestep + */ + void add(int pays, int cluster, int pdt); + +private: + POutReserveData& data; +}; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h index 5431c2dc05..ce10b29613 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h @@ -23,6 +23,7 @@ #include "AbstractStartUpCostsGroup.h" #include "ConstraintGroup.h" #include "PMaxReserve.h" +#include "POutCapacityThreasholds.h" /** * @brief Group of reserve constraints @@ -41,4 +42,5 @@ class ReserveParticipationGroup : public AbstractStartUpCostsGroup private: bool simulation_ = false; PMaxReserveData GetPMaxReserveDataFromProblemHebdo(); + POutReserveData GetPOutReserveDataFromProblemHebdo(); }; \ No newline at end of file diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h index 54cbe560dd..b774cafff9 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h @@ -151,6 +151,8 @@ class ConstraintNamer : public Namer void NbDispUnitsMinBoundSinceMinUpTime(unsigned int constraint, const std::string& clusterName); void MinDownTime(unsigned int constraint, const std::string& clusterName); void PMaxReserve(unsigned int constraint, const std::string& clusterName, const std::string& reserveName); + void POutCapacityThreasholdInf(unsigned int constraint, const std::string& clusterName); + void POutCapacityThreasholdSup(unsigned int constraint, const std::string& clusterName); void PMaxDispatchableGeneration(unsigned int constraint, const std::string& clusterName); void PMinDispatchableGeneration(unsigned int constraint, const std::string& clusterName); void ConsistenceNODU(unsigned int constraint, const std::string& clusterName); diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index e734e9b885..823ccf3143 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -371,6 +371,18 @@ void ConstraintNamer::PMaxReserve(unsigned int constraint, SetThermalClusterReserveElementName(constraint, "PMaxReserve", clusterName, reserveName); } +void ConstraintNamer::POutCapacityThreasholdInf(unsigned int constraint, + const std::string& clusterName) +{ + SetThermalClusterElementName(constraint, "POutCapacityThreasholdInf", clusterName); +} + +void ConstraintNamer::POutCapacityThreasholdSup(unsigned int constraint, + const std::string& clusterName) +{ + SetThermalClusterElementName(constraint, "POutCapacityThreasholdSup", clusterName); +} + void ConstraintNamer::PMaxDispatchableGeneration(unsigned int constraint, const std::string& clusterName) { diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index 380f7e67fd..a6064c1cfa 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -260,10 +260,11 @@ struct PDISP_ET_COUTS_HORAIRES_PAR_PALIER }; +constexpr float CLUSTER_NOT_PARTICIPATING = -1.0f; struct RESERVE_PARTICIPATION { - float maxPower=-1; - float participationCost=-1; + float maxPower = CLUSTER_NOT_PARTICIPATING; + float participationCost = CLUSTER_NOT_PARTICIPATING; std::string clusterName; }; From b021930bdad0e7d86a561b19007da8478e40d3db Mon Sep 17 00:00:00 2001 From: h-fournier Date: Thu, 18 Apr 2024 09:42:12 +0200 Subject: [PATCH 10/41] Fix cluster index --- .../optimisation/constraints/PMaxReserve.cpp | 7 +++++-- .../constraints/POutCapacityThreasholds.cpp | 15 +++++++++------ .../constraints/ReserveParticipationGroup.cpp | 4 +++- .../solver/optimisation/constraints/PMaxReserve.h | 1 + 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/solver/optimisation/constraints/PMaxReserve.cpp b/src/solver/optimisation/constraints/PMaxReserve.cpp index e2cd6c3f64..b535e6fcbc 100644 --- a/src/solver/optimisation/constraints/PMaxReserve.cpp +++ b/src/solver/optimisation/constraints/PMaxReserve.cpp @@ -19,9 +19,12 @@ void PMaxReserve::add(int pays, int reserve, int cluster, int pdt, bool isUpRese RESERVE_PARTICIPATION reserveParticipation = capacityReservation.AllReservesParticipation[cluster]; + int globalClusterIdx = data.thermalClusters[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; + builder.updateHourWithinWeek(pdt) - .RunningClusterReserveParticipation(cluster, 1.0) - .NumberOfDispatchableUnits(cluster, -reserveParticipation.maxPower) + .RunningClusterReserveParticipation(globalClusterIdx, 1.0) + .NumberOfDispatchableUnits(globalClusterIdx, -reserveParticipation.maxPower) .lessThan(); if (builder.NumberOfVariables() > 0) diff --git a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp index cf5ab8db94..796d8d40e6 100644 --- a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp +++ b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp @@ -14,12 +14,15 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) // P^on_re+ : Participation of running units in cluster θ to Up reserves // P : Power output from cluster θ + int globalClusterIdx = data.thermalClusters[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; + // 17 bis (1) : l * M + Sum(P^on_re-) - P <= 0 { builder.updateHourWithinWeek(pdt) .NumberOfDispatchableUnits( - cluster, data.thermalClusters[pays].pminDUnGroupeDuPalierThermique[cluster]) - .DispatchableProduction(cluster, -1); + globalClusterIdx, data.thermalClusters[pays].pminDUnGroupeDuPalierThermique[cluster]) + .DispatchableProduction(globalClusterIdx, -1); for (const auto& capacityReservation : data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown) @@ -28,7 +31,7 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) capacityReservation.AllReservesParticipation) { if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) - builder.RunningClusterReserveParticipation(cluster, 1); + builder.RunningClusterReserveParticipation(globalClusterIdx, 1); } } @@ -50,9 +53,9 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) // 17 bis (2) : P - u * M + Sum(P^on_re+) <= 0 { builder.updateHourWithinWeek(pdt) - .DispatchableProduction(cluster, 1) + .DispatchableProduction(globalClusterIdx, 1) .NumberOfDispatchableUnits( - cluster, -data.thermalClusters[pays].PmaxDUnGroupeDuPalierThermique[cluster]); + globalClusterIdx, -data.thermalClusters[pays].PmaxDUnGroupeDuPalierThermique[cluster]); for (const auto& capacityReservation : data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp) @@ -61,7 +64,7 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) capacityReservation.AllReservesParticipation) { if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) - builder.RunningClusterReserveParticipation(cluster, 1); + builder.RunningClusterReserveParticipation(globalClusterIdx, 1); } } diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp index 8a371780f5..030ea74032 100644 --- a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -33,7 +33,9 @@ AbstractStartUpCostsGroup(problemeHebdo,simulation,builder) PMaxReserveData ReserveParticipationGroup::GetPMaxReserveDataFromProblemHebdo() { - return {.Simulation = simulation_, .areaReserves = problemeHebdo_->allReserves}; + return {.Simulation = simulation_, + .areaReserves = problemeHebdo_->allReserves, + .thermalClusters = problemeHebdo_->PaliersThermiquesDuPays}; } POutReserveData ReserveParticipationGroup::GetPOutReserveDataFromProblemHebdo() diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h index e596dfb649..d85ddaed5a 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h @@ -5,6 +5,7 @@ struct PMaxReserveData { bool Simulation; ALL_AREA_RESERVES& areaReserves; + std::vector thermalClusters; }; /*! From 1a9b8190fd61a6e9751e280ca9b64ceb7cea62db Mon Sep 17 00:00:00 2001 From: h-fournier Date: Thu, 18 Apr 2024 10:36:47 +0200 Subject: [PATCH 11/41] Clean code duplication --- .../constraints/ReserveParticipationGroup.cpp | 13 +++---------- .../optimisation/constraints/ConstraintBuilder.h | 3 ++- .../solver/optimisation/constraints/PMaxReserve.h | 11 ++--------- .../constraints/POutCapacityThreasholds.h | 11 ++--------- .../constraints/ReserveParticipationGroup.h | 3 +-- 5 files changed, 10 insertions(+), 31 deletions(-) diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp index 030ea74032..a879301664 100644 --- a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -31,14 +31,7 @@ AbstractStartUpCostsGroup(problemeHebdo,simulation,builder) } -PMaxReserveData ReserveParticipationGroup::GetPMaxReserveDataFromProblemHebdo() -{ - return {.Simulation = simulation_, - .areaReserves = problemeHebdo_->allReserves, - .thermalClusters = problemeHebdo_->PaliersThermiquesDuPays}; -} - -POutReserveData ReserveParticipationGroup::GetPOutReserveDataFromProblemHebdo() +ReserveData ReserveParticipationGroup::GetReserveDataFromProblemHebdo() { return {.Simulation = simulation_, .areaReserves = problemeHebdo_->allReserves, @@ -52,7 +45,7 @@ POutReserveData ReserveParticipationGroup::GetPOutReserveDataFromProblemHebdo() void ReserveParticipationGroup::BuildConstraints() { { - auto data = GetPMaxReserveDataFromProblemHebdo(); + auto data = GetReserveDataFromProblemHebdo(); PMaxReserve pMaxReserve(builder_, data); for (int pdt = 0; pdt < problemeHebdo_->NombreDePasDeTempsPourUneOptimisation; pdt++) @@ -100,7 +93,7 @@ void ReserveParticipationGroup::BuildConstraints() } } { - auto data = GetPOutReserveDataFromProblemHebdo(); + auto data = GetReserveDataFromProblemHebdo(); POutCapacityThreasholds pOutCapacityThreasholds(builder_, data); for (int pdt = 0; pdt < problemeHebdo_->NombreDePasDeTempsPourUneOptimisation; pdt++) diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h index 4c620eb4ca..6dfb2d6025 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h @@ -292,8 +292,9 @@ struct StartUpCostsData bool Simulation; }; -struct ReserveParticipationData +struct ReserveData { bool Simulation; ALL_AREA_RESERVES& areaReserves; + std::vector thermalClusters; }; \ No newline at end of file diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h index d85ddaed5a..924889b763 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h @@ -1,20 +1,13 @@ #pragma once #include "ConstraintBuilder.h" -struct PMaxReserveData -{ - bool Simulation; - ALL_AREA_RESERVES& areaReserves; - std::vector thermalClusters; -}; - /*! * represent 'ReserveParticipation' Constraint type */ class PMaxReserve : private ConstraintFactory { public: - PMaxReserve(ConstraintBuilder& builder, PMaxReserveData& data) : + PMaxReserve(ConstraintBuilder& builder, ReserveData& data) : ConstraintFactory(builder), data(data) { } @@ -30,5 +23,5 @@ class PMaxReserve : private ConstraintFactory void add(int pays, int reserve, int cluster, int pdt, bool isUpReserve); private: - PMaxReserveData& data; + ReserveData& data; }; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/POutCapacityThreasholds.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/POutCapacityThreasholds.h index 304fa69187..7e28a951ca 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/POutCapacityThreasholds.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/POutCapacityThreasholds.h @@ -1,20 +1,13 @@ #pragma once #include "ConstraintBuilder.h" -struct POutReserveData -{ - bool Simulation; - ALL_AREA_RESERVES& areaReserves; - std::vector thermalClusters; -}; - /* * represent 'POutCapacityThreasholds' Constraint type */ class POutCapacityThreasholds : private ConstraintFactory { public: - POutCapacityThreasholds(ConstraintBuilder& builder, POutReserveData& data) : + POutCapacityThreasholds(ConstraintBuilder& builder, ReserveData& data) : ConstraintFactory(builder), data(data) { } @@ -28,5 +21,5 @@ class POutCapacityThreasholds : private ConstraintFactory void add(int pays, int cluster, int pdt); private: - POutReserveData& data; + ReserveData& data; }; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h index ce10b29613..3bc14c0190 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h @@ -41,6 +41,5 @@ class ReserveParticipationGroup : public AbstractStartUpCostsGroup private: bool simulation_ = false; - PMaxReserveData GetPMaxReserveDataFromProblemHebdo(); - POutReserveData GetPOutReserveDataFromProblemHebdo(); + ReserveData GetReserveDataFromProblemHebdo(); }; \ No newline at end of file From 9eaeeaa5f75c043fa0fcf13712c8d734e0327693 Mon Sep 17 00:00:00 2001 From: h-fournier Date: Thu, 18 Apr 2024 11:41:13 +0200 Subject: [PATCH 12/41] Implement equation 17 quater --- src/solver/optimisation/CMakeLists.txt | 2 + .../constraints/PRunningUnits.cpp | 46 +++++++++++++++++++ .../constraints/ReserveParticipationGroup.cpp | 5 ++ .../optimisation/constraints/PRunningUnits.h | 27 +++++++++++ .../constraints/ReserveParticipationGroup.h | 1 + 5 files changed, 81 insertions(+) create mode 100644 src/solver/optimisation/constraints/PRunningUnits.cpp create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/constraints/PRunningUnits.h diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index 94f017bbf5..29c4fab50a 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -132,6 +132,8 @@ set(RTESOLVER_OPT constraints/PMaxReserve.cpp include/antares/solver/optimisation/constraints/POutCapacityThreasholds.h constraints/POutCapacityThreasholds.cpp + include/antares/solver/optimisation/constraints/PRunningUnits.h + constraints/PRunningUnits.cpp include/antares/solver/optimisation/ProblemMatrixEssential.h ProblemMatrixEssential.cpp diff --git a/src/solver/optimisation/constraints/PRunningUnits.cpp b/src/solver/optimisation/constraints/PRunningUnits.cpp new file mode 100644 index 0000000000..f6c5b24b6a --- /dev/null +++ b/src/solver/optimisation/constraints/PRunningUnits.cpp @@ -0,0 +1,46 @@ +#include "antares/solver/optimisation/constraints/PRunningUnits.h" + +void PRunningUnits::add(int pays, int reserve, int cluster, int pdt, bool isUpReserve) +{ + if (!data.Simulation) + { + // 17 Quater + // Participation to the reserve is bounded for a cluster + // constraint : P - P^on = 0 + // P : Participation power + // P^on : Participation of running units + + CAPACITY_RESERVATION capacityReservation + = isUpReserve + ? data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp[reserve] + : data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown[reserve]; + + RESERVE_PARTICIPATION reserveParticipation + = capacityReservation.AllReservesParticipation[cluster]; + + int globalClusterIdx = data.thermalClusters[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; + + builder.updateHourWithinWeek(pdt) + .RunningClusterReserveParticipation(globalClusterIdx, 1.0) + .ClusterReserveParticipation(globalClusterIdx, -1.0) + .equalTo(); + + if (builder.NumberOfVariables() > 0) + { + ConstraintNamer namer(builder.data.NomDesContraintes); + const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; + namer.UpdateTimeStep(hourInTheYear); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + namer.PMaxReserve(builder.data.nombreDeContraintes, + reserveParticipation.clusterName, + capacityReservation.reserveName); + } + builder.build(); + } + else + { + builder.data.NbTermesContraintesPourLesReserves += 1; + builder.data.nombreDeContraintes++; + } +} diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp index a879301664..86a8e6ba11 100644 --- a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -47,6 +47,7 @@ void ReserveParticipationGroup::BuildConstraints() { auto data = GetReserveDataFromProblemHebdo(); PMaxReserve pMaxReserve(builder_, data); + PRunningUnits pRunningUnits(builder_,data); for (int pdt = 0; pdt < problemeHebdo_->NombreDePasDeTempsPourUneOptimisation; pdt++) { @@ -66,6 +67,9 @@ void ReserveParticipationGroup::BuildConstraints() { // 16 bis pMaxReserve.add(pays, reserve, cluster, pdt, true); + + // 17 quater + pRunningUnits.add(pays, reserve, cluster, pdt, true); } cluster++; } @@ -105,6 +109,7 @@ void ReserveParticipationGroup::BuildConstraints() for (int cluster = 0; cluster < PaliersThermiquesDuPays.NombreDePaliersThermiques; cluster++) { + // 17 bis pOutCapacityThreasholds.add(pays, cluster, pdt); } } diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PRunningUnits.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PRunningUnits.h new file mode 100644 index 0000000000..7732167cb6 --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PRunningUnits.h @@ -0,0 +1,27 @@ +#pragma once +#include "ConstraintBuilder.h" + +/*! + * represent 'PRunningUnits' Constraint type + */ +class PRunningUnits : private ConstraintFactory +{ +public: + PRunningUnits(ConstraintBuilder& builder, ReserveData& data) : + ConstraintFactory(builder), data(data) + { + } + + /*! + * @brief Add variables to the constraint and update constraints Matrix + * @param pays : area + * @param reserve : capacity reservation + * @param isUpReserve : true if ReserveUp, false if ReserveDown + * @param cluster : global index of the cluster + * @param pdt : timestep + */ + void add(int pays, int reserve, int cluster, int pdt, bool isUpReserve); + +private: + ReserveData& data; +}; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h index 3bc14c0190..ab4082f295 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h @@ -24,6 +24,7 @@ #include "ConstraintGroup.h" #include "PMaxReserve.h" #include "POutCapacityThreasholds.h" +#include "PRunningUnits.h" /** * @brief Group of reserve constraints From a635accf8288ac76fd9fe8a641b3965d88555c5f Mon Sep 17 00:00:00 2001 From: h-fournier Date: Fri, 19 Apr 2024 15:16:28 +0200 Subject: [PATCH 13/41] Implement equation 24 --- .../antares/study/parts/common/cluster.h | 7 +-- .../study/parts/thermal/cluster_list.h | 6 ++- .../include/antares/study/runtime/runtime.h | 3 +- .../antares/study/parts/common/cluster.cpp | 2 +- .../study/parts/thermal/cluster_list.cpp | 19 ++++++- src/libs/antares/study/runtime/runtime.cpp | 3 +- src/solver/optimisation/CMakeLists.txt | 2 + .../constraints/ConstraintBuilder.cpp | 21 ++++++++ .../constraints/ReserveParticipationGroup.cpp | 14 ++++- .../constraints/ReserveSatisfaction.cpp | 53 +++++++++++++++++++ .../constraints/ConstraintBuilder.h | 10 ++++ .../optimisation/constraints/PMaxReserve.h | 2 +- .../constraints/ReserveParticipationGroup.h | 1 + .../constraints/ReserveSatisfaction.h | 26 +++++++++ .../solver/optimisation/opt_rename_problem.h | 8 ++- ...truction_variables_reserves_thermiques.cpp | 45 +++++++++++++++- .../optimisation/opt_rename_problem.cpp | 39 +++++++++++--- .../variables/VariableManagement.cpp | 20 +++++++ .../variables/VariableManagement.h | 10 ++++ .../sim_structure_probleme_economique.h | 2 + .../simulation/sim_alloc_probleme_hebdo.cpp | 6 ++- 21 files changed, 277 insertions(+), 22 deletions(-) create mode 100644 src/solver/optimisation/constraints/ReserveSatisfaction.cpp create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveSatisfaction.h diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster.h b/src/libs/antares/study/include/antares/study/parts/common/cluster.h index 8b5b5be24a..9b6eae15b0 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster.h @@ -150,19 +150,20 @@ class Cluster float reserveCost(std::string name); //! \brief Returns the number of reserves linked to this cluster - unsigned int reservesCount(); + unsigned int reserveParticipationsCount(); protected: Data::ClusterName pName; Data::ClusterName pID; Data::ClusterName pGroup; + //! reserve + std::map clusterReservesParticipations; private: virtual unsigned int precision() const = 0; //! @brief Stores the reserves Participations for each reserve, the key is the name of the - //! reserve - std::map clusterReservesParticipations; + }; } // namespace Data diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h index d29479e02f..4677d6bf14 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h @@ -123,7 +123,11 @@ class ThermalClusterList : public ClusterList unsigned int enabledAndMustRunCount() const; unsigned int enabledAndNotMustRunCount() const; - unsigned int reservesCount() const; + // returns the number of reserve participations of all clusters + unsigned int reserveParticipationsCount() const; + // returns the number of capacity reserves that all the clusters are participating to + // (count only capacity resarvations once) + unsigned int capacityReservationsCount() const; private: // Give a special index to enbled and not must-run THERMAL clusters diff --git a/src/libs/antares/study/include/antares/study/runtime/runtime.h b/src/libs/antares/study/include/antares/study/runtime/runtime.h index 20e6177c71..52485456b0 100644 --- a/src/libs/antares/study/include/antares/study/runtime/runtime.h +++ b/src/libs/antares/study/include/antares/study/runtime/runtime.h @@ -105,7 +105,8 @@ class StudyRuntimeInfos //! Total uint thermalPlantTotalCount; uint thermalPlantTotalCountMustRun; - uint capacityReservationCount = 0; + uint reserveParticipationCount = 0; //! Total number of reserve participations + uint capacityReservationCount = 0; //! Total number of capacity reservations uint shortTermStorageCount = 0; diff --git a/src/libs/antares/study/parts/common/cluster.cpp b/src/libs/antares/study/parts/common/cluster.cpp index d71261c421..ae8f757671 100644 --- a/src/libs/antares/study/parts/common/cluster.cpp +++ b/src/libs/antares/study/parts/common/cluster.cpp @@ -131,7 +131,7 @@ float Cluster::reserveCost(std::string name) return -1; } -unsigned int Cluster::reservesCount(){ +unsigned int Cluster::reserveParticipationsCount(){ return clusterReservesParticipations.size(); } diff --git a/src/libs/antares/study/parts/thermal/cluster_list.cpp b/src/libs/antares/study/parts/thermal/cluster_list.cpp index 7224253963..a633e3bcc1 100644 --- a/src/libs/antares/study/parts/thermal/cluster_list.cpp +++ b/src/libs/antares/study/parts/thermal/cluster_list.cpp @@ -88,13 +88,28 @@ unsigned int ThermalClusterList::enabledAndMustRunCount() const return std::ranges::count_if(allClusters_, [](auto c) { return c->isEnabled() && c->isMustRun(); }); } -unsigned int ThermalClusterList::reservesCount() const +unsigned int ThermalClusterList::reserveParticipationsCount() const { return std::accumulate(allClusters_.begin(), allClusters_.end(), 0, [](int total, const std::shared_ptr cluster) - { return total + cluster->reservesCount(); }); + { return total + cluster->reserveParticipationsCount(); }); +} + +unsigned int ThermalClusterList::capacityReservationsCount() const +{ + std::set uniqueReservations; + for (auto& cluster : allClusters_) + { + for (const auto& [_, reserveParticipation] : cluster->clusterReservesParticipations) + { + const CapacityReservation* reservationPtr = &(reserveParticipation.capacityReservation.get()); + uniqueReservations.insert(reservationPtr); + } + } + + return uniqueReservations.size(); } bool ThermalClusterList::loadFromFolder(Study& study, const AnyString& folder, Area* area) diff --git a/src/libs/antares/study/runtime/runtime.cpp b/src/libs/antares/study/runtime/runtime.cpp index 38e87098f4..8c1450bd76 100644 --- a/src/libs/antares/study/runtime/runtime.cpp +++ b/src/libs/antares/study/runtime/runtime.cpp @@ -89,7 +89,8 @@ static void StudyRuntimeInfosInitializeAllAreas(Study& study, StudyRuntimeInfos& // statistics r.thermalPlantTotalCount += area.thermal.list.enabledAndNotMustRunCount(); r.thermalPlantTotalCountMustRun += area.thermal.list.enabledAndMustRunCount(); - r.capacityReservationCount += area.thermal.list.reservesCount(); + r.reserveParticipationCount += area.thermal.list.reserveParticipationsCount(); + r.capacityReservationCount += area.thermal.list.capacityReservationsCount(); r.shortTermStorageCount += area.shortTermStorage.count(); } diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index 29c4fab50a..37a2a87056 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -134,6 +134,8 @@ set(RTESOLVER_OPT constraints/POutCapacityThreasholds.cpp include/antares/solver/optimisation/constraints/PRunningUnits.h constraints/PRunningUnits.cpp + include/antares/solver/optimisation/constraints/ReserveSatisfaction.h + constraints/ReserveSatisfaction.cpp include/antares/solver/optimisation/ProblemMatrixEssential.h ProblemMatrixEssential.cpp diff --git a/src/solver/optimisation/constraints/ConstraintBuilder.cpp b/src/solver/optimisation/constraints/ConstraintBuilder.cpp index 823916b44a..1a8a272ad7 100644 --- a/src/solver/optimisation/constraints/ConstraintBuilder.cpp +++ b/src/solver/optimisation/constraints/ConstraintBuilder.cpp @@ -65,6 +65,27 @@ ConstraintBuilder& ConstraintBuilder::ClusterReserveParticipation(unsigned int i return *this; } +ConstraintBuilder& ConstraintBuilder::InternalUnsatisfiedReserve(unsigned int index, + double coeff, + int offset, + int delta) +{ + AddVariable( + variableManager_.InternalUnsatisfiedReserve(index, hourInWeek_, offset, delta), + coeff); + return *this; +} + +ConstraintBuilder& ConstraintBuilder::InternalExcessReserve(unsigned int index, + double coeff, + int offset, + int delta) +{ + AddVariable(variableManager_.InternalExcessReserve(index, hourInWeek_, offset, delta), + coeff); + return *this; +} + ConstraintBuilder& ConstraintBuilder::NumberOfDispatchableUnits(unsigned int index, double coeff) { AddVariable(variableManager_.NumberOfDispatchableUnits(index, hourInWeek_), coeff); diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp index 86a8e6ba11..df12de9aa1 100644 --- a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -47,7 +47,8 @@ void ReserveParticipationGroup::BuildConstraints() { auto data = GetReserveDataFromProblemHebdo(); PMaxReserve pMaxReserve(builder_, data); - PRunningUnits pRunningUnits(builder_,data); + PRunningUnits pRunningUnits(builder_, data); + ReserveSatisfaction reserveSatisfaction(builder_, data); for (int pdt = 0; pdt < problemeHebdo_->NombreDePasDeTempsPourUneOptimisation; pdt++) { @@ -59,6 +60,9 @@ void ReserveParticipationGroup::BuildConstraints() uint32_t reserve = 0; for (const auto& areaReserveUp : areaReservesUp) { + // 24 + reserveSatisfaction.add(pays, reserve, pdt, true); + uint32_t cluster = 0; for (const auto& clusterReserveParticipation : areaReserveUp.AllReservesParticipation) @@ -78,16 +82,22 @@ void ReserveParticipationGroup::BuildConstraints() auto areaReservesDown = data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown; - reserve = 0; for (const auto& areaReserveDown : areaReservesDown) { + // 24 + reserveSatisfaction.add(pays, reserve, pdt, false); + uint32_t cluster = 0; for (const auto& clusterReserveParticipation : areaReserveDown.AllReservesParticipation) { if (clusterReserveParticipation.maxPower >= 0) { + // 16 bis pMaxReserve.add(pays, reserve, cluster, pdt, false); + + // 17 quater + pRunningUnits.add(pays, reserve, cluster, pdt, false); } cluster++; } diff --git a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp new file mode 100644 index 0000000000..03e8a938ea --- /dev/null +++ b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp @@ -0,0 +1,53 @@ +#include "antares/solver/optimisation/constraints/ReserveSatisfaction.h" + +void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) +{ + if (!data.Simulation) + { + // 24 + + // Sum(P_θ) - S + J^+ -J^- + // P : Participation power from cluster θ to the reserve res + // S : Internal reserve res need for the area + // J^+ : Amount of internal excess reserve for the reserve res + // J^+ : Amount of internal unsatified reserve for the reserve res + + builder.updateHourWithinWeek(pdt); + + CAPACITY_RESERVATION capacityReservation + = isUpReserve + ? data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp[reserve] + : data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown[reserve]; + + for (size_t cluster = 0; cluster < capacityReservation.AllReservesParticipation.size(); cluster++) + { + if (capacityReservation.AllReservesParticipation[cluster].maxPower != CLUSTER_NOT_PARTICIPATING) + builder.RunningClusterReserveParticipation( + data.thermalClusters[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster], + 1); + } + + capacityReservation.need[pdt]; + + builder.equalTo(); + + if (builder.NumberOfVariables() > 0) + { + ConstraintNamer namer(builder.data.NomDesContraintes); + const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; + namer.UpdateTimeStep(hourInTheYear); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + namer.ReserveSatisfaction( + builder.data.nombreDeContraintes, + capacityReservation.reserveName); + } + builder.build(); + } + else + { + builder.data.NbTermesContraintesPourLesReserves += 1; + + builder.data.nombreDeContraintes += 1; + } +} diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h index 6dfb2d6025..9b1de8db88 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h @@ -111,6 +111,16 @@ class ConstraintBuilder int offset = 0, int delta = 0); + ConstraintBuilder& InternalUnsatisfiedReserve(unsigned int pays, + double coeff, + int offset = 0, + int delta = 0); + + ConstraintBuilder& InternalExcessReserve(unsigned int pays, + double coeff, + int offset = 0, + int delta = 0); + ConstraintBuilder& NumberOfDispatchableUnits(unsigned int index, double coeff); ConstraintBuilder& NumberStoppingDispatchableUnits(unsigned int index, double coeff); diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h index 924889b763..73a1002cfe 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h @@ -16,9 +16,9 @@ class PMaxReserve : private ConstraintFactory * @brief Add variables to the constraint and update constraints Matrix * @param pays : area * @param reserve : capacity reservation - * @param isUpReserve : true if ReserveUp, false if ReserveDown * @param cluster : global index of the cluster * @param pdt : timestep + * @param isUpReserve : true if ReserveUp, false if ReserveDown */ void add(int pays, int reserve, int cluster, int pdt, bool isUpReserve); diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h index ab4082f295..68de88187c 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h @@ -25,6 +25,7 @@ #include "PMaxReserve.h" #include "POutCapacityThreasholds.h" #include "PRunningUnits.h" +#include "ReserveSatisfaction.h" /** * @brief Group of reserve constraints diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveSatisfaction.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveSatisfaction.h new file mode 100644 index 0000000000..549c6820ab --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveSatisfaction.h @@ -0,0 +1,26 @@ +#pragma once +#include "ConstraintBuilder.h" + +/* + * represent 'ReserveSatisfaction' Constraint type + */ +class ReserveSatisfaction : private ConstraintFactory +{ +public: + ReserveSatisfaction(ConstraintBuilder& builder, ReserveData& data) : + ConstraintFactory(builder), data(data) + { + } + + /*! + * @brief Add variables to the constraint and update constraints Matrix + * @param pays : area + * @param reserve : global index of the reserve + * @param pdt : timestep + * @param isUpReserve : true if ReserveUp, false if ReserveDown + */ + void add(int pays, int reserve, int pdt, bool isUpReserve); + +private: + ReserveData& data; +}; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h index b774cafff9..e3f3773f62 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h @@ -66,9 +66,12 @@ class Namer void SetThermalClusterElementName(unsigned int variable, const std::string& variableType, const std::string& clusterName); + void SetThermalClusterAndReserveElementName(unsigned int variable, + const std::string& elementType, + const std::string& clusterName, + const std::string& reserveName); void SetThermalClusterReserveElementName(unsigned int variable, const std::string& elementType, - const std::string& clusterName, const std::string& reserveName); unsigned int timeStep_ = 0; @@ -89,6 +92,8 @@ class VariableNamer : public Namer void ParticipationOfRunningUnitsToReserve(unsigned int variable, const std::string& clusterName, const std::string& reserveName); + void InternalUnsatisfiedReserve(unsigned int variable, const std::string& reserveName); + void InternalExcessReserve(unsigned int variable, const std::string& reserveName); void NODU(unsigned int variable, const std::string& clusterName); void NumberStoppingDispatchableUnits(unsigned int variable, const std::string& clusterName); void NumberStartingDispatchableUnits(unsigned int variable, const std::string& clusterName); @@ -153,6 +158,7 @@ class ConstraintNamer : public Namer void PMaxReserve(unsigned int constraint, const std::string& clusterName, const std::string& reserveName); void POutCapacityThreasholdInf(unsigned int constraint, const std::string& clusterName); void POutCapacityThreasholdSup(unsigned int constraint, const std::string& clusterName); + void ReserveSatisfaction(unsigned int constraint, const std::string& reserveName); void PMaxDispatchableGeneration(unsigned int constraint, const std::string& clusterName); void PMinDispatchableGeneration(unsigned int constraint, const std::string& clusterName); void ConsistenceNODU(unsigned int constraint, const std::string& clusterName); diff --git a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp index adc911411e..5180fb2f0d 100644 --- a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp @@ -50,10 +50,31 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi variableNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); auto areaReserves = problemeHebdo->allReserves.thermalAreaReserves[pays]; int index = 0; + int reserveIndex = 0; const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; for (const auto& areaReserveUp : areaReserves.areaCapacityReservationsUp) { + if (!Simulation) + { + // For Unsatisfied Reserves + CorrespondanceVarNativesVarOptim.internalUnsatisfiedReserveIndex[reserveIndex] + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.InternalUnsatisfiedReserve(NombreDeVariables, + areaReserveUp.reserveName); + + // For Excess Reserves + CorrespondanceVarNativesVarOptim.internalExcessReserveIndex[reserveIndex] + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.InternalExcessReserve(NombreDeVariables, + areaReserveUp.reserveName); + } + NombreDeVariables += 2; + int clusterIndex = 0; for (const auto& clusterReserveParticipation : areaReserveUp.AllReservesParticipation) @@ -83,12 +104,32 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi index++; clusterIndex++; } - NombreDeVariables++; + NombreDeVariables += 2; } } } for (const auto& areaReserveDown : areaReserves.areaCapacityReservationsDown) { + if (!Simulation) + { + // For Unsatisfied Reserves + CorrespondanceVarNativesVarOptim.internalUnsatisfiedReserveIndex[reserveIndex] + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.InternalUnsatisfiedReserve(NombreDeVariables, + areaReserveDown.reserveName); + + // For Excess Reserves + CorrespondanceVarNativesVarOptim.internalExcessReserveIndex[reserveIndex] + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.InternalExcessReserve(NombreDeVariables, + areaReserveDown.reserveName); + } + NombreDeVariables += 2; + int clusterIndex = 0; for (const auto& clusterReserveParticipation : areaReserveDown.AllReservesParticipation) @@ -118,7 +159,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi index++; clusterIndex++; } - NombreDeVariables++; + NombreDeVariables += 2; } } } diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index 823ccf3143..6d6149afc9 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -89,13 +89,24 @@ void Namer::SetThermalClusterElementName(unsigned int variable, BuildName(elementType, location, TimeIdentifier(timeStep_, HOUR)), variable); } +void Namer::SetThermalClusterAndReserveElementName(unsigned int variable, + const std::string& elementType, + const std::string& clusterName, + const std::string& reserveName) +{ + const auto location = LocationIdentifier(area_, AREA) + SEPARATOR + "ThermalCluster" + "<" + + clusterName + ">" + SEPARATOR + "Reserve" + "<" + reserveName + ">"; + + targetUpdater_.UpdateTargetAtIndex( + BuildName(elementType, location, TimeIdentifier(timeStep_, HOUR)), variable); +} + void Namer::SetThermalClusterReserveElementName(unsigned int variable, const std::string& elementType, - const std::string& clusterName, const std::string& reserveName) { - const auto location = LocationIdentifier(area_, AREA) + SEPARATOR + "ThermalCluster" + "<" - + clusterName + ">" + SEPARATOR + "Reserve" + "<" + reserveName + ">"; + const auto location + = LocationIdentifier(area_, AREA) + SEPARATOR + "Reserve" + "<" + reserveName + ">"; targetUpdater_.UpdateTargetAtIndex( BuildName(elementType, location, TimeIdentifier(timeStep_, HOUR)), variable); @@ -110,7 +121,7 @@ void VariableNamer::ParticipationOfUnitsToReserve(unsigned int variable, const std::string& clusterName, const std::string& reserveName) { - SetThermalClusterReserveElementName( + SetThermalClusterAndReserveElementName( variable, "ParticipationOfUnitsToReserve", clusterName, reserveName); } @@ -118,10 +129,21 @@ void VariableNamer::ParticipationOfRunningUnitsToReserve(unsigned int variable, const std::string& clusterName, const std::string& reserveName) { - SetThermalClusterReserveElementName( + SetThermalClusterAndReserveElementName( variable, "ParticipationOfRunningUnitsToReserve", clusterName, reserveName); } +void VariableNamer::InternalUnsatisfiedReserve(unsigned int variable, + const std::string& reserveName) +{ + SetThermalClusterReserveElementName(variable, "InternalUnsatisfiedReserve", reserveName); +} + +void VariableNamer::InternalExcessReserve(unsigned int variable, const std::string& reserveName) +{ + SetThermalClusterReserveElementName(variable, "InternalExcessReserve", reserveName); +} + void VariableNamer::NODU(unsigned int variable, const std::string& clusterName) { SetThermalClusterElementName(variable, "NODU", clusterName); @@ -368,7 +390,7 @@ void ConstraintNamer::PMaxReserve(unsigned int constraint, const std::string& clusterName, const std::string& reserveName) { - SetThermalClusterReserveElementName(constraint, "PMaxReserve", clusterName, reserveName); + SetThermalClusterAndReserveElementName(constraint, "PMaxReserve", clusterName, reserveName); } void ConstraintNamer::POutCapacityThreasholdInf(unsigned int constraint, @@ -383,6 +405,11 @@ void ConstraintNamer::POutCapacityThreasholdSup(unsigned int constraint, SetThermalClusterElementName(constraint, "POutCapacityThreasholdSup", clusterName); } +void ConstraintNamer::ReserveSatisfaction(unsigned int constraint, const std::string& reserveName) +{ + SetThermalClusterReserveElementName(constraint, "ReserveSatisfaction", reserveName); +} + void ConstraintNamer::PMaxDispatchableGeneration(unsigned int constraint, const std::string& clusterName) { diff --git a/src/solver/optimisation/variables/VariableManagement.cpp b/src/solver/optimisation/variables/VariableManagement.cpp index 96d63be4e8..340633ec04 100644 --- a/src/solver/optimisation/variables/VariableManagement.cpp +++ b/src/solver/optimisation/variables/VariableManagement.cpp @@ -63,6 +63,26 @@ int& VariableManager::ClusterReserveParticipation(unsigned int index, return CorrespondanceVarNativesVarOptim_[pdt].clusterReserveParticipationIndex[index]; } +int& VariableManager::InternalUnsatisfiedReserve(unsigned int index, + unsigned int hourInWeek, + int offset, + int delta) +{ + auto pdt = GetShiftedTimeStep(offset, delta, hourInWeek); + + return CorrespondanceVarNativesVarOptim_[pdt].internalUnsatisfiedReserveIndex[index]; +} + +int& VariableManager::InternalExcessReserve(unsigned int index, + unsigned int hourInWeek, + int offset, + int delta) +{ + auto pdt = GetShiftedTimeStep(offset, delta, hourInWeek); + + return CorrespondanceVarNativesVarOptim_[pdt].internalExcessReserveIndex[index]; +} + int& VariableManager::NumberOfDispatchableUnits(unsigned int index, unsigned int hourInWeek, int offset, diff --git a/src/solver/optimisation/variables/VariableManagement.h b/src/solver/optimisation/variables/VariableManagement.h index 29e6d2d3fe..1c989885b3 100644 --- a/src/solver/optimisation/variables/VariableManagement.h +++ b/src/solver/optimisation/variables/VariableManagement.h @@ -32,6 +32,16 @@ class VariableManager int offset = 0, int delta = 0); + int& InternalUnsatisfiedReserve(unsigned int index, + unsigned int hourInWeek, + int offset = 0, + int delta = 0); + + int& InternalExcessReserve(unsigned int index, + unsigned int hourInWeek, + int offset = 0, + int delta = 0); + int& NumberOfDispatchableUnits(unsigned int index, unsigned int hourInWeek, int offset = 0, diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index a6064c1cfa..c4717aa66f 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -47,6 +47,8 @@ struct CORRESPONDANCES_DES_VARIABLES std::vector runningClusterReserveParticipationIndex; std::vector clusterReserveParticipationIndex; + std::vector internalUnsatisfiedReserveIndex; + std::vector internalExcessReserveIndex; std::vector NumeroDeVariablesDeLaProdHyd; diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index adc3c71aab..be048b33cc 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -174,8 +174,12 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, variablesMapping.NumeroDeVariableCoutExtremiteVersOrigineDeLInterconnexion .assign(linkCount, 0); variablesMapping.runningClusterReserveParticipationIndex - .assign(study.runtime->capacityReservationCount, 0); + .assign(study.runtime->reserveParticipationCount, 0); variablesMapping.clusterReserveParticipationIndex + .assign(study.runtime->reserveParticipationCount, 0); + variablesMapping.internalUnsatisfiedReserveIndex + .assign(study.runtime->capacityReservationCount, 0); + variablesMapping.internalExcessReserveIndex .assign(study.runtime->capacityReservationCount, 0); variablesMapping.NumeroDeVariableDuPalierThermique From e1a6613df117b270b782cccf6d454e0e333ad2f5 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Wed, 24 Apr 2024 12:20:28 +0200 Subject: [PATCH 14/41] Adjusting constraint 24, added global reserve index for index uniformization --- src/libs/antares/study/runtime/runtime.cpp | 5 ++++- src/solver/optimisation/LinearProblemMatrix.cpp | 3 +++ .../optimisation/constraints/ConstraintBuilder.cpp | 10 ++++++++++ .../constraints/POutCapacityThreasholds.cpp | 4 ++-- .../constraints/ReserveParticipationGroup.cpp | 1 + .../constraints/ReserveSatisfaction.cpp | 13 +++++++------ .../optimisation/constraints/ConstraintBuilder.h | 5 +++++ .../optimisation/constraints/ReserveSatisfaction.h | 2 +- .../antares/solver/optimisation/opt_fonctions.h | 3 +++ ...t_construction_variables_optimisees_lineaire.cpp | 1 + ...t_construction_variables_reserves_thermiques.cpp | 10 ++++++++++ ...t_decompte_variables_et_contraintes_reserves.cpp | 4 ++++ .../optimisation/variables/VariableManagement.cpp | 10 ++++++++++ .../optimisation/variables/VariableManagement.h | 5 +++++ .../simulation/sim_structure_probleme_economique.h | 2 ++ src/solver/simulation/sim_alloc_probleme_hebdo.cpp | 4 +++- src/solver/simulation/sim_calcul_economique.cpp | 5 +++++ 17 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/libs/antares/study/runtime/runtime.cpp b/src/libs/antares/study/runtime/runtime.cpp index 8c1450bd76..4d399666c8 100644 --- a/src/libs/antares/study/runtime/runtime.cpp +++ b/src/libs/antares/study/runtime/runtime.cpp @@ -90,7 +90,10 @@ static void StudyRuntimeInfosInitializeAllAreas(Study& study, StudyRuntimeInfos& r.thermalPlantTotalCount += area.thermal.list.enabledAndNotMustRunCount(); r.thermalPlantTotalCountMustRun += area.thermal.list.enabledAndMustRunCount(); r.reserveParticipationCount += area.thermal.list.reserveParticipationsCount(); - r.capacityReservationCount += area.thermal.list.capacityReservationsCount(); + r.capacityReservationCount + += area.allCapacityReservations.areaCapacityReservationsUp.size(); + r.capacityReservationCount + += area.allCapacityReservations.areaCapacityReservationsDown.size(); r.shortTermStorageCount += area.shortTermStorage.count(); } diff --git a/src/solver/optimisation/LinearProblemMatrix.cpp b/src/solver/optimisation/LinearProblemMatrix.cpp index e4b6a9fc11..044c82c5d6 100644 --- a/src/solver/optimisation/LinearProblemMatrix.cpp +++ b/src/solver/optimisation/LinearProblemMatrix.cpp @@ -24,6 +24,8 @@ #include "antares/solver/utils/filename.h" #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/LinearProblemMatrixStartUpCosts.h" +#include "antares/solver/optimisation/LinearProblemMatrixReserves.h" + using namespace Antares::Data; @@ -61,6 +63,7 @@ void LinearProblemMatrix::Run() if (problemeHebdo_->OptimisationAvecCoutsDeDemarrage) { LinearProblemMatrixStartUpCosts(problemeHebdo_, false, builder_).Run(); + LinearProblemMatrixReserves(problemeHebdo_, false, builder_).Run(); } return; diff --git a/src/solver/optimisation/constraints/ConstraintBuilder.cpp b/src/solver/optimisation/constraints/ConstraintBuilder.cpp index 1a8a272ad7..0b1c6b020c 100644 --- a/src/solver/optimisation/constraints/ConstraintBuilder.cpp +++ b/src/solver/optimisation/constraints/ConstraintBuilder.cpp @@ -76,6 +76,16 @@ ConstraintBuilder& ConstraintBuilder::InternalUnsatisfiedReserve(unsigned int in return *this; } +ConstraintBuilder& ConstraintBuilder::NeedReserve(unsigned int index, + double coeff, + int offset, + int delta) +{ + AddVariable(variableManager_.NeedReserve(index, hourInWeek_, offset, delta), + coeff); + return *this; +} + ConstraintBuilder& ConstraintBuilder::InternalExcessReserve(unsigned int index, double coeff, int offset, diff --git a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp index 796d8d40e6..c5cc061a46 100644 --- a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp +++ b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp @@ -108,8 +108,8 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) + countReservesFromCluster( data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown); - builder.data.NbTermesContraintesPourLesReserves += nbConstraintsToAdd; + builder.data.NbTermesContraintesPourLesReserves += 2*nbConstraintsToAdd; - builder.data.nombreDeContraintes += nbConstraintsToAdd; + builder.data.nombreDeContraintes += 2*nbConstraintsToAdd; } } diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp index df12de9aa1..7416a07b76 100644 --- a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -80,6 +80,7 @@ void ReserveParticipationGroup::BuildConstraints() reserve++; } + reserve = 0; auto areaReservesDown = data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown; for (const auto& areaReserveDown : areaReservesDown) diff --git a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp index 03e8a938ea..bab9178622 100644 --- a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp +++ b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp @@ -6,11 +6,11 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) { // 24 - // Sum(P_θ) - S + J^+ -J^- - // P : Participation power from cluster θ to the reserve res + // Sum(P_θ) = S + J^+ -J^- + // P_θ : Participation power from cluster θ to the reserve res // S : Internal reserve res need for the area // J^+ : Amount of internal excess reserve for the reserve res - // J^+ : Amount of internal unsatified reserve for the reserve res + // J^- : Amount of internal unsatified reserve for the reserve res builder.updateHourWithinWeek(pdt); @@ -27,8 +27,9 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) .NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster], 1); } - - capacityReservation.need[pdt]; + builder.InternalUnsatisfiedReserve(capacityReservation.globalReserveIndex, 1); + builder.InternalExcessReserve(capacityReservation.globalReserveIndex, -1); + builder.NeedReserve(capacityReservation.globalReserveIndex, -1); builder.equalTo(); @@ -46,7 +47,7 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) } else { - builder.data.NbTermesContraintesPourLesReserves += 1; + builder.data.NbTermesContraintesPourLesReserves += 4; builder.data.nombreDeContraintes += 1; } diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h index 9b1de8db88..c6ffd9a413 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h @@ -116,6 +116,11 @@ class ConstraintBuilder int offset = 0, int delta = 0); + ConstraintBuilder& NeedReserve(unsigned int pays, + double coeff, + int offset = 0, + int delta = 0); + ConstraintBuilder& InternalExcessReserve(unsigned int pays, double coeff, int offset = 0, diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveSatisfaction.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveSatisfaction.h index 549c6820ab..f063181ed1 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveSatisfaction.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveSatisfaction.h @@ -15,7 +15,7 @@ class ReserveSatisfaction : private ConstraintFactory /*! * @brief Add variables to the constraint and update constraints Matrix * @param pays : area - * @param reserve : global index of the reserve + * @param reserve : index of the reserve inside area * @param pdt : timestep * @param isUpReserve : true if ReserveUp, false if ReserveDown */ diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h index 87b3569646..044c0acd1b 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h @@ -110,6 +110,8 @@ void OPT_AugmenterLaTailleDeLaMatriceDesContraintes(PROBLEME_ANTARES_A_RESOUDRE* void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, bool); +void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermiques(PROBLEME_HEBDO*, + bool); void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, const int, const int); @@ -121,4 +123,5 @@ void OPT_InitialiserNombreMinEtMaxDeGroupesCoutsDeDemarrage(PROBLEME_HEBDO*); void OPT_AjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO*); double OPT_SommeDesPminThermiques(const PROBLEME_HEBDO*, int, uint); + #endif /* __SOLVER_OPTIMISATION_FUNCTIONS_H__ */ diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp index 3dc7ee7425..4ba6e760a0 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp @@ -243,6 +243,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaire(PROBLEME_HEBD { OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarrage(problemeHebdo, false); + } return; diff --git a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp index 5180fb2f0d..247067aeae 100644 --- a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp @@ -55,6 +55,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi = problemeHebdo->PaliersThermiquesDuPays[pays]; for (const auto& areaReserveUp : areaReserves.areaCapacityReservationsUp) { + reserveIndex = areaReserveUp.globalReserveIndex; if (!Simulation) { // For Unsatisfied Reserves @@ -107,9 +108,14 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi NombreDeVariables += 2; } } + // Need + CorrespondanceVarNativesVarOptim.needReserveIndex[reserveIndex] + = areaReserveUp.need[pdt]; + NombreDeVariables++; } for (const auto& areaReserveDown : areaReserves.areaCapacityReservationsDown) { + reserveIndex = areaReserveDown.globalReserveIndex; if (!Simulation) { // For Unsatisfied Reserves @@ -162,6 +168,10 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi NombreDeVariables += 2; } } + // Need + CorrespondanceVarNativesVarOptim.needReserveIndex[reserveIndex] + = areaReserveDown.need[pdt]; + NombreDeVariables++; } } } diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes_reserves.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes_reserves.cpp index 409d76f548..5df71d7455 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes_reserves.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes_reserves.cpp @@ -31,4 +31,8 @@ void OPT_DecompteDesVariablesEtDesContraintesReserves(PROBLEME_HEBDO* problemeHe auto builder_data = NewGetConstraintBuilderFromProblemHebdo(problemeHebdo); ConstraintBuilder builder(builder_data); LinearProblemMatrixReserves(problemeHebdo, true, builder).Run(); + + OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermiques(problemeHebdo, + true); } + diff --git a/src/solver/optimisation/variables/VariableManagement.cpp b/src/solver/optimisation/variables/VariableManagement.cpp index 340633ec04..0adb3e6446 100644 --- a/src/solver/optimisation/variables/VariableManagement.cpp +++ b/src/solver/optimisation/variables/VariableManagement.cpp @@ -83,6 +83,16 @@ int& VariableManager::InternalExcessReserve(unsigned int index, return CorrespondanceVarNativesVarOptim_[pdt].internalExcessReserveIndex[index]; } +int& VariableManager::NeedReserve(unsigned int index, + unsigned int hourInWeek, + int offset, + int delta) +{ + auto pdt = GetShiftedTimeStep(offset, delta, hourInWeek); + + return CorrespondanceVarNativesVarOptim_[pdt].needReserveIndex[index]; +} + int& VariableManager::NumberOfDispatchableUnits(unsigned int index, unsigned int hourInWeek, int offset, diff --git a/src/solver/optimisation/variables/VariableManagement.h b/src/solver/optimisation/variables/VariableManagement.h index 1c989885b3..fb201d4ab6 100644 --- a/src/solver/optimisation/variables/VariableManagement.h +++ b/src/solver/optimisation/variables/VariableManagement.h @@ -42,6 +42,11 @@ class VariableManager int offset = 0, int delta = 0); + int& NeedReserve(unsigned int index, + unsigned int hourInWeek, + int offset = 0, + int delta = 0); + int& NumberOfDispatchableUnits(unsigned int index, unsigned int hourInWeek, int offset = 0, diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index c4717aa66f..9e489dfe23 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -49,6 +49,7 @@ struct CORRESPONDANCES_DES_VARIABLES std::vector clusterReserveParticipationIndex; std::vector internalUnsatisfiedReserveIndex; std::vector internalExcessReserveIndex; + std::vector needReserveIndex; std::vector NumeroDeVariablesDeLaProdHyd; @@ -279,6 +280,7 @@ struct CAPACITY_RESERVATION float spillageCost = 0; std::string reserveName; + int globalReserveIndex; }; diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index be048b33cc..b40751351e 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -150,7 +150,7 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, const uint shortTermStorageCount = study.runtime->shortTermStorageCount; auto activeConstraints = study.bindingConstraints.activeConstraints(); - + for (uint k = 0; k < NombreDePasDeTemps; k++) { problem.ValeursDeNTC[k].ValeurDeNTCOrigineVersExtremite.assign(linkCount, 0.); @@ -181,6 +181,8 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, .assign(study.runtime->capacityReservationCount, 0); variablesMapping.internalExcessReserveIndex .assign(study.runtime->capacityReservationCount, 0); + variablesMapping.needReserveIndex + .assign(study.runtime->capacityReservationCount, 0); variablesMapping.NumeroDeVariableDuPalierThermique .assign(study.runtime->thermalPlantTotalCount, 0); diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 1fbf060ec5..2b0bfe6603 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -276,6 +276,7 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, } NombrePaliers = 0; + int globalReserveIndex = 0; for (uint i = 0; i < study.areas.size(); ++i) { const auto& area = *(study.areas.byIndex[i]); @@ -321,6 +322,8 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, areaCapacityReservationsUp.failureCost = val.failureCost; areaCapacityReservationsUp.spillageCost = val.spillageCost; areaCapacityReservationsUp.reserveName = key; + areaCapacityReservationsUp.globalReserveIndex = globalReserveIndex; + globalReserveIndex++; if (val.need.timeSeries.width > 0) { for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) @@ -349,6 +352,8 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, areaCapacityReservationsDown.failureCost = val.failureCost; areaCapacityReservationsDown.spillageCost = val.spillageCost; areaCapacityReservationsDown.reserveName = key; + areaCapacityReservationsDown.globalReserveIndex = globalReserveIndex; + globalReserveIndex++; if (val.need.timeSeries.width > 0) { for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) From 2840e4102692a1f691a514620b378cff14765aaf Mon Sep 17 00:00:00 2001 From: sylvmara Date: Wed, 24 Apr 2024 16:58:49 +0200 Subject: [PATCH 15/41] Implementing reserve costs for excess and failure --- .../solver/optimisation/opt_fonctions.h | 1 + .../opt_gestion_des_couts_cas_lineaire.cpp | 2 + .../opt_gestion_des_couts_reserves.cpp | 84 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 src/solver/optimisation/opt_gestion_des_couts_reserves.cpp diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h index 044c0acd1b..91b71abf0c 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h @@ -116,6 +116,7 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireCoutsDeDemarrage(PROB const int, const int); void OPT_InitialiserLesCoutsLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, const int, const int); +void OPT_InitialiserLesCoutsLineaireReserves(PROBLEME_HEBDO*, const int, const int); void OPT_InitialiserLeSecondMembreDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, int, int); void OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(PROBLEME_HEBDO*); void OPT_DecompteDesVariablesEtDesContraintesReserves(PROBLEME_HEBDO*); diff --git a/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp b/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp index 3595141031..35d1ff6dc3 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp @@ -327,6 +327,8 @@ void OPT_InitialiserLesCoutsLineaire(PROBLEME_HEBDO* problemeHebdo, { OPT_InitialiserLesCoutsLineaireCoutsDeDemarrage( problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); + OPT_InitialiserLesCoutsLineaireReserves( + problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); } return; diff --git a/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp b/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp new file mode 100644 index 0000000000..a811706547 --- /dev/null +++ b/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp @@ -0,0 +1,84 @@ +/* +** 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 . +*/ + +#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" + +#include "variables/VariableManagerUtils.h" +#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_donnees.h" +#include "antares/solver/simulation/sim_extern_variables_globales.h" + +#include "antares/solver/optimisation/opt_fonctions.h" + +void OPT_InitialiserLesCoutsLineaireReserves(PROBLEME_HEBDO* problemeHebdo, + const int PremierPdtDeLIntervalle, + const int DernierPdtDeLIntervalle) +{ + const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; + std::vector& CoutLineaire = ProblemeAResoudre->CoutLineaire; + auto variableManager = VariableManagerFromProblemHebdo(problemeHebdo); + + for (int pdtHebdo = PremierPdtDeLIntervalle; pdtHebdo < DernierPdtDeLIntervalle; + pdtHebdo++) + { + for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) + { + auto reservesDuPays = problemeHebdo->allReserves.thermalAreaReserves[pays]; + + for (int index = 0; index < reservesDuPays.areaCapacityReservationsUp.size(); index++) + { + + int var = variableManager.InternalExcessReserve( + reservesDuPays.areaCapacityReservationsUp[index].globalReserveIndex, pdtHebdo); + if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) + { + CoutLineaire[var] = reservesDuPays.areaCapacityReservationsUp[index].spillageCost; + } + + var = variableManager.InternalUnsatisfiedReserve( + reservesDuPays.areaCapacityReservationsUp[index].globalReserveIndex, pdtHebdo); + if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) + { + CoutLineaire[var] = CoutLineaire[var] + = reservesDuPays.areaCapacityReservationsUp[index].failureCost; + } + } + for (int index = 0; index < reservesDuPays.areaCapacityReservationsDown.size(); index++) + { + int var = variableManager.InternalExcessReserve( + reservesDuPays.areaCapacityReservationsDown[index].globalReserveIndex, pdtHebdo); + if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) + { + CoutLineaire[var] + = reservesDuPays.areaCapacityReservationsDown[index].spillageCost; + } + + var = variableManager.InternalUnsatisfiedReserve( + reservesDuPays.areaCapacityReservationsDown[index].globalReserveIndex, pdtHebdo); + if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) + { + CoutLineaire[var] = CoutLineaire[var] + = reservesDuPays.areaCapacityReservationsDown[index].failureCost; + } + } + } + } +} From 0a91049a239670cf9f3887858322ad46c4aad75b Mon Sep 17 00:00:00 2001 From: sylvmara Date: Thu, 25 Apr 2024 11:43:50 +0200 Subject: [PATCH 16/41] Adding reserve participation costs --- ...truction_variables_reserves_thermiques.cpp | 10 +++--- .../opt_gestion_des_couts_reserves.cpp | 33 +++++++++++++++++-- .../sim_structure_probleme_economique.h | 2 +- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp index 247067aeae..ccd6cef675 100644 --- a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp @@ -53,7 +53,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi int reserveIndex = 0; const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; - for (const auto& areaReserveUp : areaReserves.areaCapacityReservationsUp) + for (auto& areaReserveUp : areaReserves.areaCapacityReservationsUp) { reserveIndex = areaReserveUp.globalReserveIndex; if (!Simulation) @@ -77,7 +77,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi NombreDeVariables += 2; int clusterIndex = 0; - for (const auto& clusterReserveParticipation : + for (auto& clusterReserveParticipation : areaReserveUp.AllReservesParticipation) { if (clusterReserveParticipation.maxPower >= 0) @@ -102,6 +102,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.ParticipationOfUnitsToReserve( NombreDeVariables, clusterName, areaReserveUp.reserveName); + clusterReserveParticipation.indexClusterParticipation = index; index++; clusterIndex++; } @@ -113,7 +114,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi = areaReserveUp.need[pdt]; NombreDeVariables++; } - for (const auto& areaReserveDown : areaReserves.areaCapacityReservationsDown) + for (auto& areaReserveDown : areaReserves.areaCapacityReservationsDown) { reserveIndex = areaReserveDown.globalReserveIndex; if (!Simulation) @@ -137,7 +138,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi NombreDeVariables += 2; int clusterIndex = 0; - for (const auto& clusterReserveParticipation : + for (auto& clusterReserveParticipation : areaReserveDown.AllReservesParticipation) { if (clusterReserveParticipation.maxPower >= 0) @@ -162,6 +163,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.ParticipationOfUnitsToReserve( NombreDeVariables, clusterName, areaReserveDown.reserveName); + clusterReserveParticipation.indexClusterParticipation = index; index++; clusterIndex++; } diff --git a/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp b/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp index a811706547..31ee2577c5 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp @@ -43,10 +43,37 @@ void OPT_InitialiserLesCoutsLineaireReserves(PROBLEME_HEBDO* problemeHebdo, { auto reservesDuPays = problemeHebdo->allReserves.thermalAreaReserves[pays]; + const PALIERS_THERMIQUES& PaliersThermiquesDuPays + = problemeHebdo->PaliersThermiquesDuPays[pays]; + int var; + + + for (int index = 0; index < reservesDuPays.areaCapacityReservationsUp.size(); index++) { - - int var = variableManager.InternalExcessReserve( + for (const auto& clusterReserveParticipation : + reservesDuPays.areaCapacityReservationsUp[index].AllReservesParticipation) + { + if (clusterReserveParticipation.maxPower >= 0) + { + var = variableManager.ClusterReserveParticipation( + clusterReserveParticipation.indexClusterParticipation, + pdtHebdo); + CoutLineaire[var] = clusterReserveParticipation.participationCost; + } + } + for (const auto& clusterReserveParticipation : + reservesDuPays.areaCapacityReservationsDown[index].AllReservesParticipation) + { + if (clusterReserveParticipation.maxPower >= 0) + { + var = variableManager.ClusterReserveParticipation( + clusterReserveParticipation.indexClusterParticipation, pdtHebdo); + CoutLineaire[var] = clusterReserveParticipation.participationCost; + } + } + + var = variableManager.InternalExcessReserve( reservesDuPays.areaCapacityReservationsUp[index].globalReserveIndex, pdtHebdo); if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) { @@ -63,7 +90,7 @@ void OPT_InitialiserLesCoutsLineaireReserves(PROBLEME_HEBDO* problemeHebdo, } for (int index = 0; index < reservesDuPays.areaCapacityReservationsDown.size(); index++) { - int var = variableManager.InternalExcessReserve( + var = variableManager.InternalExcessReserve( reservesDuPays.areaCapacityReservationsDown[index].globalReserveIndex, pdtHebdo); if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) { diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index 9e489dfe23..4d25e10cd2 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -268,7 +268,7 @@ struct RESERVE_PARTICIPATION { float maxPower = CLUSTER_NOT_PARTICIPATING; float participationCost = CLUSTER_NOT_PARTICIPATING; - + int indexClusterParticipation = 0; std::string clusterName; }; From f429eac855df1e85d5914a2ead3e400a48d8bbe5 Mon Sep 17 00:00:00 2001 From: h-fournier Date: Mon, 29 Apr 2024 09:17:39 +0200 Subject: [PATCH 17/41] Fix include --- src/solver/optimisation/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index 37a2a87056..60473a2b9e 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -32,6 +32,7 @@ set(RTESOLVER_OPT opt_construction_variables_couts_demarrages.cpp opt_gestion_des_bornes_couts_demarrage.cpp opt_gestion_des_couts_couts_demarrage.cpp + opt_gestion_des_couts_reserves.cpp opt_gestion_second_membre_couts_demarrage.cpp opt_gestion_second_membre_couts_demarrage.cpp opt_decompte_variables_et_contraintes_couts_demarrage.cpp From 3761e7cc0e1cc467289c51327db85ad8c14e010b Mon Sep 17 00:00:00 2001 From: h-fournier Date: Tue, 30 Apr 2024 17:09:01 +0200 Subject: [PATCH 18/41] Fix variable initialization and counting variables --- ...truction_variables_optimisees_lineaire.cpp | 2 + ...truction_variables_reserves_thermiques.cpp | 91 +++++++++++++------ 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp index 4ba6e760a0..9079e31422 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp @@ -243,6 +243,8 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaire(PROBLEME_HEBD { OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarrage(problemeHebdo, false); + OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermiques(problemeHebdo, + false); } diff --git a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp index ccd6cef675..424dc222f0 100644 --- a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp @@ -38,6 +38,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi = problemeHebdo->NombreDePasDeTempsPourUneOptimisation; int& NombreDeVariables = ProblemeAResoudre->NombreDeVariables; VariableNamer variableNamer(ProblemeAResoudre->NomDesVariables); + auto variableManager = VariableManagerFromProblemHebdo(problemeHebdo); for (int pdt = 0; pdt < NombreDePasDeTempsPourUneOptimisation; pdt++) { @@ -56,25 +57,29 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi for (auto& areaReserveUp : areaReserves.areaCapacityReservationsUp) { reserveIndex = areaReserveUp.globalReserveIndex; - if (!Simulation) + if (Simulation) + { + NombreDeVariables += 2; + } + else { // For Unsatisfied Reserves - CorrespondanceVarNativesVarOptim.internalUnsatisfiedReserveIndex[reserveIndex] + variableManager.InternalUnsatisfiedReserve(reserveIndex, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.InternalUnsatisfiedReserve(NombreDeVariables, areaReserveUp.reserveName); + NombreDeVariables++; // For Excess Reserves - CorrespondanceVarNativesVarOptim.internalExcessReserveIndex[reserveIndex] - = NombreDeVariables; + variableManager.InternalExcessReserve(reserveIndex, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.InternalExcessReserve(NombreDeVariables, areaReserveUp.reserveName); + NombreDeVariables++; } - NombreDeVariables += 2; int clusterIndex = 0; for (auto& clusterReserveParticipation : @@ -84,58 +89,75 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi { const auto& clusterName = PaliersThermiquesDuPays.NomsDesPaliersThermiques[clusterIndex]; - if (!Simulation) + if (Simulation) + { + NombreDeVariables += 2; + } + else { // For running units in cluster - CorrespondanceVarNativesVarOptim - .runningClusterReserveParticipationIndex[index] + variableManager.ClusterReserveParticipation(index, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.ParticipationOfRunningUnitsToReserve( NombreDeVariables, clusterName, areaReserveUp.reserveName); + NombreDeVariables++; // For all units in cluster (off units can participate to the reserves) - CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex[index] + variableManager.RunningClusterReserveParticipation(index, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.ParticipationOfUnitsToReserve( NombreDeVariables, clusterName, areaReserveUp.reserveName); + NombreDeVariables++; + clusterReserveParticipation.indexClusterParticipation = index; index++; clusterIndex++; } - NombreDeVariables += 2; } } - // Need - CorrespondanceVarNativesVarOptim.needReserveIndex[reserveIndex] - = areaReserveUp.need[pdt]; - NombreDeVariables++; + if (Simulation) + { + NombreDeVariables++; + } + else + { + // Need + variableManager.NeedReserve(reserveIndex, pdt) = areaReserveUp.need[pdt]; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + NombreDeVariables++; + } } for (auto& areaReserveDown : areaReserves.areaCapacityReservationsDown) { reserveIndex = areaReserveDown.globalReserveIndex; - if (!Simulation) + if (Simulation) + { + NombreDeVariables += 2; + } + else { // For Unsatisfied Reserves - CorrespondanceVarNativesVarOptim.internalUnsatisfiedReserveIndex[reserveIndex] + variableManager.InternalUnsatisfiedReserve(reserveIndex, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.InternalUnsatisfiedReserve(NombreDeVariables, areaReserveDown.reserveName); + NombreDeVariables++; // For Excess Reserves - CorrespondanceVarNativesVarOptim.internalExcessReserveIndex[reserveIndex] - = NombreDeVariables; + variableManager.InternalExcessReserve(reserveIndex, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.InternalExcessReserve(NombreDeVariables, areaReserveDown.reserveName); + NombreDeVariables++; } - NombreDeVariables += 2; int clusterIndex = 0; for (auto& clusterReserveParticipation : @@ -145,35 +167,48 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi { const auto& clusterName = PaliersThermiquesDuPays.NomsDesPaliersThermiques[clusterIndex]; - if (!Simulation) + if (Simulation) + { + NombreDeVariables += 2; + } + else { // For running units in cluster - CorrespondanceVarNativesVarOptim - .runningClusterReserveParticipationIndex[index] + variableManager.ClusterReserveParticipation(index, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.ParticipationOfRunningUnitsToReserve( NombreDeVariables, clusterName, areaReserveDown.reserveName); + NombreDeVariables++; // For all units in cluster (off units can participate to the reserves) - CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex[index] + variableManager.RunningClusterReserveParticipation(index, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.ParticipationOfUnitsToReserve( NombreDeVariables, clusterName, areaReserveDown.reserveName); + NombreDeVariables++; + clusterReserveParticipation.indexClusterParticipation = index; index++; clusterIndex++; } - NombreDeVariables += 2; } } - // Need - CorrespondanceVarNativesVarOptim.needReserveIndex[reserveIndex] - = areaReserveDown.need[pdt]; - NombreDeVariables++; + if (Simulation) + { + NombreDeVariables++; + } + else + { + // Need + variableManager.NeedReserve(reserveIndex, pdt) = areaReserveDown.need[pdt]; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + NombreDeVariables++; + } } } } From 4de9dc7e1440072e9e949a1b0b5b5a012a4210ee Mon Sep 17 00:00:00 2001 From: h-fournier Date: Mon, 6 May 2024 09:24:01 +0200 Subject: [PATCH 19/41] Fix ClusterParticipationIndex --- ..._construction_variables_reserves_thermiques.cpp | 14 +++++--------- src/solver/simulation/sim_calcul_economique.cpp | 5 +++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp index 424dc222f0..d949c8ca8d 100644 --- a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp @@ -96,7 +96,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi else { // For running units in cluster - variableManager.ClusterReserveParticipation(index, pdt) + variableManager.ClusterReserveParticipation(clusterReserveParticipation.indexClusterParticipation, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; @@ -105,7 +105,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi NombreDeVariables++; // For all units in cluster (off units can participate to the reserves) - variableManager.RunningClusterReserveParticipation(index, pdt) + variableManager.RunningClusterReserveParticipation(clusterReserveParticipation.indexClusterParticipation, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; @@ -113,8 +113,6 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi NombreDeVariables, clusterName, areaReserveUp.reserveName); NombreDeVariables++; - clusterReserveParticipation.indexClusterParticipation = index; - index++; clusterIndex++; } } @@ -128,7 +126,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi // Need variableManager.NeedReserve(reserveIndex, pdt) = areaReserveUp.need[pdt]; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] - = VARIABLE_BORNEE_DES_DEUX_COTES; + = VARIABLE_FIXE; NombreDeVariables++; } } @@ -174,7 +172,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi else { // For running units in cluster - variableManager.ClusterReserveParticipation(index, pdt) + variableManager.ClusterReserveParticipation(clusterReserveParticipation.indexClusterParticipation, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; @@ -183,7 +181,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi NombreDeVariables++; // For all units in cluster (off units can participate to the reserves) - variableManager.RunningClusterReserveParticipation(index, pdt) + variableManager.RunningClusterReserveParticipation(clusterReserveParticipation.indexClusterParticipation, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; @@ -191,8 +189,6 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi NombreDeVariables, clusterName, areaReserveDown.reserveName); NombreDeVariables++; - clusterReserveParticipation.indexClusterParticipation = index; - index++; clusterIndex++; } } diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 2b0bfe6603..686069c64a 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -277,6 +277,7 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, NombrePaliers = 0; int globalReserveIndex = 0; + int globalClusterParticipationIndex = 0; for (uint i = 0; i < study.areas.size(); ++i) { const auto& area = *(study.areas.byIndex[i]); @@ -339,6 +340,8 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, reserveParticipation.maxPower = cluster->reserveMaxPower(key); reserveParticipation.participationCost = cluster->reserveCost(key); reserveParticipation.clusterName = cluster->name(); + reserveParticipation.indexClusterParticipation + = globalClusterParticipationIndex++; areaCapacityReservationsUp.AllReservesParticipation.push_back( reserveParticipation); } @@ -369,6 +372,8 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, reserveParticipation.maxPower = cluster->reserveMaxPower(key); reserveParticipation.participationCost = cluster->reserveCost(key); reserveParticipation.clusterName = cluster->name(); + reserveParticipation.indexClusterParticipation + = globalClusterParticipationIndex++; areaCapacityReservationsDown.AllReservesParticipation.push_back( reserveParticipation); } From 7a6238c4a36367e97984c403930a42e03dae5cea Mon Sep 17 00:00:00 2001 From: sylvmara Date: Mon, 13 May 2024 11:38:25 +0200 Subject: [PATCH 20/41] Correct number of terms for reserve constraints and renaming of variable for more clarity --- src/solver/optimisation/LinearProblemMatrix.cpp | 2 +- src/solver/optimisation/constraints/PMaxReserve.cpp | 2 +- src/solver/optimisation/constraints/POutCapacityThreasholds.cpp | 2 +- src/solver/optimisation/constraints/PRunningUnits.cpp | 2 +- .../opt_construction_variables_optimisees_lineaire.cpp | 2 +- .../optimisation/opt_decompte_variables_et_contraintes.cpp | 2 +- .../opt_decompte_variables_et_contraintes_couts_demarrage.cpp | 2 +- src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp | 2 +- src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp | 2 +- .../optimisation/opt_gestion_second_membre_cas_lineaire.cpp | 2 +- .../optimisation/opt_init_minmax_groupes_couts_demarrage.cpp | 2 +- .../opt_nombre_min_groupes_demarres_couts_demarrage.cpp | 2 +- src/solver/optimisation/opt_optimisation_lineaire.cpp | 2 +- src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp | 2 +- .../solver/simulation/sim_structure_probleme_economique.h | 2 +- src/solver/simulation/sim_calcul_economique.cpp | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/solver/optimisation/LinearProblemMatrix.cpp b/src/solver/optimisation/LinearProblemMatrix.cpp index 044c82c5d6..7c3565ed00 100644 --- a/src/solver/optimisation/LinearProblemMatrix.cpp +++ b/src/solver/optimisation/LinearProblemMatrix.cpp @@ -60,7 +60,7 @@ void LinearProblemMatrix::Run() ProblemMatrixEssential::Run(); - if (problemeHebdo_->OptimisationAvecCoutsDeDemarrage) + if (problemeHebdo_->OptimisationNotFastMode) { LinearProblemMatrixStartUpCosts(problemeHebdo_, false, builder_).Run(); LinearProblemMatrixReserves(problemeHebdo_, false, builder_).Run(); diff --git a/src/solver/optimisation/constraints/PMaxReserve.cpp b/src/solver/optimisation/constraints/PMaxReserve.cpp index b535e6fcbc..99c574b27b 100644 --- a/src/solver/optimisation/constraints/PMaxReserve.cpp +++ b/src/solver/optimisation/constraints/PMaxReserve.cpp @@ -41,7 +41,7 @@ void PMaxReserve::add(int pays, int reserve, int cluster, int pdt, bool isUpRese } else { - builder.data.NbTermesContraintesPourLesReserves += 1; + builder.data.NbTermesContraintesPourLesReserves += 3; builder.data.nombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp index c5cc061a46..d4bf687657 100644 --- a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp +++ b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp @@ -108,7 +108,7 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) + countReservesFromCluster( data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown); - builder.data.NbTermesContraintesPourLesReserves += 2*nbConstraintsToAdd; + builder.data.NbTermesContraintesPourLesReserves += 2*(nbConstraintsToAdd+2); builder.data.nombreDeContraintes += 2*nbConstraintsToAdd; } diff --git a/src/solver/optimisation/constraints/PRunningUnits.cpp b/src/solver/optimisation/constraints/PRunningUnits.cpp index f6c5b24b6a..8544ab893a 100644 --- a/src/solver/optimisation/constraints/PRunningUnits.cpp +++ b/src/solver/optimisation/constraints/PRunningUnits.cpp @@ -40,7 +40,7 @@ void PRunningUnits::add(int pays, int reserve, int cluster, int pdt, bool isUpRe } else { - builder.data.NbTermesContraintesPourLesReserves += 1; + builder.data.NbTermesContraintesPourLesReserves += 2; builder.data.nombreDeContraintes++; } } diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp index 9079e31422..6c7c3ad989 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp @@ -239,7 +239,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaire(PROBLEME_HEBD ProblemeAResoudre->NombreDeVariables = NombreDeVariables; - if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) + if (problemeHebdo->OptimisationNotFastMode) { OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarrage(problemeHebdo, false); diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp index eb180bd780..e3fb409495 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp @@ -253,7 +253,7 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* //Reserves //OPT_DecompteDesVariablesEtDesContraintesReserves(problemeHebdo); - if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) + if (problemeHebdo->OptimisationNotFastMode) { OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(problemeHebdo); OPT_DecompteDesVariablesEtDesContraintesReserves(problemeHebdo); diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp index 6560d0f12f..2bb954ed10 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp @@ -28,7 +28,7 @@ void OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(PROBLEME_HEBDO* problemeHebdo) { - if (!problemeHebdo->OptimisationAvecCoutsDeDemarrage) + if (!problemeHebdo->OptimisationNotFastMode) return; auto builder_data = NewGetConstraintBuilderFromProblemHebdo(problemeHebdo); diff --git a/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp b/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp index ef2a8cb706..a6930263ce 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp @@ -489,7 +489,7 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob } } - if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) + if (problemeHebdo->OptimisationNotFastMode) { OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireCoutsDeDemarrage( problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); diff --git a/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp b/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp index 35d1ff6dc3..f713d5a5a3 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp @@ -323,7 +323,7 @@ void OPT_InitialiserLesCoutsLineaire(PROBLEME_HEBDO* problemeHebdo, } } - if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) + if (problemeHebdo->OptimisationNotFastMode) { OPT_InitialiserLesCoutsLineaireCoutsDeDemarrage( problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); diff --git a/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp b/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp index 63c5c7a7e4..6d5bcf3e46 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp @@ -361,7 +361,7 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaire(PROBLEME_HEBDO* problemeHeb } } - if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) + if (problemeHebdo->OptimisationNotFastMode) { OPT_InitialiserLeSecondMembreDuProblemeLineaireCoutsDeDemarrage( problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); diff --git a/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp b/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp index b47d74e8bf..2d2d6bc116 100644 --- a/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp @@ -27,7 +27,7 @@ void OPT_InitialiserNombreMinEtMaxDeGroupesCoutsDeDemarrage(PROBLEME_HEBDO* problemeHebdo) { - if (!problemeHebdo->OptimisationAvecCoutsDeDemarrage) + if (!problemeHebdo->OptimisationNotFastMode) return; for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) diff --git a/src/solver/optimisation/opt_nombre_min_groupes_demarres_couts_demarrage.cpp b/src/solver/optimisation/opt_nombre_min_groupes_demarres_couts_demarrage.cpp index c29938a455..0a91eaec92 100644 --- a/src/solver/optimisation/opt_nombre_min_groupes_demarres_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_nombre_min_groupes_demarres_couts_demarrage.cpp @@ -50,7 +50,7 @@ void OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBL void OPT_AjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO* problemeHebdo) { - if (!problemeHebdo->OptimisationAvecCoutsDeDemarrage) + if (!problemeHebdo->OptimisationNotFastMode) return; int NombreDePasDeTempsProblemeHebdo = problemeHebdo->NombreDePasDeTemps; diff --git a/src/solver/optimisation/opt_optimisation_lineaire.cpp b/src/solver/optimisation/opt_optimisation_lineaire.cpp index 8702657ed7..a2c93a740f 100644 --- a/src/solver/optimisation/opt_optimisation_lineaire.cpp +++ b/src/solver/optimisation/opt_optimisation_lineaire.cpp @@ -119,7 +119,7 @@ bool runWeeklyOptimization(const OptimizationOptions& options, void runThermalHeuristic(PROBLEME_HEBDO* problemeHebdo) { - if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) + if (problemeHebdo->OptimisationNotFastMode) { OPT_AjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(problemeHebdo); } diff --git a/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp b/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp index 507c8bfac3..e127cd13a3 100644 --- a/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp +++ b/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp @@ -71,7 +71,7 @@ bool OPT_PilotageOptimisationLineaire(const OptimizationOptions& options, OPT_MaxDesPmaxHydrauliques(problemeHebdo); - if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) + if (problemeHebdo->OptimisationNotFastMode) { OPT_InitialiserNombreMinEtMaxDeGroupesCoutsDeDemarrage(problemeHebdo); } diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index 4d25e10cd2..60f411f740 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -524,7 +524,7 @@ struct PROBLEME_HEBDO bool OptimisationAuPasHebdomadaire = false; char TypeDeLissageHydraulique = PAS_DE_LISSAGE_HYDRAULIQUE; bool WaterValueAccurate = false; - bool OptimisationAvecCoutsDeDemarrage = false; + bool OptimisationNotFastMode = false; bool OptimisationAvecVariablesEntieres = false; uint32_t NombreDePays = 0; std::vector NomsDesPays; diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 686069c64a..17710883e1 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -116,7 +116,7 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, problem.solverLogs = study.parameters.solverLogs; problem.exportMPSOnError = Data::exportMPS(parameters.include.unfeasibleProblemBehavior); - problem.OptimisationAvecCoutsDeDemarrage + problem.OptimisationNotFastMode = (study.parameters.unitCommitment.ucMode != Antares::Data::UnitCommitmentMode::ucHeuristicFast); From 367032458a9fac9af656af6923aa20e9ef526225 Mon Sep 17 00:00:00 2001 From: h-fournier Date: Mon, 13 May 2024 16:25:30 +0200 Subject: [PATCH 21/41] Add NeedReserve name using the variableNamer --- .../include/antares/solver/optimisation/opt_rename_problem.h | 1 + .../opt_construction_variables_reserves_thermiques.cpp | 2 ++ src/solver/optimisation/opt_rename_problem.cpp | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h index e3f3773f62..6bf34dcc58 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h @@ -94,6 +94,7 @@ class VariableNamer : public Namer const std::string& reserveName); void InternalUnsatisfiedReserve(unsigned int variable, const std::string& reserveName); void InternalExcessReserve(unsigned int variable, const std::string& reserveName); + void NeedReserve(unsigned int variable, const std::string& reserveName); void NODU(unsigned int variable, const std::string& clusterName); void NumberStoppingDispatchableUnits(unsigned int variable, const std::string& clusterName); void NumberStartingDispatchableUnits(unsigned int variable, const std::string& clusterName); diff --git a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp index d949c8ca8d..a1853aa7d0 100644 --- a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp @@ -127,6 +127,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi variableManager.NeedReserve(reserveIndex, pdt) = areaReserveUp.need[pdt]; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_FIXE; + variableNamer.NeedReserve(NombreDeVariables, areaReserveUp.reserveName); NombreDeVariables++; } } @@ -203,6 +204,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi variableManager.NeedReserve(reserveIndex, pdt) = areaReserveDown.need[pdt]; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.NeedReserve(NombreDeVariables, areaReserveDown.reserveName); NombreDeVariables++; } } diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index 6d6149afc9..0469d9c540 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -144,6 +144,11 @@ void VariableNamer::InternalExcessReserve(unsigned int variable, const std::stri SetThermalClusterReserveElementName(variable, "InternalExcessReserve", reserveName); } +void VariableNamer::NeedReserve(unsigned int variable, const std::string& reserveName) +{ + SetThermalClusterReserveElementName(variable, "NeedReserve", reserveName); +} + void VariableNamer::NODU(unsigned int variable, const std::string& clusterName) { SetThermalClusterElementName(variable, "NODU", clusterName); From f3096b32200d0518f8c1afc25bb06ffe2c0e0f02 Mon Sep 17 00:00:00 2001 From: h-fournier Date: Mon, 13 May 2024 17:32:51 +0200 Subject: [PATCH 22/41] Fix counting nbTermes for equation 24 --- .../constraints/ReserveSatisfaction.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp index bab9178622..3c413eff49 100644 --- a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp +++ b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp @@ -47,7 +47,21 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) } else { - builder.data.NbTermesContraintesPourLesReserves += 4; + CAPACITY_RESERVATION capacityReservation + = isUpReserve + ? data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp[reserve] + : data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown[reserve]; + + int nbTermes = 0; + for (size_t cluster = 0; cluster < capacityReservation.AllReservesParticipation.size(); + cluster++) + { + if (capacityReservation.AllReservesParticipation[cluster].maxPower + != CLUSTER_NOT_PARTICIPATING) + nbTermes++; + } + + builder.data.NbTermesContraintesPourLesReserves += 3 + nbTermes; builder.data.nombreDeContraintes += 1; } From 85f3dcd5489a13c98818b5e4d035b28644445a4b Mon Sep 17 00:00:00 2001 From: h-fournier Date: Wed, 15 May 2024 16:06:55 +0200 Subject: [PATCH 23/41] Multiple fixes - Change NeedReserve from a fixed variable to the right hand side of the constraint equation - Complete the boundaries for all variables - Call the initialization of the boundaries - Fix some construction of constraints (remove the if when not needed) --- src/solver/optimisation/CMakeLists.txt | 3 +- .../constraints/ConstraintBuilder.cpp | 10 --- .../optimisation/constraints/PMaxReserve.cpp | 19 ++-- .../constraints/POutCapacityThreasholds.cpp | 29 ++++--- .../constraints/PRunningUnits.cpp | 17 ++-- .../constraints/ReserveParticipationGroup.cpp | 4 +- .../constraints/ReserveSatisfaction.cpp | 46 +++++----- .../constraints/ConstraintBuilder.h | 6 +- .../solver/optimisation/opt_fonctions.h | 4 + .../solver/optimisation/opt_rename_problem.h | 2 +- ...truction_variables_reserves_thermiques.cpp | 26 ------ .../opt_gestion_des_bornes_cas_lineaire.cpp | 2 + ...gestion_des_bornes_reserves_thermiques.cpp | 31 +++++-- ...opt_gestion_second_membre_cas_lineaire.cpp | 2 + .../opt_gestion_second_membre_reserves.cpp | 87 +++++++++++++++++++ .../optimisation/opt_rename_problem.cpp | 12 +-- .../variables/VariableManagement.cpp | 10 --- .../variables/VariableManagement.h | 5 -- .../sim_structure_probleme_economique.h | 3 +- .../simulation/sim_alloc_probleme_hebdo.cpp | 6 +- 20 files changed, 191 insertions(+), 133 deletions(-) create mode 100644 src/solver/optimisation/opt_gestion_second_membre_reserves.cpp diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index 60473a2b9e..9e04cb2732 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -31,10 +31,11 @@ set(RTESOLVER_OPT opt_gestion_des_couts_cas_quadratique.cpp opt_construction_variables_couts_demarrages.cpp opt_gestion_des_bornes_couts_demarrage.cpp + opt_gestion_des_bornes_reserves_thermiques.cpp opt_gestion_des_couts_couts_demarrage.cpp opt_gestion_des_couts_reserves.cpp opt_gestion_second_membre_couts_demarrage.cpp - opt_gestion_second_membre_couts_demarrage.cpp + opt_gestion_second_membre_reserves.cpp opt_decompte_variables_et_contraintes_couts_demarrage.cpp opt_decompte_variables_et_contraintes_reserves.cpp opt_init_minmax_groupes_couts_demarrage.cpp diff --git a/src/solver/optimisation/constraints/ConstraintBuilder.cpp b/src/solver/optimisation/constraints/ConstraintBuilder.cpp index 0b1c6b020c..1a8a272ad7 100644 --- a/src/solver/optimisation/constraints/ConstraintBuilder.cpp +++ b/src/solver/optimisation/constraints/ConstraintBuilder.cpp @@ -76,16 +76,6 @@ ConstraintBuilder& ConstraintBuilder::InternalUnsatisfiedReserve(unsigned int in return *this; } -ConstraintBuilder& ConstraintBuilder::NeedReserve(unsigned int index, - double coeff, - int offset, - int delta) -{ - AddVariable(variableManager_.NeedReserve(index, hourInWeek_, offset, delta), - coeff); - return *this; -} - ConstraintBuilder& ConstraintBuilder::InternalExcessReserve(unsigned int index, double coeff, int offset, diff --git a/src/solver/optimisation/constraints/PMaxReserve.cpp b/src/solver/optimisation/constraints/PMaxReserve.cpp index 99c574b27b..c3ab59e3c6 100644 --- a/src/solver/optimisation/constraints/PMaxReserve.cpp +++ b/src/solver/optimisation/constraints/PMaxReserve.cpp @@ -27,21 +27,18 @@ void PMaxReserve::add(int pays, int reserve, int cluster, int pdt, bool isUpRese .NumberOfDispatchableUnits(globalClusterIdx, -reserveParticipation.maxPower) .lessThan(); - if (builder.NumberOfVariables() > 0) - { - ConstraintNamer namer(builder.data.NomDesContraintes); - const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; - namer.UpdateTimeStep(hourInTheYear); - namer.UpdateArea(builder.data.NomsDesPays[pays]); - namer.PMaxReserve(builder.data.nombreDeContraintes, - reserveParticipation.clusterName, - capacityReservation.reserveName); - } + ConstraintNamer namer(builder.data.NomDesContraintes); + const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; + namer.UpdateTimeStep(hourInTheYear); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + namer.PMaxReserve(builder.data.nombreDeContraintes, + reserveParticipation.clusterName, + capacityReservation.reserveName); builder.build(); } else { - builder.data.NbTermesContraintesPourLesReserves += 3; + builder.data.NbTermesContraintesPourLesReserves += 2; builder.data.nombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp index d4bf687657..47547dd9bf 100644 --- a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp +++ b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp @@ -19,10 +19,7 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) // 17 bis (1) : l * M + Sum(P^on_re-) - P <= 0 { - builder.updateHourWithinWeek(pdt) - .NumberOfDispatchableUnits( - globalClusterIdx, data.thermalClusters[pays].pminDUnGroupeDuPalierThermique[cluster]) - .DispatchableProduction(globalClusterIdx, -1); + builder.updateHourWithinWeek(pdt); for (const auto& capacityReservation : data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown) @@ -35,10 +32,14 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) } } - builder.lessThan(); - if (builder.NumberOfVariables() > 0) { + builder + .NumberOfDispatchableUnits( + globalClusterIdx, + data.thermalClusters[pays].pminDUnGroupeDuPalierThermique[cluster]) + .DispatchableProduction(globalClusterIdx, -1) + .lessThan(); ConstraintNamer namer(builder.data.NomDesContraintes); const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; namer.UpdateTimeStep(hourInTheYear); @@ -46,16 +47,13 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) namer.POutCapacityThreasholdInf( builder.data.nombreDeContraintes, data.thermalClusters[pays].NomsDesPaliersThermiques[cluster]); + builder.build(); } - builder.build(); } // 17 bis (2) : P - u * M + Sum(P^on_re+) <= 0 { - builder.updateHourWithinWeek(pdt) - .DispatchableProduction(globalClusterIdx, 1) - .NumberOfDispatchableUnits( - globalClusterIdx, -data.thermalClusters[pays].PmaxDUnGroupeDuPalierThermique[cluster]); + builder.updateHourWithinWeek(pdt); for (const auto& capacityReservation : data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp) @@ -68,10 +66,14 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) } } - builder.lessThan(); - if (builder.NumberOfVariables() > 0) { + builder.DispatchableProduction(globalClusterIdx, 1) + .NumberOfDispatchableUnits( + globalClusterIdx, + -data.thermalClusters[pays].PmaxDUnGroupeDuPalierThermique[cluster]) + .lessThan() + .build(); ConstraintNamer namer(builder.data.NomDesContraintes); const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; namer.UpdateTimeStep(hourInTheYear); @@ -80,7 +82,6 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) builder.data.nombreDeContraintes, data.thermalClusters[pays].NomsDesPaliersThermiques[cluster]); } - builder.build(); } } else diff --git a/src/solver/optimisation/constraints/PRunningUnits.cpp b/src/solver/optimisation/constraints/PRunningUnits.cpp index 8544ab893a..399a3beaed 100644 --- a/src/solver/optimisation/constraints/PRunningUnits.cpp +++ b/src/solver/optimisation/constraints/PRunningUnits.cpp @@ -26,16 +26,13 @@ void PRunningUnits::add(int pays, int reserve, int cluster, int pdt, bool isUpRe .ClusterReserveParticipation(globalClusterIdx, -1.0) .equalTo(); - if (builder.NumberOfVariables() > 0) - { - ConstraintNamer namer(builder.data.NomDesContraintes); - const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; - namer.UpdateTimeStep(hourInTheYear); - namer.UpdateArea(builder.data.NomsDesPays[pays]); - namer.PMaxReserve(builder.data.nombreDeContraintes, - reserveParticipation.clusterName, - capacityReservation.reserveName); - } + ConstraintNamer namer(builder.data.NomDesContraintes); + const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; + namer.UpdateTimeStep(hourInTheYear); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + namer.ParticipationOfRunningUnitsToReserve(builder.data.nombreDeContraintes, + reserveParticipation.clusterName, + capacityReservation.reserveName); builder.build(); } else diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp index 7416a07b76..2abe15270c 100644 --- a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -35,7 +35,9 @@ ReserveData ReserveParticipationGroup::GetReserveDataFromProblemHebdo() { return {.Simulation = simulation_, .areaReserves = problemeHebdo_->allReserves, - .thermalClusters = problemeHebdo_->PaliersThermiquesDuPays}; + .thermalClusters = problemeHebdo_->PaliersThermiquesDuPays, + .CorrespondanceCntNativesCntOptim = problemeHebdo_->CorrespondanceCntNativesCntOptim + }; } /** diff --git a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp index 3c413eff49..375869ed78 100644 --- a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp +++ b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp @@ -2,24 +2,28 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) { + CAPACITY_RESERVATION capacityReservation + = isUpReserve + ? data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp[reserve] + : data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown[reserve]; + + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesDeBesoinEnReserves[capacityReservation.globalReserveIndex] + = -1; if (!data.Simulation) { // 24 // Sum(P_θ) = S + J^+ -J^- // P_θ : Participation power from cluster θ to the reserve res - // S : Internal reserve res need for the area + // S : Internal reserve res need for the area (second membre) // J^+ : Amount of internal excess reserve for the reserve res // J^- : Amount of internal unsatified reserve for the reserve res builder.updateHourWithinWeek(pdt); - CAPACITY_RESERVATION capacityReservation - = isUpReserve - ? data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp[reserve] - : data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown[reserve]; - - for (size_t cluster = 0; cluster < capacityReservation.AllReservesParticipation.size(); cluster++) + for (size_t cluster = 0; cluster < capacityReservation.AllReservesParticipation.size(); + cluster++) { if (capacityReservation.AllReservesParticipation[cluster].maxPower != CLUSTER_NOT_PARTICIPATING) builder.RunningClusterReserveParticipation( @@ -27,31 +31,27 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) .NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster], 1); } - builder.InternalUnsatisfiedReserve(capacityReservation.globalReserveIndex, 1); - builder.InternalExcessReserve(capacityReservation.globalReserveIndex, -1); - builder.NeedReserve(capacityReservation.globalReserveIndex, -1); - - builder.equalTo(); if (builder.NumberOfVariables() > 0) { + builder.InternalUnsatisfiedReserve(capacityReservation.globalReserveIndex, 1) + .InternalExcessReserve(capacityReservation.globalReserveIndex, -1) + .equalTo(); + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesDeBesoinEnReserves[capacityReservation + .globalReserveIndex] + = builder.data.nombreDeContraintes; ConstraintNamer namer(builder.data.NomDesContraintes); const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; namer.UpdateTimeStep(hourInTheYear); namer.UpdateArea(builder.data.NomsDesPays[pays]); - namer.ReserveSatisfaction( - builder.data.nombreDeContraintes, - capacityReservation.reserveName); + namer.ReserveSatisfaction(builder.data.nombreDeContraintes, + capacityReservation.reserveName); + builder.build(); } - builder.build(); } else { - CAPACITY_RESERVATION capacityReservation - = isUpReserve - ? data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp[reserve] - : data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown[reserve]; - int nbTermes = 0; for (size_t cluster = 0; cluster < capacityReservation.AllReservesParticipation.size(); cluster++) @@ -61,8 +61,8 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) nbTermes++; } - builder.data.NbTermesContraintesPourLesReserves += 3 + nbTermes; + builder.data.NbTermesContraintesPourLesReserves += nbTermes ? 2 + nbTermes : 0; - builder.data.nombreDeContraintes += 1; + builder.data.nombreDeContraintes += nbTermes ? 1 : 0; } } diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h index c6ffd9a413..ac9d331544 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h @@ -116,11 +116,6 @@ class ConstraintBuilder int offset = 0, int delta = 0); - ConstraintBuilder& NeedReserve(unsigned int pays, - double coeff, - int offset = 0, - int delta = 0); - ConstraintBuilder& InternalExcessReserve(unsigned int pays, double coeff, int offset = 0, @@ -312,4 +307,5 @@ struct ReserveData bool Simulation; ALL_AREA_RESERVES& areaReserves; std::vector thermalClusters; + std::vector& CorrespondanceCntNativesCntOptim; }; \ No newline at end of file diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h index 91b71abf0c..74650ca39c 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h @@ -115,9 +115,13 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, const int, const int); +void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques(PROBLEME_HEBDO*, + const int, + const int); void OPT_InitialiserLesCoutsLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, const int, const int); void OPT_InitialiserLesCoutsLineaireReserves(PROBLEME_HEBDO*, const int, const int); void OPT_InitialiserLeSecondMembreDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, int, int); +void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO*, int, int); void OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(PROBLEME_HEBDO*); void OPT_DecompteDesVariablesEtDesContraintesReserves(PROBLEME_HEBDO*); void OPT_InitialiserNombreMinEtMaxDeGroupesCoutsDeDemarrage(PROBLEME_HEBDO*); diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h index 6bf34dcc58..5b20c1b5c9 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h @@ -94,7 +94,6 @@ class VariableNamer : public Namer const std::string& reserveName); void InternalUnsatisfiedReserve(unsigned int variable, const std::string& reserveName); void InternalExcessReserve(unsigned int variable, const std::string& reserveName); - void NeedReserve(unsigned int variable, const std::string& reserveName); void NODU(unsigned int variable, const std::string& clusterName); void NumberStoppingDispatchableUnits(unsigned int variable, const std::string& clusterName); void NumberStartingDispatchableUnits(unsigned int variable, const std::string& clusterName); @@ -157,6 +156,7 @@ class ConstraintNamer : public Namer void NbDispUnitsMinBoundSinceMinUpTime(unsigned int constraint, const std::string& clusterName); void MinDownTime(unsigned int constraint, const std::string& clusterName); void PMaxReserve(unsigned int constraint, const std::string& clusterName, const std::string& reserveName); + void ParticipationOfRunningUnitsToReserve(unsigned int constraint, const std::string& clusterName, const std::string& reserveName); void POutCapacityThreasholdInf(unsigned int constraint, const std::string& clusterName); void POutCapacityThreasholdSup(unsigned int constraint, const std::string& clusterName); void ReserveSatisfaction(unsigned int constraint, const std::string& reserveName); diff --git a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp index a1853aa7d0..3cf810aab9 100644 --- a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp @@ -117,19 +117,6 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi } } } - if (Simulation) - { - NombreDeVariables++; - } - else - { - // Need - variableManager.NeedReserve(reserveIndex, pdt) = areaReserveUp.need[pdt]; - ProblemeAResoudre->TypeDeVariable[NombreDeVariables] - = VARIABLE_FIXE; - variableNamer.NeedReserve(NombreDeVariables, areaReserveUp.reserveName); - NombreDeVariables++; - } } for (auto& areaReserveDown : areaReserves.areaCapacityReservationsDown) { @@ -194,19 +181,6 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi } } } - if (Simulation) - { - NombreDeVariables++; - } - else - { - // Need - variableManager.NeedReserve(reserveIndex, pdt) = areaReserveDown.need[pdt]; - ProblemeAResoudre->TypeDeVariable[NombreDeVariables] - = VARIABLE_BORNEE_DES_DEUX_COTES; - variableNamer.NeedReserve(NombreDeVariables, areaReserveDown.reserveName); - NombreDeVariables++; - } } } } diff --git a/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp b/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp index a6930263ce..71c5e1d323 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp @@ -493,6 +493,8 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob { OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireCoutsDeDemarrage( problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); + OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( + problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); } return; diff --git a/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp index 71bf8f484f..201995730d 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp @@ -51,36 +51,51 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( = problemeHebdo->PaliersThermiquesDuPays[pays]; auto areaReserves = problemeHebdo->allReserves.thermalAreaReserves[pays]; - int index = 0; for (const auto& areaReserveUp : areaReserves.areaCapacityReservationsUp) { + int var = CorrespondanceVarNativesVarOptim + .internalUnsatisfiedReserveIndex[areaReserveUp.globalReserveIndex]; + Xmin[var] = 0; + Xmax[var] = LINFINI_ANTARES; + + var = CorrespondanceVarNativesVarOptim + .internalExcessReserveIndex[areaReserveUp.globalReserveIndex]; + Xmin[var] = 0; + Xmax[var] = LINFINI_ANTARES; + for (const auto& clusterReserveParticipation : areaReserveUp.AllReservesParticipation) { if (clusterReserveParticipation.maxPower >= 0) { - int var = CorrespondanceVarNativesVarOptim - .clusterReserveUpParticipationIndex[index]; + var = CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex + [clusterReserveParticipation.indexClusterParticipation]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; } - index++; } } - index = 0; for (const auto& areaReserveDown : areaReserves.areaCapacityReservationsUp) { + int var = CorrespondanceVarNativesVarOptim + .internalUnsatisfiedReserveIndex[areaReserveDown.globalReserveIndex]; + Xmin[var] = 0; + Xmax[var] = LINFINI_ANTARES; + + var = CorrespondanceVarNativesVarOptim + .internalExcessReserveIndex[areaReserveDown.globalReserveIndex]; + Xmin[var] = 0; + Xmax[var] = LINFINI_ANTARES; for (const auto& clusterReserveParticipation : areaReserveDown.AllReservesParticipation) { if (clusterReserveParticipation.maxPower >= 0) { - int var = CorrespondanceVarNativesVarOptim - .clusterReserveUpParticipationIndex[index]; + var = CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex + [clusterReserveParticipation.indexClusterParticipation]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; } - index++; } } } diff --git a/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp b/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp index 6d5bcf3e46..e079ce4bc8 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp @@ -365,6 +365,8 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaire(PROBLEME_HEBDO* problemeHeb { OPT_InitialiserLeSecondMembreDuProblemeLineaireCoutsDeDemarrage( problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); + OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves( + problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); } return; diff --git a/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp b/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp new file mode 100644 index 0000000000..931fe61eb2 --- /dev/null +++ b/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp @@ -0,0 +1,87 @@ +/* +** 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 . +*/ + +#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" + +#include "antares/solver/simulation/sim_structure_donnees.h" +#include "antares/solver/simulation/sim_extern_variables_globales.h" + +#include "antares/solver/optimisation/opt_fonctions.h" + +#include + +using namespace Antares; +using namespace Antares::Data; +using namespace Yuni; + +void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO* problemeHebdo, + int PremierPdtDeLIntervalle, + int DernierPdtDeLIntervalle) +{ + const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; + std::vector& SecondMembre = ProblemeAResoudre->SecondMembre; + + std::vector& AdresseOuPlacerLaValeurDesCoutsMarginaux + = ProblemeAResoudre->AdresseOuPlacerLaValeurDesCoutsMarginaux; + + auto& areaReserves = problemeHebdo->allReserves; + + for (int pdtJour = 0, pdtHebdo = PremierPdtDeLIntervalle; pdtHebdo < DernierPdtDeLIntervalle; + pdtHebdo++, pdtJour++) + { + const CORRESPONDANCES_DES_CONTRAINTES& CorrespondanceCntNativesCntOptim + = problemeHebdo->CorrespondanceCntNativesCntOptim[pdtJour]; + + for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) + { + auto areaReservesUp = areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp; + for (const auto& areaReserveUp : areaReservesUp) + { + int cnt + = CorrespondanceCntNativesCntOptim + .NumeroDeContrainteDesContraintesDeBesoinEnReserves[areaReserveUp + .globalReserveIndex]; + if (cnt >= 0) + { + SecondMembre[cnt] = areaReserveUp.need.at(pdtJour); + AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; + } + } + + auto areaReservesDown + = areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown; + for (const auto& areaReserveDown : areaReservesDown) + { + int cnt + = CorrespondanceCntNativesCntOptim + .NumeroDeContrainteDesContraintesDeBesoinEnReserves[areaReserveDown + .globalReserveIndex]; + if (cnt >= 0) + { + SecondMembre[cnt] = areaReserveDown.need.at(pdtJour); + AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; + } + } + } + } + + return; +} diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index 0469d9c540..c537829556 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -144,11 +144,6 @@ void VariableNamer::InternalExcessReserve(unsigned int variable, const std::stri SetThermalClusterReserveElementName(variable, "InternalExcessReserve", reserveName); } -void VariableNamer::NeedReserve(unsigned int variable, const std::string& reserveName) -{ - SetThermalClusterReserveElementName(variable, "NeedReserve", reserveName); -} - void VariableNamer::NODU(unsigned int variable, const std::string& clusterName) { SetThermalClusterElementName(variable, "NODU", clusterName); @@ -398,6 +393,13 @@ void ConstraintNamer::PMaxReserve(unsigned int constraint, SetThermalClusterAndReserveElementName(constraint, "PMaxReserve", clusterName, reserveName); } +void ConstraintNamer::ParticipationOfRunningUnitsToReserve(unsigned int constraint, + const std::string& clusterName, + const std::string& reserveName) +{ + SetThermalClusterAndReserveElementName(constraint, "ParticipationOfRunningUnitsToReserve", clusterName, reserveName); +} + void ConstraintNamer::POutCapacityThreasholdInf(unsigned int constraint, const std::string& clusterName) { diff --git a/src/solver/optimisation/variables/VariableManagement.cpp b/src/solver/optimisation/variables/VariableManagement.cpp index 0adb3e6446..340633ec04 100644 --- a/src/solver/optimisation/variables/VariableManagement.cpp +++ b/src/solver/optimisation/variables/VariableManagement.cpp @@ -83,16 +83,6 @@ int& VariableManager::InternalExcessReserve(unsigned int index, return CorrespondanceVarNativesVarOptim_[pdt].internalExcessReserveIndex[index]; } -int& VariableManager::NeedReserve(unsigned int index, - unsigned int hourInWeek, - int offset, - int delta) -{ - auto pdt = GetShiftedTimeStep(offset, delta, hourInWeek); - - return CorrespondanceVarNativesVarOptim_[pdt].needReserveIndex[index]; -} - int& VariableManager::NumberOfDispatchableUnits(unsigned int index, unsigned int hourInWeek, int offset, diff --git a/src/solver/optimisation/variables/VariableManagement.h b/src/solver/optimisation/variables/VariableManagement.h index fb201d4ab6..1c989885b3 100644 --- a/src/solver/optimisation/variables/VariableManagement.h +++ b/src/solver/optimisation/variables/VariableManagement.h @@ -42,11 +42,6 @@ class VariableManager int offset = 0, int delta = 0); - int& NeedReserve(unsigned int index, - unsigned int hourInWeek, - int offset = 0, - int delta = 0); - int& NumberOfDispatchableUnits(unsigned int index, unsigned int hourInWeek, int offset = 0, diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index 60f411f740..22bfebf05e 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -49,7 +49,6 @@ struct CORRESPONDANCES_DES_VARIABLES std::vector clusterReserveParticipationIndex; std::vector internalUnsatisfiedReserveIndex; std::vector internalExcessReserveIndex; - std::vector needReserveIndex; std::vector NumeroDeVariablesDeLaProdHyd; @@ -98,6 +97,8 @@ struct CORRESPONDANCES_DES_CONTRAINTES std::vector NumeroDeContrainteDesContraintesDeDureeMinDArret; std::vector NumeroDeLaDeuxiemeContrainteDesContraintesDesGroupesQuiTombentEnPanne; + std::vector NumeroDeContrainteDesContraintesDeBesoinEnReserves; + std::vector NumeroDeContrainteDesNiveauxPays; std::vector ShortTermStorageLevelConstraint; diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index b40751351e..1373841e7e 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -181,8 +181,6 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, .assign(study.runtime->capacityReservationCount, 0); variablesMapping.internalExcessReserveIndex .assign(study.runtime->capacityReservationCount, 0); - variablesMapping.needReserveIndex - .assign(study.runtime->capacityReservationCount, 0); variablesMapping.NumeroDeVariableDuPalierThermique .assign(study.runtime->thermalPlantTotalCount, 0); @@ -247,6 +245,10 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, .NumeroDeContrainteDesContraintesDeDureeMinDArret .assign(study.runtime->thermalPlantTotalCount, 0); + problem.CorrespondanceCntNativesCntOptim[k] + .NumeroDeContrainteDesContraintesDeBesoinEnReserves.assign( + study.runtime->capacityReservationCount, 0); + problem.CorrespondanceCntNativesCntOptim[k] .NumeroDeLaDeuxiemeContrainteDesContraintesDesGroupesQuiTombentEnPanne .assign(study.runtime->thermalPlantTotalCount, 0); From 6f1163315d842a15ffb177d257b1494e6b7bdbfd Mon Sep 17 00:00:00 2001 From: h-fournier Date: Wed, 15 May 2024 17:11:08 +0200 Subject: [PATCH 24/41] Fix missing a max boundary initialization Looks like reserves are working with on a small test --- .../opt_gestion_des_bornes_reserves_thermiques.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp index 201995730d..71c052d8f4 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp @@ -68,6 +68,11 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( { if (clusterReserveParticipation.maxPower >= 0) { + var = CorrespondanceVarNativesVarOptim.runningClusterReserveParticipationIndex + [clusterReserveParticipation.indexClusterParticipation]; + Xmin[var] = 0; + Xmax[var] = LINFINI_ANTARES; + var = CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex [clusterReserveParticipation.indexClusterParticipation]; Xmin[var] = 0; @@ -75,7 +80,7 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( } } } - for (const auto& areaReserveDown : areaReserves.areaCapacityReservationsUp) + for (const auto& areaReserveDown : areaReserves.areaCapacityReservationsDown) { int var = CorrespondanceVarNativesVarOptim .internalUnsatisfiedReserveIndex[areaReserveDown.globalReserveIndex]; @@ -91,6 +96,11 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( { if (clusterReserveParticipation.maxPower >= 0) { + var = CorrespondanceVarNativesVarOptim.runningClusterReserveParticipationIndex + [clusterReserveParticipation.indexClusterParticipation]; + Xmin[var] = 0; + Xmax[var] = LINFINI_ANTARES; + var = CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex [clusterReserveParticipation.indexClusterParticipation]; Xmin[var] = 0; From df309845c51c6a1d10a9312beaf91a8494f9a168 Mon Sep 17 00:00:00 2001 From: h-fournier Date: Thu, 16 May 2024 12:21:45 +0200 Subject: [PATCH 25/41] Work on retrocompatibility --- src/libs/antares/study/area/list.cpp | 106 +++++++++--------- .../study/parts/common/cluster_list.cpp | 2 +- 2 files changed, 55 insertions(+), 53 deletions(-) diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index 9419716cdd..ea3e6f210b 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -848,72 +848,74 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, { buffer.clear() << study.folderInput << SEP << "reserves" << SEP << area.id << SEP << "reserves.ini"; - if (!ini.open(buffer)) + if (ini.open(buffer, false)) { - logs.warning() << study.folderInput << SEP << "reserves" << SEP << area.id << SEP - << "reserves.ini"; - return false; - } - ini.each( - [&](const IniFile::Section& section) - { - if (area.allCapacityReservations.contains(section.name)) + ini.each( + [&](const IniFile::Section& section) { - logs.warning() << area.name << ": reserve name already exists for reserve " - << section.name; - } - else - { - CapacityReservation tmpCapacityReservation; - std::string file_name = AllCapacityReservations::toFilename(section.name); - int type = -1; - for (auto* p = section.firstProperty; p; p = p->next) + if (area.allCapacityReservations.contains(section.name)) { - CString<30, false> tmp; - tmp = p->key; - tmp.toLower(); - - if (tmp == "failure-cost") + logs.warning() << area.name << ": reserve name already exists for reserve " + << section.name; + } + else + { + CapacityReservation tmpCapacityReservation; + std::string file_name = AllCapacityReservations::toFilename(section.name); + int type = -1; + for (auto* p = section.firstProperty; p; p = p->next) { - if (!p->value.to(tmpCapacityReservation.failureCost)) + CString<30, false> tmp; + tmp = p->key; + tmp.toLower(); + + if (tmp == "failure-cost") { - logs.warning() << area.name << ": invalid failure cost for reserve " - << section.name; + if (!p->value.to(tmpCapacityReservation.failureCost)) + { + logs.warning() + << area.name << ": invalid failure cost for reserve " + << section.name; + } } - } - else if (tmp == "spillage-cost") - { - if (!p->value.to(tmpCapacityReservation.spillageCost)) + else if (tmp == "spillage-cost") { - logs.warning() << area.name << ": invalid spillage cost for reserve " - << section.name; + if (!p->value.to(tmpCapacityReservation.spillageCost)) + { + logs.warning() + << area.name << ": invalid spillage cost for reserve " + << section.name; + } + } + else if (tmp == "type") + { + if (p->value == "up") + type = 0; + else if (p->value == "down") + type = 1; + else + logs.warning() + << area.name << ": invalid type for reserve " << section.name; } - } - else if (tmp == "type") - { - if (p->value == "up") - type = 0; - else if (p->value == "down") - type = 1; else logs.warning() - << area.name << ": invalid type for reserve " << section.name; + << area.name << ": invalid key " << tmp << " in file " << buffer; } + buffer.clear() << study.folderInput << SEP << "reserves" << SEP << area.id + << SEP << file_name << ".txt"; + ret = tmpCapacityReservation.need.loadFromFile(buffer, false) && ret; + if (type == 0) + area.allCapacityReservations.areaCapacityReservationsUp.emplace( + section.name, tmpCapacityReservation); + else if (type == 1) + area.allCapacityReservations.areaCapacityReservationsDown.emplace( + section.name, tmpCapacityReservation); else logs.warning() - << area.name << ": invalid key " << tmp << " in file " << buffer; + << area.name << ": invalid type for reserve " << section.name; } - buffer.clear() << study.folderInput << SEP << "reserves" << SEP << area.id << SEP - << file_name << ".txt"; - ret = tmpCapacityReservation.need.loadFromFile(buffer, false) && ret; - if (type == 0) - area.allCapacityReservations.areaCapacityReservationsUp.emplace(section.name, tmpCapacityReservation); - else if (type == 1) - area.allCapacityReservations.areaCapacityReservationsDown.emplace(section.name, tmpCapacityReservation); - else - logs.warning() << area.name << ": invalid type for reserve " << section.name; - } - }); + }); + } } // Solar diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index ca6ca4df35..a66e66d207 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -272,7 +272,7 @@ template bool ClusterList::loadReserveParticipations(Area& area, const AnyString& file) { IniFile ini; - if (!ini.open(file)) + if (!ini.open(file, false)) return false; ini.each( [&](const IniFile::Section& section) From ebbaa11d60c38582a445f91fb3ab48d837442d59 Mon Sep 17 00:00:00 2001 From: h-fournier Date: Fri, 17 May 2024 11:15:35 +0200 Subject: [PATCH 26/41] Add constraint 17 ter : Power output is bounded by must-run commitments and power availability, reserves must fit within the bounds --- src/solver/optimisation/CMakeLists.txt | 2 + .../optimisation/constraints/POutBounds.cpp | 123 ++++++++++++++++++ .../constraints/POutCapacityThreasholds.cpp | 4 +- .../constraints/ReserveParticipationGroup.cpp | 4 + .../optimisation/constraints/POutBounds.h | 25 ++++ .../constraints/ReserveParticipationGroup.h | 1 + .../solver/optimisation/opt_rename_problem.h | 2 + .../opt_gestion_second_membre_reserves.cpp | 25 ++++ .../optimisation/opt_rename_problem.cpp | 10 ++ .../sim_structure_probleme_economique.h | 2 + .../simulation/sim_alloc_probleme_hebdo.cpp | 6 + 11 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 src/solver/optimisation/constraints/POutBounds.cpp create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/constraints/POutBounds.h diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index 9e04cb2732..3d70e406f0 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -134,6 +134,8 @@ set(RTESOLVER_OPT constraints/PMaxReserve.cpp include/antares/solver/optimisation/constraints/POutCapacityThreasholds.h constraints/POutCapacityThreasholds.cpp + include/antares/solver/optimisation/constraints/POutBounds.h + constraints/POutBounds.cpp include/antares/solver/optimisation/constraints/PRunningUnits.h constraints/PRunningUnits.cpp include/antares/solver/optimisation/constraints/ReserveSatisfaction.h diff --git a/src/solver/optimisation/constraints/POutBounds.cpp b/src/solver/optimisation/constraints/POutBounds.cpp new file mode 100644 index 0000000000..fcde27cd91 --- /dev/null +++ b/src/solver/optimisation/constraints/POutBounds.cpp @@ -0,0 +1,123 @@ +#include "antares/solver/optimisation/constraints/POutBounds.h" + +void POutBounds::add(int pays, int cluster, int pdt) +{ + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[cluster] + = -1; + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[cluster] + = -1; + + if (!data.Simulation) + { + // 17 ter + // Power output is bounded by must-run commitments and power availability, reserves must fit within the bounds + // P_down + Sum(P^on_re-) <= P <= P_up - Sum(P^on_re+) + // P^on_re- : Participation of running units in cluster θ to Down reserves + // P^on_re+ : Participation of running units in cluster θ to Up reserves + // P : Power output from cluster θ + // P_down : Minimal power output demanded from cluster θ + // P_up : Maximal power output from cluster θ + + int globalClusterIdx + = data.thermalClusters[pays].NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; + + // 17 ter (1) : Sum(P^on_re-) - P <= - P_down + { + builder.updateHourWithinWeek(pdt); + + for (const auto& capacityReservation : + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown) + { + for (const auto& reserveParticipations : + capacityReservation.AllReservesParticipation) + { + if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + builder.RunningClusterReserveParticipation(globalClusterIdx, 1); + } + } + + if (builder.NumberOfVariables() > 0) + { + builder.DispatchableProduction(globalClusterIdx, -1).lessThan(); + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[cluster] + = builder.data.nombreDeContraintes; + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[cluster] + = builder.data.nombreDeContraintes; + ConstraintNamer namer(builder.data.NomDesContraintes); + const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; + namer.UpdateTimeStep(hourInTheYear); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + namer.POutBoundMin(builder.data.nombreDeContraintes, + data.thermalClusters[pays].NomsDesPaliersThermiques[cluster]); + builder.build(); + } + } + + // 17 ter (2) : P + Sum(P^on_re+) <= P_up + { + builder.updateHourWithinWeek(pdt); + + for (const auto& capacityReservation : + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp) + { + for (const auto& reserveParticipations : + capacityReservation.AllReservesParticipation) + { + if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + builder.RunningClusterReserveParticipation(globalClusterIdx, 1); + } + } + + if (builder.NumberOfVariables() > 0) + { + builder.DispatchableProduction(globalClusterIdx, 1).lessThan(); + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[cluster] + = builder.data.nombreDeContraintes; + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[cluster] + = builder.data.nombreDeContraintes; + ConstraintNamer namer(builder.data.NomDesContraintes); + const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; + namer.UpdateTimeStep(hourInTheYear); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + namer.POutBoundMax(builder.data.nombreDeContraintes, + data.thermalClusters[pays].NomsDesPaliersThermiques[cluster]); + builder.build(); + } + } + } + else + { + // Lambda that count the number of reserves that the cluster is participating to + auto countReservesFromCluster + = [cluster](const std::vector& reservations) + { + int counter = 0; + for (const auto& capacityReservation : reservations) + { + for (const auto& reserveParticipations : + capacityReservation.AllReservesParticipation) + { + if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + counter++; + } + } + return counter; + }; + + int nbConstraintsToAdd + = countReservesFromCluster( + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp) + + countReservesFromCluster( + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown); + + builder.data.NbTermesContraintesPourLesReserves += 2 * (nbConstraintsToAdd + 1); + + builder.data.nombreDeContraintes += 2 * nbConstraintsToAdd; + } +} diff --git a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp index 47547dd9bf..0110ff97de 100644 --- a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp +++ b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp @@ -72,8 +72,7 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) .NumberOfDispatchableUnits( globalClusterIdx, -data.thermalClusters[pays].PmaxDUnGroupeDuPalierThermique[cluster]) - .lessThan() - .build(); + .lessThan(); ConstraintNamer namer(builder.data.NomDesContraintes); const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; namer.UpdateTimeStep(hourInTheYear); @@ -81,6 +80,7 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) namer.POutCapacityThreasholdSup( builder.data.nombreDeContraintes, data.thermalClusters[pays].NomsDesPaliersThermiques[cluster]); + builder.build(); } } } diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp index 2abe15270c..ee5fa42776 100644 --- a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -112,6 +112,7 @@ void ReserveParticipationGroup::BuildConstraints() { auto data = GetReserveDataFromProblemHebdo(); POutCapacityThreasholds pOutCapacityThreasholds(builder_, data); + POutBounds pOutBounds(builder_, data); for (int pdt = 0; pdt < problemeHebdo_->NombreDePasDeTempsPourUneOptimisation; pdt++) { @@ -124,6 +125,9 @@ void ReserveParticipationGroup::BuildConstraints() { // 17 bis pOutCapacityThreasholds.add(pays, cluster, pdt); + + // 17 ter + pOutBounds.add(pays, cluster, pdt); } } } diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/POutBounds.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/POutBounds.h new file mode 100644 index 0000000000..479dc5464c --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/POutBounds.h @@ -0,0 +1,25 @@ +#pragma once +#include "ConstraintBuilder.h" + +/* + * represent 'POutBounds' Constraint type + */ +class POutBounds : private ConstraintFactory +{ +public: + POutBounds(ConstraintBuilder& builder, ReserveData& data) : + ConstraintFactory(builder), data(data) + { + } + + /*! + * @brief Add variables to the constraint and update constraints Matrix + * @param pays : area + * @param cluster : global index of the cluster + * @param pdt : timestep + */ + void add(int pays, int cluster, int pdt); + +private: + ReserveData& data; +}; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h index 68de88187c..f247195021 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ReserveParticipationGroup.h @@ -26,6 +26,7 @@ #include "POutCapacityThreasholds.h" #include "PRunningUnits.h" #include "ReserveSatisfaction.h" +#include "POutBounds.h" /** * @brief Group of reserve constraints diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h index 5b20c1b5c9..3d13831a8a 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h @@ -159,6 +159,8 @@ class ConstraintNamer : public Namer void ParticipationOfRunningUnitsToReserve(unsigned int constraint, const std::string& clusterName, const std::string& reserveName); void POutCapacityThreasholdInf(unsigned int constraint, const std::string& clusterName); void POutCapacityThreasholdSup(unsigned int constraint, const std::string& clusterName); + void POutBoundMin(unsigned int constraint, const std::string& clusterName); + void POutBoundMax(unsigned int constraint, const std::string& clusterName); void ReserveSatisfaction(unsigned int constraint, const std::string& reserveName); void PMaxDispatchableGeneration(unsigned int constraint, const std::string& clusterName); void PMinDispatchableGeneration(unsigned int constraint, const std::string& clusterName); diff --git a/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp b/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp index 931fe61eb2..44f9482fff 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp @@ -80,6 +80,31 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO* pro AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; } } + + for (uint32_t cluster = 0; + cluster < problemeHebdo->PaliersThermiquesDuPays[pays].NombreDePaliersThermiques; + cluster++) + { + int cnt1 = CorrespondanceCntNativesCntOptim + .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[cluster]; + if (cnt1 >= 0) + { + SecondMembre[cnt1] = problemeHebdo->PaliersThermiquesDuPays[pays] + .PuissanceDisponibleEtCout[cluster] + .PuissanceMinDuPalierThermiqueRef[pdtJour]; + AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt1] = nullptr; + } + + int cnt2 = CorrespondanceCntNativesCntOptim + .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[cluster]; + if (cnt2 >= 0) + { + SecondMembre[cnt2] = problemeHebdo->PaliersThermiquesDuPays[pays] + .PuissanceDisponibleEtCout[cluster] + .PuissanceDisponibleDuPalierThermiqueRef[pdtJour]; + AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt2] = nullptr; + } + } } } diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index c537829556..f9cd394be0 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -412,6 +412,16 @@ void ConstraintNamer::POutCapacityThreasholdSup(unsigned int constraint, SetThermalClusterElementName(constraint, "POutCapacityThreasholdSup", clusterName); } +void ConstraintNamer::POutBoundMin(unsigned int constraint, const std::string& clusterName) +{ + SetThermalClusterElementName(constraint, "POutBoundMin", clusterName); +} + +void ConstraintNamer::POutBoundMax(unsigned int constraint, const std::string& clusterName) +{ + SetThermalClusterElementName(constraint, "POutBoundMax", clusterName); +} + void ConstraintNamer::ReserveSatisfaction(unsigned int constraint, const std::string& reserveName) { SetThermalClusterReserveElementName(constraint, "ReserveSatisfaction", reserveName); diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index 22bfebf05e..ee840a6d7c 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -98,6 +98,8 @@ struct CORRESPONDANCES_DES_CONTRAINTES std::vector NumeroDeLaDeuxiemeContrainteDesContraintesDesGroupesQuiTombentEnPanne; std::vector NumeroDeContrainteDesContraintesDeBesoinEnReserves; + std::vector NumeroDeContrainteDesContraintesDePuissanceMinDuPalier; + std::vector NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier; std::vector NumeroDeContrainteDesNiveauxPays; diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index 1373841e7e..eef00a4601 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -248,6 +248,12 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, problem.CorrespondanceCntNativesCntOptim[k] .NumeroDeContrainteDesContraintesDeBesoinEnReserves.assign( study.runtime->capacityReservationCount, 0); + problem.CorrespondanceCntNativesCntOptim[k] + .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier.assign( + study.runtime->thermalPlantTotalCount, 0); + problem.CorrespondanceCntNativesCntOptim[k] + .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier.assign( + study.runtime->thermalPlantTotalCount, 0); problem.CorrespondanceCntNativesCntOptim[k] .NumeroDeLaDeuxiemeContrainteDesContraintesDesGroupesQuiTombentEnPanne From 1d7dbcd04e533208d8f707c58e54db471a50c4cc Mon Sep 17 00:00:00 2001 From: h-fournier Date: Wed, 29 May 2024 09:49:19 +0200 Subject: [PATCH 27/41] Add Reserve cost : - Per cluster - Add reserve participation cost to operationnal cost - Add unsatisfied and excess reserves cost to overall cost --- .../antares/study/area/capacityReservation.h | 6 + .../antares/study/parts/common/cluster.h | 3 + .../antares/study/parts/common/cluster.cpp | 10 + .../constraints/ReserveSatisfaction.cpp | 37 +- ...gestion_des_bornes_reserves_thermiques.cpp | 48 +++ .../sim_structure_probleme_economique.h | 8 + .../simulation/sim_alloc_probleme_hebdo.cpp | 11 + src/solver/variable/CMakeLists.txt | 2 + .../antares/solver/variable/economy/all.h | 16 +- .../solver/variable/economy/overallCost.h | 26 +- .../economy/reserveParticipationCost.h | 295 +++++++++++++++ ...erveParticipationCostByDispatchablePlant.h | 339 ++++++++++++++++++ .../include/antares/solver/variable/state.h | 4 + .../include/antares/solver/variable/state.hxx | 6 + src/solver/variable/state.cpp | 45 +++ 15 files changed, 830 insertions(+), 26 deletions(-) create mode 100644 src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCost.h create mode 100644 src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h diff --git a/src/libs/antares/study/include/antares/study/area/capacityReservation.h b/src/libs/antares/study/include/antares/study/area/capacityReservation.h index 08161c6b2f..8ebc0d774b 100644 --- a/src/libs/antares/study/include/antares/study/area/capacityReservation.h +++ b/src/libs/antares/study/include/antares/study/area/capacityReservation.h @@ -72,6 +72,12 @@ struct AllCapacityReservations return std::nullopt; } + /// @brief Get the number of capacityReservations in the area + /// @return the number of capacityReservations in the area + size_t size(){ + return areaCapacityReservationsUp.size() + areaCapacityReservationsDown.size(); + } + /// @brief Returns lower case, no space string /// @param name /// @return A string usable for file naming diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster.h b/src/libs/antares/study/include/antares/study/parts/common/cluster.h index 9b6eae15b0..9bbdbfb17b 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster.h @@ -143,6 +143,9 @@ class Cluster //! \brief Returns true if cluster participates in a reserve with this name bool isParticipatingInReserve(std::string name); + //! \brief Returns an array of all reserves the cluster is participating in + std::vector listOfParticipatingReserves(); + //! \brief Returns max power for a reserve if participating, -1 otherwise float reserveMaxPower(std::string name); diff --git a/src/libs/antares/study/parts/common/cluster.cpp b/src/libs/antares/study/parts/common/cluster.cpp index ae8f757671..33267b8f00 100644 --- a/src/libs/antares/study/parts/common/cluster.cpp +++ b/src/libs/antares/study/parts/common/cluster.cpp @@ -160,5 +160,15 @@ bool CompareClusterName::operator()(const Cluster* s1, const Cluster* s2) const return (s1->getFullName() < s2->getFullName()); } +std::vector Cluster::listOfParticipatingReserves() +{ + std::vector reserves; + for (auto reserve: clusterReservesParticipations) + { + reserves.push_back(reserve.first); + } + return reserves; +} + } // namespace Antares::Data diff --git a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp index 375869ed78..5320e68894 100644 --- a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp +++ b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp @@ -18,7 +18,7 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) // P_θ : Participation power from cluster θ to the reserve res // S : Internal reserve res need for the area (second membre) // J^+ : Amount of internal excess reserve for the reserve res - // J^- : Amount of internal unsatified reserve for the reserve res + // J^- : Amount of internal unsatisfied reserve for the reserve res builder.updateHourWithinWeek(pdt); @@ -32,23 +32,20 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) 1); } - if (builder.NumberOfVariables() > 0) - { - builder.InternalUnsatisfiedReserve(capacityReservation.globalReserveIndex, 1) - .InternalExcessReserve(capacityReservation.globalReserveIndex, -1) - .equalTo(); - data.CorrespondanceCntNativesCntOptim[pdt] - .NumeroDeContrainteDesContraintesDeBesoinEnReserves[capacityReservation - .globalReserveIndex] - = builder.data.nombreDeContraintes; - ConstraintNamer namer(builder.data.NomDesContraintes); - const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; - namer.UpdateTimeStep(hourInTheYear); - namer.UpdateArea(builder.data.NomsDesPays[pays]); - namer.ReserveSatisfaction(builder.data.nombreDeContraintes, - capacityReservation.reserveName); - builder.build(); - } + builder.InternalUnsatisfiedReserve(capacityReservation.globalReserveIndex, 1) + .InternalExcessReserve(capacityReservation.globalReserveIndex, -1) + .equalTo(); + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesDeBesoinEnReserves[capacityReservation + .globalReserveIndex] + = builder.data.nombreDeContraintes; + ConstraintNamer namer(builder.data.NomDesContraintes); + const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; + namer.UpdateTimeStep(hourInTheYear); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + namer.ReserveSatisfaction(builder.data.nombreDeContraintes, + capacityReservation.reserveName); + builder.build(); } else { @@ -61,8 +58,8 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) nbTermes++; } - builder.data.NbTermesContraintesPourLesReserves += nbTermes ? 2 + nbTermes : 0; + builder.data.NbTermesContraintesPourLesReserves += 2 + nbTermes; - builder.data.nombreDeContraintes += nbTermes ? 1 : 0; + builder.data.nombreDeContraintes += 1; } } diff --git a/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp index 71c052d8f4..301f6f40ab 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp @@ -39,6 +39,9 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( std::vector& Xmin = ProblemeAResoudre->Xmin; std::vector& Xmax = ProblemeAResoudre->Xmax; + std::vector& AdresseOuPlacerLaValeurDesVariablesOptimisees + = ProblemeAResoudre->AdresseOuPlacerLaValeurDesVariablesOptimisees; + for (int pdtHebdo = PremierPdtDeLIntervalle, pdtJour = 0; pdtHebdo < DernierPdtDeLIntervalle; pdtHebdo++, pdtJour++) { @@ -57,11 +60,21 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( .internalUnsatisfiedReserveIndex[areaReserveUp.globalReserveIndex]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; + double* adresseDuResultat1 + = &(problemeHebdo->ResultatsHoraires[pays] + .ReserveThermique[pdtHebdo] + .ValeursHorairesInternalUnsatisfied[areaReserveUp.globalReserveIndex]); + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat1; var = CorrespondanceVarNativesVarOptim .internalExcessReserveIndex[areaReserveUp.globalReserveIndex]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; + double* adresseDuResultat2 + = &(problemeHebdo->ResultatsHoraires[pays] + .ReserveThermique[pdtHebdo] + .ValeursHorairesInternalExcessReserve[areaReserveUp.globalReserveIndex]); + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat2; for (const auto& clusterReserveParticipation : areaReserveUp.AllReservesParticipation) @@ -72,11 +85,23 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( [clusterReserveParticipation.indexClusterParticipation]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; + double* adresseDuResultat3 + = &(problemeHebdo->ResultatsHoraires[pays] + .ProductionThermique[pdtHebdo] + .ParticipationReservesDuPalier[clusterReserveParticipation + .indexClusterParticipation]); + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat3; var = CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex [clusterReserveParticipation.indexClusterParticipation]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; + double* adresseDuResultat4 + = &(problemeHebdo->ResultatsHoraires[pays] + .ProductionThermique[pdtHebdo] + .ParticipationReservesDuPalier[clusterReserveParticipation + .indexClusterParticipation]); + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat4; } } } @@ -86,11 +111,22 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( .internalUnsatisfiedReserveIndex[areaReserveDown.globalReserveIndex]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; + double* adresseDuResultat1 + = &(problemeHebdo->ResultatsHoraires[pays] + .ReserveThermique[pdtHebdo] + .ValeursHorairesInternalUnsatisfied[areaReserveDown.globalReserveIndex]); + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat1; var = CorrespondanceVarNativesVarOptim .internalExcessReserveIndex[areaReserveDown.globalReserveIndex]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; + double* adresseDuResultat2 + = &(problemeHebdo->ResultatsHoraires[pays] + .ReserveThermique[pdtHebdo] + .ValeursHorairesInternalExcessReserve[areaReserveDown.globalReserveIndex]); + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat2; + for (const auto& clusterReserveParticipation : areaReserveDown.AllReservesParticipation) { @@ -100,11 +136,23 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( [clusterReserveParticipation.indexClusterParticipation]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; + double* adresseDuResultat3 + = &(problemeHebdo->ResultatsHoraires[pays] + .ProductionThermique[pdtHebdo] + .ParticipationReservesDuPalier[clusterReserveParticipation + .indexClusterParticipation]); + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat3; var = CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex [clusterReserveParticipation.indexClusterParticipation]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; + double* adresseDuResultat4 + = &(problemeHebdo->ResultatsHoraires[pays] + .ProductionThermique[pdtHebdo] + .ParticipationReservesDuPalier[clusterReserveParticipation + .indexClusterParticipation]); + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat4; } } } diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index ee840a6d7c..cc55ef7dbf 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -449,6 +449,7 @@ struct RESERVE_JMOINS1 struct PRODUCTION_THERMIQUE_OPTIMALE { std::vector ProductionThermiqueDuPalier; + std::vector ParticipationReservesDuPalier; std::vector ProductionThermiqueDuPalierUp; std::vector ProductionThermiqueDuPalierDown; @@ -461,6 +462,12 @@ struct PRODUCTION_THERMIQUE_OPTIMALE std::vector NombreDeGroupesQuiTombentEnPanneDuPalier; }; +struct RESERVE_THERMIQUE +{ + std::vector ValeursHorairesInternalUnsatisfied; + std::vector ValeursHorairesInternalExcessReserve; +}; + struct RESULTATS_HORAIRES { std::vector ValeursHorairesDeDefaillancePositive; @@ -490,6 +497,7 @@ struct RESULTATS_HORAIRES std::vector CoutsMarginauxHoraires; std::vector ProductionThermique; // index is pdtHebdo + std::vector ReserveThermique; std::vector<::ShortTermStorage::RESULTS> ShortTermStorage; }; diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index eef00a4601..4beb31ccdc 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -363,6 +363,8 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, for (unsigned k = 0; k < nbPays; k++) { const uint nbPaliers = study.areas.byIndex[k]->thermal.list.enabledAndNotMustRunCount(); + const uint nbReserveParticipations = study.areas.byIndex[k]->thermal.list.reserveParticipationsCount(); + const uint nbReserves = study.areas.byIndex[k]->allCapacityReservations.size(); problem.PaliersThermiquesDuPays[k].minUpDownTime.assign(nbPaliers, 0); problem.PaliersThermiquesDuPays[k].PminDuPalierThermiquePendantUneHeure @@ -471,6 +473,7 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, problem.PaliersThermiquesDuPays[k].PuissanceDisponibleEtCout.resize(nbPaliers); problem.ResultatsHoraires[k].ProductionThermique.resize(NombreDePasDeTemps); + problem.ResultatsHoraires[k].ReserveThermique.resize(NombreDePasDeTemps); for (unsigned j = 0; j < nbPaliers; ++j) { @@ -507,6 +510,8 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, { problem.ResultatsHoraires[k].ProductionThermique[j].ProductionThermiqueDuPalier .assign(nbPaliers, 0.); + problem.ResultatsHoraires[k].ProductionThermique[j].ParticipationReservesDuPalier + .assign(nbReserveParticipations, 0.); problem.ResultatsHoraires[k].ProductionThermique[j].ProductionThermiqueDuPalierUp .assign(nbPaliers, 0.); problem.ResultatsHoraires[k].ProductionThermique[j].ProductionThermiqueDuPalierDown @@ -520,6 +525,12 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, problem.ResultatsHoraires[k].ProductionThermique[j] .NombreDeGroupesQuiTombentEnPanneDuPalier .assign(nbPaliers, 0.); + problem.ResultatsHoraires[k] + .ReserveThermique[j] + .ValeursHorairesInternalUnsatisfied.assign(nbReserves, 0.); + problem.ResultatsHoraires[k] + .ReserveThermique[j] + .ValeursHorairesInternalExcessReserve.assign(nbReserves, 0.); } // Short term storage results const unsigned long nbShortTermStorage = study.areas.byIndex[k]->shortTermStorage.count(); diff --git a/src/solver/variable/CMakeLists.txt b/src/solver/variable/CMakeLists.txt index a396bfb80e..84ad89be0f 100644 --- a/src/solver/variable/CMakeLists.txt +++ b/src/solver/variable/CMakeLists.txt @@ -127,6 +127,8 @@ set(SRC_VARIABLE_ECONOMY include/antares/solver/variable/economy/lolp.h include/antares/solver/variable/economy/avail-dispatchable-generation.h include/antares/solver/variable/economy/dispatchable-generation-margin.h + include/antares/solver/variable/economy/reserveParticipationCost.h + include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h # Links include/antares/solver/variable/economy/links/flowLinear.h diff --git a/src/solver/variable/include/antares/solver/variable/economy/all.h b/src/solver/variable/include/antares/solver/variable/economy/all.h index ef061493b5..20b56d744c 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/all.h +++ b/src/solver/variable/include/antares/solver/variable/economy/all.h @@ -60,6 +60,7 @@ #include "spilledEnergyAfterCSR.h" #include "dtgMarginAfterCsr.h" #include "spilledEnergy.h" +#include "reserveParticipationCost.h" #include "lold.h" #include "lolp.h" @@ -73,6 +74,7 @@ #include "npCostByDispatchablePlant.h" #include "nbOfDispatchedUnitsByPlant.h" #include "profitByPlant.h" +#include "reserveParticipationCostByDispatchablePlant.h" // By RES plant #include "productionByRenewablePlant.h" @@ -168,9 +170,11 @@ typedef // Prices >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VariablesPerArea; /*! @@ -260,12 +264,14 @@ typedef // Prices // Number Of Dispatched Units Common::SpatialAggregate< - NbOfDispatchedUnits // MBO + NbOfDispatchedUnits, // MBO // 25/02/2016 // - // refs: // #55 - >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + Common:: + SpatialAggregate>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VariablesPerSetOfAreas; typedef BindingConstMarginCost< // Marginal cost for a binding constraint diff --git a/src/solver/variable/include/antares/solver/variable/economy/overallCost.h b/src/solver/variable/include/antares/solver/variable/economy/overallCost.h index 9dda9bd190..ae1f2a3171 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/overallCost.h +++ b/src/solver/variable/include/antares/solver/variable/economy/overallCost.h @@ -242,7 +242,7 @@ class OverallCost : public Variable::IVariable, NextT, VCardO void hourForEachArea(State& state, unsigned int numSpace) { - const double costForSpilledOrUnsuppliedEnergy = + double costForSpilledOrUnsuppliedEnergy = // Total UnsupliedEnergy emissions (state.hourlyResults->ValeursHorairesDeDefaillancePositive[state.hourInTheWeek] * state.area->thermal.unsuppliedEnergyCost) @@ -254,6 +254,30 @@ class OverallCost : public Variable::IVariable, NextT, VCardO - state.area->hydro.pumpingEfficiency * state.hourlyResults->PompageHoraire[state.hourInTheWeek])); + for (const auto& thermalReserves : state.problemeHebdo->allReserves.thermalAreaReserves) + { + for (const auto& reserveUp : thermalReserves.areaCapacityReservationsUp) + { + costForSpilledOrUnsuppliedEnergy + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalUnsatisfied[reserveUp.globalReserveIndex] + * reserveUp.failureCost + + state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalExcessReserve[reserveUp.globalReserveIndex] + * reserveUp.spillageCost; + } + for (const auto& reserveDown : thermalReserves.areaCapacityReservationsDown) + { + costForSpilledOrUnsuppliedEnergy + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalUnsatisfied[reserveDown.globalReserveIndex] + * reserveDown.failureCost + + state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalExcessReserve[reserveDown.globalReserveIndex] + * reserveDown.spillageCost; + } + } + pValuesForTheCurrentYear[numSpace][state.hourInTheYear] += costForSpilledOrUnsuppliedEnergy; // Incrementing annual system cost (to be printed in output into a separate file) diff --git a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCost.h b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCost.h new file mode 100644 index 0000000000..53b64d7308 --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCost.h @@ -0,0 +1,295 @@ +/* +** 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 +*/ +#ifndef __SOLVER_VARIABLE_ECONOMY_ReserveParticipationCost_H__ +#define __SOLVER_VARIABLE_ECONOMY_ReserveParticipationCost_H__ + +#include "../variable.h" + +namespace Antares +{ +namespace Solver +{ +namespace Variable +{ +namespace Economy +{ +struct VCardReserveParticipationCost +{ + //! Caption + static std::string Caption() + { + return "RESERVE PARTICIPATION COST"; + } + //! Unit + static std::string Unit() + { + return "Euro"; + } + + //! The short description of the variable + static std::string Description() + { + return "Reserve Participation Cost throughout all MC years, of all the thermal dispatchable " + "clusters"; + } + + //! The expecte results + typedef Results>>>, + R::AllYears::Average // The + > + ResultsType; + + //! The VCard to look for for calculating spatial aggregates + typedef VCardReserveParticipationCost VCardForSpatialAggregate; + + enum + { + //! Data Level + categoryDataLevel = Category::area, + //! File level (provided by the type of the results) + categoryFileLevel = ResultsType::categoryFile & (Category::id | Category::va), + //! Precision (views) + precision = Category::all, + //! Indentation (GUI) + nodeDepthForGUI = +0, + //! Decimal precision + decimal = 0, + //! Number of columns used by the variable (One ResultsType per column) + columnCount = 1, + //! The Spatial aggregation + spatialAggregate = Category::spatialAggregateSum, + spatialAggregateMode = Category::spatialAggregateEachYear, + spatialAggregatePostProcessing = 0, + //! Intermediate values + hasIntermediateValues = 1, + //! Can this variable be non applicable (0 : no, 1 : yes) + isPossiblyNonApplicable = 0, + }; + + typedef IntermediateValues IntermediateValuesBaseType; + typedef IntermediateValues* IntermediateValuesType; + + typedef IntermediateValuesBaseType* IntermediateValuesTypeForSpatialAg; + +}; // class VCard + +/*! +** \brief C02 Average value of the overrall OperatingCost emissions expected from all +** the thermal dispatchable clusters +*/ +template +class ReserveParticipationCost + : public Variable::IVariable, NextT, VCardReserveParticipationCost> +{ +public: + //! Type of the next static variable + typedef NextT NextType; + //! VCard + typedef VCardReserveParticipationCost VCardType; + //! Ancestor + typedef Variable::IVariable, NextT, VCardType> AncestorType; + + //! List of expected results + typedef typename VCardType::ResultsType ResultsType; + + typedef VariableAccessor VariableAccessorType; + + enum + { + //! How many items have we got + count = 1 + NextT::count, + }; + + template + struct Statistics + { + enum + { + count + = ((VCardType::categoryDataLevel & CDataLevel && VCardType::categoryFileLevel & CFile) + ? (NextType::template Statistics::count + + VCardType::columnCount * ResultsType::count) + : NextType::template Statistics::count), + }; + }; + +public: + ~ReserveParticipationCost() + { + delete[] pValuesForTheCurrentYear; + } + + void initializeFromStudy(Data::Study& study) + { + pNbYearsParallel = study.maxNbYearsInParallel; + + InitializeResultsFromStudy(AncestorType::pResults, study); + + pValuesForTheCurrentYear = new VCardType::IntermediateValuesBaseType[pNbYearsParallel]; + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + pValuesForTheCurrentYear[numSpace].initializeFromStudy(study); + + // Next + NextType::initializeFromStudy(study); + } + + template + static void InitializeResultsFromStudy(R& results, Data::Study& study) + { + VariableAccessorType::InitializeAndReset(results, study); + } + + void initializeFromArea(Data::Study* study, Data::Area* area) + { + // Next + NextType::initializeFromArea(study, area); + } + + void initializeFromLink(Data::Study* study, Data::AreaLink* link) + { + // Next + NextType::initializeFromAreaLink(study, link); + } + + void simulationBegin() + { + // Next + NextType::simulationBegin(); + } + + void simulationEnd() + { + NextType::simulationEnd(); + } + + void yearBegin(unsigned int year, unsigned int numSpace) + { + // Reset the values for the current year + pValuesForTheCurrentYear[numSpace].reset(); + // Next variable + NextType::yearBegin(year, numSpace); + } + + void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) + { + // Get end year calculations + for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + ++i) + { + pValuesForTheCurrentYear[numSpace][i] + += state.thermalClusterReserveParticipationCostForYear[i]; + } + + // Next variable + NextType::yearEndBuildForEachThermalCluster(state, year, numSpace); + } + + void yearEndBuild(State& state, unsigned int year) + { + // Next variable + NextType::yearEndBuild(state, year); + } + + void yearEnd(unsigned int year, unsigned int numSpace) + { + // Compute all statistics for the current year (daily,weekly,monthly) + pValuesForTheCurrentYear[numSpace].computeStatisticsForTheCurrentYear(); + + // Next variable + NextType::yearEnd(year, numSpace); + } + + void computeSummary(std::map& numSpaceToYear, + unsigned int nbYearsForCurrentSummary) + { + for (unsigned int numSpace = 0; numSpace < nbYearsForCurrentSummary; ++numSpace) + { + // Merge all those values with the global results + AncestorType::pResults.merge(numSpaceToYear[numSpace] /*year*/, + pValuesForTheCurrentYear[numSpace]); + } + + // Next variable + NextType::computeSummary(numSpaceToYear, nbYearsForCurrentSummary); + } + + void hourBegin(unsigned int hourInTheYear) + { + // Next variable + NextType::hourBegin(hourInTheYear); + } + + void hourForEachArea(State& state, unsigned int numSpace) + { + // Next variable + NextType::hourForEachArea(state, numSpace); + } + + Antares::Memory::Stored::ConstReturnType retrieveRawHourlyValuesForCurrentYear( + unsigned int, + unsigned int numSpace) const + { + return pValuesForTheCurrentYear[numSpace].hour; + } + + void localBuildAnnualSurveyReport(SurveyResults& results, + int fileLevel, + int precision, + unsigned int numSpace) const + { + // Initializing external pointer on current variable non applicable status + results.isCurrentVarNA = AncestorType::isNonApplicable; + + if (AncestorType::isPrinted[0]) + { + // Write the data for the current year + results.variableCaption = VCardType::Caption(); + results.variableUnit = VCardType::Unit(); + pValuesForTheCurrentYear[numSpace].template buildAnnualSurveyReport( + results, fileLevel, precision); + } + } + +private: + //! Intermediate values for each year + typename VCardType::IntermediateValuesType pValuesForTheCurrentYear; + unsigned int pNbYearsParallel; + +}; // class RampingCost + +} // namespace Economy +} // namespace Variable +} // namespace Solver +} // namespace Antares + +#endif // __SOLVER_VARIABLE_ECONOMY_ReserveParticipationCost_H__ \ No newline at end of file diff --git a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h new file mode 100644 index 0000000000..b25272ce70 --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h @@ -0,0 +1,339 @@ +/* +** 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 +*/ +#ifndef __SOLVER_VARIABLE_ECONOMY_ReserveParticipationCostByDispatchablePlant_H__ +#define __SOLVER_VARIABLE_ECONOMY_ReserveParticipationCostByDispatchablePlant_H__ + +#include "../variable.h" + +namespace Antares +{ +namespace Solver +{ +namespace Variable +{ +namespace Economy +{ +struct VCardReserveParticipationCostByDispatchablePlant +{ + //! Caption + static std::string Caption() + { + return "RESERVE PARTICIPATION COST by plant"; + } + //! Unit + static std::string Unit() + { + return "Reserve Participation Cost - Euro"; + } + + //! The short description of the variable + static std::string Description() + { + return "Reserve Participation costs by all the clusters"; + } + + //! The expected results + typedef Results> + ResultsType; + + //! The VCard to look for for calculating spatial aggregates + typedef VCardReserveParticipationCostByDispatchablePlant VCardForSpatialAggregate; + + enum + { + //! Data Level + categoryDataLevel = Category::area, + //! File level (provided by the type of the results) + categoryFileLevel = ResultsType::categoryFile & (Category::de), + //! Precision (views) + precision = Category::all, + //! Indentation (GUI) + nodeDepthForGUI = +0, + //! Decimal precision + decimal = 0, + //! Number of columns used by the variable + columnCount = Category::dynamicColumns, + //! The Spatial aggregation + spatialAggregate = Category::spatialAggregateSum, + spatialAggregateMode = Category::spatialAggregateEachYear, + spatialAggregatePostProcessing = 0, + //! Intermediate values + hasIntermediateValues = 1, + //! Can this variable be non applicable (0 : no, 1 : yes) + isPossiblyNonApplicable = 0, + }; + + typedef IntermediateValues IntermediateValuesDeepType; + typedef IntermediateValues* IntermediateValuesBaseType; + typedef IntermediateValuesBaseType* IntermediateValuesType; + + // typedef IntermediateValues IntermediateValuesType; + +}; // class VCard + +/*! +** \brief C02 Average value of the overrall OperatingCost emissions expected from all +** the thermal dispatchable clusters +*/ +template +class ReserveParticipationCostByDispatchablePlant + : public Variable::IVariable, + NextT, + VCardReserveParticipationCostByDispatchablePlant> +{ +public: + //! Type of the next static variable + typedef NextT NextType; + //! VCard + typedef VCardReserveParticipationCostByDispatchablePlant VCardType; + //! Ancestor + typedef Variable:: + IVariable, NextT, VCardType> + AncestorType; + + //! List of expected results + typedef typename VCardType::ResultsType ResultsType; + + typedef VariableAccessor VariableAccessorType; + + enum + { + //! How many items have we got + count = 1 + NextT::count, + }; + + template + struct Statistics + { + enum + { + count + = ((VCardType::categoryDataLevel & CDataLevel && VCardType::categoryFileLevel & CFile) + ? (NextType::template Statistics::count + + VCardType::columnCount * ResultsType::count) + : NextType::template Statistics::count), + }; + }; + +public: + ReserveParticipationCostByDispatchablePlant() : pValuesForTheCurrentYear(NULL), pSize(0) + { + } + + ~ReserveParticipationCostByDispatchablePlant() + { + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + delete[] pValuesForTheCurrentYear[numSpace]; + delete[] pValuesForTheCurrentYear; + } + + void initializeFromStudy(Data::Study& study) + { + // Next + NextType::initializeFromStudy(study); + } + + void initializeFromArea(Data::Study* study, Data::Area* area) + { + // Get the number of years in parallel + pNbYearsParallel = study->maxNbYearsInParallel; + pValuesForTheCurrentYear = new VCardType::IntermediateValuesBaseType[pNbYearsParallel]; + + // Get the area + pSize = area->thermal.list.allClustersCount(); + if (pSize) + { + AncestorType::pResults.resize(pSize); + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + pValuesForTheCurrentYear[numSpace] + = new VCardType::IntermediateValuesDeepType[pSize]; + + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + for (unsigned int i = 0; i != pSize; ++i) + pValuesForTheCurrentYear[numSpace][i].initializeFromStudy(*study); + + for (unsigned int i = 0; i != pSize; ++i) + { + AncestorType::pResults[i].initializeFromStudy(*study); + AncestorType::pResults[i].reset(); + } + } + else + { + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + pValuesForTheCurrentYear[numSpace] = nullptr; + + AncestorType::pResults.clear(); + } + + // Next + NextType::initializeFromArea(study, area); + } + + size_t getMaxNumberColumns() const + { + return pSize * ResultsType::count; + } + + void initializeFromLink(Data::Study* study, Data::AreaLink* link) + { + // Next + NextType::initializeFromAreaLink(study, link); + } + + void simulationBegin() + { + // Next + NextType::simulationBegin(); + } + + void simulationEnd() + { + NextType::simulationEnd(); + } + + void yearBegin(unsigned int year, unsigned int numSpace) + { + // Reset the values for the current year + for (unsigned int i = 0; i != pSize; ++i) + pValuesForTheCurrentYear[numSpace][i].reset(); + + // Next variable + NextType::yearBegin(year, numSpace); + } + + void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) + { + // Get end year calculations + for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + ++i) + { + pValuesForTheCurrentYear[numSpace][state.thermalCluster->areaWideIndex].hour[i] + = state.thermalClusterReserveParticipationCostForYear[i]; + } + + // Next variable + NextType::yearEndBuildForEachThermalCluster(state, year, numSpace); + } + + void yearEndBuild(State& state, unsigned int year) + { + // Next variable + NextType::yearEndBuild(state, year); + } + + void yearEnd(unsigned int year, unsigned int numSpace) + { + // Merge all results for all thermal clusters + { + for (unsigned int i = 0; i < pSize; ++i) + { + // Compute all statistics for the current year (daily,weekly,monthly) + pValuesForTheCurrentYear[numSpace][i].computeStatisticsForTheCurrentYear(); + } + } + // Next variable + NextType::yearEnd(year, numSpace); + } + + void computeSummary(std::map& numSpaceToYear, + unsigned int nbYearsForCurrentSummary) + { + for (unsigned int numSpace = 0; numSpace < nbYearsForCurrentSummary; ++numSpace) + { + for (unsigned int i = 0; i < pSize; ++i) + { + // Merge all those values with the global results + AncestorType::pResults[i].merge(numSpaceToYear[numSpace], + pValuesForTheCurrentYear[numSpace][i]); + } + } + + // Next variable + NextType::computeSummary(numSpaceToYear, nbYearsForCurrentSummary); + } + + void hourBegin(unsigned int hourInTheYear) + { + // Next variable + NextType::hourBegin(hourInTheYear); + } + + void hourForEachArea(State& state, unsigned int numSpace) + { + // Next variable + NextType::hourForEachArea(state, numSpace); + } + + Antares::Memory::Stored::ConstReturnType retrieveRawHourlyValuesForCurrentYear( + unsigned int, + unsigned int numSpace) const + { + return pValuesForTheCurrentYear[numSpace]->hour; + } + + void localBuildAnnualSurveyReport(SurveyResults& results, + int fileLevel, + int precision, + unsigned int numSpace) const + { + // Initializing external pointer on current variable non applicable status + results.isCurrentVarNA = AncestorType::isNonApplicable; + + if (AncestorType::isPrinted[0]) + { + assert(NULL != results.data.area); + const auto& thermal = results.data.area->thermal; + + // Write the data for the current year + for (uint i = 0; i < pSize; ++i) + { + // Write the data for the current year + results.variableCaption = thermal.list[i]->name(); // VCardType::Caption(); + results.variableUnit = VCardType::Unit(); + pValuesForTheCurrentYear[numSpace][i].template buildAnnualSurveyReport( + results, fileLevel, precision); + } + } + } + +private: + //! Intermediate values for each year + typename VCardType::IntermediateValuesType pValuesForTheCurrentYear; + size_t pSize; + unsigned int pNbYearsParallel; + +}; // class ReserveParticipationCostByDispatchablePlant + +} // namespace Economy +} // namespace Variable +} // namespace Solver +} // namespace Antares + +#endif // __SOLVER_VARIABLE_ECONOMY_ReserveParticipationCostByDispatchablePlant_H__ \ No newline at end of file diff --git a/src/solver/variable/include/antares/solver/variable/state.h b/src/solver/variable/include/antares/solver/variable/state.h index f1f16f9618..e6d5ea2f35 100644 --- a/src/solver/variable/include/antares/solver/variable/state.h +++ b/src/solver/variable/include/antares/solver/variable/state.h @@ -116,6 +116,8 @@ class State const std::array& ON_opt, const Data::ThermalCluster* currentCluster); + void yearEndBuildCalculateReserveParticipationCosts(const Data::ThermalCluster* currentCluster); + std::array computeEconomicallyOptimalNbClustersONforEachHour( const uint& maxDurationON, const std::array& ON_min, @@ -190,6 +192,8 @@ class State double thermalClusterNonProportionalCostForYear[Variable::maxHoursInAYear]; //! Minimum power of the cluster for the whole year double thermalClusterPMinOfTheClusterForYear[Variable::maxHoursInAYear]; + //! Reserves participation cost of the thermal cluster for the whole year + double thermalClusterReserveParticipationCostForYear[Variable::maxHoursInAYear]; double renewableClusterProduction; diff --git a/src/solver/variable/include/antares/solver/variable/state.hxx b/src/solver/variable/include/antares/solver/variable/state.hxx index a6649f52ec..6f2657db1f 100644 --- a/src/solver/variable/include/antares/solver/variable/state.hxx +++ b/src/solver/variable/include/antares/solver/variable/state.hxx @@ -41,6 +41,9 @@ inline void State::startANewYear() 0, sizeof(thermalClusterDispatchedUnitsCountForYear)); + if (unitCommitmentMode != Antares::Data::UnitCommitmentMode::ucHeuristicFast) + memset(thermalClusterReserveParticipationCostForYear, 0, sizeof(thermalClusterNonProportionalCostForYear)); + // Re-initializing annual costs (to be printed in output into separate files) annualSystemCost = 0.; optimalSolutionCost1 = 0.; @@ -61,6 +64,9 @@ inline void State::yearEndResetThermal() memset(thermalClusterDispatchedUnitsCountForYear, 0, sizeof(thermalClusterDispatchedUnitsCountForYear)); + memset(thermalClusterReserveParticipationCostForYear, + 0, + sizeof(thermalClusterReserveParticipationCostForYear)); } inline void State::initFromAreaIndex(const unsigned int areaIndex, uint numSpace) diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index 6a37a2b5e7..7f46498ebf 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -199,6 +199,21 @@ void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideInde thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] += thermalCluster->fixedCost * newUnitCount; + // Reserves + if (unitCommitmentMode != Antares::Data::UnitCommitmentMode::ucHeuristicFast) + { + std::vector clusterReserves = thermalCluster->listOfParticipatingReserves(); + for (auto res : clusterReserves) + { + thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] + += thermalCluster->isParticipatingInReserve(res) >= 0 + ? hourlyResults->ProductionThermique[hourInTheWeek] + .ParticipationReservesDuPalier[thermalCluster->index] + * thermalCluster->reserveCost(res) + : 0; + } + } + // Storing the new unit count for the next hour thermal[area->index].unitCountLastHour[clusterAreaWideIndex] = newUnitCount; thermal[area->index].productionLastHour[clusterAreaWideIndex] = p; @@ -340,6 +355,36 @@ void State::yearEndBuildFromThermalClusterIndex(const uint clusterAreaWideIndex) // Calculation of non linear and startup costs yearEndBuildThermalClusterCalculateStartupCosts(maxDurationON, ON_min, ON_opt, currentCluster); + // Calculation of reserve participation costs + yearEndBuildCalculateReserveParticipationCosts(currentCluster); +} + +void State::yearEndBuildCalculateReserveParticipationCosts( + const Data::ThermalCluster* currentCluster) +{ + if (unitCommitmentMode != Antares::Data::UnitCommitmentMode::ucHeuristicFast) + { + uint startHourForCurrentYear = study.runtime->rangeLimits.hour[Data::rangeBegin]; + uint endHourForCurrentYear + = startHourForCurrentYear + study.runtime->rangeLimits.hour[Data::rangeCount]; + + for (uint h = startHourForCurrentYear; h < endHourForCurrentYear; ++h) + { + std::vector clusterReserves + = thermalCluster->listOfParticipatingReserves(); + for (auto res : clusterReserves) + { + thermalClusterReserveParticipationCostForYear[h] + += thermalCluster->isParticipatingInReserve(res) + ? hourlyResults->ProductionThermique[hourInTheWeek] + .ParticipationReservesDuPalier[thermalCluster->index] + * thermalCluster->reserveCost(res) + : 0; + } + thermalClusterOperatingCostForYear[h] + += thermalClusterReserveParticipationCostForYear[h]; + } + } } void State::yearEndBuildThermalClusterCalculateStartupCosts(const uint& maxDurationON, From aa3807a9b35f43e6cb37973ff82c4371d7c31083 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Wed, 5 Jun 2024 17:14:15 +0200 Subject: [PATCH 28/41] Working outputs to the ui for reservation costs overall and by clusters (but not yet by reserves) --- .../antares/study/parts/thermal/cluster.h | 54 ++++++++++--------- .../antares/study/parts/thermal/cluster.cpp | 52 +++++++++++++----- .../antares/solver/variable/area.inc.hxx | 2 +- .../include/antares/solver/variable/state.h | 8 +++ .../include/antares/solver/variable/state.hxx | 4 +- src/solver/variable/state.cpp | 32 ++++++----- 6 files changed, 91 insertions(+), 61 deletions(-) diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h b/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h index 3b32763d51..ac53ab3b75 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h @@ -67,38 +67,40 @@ enum class LocalTSGenerationBehavior forceNoGen }; +enum ThermalDispatchableGroup +{ + //! Nuclear + thermalDispatchGrpNuclear = 0, + //! Lignite + thermalDispatchGrpLignite, + //! Hard Coal + thermalDispatchGrpHardCoal, + //! Gas + thermalDispatchGrpGas, + //! Oil + thermalDispatchGrpOil, + //! Mixed fuel + thermalDispatchGrpMixedFuel, + //! Other 1 + thermalDispatchGrpOther1, + //! Other 2 + thermalDispatchGrpOther2, + //! Other 3 + thermalDispatchGrpOther3, + //! Other 4 + thermalDispatchGrpOther4, + + //! The highest value + groupMax +}; + /*! ** \brief A single thermal cluster */ class ThermalCluster final : public Cluster, public std::enable_shared_from_this { public: - enum ThermalDispatchableGroup - { - //! Nuclear - thermalDispatchGrpNuclear = 0, - //! Lignite - thermalDispatchGrpLignite, - //! Hard Coal - thermalDispatchGrpHardCoal, - //! Gas - thermalDispatchGrpGas, - //! Oil - thermalDispatchGrpOil, - //! Mixed fuel - thermalDispatchGrpMixedFuel, - //! Other 1 - thermalDispatchGrpOther1, - //! Other 2 - thermalDispatchGrpOther2, - //! Other 3 - thermalDispatchGrpOther3, - //! Other 4 - thermalDispatchGrpOther4, - - //! The highest value - groupMax - }; + Pollutant emissions; diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index b8a313b99a..ee8d062006 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -208,21 +208,21 @@ void Data::ThermalCluster::copyFrom(const ThermalCluster& cluster) parentArea->forceReload(); } -static Data::ThermalCluster::ThermalDispatchableGroup stringToGroup(Data::ClusterName& newgrp) +static Data::ThermalDispatchableGroup stringToGroup(Data::ClusterName& newgrp) { using namespace Antares::Data; - const static std::map mapping - = {{"nuclear", ThermalCluster::thermalDispatchGrpNuclear}, - {"lignite", ThermalCluster::thermalDispatchGrpLignite}, - {"hard coal", ThermalCluster::thermalDispatchGrpHardCoal}, - {"gas", ThermalCluster::thermalDispatchGrpGas}, - {"oil", ThermalCluster::thermalDispatchGrpOil}, - {"mixed fuel", ThermalCluster::thermalDispatchGrpMixedFuel}, - {"other", ThermalCluster::thermalDispatchGrpOther1}, - {"other 1", ThermalCluster::thermalDispatchGrpOther1}, - {"other 2", ThermalCluster::thermalDispatchGrpOther2}, - {"other 3", ThermalCluster::thermalDispatchGrpOther3}, - {"other 4", ThermalCluster::thermalDispatchGrpOther4}}; + const static std::map mapping + = {{"nuclear", thermalDispatchGrpNuclear}, + {"lignite", thermalDispatchGrpLignite}, + {"hard coal", thermalDispatchGrpHardCoal}, + {"gas", thermalDispatchGrpGas}, + {"oil", thermalDispatchGrpOil}, + {"mixed fuel", thermalDispatchGrpMixedFuel}, + {"other", thermalDispatchGrpOther1}, + {"other 1", thermalDispatchGrpOther1}, + {"other 2", thermalDispatchGrpOther2}, + {"other 3", thermalDispatchGrpOther3}, + {"other 4", thermalDispatchGrpOther4}}; boost::to_lower(newgrp); if (auto res = mapping.find(newgrp);res != mapping.end()) @@ -230,7 +230,31 @@ static Data::ThermalCluster::ThermalDispatchableGroup stringToGroup(Data::Cluste return res->second; } // assigning a default value - return ThermalCluster::thermalDispatchGrpOther1; + return thermalDispatchGrpOther1; +} + +static std::string groupToString(Data::ThermalDispatchableGroup group) +{ + using namespace Antares::Data; + const static std::map reverseMapping + = {{thermalDispatchGrpNuclear, "nuclear"}, + {thermalDispatchGrpLignite, "lignite"}, + {thermalDispatchGrpHardCoal, "hard coal"}, + {thermalDispatchGrpGas, "gas"}, + {thermalDispatchGrpOil, "oil"}, + {thermalDispatchGrpMixedFuel, "mixed fuel"}, + {thermalDispatchGrpOther1, "other"}, + {thermalDispatchGrpOther1, "other 1"}, + {thermalDispatchGrpOther2, "other 2"}, + {thermalDispatchGrpOther3, "other 3"}, + {thermalDispatchGrpOther4, "other 4"}}; + + if (auto res = reverseMapping.find(group); res != reverseMapping.end()) + { + return res->second; + } + // Returning a default value or an error indication + return "unknown"; } void Data::ThermalCluster::setGroup(Data::ClusterName newgrp) diff --git a/src/solver/variable/include/antares/solver/variable/area.inc.hxx b/src/solver/variable/include/antares/solver/variable/area.inc.hxx index 28146ad13d..330ef1cf96 100644 --- a/src/solver/variable/include/antares/solver/variable/area.inc.hxx +++ b/src/solver/variable/include/antares/solver/variable/area.inc.hxx @@ -196,7 +196,6 @@ void Areas::yearEndBuild(State& state, uint year, uint numSpace) for(auto cluster : area.thermal.list.each_enabled()) { state.thermalCluster = cluster.get(); - state.yearEndResetThermal(); // Variables variablesForArea.yearEndBuildPrepareDataForEachThermalCluster(state, year, numSpace); @@ -206,6 +205,7 @@ void Areas::yearEndBuild(State& state, uint year, uint numSpace) // Variables variablesForArea.yearEndBuildForEachThermalCluster(state, year, numSpace); + state.yearEndResetThermal(); } // for each thermal cluster }); // for each area } diff --git a/src/solver/variable/include/antares/solver/variable/state.h b/src/solver/variable/include/antares/solver/variable/state.h index e6d5ea2f35..4c428d7e31 100644 --- a/src/solver/variable/include/antares/solver/variable/state.h +++ b/src/solver/variable/include/antares/solver/variable/state.h @@ -59,6 +59,9 @@ class ThermalState std::vector unitCountLastHour; std::vector productionLastHour; std::vector pminOfAGroup; + + //! Track the number of thermalGroup different types participating to the reserves + std::vector nbThermalGroupsForReserves; }; StateForAnArea& operator[](size_t areaIndex); @@ -182,6 +185,11 @@ class State //! Thermal production for the current thermal cluster for the whole year double thermalClusterProductionForYear[Variable::maxHoursInAYear]; + //! Reserve Participation for all thermal group types (nuclear / coal / ...) for the whole year + //! per reserve + std::map> + thermalReserveParticipationPerGroupForYear[Variable::maxHoursInAYear]; + //! Number of unit dispatched for all clusters for the whole year for ucHeruistic (fast) or //! ucMILP (accurate) uint thermalClusterDispatchedUnitsCountForYear[Variable::maxHoursInAYear]; diff --git a/src/solver/variable/include/antares/solver/variable/state.hxx b/src/solver/variable/include/antares/solver/variable/state.hxx index 6f2657db1f..11c1255ace 100644 --- a/src/solver/variable/include/antares/solver/variable/state.hxx +++ b/src/solver/variable/include/antares/solver/variable/state.hxx @@ -64,9 +64,7 @@ inline void State::yearEndResetThermal() memset(thermalClusterDispatchedUnitsCountForYear, 0, sizeof(thermalClusterDispatchedUnitsCountForYear)); - memset(thermalClusterReserveParticipationCostForYear, - 0, - sizeof(thermalClusterReserveParticipationCostForYear)); + memset(thermalClusterReserveParticipationCostForYear,0,sizeof(thermalClusterReserveParticipationCostForYear)); } inline void State::initFromAreaIndex(const unsigned int areaIndex, uint numSpace) diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index 7f46498ebf..c886a8846c 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -51,6 +51,7 @@ void ThermalState::StateForAnArea::initializeFromArea(const Data::Area& area) unitCountLastHour.resize(count, 0); productionLastHour.resize(count, 0); pminOfAGroup.resize(count, 0); + nbThermalGroupsForReserves.resize(count, 0); } State::State(Data::Study& s) : @@ -206,11 +207,20 @@ void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideInde for (auto res : clusterReserves) { thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] - += thermalCluster->isParticipatingInReserve(res) >= 0 - ? hourlyResults->ProductionThermique[hourInTheWeek] - .ParticipationReservesDuPalier[thermalCluster->index] - * thermalCluster->reserveCost(res) - : 0; + += hourlyResults->ProductionThermique[hourInTheWeek] + .ParticipationReservesDuPalier[thermalCluster->index] + * thermalCluster->reserveCost(res); + double participation = hourlyResults->ProductionThermique[hourInTheWeek] + .ParticipationReservesDuPalier[thermalCluster->index]; + if (participation) + { + thermalClusterReserveParticipationCostForYear[hourInTheYear] + += participation * thermalCluster->reserveCost(res); + + thermalReserveParticipationPerGroupForYear[hourInTheYear][res][thermalCluster->groupID] + += participation; + thermal[area->index].nbThermalGroupsForReserves[thermalCluster->index]++; + } } } @@ -367,20 +377,8 @@ void State::yearEndBuildCalculateReserveParticipationCosts( uint startHourForCurrentYear = study.runtime->rangeLimits.hour[Data::rangeBegin]; uint endHourForCurrentYear = startHourForCurrentYear + study.runtime->rangeLimits.hour[Data::rangeCount]; - for (uint h = startHourForCurrentYear; h < endHourForCurrentYear; ++h) { - std::vector clusterReserves - = thermalCluster->listOfParticipatingReserves(); - for (auto res : clusterReserves) - { - thermalClusterReserveParticipationCostForYear[h] - += thermalCluster->isParticipatingInReserve(res) - ? hourlyResults->ProductionThermique[hourInTheWeek] - .ParticipationReservesDuPalier[thermalCluster->index] - * thermalCluster->reserveCost(res) - : 0; - } thermalClusterOperatingCostForYear[h] += thermalClusterReserveParticipationCostForYear[h]; } From 299664d74ac7d8e53639c407e9dffb00863924d5 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Thu, 6 Jun 2024 11:11:42 +0200 Subject: [PATCH 29/41] Hiding outputs for clusters when reserves are not activated --- ...erveParticipationCostByDispatchablePlant.h | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h index b25272ce70..cf1da31ff6 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h @@ -164,8 +164,17 @@ class ReserveParticipationCostByDispatchablePlant pNbYearsParallel = study->maxNbYearsInParallel; pValuesForTheCurrentYear = new VCardType::IntermediateValuesBaseType[pNbYearsParallel]; + // Get the area - pSize = area->thermal.list.allClustersCount(); + pSize = 0; + for (int areaIndex = 0; areaIndex < study->areas.size(); areaIndex++) + { + if (study->areas[areaIndex]->allCapacityReservations.size() > 0) + { + pSize = area->thermal.list.allClustersCount(); + break; + } + } if (pSize) { AncestorType::pResults.resize(pSize); @@ -230,12 +239,14 @@ class ReserveParticipationCostByDispatchablePlant void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) { // Get end year calculations - for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; - i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; - ++i) - { - pValuesForTheCurrentYear[numSpace][state.thermalCluster->areaWideIndex].hour[i] - = state.thermalClusterReserveParticipationCostForYear[i]; + if (pSize) { + for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + ++i) + { + pValuesForTheCurrentYear[numSpace][state.thermalCluster->areaWideIndex].hour[i] + = state.thermalClusterReserveParticipationCostForYear[i]; + } } // Next variable From be5d670e1b530b2e5cb222ceaa88f2836f15d042 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Wed, 12 Jun 2024 16:37:50 +0200 Subject: [PATCH 30/41] Added reserves outputs as files for unsupplied, spillage costs and reserve participation by cluster --- .../solver/variable/economy/overallCost.h | 38 +++++++++++++- .../include/antares/solver/variable/state.h | 2 + src/solver/variable/state.cpp | 51 +++++++++++++++++-- 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/solver/variable/include/antares/solver/variable/economy/overallCost.h b/src/solver/variable/include/antares/solver/variable/economy/overallCost.h index ae1f2a3171..3628a6580e 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/overallCost.h +++ b/src/solver/variable/include/antares/solver/variable/economy/overallCost.h @@ -22,6 +22,11 @@ #define __SOLVER_VARIABLE_ECONOMY_OverallCost_H__ #include "antares/solver/variable/variable.h" +#include +#include +#include +#include +#include namespace Antares { @@ -207,6 +212,7 @@ class OverallCost : public Variable::IVariable, NextT, VCardO void yearEndBuild(State& state, unsigned int year) { + // Next variable NextType::yearEndBuild(state, year); } @@ -253,7 +259,8 @@ class OverallCost : public Variable::IVariable, NextT, VCardO * (state.hourlyResults->TurbinageHoraire[state.hourInTheWeek] - state.area->hydro.pumpingEfficiency * state.hourlyResults->PompageHoraire[state.hourInTheWeek])); - + Yuni::String buffer; + buffer << "Hour : " << state.hourInTheYear << "\n"; for (const auto& thermalReserves : state.problemeHebdo->allReserves.thermalAreaReserves) { for (const auto& reserveUp : thermalReserves.areaCapacityReservationsUp) @@ -265,6 +272,9 @@ class OverallCost : public Variable::IVariable, NextT, VCardO + state.hourlyResults->ReserveThermique[state.hourInTheWeek] .ValeursHorairesInternalExcessReserve[reserveUp.globalReserveIndex] * reserveUp.spillageCost; + buffer << " Reserve : " << reserveUp.reserveName << " Unsupplied : " << state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalUnsatisfied[reserveUp.globalReserveIndex] << " mw, Spilled : " << state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalExcessReserve[reserveUp.globalReserveIndex] << " mw. \n"; } for (const auto& reserveDown : thermalReserves.areaCapacityReservationsDown) { @@ -275,11 +285,35 @@ class OverallCost : public Variable::IVariable, NextT, VCardO + state.hourlyResults->ReserveThermique[state.hourInTheWeek] .ValeursHorairesInternalExcessReserve[reserveDown.globalReserveIndex] * reserveDown.spillageCost; + buffer << " Reserve : " << reserveDown.reserveName << " Unsupplied : " << state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalUnsatisfied[reserveDown.globalReserveIndex] << " mw, Spilled : " << state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalExcessReserve[reserveDown.globalReserveIndex] << " mw. \n"; } } - + state.spilledUnsupplied << buffer; pValuesForTheCurrentYear[numSpace][state.hourInTheYear] += costForSpilledOrUnsuppliedEnergy; + if (state.hourInTheYear == state.study.runtime->rangeLimits.hour[Data::rangeEnd]) + { + Yuni::String path; + path << state.study.folderOutput << SEP << "reserves" << SEP << state.area->name << ".txt"; + Yuni::IO::File::Stream file; + Yuni::String pathFolder = state.study.folderOutput; + pathFolder << SEP << "reserves"; + if (Yuni::IO::Directory::Exists(pathFolder) || Yuni::IO::Directory::Create(pathFolder)) + { + if (file.openRW(path)) + { + file << state.spilledUnsupplied; + file.close(); + } + } + else + { + logs.error() << "Reserves : impossible to write " << path; + } + } + // Incrementing annual system cost (to be printed in output into a separate file) state.annualSystemCost += costForSpilledOrUnsuppliedEnergy; diff --git a/src/solver/variable/include/antares/solver/variable/state.h b/src/solver/variable/include/antares/solver/variable/state.h index 4c428d7e31..e2fc5df5cb 100644 --- a/src/solver/variable/include/antares/solver/variable/state.h +++ b/src/solver/variable/include/antares/solver/variable/state.h @@ -62,6 +62,7 @@ class ThermalState //! Track the number of thermalGroup different types participating to the reserves std::vector nbThermalGroupsForReserves; + }; StateForAnArea& operator[](size_t areaIndex); @@ -156,6 +157,7 @@ class State //! Current hour from the begining of the simulation unsigned int hourInTheSimulation; + Yuni::String spilledUnsupplied; //! The current area Data::Area* area; diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index c886a8846c..d87057d520 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -23,6 +23,13 @@ #include #include "antares/solver/variable/state.h" +#include +#include +#include +#include +#include +#include +#include "antares/solver/variable/variable.h" namespace Antares::Solver::Variable { @@ -370,17 +377,51 @@ void State::yearEndBuildFromThermalClusterIndex(const uint clusterAreaWideIndex) } void State::yearEndBuildCalculateReserveParticipationCosts( - const Data::ThermalCluster* currentCluster) + const Data::ThermalCluster* currentCluster) { if (unitCommitmentMode != Antares::Data::UnitCommitmentMode::ucHeuristicFast) { uint startHourForCurrentYear = study.runtime->rangeLimits.hour[Data::rangeBegin]; uint endHourForCurrentYear - = startHourForCurrentYear + study.runtime->rangeLimits.hour[Data::rangeCount]; - for (uint h = startHourForCurrentYear; h < endHourForCurrentYear; ++h) + = startHourForCurrentYear + study.runtime->rangeLimits.hour[Data::rangeCount]; + Yuni::IO::File::Stream file; + Yuni::String pathFolder = study.folderOutput; + pathFolder << SEP << "reserves"; + if (Yuni::IO::Directory::Exists(pathFolder) || Yuni::IO::Directory::Create(pathFolder)) { - thermalClusterOperatingCostForYear[h] - += thermalClusterReserveParticipationCostForYear[h]; + pathFolder << SEP << thermalCluster->parentArea->name; + if (Yuni::IO::Directory::Exists(pathFolder) || Yuni::IO::Directory::Create(pathFolder)) + { + Yuni::String path; + path << pathFolder << SEP << thermalCluster->name() << ".txt"; + if (file.openRW(path)) + { + for (uint h = startHourForCurrentYear; h < endHourForCurrentYear; ++h) + { + thermalClusterOperatingCostForYear[h] + += thermalClusterReserveParticipationCostForYear[h]; + std::vector clusterReserves = thermalCluster->listOfParticipatingReserves(); + + for (auto res : clusterReserves) + { + file << "Hour " << h + 1 << " : cluster " << thermalCluster->name() << " is participating to reserve " << res << " for " << thermalReserveParticipationPerGroupForYear[h][res][thermalCluster->groupID] << " mw\n"; + } + } + file.close(); + } + else + { + logs.error() << "Reserves : impossible to write " << path; + } + } + else + { + logs.error() << "Reserves : impossible to write " << pathFolder; + } + } + else + { + logs.error() << "Reserves : impossible to write " << pathFolder; } } } From 50d661dcd80e45323641bdac71f4e383e3e93472 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Thu, 13 Jun 2024 12:15:46 +0200 Subject: [PATCH 31/41] Solved bug where need values for reserves were repeating --- .../optimisation/opt_gestion_second_membre_reserves.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp b/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp index 44f9482fff..f18152a7b3 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp @@ -52,6 +52,7 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO* pro for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) { + int pdtGlobal = problemeHebdo->weekInTheYear * problemeHebdo->NombreDePasDeTempsDUneJournee * problemeHebdo->NombreDeJours + pdtJour; auto areaReservesUp = areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp; for (const auto& areaReserveUp : areaReservesUp) { @@ -61,7 +62,7 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO* pro .globalReserveIndex]; if (cnt >= 0) { - SecondMembre[cnt] = areaReserveUp.need.at(pdtJour); + SecondMembre[cnt] = areaReserveUp.need.at(pdtGlobal); AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; } } @@ -76,7 +77,7 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO* pro .globalReserveIndex]; if (cnt >= 0) { - SecondMembre[cnt] = areaReserveDown.need.at(pdtJour); + SecondMembre[cnt] = areaReserveDown.need.at(pdtGlobal); AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; } } From 0bb5a73b521fb9eb0979b0c8ceed169ca4edce25 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Mon, 17 Jun 2024 11:29:25 +0200 Subject: [PATCH 32/41] Removed bug index for cluster reserve participation --- .../include/antares/solver/variable/state.h | 1 + src/solver/variable/state.cpp | 62 ++++++++++++++----- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/solver/variable/include/antares/solver/variable/state.h b/src/solver/variable/include/antares/solver/variable/state.h index e2fc5df5cb..33bb79d375 100644 --- a/src/solver/variable/include/antares/solver/variable/state.h +++ b/src/solver/variable/include/antares/solver/variable/state.h @@ -104,6 +104,7 @@ class State void yearEndBuildFromThermalClusterIndex(const unsigned int areaWideIndex); + int getIndexFromClusterAndReserve(std::string reserveName, std::string clusterName); private: /*! ** \brief Initialize some variable according a thermal cluster index diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index d87057d520..f83e4ee3b6 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -58,7 +58,7 @@ void ThermalState::StateForAnArea::initializeFromArea(const Data::Area& area) unitCountLastHour.resize(count, 0); productionLastHour.resize(count, 0); pminOfAGroup.resize(count, 0); - nbThermalGroupsForReserves.resize(count, 0); + nbThermalGroupsForReserves.resize(Antares::Data::groupMax, 0); } State::State(Data::Study& s) : @@ -153,10 +153,36 @@ void State::initFromThermalClusterIndex(const uint clusterAreaWideIndex) // en mode fast : est pris depuis l'heuristique } +int State::getIndexFromClusterAndReserve(std::string reserveName, std::string clusterName) +{ + for (auto reserve : problemeHebdo->allReserves.thermalAreaReserves[area->index].areaCapacityReservationsUp) + { + if (reserve.reserveName == reserveName) + { + for (auto cluster : reserve.AllReservesParticipation) + { + if (cluster.clusterName == clusterName) + return cluster.indexClusterParticipation; + } + } + } + for (auto reserve : problemeHebdo->allReserves.thermalAreaReserves[area->index].areaCapacityReservationsDown) + { + if (reserve.reserveName == reserveName) + { + for (auto cluster : reserve.AllReservesParticipation) + { + if (cluster.clusterName == clusterName) + return cluster.indexClusterParticipation; + } + } + } + return -1; +} + void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideIndex) { uint serieIndex = thermalCluster->series.timeseriesNumbers[0][this->year]; - if (thermal[area->index].thermalClustersProductions[clusterAreaWideIndex] > 0.) { // alias to the production of the current thermal cluster @@ -190,7 +216,6 @@ void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideInde if (newUnitCount > previousUnitCount) newUnitCount = previousUnitCount; } - // calculating the operating cost for the current hour // O(h) = MA * P(h) * Modulation thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] @@ -213,21 +238,28 @@ void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideInde std::vector clusterReserves = thermalCluster->listOfParticipatingReserves(); for (auto res : clusterReserves) { - thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] - += hourlyResults->ProductionThermique[hourInTheWeek] - .ParticipationReservesDuPalier[thermalCluster->index] - * thermalCluster->reserveCost(res); - double participation = hourlyResults->ProductionThermique[hourInTheWeek] - .ParticipationReservesDuPalier[thermalCluster->index]; - if (participation) + int clusterIndex = getIndexFromClusterAndReserve(res, thermalCluster->name()); + if (clusterIndex != -1) { - thermalClusterReserveParticipationCostForYear[hourInTheYear] - += participation * thermalCluster->reserveCost(res); + thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] + += hourlyResults->ProductionThermique[hourInTheWeek] + .ParticipationReservesDuPalier[clusterIndex] + * thermalCluster->reserveCost(res); + double participation = hourlyResults->ProductionThermique[hourInTheWeek] + .ParticipationReservesDuPalier[clusterIndex]; + if (participation) + { + thermalClusterReserveParticipationCostForYear[hourInTheYear] + += participation * thermalCluster->reserveCost(res); - thermalReserveParticipationPerGroupForYear[hourInTheYear][res][thermalCluster->groupID] - += participation; - thermal[area->index].nbThermalGroupsForReserves[thermalCluster->index]++; + thermalReserveParticipationPerGroupForYear[hourInTheYear][res][thermalCluster->groupID] + += participation; + thermal[area->index].nbThermalGroupsForReserves[thermalCluster->groupID]++; + + } } + else + logs.error() << "No index for cluster " << thermalCluster->name() << " in reserve " << res; } } From 1fbd4cf8439f577e7aec31eee097a6127bd38628 Mon Sep 17 00:00:00 2001 From: h-fournier Date: Fri, 21 Jun 2024 14:02:25 +0200 Subject: [PATCH 33/41] =?UTF-8?q?Add=20a=20colomn=20for=20each=20each=20cl?= =?UTF-8?q?uster=20participation=20to=20reserves=20to=20the=20outputs=20"e?= =?UTF-8?q?conomy/mc-all/areas//details"=20Spec=20:=20Dans=20le=20fi?= =?UTF-8?q?chier=20"economy/mc-all/areas//details"=20:=20La=20partic?= =?UTF-8?q?ipation=20en=20MW=20de=20chaque=20cluster,=20pour=20chaque=20r?= =?UTF-8?q?=C3=A9serve=20d=C3=A9finie=20au=20niveau=20du=20n=C5=93ud=20via?= =?UTF-8?q?=20la=20d=C3=A9finition=20d'une=20nouvelle=20colonne=20("=5F").?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../antares/study/area/capacityReservation.h | 6 +- .../antares/study/include/antares/study/fwd.h | 2 + .../antares/study/parts/common/cluster.h | 10 +- .../antares/study/parts/common/cluster_list.h | 11 ++ .../antares/study/parts/common/cluster.cpp | 12 +- .../study/parts/common/cluster_list.cpp | 43 +++++++- .../opt_gestion_des_couts_reserves.cpp | 24 ++-- src/solver/variable/CMakeLists.txt | 3 +- .../antares/solver/variable/economy/all.h | 4 +- ...reserveParticipationByDispatchablePlant.h} | 103 +++++------------- ...dReserveParticipationByDispatchablePlant.h | 103 ++++++++++++++++++ .../include/antares/solver/variable/info.h | 27 ++++- .../include/antares/solver/variable/state.h | 8 +- src/solver/variable/state.cpp | 14 ++- 14 files changed, 255 insertions(+), 115 deletions(-) rename src/solver/variable/include/antares/solver/variable/economy/{reserveParticipationCostByDispatchablePlant.h => reserveParticipationByDispatchablePlant.h} (73%) create mode 100644 src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h diff --git a/src/libs/antares/study/include/antares/study/area/capacityReservation.h b/src/libs/antares/study/include/antares/study/area/capacityReservation.h index 8ebc0d774b..69391724ed 100644 --- a/src/libs/antares/study/include/antares/study/area/capacityReservation.h +++ b/src/libs/antares/study/include/antares/study/area/capacityReservation.h @@ -44,13 +44,13 @@ struct CapacityReservation /// @brief Stores all the Capacity reservations in two vectors for the up and down reserves struct AllCapacityReservations { - std::map areaCapacityReservationsUp; - std::map areaCapacityReservationsDown; + std::map areaCapacityReservationsUp; + std::map areaCapacityReservationsDown; /// @brief Check if the capacity reservation name already exist in both the up and down reserves /// @param name /// @return true if the capacity reservation already existed - bool contains(std::string name) + bool contains(Data::ReserveName name) { return areaCapacityReservationsUp.contains(name) || areaCapacityReservationsDown.contains(name); } diff --git a/src/libs/antares/study/include/antares/study/fwd.h b/src/libs/antares/study/include/antares/study/fwd.h index c5e5933691..708ce24247 100644 --- a/src/libs/antares/study/include/antares/study/fwd.h +++ b/src/libs/antares/study/include/antares/study/fwd.h @@ -62,6 +62,8 @@ using AreaName = Yuni::CString; using AreaLinkName = Yuni::CString; //! Name of a single thermal using ClusterName = std::string; +//! Name of a reserve +using ReserveName = std::string; using ConstraintName = Yuni::CString; diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster.h b/src/libs/antares/study/include/antares/study/parts/common/cluster.h index 9bbdbfb17b..c5a4ea7e03 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster.h @@ -141,16 +141,16 @@ class Cluster Matrix<> modulation; //! \brief Returns true if cluster participates in a reserve with this name - bool isParticipatingInReserve(std::string name); + bool isParticipatingInReserve(Data::ReserveName name); //! \brief Returns an array of all reserves the cluster is participating in - std::vector listOfParticipatingReserves(); + std::vector listOfParticipatingReserves(); //! \brief Returns max power for a reserve if participating, -1 otherwise - float reserveMaxPower(std::string name); + float reserveMaxPower(Data::ReserveName name); //! \brief Returns participating cost for a reserve if participating, -1 otherwise - float reserveCost(std::string name); + float reserveCost(Data::ReserveName name); //! \brief Returns the number of reserves linked to this cluster unsigned int reserveParticipationsCount(); @@ -161,7 +161,7 @@ class Cluster Data::ClusterName pID; Data::ClusterName pGroup; //! reserve - std::map clusterReservesParticipations; + std::map clusterReservesParticipations; private: virtual unsigned int precision() const = 0; diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h index 88fb7764ee..978ee182db 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h @@ -96,6 +96,17 @@ class ClusterList SharedPtr operator[](std::size_t idx) const { return allClusters_[idx]; } SharedPtr enabledClusterAt(unsigned int index) const; + + /*! + ** @brief Get the cluster and reserve names for a given index of reserveParticipation + ** @param area The area where to took for the reserveParticipation + ** @param index Global index of the reserveParicipation + ** @return the cluster and reserve names + */ + std::pair reserveParticipationAt( + const Area* area, + unsigned int index) const; + /*! ** \brief Resize all matrices dedicated to the sampled timeseries numbers ** diff --git a/src/libs/antares/study/parts/common/cluster.cpp b/src/libs/antares/study/parts/common/cluster.cpp index 33267b8f00..7bf2fdab97 100644 --- a/src/libs/antares/study/parts/common/cluster.cpp +++ b/src/libs/antares/study/parts/common/cluster.cpp @@ -101,13 +101,13 @@ bool Cluster::loadDataSeriesFromFolder(Study& s, const AnyString& folder) void Cluster::addReserveParticipation( - std::string name, + Data::ReserveName name, ClusterReserveParticipation reserveParticipation) { clusterReservesParticipations.emplace(name, reserveParticipation); } -bool Cluster::isParticipatingInReserve(std::string name) +bool Cluster::isParticipatingInReserve(Data::ReserveName name) { if (clusterReservesParticipations.contains(name)) return true; @@ -115,7 +115,7 @@ bool Cluster::isParticipatingInReserve(std::string name) return false; } -float Cluster::reserveMaxPower(std::string name) +float Cluster::reserveMaxPower(Data::ReserveName name) { if (clusterReservesParticipations.contains(name)) return clusterReservesParticipations.at(name).maxPower; @@ -123,7 +123,7 @@ float Cluster::reserveMaxPower(std::string name) return -1; } -float Cluster::reserveCost(std::string name) +float Cluster::reserveCost(Data::ReserveName name) { if (clusterReservesParticipations.contains(name)) return clusterReservesParticipations.at(name).participationCost; @@ -160,9 +160,9 @@ bool CompareClusterName::operator()(const Cluster* s1, const Cluster* s2) const return (s1->getFullName() < s2->getFullName()); } -std::vector Cluster::listOfParticipatingReserves() +std::vector Cluster::listOfParticipatingReserves() { - std::vector reserves; + std::vector reserves; for (auto reserve: clusterReservesParticipations) { reserves.push_back(reserve.first); diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index a66e66d207..212e195aa5 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -55,6 +55,48 @@ std::shared_ptr ClusterList::enabledClusterAt(unsigned int i return *(std::views::drop(each_enabled(), index).begin()); } +template +std::pair ClusterList::reserveParticipationAt( + const Area* area, + unsigned int index) const +{ + int globalReserveParticipationIdx = 0; + + for (auto const& [reserveUpName, _] : area->allCapacityReservations.areaCapacityReservationsUp) + { + for (auto& cluster : allClusters_) + { + if (cluster->isParticipatingInReserve(reserveUpName)) + { + if (globalReserveParticipationIdx == index) + { + return {cluster->name(), reserveUpName}; + } + globalReserveParticipationIdx++; + } + } + } + + for (auto const& [reserveDownName, _] : + area->allCapacityReservations.areaCapacityReservationsDown) + { + for (auto& cluster : allClusters_) + { + if (cluster->isParticipatingInReserve(reserveDownName)) + { + if (globalReserveParticipationIdx == index) + { + return {cluster->name(), reserveDownName}; + } + globalReserveParticipationIdx++; + } + } + } + + throw std::out_of_range( + "This reserve participation index has not been found in all the reserve participations"); +} + template ClusterT* ClusterList::findInAll(std::string_view id) const { @@ -345,4 +387,3 @@ template class ClusterList; template class ClusterList; } // namespace Antares::Data - diff --git a/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp b/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp index 31ee2577c5..c4a67c0970 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp @@ -62,17 +62,7 @@ void OPT_InitialiserLesCoutsLineaireReserves(PROBLEME_HEBDO* problemeHebdo, CoutLineaire[var] = clusterReserveParticipation.participationCost; } } - for (const auto& clusterReserveParticipation : - reservesDuPays.areaCapacityReservationsDown[index].AllReservesParticipation) - { - if (clusterReserveParticipation.maxPower >= 0) - { - var = variableManager.ClusterReserveParticipation( - clusterReserveParticipation.indexClusterParticipation, pdtHebdo); - CoutLineaire[var] = clusterReserveParticipation.participationCost; - } - } - + var = variableManager.InternalExcessReserve( reservesDuPays.areaCapacityReservationsUp[index].globalReserveIndex, pdtHebdo); if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) @@ -88,8 +78,20 @@ void OPT_InitialiserLesCoutsLineaireReserves(PROBLEME_HEBDO* problemeHebdo, = reservesDuPays.areaCapacityReservationsUp[index].failureCost; } } + for (int index = 0; index < reservesDuPays.areaCapacityReservationsDown.size(); index++) { + for (const auto& clusterReserveParticipation : + reservesDuPays.areaCapacityReservationsDown[index].AllReservesParticipation) + { + if (clusterReserveParticipation.maxPower >= 0) + { + var = variableManager.ClusterReserveParticipation( + clusterReserveParticipation.indexClusterParticipation, pdtHebdo); + CoutLineaire[var] = clusterReserveParticipation.participationCost; + } + } + var = variableManager.InternalExcessReserve( reservesDuPays.areaCapacityReservationsDown[index].globalReserveIndex, pdtHebdo); if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) diff --git a/src/solver/variable/CMakeLists.txt b/src/solver/variable/CMakeLists.txt index 84ad89be0f..ec62c3d176 100644 --- a/src/solver/variable/CMakeLists.txt +++ b/src/solver/variable/CMakeLists.txt @@ -128,7 +128,8 @@ set(SRC_VARIABLE_ECONOMY include/antares/solver/variable/economy/avail-dispatchable-generation.h include/antares/solver/variable/economy/dispatchable-generation-margin.h include/antares/solver/variable/economy/reserveParticipationCost.h - include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h + include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h + include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h # Links include/antares/solver/variable/economy/links/flowLinear.h diff --git a/src/solver/variable/include/antares/solver/variable/economy/all.h b/src/solver/variable/include/antares/solver/variable/economy/all.h index 20b56d744c..a2e14e0c0b 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/all.h +++ b/src/solver/variable/include/antares/solver/variable/economy/all.h @@ -74,7 +74,7 @@ #include "npCostByDispatchablePlant.h" #include "nbOfDispatchedUnitsByPlant.h" #include "profitByPlant.h" -#include "reserveParticipationCostByDispatchablePlant.h" +#include "reserveParticipationByDispatchablePlant.h" // By RES plant #include "productionByRenewablePlant.h" @@ -171,7 +171,7 @@ typedef // Prices // plant >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h similarity index 73% rename from src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h rename to src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h index cf1da31ff6..1b74b3ec3f 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCostByDispatchablePlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h @@ -24,10 +24,11 @@ ** ** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions */ -#ifndef __SOLVER_VARIABLE_ECONOMY_ReserveParticipationCostByDispatchablePlant_H__ -#define __SOLVER_VARIABLE_ECONOMY_ReserveParticipationCostByDispatchablePlant_H__ +#ifndef __SOLVER_VARIABLE_ECONOMY_ReserveParticipationByDispatchablePlant_H__ +#define __SOLVER_VARIABLE_ECONOMY_ReserveParticipationByDispatchablePlant_H__ #include "../variable.h" +#include "./vCardReserveParticipationByDispatchablePlant.h" namespace Antares { @@ -37,83 +38,24 @@ namespace Variable { namespace Economy { -struct VCardReserveParticipationCostByDispatchablePlant -{ - //! Caption - static std::string Caption() - { - return "RESERVE PARTICIPATION COST by plant"; - } - //! Unit - static std::string Unit() - { - return "Reserve Participation Cost - Euro"; - } - - //! The short description of the variable - static std::string Description() - { - return "Reserve Participation costs by all the clusters"; - } - - //! The expected results - typedef Results> - ResultsType; - - //! The VCard to look for for calculating spatial aggregates - typedef VCardReserveParticipationCostByDispatchablePlant VCardForSpatialAggregate; - - enum - { - //! Data Level - categoryDataLevel = Category::area, - //! File level (provided by the type of the results) - categoryFileLevel = ResultsType::categoryFile & (Category::de), - //! Precision (views) - precision = Category::all, - //! Indentation (GUI) - nodeDepthForGUI = +0, - //! Decimal precision - decimal = 0, - //! Number of columns used by the variable - columnCount = Category::dynamicColumns, - //! The Spatial aggregation - spatialAggregate = Category::spatialAggregateSum, - spatialAggregateMode = Category::spatialAggregateEachYear, - spatialAggregatePostProcessing = 0, - //! Intermediate values - hasIntermediateValues = 1, - //! Can this variable be non applicable (0 : no, 1 : yes) - isPossiblyNonApplicable = 0, - }; - - typedef IntermediateValues IntermediateValuesDeepType; - typedef IntermediateValues* IntermediateValuesBaseType; - typedef IntermediateValuesBaseType* IntermediateValuesType; - - // typedef IntermediateValues IntermediateValuesType; - -}; // class VCard /*! ** \brief C02 Average value of the overrall OperatingCost emissions expected from all ** the thermal dispatchable clusters */ template -class ReserveParticipationCostByDispatchablePlant - : public Variable::IVariable, +class ReserveParticipationByDispatchablePlant + : public Variable::IVariable, NextT, - VCardReserveParticipationCostByDispatchablePlant> + VCardReserveParticipationByDispatchablePlant> { public: //! Type of the next static variable typedef NextT NextType; //! VCard - typedef VCardReserveParticipationCostByDispatchablePlant VCardType; + typedef VCardReserveParticipationByDispatchablePlant VCardType; //! Ancestor - typedef Variable:: - IVariable, NextT, VCardType> + typedef Variable::IVariable, NextT, VCardType> AncestorType; //! List of expected results @@ -141,11 +83,11 @@ class ReserveParticipationCostByDispatchablePlant }; public: - ReserveParticipationCostByDispatchablePlant() : pValuesForTheCurrentYear(NULL), pSize(0) + ReserveParticipationByDispatchablePlant() : pValuesForTheCurrentYear(NULL), pSize(0) { } - ~ReserveParticipationCostByDispatchablePlant() + ~ReserveParticipationByDispatchablePlant() { for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) delete[] pValuesForTheCurrentYear[numSpace]; @@ -164,14 +106,13 @@ class ReserveParticipationCostByDispatchablePlant pNbYearsParallel = study->maxNbYearsInParallel; pValuesForTheCurrentYear = new VCardType::IntermediateValuesBaseType[pNbYearsParallel]; - // Get the area pSize = 0; for (int areaIndex = 0; areaIndex < study->areas.size(); areaIndex++) { if (study->areas[areaIndex]->allCapacityReservations.size() > 0) { - pSize = area->thermal.list.allClustersCount(); + pSize = area->thermal.list.reserveParticipationsCount(); break; } } @@ -239,13 +180,21 @@ class ReserveParticipationCostByDispatchablePlant void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) { // Get end year calculations - if (pSize) { + if (pSize) + { for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; - i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; - ++i) + i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + ++i) { - pValuesForTheCurrentYear[numSpace][state.thermalCluster->areaWideIndex].hour[i] - = state.thermalClusterReserveParticipationCostForYear[i]; + for (auto const& [reserveName, reserveParticipation] : + state.thermalReserveParticipationPerClusterForYear[i][state.thermalCluster + ->name()]) + { + pValuesForTheCurrentYear[numSpace][state.getIndexFromReserveAndCluster( + reserveName, state.thermalCluster->name())] + .hour[i] + = reserveParticipation; + } } } @@ -340,11 +289,11 @@ class ReserveParticipationCostByDispatchablePlant size_t pSize; unsigned int pNbYearsParallel; -}; // class ReserveParticipationCostByDispatchablePlant +}; // class ReserveParticipationByDispatchablePlant } // namespace Economy } // namespace Variable } // namespace Solver } // namespace Antares -#endif // __SOLVER_VARIABLE_ECONOMY_ReserveParticipationCostByDispatchablePlant_H__ \ No newline at end of file +#endif // __SOLVER_VARIABLE_ECONOMY_ReserveParticipationByDispatchablePlant_H__ \ No newline at end of file diff --git a/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h new file mode 100644 index 0000000000..d773aafa16 --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h @@ -0,0 +1,103 @@ +/* +** 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 +*/ +#ifndef __SOLVER_VARIABLE_ECONOMY_VCardReserveParticipationByDispatchablePlant_H__ +#define __SOLVER_VARIABLE_ECONOMY_VCardReserveParticipationByDispatchablePlant_H__ + +#include "../storage/results.h" + +namespace Antares +{ +namespace Solver +{ +namespace Variable +{ +namespace Economy +{ +struct VCardReserveParticipationByDispatchablePlant +{ + //! Caption + static std::string Caption() + { + return "CLUSTER PARTICIPATION TO RESERVE"; + } + //! Unit + static std::string Unit() + { + return "Reserve Participation Power - MW"; + } + + //! The short description of the variable + static std::string Description() + { + return "Reserve Participation from a cluster to a reserve"; + } + + //! The expected results + typedef Results> + ResultsType; + + //! The VCard to look for for calculating spatial aggregates + typedef VCardReserveParticipationByDispatchablePlant VCardForSpatialAggregate; + + enum + { + //! Data Level + categoryDataLevel = Category::area, + //! File level (provided by the type of the results) + categoryFileLevel = ResultsType::categoryFile & (Category::de), + //! Precision (views) + precision = Category::all, + //! Indentation (GUI) + nodeDepthForGUI = +0, + //! Decimal precision + decimal = 0, + //! Number of columns used by the variable + columnCount = Category::dynamicColumns, + //! The Spatial aggregation + spatialAggregate = Category::spatialAggregateSum, + spatialAggregateMode = Category::spatialAggregateEachYear, + spatialAggregatePostProcessing = 0, + //! Intermediate values + hasIntermediateValues = 1, + //! Can this variable be non applicable (0 : no, 1 : yes) + isPossiblyNonApplicable = 0, + }; + + typedef IntermediateValues IntermediateValuesDeepType; + typedef IntermediateValues* IntermediateValuesBaseType; + typedef IntermediateValuesBaseType* IntermediateValuesType; + + // typedef IntermediateValues IntermediateValuesType; + +}; // class VCard +} // namespace Economy +} // namespace Variable +} // namespace Solver +} // namespace Antares + +#endif //__SOLVER_VARIABLE_ECONOMY_VCardReserveParticipationByDispatchablePlant_H__ \ No newline at end of file diff --git a/src/solver/variable/include/antares/solver/variable/info.h b/src/solver/variable/include/antares/solver/variable/info.h index 00cfc00f22..7d3642c26b 100644 --- a/src/solver/variable/include/antares/solver/variable/info.h +++ b/src/solver/variable/include/antares/solver/variable/info.h @@ -22,6 +22,7 @@ #define __SOLVER_VARIABLE_INFO_H__ #include +#include "./economy/vCardReserveParticipationByDispatchablePlant.h" namespace Antares { @@ -368,13 +369,31 @@ struct VariableAccessor const Data::PartThermal& thermal = results.data.area->thermal; for (uint i = 0; i != container.size(); ++i) { - results.variableCaption = thermal.list.enabledClusterAt(i)->name(); + if (typeid(VCardT) == typeid(Economy::VCardReserveParticipationByDispatchablePlant)) + { + auto [clusterName, reserveName] + = thermal.list.reserveParticipationAt(results.data.area, i); + results.variableCaption = reserveName + "_" + clusterName; + } + else + results.variableCaption = thermal.list.enabledClusterAt(i)->name(); container[i].template buildDigest(results, digestLevel, dataLevel); } } } + static bool setClusterReserveCaption(SurveyResults& results, uint reserveParticipationIdx) + { + assert(results.data.area && "Area is NULL"); + + auto& thermal = results.data.area->thermal; + auto [clusterName, reserveName] + = thermal.list.reserveParticipationAt(results.data.area, reserveParticipationIdx); + results.variableCaption = clusterName + " - " + reserveName; + return true; + } + static bool setClusterCaption(SurveyResults& results, int fileLevel, uint idx) { assert(results.data.area && "Area is NULL"); @@ -427,7 +446,11 @@ struct VariableAccessor { for (uint i = 0; i != container.size(); ++i) { - res = setClusterCaption(results, fileLevel, i); + if (typeid(VCardType) + == typeid(Economy::VCardReserveParticipationByDispatchablePlant)) + res = setClusterReserveCaption(results, i); + else + res = setClusterCaption(results, fileLevel, i); if (!res) return; results.variableUnit = VCardType::Unit(); diff --git a/src/solver/variable/include/antares/solver/variable/state.h b/src/solver/variable/include/antares/solver/variable/state.h index 33bb79d375..a9d349bab5 100644 --- a/src/solver/variable/include/antares/solver/variable/state.h +++ b/src/solver/variable/include/antares/solver/variable/state.h @@ -104,7 +104,7 @@ class State void yearEndBuildFromThermalClusterIndex(const unsigned int areaWideIndex); - int getIndexFromClusterAndReserve(std::string reserveName, std::string clusterName); + int getIndexFromReserveAndCluster(Data::ReserveName reserveName, Data::ClusterName clusterName); private: /*! ** \brief Initialize some variable according a thermal cluster index @@ -190,9 +190,13 @@ class State double thermalClusterProductionForYear[Variable::maxHoursInAYear]; //! Reserve Participation for all thermal group types (nuclear / coal / ...) for the whole year //! per reserve - std::map> + std::map> thermalReserveParticipationPerGroupForYear[Variable::maxHoursInAYear]; + //! Reserve Participation for all clusters per reserve + std::map> + thermalReserveParticipationPerClusterForYear[Variable::maxHoursInAYear]; + //! Number of unit dispatched for all clusters for the whole year for ucHeruistic (fast) or //! ucMILP (accurate) uint thermalClusterDispatchedUnitsCountForYear[Variable::maxHoursInAYear]; diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index f83e4ee3b6..39a4f76f20 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -153,7 +153,7 @@ void State::initFromThermalClusterIndex(const uint clusterAreaWideIndex) // en mode fast : est pris depuis l'heuristique } -int State::getIndexFromClusterAndReserve(std::string reserveName, std::string clusterName) +int State::getIndexFromReserveAndCluster(Data::ReserveName reserveName, Data::ClusterName clusterName) { for (auto reserve : problemeHebdo->allReserves.thermalAreaReserves[area->index].areaCapacityReservationsUp) { @@ -238,15 +238,15 @@ void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideInde std::vector clusterReserves = thermalCluster->listOfParticipatingReserves(); for (auto res : clusterReserves) { - int clusterIndex = getIndexFromClusterAndReserve(res, thermalCluster->name()); - if (clusterIndex != -1) + int reserveParticipationIdx = getIndexFromReserveAndCluster(res, thermalCluster->name()); + if (reserveParticipationIdx != -1) { thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] += hourlyResults->ProductionThermique[hourInTheWeek] - .ParticipationReservesDuPalier[clusterIndex] + .ParticipationReservesDuPalier[reserveParticipationIdx] * thermalCluster->reserveCost(res); double participation = hourlyResults->ProductionThermique[hourInTheWeek] - .ParticipationReservesDuPalier[clusterIndex]; + .ParticipationReservesDuPalier[reserveParticipationIdx]; if (participation) { thermalClusterReserveParticipationCostForYear[hourInTheYear] @@ -254,6 +254,10 @@ void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideInde thermalReserveParticipationPerGroupForYear[hourInTheYear][res][thermalCluster->groupID] += participation; + + thermalReserveParticipationPerClusterForYear[hourInTheYear][thermalCluster->name()][res] + += participation; + thermal[area->index].nbThermalGroupsForReserves[thermalCluster->groupID]++; } From 60eff8edf35f7d8a939d45929b9e4793ff510a6e Mon Sep 17 00:00:00 2001 From: h-fournier Date: Mon, 24 Jun 2024 09:35:33 +0200 Subject: [PATCH 34/41] =?UTF-8?q?Add=20a=20column=20for=20each=20group=20f?= =?UTF-8?q?o=20each=20reserve=20for=20the=20participation=20to=20the=20res?= =?UTF-8?q?erves:=20Specs=20:=20On=20ajoutera=20la=20participation=20?= =?UTF-8?q?=C3=A0=20chaque=20r=C3=A9serves=20via=20la=20d=C3=A9finition=20?= =?UTF-8?q?de=20nouvelles=20colonnes=20pour=20chaque=20type=20de=20product?= =?UTF-8?q?ion=20(nucl=C3=A9aire,=20charbon=E2=80=A6)=20("?= =?UTF-8?q?=5F").?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../antares/study/parts/common/cluster_list.h | 15 +- .../study/parts/common/cluster_list.cpp | 36 +- src/solver/variable/CMakeLists.txt | 1 + .../antares/solver/variable/economy/all.h | 8 +- .../economy/reserveParticipationByGroup.h | 328 ++++++++++++++++++ .../vCardReserveParticipationByGroup.h | 133 +++++++ .../include/antares/solver/variable/info.h | 27 +- .../include/antares/solver/variable/state.h | 6 +- src/solver/variable/state.cpp | 13 +- 9 files changed, 539 insertions(+), 28 deletions(-) create mode 100644 src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByGroup.h create mode 100644 src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByGroup.h diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h index 978ee182db..780faf2997 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -99,11 +100,21 @@ class ClusterList /*! ** @brief Get the cluster and reserve names for a given index of reserveParticipation - ** @param area The area where to took for the reserveParticipation + ** @param area The area where to look for the reserveParticipation ** @param index Global index of the reserveParicipation ** @return the cluster and reserve names */ - std::pair reserveParticipationAt( + std::pair reserveParticipationClusterAt( + const Area* area, + unsigned int index) const; + + /*! + ** @brief Get the group and reserve names for a given index of reserveParticipation + ** @param area The area where to look for the reserveParticipation + ** @param index Global index of the reserveParicipation + ** @return the group and reserve names + */ + std::pair reserveParticipationGroupAt( const Area* area, unsigned int index) const; diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index 212e195aa5..dfc11f688e 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -56,9 +56,8 @@ std::shared_ptr ClusterList::enabledClusterAt(unsigned int i } template -std::pair ClusterList::reserveParticipationAt( - const Area* area, - unsigned int index) const +std::pair + ClusterList::reserveParticipationClusterAt(const Area* area, unsigned int index) const { int globalReserveParticipationIdx = 0; @@ -93,8 +92,35 @@ std::pair ClusterList::reservePa } } - throw std::out_of_range( - "This reserve participation index has not been found in all the reserve participations"); + throw std::out_of_range("This cluster reserve participation index has not been found in all " + "the reserve participations"); +} + +template +std::pair + ClusterList::reserveParticipationGroupAt(const Area* area, unsigned int index) const +{ + int column = 0; + for (auto [reserveName, _] : area->allCapacityReservations.areaCapacityReservationsUp) + { + for (int indexGroup = 0; indexGroup < Data::groupMax; indexGroup++) + { + if (column == index) + return {static_cast(indexGroup), reserveName}; + column++; + } + } + for (auto [reserveName, _] : area->allCapacityReservations.areaCapacityReservationsDown) + { + for (int indexGroup = 0; indexGroup < Data::groupMax; indexGroup++) + { + if (column == index) + return {static_cast(indexGroup), reserveName}; + column++; + } + } + throw std::out_of_range("This group reserve participation index has not been found in all the " + "reserve participations"); } template diff --git a/src/solver/variable/CMakeLists.txt b/src/solver/variable/CMakeLists.txt index ec62c3d176..292ce8ed35 100644 --- a/src/solver/variable/CMakeLists.txt +++ b/src/solver/variable/CMakeLists.txt @@ -130,6 +130,7 @@ set(SRC_VARIABLE_ECONOMY include/antares/solver/variable/economy/reserveParticipationCost.h include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h + include/antares/solver/variable/economy/reserveParticipationByGroup.h # Links include/antares/solver/variable/economy/links/flowLinear.h diff --git a/src/solver/variable/include/antares/solver/variable/economy/all.h b/src/solver/variable/include/antares/solver/variable/economy/all.h index a2e14e0c0b..150f0afb5e 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/all.h +++ b/src/solver/variable/include/antares/solver/variable/economy/all.h @@ -75,6 +75,7 @@ #include "nbOfDispatchedUnitsByPlant.h" #include "profitByPlant.h" #include "reserveParticipationByDispatchablePlant.h" +#include "reserveParticipationByGroup.h" // By RES plant #include "productionByRenewablePlant.h" @@ -172,9 +173,10 @@ typedef // Prices >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VariablesPerArea; /*! diff --git a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByGroup.h b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByGroup.h new file mode 100644 index 0000000000..e03a2bd5cb --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByGroup.h @@ -0,0 +1,328 @@ +/* +** 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 +*/ +#ifndef __SOLVER_VARIABLE_ECONOMY_ReserveParticipationByGroup_H__ +#define __SOLVER_VARIABLE_ECONOMY_ReserveParticipationByGroup_H__ + +#include "../variable.h" +#include "./vCardReserveParticipationByGroup.h" + +namespace Antares +{ +namespace Solver +{ +namespace Variable +{ +namespace Economy +{ + +/*! +** \brief Reserve participation for all groups for all reserves of the area +*/ +template +class ReserveParticipationByGroup : public Variable::IVariable, + NextT, + VCardReserveParticipationByGroup> +{ +public: + //! Type of the next static variable + typedef NextT NextType; + //! VCard + typedef VCardReserveParticipationByGroup VCardType; + //! Ancestor + typedef Variable::IVariable, NextT, VCardType> AncestorType; + + //! List of expected results + typedef typename VCardType::ResultsType ResultsType; + + typedef VariableAccessor VariableAccessorType; + + enum + { + //! How many items have we got + count = 1 + NextT::count, + }; + + template + struct Statistics + { + enum + { + count + = ((VCardType::categoryDataLevel & CDataLevel && VCardType::categoryFileLevel & CFile) + ? (NextType::template Statistics::count + + VCardType::columnCount * ResultsType::count) + : NextType::template Statistics::count), + }; + }; + +public: + ReserveParticipationByGroup() : pValuesForTheCurrentYear(NULL), pSize(0) + { + } + + ~ReserveParticipationByGroup() + { + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + delete[] pValuesForTheCurrentYear[numSpace]; + delete[] pValuesForTheCurrentYear; + } + + void initializeFromStudy(Data::Study& study) + { + // Next + NextType::initializeFromStudy(study); + } + + void initializeFromArea(Data::Study* study, Data::Area* area) + { + // Get the number of years in parallel + pNbYearsParallel = study->maxNbYearsInParallel; + pValuesForTheCurrentYear = new VCardType::IntermediateValuesBaseType[pNbYearsParallel]; + + // Get the area + pSize = 0; + for (auto res : area->allCapacityReservations.areaCapacityReservationsUp) + { + pSize += Antares::Data::groupMax; + } + for (auto res : area->allCapacityReservations.areaCapacityReservationsDown) + { + pSize += Antares::Data::groupMax; + } + if (pSize) + { + AncestorType::pResults.resize(pSize); + + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + pValuesForTheCurrentYear[numSpace] + = new VCardType::IntermediateValuesDeepType[pSize]; + + // Minimum power values of the cluster for the whole year - from the solver in the + // accurate mode not to be displayed in the output \todo think of a better place like + // the DispatchableMarginForAllAreas done at the beginning of the year + + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + for (unsigned int i = 0; i != pSize; ++i) + pValuesForTheCurrentYear[numSpace][i].initializeFromStudy(*study); + + for (unsigned int i = 0; i != pSize; ++i) + { + AncestorType::pResults[i].initializeFromStudy(*study); + AncestorType::pResults[i].reset(); + } + } + else + { + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + { + pValuesForTheCurrentYear[numSpace] = nullptr; + } + AncestorType::pResults.clear(); + } + // Next + NextType::initializeFromArea(study, area); + } + + size_t getMaxNumberColumns() const + { + return pSize * ResultsType::count; + } + + void initializeFromLink(Data::Study* study, Data::AreaLink* link) + { + // Next + NextType::initializeFromAreaLink(study, link); + } + + void simulationBegin() + { + // Next + NextType::simulationBegin(); + } + + void simulationEnd() + { + NextType::simulationEnd(); + } + + void yearBegin(unsigned int year, unsigned int numSpace) + { + // Reset the values for the current year + for (unsigned int i = 0; i != pSize; ++i) + pValuesForTheCurrentYear[numSpace][i].reset(); + + // Next variable + NextType::yearBegin(year, numSpace); + } + + void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) + { + // Next variable + NextType::yearEndBuildForEachThermalCluster(state, year, numSpace); + } + + void yearEndBuild(State& state, unsigned int year) + { + // Next variable + NextType::yearEndBuild(state, year); + } + + void yearEnd(unsigned int year, unsigned int numSpace) + { + // Merge all results for all thermal clusters + { + for (unsigned int i = 0; i < pSize; ++i) + { + // Compute all statistics for the current year (daily,weekly,monthly) + pValuesForTheCurrentYear[numSpace][i].computeStatisticsForTheCurrentYear(); + } + } + // Next variable + NextType::yearEnd(year, numSpace); + } + + void computeSummary(std::map& numSpaceToYear, + unsigned int nbYearsForCurrentSummary) + { + for (unsigned int numSpace = 0; numSpace < nbYearsForCurrentSummary; ++numSpace) + { + for (unsigned int i = 0; i < pSize; ++i) + { + // Merge all those values with the global results + AncestorType::pResults[i].merge(numSpaceToYear[numSpace], + pValuesForTheCurrentYear[numSpace][i]); + } + } + + // Next variable + NextType::computeSummary(numSpaceToYear, nbYearsForCurrentSummary); + } + + void hourBegin(unsigned int hourInTheYear) + { + // Next variable + NextType::hourBegin(hourInTheYear); + } + + void hourForEachArea(State& state, unsigned int numSpace) + { + auto& area = state.area; + auto& thermal = state.thermal; + int column = 0; + for (auto [reserveName, _] : area->allCapacityReservations.areaCapacityReservationsUp) + { + for (int indexGroup = 0; indexGroup < Antares::Data::groupMax; indexGroup++) + { + pValuesForTheCurrentYear[numSpace][column].hour[state.hourInTheYear] + += state.thermalReserveParticipationPerGroupForYear + [state.hourInTheYear][static_cast(indexGroup)] + [reserveName]; + column++; + } + } + for (auto [reserveName, _] : area->allCapacityReservations.areaCapacityReservationsDown) + { + for (int indexGroup = 0; indexGroup < Antares::Data::groupMax; indexGroup++) + { + pValuesForTheCurrentYear[numSpace][column].hour[state.hourInTheYear] + += state.thermalReserveParticipationPerGroupForYear + [state.hourInTheYear][static_cast(indexGroup)] + [reserveName]; + column++; + } + } + // Next variable + NextType::hourForEachArea(state, numSpace); + } + + Antares::Memory::Stored::ConstReturnType retrieveRawHourlyValuesForCurrentYear( + unsigned int, + unsigned int numSpace) const + { + return pValuesForTheCurrentYear[numSpace]->hour; + } + + void localBuildAnnualSurveyReport(SurveyResults& results, + int fileLevel, + int precision, + unsigned int numSpace) const + { + // Initializing external pointer on current variable non applicable status + results.isCurrentVarNA = AncestorType::isNonApplicable; + + if (AncestorType::isPrinted[0]) + { + assert(NULL != results.data.area); + const auto& thermal = results.data.area->thermal; + + // Write the data for the current year + int column = 0; + for (auto res : results.data.area->allCapacityReservations.areaCapacityReservationsUp) + { + for (int indexGroup = 0; indexGroup < Antares::Data::groupMax; indexGroup++) + { + // Write the data for the current year + Yuni::String caption = res.first; + caption << "_" << Data::ThermalCluster::GroupName(static_cast(indexGroup)); + results.variableCaption = caption; // VCardType::Caption(); + results.variableUnit = VCardType::Unit(); + pValuesForTheCurrentYear[numSpace][column].template buildAnnualSurveyReport( + results, fileLevel, precision); + column++; + } + } + for (auto res : results.data.area->allCapacityReservations.areaCapacityReservationsDown) + { + for (int indexGroup = 0; indexGroup < Antares::Data::groupMax; indexGroup++) + { + // Write the data for the current year + Yuni::String caption = res.first; + caption << "_" << Data::ThermalCluster::GroupName(static_cast(indexGroup)); + results.variableCaption = caption; // VCardType::Caption(); + results.variableUnit = VCardType::Unit(); + pValuesForTheCurrentYear[numSpace][column].template buildAnnualSurveyReport( + results, fileLevel, precision); + column++; + } + } + } + } + +private: + //! Intermediate values for each year + typename VCardType::IntermediateValuesType pValuesForTheCurrentYear; + size_t pSize; + unsigned int pNbYearsParallel; + +}; // class ReserveParticipationByGroup + +} // namespace Economy +} // namespace Variable +} // namespace Solver +} // namespace Antares + +#endif // __SOLVER_VARIABLE_ECONOMY_ReserveParticipationByGroup_H__ \ No newline at end of file diff --git a/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByGroup.h b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByGroup.h new file mode 100644 index 0000000000..6ea3ed84cd --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByGroup.h @@ -0,0 +1,133 @@ +/* +** 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 +*/ +#ifndef __SOLVER_VARIABLE_ECONOMY_VCardReserveParticipationByGroup_H__ +#define __SOLVER_VARIABLE_ECONOMY_VCardReserveParticipationByGroup_H__ + +#include "../storage/results.h" + +namespace Antares +{ +namespace Solver +{ +namespace Variable +{ +namespace Economy +{ +struct VCardReserveParticipationByGroup +{ + //! Caption + static std::string Caption() + { + return "GROUP PARTICIPATION TO RESERVE"; + } + //! Unit + static std::string Unit() + { + return "MWh"; + } + + //! The short description of the variable + static std::string Description() + { + return "Reserve Participation from a group to a reserve"; + } + + //! The expected results + typedef Results> + ResultsType; + + //! The VCard to look for for calculating spatial aggregates + typedef VCardReserveParticipationByGroup VCardForSpatialAggregate; + + enum + { + //! Data Level + categoryDataLevel = Category::area, + //! File level (provided by the type of the results) + categoryFileLevel = ResultsType::categoryFile & (Category::id | Category::va), + //! Precision (views) + precision = Category::all, + //! Indentation (GUI) + nodeDepthForGUI = +0, + //! Decimal precision + decimal = 0, + //! Number of columns used by the variable + columnCount = Category::dynamicColumns, + //! The Spatial aggregation + spatialAggregate = Category::spatialAggregateSum, + spatialAggregateMode = Category::spatialAggregateEachYear, + spatialAggregatePostProcessing = 0, + //! Intermediate values + hasIntermediateValues = 1, + //! Can this variable be non applicable (0 : no, 1 : yes) + isPossiblyNonApplicable = 0, + }; + + typedef IntermediateValues IntermediateValuesDeepType; + typedef IntermediateValues* IntermediateValuesBaseType; + typedef IntermediateValuesBaseType* IntermediateValuesType; + + // typedef IntermediateValues IntermediateValuesType; + +}; // class VCard + +static std::string thermalDispatchableGroupToString(Data::ThermalDispatchableGroup idx) +{ + switch (idx) + { + case 0: + return "NUCLEAR"; + case 1: + return "LIGNITE"; + case 2: + return "COAL"; + case 3: + return "GAS"; + case 4: + return "OIL"; + case 5: + return "MIX. FUEL"; + case 6: + return "MISC. DTG"; + case 7: + return "MISC. DTG 2"; + case 8: + return "MISC. DTG 3"; + case 9: + return "MISC. DTG 4"; + + default: + return ""; + } +} +} // namespace Economy +} // namespace Variable +} // namespace Solver +} // namespace Antares + +#endif //__SOLVER_VARIABLE_ECONOMY_VCardReserveParticipationByDispatchablePlant_H__ \ No newline at end of file diff --git a/src/solver/variable/include/antares/solver/variable/info.h b/src/solver/variable/include/antares/solver/variable/info.h index 7d3642c26b..2b3874aa14 100644 --- a/src/solver/variable/include/antares/solver/variable/info.h +++ b/src/solver/variable/include/antares/solver/variable/info.h @@ -23,6 +23,7 @@ #include #include "./economy/vCardReserveParticipationByDispatchablePlant.h" +#include "./economy/vCardReserveParticipationByGroup.h" namespace Antares { @@ -372,8 +373,13 @@ struct VariableAccessor if (typeid(VCardT) == typeid(Economy::VCardReserveParticipationByDispatchablePlant)) { auto [clusterName, reserveName] - = thermal.list.reserveParticipationAt(results.data.area, i); + = thermal.list.reserveParticipationClusterAt(results.data.area, i); results.variableCaption = reserveName + "_" + clusterName; + } else if (typeid(VCardT) == typeid(Economy::VCardReserveParticipationByGroup)) + { + auto [groupName, reserveName] + = thermal.list.reserveParticipationGroupAt(results.data.area, i); + results.variableCaption = reserveName + "_" + Economy::thermalDispatchableGroupToString(groupName); } else results.variableCaption = thermal.list.enabledClusterAt(i)->name(); @@ -389,7 +395,7 @@ struct VariableAccessor auto& thermal = results.data.area->thermal; auto [clusterName, reserveName] - = thermal.list.reserveParticipationAt(results.data.area, reserveParticipationIdx); + = thermal.list.reserveParticipationClusterAt(results.data.area, reserveParticipationIdx); results.variableCaption = clusterName + " - " + reserveName; return true; } @@ -444,11 +450,22 @@ struct VariableAccessor bool res; if (*results.isPrinted) { + const Data::PartThermal& thermal = results.data.area->thermal; for (uint i = 0; i != container.size(); ++i) { - if (typeid(VCardType) - == typeid(Economy::VCardReserveParticipationByDispatchablePlant)) - res = setClusterReserveCaption(results, i); + if (typeid(VCardType) == typeid(Economy::VCardReserveParticipationByDispatchablePlant)) + { + auto [clusterName, reserveName] + = thermal.list.reserveParticipationClusterAt(results.data.area, i); + results.variableCaption = reserveName + "_" + clusterName; + res = true; + } else if (typeid(VCardType) == typeid(Economy::VCardReserveParticipationByGroup)) + { + auto [groupName, reserveName] + = thermal.list.reserveParticipationGroupAt(results.data.area, i); + results.variableCaption = reserveName + "_" + Economy::thermalDispatchableGroupToString(groupName); + res = true; + } else res = setClusterCaption(results, fileLevel, i); if (!res) diff --git a/src/solver/variable/include/antares/solver/variable/state.h b/src/solver/variable/include/antares/solver/variable/state.h index a9d349bab5..0735d28e23 100644 --- a/src/solver/variable/include/antares/solver/variable/state.h +++ b/src/solver/variable/include/antares/solver/variable/state.h @@ -59,10 +59,6 @@ class ThermalState std::vector unitCountLastHour; std::vector productionLastHour; std::vector pminOfAGroup; - - //! Track the number of thermalGroup different types participating to the reserves - std::vector nbThermalGroupsForReserves; - }; StateForAnArea& operator[](size_t areaIndex); @@ -190,7 +186,7 @@ class State double thermalClusterProductionForYear[Variable::maxHoursInAYear]; //! Reserve Participation for all thermal group types (nuclear / coal / ...) for the whole year //! per reserve - std::map> + std::map> thermalReserveParticipationPerGroupForYear[Variable::maxHoursInAYear]; //! Reserve Participation for all clusters per reserve diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index 39a4f76f20..ceac1f6ddf 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -58,7 +58,6 @@ void ThermalState::StateForAnArea::initializeFromArea(const Data::Area& area) unitCountLastHour.resize(count, 0); productionLastHour.resize(count, 0); pminOfAGroup.resize(count, 0); - nbThermalGroupsForReserves.resize(Antares::Data::groupMax, 0); } State::State(Data::Study& s) : @@ -252,14 +251,12 @@ void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideInde thermalClusterReserveParticipationCostForYear[hourInTheYear] += participation * thermalCluster->reserveCost(res); - thermalReserveParticipationPerGroupForYear[hourInTheYear][res][thermalCluster->groupID] + thermalReserveParticipationPerGroupForYear[hourInTheYear][thermalCluster->groupID][res] += participation; - thermalReserveParticipationPerClusterForYear[hourInTheYear][thermalCluster->name()][res] - += participation; - - thermal[area->index].nbThermalGroupsForReserves[thermalCluster->groupID]++; - + thermalReserveParticipationPerClusterForYear[hourInTheYear] + [thermalCluster->name()][res] + += participation; } } else @@ -440,7 +437,7 @@ void State::yearEndBuildCalculateReserveParticipationCosts( for (auto res : clusterReserves) { - file << "Hour " << h + 1 << " : cluster " << thermalCluster->name() << " is participating to reserve " << res << " for " << thermalReserveParticipationPerGroupForYear[h][res][thermalCluster->groupID] << " mw\n"; + file << "Hour " << h + 1 << " : cluster " << thermalCluster->name() << " is participating to reserve " << res << " for " << thermalReserveParticipationPerGroupForYear[h][thermalCluster->groupID][res] << " mw\n"; } } file.close(); From e7ea4b32ad8a53a22bf1a7a7bb651031600e4859 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Mon, 24 Jun 2024 18:10:06 +0200 Subject: [PATCH 35/41] Added outputs for spilled and unsupplied volumes into the interface and removed them from text outputs --- .../antares/study/parts/common/cluster_list.h | 10 + .../antares/study/parts/thermal/cluster.h | 11 + .../study/parts/common/cluster_list.cpp | 28 ++ src/solver/variable/CMakeLists.txt | 3 + ...ardReserveParticipationUnsuppliedSpilled.h | 117 +++++++ .../antares/solver/variable/economy/all.h | 11 +- .../solver/variable/economy/overallCost.h | 31 +- .../reserveParticipationUnsuppliedSpilled.h | 328 ++++++++++++++++++ ...dReserveParticipationByDispatchablePlant.h | 2 +- .../include/antares/solver/variable/info.h | 14 + .../include/antares/solver/variable/state.h | 1 - src/solver/variable/state.cpp | 40 +-- 12 files changed, 523 insertions(+), 73 deletions(-) create mode 100644 src/solver/variable/include/antares/solver/variable/economy/VCardReserveParticipationUnsuppliedSpilled.h create mode 100644 src/solver/variable/include/antares/solver/variable/economy/reserveParticipationUnsuppliedSpilled.h diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h index 780faf2997..30b11b08ee 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h @@ -119,6 +119,16 @@ class ClusterList unsigned int index) const; /*! +** @brief Get the reserve and spilled/unsupplied status and names for a given index of reserveParticipation +** @param area The area where to look for the reserveParticipation +** @param index Global index of the reserveParicipation +** @return the status and reserve names +*/ + std::pair reserveParticipationUnsuppliedSpilledAt( + const Area* area, + unsigned int index) const; + + /*! ** \brief Resize all matrices dedicated to the sampled timeseries numbers ** ** \param n A number of years diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h b/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h index ac53ab3b75..5cb331230c 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h @@ -94,6 +94,17 @@ enum ThermalDispatchableGroup groupMax }; +enum ThermalUnsuppliedSpilled +{ + //! Spilled + ThermalUnsuppliedSpilledSpilled = 0, + //! Unsupplied + ThermalUnsuppliedSpilledUnsupplied, + + //! The highest value + unsuppliedSpilledMax +}; + /*! ** \brief A single thermal cluster */ diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index dfc11f688e..5ab34ca02b 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -123,6 +123,34 @@ std::pair "reserve participations"); } +template +std::pair +ClusterList::reserveParticipationUnsuppliedSpilledAt(const Area* area, unsigned int index) const +{ + int column = 0; + for (auto [reserveName, _] : area->allCapacityReservations.areaCapacityReservationsUp) + { + for (int indexUnsuppliedSpilled = 0; indexUnsuppliedSpilled < Data::unsuppliedSpilledMax; indexUnsuppliedSpilled++) + { + if (column == index) + return { static_cast(indexUnsuppliedSpilled), reserveName }; + column++; + } + } + for (auto [reserveName, _] : area->allCapacityReservations.areaCapacityReservationsDown) + { + for (int indexUnsuppliedSpilled = 0; indexUnsuppliedSpilled < Data::unsuppliedSpilledMax; indexUnsuppliedSpilled++) + { + if (column == index) + return { static_cast(indexUnsuppliedSpilled), reserveName }; + column++; + } + } + throw std::out_of_range("This reserve status index has not been found in all the " + "reserve participations"); +} + + template ClusterT* ClusterList::findInAll(std::string_view id) const { diff --git a/src/solver/variable/CMakeLists.txt b/src/solver/variable/CMakeLists.txt index 292ce8ed35..5db18dc13c 100644 --- a/src/solver/variable/CMakeLists.txt +++ b/src/solver/variable/CMakeLists.txt @@ -130,7 +130,10 @@ set(SRC_VARIABLE_ECONOMY include/antares/solver/variable/economy/reserveParticipationCost.h include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h + include/antares/solver/variable/economy/reserveParticipationUnsuppliedSpilled.h + include/antares/solver/variable/economy/vCardReserveParticipationUnsuppliedSpilled.h include/antares/solver/variable/economy/reserveParticipationByGroup.h + include/antares/solver/variable/economy/vCardreserveParticipationByGroup.h # Links include/antares/solver/variable/economy/links/flowLinear.h diff --git a/src/solver/variable/include/antares/solver/variable/economy/VCardReserveParticipationUnsuppliedSpilled.h b/src/solver/variable/include/antares/solver/variable/economy/VCardReserveParticipationUnsuppliedSpilled.h new file mode 100644 index 0000000000..a5c093220c --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/VCardReserveParticipationUnsuppliedSpilled.h @@ -0,0 +1,117 @@ +/* +** 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 +*/ +#ifndef __SOLVER_VARIABLE_ECONOMY_VCardReserveParticipationUnsuppliedSpilled_H__ +#define __SOLVER_VARIABLE_ECONOMY_VCardReserveParticipationUnsuppliedSpilled_H__ + +#include "../storage/results.h" + +namespace Antares +{ +namespace Solver +{ +namespace Variable +{ +namespace Economy +{ +struct VCardReserveParticipationUnsuppliedSpilled +{ + //! Caption + static std::string Caption() + { + return "RESERVE UNSUPPLIED OR SPILLED ENERGY"; + } + //! Unit + static std::string Unit() + { + return "MWh"; + } + + //! The short description of the variable + static std::string Description() + { + return "Reserve unsupplied or spilled Power"; + } + + //! The expected results + typedef Results> + ResultsType; + + //! The VCard to look for for calculating spatial aggregates + typedef VCardReserveParticipationUnsuppliedSpilled VCardForSpatialAggregate; + + enum + { + //! Data Level + categoryDataLevel = Category::area, + //! File level (provided by the type of the results) + categoryFileLevel = ResultsType::categoryFile & (Category::id | Category::va), + //! Precision (views) + precision = Category::all, + //! Indentation (GUI) + nodeDepthForGUI = +0, + //! Decimal precision + decimal = 0, + //! Number of columns used by the variable + columnCount = Category::dynamicColumns, + //! The Spatial aggregation + spatialAggregate = Category::spatialAggregateSum, + spatialAggregateMode = Category::spatialAggregateEachYear, + spatialAggregatePostProcessing = 0, + //! Intermediate values + hasIntermediateValues = 1, + //! Can this variable be non applicable (0 : no, 1 : yes) + isPossiblyNonApplicable = 0, + }; + + typedef IntermediateValues IntermediateValuesDeepType; + typedef IntermediateValues* IntermediateValuesBaseType; + typedef IntermediateValuesBaseType* IntermediateValuesType; + + // typedef IntermediateValues IntermediateValuesType; + +}; // class VCard + +static std::string thermalUnsuppliedSpilledToString(Data::ThermalUnsuppliedSpilled idx) +{ + switch (idx) + { + case 0: + return "UNSP."; + case 1: + return "SPIL."; + default: + return ""; + } +} + +} // namespace Economy +} // namespace Variable +} // namespace Solver +} // namespace Antares + +#endif //__SOLVER_VARIABLE_ECONOMY_VCardReserveParticipationUnsuppliedSpilled_H__ \ No newline at end of file diff --git a/src/solver/variable/include/antares/solver/variable/economy/all.h b/src/solver/variable/include/antares/solver/variable/economy/all.h index 150f0afb5e..d6dfa246bc 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/all.h +++ b/src/solver/variable/include/antares/solver/variable/economy/all.h @@ -61,6 +61,8 @@ #include "dtgMarginAfterCsr.h" #include "spilledEnergy.h" #include "reserveParticipationCost.h" +#include "reserveParticipationByGroup.h" +#include "reserveParticipationUnsuppliedSpilled.h" #include "lold.h" #include "lolp.h" @@ -75,7 +77,7 @@ #include "nbOfDispatchedUnitsByPlant.h" #include "profitByPlant.h" #include "reserveParticipationByDispatchablePlant.h" -#include "reserveParticipationByGroup.h" + // By RES plant #include "productionByRenewablePlant.h" @@ -174,9 +176,10 @@ typedef // Prices >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VariablesPerArea; /*! diff --git a/src/solver/variable/include/antares/solver/variable/economy/overallCost.h b/src/solver/variable/include/antares/solver/variable/economy/overallCost.h index 3628a6580e..3a9db96798 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/overallCost.h +++ b/src/solver/variable/include/antares/solver/variable/economy/overallCost.h @@ -259,8 +259,6 @@ class OverallCost : public Variable::IVariable, NextT, VCardO * (state.hourlyResults->TurbinageHoraire[state.hourInTheWeek] - state.area->hydro.pumpingEfficiency * state.hourlyResults->PompageHoraire[state.hourInTheWeek])); - Yuni::String buffer; - buffer << "Hour : " << state.hourInTheYear << "\n"; for (const auto& thermalReserves : state.problemeHebdo->allReserves.thermalAreaReserves) { for (const auto& reserveUp : thermalReserves.areaCapacityReservationsUp) @@ -272,9 +270,6 @@ class OverallCost : public Variable::IVariable, NextT, VCardO + state.hourlyResults->ReserveThermique[state.hourInTheWeek] .ValeursHorairesInternalExcessReserve[reserveUp.globalReserveIndex] * reserveUp.spillageCost; - buffer << " Reserve : " << reserveUp.reserveName << " Unsupplied : " << state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalUnsatisfied[reserveUp.globalReserveIndex] << " mw, Spilled : " << state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalExcessReserve[reserveUp.globalReserveIndex] << " mw. \n"; } for (const auto& reserveDown : thermalReserves.areaCapacityReservationsDown) { @@ -285,35 +280,11 @@ class OverallCost : public Variable::IVariable, NextT, VCardO + state.hourlyResults->ReserveThermique[state.hourInTheWeek] .ValeursHorairesInternalExcessReserve[reserveDown.globalReserveIndex] * reserveDown.spillageCost; - buffer << " Reserve : " << reserveDown.reserveName << " Unsupplied : " << state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalUnsatisfied[reserveDown.globalReserveIndex] << " mw, Spilled : " << state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalExcessReserve[reserveDown.globalReserveIndex] << " mw. \n"; } } - state.spilledUnsupplied << buffer; + pValuesForTheCurrentYear[numSpace][state.hourInTheYear] += costForSpilledOrUnsuppliedEnergy; - if (state.hourInTheYear == state.study.runtime->rangeLimits.hour[Data::rangeEnd]) - { - Yuni::String path; - path << state.study.folderOutput << SEP << "reserves" << SEP << state.area->name << ".txt"; - Yuni::IO::File::Stream file; - Yuni::String pathFolder = state.study.folderOutput; - pathFolder << SEP << "reserves"; - if (Yuni::IO::Directory::Exists(pathFolder) || Yuni::IO::Directory::Create(pathFolder)) - { - if (file.openRW(path)) - { - file << state.spilledUnsupplied; - file.close(); - } - } - else - { - logs.error() << "Reserves : impossible to write " << path; - } - } - // Incrementing annual system cost (to be printed in output into a separate file) state.annualSystemCost += costForSpilledOrUnsuppliedEnergy; diff --git a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationUnsuppliedSpilled.h b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationUnsuppliedSpilled.h new file mode 100644 index 0000000000..0cebcd3efa --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationUnsuppliedSpilled.h @@ -0,0 +1,328 @@ +/* +** 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 +*/ +#ifndef __SOLVER_VARIABLE_ECONOMY_ReserveParticipationUnsuppliedSpilled_H__ +#define __SOLVER_VARIABLE_ECONOMY_ReserveParticipationUnsuppliedSpilled_H__ + +#include "../variable.h" +#include "./vCardReserveParticipationUnsuppliedSpilled.h" + +namespace Antares +{ +namespace Solver +{ +namespace Variable +{ +namespace Economy +{ + +/*! +** \brief Reserve participation unsupplied and spilled volumes for an area +*/ +template +class ReserveParticipationUnsuppliedSpilled : public Variable::IVariable, + NextT, + VCardReserveParticipationUnsuppliedSpilled> +{ +public: + //! Type of the next static variable + typedef NextT NextType; + //! VCard + typedef VCardReserveParticipationUnsuppliedSpilled VCardType; + //! Ancestor + typedef Variable::IVariable, NextT, VCardType> AncestorType; + + //! List of expected results + typedef typename VCardType::ResultsType ResultsType; + + typedef VariableAccessor VariableAccessorType; + + enum + { + //! How many items have we got + count = 1 + NextT::count, + }; + + template + struct Statistics + { + enum + { + count + = ((VCardType::categoryDataLevel & CDataLevel && VCardType::categoryFileLevel & CFile) + ? (NextType::template Statistics::count + + VCardType::columnCount * ResultsType::count) + : NextType::template Statistics::count), + }; + }; + +public: + ReserveParticipationUnsuppliedSpilled() : pValuesForTheCurrentYear(NULL), pSize(0) + { + } + + ~ReserveParticipationUnsuppliedSpilled() + { + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + delete[] pValuesForTheCurrentYear[numSpace]; + delete[] pValuesForTheCurrentYear; + } + + void initializeFromStudy(Data::Study& study) + { + // Next + NextType::initializeFromStudy(study); + } + + void initializeFromArea(Data::Study* study, Data::Area* area) + { + // Get the number of years in parallel + pNbYearsParallel = study->maxNbYearsInParallel; + pValuesForTheCurrentYear = new VCardType::IntermediateValuesBaseType[pNbYearsParallel]; + + // Get the area + pSize = 0; + for (auto res : area->allCapacityReservations.areaCapacityReservationsUp) + { + pSize += 2; + } + for (auto res : area->allCapacityReservations.areaCapacityReservationsDown) + { + pSize += 2; + } + if (pSize) + { + AncestorType::pResults.resize(pSize); + + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + pValuesForTheCurrentYear[numSpace] + = new VCardType::IntermediateValuesDeepType[pSize]; + + // Minimum power values of the cluster for the whole year - from the solver in the + // accurate mode not to be displayed in the output \todo think of a better place like + // the DispatchableMarginForAllAreas done at the beginning of the year + + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + for (unsigned int i = 0; i != pSize; ++i) + pValuesForTheCurrentYear[numSpace][i].initializeFromStudy(*study); + + for (unsigned int i = 0; i != pSize; ++i) + { + AncestorType::pResults[i].initializeFromStudy(*study); + AncestorType::pResults[i].reset(); + } + } + else + { + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + { + pValuesForTheCurrentYear[numSpace] = nullptr; + } + AncestorType::pResults.clear(); + } + // Next + NextType::initializeFromArea(study, area); + } + + size_t getMaxNumberColumns() const + { + return pSize * ResultsType::count; + } + + void initializeFromLink(Data::Study* study, Data::AreaLink* link) + { + // Next + NextType::initializeFromAreaLink(study, link); + } + + void simulationBegin() + { + // Next + NextType::simulationBegin(); + } + + void simulationEnd() + { + NextType::simulationEnd(); + } + + void yearBegin(unsigned int year, unsigned int numSpace) + { + // Reset the values for the current year + for (unsigned int i = 0; i != pSize; ++i) + pValuesForTheCurrentYear[numSpace][i].reset(); + + // Next variable + NextType::yearBegin(year, numSpace); + } + + void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) + { + // Next variable + NextType::yearEndBuildForEachThermalCluster(state, year, numSpace); + } + + void yearEndBuild(State& state, unsigned int year) + { + // Next variable + NextType::yearEndBuild(state, year); + } + + void yearEnd(unsigned int year, unsigned int numSpace) + { + // Merge all results for all thermal clusters + { + for (unsigned int i = 0; i < pSize; ++i) + { + // Compute all statistics for the current year (daily,weekly,monthly) + pValuesForTheCurrentYear[numSpace][i].computeStatisticsForTheCurrentYear(); + } + } + // Next variable + NextType::yearEnd(year, numSpace); + } + + void computeSummary(std::map& numSpaceToYear, + unsigned int nbYearsForCurrentSummary) + { + for (unsigned int numSpace = 0; numSpace < nbYearsForCurrentSummary; ++numSpace) + { + for (unsigned int i = 0; i < pSize; ++i) + { + // Merge all those values with the global results + AncestorType::pResults[i].merge(numSpaceToYear[numSpace], + pValuesForTheCurrentYear[numSpace][i]); + } + } + + // Next variable + NextType::computeSummary(numSpaceToYear, nbYearsForCurrentSummary); + } + + void hourBegin(unsigned int hourInTheYear) + { + // Next variable + NextType::hourBegin(hourInTheYear); + } + + void hourForEachArea(State& state, unsigned int numSpace) + { + auto& area = state.area; + auto& thermal = state.thermal; + int column = 0; + for (const auto& thermalReserves : state.problemeHebdo->allReserves.thermalAreaReserves) + { + for (const auto& reserveUp : thermalReserves.areaCapacityReservationsUp) + { + pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalUnsatisfied[reserveUp.globalReserveIndex]; + pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalExcessReserve[reserveUp.globalReserveIndex]; + } + for (const auto& reserveDown : thermalReserves.areaCapacityReservationsDown) + { + pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalUnsatisfied[reserveDown.globalReserveIndex]; + pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalExcessReserve[reserveDown.globalReserveIndex]; + } + } + + // Next variable + NextType::hourForEachArea(state, numSpace); + } + + Antares::Memory::Stored::ConstReturnType retrieveRawHourlyValuesForCurrentYear( + unsigned int, + unsigned int numSpace) const + { + return pValuesForTheCurrentYear[numSpace]->hour; + } + + void localBuildAnnualSurveyReport(SurveyResults& results, + int fileLevel, + int precision, + unsigned int numSpace) const + { + // Initializing external pointer on current variable non applicable status + results.isCurrentVarNA = AncestorType::isNonApplicable; + + if (AncestorType::isPrinted[0]) + { + assert(NULL != results.data.area); + const auto& thermal = results.data.area->thermal; + results.variableUnit = VCardType::Unit(); + // Write the data for the current year + int column = 0; + for (const auto& reserveUp : results.data.area->allCapacityReservations.areaCapacityReservationsUp) + { + // Write the data for the current year + Yuni::String caption = reserveUp.first; + caption << "_UNSP. ENRG"; + results.variableCaption = caption; // VCardType::Caption(); + pValuesForTheCurrentYear[numSpace][column++].template buildAnnualSurveyReport( + results, fileLevel, precision); + caption = reserveUp.first; + caption << "_SPIL. ENRG"; + results.variableCaption = caption; // VCardType::Caption(); + pValuesForTheCurrentYear[numSpace][column++].template buildAnnualSurveyReport( + results, fileLevel, precision); + } + for (const auto& reserveDown : results.data.area->allCapacityReservations.areaCapacityReservationsDown) + { + // Write the data for the current year + Yuni::String caption = reserveDown.first; + caption << "_UNSP. ENRG"; + results.variableCaption = caption; // VCardType::Caption(); + pValuesForTheCurrentYear[numSpace][column++].template buildAnnualSurveyReport( + results, fileLevel, precision); + caption = reserveDown.first; + caption << "_SPIL. ENRG"; + results.variableCaption = caption; // VCardType::Caption(); + pValuesForTheCurrentYear[numSpace][column++].template buildAnnualSurveyReport( + results, fileLevel, precision); + } + } + } + +private: + //! Intermediate values for each year + typename VCardType::IntermediateValuesType pValuesForTheCurrentYear; + size_t pSize; + unsigned int pNbYearsParallel; + +}; // class ReserveParticipationUnsuppliedSpilled + +} // namespace Economy +} // namespace Variable +} // namespace Solver +} // namespace Antares + +#endif // __SOLVER_VARIABLE_ECONOMY_ReserveUnsuppliedSpilled_H__ \ No newline at end of file diff --git a/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h index d773aafa16..53f0ec174b 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h @@ -47,7 +47,7 @@ struct VCardReserveParticipationByDispatchablePlant //! Unit static std::string Unit() { - return "Reserve Participation Power - MW"; + return "Reserve Participation Power - MWh"; } //! The short description of the variable diff --git a/src/solver/variable/include/antares/solver/variable/info.h b/src/solver/variable/include/antares/solver/variable/info.h index 2b3874aa14..f7b46ad292 100644 --- a/src/solver/variable/include/antares/solver/variable/info.h +++ b/src/solver/variable/include/antares/solver/variable/info.h @@ -24,6 +24,7 @@ #include #include "./economy/vCardReserveParticipationByDispatchablePlant.h" #include "./economy/vCardReserveParticipationByGroup.h" +#include "./economy/vCardReserveParticipationUnsuppliedSpilled.h" namespace Antares { @@ -381,6 +382,12 @@ struct VariableAccessor = thermal.list.reserveParticipationGroupAt(results.data.area, i); results.variableCaption = reserveName + "_" + Economy::thermalDispatchableGroupToString(groupName); } + else if (typeid(VCardT) == typeid(Economy::VCardReserveParticipationUnsuppliedSpilled)) + { + auto [unsuppliedOrSpilled, reserveName] + = thermal.list.reserveParticipationGroupAt(results.data.area, i); + results.variableCaption = reserveName + "_" + Economy::thermalDispatchableGroupToString(unsuppliedOrSpilled); + } else results.variableCaption = thermal.list.enabledClusterAt(i)->name(); @@ -466,6 +473,13 @@ struct VariableAccessor results.variableCaption = reserveName + "_" + Economy::thermalDispatchableGroupToString(groupName); res = true; } + else if (typeid(VCardType) == typeid(Economy::VCardReserveParticipationUnsuppliedSpilled)) + { + auto [unsuppliedOrSpilled, reserveName] + = thermal.list.reserveParticipationUnsuppliedSpilledAt(results.data.area, i); + results.variableCaption = reserveName + "_" + Economy::thermalUnsuppliedSpilledToString(unsuppliedOrSpilled); + res = true; + } else res = setClusterCaption(results, fileLevel, i); if (!res) diff --git a/src/solver/variable/include/antares/solver/variable/state.h b/src/solver/variable/include/antares/solver/variable/state.h index 0735d28e23..aae5c6f61c 100644 --- a/src/solver/variable/include/antares/solver/variable/state.h +++ b/src/solver/variable/include/antares/solver/variable/state.h @@ -154,7 +154,6 @@ class State //! Current hour from the begining of the simulation unsigned int hourInTheSimulation; - Yuni::String spilledUnsupplied; //! The current area Data::Area* area; diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index ceac1f6ddf..77edbb012f 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -417,44 +417,10 @@ void State::yearEndBuildCalculateReserveParticipationCosts( uint startHourForCurrentYear = study.runtime->rangeLimits.hour[Data::rangeBegin]; uint endHourForCurrentYear = startHourForCurrentYear + study.runtime->rangeLimits.hour[Data::rangeCount]; - Yuni::IO::File::Stream file; - Yuni::String pathFolder = study.folderOutput; - pathFolder << SEP << "reserves"; - if (Yuni::IO::Directory::Exists(pathFolder) || Yuni::IO::Directory::Create(pathFolder)) + for (uint h = startHourForCurrentYear; h < endHourForCurrentYear; ++h) { - pathFolder << SEP << thermalCluster->parentArea->name; - if (Yuni::IO::Directory::Exists(pathFolder) || Yuni::IO::Directory::Create(pathFolder)) - { - Yuni::String path; - path << pathFolder << SEP << thermalCluster->name() << ".txt"; - if (file.openRW(path)) - { - for (uint h = startHourForCurrentYear; h < endHourForCurrentYear; ++h) - { - thermalClusterOperatingCostForYear[h] - += thermalClusterReserveParticipationCostForYear[h]; - std::vector clusterReserves = thermalCluster->listOfParticipatingReserves(); - - for (auto res : clusterReserves) - { - file << "Hour " << h + 1 << " : cluster " << thermalCluster->name() << " is participating to reserve " << res << " for " << thermalReserveParticipationPerGroupForYear[h][thermalCluster->groupID][res] << " mw\n"; - } - } - file.close(); - } - else - { - logs.error() << "Reserves : impossible to write " << path; - } - } - else - { - logs.error() << "Reserves : impossible to write " << pathFolder; - } - } - else - { - logs.error() << "Reserves : impossible to write " << pathFolder; + thermalClusterOperatingCostForYear[h] + += thermalClusterReserveParticipationCostForYear[h]; } } } From 8cfba684ea6f2392f0137a11e198ff1419d5df77 Mon Sep 17 00:00:00 2001 From: sylvmara <48436175+sylvmara@users.noreply.github.com> Date: Wed, 26 Jun 2024 10:54:20 +0200 Subject: [PATCH 36/41] Rename VCardReserveParticipationUnsuppliedSpilled.h to vCardReserveParticipationUnsuppliedSpilled.h Fixing cmake error for CI --- ...edSpilled.h => vCardReserveParticipationUnsuppliedSpilled.h} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/solver/variable/include/antares/solver/variable/economy/{VCardReserveParticipationUnsuppliedSpilled.h => vCardReserveParticipationUnsuppliedSpilled.h} (99%) diff --git a/src/solver/variable/include/antares/solver/variable/economy/VCardReserveParticipationUnsuppliedSpilled.h b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationUnsuppliedSpilled.h similarity index 99% rename from src/solver/variable/include/antares/solver/variable/economy/VCardReserveParticipationUnsuppliedSpilled.h rename to src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationUnsuppliedSpilled.h index a5c093220c..dac67a0992 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/VCardReserveParticipationUnsuppliedSpilled.h +++ b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationUnsuppliedSpilled.h @@ -114,4 +114,4 @@ static std::string thermalUnsuppliedSpilledToString(Data::ThermalUnsuppliedSpill } // namespace Solver } // namespace Antares -#endif //__SOLVER_VARIABLE_ECONOMY_VCardReserveParticipationUnsuppliedSpilled_H__ \ No newline at end of file +#endif //__SOLVER_VARIABLE_ECONOMY_VCardReserveParticipationUnsuppliedSpilled_H__ From 502207c99996c46fc1ef12f06f409a8523798188 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Wed, 26 Jun 2024 11:13:56 +0200 Subject: [PATCH 37/41] Changeed the cmake list in order to pass the CI --- src/solver/variable/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/variable/CMakeLists.txt b/src/solver/variable/CMakeLists.txt index 5db18dc13c..e196dc2396 100644 --- a/src/solver/variable/CMakeLists.txt +++ b/src/solver/variable/CMakeLists.txt @@ -133,7 +133,7 @@ set(SRC_VARIABLE_ECONOMY include/antares/solver/variable/economy/reserveParticipationUnsuppliedSpilled.h include/antares/solver/variable/economy/vCardReserveParticipationUnsuppliedSpilled.h include/antares/solver/variable/economy/reserveParticipationByGroup.h - include/antares/solver/variable/economy/vCardreserveParticipationByGroup.h + include/antares/solver/variable/economy/vCardReserveParticipationByGroup.h # Links include/antares/solver/variable/economy/links/flowLinear.h From 5c27d68bc77f79b7642afbb746180c3a848a7f67 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Mon, 1 Jul 2024 14:22:51 +0200 Subject: [PATCH 38/41] Fixed bugs in indexes of reserves participations --- .../optimisation/constraints/PMaxReserve.cpp | 4 +- .../optimisation/constraints/POutBounds.cpp | 38 ++++++++++++++----- .../constraints/POutCapacityThreasholds.cpp | 30 +++++++++------ .../constraints/PRunningUnits.cpp | 6 +-- .../constraints/ReserveParticipationGroup.cpp | 22 +++++++---- .../constraints/ReserveSatisfaction.cpp | 6 +-- .../optimisation/constraints/PMaxReserve.h | 2 +- .../sim_structure_probleme_economique.h | 1 + .../simulation/sim_calcul_economique.cpp | 30 +++++++-------- 9 files changed, 85 insertions(+), 54 deletions(-) diff --git a/src/solver/optimisation/constraints/PMaxReserve.cpp b/src/solver/optimisation/constraints/PMaxReserve.cpp index c3ab59e3c6..37d0557983 100644 --- a/src/solver/optimisation/constraints/PMaxReserve.cpp +++ b/src/solver/optimisation/constraints/PMaxReserve.cpp @@ -20,10 +20,10 @@ void PMaxReserve::add(int pays, int reserve, int cluster, int pdt, bool isUpRese = capacityReservation.AllReservesParticipation[cluster]; int globalClusterIdx = data.thermalClusters[pays] - .NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipation.clusterIdInArea]; builder.updateHourWithinWeek(pdt) - .RunningClusterReserveParticipation(globalClusterIdx, 1.0) + .RunningClusterReserveParticipation(reserveParticipation.indexClusterParticipation, 1.0) .NumberOfDispatchableUnits(globalClusterIdx, -reserveParticipation.maxPower) .lessThan(); diff --git a/src/solver/optimisation/constraints/POutBounds.cpp b/src/solver/optimisation/constraints/POutBounds.cpp index fcde27cd91..7fc0b9c739 100644 --- a/src/solver/optimisation/constraints/POutBounds.cpp +++ b/src/solver/optimisation/constraints/POutBounds.cpp @@ -9,6 +9,9 @@ void POutBounds::add(int pays, int cluster, int pdt) .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[cluster] = -1; + int globalClusterIdx + = data.thermalClusters[pays].NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; + if (!data.Simulation) { // 17 ter @@ -20,8 +23,6 @@ void POutBounds::add(int pays, int cluster, int pdt) // P_down : Minimal power output demanded from cluster θ // P_up : Maximal power output from cluster θ - int globalClusterIdx - = data.thermalClusters[pays].NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; // 17 ter (1) : Sum(P^on_re-) - P <= - P_down { @@ -33,8 +34,14 @@ void POutBounds::add(int pays, int cluster, int pdt) for (const auto& reserveParticipations : capacityReservation.AllReservesParticipation) { - if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) - builder.RunningClusterReserveParticipation(globalClusterIdx, 1); + if ((reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + && (data.thermalClusters[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipations + .clusterIdInArea] + == globalClusterIdx)) + { + builder.RunningClusterReserveParticipation(reserveParticipations.indexClusterParticipation, 1); + } } } @@ -67,8 +74,12 @@ void POutBounds::add(int pays, int cluster, int pdt) for (const auto& reserveParticipations : capacityReservation.AllReservesParticipation) { - if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) - builder.RunningClusterReserveParticipation(globalClusterIdx, 1); + if ((reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + && (data.thermalClusters[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipations + .clusterIdInArea] + == globalClusterIdx)) + builder.RunningClusterReserveParticipation(reserveParticipations.indexClusterParticipation, 1); } } @@ -95,7 +106,10 @@ void POutBounds::add(int pays, int cluster, int pdt) { // Lambda that count the number of reserves that the cluster is participating to auto countReservesFromCluster - = [cluster](const std::vector& reservations) + = [cluster](const std::vector& reservations, + int globalClusterIdx, + int pays, + ReserveData data) { int counter = 0; for (const auto& capacityReservation : reservations) @@ -103,7 +117,11 @@ void POutBounds::add(int pays, int cluster, int pdt) for (const auto& reserveParticipations : capacityReservation.AllReservesParticipation) { - if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + if ((reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + && (data.thermalClusters[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipations + .clusterIdInArea] + == globalClusterIdx)) counter++; } } @@ -112,9 +130,9 @@ void POutBounds::add(int pays, int cluster, int pdt) int nbConstraintsToAdd = countReservesFromCluster( - data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp) + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp, globalClusterIdx, pays, data) + countReservesFromCluster( - data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown); + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown, globalClusterIdx, pays, data); builder.data.NbTermesContraintesPourLesReserves += 2 * (nbConstraintsToAdd + 1); diff --git a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp index 0110ff97de..2277760c4f 100644 --- a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp +++ b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp @@ -2,6 +2,9 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) { + int globalClusterIdx + = data.thermalClusters[pays].NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; + if (!data.Simulation) { // 17 bis @@ -14,9 +17,6 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) // P^on_re+ : Participation of running units in cluster θ to Up reserves // P : Power output from cluster θ - int globalClusterIdx = data.thermalClusters[pays] - .NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; - // 17 bis (1) : l * M + Sum(P^on_re-) - P <= 0 { builder.updateHourWithinWeek(pdt); @@ -27,8 +27,10 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) for (const auto& reserveParticipations : capacityReservation.AllReservesParticipation) { - if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) - builder.RunningClusterReserveParticipation(globalClusterIdx, 1); + if ((reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + && (data.thermalClusters[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipations.clusterIdInArea] == globalClusterIdx)) + builder.RunningClusterReserveParticipation(reserveParticipations.indexClusterParticipation, 1); } } @@ -61,8 +63,10 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) for (const auto& reserveParticipations : capacityReservation.AllReservesParticipation) { - if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) - builder.RunningClusterReserveParticipation(globalClusterIdx, 1); + if ((reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + && (data.thermalClusters[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipations.clusterIdInArea] == globalClusterIdx)) + builder.RunningClusterReserveParticipation(reserveParticipations.indexClusterParticipation, 1); } } @@ -88,7 +92,7 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) { // Lambda that count the number of reserves that the cluster is participating to auto countReservesFromCluster - = [cluster](const std::vector& reservations) + = [cluster](const std::vector& reservations, int globalClusterIdx, int pays, ReserveData data) { int counter = 0; for (const auto& capacityReservation : reservations) @@ -96,7 +100,11 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) for (const auto& reserveParticipations : capacityReservation.AllReservesParticipation) { - if (reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + if ((reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) + && (data.thermalClusters[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipations + .clusterIdInArea] + == globalClusterIdx)) counter++; } } @@ -105,9 +113,9 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) int nbConstraintsToAdd = countReservesFromCluster( - data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp) + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsUp, globalClusterIdx, pays, data) + countReservesFromCluster( - data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown); + data.areaReserves.thermalAreaReserves[pays].areaCapacityReservationsDown, globalClusterIdx, pays, data); builder.data.NbTermesContraintesPourLesReserves += 2*(nbConstraintsToAdd+2); diff --git a/src/solver/optimisation/constraints/PRunningUnits.cpp b/src/solver/optimisation/constraints/PRunningUnits.cpp index 399a3beaed..c47e1197a7 100644 --- a/src/solver/optimisation/constraints/PRunningUnits.cpp +++ b/src/solver/optimisation/constraints/PRunningUnits.cpp @@ -19,11 +19,11 @@ void PRunningUnits::add(int pays, int reserve, int cluster, int pdt, bool isUpRe = capacityReservation.AllReservesParticipation[cluster]; int globalClusterIdx = data.thermalClusters[pays] - .NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipation.clusterIdInArea]; builder.updateHourWithinWeek(pdt) - .RunningClusterReserveParticipation(globalClusterIdx, 1.0) - .ClusterReserveParticipation(globalClusterIdx, -1.0) + .RunningClusterReserveParticipation(reserveParticipation.indexClusterParticipation, 1.0) + .ClusterReserveParticipation(reserveParticipation.indexClusterParticipation, -1.0) .equalTo(); ConstraintNamer namer(builder.data.NomDesContraintes); diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp index ee5fa42776..e3025173da 100644 --- a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -65,19 +65,19 @@ void ReserveParticipationGroup::BuildConstraints() // 24 reserveSatisfaction.add(pays, reserve, pdt, true); - uint32_t cluster = 0; + uint32_t cluster_participation = 0; for (const auto& clusterReserveParticipation : areaReserveUp.AllReservesParticipation) { if (clusterReserveParticipation.maxPower >= 0) { // 16 bis - pMaxReserve.add(pays, reserve, cluster, pdt, true); + pMaxReserve.add(pays, reserve, cluster_participation, pdt, true); // 17 quater - pRunningUnits.add(pays, reserve, cluster, pdt, true); + pRunningUnits.add(pays, reserve, cluster_participation, pdt, true); } - cluster++; + cluster_participation++; } reserve++; } @@ -90,19 +90,25 @@ void ReserveParticipationGroup::BuildConstraints() // 24 reserveSatisfaction.add(pays, reserve, pdt, false); - uint32_t cluster = 0; + uint32_t cluster_participation = 0; for (const auto& clusterReserveParticipation : areaReserveDown.AllReservesParticipation) { if (clusterReserveParticipation.maxPower >= 0) { // 16 bis - pMaxReserve.add(pays, reserve, cluster, pdt, false); + pMaxReserve.add(pays, + reserve, cluster_participation, + pdt, + false); // 17 quater - pRunningUnits.add(pays, reserve, cluster, pdt, false); + pRunningUnits.add(pays, + reserve, cluster_participation, + pdt, + false); } - cluster++; + cluster_participation++; } reserve++; } diff --git a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp index 5320e68894..d7a9d85a2e 100644 --- a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp +++ b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp @@ -27,8 +27,7 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) { if (capacityReservation.AllReservesParticipation[cluster].maxPower != CLUSTER_NOT_PARTICIPATING) builder.RunningClusterReserveParticipation( - data.thermalClusters[pays] - .NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster], + capacityReservation.AllReservesParticipation[cluster].indexClusterParticipation, 1); } @@ -36,8 +35,7 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) .InternalExcessReserve(capacityReservation.globalReserveIndex, -1) .equalTo(); data.CorrespondanceCntNativesCntOptim[pdt] - .NumeroDeContrainteDesContraintesDeBesoinEnReserves[capacityReservation - .globalReserveIndex] + .NumeroDeContrainteDesContraintesDeBesoinEnReserves[capacityReservation.globalReserveIndex] = builder.data.nombreDeContraintes; ConstraintNamer namer(builder.data.NomDesContraintes); const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h index 73a1002cfe..6a3b166c8e 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PMaxReserve.h @@ -16,7 +16,7 @@ class PMaxReserve : private ConstraintFactory * @brief Add variables to the constraint and update constraints Matrix * @param pays : area * @param reserve : capacity reservation - * @param cluster : global index of the cluster + * @param cluster : local index of the cluster * @param pdt : timestep * @param isUpReserve : true if ReserveUp, false if ReserveDown */ diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index cc55ef7dbf..e64a1018bc 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -273,6 +273,7 @@ struct RESERVE_PARTICIPATION float participationCost = CLUSTER_NOT_PARTICIPATING; int indexClusterParticipation = 0; std::string clusterName; + int clusterIdInArea; }; struct CAPACITY_RESERVATION diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 17710883e1..c243789731 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -335,16 +335,15 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, for (auto cluster : area.thermal.list.each_enabled_and_not_mustrun()) { RESERVE_PARTICIPATION reserveParticipation; - if (cluster->isParticipatingInReserve(key)) - { - reserveParticipation.maxPower = cluster->reserveMaxPower(key); - reserveParticipation.participationCost = cluster->reserveCost(key); - reserveParticipation.clusterName = cluster->name(); - reserveParticipation.indexClusterParticipation - = globalClusterParticipationIndex++; - areaCapacityReservationsUp.AllReservesParticipation.push_back( - reserveParticipation); - } + reserveParticipation.maxPower = cluster->reserveMaxPower(key); + reserveParticipation.participationCost = cluster->reserveCost(key); + reserveParticipation.clusterName = cluster->name(); + reserveParticipation.clusterIdInArea = cluster->index; + reserveParticipation.indexClusterParticipation + = globalClusterParticipationIndex; + globalClusterParticipationIndex++; + areaCapacityReservationsUp.AllReservesParticipation.push_back( + reserveParticipation); } areaReserves.areaCapacityReservationsUp.push_back(areaCapacityReservationsUp); @@ -367,16 +366,17 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, for (auto cluster : area.thermal.list.each_enabled_and_not_mustrun()) { RESERVE_PARTICIPATION reserveParticipation; - if (cluster->isParticipatingInReserve(key)) - { + //if (cluster->isParticipatingInReserve(key)) + //{ reserveParticipation.maxPower = cluster->reserveMaxPower(key); reserveParticipation.participationCost = cluster->reserveCost(key); reserveParticipation.clusterName = cluster->name(); - reserveParticipation.indexClusterParticipation - = globalClusterParticipationIndex++; + reserveParticipation.clusterIdInArea = cluster->index; + reserveParticipation.indexClusterParticipation = globalClusterParticipationIndex; + globalClusterParticipationIndex++; areaCapacityReservationsDown.AllReservesParticipation.push_back( reserveParticipation); - } + //} } areaReserves.areaCapacityReservationsDown.push_back(areaCapacityReservationsDown); From af6acc8feed172b6ccd1ef56ec013648cfb3e086 Mon Sep 17 00:00:00 2001 From: bencamus Date: Mon, 8 Jul 2024 17:03:54 +0200 Subject: [PATCH 39/41] fix bugs related to the use of reserves with different areas. --- .../optimisation/constraints/PMaxReserve.cpp | 2 +- .../optimisation/constraints/POutBounds.cpp | 22 +++++----- .../constraints/POutCapacityThreasholds.cpp | 4 +- .../constraints/PRunningUnits.cpp | 4 +- .../constraints/ReserveSatisfaction.cpp | 2 +- ...truction_variables_reserves_thermiques.cpp | 8 ++-- ...gestion_des_bornes_reserves_thermiques.cpp | 24 +++++------ .../opt_gestion_des_couts_reserves.cpp | 4 +- .../opt_gestion_second_membre_reserves.cpp | 6 ++- .../sim_structure_probleme_economique.h | 4 +- .../simulation/sim_calcul_economique.cpp | 16 ++++++-- .../solver/variable/economy/overallCost.h | 41 +++++++++---------- .../reserveParticipationByDispatchablePlant.h | 2 +- .../reserveParticipationUnsuppliedSpilled.h | 37 ++++++++--------- .../include/antares/solver/variable/state.h | 2 +- 15 files changed, 95 insertions(+), 83 deletions(-) diff --git a/src/solver/optimisation/constraints/PMaxReserve.cpp b/src/solver/optimisation/constraints/PMaxReserve.cpp index 37d0557983..e9c253bac6 100644 --- a/src/solver/optimisation/constraints/PMaxReserve.cpp +++ b/src/solver/optimisation/constraints/PMaxReserve.cpp @@ -23,7 +23,7 @@ void PMaxReserve::add(int pays, int reserve, int cluster, int pdt, bool isUpRese .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipation.clusterIdInArea]; builder.updateHourWithinWeek(pdt) - .RunningClusterReserveParticipation(reserveParticipation.indexClusterParticipation, 1.0) + .RunningClusterReserveParticipation(reserveParticipation.globalIndexClusterParticipation, 1.0) .NumberOfDispatchableUnits(globalClusterIdx, -reserveParticipation.maxPower) .lessThan(); diff --git a/src/solver/optimisation/constraints/POutBounds.cpp b/src/solver/optimisation/constraints/POutBounds.cpp index 7fc0b9c739..0e004487fd 100644 --- a/src/solver/optimisation/constraints/POutBounds.cpp +++ b/src/solver/optimisation/constraints/POutBounds.cpp @@ -2,16 +2,16 @@ void POutBounds::add(int pays, int cluster, int pdt) { + int globalClusterIdx + = data.thermalClusters[pays].NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; + data.CorrespondanceCntNativesCntOptim[pdt] - .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[cluster] + .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[globalClusterIdx] = -1; data.CorrespondanceCntNativesCntOptim[pdt] - .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[cluster] + .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[globalClusterIdx] = -1; - int globalClusterIdx - = data.thermalClusters[pays].NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; - if (!data.Simulation) { // 17 ter @@ -40,7 +40,7 @@ void POutBounds::add(int pays, int cluster, int pdt) .clusterIdInArea] == globalClusterIdx)) { - builder.RunningClusterReserveParticipation(reserveParticipations.indexClusterParticipation, 1); + builder.RunningClusterReserveParticipation(reserveParticipations.globalIndexClusterParticipation, 1); } } } @@ -49,10 +49,10 @@ void POutBounds::add(int pays, int cluster, int pdt) { builder.DispatchableProduction(globalClusterIdx, -1).lessThan(); data.CorrespondanceCntNativesCntOptim[pdt] - .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[cluster] + .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[globalClusterIdx] = builder.data.nombreDeContraintes; data.CorrespondanceCntNativesCntOptim[pdt] - .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[cluster] + .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[globalClusterIdx] = builder.data.nombreDeContraintes; ConstraintNamer namer(builder.data.NomDesContraintes); const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; @@ -79,7 +79,7 @@ void POutBounds::add(int pays, int cluster, int pdt) .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipations .clusterIdInArea] == globalClusterIdx)) - builder.RunningClusterReserveParticipation(reserveParticipations.indexClusterParticipation, 1); + builder.RunningClusterReserveParticipation(reserveParticipations.globalIndexClusterParticipation, 1); } } @@ -87,10 +87,10 @@ void POutBounds::add(int pays, int cluster, int pdt) { builder.DispatchableProduction(globalClusterIdx, 1).lessThan(); data.CorrespondanceCntNativesCntOptim[pdt] - .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[cluster] + .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[globalClusterIdx] = builder.data.nombreDeContraintes; data.CorrespondanceCntNativesCntOptim[pdt] - .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[cluster] + .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[globalClusterIdx] = builder.data.nombreDeContraintes; ConstraintNamer namer(builder.data.NomDesContraintes); const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; diff --git a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp index 2277760c4f..7f7383b692 100644 --- a/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp +++ b/src/solver/optimisation/constraints/POutCapacityThreasholds.cpp @@ -30,7 +30,7 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) if ((reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) && (data.thermalClusters[pays] .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipations.clusterIdInArea] == globalClusterIdx)) - builder.RunningClusterReserveParticipation(reserveParticipations.indexClusterParticipation, 1); + builder.RunningClusterReserveParticipation(reserveParticipations.globalIndexClusterParticipation, 1); } } @@ -66,7 +66,7 @@ void POutCapacityThreasholds::add(int pays, int cluster, int pdt) if ((reserveParticipations.maxPower != CLUSTER_NOT_PARTICIPATING) && (data.thermalClusters[pays] .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipations.clusterIdInArea] == globalClusterIdx)) - builder.RunningClusterReserveParticipation(reserveParticipations.indexClusterParticipation, 1); + builder.RunningClusterReserveParticipation(reserveParticipations.globalIndexClusterParticipation, 1); } } diff --git a/src/solver/optimisation/constraints/PRunningUnits.cpp b/src/solver/optimisation/constraints/PRunningUnits.cpp index c47e1197a7..e3a19c0b1b 100644 --- a/src/solver/optimisation/constraints/PRunningUnits.cpp +++ b/src/solver/optimisation/constraints/PRunningUnits.cpp @@ -22,8 +22,8 @@ void PRunningUnits::add(int pays, int reserve, int cluster, int pdt, bool isUpRe .NumeroDuPalierDansLEnsembleDesPaliersThermiques[reserveParticipation.clusterIdInArea]; builder.updateHourWithinWeek(pdt) - .RunningClusterReserveParticipation(reserveParticipation.indexClusterParticipation, 1.0) - .ClusterReserveParticipation(reserveParticipation.indexClusterParticipation, -1.0) + .RunningClusterReserveParticipation(reserveParticipation.globalIndexClusterParticipation, 1.0) + .ClusterReserveParticipation(reserveParticipation.globalIndexClusterParticipation, -1.0) .equalTo(); ConstraintNamer namer(builder.data.NomDesContraintes); diff --git a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp index d7a9d85a2e..3cd51e2d85 100644 --- a/src/solver/optimisation/constraints/ReserveSatisfaction.cpp +++ b/src/solver/optimisation/constraints/ReserveSatisfaction.cpp @@ -27,7 +27,7 @@ void ReserveSatisfaction::add(int pays, int reserve, int pdt, bool isUpReserve) { if (capacityReservation.AllReservesParticipation[cluster].maxPower != CLUSTER_NOT_PARTICIPATING) builder.RunningClusterReserveParticipation( - capacityReservation.AllReservesParticipation[cluster].indexClusterParticipation, + capacityReservation.AllReservesParticipation[cluster].globalIndexClusterParticipation, 1); } diff --git a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp index 3cf810aab9..1d6f90e290 100644 --- a/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_reserves_thermiques.cpp @@ -96,7 +96,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi else { // For running units in cluster - variableManager.ClusterReserveParticipation(clusterReserveParticipation.indexClusterParticipation, pdt) + variableManager.ClusterReserveParticipation(clusterReserveParticipation.globalIndexClusterParticipation, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; @@ -105,7 +105,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi NombreDeVariables++; // For all units in cluster (off units can participate to the reserves) - variableManager.RunningClusterReserveParticipation(clusterReserveParticipation.indexClusterParticipation, pdt) + variableManager.RunningClusterReserveParticipation(clusterReserveParticipation.globalIndexClusterParticipation, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; @@ -160,7 +160,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi else { // For running units in cluster - variableManager.ClusterReserveParticipation(clusterReserveParticipation.indexClusterParticipation, pdt) + variableManager.ClusterReserveParticipation(clusterReserveParticipation.globalIndexClusterParticipation, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; @@ -169,7 +169,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireReservesThermi NombreDeVariables++; // For all units in cluster (off units can participate to the reserves) - variableManager.RunningClusterReserveParticipation(clusterReserveParticipation.indexClusterParticipation, pdt) + variableManager.RunningClusterReserveParticipation(clusterReserveParticipation.globalIndexClusterParticipation, pdt) = NombreDeVariables; ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; diff --git a/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp index 301f6f40ab..a95b882f8d 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_reserves_thermiques.cpp @@ -63,7 +63,7 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( double* adresseDuResultat1 = &(problemeHebdo->ResultatsHoraires[pays] .ReserveThermique[pdtHebdo] - .ValeursHorairesInternalUnsatisfied[areaReserveUp.globalReserveIndex]); + .ValeursHorairesInternalUnsatisfied[areaReserveUp.areaReserveIndex]); AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat1; var = CorrespondanceVarNativesVarOptim @@ -73,7 +73,7 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( double* adresseDuResultat2 = &(problemeHebdo->ResultatsHoraires[pays] .ReserveThermique[pdtHebdo] - .ValeursHorairesInternalExcessReserve[areaReserveUp.globalReserveIndex]); + .ValeursHorairesInternalExcessReserve[areaReserveUp.areaReserveIndex]); AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat2; for (const auto& clusterReserveParticipation : @@ -82,25 +82,25 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( if (clusterReserveParticipation.maxPower >= 0) { var = CorrespondanceVarNativesVarOptim.runningClusterReserveParticipationIndex - [clusterReserveParticipation.indexClusterParticipation]; + [clusterReserveParticipation.globalIndexClusterParticipation]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; double* adresseDuResultat3 = &(problemeHebdo->ResultatsHoraires[pays] .ProductionThermique[pdtHebdo] .ParticipationReservesDuPalier[clusterReserveParticipation - .indexClusterParticipation]); + .areaIndexClusterParticipation]); AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat3; var = CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex - [clusterReserveParticipation.indexClusterParticipation]; + [clusterReserveParticipation.globalIndexClusterParticipation]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; double* adresseDuResultat4 = &(problemeHebdo->ResultatsHoraires[pays] .ProductionThermique[pdtHebdo] .ParticipationReservesDuPalier[clusterReserveParticipation - .indexClusterParticipation]); + .areaIndexClusterParticipation]); AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat4; } } @@ -114,7 +114,7 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( double* adresseDuResultat1 = &(problemeHebdo->ResultatsHoraires[pays] .ReserveThermique[pdtHebdo] - .ValeursHorairesInternalUnsatisfied[areaReserveDown.globalReserveIndex]); + .ValeursHorairesInternalUnsatisfied[areaReserveDown.areaReserveIndex]); AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat1; var = CorrespondanceVarNativesVarOptim @@ -124,7 +124,7 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( double* adresseDuResultat2 = &(problemeHebdo->ResultatsHoraires[pays] .ReserveThermique[pdtHebdo] - .ValeursHorairesInternalExcessReserve[areaReserveDown.globalReserveIndex]); + .ValeursHorairesInternalExcessReserve[areaReserveDown.areaReserveIndex]); AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat2; for (const auto& clusterReserveParticipation : @@ -133,25 +133,25 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireReservesThermiques( if (clusterReserveParticipation.maxPower >= 0) { var = CorrespondanceVarNativesVarOptim.runningClusterReserveParticipationIndex - [clusterReserveParticipation.indexClusterParticipation]; + [clusterReserveParticipation.globalIndexClusterParticipation]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; double* adresseDuResultat3 = &(problemeHebdo->ResultatsHoraires[pays] .ProductionThermique[pdtHebdo] .ParticipationReservesDuPalier[clusterReserveParticipation - .indexClusterParticipation]); + .areaIndexClusterParticipation]); AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat3; var = CorrespondanceVarNativesVarOptim.clusterReserveParticipationIndex - [clusterReserveParticipation.indexClusterParticipation]; + [clusterReserveParticipation.globalIndexClusterParticipation]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; double* adresseDuResultat4 = &(problemeHebdo->ResultatsHoraires[pays] .ProductionThermique[pdtHebdo] .ParticipationReservesDuPalier[clusterReserveParticipation - .indexClusterParticipation]); + .areaIndexClusterParticipation]); AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat4; } } diff --git a/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp b/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp index c4a67c0970..03337ccf26 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_reserves.cpp @@ -57,7 +57,7 @@ void OPT_InitialiserLesCoutsLineaireReserves(PROBLEME_HEBDO* problemeHebdo, if (clusterReserveParticipation.maxPower >= 0) { var = variableManager.ClusterReserveParticipation( - clusterReserveParticipation.indexClusterParticipation, + clusterReserveParticipation.globalIndexClusterParticipation, pdtHebdo); CoutLineaire[var] = clusterReserveParticipation.participationCost; } @@ -87,7 +87,7 @@ void OPT_InitialiserLesCoutsLineaireReserves(PROBLEME_HEBDO* problemeHebdo, if (clusterReserveParticipation.maxPower >= 0) { var = variableManager.ClusterReserveParticipation( - clusterReserveParticipation.indexClusterParticipation, pdtHebdo); + clusterReserveParticipation.globalIndexClusterParticipation, pdtHebdo); CoutLineaire[var] = clusterReserveParticipation.participationCost; } } diff --git a/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp b/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp index f18152a7b3..25a165aa47 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp @@ -86,8 +86,10 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO* pro cluster < problemeHebdo->PaliersThermiquesDuPays[pays].NombreDePaliersThermiques; cluster++) { + int globalClusterIdx = problemeHebdo->PaliersThermiquesDuPays[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[cluster]; int cnt1 = CorrespondanceCntNativesCntOptim - .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[cluster]; + .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier[globalClusterIdx]; if (cnt1 >= 0) { SecondMembre[cnt1] = problemeHebdo->PaliersThermiquesDuPays[pays] @@ -97,7 +99,7 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO* pro } int cnt2 = CorrespondanceCntNativesCntOptim - .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[cluster]; + .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier[globalClusterIdx]; if (cnt2 >= 0) { SecondMembre[cnt2] = problemeHebdo->PaliersThermiquesDuPays[pays] diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index e64a1018bc..b9fa63eba5 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -271,7 +271,8 @@ struct RESERVE_PARTICIPATION { float maxPower = CLUSTER_NOT_PARTICIPATING; float participationCost = CLUSTER_NOT_PARTICIPATING; - int indexClusterParticipation = 0; + int globalIndexClusterParticipation = 0; + int areaIndexClusterParticipation = 0; std::string clusterName; int clusterIdInArea; }; @@ -285,6 +286,7 @@ struct CAPACITY_RESERVATION std::string reserveName; int globalReserveIndex; + int areaReserveIndex; }; diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index c243789731..b7a493bab9 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -280,8 +280,9 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, int globalClusterParticipationIndex = 0; for (uint i = 0; i < study.areas.size(); ++i) { + int areaReserveIndex = 0; + int areaClusterParticipationIndex = 0; const auto& area = *(study.areas.byIndex[i]); - auto& pbPalier = problem.PaliersThermiquesDuPays[i]; unsigned int clusterCount = area.thermal.list.enabledAndNotMustRunCount(); pbPalier.NombreDePaliersThermiques = clusterCount; @@ -324,7 +325,9 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, areaCapacityReservationsUp.spillageCost = val.spillageCost; areaCapacityReservationsUp.reserveName = key; areaCapacityReservationsUp.globalReserveIndex = globalReserveIndex; + areaCapacityReservationsUp.areaReserveIndex = areaReserveIndex; globalReserveIndex++; + areaReserveIndex++; if (val.need.timeSeries.width > 0) { for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) @@ -339,9 +342,12 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, reserveParticipation.participationCost = cluster->reserveCost(key); reserveParticipation.clusterName = cluster->name(); reserveParticipation.clusterIdInArea = cluster->index; - reserveParticipation.indexClusterParticipation + reserveParticipation.globalIndexClusterParticipation = globalClusterParticipationIndex; + reserveParticipation.areaIndexClusterParticipation + = areaClusterParticipationIndex; globalClusterParticipationIndex++; + areaClusterParticipationIndex++; areaCapacityReservationsUp.AllReservesParticipation.push_back( reserveParticipation); } @@ -355,7 +361,9 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, areaCapacityReservationsDown.spillageCost = val.spillageCost; areaCapacityReservationsDown.reserveName = key; areaCapacityReservationsDown.globalReserveIndex = globalReserveIndex; + areaCapacityReservationsDown.areaReserveIndex = areaReserveIndex; globalReserveIndex++; + areaReserveIndex++; if (val.need.timeSeries.width > 0) { for (int indexSeries = 0; indexSeries < val.need.timeSeries.height; indexSeries++) @@ -372,8 +380,10 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, reserveParticipation.participationCost = cluster->reserveCost(key); reserveParticipation.clusterName = cluster->name(); reserveParticipation.clusterIdInArea = cluster->index; - reserveParticipation.indexClusterParticipation = globalClusterParticipationIndex; + reserveParticipation.globalIndexClusterParticipation = globalClusterParticipationIndex; + reserveParticipation.areaIndexClusterParticipation = areaClusterParticipationIndex; globalClusterParticipationIndex++; + areaClusterParticipationIndex++; areaCapacityReservationsDown.AllReservesParticipation.push_back( reserveParticipation); //} diff --git a/src/solver/variable/include/antares/solver/variable/economy/overallCost.h b/src/solver/variable/include/antares/solver/variable/economy/overallCost.h index 3a9db96798..2dc9ebef77 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/overallCost.h +++ b/src/solver/variable/include/antares/solver/variable/economy/overallCost.h @@ -248,6 +248,7 @@ class OverallCost : public Variable::IVariable, NextT, VCardO void hourForEachArea(State& state, unsigned int numSpace) { + auto& area = state.area; double costForSpilledOrUnsuppliedEnergy = // Total UnsupliedEnergy emissions (state.hourlyResults->ValeursHorairesDeDefaillancePositive[state.hourInTheWeek] @@ -259,28 +260,26 @@ class OverallCost : public Variable::IVariable, NextT, VCardO * (state.hourlyResults->TurbinageHoraire[state.hourInTheWeek] - state.area->hydro.pumpingEfficiency * state.hourlyResults->PompageHoraire[state.hourInTheWeek])); - for (const auto& thermalReserves : state.problemeHebdo->allReserves.thermalAreaReserves) + auto thermalReserves = state.problemeHebdo->allReserves.thermalAreaReserves[area->index]; + for (const auto& reserveUp : thermalReserves.areaCapacityReservationsUp) { - for (const auto& reserveUp : thermalReserves.areaCapacityReservationsUp) - { - costForSpilledOrUnsuppliedEnergy - += state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalUnsatisfied[reserveUp.globalReserveIndex] - * reserveUp.failureCost - + state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalExcessReserve[reserveUp.globalReserveIndex] - * reserveUp.spillageCost; - } - for (const auto& reserveDown : thermalReserves.areaCapacityReservationsDown) - { - costForSpilledOrUnsuppliedEnergy - += state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalUnsatisfied[reserveDown.globalReserveIndex] - * reserveDown.failureCost - + state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalExcessReserve[reserveDown.globalReserveIndex] - * reserveDown.spillageCost; - } + costForSpilledOrUnsuppliedEnergy + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalUnsatisfied[reserveUp.areaReserveIndex] + * reserveUp.failureCost + + state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalExcessReserve[reserveUp.areaReserveIndex] + * reserveUp.spillageCost; + } + for (const auto& reserveDown : thermalReserves.areaCapacityReservationsDown) + { + costForSpilledOrUnsuppliedEnergy + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalUnsatisfied[reserveDown.areaReserveIndex] + * reserveDown.failureCost + + state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalExcessReserve[reserveDown.areaReserveIndex] + * reserveDown.spillageCost; } pValuesForTheCurrentYear[numSpace][state.hourInTheYear] += costForSpilledOrUnsuppliedEnergy; diff --git a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h index 1b74b3ec3f..34861d4708 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h @@ -190,7 +190,7 @@ class ReserveParticipationByDispatchablePlant state.thermalReserveParticipationPerClusterForYear[i][state.thermalCluster ->name()]) { - pValuesForTheCurrentYear[numSpace][state.getIndexFromReserveAndCluster( + pValuesForTheCurrentYear[numSpace][state.getAreaIndexFromReserveAndCluster( reserveName, state.thermalCluster->name())] .hour[i] = reserveParticipation; diff --git a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationUnsuppliedSpilled.h b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationUnsuppliedSpilled.h index 0cebcd3efa..b958f33458 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationUnsuppliedSpilled.h +++ b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationUnsuppliedSpilled.h @@ -233,26 +233,25 @@ class ReserveParticipationUnsuppliedSpilled : public Variable::IVariableallReserves.thermalAreaReserves) + + auto thermalReserves = state.problemeHebdo->allReserves.thermalAreaReserves[area->index]; + for (const auto& reserveUp : thermalReserves.areaCapacityReservationsUp) { - for (const auto& reserveUp : thermalReserves.areaCapacityReservationsUp) - { - pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] - += state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalUnsatisfied[reserveUp.globalReserveIndex]; - pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] - += state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalExcessReserve[reserveUp.globalReserveIndex]; - } - for (const auto& reserveDown : thermalReserves.areaCapacityReservationsDown) - { - pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] - += state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalUnsatisfied[reserveDown.globalReserveIndex]; - pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] - += state.hourlyResults->ReserveThermique[state.hourInTheWeek] - .ValeursHorairesInternalExcessReserve[reserveDown.globalReserveIndex]; - } + pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalUnsatisfied[reserveUp.areaReserveIndex]; + pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalExcessReserve[reserveUp.areaReserveIndex]; + } + for (const auto& reserveDown : thermalReserves.areaCapacityReservationsDown) + { + pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalUnsatisfied[reserveDown.areaReserveIndex]; + pValuesForTheCurrentYear[numSpace][column++].hour[state.hourInTheYear] + += state.hourlyResults->ReserveThermique[state.hourInTheWeek] + .ValeursHorairesInternalExcessReserve[reserveDown.areaReserveIndex]; } // Next variable diff --git a/src/solver/variable/include/antares/solver/variable/state.h b/src/solver/variable/include/antares/solver/variable/state.h index aae5c6f61c..a9443cd3df 100644 --- a/src/solver/variable/include/antares/solver/variable/state.h +++ b/src/solver/variable/include/antares/solver/variable/state.h @@ -100,7 +100,7 @@ class State void yearEndBuildFromThermalClusterIndex(const unsigned int areaWideIndex); - int getIndexFromReserveAndCluster(Data::ReserveName reserveName, Data::ClusterName clusterName); + int getAreaIndexFromReserveAndCluster(Data::ReserveName reserveName, Data::ClusterName clusterName); private: /*! ** \brief Initialize some variable according a thermal cluster index From 377a131102e538f77a43910225878f43e947df03 Mon Sep 17 00:00:00 2001 From: bencamus Date: Tue, 9 Jul 2024 11:04:59 +0200 Subject: [PATCH 40/41] complement of bug fixing related to the use of the reserves with several areas --- src/solver/variable/state.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index 77edbb012f..e8bf3c8121 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -152,7 +152,7 @@ void State::initFromThermalClusterIndex(const uint clusterAreaWideIndex) // en mode fast : est pris depuis l'heuristique } -int State::getIndexFromReserveAndCluster(Data::ReserveName reserveName, Data::ClusterName clusterName) +int State::getAreaIndexFromReserveAndCluster(Data::ReserveName reserveName, Data::ClusterName clusterName) { for (auto reserve : problemeHebdo->allReserves.thermalAreaReserves[area->index].areaCapacityReservationsUp) { @@ -161,7 +161,7 @@ int State::getIndexFromReserveAndCluster(Data::ReserveName reserveName, Data::Cl for (auto cluster : reserve.AllReservesParticipation) { if (cluster.clusterName == clusterName) - return cluster.indexClusterParticipation; + return cluster.areaIndexClusterParticipation; } } } @@ -172,7 +172,7 @@ int State::getIndexFromReserveAndCluster(Data::ReserveName reserveName, Data::Cl for (auto cluster : reserve.AllReservesParticipation) { if (cluster.clusterName == clusterName) - return cluster.indexClusterParticipation; + return cluster.areaIndexClusterParticipation; } } } @@ -237,7 +237,7 @@ void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideInde std::vector clusterReserves = thermalCluster->listOfParticipatingReserves(); for (auto res : clusterReserves) { - int reserveParticipationIdx = getIndexFromReserveAndCluster(res, thermalCluster->name()); + int reserveParticipationIdx = getAreaIndexFromReserveAndCluster(res, thermalCluster->name()); if (reserveParticipationIdx != -1) { thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] From 9f1d36abcce2e31ce8d2915341da20ffb5dcf568 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Wed, 24 Jul 2024 16:47:02 +0200 Subject: [PATCH 41/41] Corrected merge bugs and applied format-code --- src/format-code.sh | 24 ------------------- .../antares/study/area/capacityReservation.h | 2 +- .../antares/study/parts/thermal/cluster.cpp | 24 +++++++++---------- .../solver/optimisation/LinearProblemMatrix.h | 5 +--- .../simulation/sim_alloc_probleme_hebdo.cpp | 18 ++++++-------- .../reserveParticipationByDispatchablePlant.h | 4 ++-- .../economy/reserveParticipationCost.h | 8 +++---- ...dReserveParticipationByDispatchablePlant.h | 4 ++-- .../vCardReserveParticipationByGroup.h | 4 ++-- ...ardReserveParticipationUnsuppliedSpilled.h | 4 ++-- .../include/antares/solver/variable/state.h | 12 +++++----- src/solver/variable/state.cpp | 6 ++--- 12 files changed, 42 insertions(+), 73 deletions(-) diff --git a/src/format-code.sh b/src/format-code.sh index abac85a423..e69de29bb2 100755 --- a/src/format-code.sh +++ b/src/format-code.sh @@ -1,24 +0,0 @@ -#!/bin/bash - -if [ $# -eq 0 ] -then - # No arguments: format all - SOURCE_DIRS="analyzer/ libs/ solver/ tools/ config/ tests/ packaging/" - SOURCE_FILES=$(find $SOURCE_DIRS -regextype egrep -regex ".*/*\.(c|cxx|cpp|cc|h|hxx|hpp)$" ! -path '*/antlr-interface/*') -else - # Format files provided as arguments - SOURCE_FILES="$@" -fi - -# Remove ^M, etc. -if ! [ -x "$(command -v dos2unix)" ]; then - echo 'Warning: dos2unix is not installed. Skipping' >&2 -else - echo "$SOURCE_FILES" | xargs dos2unix -fi - -if ! [ -x "$(command -v clang-format)" ]; then - echo 'Warning: clang-format is not installed. Skipping' >&2 -else - echo "$SOURCE_FILES" | xargs clang-format -i --verbose -fi diff --git a/src/libs/antares/study/include/antares/study/area/capacityReservation.h b/src/libs/antares/study/include/antares/study/area/capacityReservation.h index 69391724ed..72195e1cae 100644 --- a/src/libs/antares/study/include/antares/study/area/capacityReservation.h +++ b/src/libs/antares/study/include/antares/study/area/capacityReservation.h @@ -38,7 +38,7 @@ struct CapacityReservation Antares::Data::TimeSeries need; private: - Matrix timeseriesNumbers; + Data::TimeSeriesNumbers timeseriesNumbers; }; /// @brief Stores all the Capacity reservations in two vectors for the up and down reserves diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index 6a17a7a964..e5388dddb9 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -224,18 +224,18 @@ void Data::ThermalCluster::copyFrom(const ThermalCluster& cluster) static Data::ThermalDispatchableGroup stringToGroup(Data::ClusterName& newgrp) { using namespace Antares::Data; - const static std::map mapping = { - {"nuclear", ThermalCluster::thermalDispatchGrpNuclear}, - {"lignite", ThermalCluster::thermalDispatchGrpLignite}, - {"hard coal", ThermalCluster::thermalDispatchGrpHardCoal}, - {"gas", ThermalCluster::thermalDispatchGrpGas}, - {"oil", ThermalCluster::thermalDispatchGrpOil}, - {"mixed fuel", ThermalCluster::thermalDispatchGrpMixedFuel}, - {"other", ThermalCluster::thermalDispatchGrpOther1}, - {"other 1", ThermalCluster::thermalDispatchGrpOther1}, - {"other 2", ThermalCluster::thermalDispatchGrpOther2}, - {"other 3", ThermalCluster::thermalDispatchGrpOther3}, - {"other 4", ThermalCluster::thermalDispatchGrpOther4}}; + const static std::map mapping = { + {"nuclear", thermalDispatchGrpNuclear}, + {"lignite", thermalDispatchGrpLignite}, + {"hard coal", thermalDispatchGrpHardCoal}, + {"gas", thermalDispatchGrpGas}, + {"oil", thermalDispatchGrpOil}, + {"mixed fuel", thermalDispatchGrpMixedFuel}, + {"other", thermalDispatchGrpOther1}, + {"other 1", thermalDispatchGrpOther1}, + {"other 2", thermalDispatchGrpOther2}, + {"other 3", thermalDispatchGrpOther3}, + {"other 4", thermalDispatchGrpOther4}}; boost::to_lower(newgrp); if (auto res = mapping.find(newgrp); res != mapping.end()) diff --git a/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h b/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h index fd49fc05c7..0089c8f3b5 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/LinearProblemMatrix.h @@ -55,7 +55,4 @@ class LinearProblemMatrix: public ProblemMatrixEssential MaxPumpingGroup maxPumpingGroup_; AreaHydroLevelGroup areaHydroLevelGroup_; FinalStockGroup finalStockGroup_; -}; -======= -}; ->>>>>>> develop +}; \ No newline at end of file diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index 13f624b5fc..970c0b8b01 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -160,13 +160,13 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, variablesMapping.NumeroDeVariableCoutExtremiteVersOrigineDeLInterconnexion .assign(linkCount, 0); variablesMapping.runningClusterReserveParticipationIndex - .assign(study.runtime->reserveParticipationCount, 0); + .assign(study.runtime.reserveParticipationCount, 0); variablesMapping.clusterReserveParticipationIndex - .assign(study.runtime->reserveParticipationCount, 0); + .assign(study.runtime.reserveParticipationCount, 0); variablesMapping.internalUnsatisfiedReserveIndex - .assign(study.runtime->capacityReservationCount, 0); + .assign(study.runtime.capacityReservationCount, 0); variablesMapping.internalExcessReserveIndex - .assign(study.runtime->capacityReservationCount, 0); + .assign(study.runtime.capacityReservationCount, 0); variablesMapping.NumeroDeVariableDuPalierThermique .assign(study.runtime.thermalPlantTotalCount, 0); @@ -222,13 +222,13 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, problem.CorrespondanceCntNativesCntOptim[k] .NumeroDeContrainteDesContraintesDeBesoinEnReserves.assign( - study.runtime->capacityReservationCount, 0); + study.runtime.capacityReservationCount, 0); problem.CorrespondanceCntNativesCntOptim[k] .NumeroDeContrainteDesContraintesDePuissanceMinDuPalier.assign( - study.runtime->thermalPlantTotalCount, 0); + study.runtime.thermalPlantTotalCount, 0); problem.CorrespondanceCntNativesCntOptim[k] .NumeroDeContrainteDesContraintesDePuissanceMaxDuPalier.assign( - study.runtime->thermalPlantTotalCount, 0); + study.runtime.thermalPlantTotalCount, 0); problem.CorrespondanceCntNativesCntOptim[k] .NumeroDeLaDeuxiemeContrainteDesContraintesDesGroupesQuiTombentEnPanne @@ -439,10 +439,6 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, .assign(nbPaliers, 0.); problem.ResultatsHoraires[k].ProductionThermique[j].ParticipationReservesDuPalier .assign(nbReserveParticipations, 0.); - problem.ResultatsHoraires[k].ProductionThermique[j].ProductionThermiqueDuPalierUp - .assign(nbPaliers, 0.); - problem.ResultatsHoraires[k].ProductionThermique[j].ProductionThermiqueDuPalierDown - .assign(nbPaliers, 0.); problem.ResultatsHoraires[k].ProductionThermique[j].NombreDeGroupesEnMarcheDuPalier .assign(nbPaliers, 0.); problem.ResultatsHoraires[k].ProductionThermique[j].NombreDeGroupesQuiDemarrentDuPalier diff --git a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h index 34861d4708..f34c84fe03 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationByDispatchablePlant.h @@ -182,8 +182,8 @@ class ReserveParticipationByDispatchablePlant // Get end year calculations if (pSize) { - for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; - i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + for (unsigned int i = state.study.runtime.rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd]; ++i) { for (auto const& [reserveName, reserveParticipation] : diff --git a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCost.h b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCost.h index 53b64d7308..222d2a7121 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCost.h +++ b/src/solver/variable/include/antares/solver/variable/economy/reserveParticipationCost.h @@ -74,9 +74,9 @@ struct VCardReserveParticipationCost enum { //! Data Level - categoryDataLevel = Category::area, + categoryDataLevel = Category::DataLevel::area, //! File level (provided by the type of the results) - categoryFileLevel = ResultsType::categoryFile & (Category::id | Category::va), + categoryFileLevel = ResultsType::categoryFile & (Category::FileLevel::id | Category::FileLevel::va), //! Precision (views) precision = Category::all, //! Indentation (GUI) @@ -202,8 +202,8 @@ class ReserveParticipationCost void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) { // Get end year calculations - for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; - i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + for (unsigned int i = state.study.runtime.rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd]; ++i) { pValuesForTheCurrentYear[numSpace][i] diff --git a/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h index 53f0ec174b..09ac1ac6b8 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByDispatchablePlant.h @@ -67,9 +67,9 @@ struct VCardReserveParticipationByDispatchablePlant enum { //! Data Level - categoryDataLevel = Category::area, + categoryDataLevel = Category::DataLevel::area, //! File level (provided by the type of the results) - categoryFileLevel = ResultsType::categoryFile & (Category::de), + categoryFileLevel = ResultsType::categoryFile & (Category::FileLevel::de), //! Precision (views) precision = Category::all, //! Indentation (GUI) diff --git a/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByGroup.h b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByGroup.h index 6ea3ed84cd..33eef2662c 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByGroup.h +++ b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationByGroup.h @@ -67,9 +67,9 @@ struct VCardReserveParticipationByGroup enum { //! Data Level - categoryDataLevel = Category::area, + categoryDataLevel = Category::DataLevel::area, //! File level (provided by the type of the results) - categoryFileLevel = ResultsType::categoryFile & (Category::id | Category::va), + categoryFileLevel = ResultsType::categoryFile & (Category::FileLevel::id | Category::FileLevel::va), //! Precision (views) precision = Category::all, //! Indentation (GUI) diff --git a/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationUnsuppliedSpilled.h b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationUnsuppliedSpilled.h index dac67a0992..a266bb5a9c 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationUnsuppliedSpilled.h +++ b/src/solver/variable/include/antares/solver/variable/economy/vCardReserveParticipationUnsuppliedSpilled.h @@ -67,9 +67,9 @@ struct VCardReserveParticipationUnsuppliedSpilled enum { //! Data Level - categoryDataLevel = Category::area, + categoryDataLevel = Category::DataLevel::area, //! File level (provided by the type of the results) - categoryFileLevel = ResultsType::categoryFile & (Category::id | Category::va), + categoryFileLevel = ResultsType::categoryFile & (Category::FileLevel::id | Category::FileLevel::va), //! Precision (views) precision = Category::all, //! Indentation (GUI) diff --git a/src/solver/variable/include/antares/solver/variable/state.h b/src/solver/variable/include/antares/solver/variable/state.h index 562a88c98f..aec179ce01 100644 --- a/src/solver/variable/include/antares/solver/variable/state.h +++ b/src/solver/variable/include/antares/solver/variable/state.h @@ -120,7 +120,7 @@ class State void yearEndBuildCalculateReserveParticipationCosts(const Data::ThermalCluster* currentCluster); - std::array computeEconomicallyOptimalNbClustersONforEachHour( + std::array computeEconomicallyOptimalNbClustersONforEachHour( const uint& maxDurationON, const std::array& ON_min, const std::array& ON_max) const; @@ -183,15 +183,15 @@ class State VALEURS_DE_NTC_ET_RESISTANCES ntc; //! Thermal production for the current thermal cluster for the whole year - double thermalClusterProductionForYear[Variable::maxHoursInAYear]; + double thermalClusterProductionForYear[HOURS_PER_YEAR]; //! Reserve Participation for all thermal group types (nuclear / coal / ...) for the whole year //! per reserve std::map> - thermalReserveParticipationPerGroupForYear[Variable::maxHoursInAYear]; + thermalReserveParticipationPerGroupForYear[HOURS_PER_YEAR]; //! Reserve Participation for all clusters per reserve std::map> - thermalReserveParticipationPerClusterForYear[Variable::maxHoursInAYear]; + thermalReserveParticipationPerClusterForYear[HOURS_PER_YEAR]; //! Number of unit dispatched for all clusters for the whole year for ucHeruistic (fast) or //! ucMILP (accurate) @@ -202,9 +202,9 @@ class State //! Thermal NP Cost for the current thermal cluster for the whole year double thermalClusterNonProportionalCostForYear[HOURS_PER_YEAR]; //! Minimum power of the cluster for the whole year - double thermalClusterPMinOfTheClusterForYear[Variable::maxHoursInAYear]; + double thermalClusterPMinOfTheClusterForYear[HOURS_PER_YEAR]; //! Reserves participation cost of the thermal cluster for the whole year - double thermalClusterReserveParticipationCostForYear[Variable::maxHoursInAYear]; + double thermalClusterReserveParticipationCostForYear[HOURS_PER_YEAR]; double renewableClusterProduction; diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index e6683d01d8..594beb8d43 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -184,7 +184,7 @@ int State::getAreaIndexFromReserveAndCluster(Data::ReserveName reserveName, Data void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideIndex) { - uint serieIndex = thermalCluster->series.timeseriesNumbers[0][this->year]; + uint serieIndex = thermalCluster->series.timeseriesNumbers[this->year]; if (thermal[area->index].thermalClustersProductions[clusterAreaWideIndex] > 0.) { // alias to the production of the current thermal cluster @@ -443,9 +443,9 @@ void State::yearEndBuildCalculateReserveParticipationCosts( { if (unitCommitmentMode != Antares::Data::UnitCommitmentMode::ucHeuristicFast) { - uint startHourForCurrentYear = study.runtime->rangeLimits.hour[Data::rangeBegin]; + uint startHourForCurrentYear = study.runtime.rangeLimits.hour[Data::rangeBegin]; uint endHourForCurrentYear - = startHourForCurrentYear + study.runtime->rangeLimits.hour[Data::rangeCount]; + = startHourForCurrentYear + study.runtime.rangeLimits.hour[Data::rangeCount]; for (uint h = startHourForCurrentYear; h < endHourForCurrentYear; ++h) { thermalClusterOperatingCostForYear[h]