From 28208e6689e532891cf1e3e633859fd8dedc73da Mon Sep 17 00:00:00 2001 From: sylvmara Date: Mon, 8 Apr 2024 17:31:50 +0200 Subject: [PATCH] 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);