From 1a3fe6ed0d50f49c52b08624c37a59b306661e8d Mon Sep 17 00:00:00 2001 From: CAMUS Benjamin Date: Thu, 28 Nov 2024 16:44:54 +0100 Subject: [PATCH] first version of the implementation of the reserve equations v.2 for part 3 --- src/libs/antares/study/area/list.cpp | 53 +++++++- .../antares/study/area/capacityReservation.h | 8 +- src/solver/optimisation/CMakeLists.txt | 4 + .../constraints/ReserveParticipationGroup.cpp | 16 ++- ...STStockEnergyLevelReserveParticipation.cpp | 59 +++++++++ ...kGlobalEnergyLevelReserveParticipation.cpp | 123 ++++++++++++++++++ .../STStockLevelReserveParticipation.cpp | 121 ++++++++--------- .../STStockEnergyLevelReserveParticipation.h | 26 ++++ ...ockGlobalEnergyLevelReserveParticipation.h | 25 ++++ .../solver/optimisation/opt_rename_problem.h | 4 + .../opt_gestion_second_membre_reserves.cpp | 61 ++++++++- .../optimisation/opt_rename_problem.cpp | 19 ++- .../sim_structure_probleme_economique.h | 8 ++ .../simulation/sim_alloc_probleme_hebdo.cpp | 11 +- .../simulation/sim_calcul_economique.cpp | 7 + 15 files changed, 465 insertions(+), 80 deletions(-) create mode 100644 src/solver/optimisation/constraints/STStockEnergyLevelReserveParticipation.cpp create mode 100644 src/solver/optimisation/constraints/STStockGlobalEnergyLevelReserveParticipation.cpp create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/constraints/STStockEnergyLevelReserveParticipation.h create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/constraints/STStockGlobalEnergyLevelReserveParticipation.h diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index 5f26fc925d..6c915b7d0f 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -920,7 +920,49 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, ini.each( [&](const IniFile::Section& section) { - if (area.allCapacityReservations.contains(section.name)) + if (section.name == "globalparameters" && section.firstProperty) + { + for (auto* p = section.firstProperty; p; p = p->next) + { + CString<30, false> tmp; + tmp = p->key; + tmp.toLower(); + + if (tmp == "max_activation_ratio_up") + { + if (!p->value.to(area.allCapacityReservations.maxGlobalEnergyActivationRatioUp)) + { + logs.warning() + << area.name << ": invalid maximum energy activation ratio for UP reserves"; + } + } + else if (tmp == "max_activation_ratio_down") + { + if (!p->value.to(area.allCapacityReservations.maxGlobalEnergyActivationRatioDown)) + { + logs.warning() + << area.name << ": invalid maximum energy activation ratio for DOWN reserves"; + } + } + else if (tmp == "max_activation_duration_up") + { + if (!p->value.to(area.allCapacityReservations.maxGlobalActivationDurationUp)) + { + logs.warning() + << area.name << ": invalid maximum energy activation duration for UP reserves"; + } + } + else if (tmp == "max_activation_duration_down") + { + if (!p->value.to(area.allCapacityReservations.maxGlobalActivationDurationDown)) + { + logs.warning() + << area.name << ": invalid maximum energy activation duration for DOWN reserves"; + } + } + } + } + else if (area.allCapacityReservations.contains(section.name)) { logs.warning() << area.name << ": reserve name already exists for reserve " << section.name; @@ -963,6 +1005,15 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, << section.name; } } + else if (tmp == "max-energy-activation-ratio") + { + if (!p->value.to(tmpCapacityReservation.maxEnergyActivationRatio)) + { + logs.warning() + << area.name << ": invalid maximum energy activation ratio for reserve " + << section.name; + } + } else if (tmp == "max-activation-duration") { if (!p->value.to(tmpCapacityReservation.maxActivationHours)) 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 5c4056fc4c..df06f50c5e 100644 --- a/src/libs/antares/study/include/antares/study/area/capacityReservation.h +++ b/src/libs/antares/study/include/antares/study/area/capacityReservation.h @@ -33,10 +33,11 @@ /// @brief Represents an area capacity reservation using it's name, it's failure cost and it's spillage cost struct CapacityReservation { - CapacityReservation() : failureCost(0), spillageCost(0), need(timeseriesNumbers), maxActivationRatio(1.), maxActivationHours(0) {} + CapacityReservation() : failureCost(0), spillageCost(0), need(timeseriesNumbers), maxActivationRatio(0.), maxEnergyActivationRatio(1.), maxActivationHours(1.) {} float failureCost; float spillageCost; float maxActivationRatio; + float maxEnergyActivationRatio; int maxActivationHours; Antares::Data::TimeSeries need; @@ -47,6 +48,11 @@ struct CapacityReservation /// @brief Stores all the Capacity reservations in two vectors for the up and down reserves struct AllCapacityReservations { + float maxGlobalEnergyActivationRatioUp = 1.; + float maxGlobalEnergyActivationRatioDown = 1.; + int maxGlobalActivationDurationUp = 1; + int maxGlobalActivationDurationDown = 1; + std::map areaCapacityReservationsUp; std::map areaCapacityReservationsDown; diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index f855534522..90c37a2652 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -166,6 +166,10 @@ set(RTESOLVER_OPT constraints/LTPumpingCapacityThreasholds.cpp include/antares/solver/optimisation/constraints/LTStockLevelReserveParticipation.h constraints/LTStockLevelReserveParticipation.cpp + include/antares/solver/optimisation/constraints/STStockEnergyLevelReserveParticipation.h + constraints/STStockEnergyLevelReserveParticipation.cpp + include/antares/solver/optimisation/constraints/STStockGlobalEnergyLevelReserveParticipation.h + constraints/STStockGlobalEnergyLevelReserveParticipation.cpp include/antares/solver/optimisation/ProblemMatrixEssential.h ProblemMatrixEssential.cpp include/antares/solver/optimisation/LinearProblemMatrixStartUpCosts.h diff --git a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp index 5fc3d96d0d..49e8c51e01 100644 --- a/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp +++ b/src/solver/optimisation/constraints/ReserveParticipationGroup.cpp @@ -42,7 +42,8 @@ #include "antares/solver/optimisation/constraints/LTPumpingCapacityThreasholds.h" #include "antares/solver/optimisation/constraints/LTStockLevelReserveParticipation.h" #include "antares/solver/optimisation/constraints/STStockLevelReserveParticipation.h" - +#include "antares/solver/optimisation/constraints/STStockEnergyLevelReserveParticipation.h" +#include "antares/solver/optimisation/constraints/STStockGlobalEnergyLevelReserveParticipation.h" ReserveParticipationGroup::ReserveParticipationGroup(PROBLEME_HEBDO* problemeHebdo, @@ -80,6 +81,7 @@ void ReserveParticipationGroup::BuildConstraints() STPumpingMaxReserve STPumpingMaxReserve(builder_, data); STReserveUpParticipation STReserveUpParticipation(builder_, data); STReserveDownParticipation STReserveDownParticipation(builder_, data); + STStockEnergyLevelReserveParticipation STStockEnergyLevelReserveParticipation(builder_, data); LTTurbiningMaxReserve LTTurbiningMaxReserve(builder_, data); LTPumpingMaxReserve LTPumpingMaxReserve(builder_, data); LTReserveUpParticipation LTReserveUpParticipation(builder_, data); @@ -188,6 +190,9 @@ void ReserveParticipationGroup::BuildConstraints() // 15 (o) STReserveUpParticipation .add(pays, reserve, clusterReserveParticipation.clusterIdInArea, pdt); + + // 15 (h) + STStockEnergyLevelReserveParticipation.add(pays, clusterReserveParticipation.clusterIdInArea, reserve, pdt, true); } reserve++; } @@ -214,6 +219,9 @@ void ReserveParticipationGroup::BuildConstraints() // 15 (p) STReserveDownParticipation .add(pays, reserve, clusterReserveParticipation.clusterIdInArea, pdt); + + // 15 (h) + STStockEnergyLevelReserveParticipation.add(pays, clusterReserveParticipation.clusterIdInArea, reserve, pdt, false); } reserve++; } @@ -286,6 +294,7 @@ void ReserveParticipationGroup::BuildConstraints() LTPumpingCapacityThreasholds LTPumpingCapacityThreasholds(builder_, data); LTStockLevelReserveParticipation LTStockLevelReserveParticipation(builder_, data); STStockLevelReserveParticipation STStockLevelReserveParticipation(builder_, data); + STStockGlobalEnergyLevelReserveParticipation STStockGlobalEnergyLevelReserveParticipation(builder_, data); for (int pdt = 0; pdt < problemeHebdo_->NombreDePasDeTempsPourUneOptimisation; pdt++) { @@ -312,8 +321,10 @@ void ReserveParticipationGroup::BuildConstraints() STTurbiningCapacityThreasholds.add(pays, cluster, pdt); // 15 (n) STPumpingCapacityThreasholds.add(pays, cluster, pdt); - // 15 (r) + // 15 (g) STStockLevelReserveParticipation.add(pays, cluster, pdt); + // 15 (i) + STStockGlobalEnergyLevelReserveParticipation.add(pays, cluster, pdt); } // Long Term Storage Clusters @@ -337,7 +348,6 @@ void ReserveParticipationGroup::BuildConstraints() LTPumpingCapacityThreasholds.add(pays, 0, pdt); // 15 (r) LTStockLevelReserveParticipation.add(pays, 0, pdt); - } } } diff --git a/src/solver/optimisation/constraints/STStockEnergyLevelReserveParticipation.cpp b/src/solver/optimisation/constraints/STStockEnergyLevelReserveParticipation.cpp new file mode 100644 index 0000000000..df111f3e81 --- /dev/null +++ b/src/solver/optimisation/constraints/STStockEnergyLevelReserveParticipation.cpp @@ -0,0 +1,59 @@ +#include "antares/solver/optimisation/constraints/STStockEnergyLevelReserveParticipation.h" + +void STStockEnergyLevelReserveParticipation::add(int pays, int cluster, int reserve, int pdt, bool isUpReserve) +{ + int globalClusterIdx = data.shortTermStorageOfArea[pays][cluster].clusterGlobalIndex; + CAPACITY_RESERVATION& capacityReservation + = isUpReserve ? data.areaReserves[pays].areaCapacityReservationsUp[reserve] + : data.areaReserves[pays].areaCapacityReservationsDown[reserve]; + + if (!data.Simulation) + { + // 15 (h) (1) + // Participation of down reserves requires a sufficient level of stock + // Sum(P_{res,t_st} * R_{min,res} +/- J_res * R_{lambda,t_st}) <= n_min * R_up + // R_t : stock level at time t + // P_{res,t_st} : power participation for reserve down res at time t_st + // R_{min,res} : max power participation ratio + // R_up : max stock level + { + float sign = isUpReserve ? -1. : 1.; + + RESERVE_PARTICIPATION_STSTORAGE& reserveParticipation + = capacityReservation.AllSTStorageReservesParticipation[cluster]; + + builder.updateHourWithinWeek(pdt); + + for (int t=0; t < capacityReservation.maxActivationDuration; t++) + { + builder.STStorageClusterReserveDownParticipation( + reserveParticipation.globalIndexClusterParticipation, + capacityReservation.maxActivationRatio, + t, builder.data.NombreDePasDeTempsPourUneOptimisation); + builder.ShortTermStorageLevel(globalClusterIdx, sign * capacityReservation.maxEnergyActivationRatio, + t, builder.data.NombreDePasDeTempsPourUneOptimisation); + } + + builder.lessThan(); + + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesSTStockEnergyLevelReserveParticipation + [reserveParticipation.globalIndexClusterParticipation] + = 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.STEnergyStockLevelReserveParticipationDown(builder.data.nombreDeContraintes, + reserveParticipation.clusterName, + capacityReservation.reserveName); + builder.build(); + } + } + else + { + builder.data.NbTermesContraintesPourLesReserves += 2 * capacityReservation.maxActivationDuration; + builder.data.nombreDeContraintes += 1; + } +} \ No newline at end of file diff --git a/src/solver/optimisation/constraints/STStockGlobalEnergyLevelReserveParticipation.cpp b/src/solver/optimisation/constraints/STStockGlobalEnergyLevelReserveParticipation.cpp new file mode 100644 index 0000000000..3e1fbe7c18 --- /dev/null +++ b/src/solver/optimisation/constraints/STStockGlobalEnergyLevelReserveParticipation.cpp @@ -0,0 +1,123 @@ +#include "antares/solver/optimisation/constraints/STStockGlobalEnergyLevelReserveParticipation.h" + +void STStockGlobalEnergyLevelReserveParticipation::add(int pays, int cluster, int pdt) +{ + int globalClusterIdx = data.shortTermStorageOfArea[pays][cluster].clusterGlobalIndex; + + + if (!data.Simulation) + { + // Stock participation is energy constrained (optional constraints) + // Sum(P_{res,t_st} * R_{min,res} +/- J_down/up * R_{lambda,t_st}) <= n_min * R_up + // R_t : stock level at time t + // P_{res,t_st} : power participation for reserve down res at time t_st + // R_{min,res} : max power participation ratio + // R_up : max stock level + + // DOWN reserves + { + builder.updateHourWithinWeek(pdt); + + for (int t=0; t < data.areaReserves[pays].maxGlobalActivationDurationDown; t++) + { + + for (auto& capacityReservation : data.areaReserves[pays].areaCapacityReservationsDown) + { + if (capacityReservation.AllSTStorageReservesParticipation.contains(cluster)) + { + RESERVE_PARTICIPATION_STSTORAGE& reserveParticipation = capacityReservation.AllSTStorageReservesParticipation[cluster]; + builder.STStorageClusterReserveDownParticipation( + reserveParticipation.globalIndexClusterParticipation, + capacityReservation.maxActivationRatio, + t, builder.data.NombreDePasDeTempsPourUneOptimisation); + } + } + if (builder.NumberOfVariables() > 0) + { + builder.ShortTermStorageLevel(globalClusterIdx, data.areaReserves[pays].maxGlobalEnergyActivationRatioDown, + t, builder.data.NombreDePasDeTempsPourUneOptimisation); + } + } + + if (builder.NumberOfVariables() > 0) + { + builder.lessThan(); + + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesSTGlobalStockEnergyLevelReserveParticipationDown + [globalClusterIdx] + = 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.STGlobalEnergyStockLevelReserveParticipationDown(builder.data.nombreDeContraintes, + "ShortTermStorage"); + builder.build(); + } + } + + // UP reserves + { + builder.updateHourWithinWeek(pdt); + + for (int t=0; t < data.areaReserves[pays].maxGlobalActivationDurationUp; t++) + { + for (auto& capacityReservation : data.areaReserves[pays].areaCapacityReservationsUp) + { + if (capacityReservation.AllSTStorageReservesParticipation.contains(cluster)) + { + RESERVE_PARTICIPATION_STSTORAGE& reserveParticipation = capacityReservation.AllSTStorageReservesParticipation[cluster]; + builder.STStorageClusterReserveUpParticipation( + reserveParticipation.globalIndexClusterParticipation, + capacityReservation.maxActivationRatio, + t, builder.data.NombreDePasDeTempsPourUneOptimisation); + } + } + if (builder.NumberOfVariables() > 0) + { + builder.ShortTermStorageLevel(globalClusterIdx, -data.areaReserves[pays].maxGlobalEnergyActivationRatioUp, + t, builder.data.NombreDePasDeTempsPourUneOptimisation); + } + } + + if (builder.NumberOfVariables() > 0) + { + builder.lessThan(); + + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesSTGlobalStockEnergyLevelReserveParticipationUp + [globalClusterIdx] + = 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.STGlobalEnergyStockLevelReserveParticipationUp(builder.data.nombreDeContraintes, + "ShortTermStorage"); + builder.build(); + } + } + } + else + { + // Lambda that count the number of reserveParticipations + auto countReservesParticipations = [cluster](const std::vector& reservations, int t_max) + { + int counter = 0; + for (const auto& capacityReservation: reservations) + { + counter += capacityReservation.AllSTStorageReservesParticipation.count(cluster) * t_max; + } + return counter; + }; + + int nbTermsUp = countReservesParticipations(data.areaReserves[pays].areaCapacityReservationsUp, data.areaReserves[pays].maxGlobalActivationDurationUp); + int nbTermsDown = countReservesParticipations(data.areaReserves[pays].areaCapacityReservationsDown, data.areaReserves[pays].maxGlobalActivationDurationDown); + + builder.data.NbTermesContraintesPourLesReserves += (nbTermsUp + data.areaReserves[pays].maxGlobalActivationDurationUp) * (nbTermsUp > 0) + (nbTermsDown + data.areaReserves[pays].maxGlobalActivationDurationDown) * (nbTermsDown > 0); + builder.data.nombreDeContraintes += (nbTermsUp > 0) + (nbTermsDown > 0); + } +} \ No newline at end of file diff --git a/src/solver/optimisation/constraints/STStockLevelReserveParticipation.cpp b/src/solver/optimisation/constraints/STStockLevelReserveParticipation.cpp index f93d5d9cf2..0bb982a088 100644 --- a/src/solver/optimisation/constraints/STStockLevelReserveParticipation.cpp +++ b/src/solver/optimisation/constraints/STStockLevelReserveParticipation.cpp @@ -6,112 +6,99 @@ void STStockLevelReserveParticipation::add(int pays, int cluster, int pdt) if (!data.Simulation) { - // 15 (r) (1) + // 15 (g) (1) // Participation of down reserves requires a sufficient level of stock - // R_t + Sum(P_{res,t_st} * R_{min,res}) <= R_up + // R_t + Sum(P_{res} * R_{min,res}) <= R_up // R_t : stock level at time t - // P_{res,t_st} : power participation for reserve down res at time t_st + // P_{res} : power participation for reserve down res // R_{min,res} : max power participation ratio // R_up : max stock level { - builder.updateHourWithinWeek(pdt).ShortTermStorageLevel(globalClusterIdx, 1.); + builder.updateHourWithinWeek(pdt); - for (const auto& capacityReservation : data.areaReserves[pays].areaCapacityReservationsDown) + for (auto& capacityReservation : data.areaReserves[pays].areaCapacityReservationsDown) { - int t_max = pdt + capacityReservation.maxActivationDuration; - if (t_max > builder.data.NombreDePasDeTempsPourUneOptimisation) - t_max = builder.data.NombreDePasDeTempsPourUneOptimisation; - - for (int t=pdt; t < t_max; t++) + if (capacityReservation.AllSTStorageReservesParticipation.contains(cluster)) { - builder.updateHourWithinWeek(t); - for (const auto& [clusterId, reserveParticipations] : capacityReservation.AllSTStorageReservesParticipation) - { - if (cluster == clusterId) - builder.STStorageClusterReserveDownParticipation( + RESERVE_PARTICIPATION_STSTORAGE reserveParticipations = capacityReservation.AllSTStorageReservesParticipation[cluster]; + builder.STStorageClusterReserveDownParticipation( reserveParticipations.globalIndexClusterParticipation, capacityReservation.maxActivationRatio); - } } } - builder.lessThan(); - data.CorrespondanceCntNativesCntOptim[pdt] - .NumeroDeContrainteDesContraintesSTStockLevelReserveParticipationDown - [globalClusterIdx] - = 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.STStockLevelReserveParticipationDown(builder.data.nombreDeContraintes, - "ShortTermStorage"); - builder.build(); + if (builder.NumberOfVariables() > 0) + { + builder.ShortTermStorageLevel(globalClusterIdx, 1.); + builder.lessThan(); + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesSTStockLevelReserveParticipationDown + [globalClusterIdx] + = 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.STStockLevelReserveParticipationDown(builder.data.nombreDeContraintes, + "ShortTermStorage"); + builder.build(); + } } - // 15 (r) (2) + // 15 (g) (2) // Participation of up reserves requires a sufficient level of stock - // R_t - Sum(P_{res,t_st} * R_{min,res}) >= R_down + // R_t - Sum(P_{res} * R_{min,res}) >= R_down // R_t : stock level at time t - // P_{res,t_st} : power participation for reserve up res at time t_st + // P_{res} : power participation for reserve up res // R_{min,res} : max power participation ratio // R_down : min stock level { - builder.updateHourWithinWeek(pdt).ShortTermStorageLevel(globalClusterIdx, 1.); + builder.updateHourWithinWeek(pdt); - for (const auto& capacityReservation : data.areaReserves[pays].areaCapacityReservationsUp) + for (auto& capacityReservation : data.areaReserves[pays].areaCapacityReservationsUp) { - int t_max = pdt + capacityReservation.maxActivationDuration; - if (t_max > builder.data.NombreDePasDeTempsPourUneOptimisation) - t_max = builder.data.NombreDePasDeTempsPourUneOptimisation; - - for (int t=pdt; t < t_max; t++) + if (capacityReservation.AllSTStorageReservesParticipation.contains(cluster)) { - builder.updateHourWithinWeek(t); - for (const auto& [clusterId, reserveParticipations] : capacityReservation.AllSTStorageReservesParticipation) - { - if (cluster == clusterId) - builder.STStorageClusterReserveUpParticipation( + RESERVE_PARTICIPATION_STSTORAGE reserveParticipations = capacityReservation.AllSTStorageReservesParticipation[cluster]; + builder.STStorageClusterReserveUpParticipation( reserveParticipations.globalIndexClusterParticipation, -capacityReservation.maxActivationRatio); - } } } - builder.greaterThan(); - data.CorrespondanceCntNativesCntOptim[pdt] - .NumeroDeContrainteDesContraintesSTStockLevelReserveParticipationUp - [globalClusterIdx] - = 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.STStockLevelReserveParticipationUp(builder.data.nombreDeContraintes, - "ShortTermStorage"); - builder.build(); + if (builder.NumberOfVariables() > 0) + { + builder.ShortTermStorageLevel(globalClusterIdx, -1.); + builder.lessThan(); + data.CorrespondanceCntNativesCntOptim[pdt] + .NumeroDeContrainteDesContraintesSTStockLevelReserveParticipationUp + [globalClusterIdx] + = 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.STStockLevelReserveParticipationUp(builder.data.nombreDeContraintes, + "ShortTermStorage"); + builder.build(); + } } } else { // Lambda that count the number of reserveParticipations - auto countReservesParticipations = [cluster](const std::vector& reservations, int time, int time_max) + auto countReservesParticipations = [cluster](const std::vector& reservations) { int counter = 0; for (const auto& capacityReservation: reservations) { - int n_t = capacityReservation.maxActivationDuration; - if (time + n_t > time_max) - n_t = time_max - time; - counter += capacityReservation.AllSTStorageReservesParticipation.count(cluster) * n_t; + counter += capacityReservation.AllSTStorageReservesParticipation.count(cluster); } return counter; }; - int nbTermsUp = countReservesParticipations( - data.areaReserves[pays].areaCapacityReservationsUp, pdt, builder.data.NombreDePasDeTempsPourUneOptimisation); - int nbTermsDown = countReservesParticipations( - data.areaReserves[pays].areaCapacityReservationsDown, pdt, builder.data.NombreDePasDeTempsPourUneOptimisation); + int nbTermsUp = countReservesParticipations(data.areaReserves[pays].areaCapacityReservationsUp); + int nbTermsDown = countReservesParticipations(data.areaReserves[pays].areaCapacityReservationsDown); - builder.data.NbTermesContraintesPourLesReserves += (nbTermsUp + 1) + (nbTermsDown + 1); - builder.data.nombreDeContraintes += 2; + builder.data.NbTermesContraintesPourLesReserves += (nbTermsUp + 1) * (nbTermsUp > 0) + (nbTermsDown + 1) * (nbTermsDown > 0); + builder.data.nombreDeContraintes += (nbTermsUp > 0) + (nbTermsDown > 0); } } \ No newline at end of file diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/STStockEnergyLevelReserveParticipation.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/STStockEnergyLevelReserveParticipation.h new file mode 100644 index 0000000000..6e2c7b624a --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/STStockEnergyLevelReserveParticipation.h @@ -0,0 +1,26 @@ +#pragma once +#include "ConstraintBuilder.h" + +/* + * represent 'STStockLevelReserveParticipation' Constraint type + */ +class STStockEnergyLevelReserveParticipation : private ConstraintFactory +{ +public: + STStockEnergyLevelReserveParticipation(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 + * @param isUpReserve : true if ReserveUp, false if ReserveDown + */ + void add(int pays, int cluster, int reserve, int pdt, bool isUpReserve); + +private: + ReserveData& data; +}; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/STStockGlobalEnergyLevelReserveParticipation.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/STStockGlobalEnergyLevelReserveParticipation.h new file mode 100644 index 0000000000..e797389722 --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/STStockGlobalEnergyLevelReserveParticipation.h @@ -0,0 +1,25 @@ +#pragma once +#include "ConstraintBuilder.h" + +/* + * represent 'STStockLevelReserveParticipation' Constraint type + */ +class STStockGlobalEnergyLevelReserveParticipation : private ConstraintFactory +{ +public: + STStockGlobalEnergyLevelReserveParticipation(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/opt_rename_problem.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h index 228fc376f6..6da8f953da 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 @@ -232,6 +232,10 @@ class ConstraintNamer: public Namer void STPumpingCapacityThreasholdsDown(unsigned int constraint, const std::string& clusterName); void STStockLevelReserveParticipationUp(unsigned int constraint, const std::string& clusterName); void STStockLevelReserveParticipationDown(unsigned int constraint, const std::string& clusterName); + void STEnergyStockLevelReserveParticipationDown(unsigned int constraint, const std::string& clusterName, const std::string& reserveName); + void STGlobalEnergyStockLevelReserveParticipationDown(unsigned int constraint, const std::string& clusterName); + void STGlobalEnergyStockLevelReserveParticipationUp(unsigned int constraint, const std::string& clusterName); + void LTReserveUpParticipation(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 f4a1378834..53d5d842fa 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_reserves.cpp @@ -165,6 +165,21 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO* pro SecondMembre[cnt] = reserveParticipation.maxPumping; AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; } + + cnt + = CorrespondanceCntNativesCntOptim + .NumeroDeContrainteDesContraintesSTStockEnergyLevelReserveParticipation + [reserveParticipation.globalIndexClusterParticipation]; + if (cnt >= 0) + { + auto variableManager = VariableManagerFromProblemHebdo(problemeHebdo); + std::vector& Xmin = problemeHebdo->ProblemeAResoudre->Xmin; + int clusterGlobalIndex = problemeHebdo->ShortTermStorage[pays][reserveParticipation.clusterIdInArea].clusterGlobalIndex; + int varLevel = variableManager.ShortTermStorageLevel(clusterGlobalIndex, pdtJour); + double level_min = Xmin[varLevel]; + SecondMembre[cnt] = -areaReserveUp.maxEnergyActivationRatio * areaReserveUp.maxActivationDuration * level_min; + AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; + } } } auto& areaReservesDown @@ -192,6 +207,21 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO* pro SecondMembre[cnt] = reserveParticipation.maxPumping; AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; } + + cnt + = CorrespondanceCntNativesCntOptim + .NumeroDeContrainteDesContraintesSTStockEnergyLevelReserveParticipation + [reserveParticipation.globalIndexClusterParticipation]; + if (cnt >= 0) + { + auto variableManager = VariableManagerFromProblemHebdo(problemeHebdo); + std::vector& Xmax = problemeHebdo->ProblemeAResoudre->Xmax; + int clusterGlobalIndex = problemeHebdo->ShortTermStorage[pays][reserveParticipation.clusterIdInArea].clusterGlobalIndex; + int varLevel = variableManager.ShortTermStorageLevel(clusterGlobalIndex, pdtJour); + double level_max = Xmax[varLevel]; + SecondMembre[cnt] = areaReserveDown.maxEnergyActivationRatio * areaReserveDown.maxActivationDuration * level_max; + AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; + } } } for (const auto& cluster : problemeHebdo->ShortTermStorage[pays]) @@ -230,13 +260,19 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO* pro AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; } + auto variableManager = VariableManagerFromProblemHebdo(problemeHebdo); + int varLevel = variableManager.ShortTermStorageLevel(globalClusterIdx, pdtJour); + std::vector& Xmax = problemeHebdo->ProblemeAResoudre->Xmax; + double level_max = Xmax[varLevel]; + std::vector& Xmin = problemeHebdo->ProblemeAResoudre->Xmin; + double level_min = Xmin[varLevel]; + cnt = CorrespondanceCntNativesCntOptim .NumeroDeContrainteDesContraintesSTStockLevelReserveParticipationDown [globalClusterIdx]; if (cnt >= 0) { - SecondMembre[cnt] = cluster.reservoirCapacity - * cluster.series->upperRuleCurve[pdtJour]; + SecondMembre[cnt] = level_max; AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; } @@ -245,10 +281,27 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireReserves(PROBLEME_HEBDO* pro [globalClusterIdx]; if (cnt >= 0) { - SecondMembre[cnt] = cluster.reservoirCapacity - * cluster.series->lowerRuleCurve[pdtJour]; + SecondMembre[cnt] = -level_min; AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; } + + cnt = CorrespondanceCntNativesCntOptim + .NumeroDeContrainteDesContraintesSTGlobalStockEnergyLevelReserveParticipationDown + [globalClusterIdx]; + if (cnt >= 0) + { + SecondMembre[cnt] = areaReserves[pays].maxGlobalActivationDurationDown * areaReserves[pays].maxGlobalEnergyActivationRatioDown * level_max; + AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; + } + + cnt = CorrespondanceCntNativesCntOptim + .NumeroDeContrainteDesContraintesSTGlobalStockEnergyLevelReserveParticipationUp + [globalClusterIdx]; + if (cnt >= 0) + { + SecondMembre[cnt] = -areaReserves[pays].maxGlobalActivationDurationUp * areaReserves[pays].maxGlobalEnergyActivationRatioUp * level_min; + AdresseOuPlacerLaValeurDesCoutsMarginaux[cnt] = nullptr; + } } } diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index cba9f668b6..3c271c86cf 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -641,12 +641,27 @@ void ConstraintNamer::STPumpingCapacityThreasholdsDown(unsigned int constraint, void ConstraintNamer::STStockLevelReserveParticipationUp(unsigned int constraint, const std::string& clusterName) { - SetLTStorageClusterElementName(constraint, "STStockLevelReserveParticipationUp", clusterName); + SetSTStorageClusterElementName(constraint, "STStockLevelReserveParticipationUp", clusterName); } void ConstraintNamer::STStockLevelReserveParticipationDown(unsigned int constraint, const std::string& clusterName) { - SetLTStorageClusterElementName(constraint, "STStockLevelReserveParticipationDown", clusterName); + SetSTStorageClusterElementName(constraint, "STStockLevelReserveParticipationDown", clusterName); +} + +void ConstraintNamer::STEnergyStockLevelReserveParticipationDown(unsigned int constraint, const std::string& clusterName, const std::string& reserveName) +{ + SetSTStorageClusterAndReserveElementName(constraint, "STEnergyStockLevelReserveParticipationDown", clusterName, reserveName); +} + +void ConstraintNamer::STGlobalEnergyStockLevelReserveParticipationDown(unsigned int constraint, const std::string& clusterName) +{ + SetSTStorageClusterElementName(constraint, "STGlobalEnergyStockLevelReserveParticipationDown", clusterName); +} + +void ConstraintNamer::STGlobalEnergyStockLevelReserveParticipationUp(unsigned int constraint, const std::string& clusterName) +{ + SetSTStorageClusterElementName(constraint, "STGlobalEnergyStockLevelReserveParticipationUp", clusterName); } void ConstraintNamer::LTReserveUpParticipation(unsigned int constraint, 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 5e3bd29139..20f398259d 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 @@ -121,6 +121,9 @@ struct CORRESPONDANCES_DES_CONTRAINTES std::vector NumeroDeContrainteDesContraintesSTStorageClusterPumpingCapacityThreasholds; std::vector NumeroDeContrainteDesContraintesSTStockLevelReserveParticipationUp; std::vector NumeroDeContrainteDesContraintesSTStockLevelReserveParticipationDown; + std::vector NumeroDeContrainteDesContraintesSTStockEnergyLevelReserveParticipation; + std::vector NumeroDeContrainteDesContraintesSTGlobalStockEnergyLevelReserveParticipationUp; + std::vector NumeroDeContrainteDesContraintesSTGlobalStockEnergyLevelReserveParticipationDown; std::vector NumeroDeContrainteDesContraintesLTStorageClusterMaxWithdrawParticipation; std::vector NumeroDeContrainteDesContraintesLTStorageClusterMaxInjectionParticipation; @@ -333,6 +336,7 @@ struct CAPACITY_RESERVATION float failureCost = 0; float spillageCost = 0; float maxActivationRatio = 0; + float maxEnergyActivationRatio = 1; int maxActivationDuration = 0; std::string reserveName; int globalReserveIndex; @@ -342,6 +346,10 @@ struct CAPACITY_RESERVATION // Vector size is number of reserves up or down struct AREA_RESERVES_VECTOR { + float maxGlobalEnergyActivationRatioUp = 1.; + float maxGlobalEnergyActivationRatioDown = 1.; + int maxGlobalActivationDurationUp = 0; + int maxGlobalActivationDurationDown = 0; std::vector areaCapacityReservationsUp; std::vector areaCapacityReservationsDown; }; diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index e6bc2f4203..93e745697f 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -269,9 +269,16 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, .NumeroDeContrainteDesContraintesSTStorageClusterPumpingCapacityThreasholds.assign( study.runtime.shortTermStorageCount, -1); problem.CorrespondanceCntNativesCntOptim[k] - .NumeroDeContrainteDesContraintesSTStockLevelReserveParticipationDown.assign(study.runtime.longTermStorageCount, -1); + .NumeroDeContrainteDesContraintesSTStockLevelReserveParticipationDown.assign(study.runtime.shortTermStorageCount, -1); problem.CorrespondanceCntNativesCntOptim[k] - .NumeroDeContrainteDesContraintesSTStockLevelReserveParticipationUp.assign(study.runtime.longTermStorageCount, -1); + .NumeroDeContrainteDesContraintesSTStockLevelReserveParticipationUp.assign(study.runtime.shortTermStorageCount, -1); + problem.CorrespondanceCntNativesCntOptim[k] + .NumeroDeContrainteDesContraintesSTStockEnergyLevelReserveParticipation.assign(study.runtime.shortTermStorageCount * study.runtime.capacityReservationCount, -1); + problem.CorrespondanceCntNativesCntOptim[k] + .NumeroDeContrainteDesContraintesSTGlobalStockEnergyLevelReserveParticipationUp.assign(study.runtime.shortTermStorageCount, -1); + problem.CorrespondanceCntNativesCntOptim[k] + .NumeroDeContrainteDesContraintesSTGlobalStockEnergyLevelReserveParticipationDown.assign(study.runtime.shortTermStorageCount, -1); + problem.CorrespondanceCntNativesCntOptim[k] .NumeroDeContrainteDesContraintesLTStorageClusterMaxWithdrawParticipation.assign( diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index fb5837f456..598ca73df9 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -43,6 +43,11 @@ static void importCapacityReservations(AreaList& areas, PROBLEME_HEBDO& problem) auto area = areas[areaIndex]; auto& areaReserves = problem.allReserves[areaIndex]; + areaReserves.maxGlobalActivationDurationDown = area->allCapacityReservations.maxGlobalActivationDurationDown; + areaReserves.maxGlobalActivationDurationUp = area->allCapacityReservations.maxGlobalActivationDurationUp; + areaReserves.maxGlobalEnergyActivationRatioDown = area->allCapacityReservations.maxGlobalEnergyActivationRatioDown; + areaReserves.maxGlobalEnergyActivationRatioUp = area->allCapacityReservations.maxGlobalEnergyActivationRatioUp; + for (auto const& [reserveName, reserveCapacity] : area->allCapacityReservations.areaCapacityReservationsUp) { @@ -50,6 +55,7 @@ static void importCapacityReservations(AreaList& areas, PROBLEME_HEBDO& problem) areaCapacityReservationsUp.failureCost = reserveCapacity.failureCost; areaCapacityReservationsUp.spillageCost = reserveCapacity.spillageCost; areaCapacityReservationsUp.maxActivationRatio = reserveCapacity.maxActivationRatio; + areaCapacityReservationsUp.maxEnergyActivationRatio = reserveCapacity.maxEnergyActivationRatio; areaCapacityReservationsUp.maxActivationDuration = reserveCapacity.maxActivationHours; areaCapacityReservationsUp.reserveName = reserveName; areaCapacityReservationsUp.globalReserveIndex = globalReserveIndex; @@ -76,6 +82,7 @@ static void importCapacityReservations(AreaList& areas, PROBLEME_HEBDO& problem) areaCapacityReservationsDown.spillageCost = reserveCapacity.spillageCost; areaCapacityReservationsDown.maxActivationRatio = reserveCapacity.maxActivationRatio; areaCapacityReservationsDown.maxActivationDuration = reserveCapacity.maxActivationHours; + areaCapacityReservationsDown.maxEnergyActivationRatio = reserveCapacity.maxEnergyActivationRatio; areaCapacityReservationsDown.reserveName = reserveName; areaCapacityReservationsDown.globalReserveIndex = globalReserveIndex; areaCapacityReservationsDown.areaReserveIndex = areaReserveIndex;