From a64625a3befc9f57ea40c52ae422c817d8bb8506 Mon Sep 17 00:00:00 2001 From: CAMUS Benjamin Date: Tue, 5 Dec 2023 17:17:00 +0100 Subject: [PATCH 01/22] core implementation of the ramping model --- .../antares/study/parts/thermal/cluster.cpp | 35 +++++++ .../antares/study/parts/thermal/cluster.h | 10 ++ src/solver/optimisation/CMakeLists.txt | 12 ++- .../constraints/ConstraintBuilder.cpp | 19 ++++ .../constraints/ConstraintBuilder.h | 20 ++++ .../constraints/PowerOutputVariation.cpp | 47 +++++++++ .../constraints/PowerOutputVariation.h | 20 ++++ .../constraints/RampingDecreaseRate.cpp | 48 ++++++++++ .../constraints/RampingDecreaseRate.h | 20 ++++ .../constraints/RampingIncreaseRate.cpp | 47 +++++++++ .../constraints/RampingIncreaseRate.h | 21 ++++ .../opt_alloc_probleme_a_optimiser.cpp | 1 + .../opt_construction_contraintes_rampes.h | 4 + ...truction_contraintes_rampes_thermiques.cpp | 42 ++++++++ ...n_matrice_des_contraintes_cas_lineaire.cpp | 11 ++- ...truction_variables_optimisees_lineaire.cpp | 7 +- ...nstruction_variables_rampes_thermiques.cpp | 50 ++++++++++ ...construction_variables_rampes_thermiques.h | 0 .../opt_decompte_variables_et_contraintes.cpp | 5 +- ...ables_et_contraintes_rampes_thermiques.cpp | 37 ++++++++ src/solver/optimisation/opt_fonctions.h | 9 ++ .../opt_gestion_des_bornes_cas_lineaire.cpp | 4 +- ...t_gestion_des_bornes_rampes_thermiques.cpp | 67 +++++++++++++ .../opt_gestion_des_couts_cas_lineaire.cpp | 4 +- ...pt_gestion_des_couts_rampes_thermiques.cpp | 72 ++++++++++++++ ...estion_second_membre_rampes_thermiques.cpp | 95 +++++++++++++++++++ .../optimisation/opt_rename_problem.cpp | 29 ++++++ src/solver/optimisation/opt_rename_problem.h | 5 + .../simulation/sim_alloc_probleme_hebdo.cpp | 10 ++ .../simulation/sim_calcul_economique.cpp | 8 ++ .../sim_structure_probleme_economique.h | 18 +++- 31 files changed, 762 insertions(+), 15 deletions(-) create mode 100644 src/solver/optimisation/constraints/PowerOutputVariation.cpp create mode 100644 src/solver/optimisation/constraints/PowerOutputVariation.h create mode 100644 src/solver/optimisation/constraints/RampingDecreaseRate.cpp create mode 100644 src/solver/optimisation/constraints/RampingDecreaseRate.h create mode 100644 src/solver/optimisation/constraints/RampingIncreaseRate.cpp create mode 100644 src/solver/optimisation/constraints/RampingIncreaseRate.h create mode 100644 src/solver/optimisation/opt_construction_contraintes_rampes.h create mode 100644 src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp create mode 100644 src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp create mode 100644 src/solver/optimisation/opt_construction_variables_rampes_thermiques.h create mode 100644 src/solver/optimisation/opt_decompte_variables_et_contraintes_rampes_thermiques.cpp create mode 100644 src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp create mode 100644 src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp create mode 100644 src/solver/optimisation/opt_gestion_second_membre_rampes_thermiques.cpp diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index a6c8c49d6d..1b6ebcbfaa 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -479,6 +479,11 @@ void Data::ThermalCluster::reset() marketBidCost = 0.; variableomcost = 0.; costsTimeSeries.resize(1, CostsTimeSeries()); + powerIncreaseCost = 0; + powerDecreaseCost = 0; + + maxUpwardPowerRampingRate = 0; + maxDownwardPowerRampingRate = 0; // modulation modulation.resize(thermalModulationMax, HOURS_PER_YEAR); @@ -608,6 +613,36 @@ bool Data::ThermalCluster::integrityCheck() ret = false; }*/ + // ramping + if (maxUpwardPowerRampingRate <= 0) + { + logs.error() << "Thermal cluster: " << parentArea->name << '/' << pName + << ": The maximum upward power ramping rate must greater than zero."; + maxUpwardPowerRampingRate = 1.; + ret = false; + } + if (maxDownwardPowerRampingRate <= 0) + { + logs.error() << "Thermal cluster: " << parentArea->name << '/' << pName + << ": The maximum downward power ramping rate must greater than zero."; + maxDownwardPowerRampingRate = 1.; + ret = false; + } + if (powerIncreaseCost < 0) + { + logs.error() << "Thermal cluster: " << parentArea->name << '/' << pName + << ": The ramping power increase cost must be positive or null."; + powerIncreaseCost = 0.; + ret = false; + } + if (powerDecreaseCost < 0) + { + logs.error() << "Thermal cluster: " << parentArea->name << '/' << pName + << ": The ramping power decrease cost must be positive or null."; + powerDecreaseCost = 0.; + ret = false; + } + return ret; } diff --git a/src/libs/antares/study/parts/thermal/cluster.h b/src/libs/antares/study/parts/thermal/cluster.h index a75ce10a00..a9a9705363 100644 --- a/src/libs/antares/study/parts/thermal/cluster.h +++ b/src/libs/antares/study/parts/thermal/cluster.h @@ -340,6 +340,16 @@ class ThermalCluster final : public Cluster, public std::enable_shared_from_this double marketBidCost = 0; //! Variable O&M cost (euros/MWh) double variableomcost = 0; + //! Cost of power increase (euros/MW) + double powerIncreaseCost = 0; + //! Cost of power decrease (euros/MW) + double powerDecreaseCost = 0; + + //! Maximum hourly upward power ramping rate (MW/hour) + double maxUpwardPowerRampingRate = 0; + //! Maximum hourly downward power ramping rate (MW/hour) + double maxDownwardPowerRampingRate = 0; + //@} /*! diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index 4d23d3ef89..5531f67b80 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -38,6 +38,11 @@ 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_contraintes_rampes_thermiques.cpp + opt_decompte_variables_et_contraintes_rampes_thermiques.cpp + opt_construction_variables_rampes_thermiques.cpp + opt_gestion_des_bornes_rampes_thermiques.cpp + opt_gestion_des_couts_rampes_thermiques.cpp opt_export_structure.h opt_export_structure.cpp base_weekly_optimization.h @@ -119,7 +124,12 @@ set(RTESOLVER_OPT constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp constraints/MinDownTime.h constraints/MinDownTime.cpp - + constraints/RampingIncreaseRate.h + constraints/RampingIncreaseRate.cpp + constraints/RampingDecreaseRate.h + constraints/RampingDecreaseRate.cpp + constraints/PowerOutputVariation.h + constraints/PowerOutputVariation.cpp ) diff --git a/src/solver/optimisation/constraints/ConstraintBuilder.cpp b/src/solver/optimisation/constraints/ConstraintBuilder.cpp index 195d8dad30..72a80f0117 100644 --- a/src/solver/optimisation/constraints/ConstraintBuilder.cpp +++ b/src/solver/optimisation/constraints/ConstraintBuilder.cpp @@ -58,6 +58,25 @@ ConstraintBuilder& ConstraintBuilder::DispatchableProduction(unsigned int index, int delta) { AddVariable(GetVariableManager(offset, delta).DispatchableProduction(index), coeff); + // logs.info() << "dispatchable production idx " << GetVariableManager(offset, delta).DispatchableProduction(index); + return *this; +} + +ConstraintBuilder& ConstraintBuilder::ProductionDecreaseAboveMin(unsigned int index, + double coeff, + int offset, + int delta) +{ + AddVariable(GetVariableManager(offset, delta).ProductionDecreaseAboveMin(index), coeff); + return *this; +} + +ConstraintBuilder& ConstraintBuilder::ProductionIncreaseAboveMin(unsigned int index, + double coeff, + int offset, + int delta) +{ + AddVariable(GetVariableManager(offset, delta).ProductionIncreaseAboveMin(index), coeff); return *this; } diff --git a/src/solver/optimisation/constraints/ConstraintBuilder.h b/src/solver/optimisation/constraints/ConstraintBuilder.h index 0ef7bf5675..be7d206b24 100644 --- a/src/solver/optimisation/constraints/ConstraintBuilder.h +++ b/src/solver/optimisation/constraints/ConstraintBuilder.h @@ -31,6 +31,16 @@ class VariableManager return nativeOptimVar.NumeroDeVariableDuPalierThermique[index]; } + int ProductionIncreaseAboveMin(unsigned int index) const + { + return nativeOptimVar.powerRampingIncreaseIndex[index]; + } + + int ProductionDecreaseAboveMin(unsigned int index) const + { + return nativeOptimVar.powerRampingDecreaseIndex[index]; + } + int NumberOfDispatchableUnits(unsigned int index) const { return nativeOptimVar.NumeroDeVariableDuNombreDeGroupesEnMarcheDuPalierThermique[index]; @@ -183,6 +193,16 @@ class ConstraintBuilder int offset = 0, int delta = 0); + ConstraintBuilder& ProductionDecreaseAboveMin(unsigned int index, + double coeff, + int offset = 0, + int delta = 0); + + ConstraintBuilder& ProductionIncreaseAboveMin(unsigned int index, + double coeff, + int offset = 0, + int delta = 0); + ConstraintBuilder& NumberOfDispatchableUnits(unsigned int index, double coeff, int offset = 0, diff --git a/src/solver/optimisation/constraints/PowerOutputVariation.cpp b/src/solver/optimisation/constraints/PowerOutputVariation.cpp new file mode 100644 index 0000000000..d24196c387 --- /dev/null +++ b/src/solver/optimisation/constraints/PowerOutputVariation.cpp @@ -0,0 +1,47 @@ +#include "PowerOutputVariation.h" + +void PowerOutputVariation::add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation) +{ + if (!Simulation) + { + const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; + double maxUpwardPowerRampingRate = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[clusterIndex]; + double pminDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.pminDUnGroupeDuPalierThermique[clusterIndex]; + // constraint : P(t) - P(t-1) - l * M^+(t) - P^+ + P^- = 0 + if (pdt > 0) + { + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1.0) + .DispatchableProduction(cluster, -1.0, -1, problemeHebdo->NombreDePasDeTempsPourUneOptimisation) + .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) + .ProductionIncreaseAboveMin(cluster, -1.0) + .ProductionDecreaseAboveMin(cluster, 1.0) + .equalTo(); + } + else + { + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1.0) + .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) + .ProductionIncreaseAboveMin(cluster, -1.0) + .ProductionDecreaseAboveMin(cluster, 1.0) + .equalTo(); + } + if (builder.NumberOfVariables() > 0) + { + ConstraintNamer namer(problemeHebdo->ProblemeAResoudre->NomDesContraintes); + + namer.UpdateTimeStep(problemeHebdo->weekInTheYear * 168 + pdt); + namer.UpdateArea(problemeHebdo->NomsDesPays[pays]); + + namer.ProductionOutputVariation(problemeHebdo->ProblemeAResoudre->NombreDeContraintes, PaliersThermiquesDuPays.NomsDesPaliersThermiques[clusterIndex]); + } + builder.build(); + } + else + { + int add = (pdt == 0) ? 4 : 5; + problemeHebdo->NbTermesContraintesPourLesRampes += add; + problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; + } +} diff --git a/src/solver/optimisation/constraints/PowerOutputVariation.h b/src/solver/optimisation/constraints/PowerOutputVariation.h new file mode 100644 index 0000000000..729a3d4af5 --- /dev/null +++ b/src/solver/optimisation/constraints/PowerOutputVariation.h @@ -0,0 +1,20 @@ +#pragma once +#include "ConstraintBuilder.h" + +/*! + * represent 'RampingIncreaseRate' Constraint type + */ +class PowerOutputVariation : private ConstraintFactory +{ +public: + using ConstraintFactory::ConstraintFactory; + + /*! + * @brief Add variables to the constraint and update constraints Matrix + * @param pays : area + * @param cluster : global index of the cluster + * @param pdt : timestep + * @param Simulation : --- + */ + void add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation); +}; \ No newline at end of file diff --git a/src/solver/optimisation/constraints/RampingDecreaseRate.cpp b/src/solver/optimisation/constraints/RampingDecreaseRate.cpp new file mode 100644 index 0000000000..5cdb3f5d76 --- /dev/null +++ b/src/solver/optimisation/constraints/RampingDecreaseRate.cpp @@ -0,0 +1,48 @@ +#include "RampingDecreaseRate.h" + +void RampingDecreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation) +{ + if (!Simulation) + { + const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; + double maxDownwardPowerRampingRate = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[clusterIndex]; + double pmaxDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.PmaxDUnGroupeDuPalierThermique[clusterIndex]; + // constraint : P(t) - P(t-1) + R^- * M(t) + u * M^-(t) + u * M^--(t) > 0 + if (pdt > 0) + { + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1.0) + .DispatchableProduction(cluster, -1.0, -1, problemeHebdo->NombreDePasDeTempsPourUneOptimisation) + .NumberOfDispatchableUnits(cluster, maxDownwardPowerRampingRate) + .NumberStoppingDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) + .NumberBreakingDownDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) + .greaterThan(); + } + else + { + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1.0) + .NumberOfDispatchableUnits(cluster, maxDownwardPowerRampingRate) + .NumberStoppingDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) + .NumberBreakingDownDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) + .greaterThan(); + } + if (builder.NumberOfVariables() > 0) + { + ConstraintNamer namer(problemeHebdo->ProblemeAResoudre->NomDesContraintes); + + namer.UpdateTimeStep(problemeHebdo->weekInTheYear * 168 + pdt); + namer.UpdateArea(problemeHebdo->NomsDesPays[pays]); + + namer.RampingDecreaseRate(problemeHebdo->ProblemeAResoudre->NombreDeContraintes, + PaliersThermiquesDuPays.NomsDesPaliersThermiques[clusterIndex]); + } + builder.build(); + } + else + { + int add = (pdt == 0) ? 4 : 5; + problemeHebdo->NbTermesContraintesPourLesRampes += add; + problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; + } +} diff --git a/src/solver/optimisation/constraints/RampingDecreaseRate.h b/src/solver/optimisation/constraints/RampingDecreaseRate.h new file mode 100644 index 0000000000..939ad767ba --- /dev/null +++ b/src/solver/optimisation/constraints/RampingDecreaseRate.h @@ -0,0 +1,20 @@ +#pragma once +#include "ConstraintBuilder.h" + +/*! + * represent 'RampingIncreaseRate' Constraint type + */ +class RampingDecreaseRate : private ConstraintFactory +{ +public: + using ConstraintFactory::ConstraintFactory; + + /*! + * @brief Add variables to the constraint and update constraints Matrix + * @param pays : area + * @param cluster : global index of the cluster + * @param pdt : timestep + * @param Simulation : --- + */ + void add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation); +}; \ No newline at end of file diff --git a/src/solver/optimisation/constraints/RampingIncreaseRate.cpp b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp new file mode 100644 index 0000000000..508e2939d1 --- /dev/null +++ b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp @@ -0,0 +1,47 @@ +#include "RampingIncreaseRate.h" + +void RampingIncreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation) +{ + if (!Simulation) + { + const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; + double maxUpwardPowerRampingRate = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[clusterIndex]; + double pminDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.pminDUnGroupeDuPalierThermique[clusterIndex]; + // constraint : P(t) - P(t-1) - R^+ * M(t) - l * M^+(t) < 0 + // logs.info() << "add up ramping constraint for cluster " << cluster << " pdt " << pdt; + + if (pdt > 0) + { + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1.0) + .DispatchableProduction( + cluster, -1.0, -1, problemeHebdo->NombreDePasDeTempsPourUneOptimisation) + .NumberOfDispatchableUnits(cluster, -maxUpwardPowerRampingRate) + .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) + .lessThan(); + } + else + { + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1.0) + .NumberOfDispatchableUnits(cluster, -maxUpwardPowerRampingRate) + .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) + .lessThan(); + } + if (builder.NumberOfVariables() > 0) + { + ConstraintNamer namer(problemeHebdo->ProblemeAResoudre->NomDesContraintes); + namer.UpdateTimeStep(problemeHebdo->weekInTheYear * 168 + pdt); + namer.UpdateArea(problemeHebdo->NomsDesPays[pays]); + namer.RampingIncreaseRate(problemeHebdo->ProblemeAResoudre->NombreDeContraintes, + PaliersThermiquesDuPays.NomsDesPaliersThermiques[clusterIndex]); + } + builder.build(); + } + else + { + int add = (pdt == 0) ? 3 : 4; + problemeHebdo->NbTermesContraintesPourLesRampes += add; + problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; + } +} diff --git a/src/solver/optimisation/constraints/RampingIncreaseRate.h b/src/solver/optimisation/constraints/RampingIncreaseRate.h new file mode 100644 index 0000000000..c924b58180 --- /dev/null +++ b/src/solver/optimisation/constraints/RampingIncreaseRate.h @@ -0,0 +1,21 @@ +#pragma once +#include "ConstraintBuilder.h" + +/*! + * represent 'RampingIncreaseRate' Constraint type + */ +class RampingIncreaseRate : private ConstraintFactory +{ +public: + using ConstraintFactory::ConstraintFactory; + + /*! + * @brief Add variables to the constraint and update constraints Matrix + * @param pays : area + * @param cluster : global index of the cluster + * @param pdt : timestep + * @param Simulation : --- + */ + void add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation); +}; + diff --git a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp index 809ea0f5d5..4c8e3f6521 100644 --- a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp +++ b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp @@ -133,6 +133,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->NbTermesContraintesPourLesRampes; logs.info(); logs.info() diff --git a/src/solver/optimisation/opt_construction_contraintes_rampes.h b/src/solver/optimisation/opt_construction_contraintes_rampes.h new file mode 100644 index 0000000000..566bdf27ac --- /dev/null +++ b/src/solver/optimisation/opt_construction_contraintes_rampes.h @@ -0,0 +1,4 @@ +#pragma once +class opt_construction_contraintes_rampes +{ +}; diff --git a/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp b/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp new file mode 100644 index 0000000000..a009f06f74 --- /dev/null +++ b/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp @@ -0,0 +1,42 @@ +#include "opt_structure_probleme_a_resoudre.h" + +#include "../simulation/sim_structure_donnees.h" +#include "../simulation/sim_structure_probleme_economique.h" + +#include "opt_fonctions.h" +#include "opt_rename_problem.h" +#include "constraints/RampingDecreaseRate.h" +#include "constraints/RampingIncreaseRate.h" +#include "constraints/PowerOutputVariation.h" + +#include + +void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO* problemeHebdo, bool Simulation) +{ + int nombreDePasDeTempsPourUneOptimisation = problemeHebdo->NombreDePasDeTempsPourUneOptimisation; + const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; + + ConstraintNamer constraintNamer(ProblemeAResoudre->NomDesContraintes); + + for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) + { + const PALIERS_THERMIQUES& PaliersThermiquesDuPays + = problemeHebdo->PaliersThermiquesDuPays[pays]; + constraintNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); + for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) + { + RampingIncreaseRate rampingIncreaseRate(problemeHebdo); + RampingDecreaseRate rampingDecreaseRate(problemeHebdo); + PowerOutputVariation powerOutputVariation(problemeHebdo); + + const int palier = PaliersThermiquesDuPays.NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; + + for (int pdt = 0; pdt < nombreDePasDeTempsPourUneOptimisation; pdt++) + { + rampingIncreaseRate.add(pays, palier, index, pdt, Simulation); + rampingDecreaseRate.add(pays, palier, index, pdt, Simulation); + powerOutputVariation.add(pays, palier, index, pdt, Simulation); + } + } + } +} \ No newline at end of file diff --git a/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp b/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp index 3dd43259a4..54f05cc6d2 100644 --- a/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp @@ -47,6 +47,9 @@ #include "constraints/AreaHydroLevel.h" #include "constraints/FinalStockEquivalent.h" #include "constraints/FinalStockExpression.h" +#include "constraints/RampingDecreaseRate.h" +#include "constraints/RampingIncreaseRate.h" +#include "constraints/PowerOutputVariation.h" #include @@ -188,10 +191,14 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaire(PROBLEME_HEBDO* pro finalStockExpression.add(pays); } + logs.info() << "adding ramping constraints"; + + + if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) { - OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireCoutsDeDemarrage(problemeHebdo, - false); + OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireCoutsDeDemarrage(problemeHebdo,false); + OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireRampesThermiques(problemeHebdo,false); } // Export structure diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp index c33a5300b8..de4d09e06d 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp @@ -90,8 +90,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaire(PROBLEME_HEBD const auto& clusterName = PaliersThermiquesDuPays.NomsDesPaliersThermiques[index]; CorrespondanceVarNativesVarOptim.NumeroDeVariableDuPalierThermique[palier] = NombreDeVariables; - ProblemeAResoudre->TypeDeVariable[NombreDeVariables] - = VARIABLE_BORNEE_DES_DEUX_COTES; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.DispatchableProduction(NombreDeVariables, clusterName); NombreDeVariables++; } @@ -265,8 +264,8 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaire(PROBLEME_HEBD if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) { - OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarrage(problemeHebdo, - false); + OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarrage(problemeHebdo, false); + OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireRampesThermiques(problemeHebdo, false); } return; diff --git a/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp new file mode 100644 index 0000000000..b720e22a45 --- /dev/null +++ b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp @@ -0,0 +1,50 @@ +#include "opt_structure_probleme_a_resoudre.h" + +#include "../simulation/sim_extern_variables_globales.h" + +#include "opt_fonctions.h" +#include "opt_rename_problem.h" + +#include "spx_constantes_externes.h" + +void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireRampesThermiques(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++) + { + const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; + variableNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); + for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) + { + const int palier = PaliersThermiquesDuPays.NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; + const auto& clusterName = PaliersThermiquesDuPays.NomsDesPaliersThermiques[index]; + + if (!Simulation) + { + CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier] = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.ProductionIncreaseAboveMin(NombreDeVariables, clusterName); + } + NombreDeVariables++; + + if (!Simulation) + { + CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier] = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.ProductionDecreaseAboveMin(NombreDeVariables, clusterName); + } + NombreDeVariables++; + } + } + } +} diff --git a/src/solver/optimisation/opt_construction_variables_rampes_thermiques.h b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp index 17738e7b1d..e4adbdbc88 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp @@ -50,9 +50,7 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) { - ProblemeAResoudre->NombreDeVariables - += problemeHebdo->PaliersThermiquesDuPays[pays].NombreDePaliersThermiques; - + ProblemeAResoudre->NombreDeVariables += problemeHebdo->PaliersThermiquesDuPays[pays].NombreDePaliersThermiques; mxPaliers += problemeHebdo->PaliersThermiquesDuPays[pays].NombreDePaliersThermiques; if (problemeHebdo->CaracteristiquesHydrauliques[pays].PresenceDHydrauliqueModulable) @@ -260,6 +258,7 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) { OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(problemeHebdo); + OPT_DecompteDesVariablesEtDesContraintesRampesThermiques(problemeHebdo); } return mxPaliers; diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes_rampes_thermiques.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes_rampes_thermiques.cpp new file mode 100644 index 0000000000..26e9f78124 --- /dev/null +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes_rampes_thermiques.cpp @@ -0,0 +1,37 @@ +/* +** Copyright 2007-2023 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include "../simulation/simulation.h" +#include "../simulation/sim_extern_variables_globales.h" + +#include "opt_fonctions.h" + +void OPT_DecompteDesVariablesEtDesContraintesRampesThermiques(PROBLEME_HEBDO* problemeHebdo) +{ + OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireRampesThermiques(problemeHebdo, true); + OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireRampesThermiques(problemeHebdo, true); +} \ No newline at end of file diff --git a/src/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/opt_fonctions.h index e2807f0c8d..5af67e58fb 100644 --- a/src/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/opt_fonctions.h @@ -129,6 +129,15 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HE void OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(PROBLEME_HEBDO*); void OPT_InitialiserNombreMinEtMaxDeGroupesCoutsDeDemarrage(PROBLEME_HEBDO*); void OPT_AjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO*); + +void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO*, bool); +void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO*, bool); +void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO*, const int, const int); +void OPT_DecompteDesVariablesEtDesContraintesRampesThermiques(PROBLEME_HEBDO*); +void OPT_InitialiserLesCoutsLineaireRampesThermiques(PROBLEME_HEBDO*, const int, const int); +void OPT_InitialiserLeSecondMembreDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO*, int, int); + + double OPT_SommeDesPminThermiques(const PROBLEME_HEBDO*, int, uint); #endif /* __SOLVER_OPTIMISATION_FUNCTIONS_H__ */ 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 b45190106c..9631e2d8b7 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp @@ -504,8 +504,8 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) { - OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireCoutsDeDemarrage( - problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); + OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireCoutsDeDemarrage(problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); + OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques(problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); } return; diff --git a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp new file mode 100644 index 0000000000..a62b30a307 --- /dev/null +++ b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp @@ -0,0 +1,67 @@ +/* +** Copyright 2007-2023 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include "opt_structure_probleme_a_resoudre.h" + +#include "../simulation/simulation.h" +#include "../simulation/sim_structure_donnees.h" +#include "../simulation/sim_structure_probleme_economique.h" +#include "opt_fonctions.h" + +using namespace Yuni; + +void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques(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]; + int maxThermalPlant = PaliersThermiquesDuPays.NombreDePaliersThermiques; + + for (int index = 0; index < maxThermalPlant; index++) + { + const int palier = PaliersThermiquesDuPays.NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; + + int var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; + Xmin[var] = 0; + Xmax[var] = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[index] * PaliersThermiquesDuPays.NombreDePaliersThermiques; + + var = CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier]; + Xmin[var] = 0; + Xmax[var] = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] * PaliersThermiquesDuPays.NombreDePaliersThermiques; + } + } + } +} \ No newline at end of file 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 189a27662a..b1626d69dc 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp @@ -339,8 +339,8 @@ void OPT_InitialiserLesCoutsLineaire(PROBLEME_HEBDO* problemeHebdo, if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) { - OPT_InitialiserLesCoutsLineaireCoutsDeDemarrage( - problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); + OPT_InitialiserLesCoutsLineaireCoutsDeDemarrage(problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); + OPT_InitialiserLesCoutsLineaireRampesThermiques(problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); } return; diff --git a/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp new file mode 100644 index 0000000000..1270b99616 --- /dev/null +++ b/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp @@ -0,0 +1,72 @@ +/* +** Copyright 2007-2023 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include +#include "opt_structure_probleme_a_resoudre.h" + +#include "../simulation/simulation.h" +#include "../simulation/sim_structure_donnees.h" +#include "../simulation/sim_extern_variables_globales.h" + +#include "opt_fonctions.h" + +void OPT_InitialiserLesCoutsLineaireRampesThermiques(PROBLEME_HEBDO* problemeHebdo, + const int PremierPdtDeLIntervalle, + const int DernierPdtDeLIntervalle) +{ + const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; + + int pdtJour = 0; + + 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]; + int var; + + for (int Index = 0; Index < PaliersThermiquesDuPays.NombreDePaliersThermiques; Index++) + { + int palier = PaliersThermiquesDuPays.NumeroDuPalierDansLEnsembleDesPaliersThermiques[Index]; + + var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; + if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) + { + ProblemeAResoudre->CoutLineaire[var] = PaliersThermiquesDuPays.downwardRampingCost[Index]; + } + + var = CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier]; + if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) + { + ProblemeAResoudre->CoutLineaire[var] = PaliersThermiquesDuPays.upwardRampingCost[Index]; + } + } + } + } +} \ No newline at end of file diff --git a/src/solver/optimisation/opt_gestion_second_membre_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_second_membre_rampes_thermiques.cpp new file mode 100644 index 0000000000..e245b4cb3c --- /dev/null +++ b/src/solver/optimisation/opt_gestion_second_membre_rampes_thermiques.cpp @@ -0,0 +1,95 @@ +/* +** Copyright 2007-2023 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include "opt_structure_probleme_a_resoudre.h" + +#include "../simulation/sim_structure_donnees.h" +#include "../simulation/sim_extern_variables_globales.h" + +#include "opt_fonctions.h" + +#include + +using namespace Antares; +using namespace Antares::Data; +using namespace Yuni; + +void OPT_InitialiserLeSecondMembreDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO* problemeHebdo, + int PremierPdtDeLIntervalle, + int DernierPdtDeLIntervalle) +{ + logs.info() << "PremierPdtDeLIntervalle= " << PremierPdtDeLIntervalle; + + if (PremierPdtDeLIntervalle > 0) + { + const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; + std::vector& SecondMembre = ProblemeAResoudre->SecondMembre; + + int NombreDePasDeTempsPourUneOptimisation + = problemeHebdo->NombreDePasDeTempsPourUneOptimisation; + + for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) + { + const PALIERS_THERMIQUES& PaliersThermiquesDuPays + = problemeHebdo->PaliersThermiquesDuPays[pays]; + + for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) + { + const int palier + = PaliersThermiquesDuPays.NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; + + const CORRESPONDANCES_DES_CONTRAINTES& CorrespondanceCntNativesCntOptim + = problemeHebdo->CorrespondanceCntNativesCntOptim[0]; + int cnt = CorrespondanceCntNativesCntOptim.ConstraintIndexRampingIncrease[palier]; + if (cnt >= 0) + { + SecondMembre[cnt] = problemeHebdo->ResultatsHoraires[pays] + .ProductionThermique[PremierPdtDeLIntervalle - 1] + .ProductionThermiqueDuPalier[index]; + logs.info() << "second membre = " << SecondMembre[cnt]; + } + + cnt = CorrespondanceCntNativesCntOptim.ConstraintIndexRampingIncrease[palier]; + if (cnt >= 0) + { + SecondMembre[cnt] = problemeHebdo->ResultatsHoraires[pays] + .ProductionThermique[PremierPdtDeLIntervalle - 1] + .ProductionThermiqueDuPalier[index]; + } + + cnt = CorrespondanceCntNativesCntOptim.ConstraintIndexRampingIncrease[palier]; + if (cnt >= 0) + { + SecondMembre[cnt] = problemeHebdo->ResultatsHoraires[pays] + .ProductionThermique[PremierPdtDeLIntervalle - 1] + .ProductionThermiqueDuPalier[index]; + } + } + } + } + +} \ No newline at end of file diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index 0d90030460..b7ea8995b0 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -73,6 +73,18 @@ void VariableNamer::DispatchableProduction(unsigned int variable, const std::str SetThermalClusterElementName(variable, "DispatchableProduction", clusterName); } +void VariableNamer::ProductionIncreaseAboveMin(unsigned int variable, const std::string& clusterName) +{ + SetThermalClusterElementName(variable, "ProductionIncreaseAboveMin", clusterName); +} + +void VariableNamer::ProductionDecreaseAboveMin(unsigned int variable, + const std::string& clusterName) +{ + SetThermalClusterElementName(variable, "ProductionDecreaseAboveMin", clusterName); +} + + void VariableNamer::NODU(unsigned int variable, const std::string& clusterName) { SetThermalClusterElementName(variable, "NODU", clusterName); @@ -313,6 +325,23 @@ void ConstraintNamer::PMinDispatchableGeneration(unsigned int constraint, SetThermalClusterElementName(constraint, "PMinDispatchableGeneration", clusterName); } +void ConstraintNamer::RampingIncreaseRate(unsigned int constraint, + const std::string& clusterName) +{ + SetThermalClusterElementName(constraint, "RampingIncreaseRate", clusterName); +} + +void ConstraintNamer::RampingDecreaseRate(unsigned int constraint, const std::string& clusterName) +{ + SetThermalClusterElementName(constraint, "RampingDecreaseRate", clusterName); +} + +void ConstraintNamer::ProductionOutputVariation(unsigned int constraint, + const std::string& clusterName) +{ + SetThermalClusterElementName(constraint, "ProductionOutputVariation", clusterName); +} + void ConstraintNamer::ConsistenceNODU(unsigned int constraint, const std::string& clusterName) { SetThermalClusterElementName(constraint, "ConsistenceNODU", clusterName); diff --git a/src/solver/optimisation/opt_rename_problem.h b/src/solver/optimisation/opt_rename_problem.h index 50c0ac8778..4f4d9cd1f5 100644 --- a/src/solver/optimisation/opt_rename_problem.h +++ b/src/solver/optimisation/opt_rename_problem.h @@ -59,6 +59,8 @@ class VariableNamer : public Namer public: using Namer::Namer; void DispatchableProduction(unsigned int variable, const std::string& clusterName); + void ProductionIncreaseAboveMin(unsigned int variable, const std::string& clusterName); + void ProductionDecreaseAboveMin(unsigned int variable, const std::string& clusterName); 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); @@ -120,6 +122,9 @@ class ConstraintNamer : public Namer void NbDispUnitsMinBoundSinceMinUpTime(unsigned int constraint, const std::string& clusterName); void MinDownTime(unsigned int constraint, const std::string& clusterName); void PMaxDispatchableGeneration(unsigned int constraint, const std::string& clusterName); + void RampingIncreaseRate(unsigned int constraint, const std::string& clusterName); + void RampingDecreaseRate(unsigned int constraint, const std::string& clusterName); + void ProductionOutputVariation(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); void ShortTermStorageLevel(unsigned int constraint, const std::string& name); diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index c4da3fbc36..f0f588b86c 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -185,6 +185,10 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, variablesMapping.NumeroDeVariableDuPalierThermique .assign(study.runtime->thermalPlantTotalCount, 0); + variablesMapping.powerRampingIncreaseIndex + .assign(study.runtime->thermalPlantTotalCount, 0); + variablesMapping.powerRampingDecreaseIndex + .assign(study.runtime->thermalPlantTotalCount, 0); variablesMapping.NumeroDeVariablesDeLaProdHyd .assign(nbPays, 0); variablesMapping.NumeroDeVariablesDePompage @@ -380,6 +384,12 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, .assign(nbPaliers, 0); problem.PaliersThermiquesDuPays[k].NomsDesPaliersThermiques.resize(nbPaliers); + problem.PaliersThermiquesDuPays[k].downwardRampingCost.assign( + nbPaliers, 0); + problem.PaliersThermiquesDuPays[k].upwardRampingCost.assign(nbPaliers, 0); + problem.PaliersThermiquesDuPays[k].maxUpwardPowerRampingRate.assign(nbPaliers, 0); + problem.PaliersThermiquesDuPays[k].maxDownwardPowerRampingRate.assign(nbPaliers, 0); + problem.CaracteristiquesHydrauliques[k].CntEnergieH2OParIntervalleOptimise .assign(7, 0.); problem.CaracteristiquesHydrauliques[k].CntEnergieH2OParJour diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index c9a64ab22d..d545917625 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -301,6 +301,14 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, pbPalier.DureeMinimaleDArretDUnGroupeDuPalierThermique[clusterIndex] = cluster.minDownTime; + pbPalier.upwardRampingCost[clusterIndex] + = cluster.powerIncreaseCost; + pbPalier.downwardRampingCost[clusterIndex] = cluster.powerDecreaseCost; + pbPalier.maxDownwardPowerRampingRate[clusterIndex] = cluster.maxDownwardPowerRampingRate; + pbPalier.maxUpwardPowerRampingRate[clusterIndex] = cluster.maxUpwardPowerRampingRate; + + + pbPalier.PmaxDUnGroupeDuPalierThermique[clusterIndex] = cluster.nominalCapacityWithSpinning; pbPalier.pminDUnGroupeDuPalierThermique[clusterIndex] diff --git a/src/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/sim_structure_probleme_economique.h index e935899904..d640954be4 100644 --- a/src/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/sim_structure_probleme_economique.h @@ -50,6 +50,12 @@ struct CORRESPONDANCES_DES_VARIABLES std::vector NumeroDeVariableCoutExtremiteVersOrigineDeLInterconnexion; std::vector NumeroDeVariableDuPalierThermique; + //! index of the variables for the power output hourly increases (MW above P_min,between t and t+1) + // for the thermal clusters + std::vector powerRampingIncreaseIndex; + //! index of the variables for the power output hourly dereases (MW above P_min,between t and t+1) + // for the thermal clusters + std::vector powerRampingDecreaseIndex; std::vector NumeroDeVariablesDeLaProdHyd; @@ -268,7 +274,7 @@ struct PDISP_ET_COUTS_HORAIRES_PAR_PALIER struct PALIERS_THERMIQUES { - int NombreDePaliersThermiques; + int NombreDePaliersThermiques; std::vector minUpDownTime; @@ -286,6 +292,15 @@ struct PALIERS_THERMIQUES std::vector DureeMinimaleDeMarcheDUnGroupeDuPalierThermique; std::vector DureeMinimaleDArretDUnGroupeDuPalierThermique; std::vector NomsDesPaliersThermiques; + + //! maximum hourly upward power ramping rate for a thermal unit (MW/hour) + std::vector maxUpwardPowerRampingRate; + //! maximum hourly downward power ramping rate for a thermal unit (MW/hour) + std::vector maxDownwardPowerRampingRate; + //! cost of 1 MW power increase for the thermal cluster (above minimum stable level) + std::vector upwardRampingCost; + //! cost of 1 MW power decrease for the thermal cluster + std::vector downwardRampingCost; }; struct ENERGIES_ET_PUISSANCES_HYDRAULIQUES @@ -525,6 +540,7 @@ struct PROBLEME_HEBDO /* Optimization problem */ uint32_t NbTermesContraintesPourLesCoutsDeDemarrage = 0; + uint32_t NbTermesContraintesPourLesRampes = 0; std::vector DefaillanceNegativeUtiliserPMinThermique; std::vector DefaillanceNegativeUtiliserHydro; std::vector DefaillanceNegativeUtiliserConsoAbattue; From b9c4f2b008ca8ea9ee08529c5a9e279a7d191bba Mon Sep 17 00:00:00 2001 From: bencamus Date: Thu, 7 Dec 2023 12:46:25 +0100 Subject: [PATCH 02/22] add export/import features for the thermal ramping attributes --- .../antares/study/parts/thermal/cluster.cpp | 12 +++++++++++- .../study/parts/thermal/cluster_list.cpp | 18 ++++++++++++++++++ .../variable/surveyresults/surveyresults.cpp | 7 ++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index 1b6ebcbfaa..25297fedda 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -137,7 +137,11 @@ Data::ThermalCluster::ThermalCluster(Area* parent) : forcedLaw(thermalLawUniform), plannedLaw(thermalLawUniform), PthetaInf(HOURS_PER_YEAR, 0), - costsTimeSeries(1, CostsTimeSeries()) + costsTimeSeries(1, CostsTimeSeries()), + maxUpwardPowerRampingRate(0.), + maxDownwardPowerRampingRate(0.), + powerIncreaseCost(0.), + powerDecreaseCost(0.) { // assert assert(parent and "A parent for a thermal dispatchable cluster can not be null"); @@ -182,6 +186,12 @@ void Data::ThermalCluster::copyFrom(const ThermalCluster& cluster) minUpTime = cluster.minUpTime; minDownTime = cluster.minDownTime; + // ramping + maxUpwardPowerRampingRate = cluster.maxUpwardPowerRampingRate; + maxDownwardPowerRampingRate = cluster.maxDownwardPowerRampingRate; + powerDecreaseCost = cluster.powerDecreaseCost; + powerIncreaseCost = cluster.powerIncreaseCost; + // spinning spinning = cluster.spinning; diff --git a/src/libs/antares/study/parts/thermal/cluster_list.cpp b/src/libs/antares/study/parts/thermal/cluster_list.cpp index 2cd45cfa14..b5a5385042 100644 --- a/src/libs/antares/study/parts/thermal/cluster_list.cpp +++ b/src/libs/antares/study/parts/thermal/cluster_list.cpp @@ -222,6 +222,15 @@ static bool ThermalClusterLoadFromProperty(ThermalCluster& cluster, const IniFil if (p->key == "startup-cost") return p->value.to(cluster.startupCost); + if (p->key == "power-increase-cost") + return p->value.to(cluster.powerIncreaseCost); + if (p->key == "power-decrease-cost") + return p->value.to(cluster.powerDecreaseCost); + if (p->key == "max-upward-power-ramping-rate") + return p->value.to(cluster.maxUpwardPowerRampingRate); + if (p->key == "max-downward-power-ramping-rate") + return p->value.to(cluster.maxDownwardPowerRampingRate); + if (p->key == "unitcount") return p->value.to(cluster.unitCount); if (p->key == "volatility.planned") @@ -405,6 +414,15 @@ bool ThermalClusterList::saveToFolder(const AnyString& folder) const if (!Math::Zero(c.variableomcost)) s->add("variableomcost", Math::Round(c.variableomcost,3)); + // ramping + if (not Math::Zero(c.powerIncreaseCost)) + s->add("power-increase-cost", Math::Round(c.powerIncreaseCost, 3)); + if (not Math::Zero(c.powerDecreaseCost)) + s->add("power-decrease-cost", Math::Round(c.powerDecreaseCost, 3)); + if (not Math::Zero(c.maxUpwardPowerRampingRate)) + s->add("max-upward-power-ramping-rate", Math::Round(c.maxUpwardPowerRampingRate, 3)); + if (not Math::Zero(c.maxDownwardPowerRampingRate)) + s->add("max-downward-power-ramping-rate", Math::Round(c.maxDownwardPowerRampingRate, 3)); //pollutant factor for (auto const& [key, val] : Pollutant::namesToEnum) diff --git a/src/solver/variable/surveyresults/surveyresults.cpp b/src/solver/variable/surveyresults/surveyresults.cpp index 052e7ab383..2a86dff42b 100644 --- a/src/solver/variable/surveyresults/surveyresults.cpp +++ b/src/solver/variable/surveyresults/surveyresults.cpp @@ -123,7 +123,8 @@ static void ExportGridInfosAreas(const Data::Study& study, outLinks << "upstream\tdownstream\n"; outThermal << "area id\tid\tname\tgroup\tunit count\tnominal capacity\t" "min stable power\tmin up/down time\tspinning\tco2\t" - "marginal cost\tfixed cost\tstartup cost\tmarket bid cost\tspread cost\n"; + "marginal cost\tfixed cost\tstartup cost\tmarket bid cost\tspread cost\t" + "power increase cost`\rpower decrease cost\t max power upward rate\t max power downward rate\n "; study.areas.each([&](const Data::Area& area) { out << area.id << '\t'; @@ -158,6 +159,10 @@ static void ExportGridInfosAreas(const Data::Study& study, outThermal << cluster.startupCost << '\t'; outThermal << cluster.marketBidCost << '\t'; outThermal << cluster.spreadCost << '\n'; + outThermal << cluster.powerIncreaseCost << '\n'; + outThermal << cluster.powerDecreaseCost << '\n'; + outThermal << cluster.maxUpwardPowerRampingRate << '\n'; + outThermal << cluster.maxDownwardPowerRampingRate << '\n'; } // each thermal cluster }); // each area From 624f2ce5436532ef019be957135c5cbb154c5a60 Mon Sep 17 00:00:00 2001 From: bencamus Date: Mon, 18 Dec 2023 09:44:22 +0100 Subject: [PATCH 03/22] make the ramping constraints cyclical as the evolution of the production for the first hour is constrained the production of the last hour + remove commented ramping debug logs --- .../constraints/ConstraintBuilder.cpp | 1 - .../constraints/PowerOutputVariation.cpp | 30 ++++++------------- .../constraints/RampingDecreaseRate.cpp | 30 ++++++------------- .../constraints/RampingIncreaseRate.cpp | 30 ++++++------------- 4 files changed, 27 insertions(+), 64 deletions(-) diff --git a/src/solver/optimisation/constraints/ConstraintBuilder.cpp b/src/solver/optimisation/constraints/ConstraintBuilder.cpp index 72a80f0117..2188e009f4 100644 --- a/src/solver/optimisation/constraints/ConstraintBuilder.cpp +++ b/src/solver/optimisation/constraints/ConstraintBuilder.cpp @@ -58,7 +58,6 @@ ConstraintBuilder& ConstraintBuilder::DispatchableProduction(unsigned int index, int delta) { AddVariable(GetVariableManager(offset, delta).DispatchableProduction(index), coeff); - // logs.info() << "dispatchable production idx " << GetVariableManager(offset, delta).DispatchableProduction(index); return *this; } diff --git a/src/solver/optimisation/constraints/PowerOutputVariation.cpp b/src/solver/optimisation/constraints/PowerOutputVariation.cpp index d24196c387..3e219599f5 100644 --- a/src/solver/optimisation/constraints/PowerOutputVariation.cpp +++ b/src/solver/optimisation/constraints/PowerOutputVariation.cpp @@ -8,25 +8,14 @@ void PowerOutputVariation::add(int pays, int cluster, int clusterIndex, int pdt, double maxUpwardPowerRampingRate = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[clusterIndex]; double pminDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.pminDUnGroupeDuPalierThermique[clusterIndex]; // constraint : P(t) - P(t-1) - l * M^+(t) - P^+ + P^- = 0 - if (pdt > 0) - { - builder.updateHourWithinWeek(pdt) - .DispatchableProduction(cluster, 1.0) - .DispatchableProduction(cluster, -1.0, -1, problemeHebdo->NombreDePasDeTempsPourUneOptimisation) - .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) - .ProductionIncreaseAboveMin(cluster, -1.0) - .ProductionDecreaseAboveMin(cluster, 1.0) - .equalTo(); - } - else - { - builder.updateHourWithinWeek(pdt) - .DispatchableProduction(cluster, 1.0) - .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) - .ProductionIncreaseAboveMin(cluster, -1.0) - .ProductionDecreaseAboveMin(cluster, 1.0) - .equalTo(); - } + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1.0) + .DispatchableProduction(cluster, -1.0, -1, problemeHebdo->NombreDePasDeTempsPourUneOptimisation) + .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) + .ProductionIncreaseAboveMin(cluster, -1.0) + .ProductionDecreaseAboveMin(cluster, 1.0) + .equalTo(); + if (builder.NumberOfVariables() > 0) { ConstraintNamer namer(problemeHebdo->ProblemeAResoudre->NomDesContraintes); @@ -40,8 +29,7 @@ void PowerOutputVariation::add(int pays, int cluster, int clusterIndex, int pdt, } else { - int add = (pdt == 0) ? 4 : 5; - problemeHebdo->NbTermesContraintesPourLesRampes += add; + problemeHebdo->NbTermesContraintesPourLesRampes += 5; problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/RampingDecreaseRate.cpp b/src/solver/optimisation/constraints/RampingDecreaseRate.cpp index 5cdb3f5d76..f067825fce 100644 --- a/src/solver/optimisation/constraints/RampingDecreaseRate.cpp +++ b/src/solver/optimisation/constraints/RampingDecreaseRate.cpp @@ -8,25 +8,14 @@ void RampingDecreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, double maxDownwardPowerRampingRate = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[clusterIndex]; double pmaxDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.PmaxDUnGroupeDuPalierThermique[clusterIndex]; // constraint : P(t) - P(t-1) + R^- * M(t) + u * M^-(t) + u * M^--(t) > 0 - if (pdt > 0) - { - builder.updateHourWithinWeek(pdt) - .DispatchableProduction(cluster, 1.0) - .DispatchableProduction(cluster, -1.0, -1, problemeHebdo->NombreDePasDeTempsPourUneOptimisation) - .NumberOfDispatchableUnits(cluster, maxDownwardPowerRampingRate) - .NumberStoppingDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) - .NumberBreakingDownDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) - .greaterThan(); - } - else - { - builder.updateHourWithinWeek(pdt) - .DispatchableProduction(cluster, 1.0) - .NumberOfDispatchableUnits(cluster, maxDownwardPowerRampingRate) - .NumberStoppingDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) - .NumberBreakingDownDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) - .greaterThan(); - } + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1.0) + .DispatchableProduction(cluster, -1.0, -1, problemeHebdo->NombreDePasDeTempsPourUneOptimisation) + .NumberOfDispatchableUnits(cluster, maxDownwardPowerRampingRate) + .NumberStoppingDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) + .NumberBreakingDownDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) + .greaterThan(); + if (builder.NumberOfVariables() > 0) { ConstraintNamer namer(problemeHebdo->ProblemeAResoudre->NomDesContraintes); @@ -41,8 +30,7 @@ void RampingDecreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, } else { - int add = (pdt == 0) ? 4 : 5; - problemeHebdo->NbTermesContraintesPourLesRampes += add; + problemeHebdo->NbTermesContraintesPourLesRampes += 5; problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/RampingIncreaseRate.cpp b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp index 508e2939d1..6dd698a45c 100644 --- a/src/solver/optimisation/constraints/RampingIncreaseRate.cpp +++ b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp @@ -8,26 +8,15 @@ void RampingIncreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, double maxUpwardPowerRampingRate = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[clusterIndex]; double pminDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.pminDUnGroupeDuPalierThermique[clusterIndex]; // constraint : P(t) - P(t-1) - R^+ * M(t) - l * M^+(t) < 0 - // logs.info() << "add up ramping constraint for cluster " << cluster << " pdt " << pdt; - if (pdt > 0) - { - builder.updateHourWithinWeek(pdt) - .DispatchableProduction(cluster, 1.0) - .DispatchableProduction( - cluster, -1.0, -1, problemeHebdo->NombreDePasDeTempsPourUneOptimisation) - .NumberOfDispatchableUnits(cluster, -maxUpwardPowerRampingRate) - .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) - .lessThan(); - } - else - { - builder.updateHourWithinWeek(pdt) - .DispatchableProduction(cluster, 1.0) - .NumberOfDispatchableUnits(cluster, -maxUpwardPowerRampingRate) - .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) - .lessThan(); - } + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1.0) + .DispatchableProduction( + cluster, -1.0, -1, problemeHebdo->NombreDePasDeTempsPourUneOptimisation) + .NumberOfDispatchableUnits(cluster, -maxUpwardPowerRampingRate) + .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) + .lessThan(); + if (builder.NumberOfVariables() > 0) { ConstraintNamer namer(problemeHebdo->ProblemeAResoudre->NomDesContraintes); @@ -40,8 +29,7 @@ void RampingIncreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, } else { - int add = (pdt == 0) ? 3 : 4; - problemeHebdo->NbTermesContraintesPourLesRampes += add; + problemeHebdo->NbTermesContraintesPourLesRampes += 4; problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; } } From 915e0c704483d4e4872e31f35429f41f5546c8da Mon Sep 17 00:00:00 2001 From: bencamus Date: Mon, 18 Dec 2023 09:47:04 +0100 Subject: [PATCH 04/22] remove reference to Yuni in the ramping model code --- src/libs/antares/study/parts/thermal/cluster_list.cpp | 8 ++++---- .../opt_gestion_des_bornes_rampes_thermiques.cpp | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libs/antares/study/parts/thermal/cluster_list.cpp b/src/libs/antares/study/parts/thermal/cluster_list.cpp index b5a5385042..b5320be9d8 100644 --- a/src/libs/antares/study/parts/thermal/cluster_list.cpp +++ b/src/libs/antares/study/parts/thermal/cluster_list.cpp @@ -415,13 +415,13 @@ bool ThermalClusterList::saveToFolder(const AnyString& folder) const s->add("variableomcost", Math::Round(c.variableomcost,3)); // ramping - if (not Math::Zero(c.powerIncreaseCost)) + if (c.powerIncreaseCost != 0) s->add("power-increase-cost", Math::Round(c.powerIncreaseCost, 3)); - if (not Math::Zero(c.powerDecreaseCost)) + if (c.powerDecreaseCost != 0) s->add("power-decrease-cost", Math::Round(c.powerDecreaseCost, 3)); - if (not Math::Zero(c.maxUpwardPowerRampingRate)) + if (c.maxUpwardPowerRampingRate != 0) s->add("max-upward-power-ramping-rate", Math::Round(c.maxUpwardPowerRampingRate, 3)); - if (not Math::Zero(c.maxDownwardPowerRampingRate)) + if (c.maxDownwardPowerRampingRate != 0) s->add("max-downward-power-ramping-rate", Math::Round(c.maxDownwardPowerRampingRate, 3)); //pollutant factor diff --git a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp index a62b30a307..2c3775ef47 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp @@ -32,7 +32,6 @@ #include "../simulation/sim_structure_probleme_economique.h" #include "opt_fonctions.h" -using namespace Yuni; void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO* problemeHebdo, const int PremierPdtDeLIntervalle, const int DernierPdtDeLIntervalle) { From f2d469eb5974cd56f12d6c58a2613d4505fba7a4 Mon Sep 17 00:00:00 2001 From: bencamus Date: Mon, 18 Dec 2023 11:41:38 +0100 Subject: [PATCH 05/22] removing of a useless header file --- .../optimisation/opt_construction_variables_rampes_thermiques.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/solver/optimisation/opt_construction_variables_rampes_thermiques.h diff --git a/src/solver/optimisation/opt_construction_variables_rampes_thermiques.h b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.h deleted file mode 100644 index e69de29bb2..0000000000 From e78c03491ac707703a8f888f11e1fce0270a6560 Mon Sep 17 00:00:00 2001 From: bencamus Date: Mon, 18 Dec 2023 11:44:46 +0100 Subject: [PATCH 06/22] improve readability of ramping model methods by naming their parameters in the header file --- src/solver/optimisation/opt_fonctions.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/opt_fonctions.h index 5af67e58fb..e88ae7012d 100644 --- a/src/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/opt_fonctions.h @@ -130,12 +130,20 @@ void OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(PROBLEME_HEBDO*); void OPT_InitialiserNombreMinEtMaxDeGroupesCoutsDeDemarrage(PROBLEME_HEBDO*); void OPT_AjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO*); -void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO*, bool); -void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO*, bool); -void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO*, const int, const int); -void OPT_DecompteDesVariablesEtDesContraintesRampesThermiques(PROBLEME_HEBDO*); -void OPT_InitialiserLesCoutsLineaireRampesThermiques(PROBLEME_HEBDO*, const int, const int); -void OPT_InitialiserLeSecondMembreDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO*, int, int); +void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireRampesThermiques( + PROBLEME_HEBDO* problemeHebdo, + bool Simulation); +void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireRampesThermiques( + PROBLEME_HEBDO* problemeHebdo, + bool Simulation); +void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques( + PROBLEME_HEBDO* problemeHebdo, + const int PremierPdtDeLIntervalle, + const int DernierPdtDeLIntervalle); +void OPT_DecompteDesVariablesEtDesContraintesRampesThermiques(PROBLEME_HEBDO* problemeHebdo); +void OPT_InitialiserLesCoutsLineaireRampesThermiques(PROBLEME_HEBDO* problemeHebdo, + const int PremierPdtDeLIntervalle, + const int DernierPdtDeLIntervalle); double OPT_SommeDesPminThermiques(const PROBLEME_HEBDO*, int, uint); From b9801feaf09d246c7f326859a24d4c2b97674d71 Mon Sep 17 00:00:00 2001 From: bencamus Date: Mon, 18 Dec 2023 18:16:24 +0100 Subject: [PATCH 07/22] add subclass to store and check thermal cluster ramping attributes --- .../antares/study/parts/thermal/cluster.cpp | 90 ++++++++++--------- .../antares/study/parts/thermal/cluster.h | 33 +++++-- .../study/parts/thermal/cluster_list.cpp | 26 +++--- .../simulation/sim_calcul_economique.cpp | 8 +- .../variable/surveyresults/surveyresults.cpp | 8 +- 5 files changed, 95 insertions(+), 70 deletions(-) diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index 25297fedda..4ade08ae1f 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -138,10 +138,7 @@ Data::ThermalCluster::ThermalCluster(Area* parent) : plannedLaw(thermalLawUniform), PthetaInf(HOURS_PER_YEAR, 0), costsTimeSeries(1, CostsTimeSeries()), - maxUpwardPowerRampingRate(0.), - maxDownwardPowerRampingRate(0.), - powerIncreaseCost(0.), - powerDecreaseCost(0.) + ramping() { // assert assert(parent and "A parent for a thermal dispatchable cluster can not be null"); @@ -187,10 +184,7 @@ void Data::ThermalCluster::copyFrom(const ThermalCluster& cluster) minDownTime = cluster.minDownTime; // ramping - maxUpwardPowerRampingRate = cluster.maxUpwardPowerRampingRate; - maxDownwardPowerRampingRate = cluster.maxDownwardPowerRampingRate; - powerDecreaseCost = cluster.powerDecreaseCost; - powerIncreaseCost = cluster.powerIncreaseCost; + ramping = cluster.ramping; // spinning spinning = cluster.spinning; @@ -489,11 +483,9 @@ void Data::ThermalCluster::reset() marketBidCost = 0.; variableomcost = 0.; costsTimeSeries.resize(1, CostsTimeSeries()); - powerIncreaseCost = 0; - powerDecreaseCost = 0; - - maxUpwardPowerRampingRate = 0; - maxDownwardPowerRampingRate = 0; + + // ramping + ramping.reset(); // modulation modulation.resize(thermalModulationMax, HOURS_PER_YEAR); @@ -624,34 +616,7 @@ bool Data::ThermalCluster::integrityCheck() }*/ // ramping - if (maxUpwardPowerRampingRate <= 0) - { - logs.error() << "Thermal cluster: " << parentArea->name << '/' << pName - << ": The maximum upward power ramping rate must greater than zero."; - maxUpwardPowerRampingRate = 1.; - ret = false; - } - if (maxDownwardPowerRampingRate <= 0) - { - logs.error() << "Thermal cluster: " << parentArea->name << '/' << pName - << ": The maximum downward power ramping rate must greater than zero."; - maxDownwardPowerRampingRate = 1.; - ret = false; - } - if (powerIncreaseCost < 0) - { - logs.error() << "Thermal cluster: " << parentArea->name << '/' << pName - << ": The ramping power increase cost must be positive or null."; - powerIncreaseCost = 0.; - ret = false; - } - if (powerDecreaseCost < 0) - { - logs.error() << "Thermal cluster: " << parentArea->name << '/' << pName - << ": The ramping power decrease cost must be positive or null."; - powerDecreaseCost = 0.; - ret = false; - } + ret = ramping.checkValidity(parentArea, pName) && ret; return ret; } @@ -867,5 +832,48 @@ bool ThermalCluster::isActive() const { return enabled && !mustrun; } +void ThermalCluster::Ramping::reset() +{ + powerIncreaseCost = 0; + powerDecreaseCost = 0; + maxUpwardPowerRampingRate = 0; + maxDownwardPowerRampingRate = 0; +} + +bool ThermalCluster::Ramping::checkValidity(Area* parentArea, Data::ClusterName clusterName) +{ + bool ret = true; + + if (maxUpwardPowerRampingRate <= 0) + { + logs.error() << "Thermal cluster: " << parentArea->name << '/' << clusterName + << ": The maximum upward power ramping rate must greater than zero."; + maxUpwardPowerRampingRate = 1.; + ret = false; + } + if (maxDownwardPowerRampingRate <= 0) + { + logs.error() << "Thermal cluster: " << parentArea->name << '/' << clusterName + << ": The maximum downward power ramping rate must greater than zero."; + maxDownwardPowerRampingRate = 1.; + ret = false; + } + if (powerIncreaseCost < 0) + { + logs.error() << "Thermal cluster: " << parentArea->name << '/' << clusterName + << ": The ramping power increase cost must be positive or null."; + powerIncreaseCost = 0.; + ret = false; + } + if (powerDecreaseCost < 0) + { + logs.error() << "Thermal cluster: " << parentArea->name << '/' << clusterName + << ": The ramping power decrease cost must be positive or null."; + powerDecreaseCost = 0.; + ret = false; + } + return ret; +} + } // namespace Data } // namespace Antares diff --git a/src/libs/antares/study/parts/thermal/cluster.h b/src/libs/antares/study/parts/thermal/cluster.h index a9a9705363..c27e70473d 100644 --- a/src/libs/antares/study/parts/thermal/cluster.h +++ b/src/libs/antares/study/parts/thermal/cluster.h @@ -340,15 +340,30 @@ class ThermalCluster final : public Cluster, public std::enable_shared_from_this double marketBidCost = 0; //! Variable O&M cost (euros/MWh) double variableomcost = 0; - //! Cost of power increase (euros/MW) - double powerIncreaseCost = 0; - //! Cost of power decrease (euros/MW) - double powerDecreaseCost = 0; - - //! Maximum hourly upward power ramping rate (MW/hour) - double maxUpwardPowerRampingRate = 0; - //! Maximum hourly downward power ramping rate (MW/hour) - double maxDownwardPowerRampingRate = 0; + + struct Ramping + { + //! Cost of power increase (euros/MW) + double powerIncreaseCost; + //! Cost of power decrease (euros/MW) + double powerDecreaseCost; + //! Maximum hourly upward power ramping rate (MW/hour) + double maxUpwardPowerRampingRate; + //! Maximum hourly downward power ramping rate (MW/hour) + double maxDownwardPowerRampingRate; + + Ramping() : + powerIncreaseCost(0.), + powerDecreaseCost(0.), + maxUpwardPowerRampingRate(0.), + maxDownwardPowerRampingRate(0.) + { + } + + void reset(); + bool checkValidity(Area* area, Data::ClusterName clusterName); + }; + Ramping ramping; //@} diff --git a/src/libs/antares/study/parts/thermal/cluster_list.cpp b/src/libs/antares/study/parts/thermal/cluster_list.cpp index b5320be9d8..9ba5d025fd 100644 --- a/src/libs/antares/study/parts/thermal/cluster_list.cpp +++ b/src/libs/antares/study/parts/thermal/cluster_list.cpp @@ -223,13 +223,13 @@ static bool ThermalClusterLoadFromProperty(ThermalCluster& cluster, const IniFil return p->value.to(cluster.startupCost); if (p->key == "power-increase-cost") - return p->value.to(cluster.powerIncreaseCost); + return p->value.to(cluster.ramping.powerIncreaseCost); if (p->key == "power-decrease-cost") - return p->value.to(cluster.powerDecreaseCost); + return p->value.to(cluster.ramping.powerDecreaseCost); if (p->key == "max-upward-power-ramping-rate") - return p->value.to(cluster.maxUpwardPowerRampingRate); + return p->value.to(cluster.ramping.maxUpwardPowerRampingRate); if (p->key == "max-downward-power-ramping-rate") - return p->value.to(cluster.maxDownwardPowerRampingRate); + return p->value.to(cluster.ramping.maxDownwardPowerRampingRate); if (p->key == "unitcount") return p->value.to(cluster.unitCount); @@ -415,14 +415,16 @@ bool ThermalClusterList::saveToFolder(const AnyString& folder) const s->add("variableomcost", Math::Round(c.variableomcost,3)); // ramping - if (c.powerIncreaseCost != 0) - s->add("power-increase-cost", Math::Round(c.powerIncreaseCost, 3)); - if (c.powerDecreaseCost != 0) - s->add("power-decrease-cost", Math::Round(c.powerDecreaseCost, 3)); - if (c.maxUpwardPowerRampingRate != 0) - s->add("max-upward-power-ramping-rate", Math::Round(c.maxUpwardPowerRampingRate, 3)); - if (c.maxDownwardPowerRampingRate != 0) - s->add("max-downward-power-ramping-rate", Math::Round(c.maxDownwardPowerRampingRate, 3)); + if (c.ramping.powerIncreaseCost != 0) + s->add("power-increase-cost", Math::Round(c.ramping.powerIncreaseCost, 3)); + if (c.ramping.powerDecreaseCost != 0) + s->add("power-decrease-cost", Math::Round(c.ramping.powerDecreaseCost, 3)); + if (c.ramping.maxUpwardPowerRampingRate != 0) + s->add("max-upward-power-ramping-rate", + Math::Round(c.ramping.maxUpwardPowerRampingRate, 3)); + if (c.ramping.maxDownwardPowerRampingRate != 0) + s->add("max-downward-power-ramping-rate", + Math::Round(c.ramping.maxDownwardPowerRampingRate, 3)); //pollutant factor for (auto const& [key, val] : Pollutant::namesToEnum) diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index d545917625..839917cd5d 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -302,10 +302,10 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, = cluster.minDownTime; pbPalier.upwardRampingCost[clusterIndex] - = cluster.powerIncreaseCost; - pbPalier.downwardRampingCost[clusterIndex] = cluster.powerDecreaseCost; - pbPalier.maxDownwardPowerRampingRate[clusterIndex] = cluster.maxDownwardPowerRampingRate; - pbPalier.maxUpwardPowerRampingRate[clusterIndex] = cluster.maxUpwardPowerRampingRate; + = cluster.ramping.powerIncreaseCost; + pbPalier.downwardRampingCost[clusterIndex] = cluster.ramping.powerDecreaseCost; + pbPalier.maxDownwardPowerRampingRate[clusterIndex] = cluster.ramping.maxDownwardPowerRampingRate; + pbPalier.maxUpwardPowerRampingRate[clusterIndex] = cluster.ramping.maxUpwardPowerRampingRate; diff --git a/src/solver/variable/surveyresults/surveyresults.cpp b/src/solver/variable/surveyresults/surveyresults.cpp index 2a86dff42b..45558ab172 100644 --- a/src/solver/variable/surveyresults/surveyresults.cpp +++ b/src/solver/variable/surveyresults/surveyresults.cpp @@ -159,10 +159,10 @@ static void ExportGridInfosAreas(const Data::Study& study, outThermal << cluster.startupCost << '\t'; outThermal << cluster.marketBidCost << '\t'; outThermal << cluster.spreadCost << '\n'; - outThermal << cluster.powerIncreaseCost << '\n'; - outThermal << cluster.powerDecreaseCost << '\n'; - outThermal << cluster.maxUpwardPowerRampingRate << '\n'; - outThermal << cluster.maxDownwardPowerRampingRate << '\n'; + outThermal << cluster.ramping.powerIncreaseCost << '\n'; + outThermal << cluster.ramping.powerDecreaseCost << '\n'; + outThermal << cluster.ramping.maxUpwardPowerRampingRate << '\n'; + outThermal << cluster.ramping.maxDownwardPowerRampingRate << '\n'; } // each thermal cluster }); // each area From 09a2ca9082d0ecd5b8fecd9f0aed1223d5508cf2 Mon Sep 17 00:00:00 2001 From: Florian OMNES <26088210+flomnes@users.noreply.github.com> Date: Mon, 18 Dec 2023 21:46:51 +0100 Subject: [PATCH 08/22] Small code improvement for ramping --- .../antares/study/parts/thermal/cluster.cpp | 8 +++++++ .../antares/study/parts/thermal/cluster.h | 1 + .../variable/surveyresults/surveyresults.cpp | 21 ++++++++----------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index 4ade08ae1f..75ea1b1c73 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -875,5 +875,13 @@ bool ThermalCluster::Ramping::checkValidity(Area* parentArea, Data::ClusterName return ret; } +std::ostream& ThermalCluster::Ramping::operator<<(std::ostream& os) const +{ + return os << powerIncreaseCost << '\t' + << powerDecreaseCost << '\t' + << maxUpwardPowerRampingRate << '\t' + << maxDownwardPowerRampingRate; +} + } // namespace Data } // namespace Antares diff --git a/src/libs/antares/study/parts/thermal/cluster.h b/src/libs/antares/study/parts/thermal/cluster.h index c27e70473d..91735f88a8 100644 --- a/src/libs/antares/study/parts/thermal/cluster.h +++ b/src/libs/antares/study/parts/thermal/cluster.h @@ -362,6 +362,7 @@ class ThermalCluster final : public Cluster, public std::enable_shared_from_this void reset(); bool checkValidity(Area* area, Data::ClusterName clusterName); + std::ostream& operator<<(std::ostream&) const; }; Ramping ramping; diff --git a/src/solver/variable/surveyresults/surveyresults.cpp b/src/solver/variable/surveyresults/surveyresults.cpp index 45558ab172..0263baf395 100644 --- a/src/solver/variable/surveyresults/surveyresults.cpp +++ b/src/solver/variable/surveyresults/surveyresults.cpp @@ -32,6 +32,7 @@ #include #include #include +#include using namespace Yuni; using namespace Antares; @@ -115,9 +116,7 @@ static void ExportGridInfosAreas(const Data::Study& study, const Yuni::String& originalOutput, IResultWriter& writer) { - Clob out; - Clob outLinks; - Clob outThermal; + std::ostringstream out, outLinks, outThermal; out << "id\tname\n"; outLinks << "upstream\tdownstream\n"; @@ -158,23 +157,21 @@ static void ExportGridInfosAreas(const Data::Study& study, outThermal << cluster.fixedCost << '\t'; outThermal << cluster.startupCost << '\t'; outThermal << cluster.marketBidCost << '\t'; - outThermal << cluster.spreadCost << '\n'; - outThermal << cluster.ramping.powerIncreaseCost << '\n'; - outThermal << cluster.ramping.powerDecreaseCost << '\n'; - outThermal << cluster.ramping.maxUpwardPowerRampingRate << '\n'; - outThermal << cluster.ramping.maxDownwardPowerRampingRate << '\n'; + outThermal << cluster.spreadCost << '\t'; + outThermal << cluster.ramping << '\n'; } // each thermal cluster }); // each area - auto add = [&writer, &originalOutput](const YString& filename, Clob&& buffer) { + // buffer must be copied since addEntryFromBuffer has no std::string&& variant, unfortunately + auto add = [&writer, &originalOutput](const YString& filename, std::string buffer) { YString path; path << originalOutput << SEP << "grid" << SEP << filename; writer.addEntryFromBuffer(path.c_str(), buffer); }; - add("areas.txt", std::move(out)); - add("links.txt", std::move(outLinks)); - add("thermal.txt", std::move(outThermal)); + add("areas.txt", out.str()); + add("links.txt", outLinks.str()); + add("thermal.txt", outThermal.str()); } SurveyResultsData::SurveyResultsData(const Data::Study& s, const String& o) : From 5ce453172bb352fa24d82c30855b7c22b4331993 Mon Sep 17 00:00:00 2001 From: Florian OMNES <26088210+flomnes@users.noreply.github.com> Date: Tue, 19 Dec 2023 10:08:07 +0100 Subject: [PATCH 09/22] Solve build errors with a friend --- src/libs/antares/study/parts/thermal/cluster.cpp | 10 +++++----- src/libs/antares/study/parts/thermal/cluster.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index 75ea1b1c73..e3991c723f 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -875,12 +875,12 @@ bool ThermalCluster::Ramping::checkValidity(Area* parentArea, Data::ClusterName return ret; } -std::ostream& ThermalCluster::Ramping::operator<<(std::ostream& os) const +std::ostream& operator<<(std::ostream& os, const ThermalCluster::Ramping& r) { - return os << powerIncreaseCost << '\t' - << powerDecreaseCost << '\t' - << maxUpwardPowerRampingRate << '\t' - << maxDownwardPowerRampingRate; + return os << r.powerIncreaseCost << '\t' + << r.powerDecreaseCost << '\t' + << r.maxUpwardPowerRampingRate << '\t' + << r.maxDownwardPowerRampingRate; } } // namespace Data diff --git a/src/libs/antares/study/parts/thermal/cluster.h b/src/libs/antares/study/parts/thermal/cluster.h index 91735f88a8..f80cdaf8b0 100644 --- a/src/libs/antares/study/parts/thermal/cluster.h +++ b/src/libs/antares/study/parts/thermal/cluster.h @@ -362,7 +362,7 @@ class ThermalCluster final : public Cluster, public std::enable_shared_from_this void reset(); bool checkValidity(Area* area, Data::ClusterName clusterName); - std::ostream& operator<<(std::ostream&) const; + friend std::ostream& operator<<(std::ostream&, const Ramping& ramping); }; Ramping ramping; From 77daa3606908d6d45a008d5e61288b106232a6e3 Mon Sep 17 00:00:00 2001 From: bencamus Date: Wed, 20 Dec 2023 16:02:19 +0100 Subject: [PATCH 10/22] add the possibility to enable/disable the ramping model for each cluster --- .../antares/study/parts/thermal/cluster.cpp | 30 ++++++++----- .../antares/study/parts/thermal/cluster.h | 4 +- .../study/parts/thermal/cluster_list.cpp | 44 +++++++++++++------ ...truction_contraintes_rampes_thermiques.cpp | 27 +++++++----- ...n_matrice_des_contraintes_cas_lineaire.cpp | 3 -- ...nstruction_variables_rampes_thermiques.cpp | 44 ++++++++++++------- ...t_gestion_des_bornes_rampes_thermiques.cpp | 23 +++++++--- ...pt_gestion_des_couts_rampes_thermiques.cpp | 29 +++++++----- .../simulation/sim_calcul_economique.cpp | 28 ++++++++---- .../variable/surveyresults/surveyresults.cpp | 13 +++--- 10 files changed, 161 insertions(+), 84 deletions(-) diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index 4ade08ae1f..b9192fc639 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -137,8 +137,7 @@ Data::ThermalCluster::ThermalCluster(Area* parent) : forcedLaw(thermalLawUniform), plannedLaw(thermalLawUniform), PthetaInf(HOURS_PER_YEAR, 0), - costsTimeSeries(1, CostsTimeSeries()), - ramping() + costsTimeSeries(1, CostsTimeSeries()) { // assert assert(parent and "A parent for a thermal dispatchable cluster can not be null"); @@ -616,7 +615,16 @@ bool Data::ThermalCluster::integrityCheck() }*/ // ramping - ret = ramping.checkValidity(parentArea, pName) && ret; + if (ramping) + { + // if the ramping model is ill defined, then we disable the ramping model for this cluster + bool ramping_ret = ramping.value().checkValidity(parentArea, pName); + if(!ramping_ret) + { + ramping.reset(); + } + ret = ramping_ret && ret; + } return ret; } @@ -847,29 +855,29 @@ bool ThermalCluster::Ramping::checkValidity(Area* parentArea, Data::ClusterName if (maxUpwardPowerRampingRate <= 0) { logs.error() << "Thermal cluster: " << parentArea->name << '/' << clusterName - << ": The maximum upward power ramping rate must greater than zero."; - maxUpwardPowerRampingRate = 1.; + << ": The maximum upward power ramping rate must greater than zero." + << "Ramping is disabled for this thermal cluster"; ret = false; } if (maxDownwardPowerRampingRate <= 0) { logs.error() << "Thermal cluster: " << parentArea->name << '/' << clusterName - << ": The maximum downward power ramping rate must greater than zero."; - maxDownwardPowerRampingRate = 1.; + << ": The maximum downward power ramping rate must greater than zero." + << "Ramping is disabled for this thermal cluster"; ret = false; } if (powerIncreaseCost < 0) { logs.error() << "Thermal cluster: " << parentArea->name << '/' << clusterName - << ": The ramping power increase cost must be positive or null."; - powerIncreaseCost = 0.; + << ": The ramping power increase cost must be positive or null." + << "Ramping is disabled for this thermal cluster"; ret = false; } if (powerDecreaseCost < 0) { logs.error() << "Thermal cluster: " << parentArea->name << '/' << clusterName - << ": The ramping power decrease cost must be positive or null."; - powerDecreaseCost = 0.; + << ": The ramping power decrease cost must be positive or null." + << "Ramping is disabled for this thermal cluster"; ret = false; } return ret; diff --git a/src/libs/antares/study/parts/thermal/cluster.h b/src/libs/antares/study/parts/thermal/cluster.h index c27e70473d..ec3a272cda 100644 --- a/src/libs/antares/study/parts/thermal/cluster.h +++ b/src/libs/antares/study/parts/thermal/cluster.h @@ -40,6 +40,8 @@ #include #include #include +#include + namespace Antares { @@ -363,7 +365,7 @@ class ThermalCluster final : public Cluster, public std::enable_shared_from_this void reset(); bool checkValidity(Area* area, Data::ClusterName clusterName); }; - Ramping ramping; + std::optional ramping; //@} diff --git a/src/libs/antares/study/parts/thermal/cluster_list.cpp b/src/libs/antares/study/parts/thermal/cluster_list.cpp index 9ba5d025fd..4572ea0170 100644 --- a/src/libs/antares/study/parts/thermal/cluster_list.cpp +++ b/src/libs/antares/study/parts/thermal/cluster_list.cpp @@ -222,14 +222,22 @@ static bool ThermalClusterLoadFromProperty(ThermalCluster& cluster, const IniFil if (p->key == "startup-cost") return p->value.to(cluster.startupCost); + // initialize the ramping attributes only if ramping is enabled, else ignore these properties if (p->key == "power-increase-cost") - return p->value.to(cluster.ramping.powerIncreaseCost); + return (cluster.ramping)? p->value.to(cluster.ramping.value().powerIncreaseCost) : true; if (p->key == "power-decrease-cost") - return p->value.to(cluster.ramping.powerDecreaseCost); + return (cluster.ramping) ? p->value.to(cluster.ramping.value().powerDecreaseCost) + : true; if (p->key == "max-upward-power-ramping-rate") - return p->value.to(cluster.ramping.maxUpwardPowerRampingRate); + return (cluster.ramping) + ? p->value.to(cluster.ramping.value().maxUpwardPowerRampingRate) + : true; if (p->key == "max-downward-power-ramping-rate") - return p->value.to(cluster.ramping.maxDownwardPowerRampingRate); + return (cluster.ramping) + ? p->value.to(cluster.ramping.value().maxDownwardPowerRampingRate) : true; + // we ignore this property as it was already handled in ThermalClusterLoadFromSection + if (p->key == "ramping-enabled") + return true; if (p->key == "unitcount") return p->value.to(cluster.unitCount); @@ -257,6 +265,16 @@ bool ThermalClusterLoadFromSection(const AnyString& filename, cluster.setName(section.name); + // initialize the ramping attributes only if ramping-enabled=true + auto* rampingEnabledProperty = section.find("ramping-enabled"); + if(rampingEnabledProperty) + { + bool rampingEnabled = false; + bool attributeOK = rampingEnabledProperty->value.to(rampingEnabled); + if (rampingEnabled && attributeOK) + cluster.ramping = ThermalCluster::Ramping(); + } + if (section.firstProperty) { // Browse all properties @@ -414,17 +432,17 @@ bool ThermalClusterList::saveToFolder(const AnyString& folder) const if (!Math::Zero(c.variableomcost)) s->add("variableomcost", Math::Round(c.variableomcost,3)); - // ramping - if (c.ramping.powerIncreaseCost != 0) - s->add("power-increase-cost", Math::Round(c.ramping.powerIncreaseCost, 3)); - if (c.ramping.powerDecreaseCost != 0) - s->add("power-decrease-cost", Math::Round(c.ramping.powerDecreaseCost, 3)); - if (c.ramping.maxUpwardPowerRampingRate != 0) + // ramping (only if ramping is enabled) + if (c.ramping && c.ramping.value().powerIncreaseCost != 0) + s->add("power-increase-cost", Math::Round(c.ramping.value().powerIncreaseCost, 3)); + if (c.ramping && c.ramping.value().powerDecreaseCost != 0) + s->add("power-decrease-cost", Math::Round(c.ramping.value().powerDecreaseCost, 3)); + if (c.ramping && c.ramping.value().maxUpwardPowerRampingRate != 0) s->add("max-upward-power-ramping-rate", - Math::Round(c.ramping.maxUpwardPowerRampingRate, 3)); - if (c.ramping.maxDownwardPowerRampingRate != 0) + Math::Round(c.ramping.value().maxUpwardPowerRampingRate, 3)); + if (c.ramping && c.ramping.value().maxDownwardPowerRampingRate != 0) s->add("max-downward-power-ramping-rate", - Math::Round(c.ramping.maxDownwardPowerRampingRate, 3)); + Math::Round(c.ramping.value().maxDownwardPowerRampingRate, 3)); //pollutant factor for (auto const& [key, val] : Pollutant::namesToEnum) diff --git a/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp b/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp index a009f06f74..32885d9eaf 100644 --- a/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp @@ -25,17 +25,24 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireRampesThermiques(PRO constraintNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) { - RampingIncreaseRate rampingIncreaseRate(problemeHebdo); - RampingDecreaseRate rampingDecreaseRate(problemeHebdo); - PowerOutputVariation powerOutputVariation(problemeHebdo); - - const int palier = PaliersThermiquesDuPays.NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; - - for (int pdt = 0; pdt < nombreDePasDeTempsPourUneOptimisation; pdt++) + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] > 0. + && PaliersThermiquesDuPays.maxDownwardPowerRampingRate[index] > 0. + && PaliersThermiquesDuPays.upwardRampingCost[index] >= 0. + && PaliersThermiquesDuPays.downwardRampingCost[index] >= 0.) { - rampingIncreaseRate.add(pays, palier, index, pdt, Simulation); - rampingDecreaseRate.add(pays, palier, index, pdt, Simulation); - powerOutputVariation.add(pays, palier, index, pdt, Simulation); + RampingIncreaseRate rampingIncreaseRate(problemeHebdo); + RampingDecreaseRate rampingDecreaseRate(problemeHebdo); + PowerOutputVariation powerOutputVariation(problemeHebdo); + + const int palier + = PaliersThermiquesDuPays.NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; + + for (int pdt = 0; pdt < nombreDePasDeTempsPourUneOptimisation; pdt++) + { + rampingIncreaseRate.add(pays, palier, index, pdt, Simulation); + rampingDecreaseRate.add(pays, palier, index, pdt, Simulation); + powerOutputVariation.add(pays, palier, index, pdt, Simulation); + } } } } diff --git a/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp b/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp index 54f05cc6d2..607cc09a84 100644 --- a/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_matrice_des_contraintes_cas_lineaire.cpp @@ -190,9 +190,6 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaire(PROBLEME_HEBDO* pro finalStockExpression.add(pays); } - - logs.info() << "adding ramping constraints"; - if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) diff --git a/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp index b720e22a45..4fb5269b8d 100644 --- a/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp @@ -26,24 +26,36 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireRampesThermiqu variableNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) { - const int palier = PaliersThermiquesDuPays.NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; - const auto& clusterName = PaliersThermiquesDuPays.NomsDesPaliersThermiques[index]; - - if (!Simulation) - { - CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier] = NombreDeVariables; - ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; - variableNamer.ProductionIncreaseAboveMin(NombreDeVariables, clusterName); - } - NombreDeVariables++; - - if (!Simulation) + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] > 0. + && PaliersThermiquesDuPays.maxDownwardPowerRampingRate[index] > 0. + && PaliersThermiquesDuPays.upwardRampingCost[index] >= 0. + && PaliersThermiquesDuPays.downwardRampingCost[index] >= 0.) { - CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier] = NombreDeVariables; - ProblemeAResoudre->TypeDeVariable[NombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; - variableNamer.ProductionDecreaseAboveMin(NombreDeVariables, clusterName); + const int palier = PaliersThermiquesDuPays + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; + const auto& clusterName + = PaliersThermiquesDuPays.NomsDesPaliersThermiques[index]; + + if (!Simulation) + { + CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier] + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.ProductionIncreaseAboveMin(NombreDeVariables, clusterName); + } + NombreDeVariables++; + + if (!Simulation) + { + CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier] + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_DES_DEUX_COTES; + variableNamer.ProductionDecreaseAboveMin(NombreDeVariables, clusterName); + } + NombreDeVariables++; } - NombreDeVariables++; } } } diff --git a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp index 2c3775ef47..748949e259 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp @@ -51,15 +51,24 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques(PROB for (int index = 0; index < maxThermalPlant; index++) { - const int palier = PaliersThermiquesDuPays.NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] > 0. + && PaliersThermiquesDuPays.maxDownwardPowerRampingRate[index] > 0. + && PaliersThermiquesDuPays.upwardRampingCost[index] >= 0. + && PaliersThermiquesDuPays.downwardRampingCost[index] >= 0.) + { + const int palier = PaliersThermiquesDuPays + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; - int var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; - Xmin[var] = 0; - Xmax[var] = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[index] * PaliersThermiquesDuPays.NombreDePaliersThermiques; + int var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; + Xmin[var] = 0; + Xmax[var] = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[index] + * PaliersThermiquesDuPays.NombreDePaliersThermiques; - var = CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier]; - Xmin[var] = 0; - Xmax[var] = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] * PaliersThermiquesDuPays.NombreDePaliersThermiques; + var = CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier]; + Xmin[var] = 0; + Xmax[var] = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] + * PaliersThermiquesDuPays.NombreDePaliersThermiques; + } } } } diff --git a/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp index 1270b99616..9c85d6a2e1 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp @@ -53,18 +53,27 @@ void OPT_InitialiserLesCoutsLineaireRampesThermiques(PROBLEME_HEBDO* problemeHeb for (int Index = 0; Index < PaliersThermiquesDuPays.NombreDePaliersThermiques; Index++) { - int palier = PaliersThermiquesDuPays.NumeroDuPalierDansLEnsembleDesPaliersThermiques[Index]; - - var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; - if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[Index] > 0. + && PaliersThermiquesDuPays.maxDownwardPowerRampingRate[Index] > 0. + && PaliersThermiquesDuPays.upwardRampingCost[Index] >= 0. + && PaliersThermiquesDuPays.downwardRampingCost[Index] >= 0.) { - ProblemeAResoudre->CoutLineaire[var] = PaliersThermiquesDuPays.downwardRampingCost[Index]; - } + int palier = PaliersThermiquesDuPays + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[Index]; - var = CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier]; - if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) - { - ProblemeAResoudre->CoutLineaire[var] = PaliersThermiquesDuPays.upwardRampingCost[Index]; + var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; + if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) + { + ProblemeAResoudre->CoutLineaire[var] + = PaliersThermiquesDuPays.downwardRampingCost[Index]; + } + + var = CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier]; + if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) + { + ProblemeAResoudre->CoutLineaire[var] + = PaliersThermiquesDuPays.upwardRampingCost[Index]; + } } } } diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 839917cd5d..ba85512cf9 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -301,14 +301,26 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, pbPalier.DureeMinimaleDArretDUnGroupeDuPalierThermique[clusterIndex] = cluster.minDownTime; - pbPalier.upwardRampingCost[clusterIndex] - = cluster.ramping.powerIncreaseCost; - pbPalier.downwardRampingCost[clusterIndex] = cluster.ramping.powerDecreaseCost; - pbPalier.maxDownwardPowerRampingRate[clusterIndex] = cluster.ramping.maxDownwardPowerRampingRate; - pbPalier.maxUpwardPowerRampingRate[clusterIndex] = cluster.ramping.maxUpwardPowerRampingRate; - - - + // ramping (if enabled) + if (cluster.ramping) + { + pbPalier.upwardRampingCost[clusterIndex] + = cluster.ramping.value().powerIncreaseCost; + pbPalier.downwardRampingCost[clusterIndex] + = cluster.ramping.value().powerDecreaseCost; + pbPalier.maxDownwardPowerRampingRate[clusterIndex] + = cluster.ramping.value().maxDownwardPowerRampingRate; + pbPalier.maxUpwardPowerRampingRate[clusterIndex] + = cluster.ramping.value().maxUpwardPowerRampingRate; + } + else + { + pbPalier.upwardRampingCost[clusterIndex] = -1; + pbPalier.downwardRampingCost[clusterIndex] = -1; + pbPalier.maxDownwardPowerRampingRate[clusterIndex] = -1; + pbPalier.maxUpwardPowerRampingRate[clusterIndex] = -1; + } + pbPalier.PmaxDUnGroupeDuPalierThermique[clusterIndex] = cluster.nominalCapacityWithSpinning; pbPalier.pminDUnGroupeDuPalierThermique[clusterIndex] diff --git a/src/solver/variable/surveyresults/surveyresults.cpp b/src/solver/variable/surveyresults/surveyresults.cpp index 45558ab172..79c7eedb81 100644 --- a/src/solver/variable/surveyresults/surveyresults.cpp +++ b/src/solver/variable/surveyresults/surveyresults.cpp @@ -158,11 +158,14 @@ static void ExportGridInfosAreas(const Data::Study& study, outThermal << cluster.fixedCost << '\t'; outThermal << cluster.startupCost << '\t'; outThermal << cluster.marketBidCost << '\t'; - outThermal << cluster.spreadCost << '\n'; - outThermal << cluster.ramping.powerIncreaseCost << '\n'; - outThermal << cluster.ramping.powerDecreaseCost << '\n'; - outThermal << cluster.ramping.maxUpwardPowerRampingRate << '\n'; - outThermal << cluster.ramping.maxDownwardPowerRampingRate << '\n'; + outThermal << cluster.spreadCost << '\t'; + if (cluster.ramping) + { + outThermal << cluster.ramping.value().powerIncreaseCost << '\t'; + outThermal << cluster.ramping.value().powerDecreaseCost << '\t'; + outThermal << cluster.ramping.value().maxUpwardPowerRampingRate << '\t'; + outThermal << cluster.ramping.value().maxDownwardPowerRampingRate << '\t'; + } } // each thermal cluster }); // each area From 8133150b562b9e7655a86f76893116f5b9e5ccea Mon Sep 17 00:00:00 2001 From: bencamus Date: Wed, 20 Dec 2023 18:16:57 +0100 Subject: [PATCH 11/22] improvement of the implementation of the ON/OFF ramping model features --- .../constraints/PowerOutputVariation.cpp | 5 +++- .../constraints/RampingDecreaseRate.cpp | 5 +++- .../constraints/RampingIncreaseRate.cpp | 8 ++++-- ...truction_contraintes_rampes_thermiques.cpp | 5 +--- ...nstruction_variables_rampes_thermiques.cpp | 5 +--- ...t_gestion_des_bornes_rampes_thermiques.cpp | 14 +++++----- ...pt_gestion_des_couts_rampes_thermiques.cpp | 12 ++++----- .../simulation/sim_alloc_probleme_hebdo.cpp | 27 ++++++++++++------- .../simulation/sim_calcul_economique.cpp | 20 +++++++------- .../sim_structure_probleme_economique.h | 8 ++++-- 10 files changed, 63 insertions(+), 46 deletions(-) diff --git a/src/solver/optimisation/constraints/PowerOutputVariation.cpp b/src/solver/optimisation/constraints/PowerOutputVariation.cpp index 3e219599f5..d175c1fceb 100644 --- a/src/solver/optimisation/constraints/PowerOutputVariation.cpp +++ b/src/solver/optimisation/constraints/PowerOutputVariation.cpp @@ -5,7 +5,10 @@ void PowerOutputVariation::add(int pays, int cluster, int clusterIndex, int pdt, if (!Simulation) { const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; - double maxUpwardPowerRampingRate = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[clusterIndex]; + int rampingClusterIndex + = PaliersThermiquesDuPays.clusterRampingVariablesIndex[clusterIndex]; + double maxUpwardPowerRampingRate + = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[rampingClusterIndex]; double pminDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.pminDUnGroupeDuPalierThermique[clusterIndex]; // constraint : P(t) - P(t-1) - l * M^+(t) - P^+ + P^- = 0 builder.updateHourWithinWeek(pdt) diff --git a/src/solver/optimisation/constraints/RampingDecreaseRate.cpp b/src/solver/optimisation/constraints/RampingDecreaseRate.cpp index f067825fce..738dcb4d88 100644 --- a/src/solver/optimisation/constraints/RampingDecreaseRate.cpp +++ b/src/solver/optimisation/constraints/RampingDecreaseRate.cpp @@ -5,7 +5,10 @@ void RampingDecreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, if (!Simulation) { const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; - double maxDownwardPowerRampingRate = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[clusterIndex]; + int rampingClusterIndex + = PaliersThermiquesDuPays.clusterRampingVariablesIndex[clusterIndex]; + double maxDownwardPowerRampingRate + = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[rampingClusterIndex]; double pmaxDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.PmaxDUnGroupeDuPalierThermique[clusterIndex]; // constraint : P(t) - P(t-1) + R^- * M(t) + u * M^-(t) + u * M^--(t) > 0 builder.updateHourWithinWeek(pdt) diff --git a/src/solver/optimisation/constraints/RampingIncreaseRate.cpp b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp index 6dd698a45c..03093df1d5 100644 --- a/src/solver/optimisation/constraints/RampingIncreaseRate.cpp +++ b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp @@ -5,8 +5,12 @@ void RampingIncreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, if (!Simulation) { const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; - double maxUpwardPowerRampingRate = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[clusterIndex]; - double pminDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.pminDUnGroupeDuPalierThermique[clusterIndex]; + int rampingClusterIndex + = PaliersThermiquesDuPays.clusterRampingVariablesIndex[clusterIndex]; + double maxUpwardPowerRampingRate + = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[rampingClusterIndex]; + double pminDUnGroupeDuPalierThermique + = PaliersThermiquesDuPays.pminDUnGroupeDuPalierThermique[clusterIndex]; // constraint : P(t) - P(t-1) - R^+ * M(t) - l * M^+(t) < 0 builder.updateHourWithinWeek(pdt) diff --git a/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp b/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp index 32885d9eaf..883ef387b6 100644 --- a/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp @@ -25,10 +25,7 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireRampesThermiques(PRO constraintNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) { - if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] > 0. - && PaliersThermiquesDuPays.maxDownwardPowerRampingRate[index] > 0. - && PaliersThermiquesDuPays.upwardRampingCost[index] >= 0. - && PaliersThermiquesDuPays.downwardRampingCost[index] >= 0.) + if (PaliersThermiquesDuPays.clusterRampingVariablesIndex[index] >= 0) { RampingIncreaseRate rampingIncreaseRate(problemeHebdo); RampingDecreaseRate rampingDecreaseRate(problemeHebdo); diff --git a/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp index 4fb5269b8d..be2a195859 100644 --- a/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp @@ -26,10 +26,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireRampesThermiqu variableNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) { - if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] > 0. - && PaliersThermiquesDuPays.maxDownwardPowerRampingRate[index] > 0. - && PaliersThermiquesDuPays.upwardRampingCost[index] >= 0. - && PaliersThermiquesDuPays.downwardRampingCost[index] >= 0.) + if (PaliersThermiquesDuPays.clusterRampingVariablesIndex[index] >= 0) { const int palier = PaliersThermiquesDuPays .NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; diff --git a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp index 748949e259..221f191377 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp @@ -51,22 +51,24 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques(PROB for (int index = 0; index < maxThermalPlant; index++) { - if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] > 0. - && PaliersThermiquesDuPays.maxDownwardPowerRampingRate[index] > 0. - && PaliersThermiquesDuPays.upwardRampingCost[index] >= 0. - && PaliersThermiquesDuPays.downwardRampingCost[index] >= 0.) + if (PaliersThermiquesDuPays.clusterRampingVariablesIndex[index] >= 0) { const int palier = PaliersThermiquesDuPays .NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; + int rampingClusterIndex + = PaliersThermiquesDuPays.clusterRampingVariablesIndex[index]; + int var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; Xmin[var] = 0; - Xmax[var] = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[index] + Xmax[var] + = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[rampingClusterIndex] * PaliersThermiquesDuPays.NombreDePaliersThermiques; var = CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier]; Xmin[var] = 0; - Xmax[var] = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] + Xmax[var] + = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[rampingClusterIndex] * PaliersThermiquesDuPays.NombreDePaliersThermiques; } } diff --git a/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp index 9c85d6a2e1..5e5f1b706b 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp @@ -53,26 +53,26 @@ void OPT_InitialiserLesCoutsLineaireRampesThermiques(PROBLEME_HEBDO* problemeHeb for (int Index = 0; Index < PaliersThermiquesDuPays.NombreDePaliersThermiques; Index++) { - if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[Index] > 0. - && PaliersThermiquesDuPays.maxDownwardPowerRampingRate[Index] > 0. - && PaliersThermiquesDuPays.upwardRampingCost[Index] >= 0. - && PaliersThermiquesDuPays.downwardRampingCost[Index] >= 0.) + if (PaliersThermiquesDuPays.clusterRampingVariablesIndex[Index] >= 0) { int palier = PaliersThermiquesDuPays .NumeroDuPalierDansLEnsembleDesPaliersThermiques[Index]; + int rampingClusterIndex + = PaliersThermiquesDuPays.clusterRampingVariablesIndex[Index]; + var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) { ProblemeAResoudre->CoutLineaire[var] - = PaliersThermiquesDuPays.downwardRampingCost[Index]; + = PaliersThermiquesDuPays.downwardRampingCost[rampingClusterIndex]; } var = CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier]; if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) { ProblemeAResoudre->CoutLineaire[var] - = PaliersThermiquesDuPays.upwardRampingCost[Index]; + = PaliersThermiquesDuPays.upwardRampingCost[rampingClusterIndex]; } } } diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index f0f588b86c..11a9642418 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -182,13 +182,13 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, .assign(linkCount, 0); variablesMapping.NumeroDeVariableCoutExtremiteVersOrigineDeLInterconnexion .assign(linkCount, 0); - - variablesMapping.NumeroDeVariableDuPalierThermique - .assign(study.runtime->thermalPlantTotalCount, 0); + variablesMapping.NumeroDeVariableDuPalierThermique.assign( + study.runtime->thermalPlantTotalCount, 0); variablesMapping.powerRampingIncreaseIndex .assign(study.runtime->thermalPlantTotalCount, 0); variablesMapping.powerRampingDecreaseIndex .assign(study.runtime->thermalPlantTotalCount, 0); + variablesMapping.NumeroDeVariablesDeLaProdHyd .assign(nbPays, 0); variablesMapping.NumeroDeVariablesDePompage @@ -356,7 +356,16 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, for (unsigned k = 0; k < nbPays; k++) { - const uint nbPaliers = study.areas.byIndex[k]->thermal.list.size(); + const uint nbPaliers = study.areas.byIndex[k]->thermal.list.size(); + + // count clusters with ramping enabled + uint nRampingClusters = 0; + for (uint clusterIndex = 0; clusterIndex != nbPaliers; ++clusterIndex) + { + auto& cluster = *(study.areas.byIndex[k]->thermal.list.byIndex[clusterIndex]); + if (cluster.ramping) + nRampingClusters++; + } problem.PaliersThermiquesDuPays[k].minUpDownTime.assign(nbPaliers, 0); problem.PaliersThermiquesDuPays[k].PminDuPalierThermiquePendantUneHeure @@ -384,11 +393,11 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, .assign(nbPaliers, 0); problem.PaliersThermiquesDuPays[k].NomsDesPaliersThermiques.resize(nbPaliers); - problem.PaliersThermiquesDuPays[k].downwardRampingCost.assign( - nbPaliers, 0); - problem.PaliersThermiquesDuPays[k].upwardRampingCost.assign(nbPaliers, 0); - problem.PaliersThermiquesDuPays[k].maxUpwardPowerRampingRate.assign(nbPaliers, 0); - problem.PaliersThermiquesDuPays[k].maxDownwardPowerRampingRate.assign(nbPaliers, 0); + problem.PaliersThermiquesDuPays[k].downwardRampingCost.assign(nRampingClusters, 0); + problem.PaliersThermiquesDuPays[k].upwardRampingCost.assign(nRampingClusters, 0); + problem.PaliersThermiquesDuPays[k].maxUpwardPowerRampingRate.assign(nRampingClusters, 0); + problem.PaliersThermiquesDuPays[k].maxDownwardPowerRampingRate.assign(nRampingClusters, 0); + problem.PaliersThermiquesDuPays[k].clusterRampingVariablesIndex.assign(nbPaliers, -1); problem.CaracteristiquesHydrauliques[k].CntEnergieH2OParIntervalleOptimise .assign(7, 0.); diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index ba85512cf9..91a3c557f3 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -282,6 +282,8 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, auto& pbPalier = problem.PaliersThermiquesDuPays[i]; pbPalier.NombreDePaliersThermiques = area.thermal.list.size(); + uint nRampingCluster = 0; + for (uint clusterIndex = 0; clusterIndex != area.thermal.list.size(); ++clusterIndex) { auto& cluster = *(area.thermal.list.byIndex[clusterIndex]); @@ -304,21 +306,16 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, // ramping (if enabled) if (cluster.ramping) { - pbPalier.upwardRampingCost[clusterIndex] + pbPalier.upwardRampingCost[nRampingCluster] = cluster.ramping.value().powerIncreaseCost; - pbPalier.downwardRampingCost[clusterIndex] + pbPalier.downwardRampingCost[nRampingCluster] = cluster.ramping.value().powerDecreaseCost; - pbPalier.maxDownwardPowerRampingRate[clusterIndex] + pbPalier.maxDownwardPowerRampingRate[nRampingCluster] = cluster.ramping.value().maxDownwardPowerRampingRate; - pbPalier.maxUpwardPowerRampingRate[clusterIndex] + pbPalier.maxUpwardPowerRampingRate[nRampingCluster] = cluster.ramping.value().maxUpwardPowerRampingRate; - } - else - { - pbPalier.upwardRampingCost[clusterIndex] = -1; - pbPalier.downwardRampingCost[clusterIndex] = -1; - pbPalier.maxDownwardPowerRampingRate[clusterIndex] = -1; - pbPalier.maxUpwardPowerRampingRate[clusterIndex] = -1; + pbPalier.clusterRampingVariablesIndex[clusterIndex] = nRampingCluster; + nRampingCluster++; } pbPalier.PmaxDUnGroupeDuPalierThermique[clusterIndex] @@ -329,6 +326,7 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, : cluster.minStablePower; pbPalier.NomsDesPaliersThermiques[clusterIndex] = cluster.name().c_str(); } + pbPalier.numberOfRampingCluster = nRampingCluster; NombrePaliers += area.thermal.list.size(); } diff --git a/src/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/sim_structure_probleme_economique.h index d640954be4..09766047bf 100644 --- a/src/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/sim_structure_probleme_economique.h @@ -297,10 +297,14 @@ struct PALIERS_THERMIQUES std::vector maxUpwardPowerRampingRate; //! maximum hourly downward power ramping rate for a thermal unit (MW/hour) std::vector maxDownwardPowerRampingRate; - //! cost of 1 MW power increase for the thermal cluster (above minimum stable level) + //! cost of 1 MW power increase for the thermal cluster (above minimum stable level) std::vector upwardRampingCost; - //! cost of 1 MW power decrease for the thermal cluster + //! cost of 1 MW power decrease for the thermal cluster std::vector downwardRampingCost; + //! index of the ramping variables for each cluster (or -1 if the ramping is disabled for the cluster) + std::vector clusterRampingVariablesIndex; + //! number of clusters with ramping enabled + int numberOfRampingCluster; }; struct ENERGIES_ET_PUISSANCES_HYDRAULIQUES From 54ef1942f10fa59d4fba95bd41d8f25d8ce2969e Mon Sep 17 00:00:00 2001 From: bencamus Date: Mon, 15 Jan 2024 20:35:34 +0100 Subject: [PATCH 12/22] add ramping costs to the output operational costs of the cluster --- src/solver/variable/state.cpp | 99 +++++++++++++++++++++++++++++++++++ src/solver/variable/state.h | 9 ++++ src/solver/variable/state.hxx | 3 ++ 3 files changed, 111 insertions(+) diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index cb9c6d1448..5656583913 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -212,6 +212,31 @@ void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideInde thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] += thermalCluster->fixedCost * newUnitCount; + // ramping + if (unitCommitmentMode == Antares::Data::UnitCommitmentMode::ucHeuristicAccurate + && thermalCluster->ramping) + { + double startingProduction + = (newUnitCount <= previousUnitCount) + ? 0. + : (newUnitCount - previousUnitCount) + * thermal[area->index].pminOfAGroup[clusterAreaWideIndex]; + double rampingProduction + = p - thermal[area->index].productionLastHour[clusterAreaWideIndex] + - startingProduction; + + if (rampingProduction >= 0) + { + thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] + += rampingProduction * thermalCluster->ramping->powerIncreaseCost; + } + else + { + thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] + += -rampingProduction * thermalCluster->ramping->powerDecreaseCost; + } + } + // Storing the new unit count for the next hour thermal[area->index].unitCountLastHour[clusterAreaWideIndex] = newUnitCount; thermal[area->index].productionLastHour[clusterAreaWideIndex] = p; @@ -354,8 +379,82 @@ void State::yearEndBuildFromThermalClusterIndex(const uint clusterAreaWideIndex) // Calculation of non linear and startup costs yearEndBuildThermalClusterCalculateStartupCosts(maxDurationON, ON_min, ON_opt, currentCluster); + // Calculation of ramping costs + yearEndBuildCalculateRampingCosts(maxDurationON, ON_min, ON_opt, currentCluster); +} + + +void State::yearEndBuildCalculateRampingCosts( + const uint& maxDurationON, + const std::array& ON_min, + const std::array& ON_opt, + const Data::ThermalCluster* currentCluster) +{ + if (unitCommitmentMode == Antares::Data::UnitCommitmentMode::ucHeuristicAccurate + && currentCluster->ramping) + { + uint startHourForCurrentYear = study.runtime->rangeLimits.hour[Data::rangeBegin]; + uint endHourForCurrentYear + = startHourForCurrentYear + study.runtime->rangeLimits.hour[Data::rangeCount]; + // min, and max unit ON calculation + const auto& availableProduction + = currentCluster->series->getAvailablePowerYearly(this->year); + for (uint h = startHourForCurrentYear; h < endHourForCurrentYear; ++h) + { + // Getting available production from cluster data + double thermalClusterAvailableProduction = availableProduction[h]; + uint last_index = (h > startHourForCurrentYear) ? h - 1 : startHourForCurrentYear; + double thermalClusterLastAvailableProduction = availableProduction[last_index]; + double thermalClusterProduction = 0.; + double thermalClusterLastProduction = 0.; + if (currentCluster->mustrun) + { + // When the cluster is in must-run mode, the production value + // directly comes from the time-series + thermalClusterProduction + = thermalClusterAvailableProduction; // in mustrun, production==available + thermalClusterLastProduction = thermalClusterLastAvailableProduction; + // production + } + else + { + // otherwise from the solver results (most of the time) + thermalClusterProduction = thermalClusterProductionForYear[h]; + thermalClusterLastProduction = thermalClusterProductionForYear[last_index]; + } + + double rampingStartupProduction = 0; + + if (h >= startHourForCurrentYear + 1) // starting hour +1 (fron start hour) + { + // nombre de groupes démarrés à l'heure h + int delta + = (maxDurationON == 0) ? ON_min[h] - ON_min[h - 1] : ON_opt[h] - ON_opt[h - 1]; + + rampingStartupProduction = std::max(0, delta) * currentCluster->minStablePower; + } + + double rampingProduction + = thermalClusterProduction - thermalClusterLastProduction - rampingStartupProduction; + + if (rampingProduction >= 0) + { + thermalClusterRampingCostForYear[h] + = rampingProduction * currentCluster->ramping->powerIncreaseCost; + } + else + { + thermalClusterRampingCostForYear[h] + = -rampingProduction * currentCluster->ramping->powerDecreaseCost; + } + thermalClusterOperatingCostForYear[h] += thermalClusterRampingCostForYear[h]; + } + } + } + + void State::yearEndBuildThermalClusterCalculateStartupCosts(const uint& maxDurationON, const std::array& ON_min, const std::array& ON_opt, diff --git a/src/solver/variable/state.h b/src/solver/variable/state.h index 7969a41906..9752a5210c 100644 --- a/src/solver/variable/state.h +++ b/src/solver/variable/state.h @@ -106,6 +106,7 @@ class State void yearEndBuildFromThermalClusterIndex(const unsigned int areaWideIndex); + private: /*! ** \brief Initialize some variable according a thermal cluster index @@ -122,6 +123,12 @@ class State const std::array& ON_opt, const Data::ThermalCluster* currentCluster); + void yearEndBuildCalculateRampingCosts( + const uint& maxDurationON, + const std::array& ON_min, + const std::array& ON_opt, + const Data::ThermalCluster* currentCluster); + std::array computeEconomicallyOptimalNbClustersONforEachHour( const uint& maxDurationON, const std::array& ON_min, @@ -196,6 +203,8 @@ class State double thermalClusterNonProportionalCostForYear[Variable::maxHoursInAYear]; //! Minimum power of the cluster for the whole year double thermalClusterPMinOfTheClusterForYear[Variable::maxHoursInAYear]; + //! Ramping cost of the thermal cluster for the whole year + double thermalClusterRampingCostForYear[Variable::maxHoursInAYear]; double renewableClusterProduction; diff --git a/src/solver/variable/state.hxx b/src/solver/variable/state.hxx index dca9b0a9b5..83be1c2ebe 100644 --- a/src/solver/variable/state.hxx +++ b/src/solver/variable/state.hxx @@ -47,6 +47,9 @@ inline void State::startANewYear() 0, sizeof(thermalClusterDispatchedUnitsCountForYear)); + if (unitCommitmentMode == Antares::Data::UnitCommitmentMode::ucHeuristicAccurate) + memset(thermalClusterRampingCostForYear, 0, sizeof(thermalClusterNonProportionalCostForYear)); + // Re-initializing annual costs (to be printed in output into separate files) annualSystemCost = 0.; optimalSolutionCost1 = 0.; From d8ca6aa94a36980ae51e2b735209d4978f0971d9 Mon Sep 17 00:00:00 2001 From: bencamus Date: Tue, 16 Jan 2024 17:23:29 +0100 Subject: [PATCH 13/22] add dedicated output log for ramping costs --- src/solver/variable/CMakeLists.txt | 2 + src/solver/variable/economy/all.h | 18 +- .../economy/rampingCostByDispatchablePlant.h | 338 ++++++++++++++++++ src/solver/variable/economy/rampingCosts.h | 295 +++++++++++++++ src/solver/variable/state.cpp | 4 + src/solver/variable/state.hxx | 5 +- 6 files changed, 654 insertions(+), 8 deletions(-) create mode 100644 src/solver/variable/economy/rampingCostByDispatchablePlant.h create mode 100644 src/solver/variable/economy/rampingCosts.h diff --git a/src/solver/variable/CMakeLists.txt b/src/solver/variable/CMakeLists.txt index df21955781..16039e81d4 100644 --- a/src/solver/variable/CMakeLists.txt +++ b/src/solver/variable/CMakeLists.txt @@ -127,6 +127,8 @@ set(SRC_VARIABLE_ECONOMY economy/lolp.h economy/avail-dispatchable-generation.h economy/dispatchable-generation-margin.h + economy/rampingCosts.h + economy/rampingCostByDispatchablePlant.h # Links economy/links/flowLinear.h diff --git a/src/solver/variable/economy/all.h b/src/solver/variable/economy/all.h index b961c8dbf7..95cfb95f31 100644 --- a/src/solver/variable/economy/all.h +++ b/src/solver/variable/economy/all.h @@ -66,6 +66,7 @@ #include "spilledEnergyAfterCSR.h" #include "dtgMarginAfterCsr.h" #include "spilledEnergy.h" +#include "rampingCosts.h" #include "lold.h" #include "lolp.h" @@ -79,6 +80,7 @@ #include "npCostByDispatchablePlant.h" #include "nbOfDispatchedUnitsByPlant.h" #include "profitByPlant.h" +#include "rampingCostByDispatchablePlant.h" // By RES plant #include "productionByRenewablePlant.h" @@ -173,10 +175,12 @@ typedef // Prices >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VariablesPerArea; /*! @@ -266,12 +270,14 @@ typedef // Prices // Number Of Dispatched Units Common::SpatialAggregate< - NbOfDispatchedUnits // MBO + NbOfDispatchedUnits, // MBO // 25/02/2016 // - // refs: // #55 - >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + Common::SpatialAggregate< + RampingCost + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VariablesPerSetOfAreas; typedef BindingConstMarginCost< // Marginal cost for a binding constraint diff --git a/src/solver/variable/economy/rampingCostByDispatchablePlant.h b/src/solver/variable/economy/rampingCostByDispatchablePlant.h new file mode 100644 index 0000000000..11f90d24b5 --- /dev/null +++ b/src/solver/variable/economy/rampingCostByDispatchablePlant.h @@ -0,0 +1,338 @@ +/* +** 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_RampingCostByDispatchablePlant_H__ +#define __SOLVER_VARIABLE_ECONOMY_RampingCostByDispatchablePlant_H__ + +#include "../variable.h" + +namespace Antares +{ +namespace Solver +{ +namespace Variable +{ +namespace Economy +{ +struct VCardRampingCostByDispatchablePlant +{ + //! Caption + static std::string Caption() + { + return "RAMP COST by plant"; + } + //! Unit + static std::string Unit() + { + return "Ramping Cost - Euro"; + } + + //! The short description of the variable + static std::string Description() + { + return "Ramping costs by all the clusters"; + } + + //! The expected results + typedef Results> + ResultsType; + + //! The VCard to look for for calculating spatial aggregates + typedef VCardRampingCostByDispatchablePlant 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 RampingCostByDispatchablePlant + : public Variable::IVariable, + NextT, + VCardRampingCostByDispatchablePlant> +{ +public: + //! Type of the next static variable + typedef NextT NextType; + //! VCard + typedef VCardRampingCostByDispatchablePlant 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: + RampingCostByDispatchablePlant() : pValuesForTheCurrentYear(NULL), pSize(0) + { + } + + ~RampingCostByDispatchablePlant() + { + 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.clusterCount(); + 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.thermalClusterRampingCostForYear[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.clusters[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 RampingCostByDispatchablePlant + +} // namespace Economy +} // namespace Variable +} // namespace Solver +} // namespace Antares + +#endif // __SOLVER_VARIABLE_ECONOMY_RampingCostByDispatchablePlant_H__ diff --git a/src/solver/variable/economy/rampingCosts.h b/src/solver/variable/economy/rampingCosts.h new file mode 100644 index 0000000000..6c08859bea --- /dev/null +++ b/src/solver/variable/economy/rampingCosts.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_RampingCost_H__ +#define __SOLVER_VARIABLE_ECONOMY_RampingCost_H__ + +#include "../variable.h" + +namespace Antares +{ +namespace Solver +{ +namespace Variable +{ +namespace Economy +{ +struct VCardRampingCost +{ + //! Caption + static std::string Caption() + { + return "RAMP COST"; + } + //! Unit + static std::string Unit() + { + return "Euro"; + } + + //! The short description of the variable + static std::string Description() + { + return "Ramping 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 VCardRampingCost 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 RampingCost + : public Variable::IVariable, NextT, VCardRampingCost> +{ +public: + //! Type of the next static variable + typedef NextT NextType; + //! VCard + typedef VCardRampingCost 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: + ~RampingCost() + { + 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.thermalClusterRampingCostForYear[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_RampingCost_H__ diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index 5656583913..81191ce4ba 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -441,11 +441,15 @@ void State::yearEndBuildCalculateRampingCosts( { thermalClusterRampingCostForYear[h] = rampingProduction * currentCluster->ramping->powerIncreaseCost; + logs.info() << " power increase cost = " + << currentCluster->ramping->powerIncreaseCost; } else { thermalClusterRampingCostForYear[h] = -rampingProduction * currentCluster->ramping->powerDecreaseCost; + logs.info() << " power decrease cost = " + << currentCluster->ramping->powerDecreaseCost; } thermalClusterOperatingCostForYear[h] += thermalClusterRampingCostForYear[h]; } diff --git a/src/solver/variable/state.hxx b/src/solver/variable/state.hxx index 83be1c2ebe..af25686dc2 100644 --- a/src/solver/variable/state.hxx +++ b/src/solver/variable/state.hxx @@ -47,8 +47,8 @@ inline void State::startANewYear() 0, sizeof(thermalClusterDispatchedUnitsCountForYear)); - if (unitCommitmentMode == Antares::Data::UnitCommitmentMode::ucHeuristicAccurate) - memset(thermalClusterRampingCostForYear, 0, sizeof(thermalClusterNonProportionalCostForYear)); + //if (unitCommitmentMode == Antares::Data::UnitCommitmentMode::ucHeuristicAccurate) + memset(thermalClusterRampingCostForYear, 0, sizeof(thermalClusterRampingCostForYear)); // Re-initializing annual costs (to be printed in output into separate files) annualSystemCost = 0.; @@ -69,6 +69,7 @@ inline void State::yearEndResetThermal() memset(thermalClusterDispatchedUnitsCountForYear, 0, sizeof(thermalClusterDispatchedUnitsCountForYear)); + memset(thermalClusterRampingCostForYear, 0, sizeof(thermalClusterRampingCostForYear)); } inline void State::initFromAreaIndex(const unsigned int areaIndex, uint numSpace) From d1f983c61267de52377958a1efba7863ff6380d7 Mon Sep 17 00:00:00 2001 From: bencamus Date: Thu, 29 Feb 2024 17:34:14 +0100 Subject: [PATCH 14/22] implementation of a new version of the ramping equations --- .../optimisation/constraints/PowerOutputVariation.cpp | 9 +++++---- .../optimisation/constraints/RampingIncreaseRate.cpp | 8 ++++---- .../opt_gestion_des_bornes_rampes_thermiques.cpp | 6 ------ src/solver/variable/state.cpp | 4 ---- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/solver/optimisation/constraints/PowerOutputVariation.cpp b/src/solver/optimisation/constraints/PowerOutputVariation.cpp index d175c1fceb..cd507e9bbb 100644 --- a/src/solver/optimisation/constraints/PowerOutputVariation.cpp +++ b/src/solver/optimisation/constraints/PowerOutputVariation.cpp @@ -9,14 +9,15 @@ void PowerOutputVariation::add(int pays, int cluster, int clusterIndex, int pdt, = PaliersThermiquesDuPays.clusterRampingVariablesIndex[clusterIndex]; double maxUpwardPowerRampingRate = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[rampingClusterIndex]; - double pminDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.pminDUnGroupeDuPalierThermique[clusterIndex]; - // constraint : P(t) - P(t-1) - l * M^+(t) - P^+ + P^- = 0 + double pmaxDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.PmaxDUnGroupeDuPalierThermique[clusterIndex]; + // constraint : P(t) - P(t-1) - u * M^+(t) - P^+ + P^- + u * M^-(t) = 0 builder.updateHourWithinWeek(pdt) .DispatchableProduction(cluster, 1.0) .DispatchableProduction(cluster, -1.0, -1, problemeHebdo->NombreDePasDeTempsPourUneOptimisation) - .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) + .NumberStartingDispatchableUnits(cluster, -pmaxDUnGroupeDuPalierThermique) .ProductionIncreaseAboveMin(cluster, -1.0) - .ProductionDecreaseAboveMin(cluster, 1.0) + .ProductionDecreaseAboveMin(cluster, 1.0) + .NumberStoppingDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) .equalTo(); if (builder.NumberOfVariables() > 0) diff --git a/src/solver/optimisation/constraints/RampingIncreaseRate.cpp b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp index 03093df1d5..bde7acc0f7 100644 --- a/src/solver/optimisation/constraints/RampingIncreaseRate.cpp +++ b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp @@ -9,16 +9,16 @@ void RampingIncreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, = PaliersThermiquesDuPays.clusterRampingVariablesIndex[clusterIndex]; double maxUpwardPowerRampingRate = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[rampingClusterIndex]; - double pminDUnGroupeDuPalierThermique - = PaliersThermiquesDuPays.pminDUnGroupeDuPalierThermique[clusterIndex]; - // constraint : P(t) - P(t-1) - R^+ * M(t) - l * M^+(t) < 0 + double pmaxDUnGroupeDuPalierThermique + = PaliersThermiquesDuPays.PmaxDUnGroupeDuPalierThermique[clusterIndex]; + // constraint : P(t) - P(t-1) - R^+ * M(t) - u * M^+(t) < 0 builder.updateHourWithinWeek(pdt) .DispatchableProduction(cluster, 1.0) .DispatchableProduction( cluster, -1.0, -1, problemeHebdo->NombreDePasDeTempsPourUneOptimisation) .NumberOfDispatchableUnits(cluster, -maxUpwardPowerRampingRate) - .NumberStartingDispatchableUnits(cluster, -pminDUnGroupeDuPalierThermique) + .NumberStartingDispatchableUnits(cluster, -pmaxDUnGroupeDuPalierThermique) .lessThan(); if (builder.NumberOfVariables() > 0) diff --git a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp index 221f191377..9622d47feb 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp @@ -61,15 +61,9 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques(PROB int var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; Xmin[var] = 0; - Xmax[var] - = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[rampingClusterIndex] - * PaliersThermiquesDuPays.NombreDePaliersThermiques; var = CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier]; Xmin[var] = 0; - Xmax[var] - = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[rampingClusterIndex] - * PaliersThermiquesDuPays.NombreDePaliersThermiques; } } } diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index 81191ce4ba..5656583913 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -441,15 +441,11 @@ void State::yearEndBuildCalculateRampingCosts( { thermalClusterRampingCostForYear[h] = rampingProduction * currentCluster->ramping->powerIncreaseCost; - logs.info() << " power increase cost = " - << currentCluster->ramping->powerIncreaseCost; } else { thermalClusterRampingCostForYear[h] = -rampingProduction * currentCluster->ramping->powerDecreaseCost; - logs.info() << " power decrease cost = " - << currentCluster->ramping->powerDecreaseCost; } thermalClusterOperatingCostForYear[h] += thermalClusterRampingCostForYear[h]; } From 70ba5832ac2a843485f0d2d6d7b5b0ccd7125785 Mon Sep 17 00:00:00 2001 From: bencamus Date: Wed, 6 Mar 2024 16:34:11 +0100 Subject: [PATCH 15/22] fixing a bug in the definition of the ramping variables bounds + freezing the NODU variables during the second optimization step for the cluster with ramping --- .../opt_gestion_des_bornes_rampes_thermiques.cpp | 4 ++++ ...opt_nombre_min_groupes_demarres_couts_demarrage.cpp | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp index 9622d47feb..3c2b322694 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp @@ -61,9 +61,13 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques(PROB int var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; Xmin[var] = 0; + Xmax[var] = LINFINI_ANTARES; + var = CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier]; Xmin[var] = 0; + Xmax[var] = LINFINI_ANTARES; + } } } 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 59742b94f6..2e0a33746b 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 @@ -174,6 +174,9 @@ void OPT_AjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO* pro } NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo] = (int)ceil(X); + /* logs.info() + << " Nombre de groupe en marche = " + << NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo] << " avant = " << X;*/ } if (!problemeHebdo->OptimisationAvecVariablesEntieres) @@ -181,10 +184,15 @@ void OPT_AjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO* pro OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage( problemeHebdo, NombreMinDeGroupesEnMarcheDuPalierThermique, pays, index); + int ramp = PaliersThermiquesDuPays.clusterRampingVariablesIndex[index]; + + for (int pdtHebdo = 0; pdtHebdo < NombreDePasDeTempsProblemeHebdo; pdtHebdo++) { + // When using the ramping model, we must ensure that the NODU don't change during the 2nd optimization. + // Without this, the solver may bypass the ramping constraints by partially starting/stopping units. if (NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo] - < NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo]) + < NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo] || ramp >= 0) NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo] = NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo]; From 7387013fa403bd616d7471ff172b0c2fae135181 Mon Sep 17 00:00:00 2001 From: sylvmara Date: Thu, 7 Mar 2024 10:22:10 +0100 Subject: [PATCH 16/22] Supression of clusterRampingVariablesIndex and standardisation of the problemhebdo constrainst vectors length --- .../constraints/PowerOutputVariation.cpp | 2 -- .../constraints/RampingDecreaseRate.cpp | 4 +--- .../constraints/RampingIncreaseRate.cpp | 2 -- ...t_construction_contraintes_rampes_thermiques.cpp | 2 +- ...opt_construction_variables_rampes_thermiques.cpp | 2 +- .../opt_gestion_des_bornes_rampes_thermiques.cpp | 5 +---- .../opt_gestion_des_couts_rampes_thermiques.cpp | 13 +++++-------- src/solver/simulation/sim_alloc_probleme_hebdo.cpp | 9 ++++----- src/solver/simulation/sim_calcul_economique.cpp | 12 ++++-------- .../simulation/sim_structure_probleme_economique.h | 4 ---- 10 files changed, 17 insertions(+), 38 deletions(-) diff --git a/src/solver/optimisation/constraints/PowerOutputVariation.cpp b/src/solver/optimisation/constraints/PowerOutputVariation.cpp index cd507e9bbb..2d7d3195c5 100644 --- a/src/solver/optimisation/constraints/PowerOutputVariation.cpp +++ b/src/solver/optimisation/constraints/PowerOutputVariation.cpp @@ -5,8 +5,6 @@ void PowerOutputVariation::add(int pays, int cluster, int clusterIndex, int pdt, if (!Simulation) { const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; - int rampingClusterIndex - = PaliersThermiquesDuPays.clusterRampingVariablesIndex[clusterIndex]; double maxUpwardPowerRampingRate = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[rampingClusterIndex]; double pmaxDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.PmaxDUnGroupeDuPalierThermique[clusterIndex]; diff --git a/src/solver/optimisation/constraints/RampingDecreaseRate.cpp b/src/solver/optimisation/constraints/RampingDecreaseRate.cpp index 738dcb4d88..3c6eb69c25 100644 --- a/src/solver/optimisation/constraints/RampingDecreaseRate.cpp +++ b/src/solver/optimisation/constraints/RampingDecreaseRate.cpp @@ -5,10 +5,8 @@ void RampingDecreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, if (!Simulation) { const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; - int rampingClusterIndex - = PaliersThermiquesDuPays.clusterRampingVariablesIndex[clusterIndex]; double maxDownwardPowerRampingRate - = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[rampingClusterIndex]; + = PaliersThermiquesDuPays.maxDownwardPowerRampingRate[clusterIndex]; double pmaxDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.PmaxDUnGroupeDuPalierThermique[clusterIndex]; // constraint : P(t) - P(t-1) + R^- * M(t) + u * M^-(t) + u * M^--(t) > 0 builder.updateHourWithinWeek(pdt) diff --git a/src/solver/optimisation/constraints/RampingIncreaseRate.cpp b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp index bde7acc0f7..dfb4a0f5c8 100644 --- a/src/solver/optimisation/constraints/RampingIncreaseRate.cpp +++ b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp @@ -5,8 +5,6 @@ void RampingIncreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, if (!Simulation) { const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; - int rampingClusterIndex - = PaliersThermiquesDuPays.clusterRampingVariablesIndex[clusterIndex]; double maxUpwardPowerRampingRate = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[rampingClusterIndex]; double pmaxDUnGroupeDuPalierThermique diff --git a/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp b/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp index 883ef387b6..1584c9dd15 100644 --- a/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp @@ -25,7 +25,7 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireRampesThermiques(PRO constraintNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) { - if (PaliersThermiquesDuPays.clusterRampingVariablesIndex[index] >= 0) + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] != -1) { RampingIncreaseRate rampingIncreaseRate(problemeHebdo); RampingDecreaseRate rampingDecreaseRate(problemeHebdo); diff --git a/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp index be2a195859..9f6b1aab6a 100644 --- a/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp @@ -26,7 +26,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireRampesThermiqu variableNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) { - if (PaliersThermiquesDuPays.clusterRampingVariablesIndex[index] >= 0) + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] != -1) { const int palier = PaliersThermiquesDuPays .NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; diff --git a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp index 3c2b322694..85ec67bdeb 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp @@ -51,14 +51,11 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques(PROB for (int index = 0; index < maxThermalPlant; index++) { - if (PaliersThermiquesDuPays.clusterRampingVariablesIndex[index] >= 0) + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] != -1) { const int palier = PaliersThermiquesDuPays .NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; - int rampingClusterIndex - = PaliersThermiquesDuPays.clusterRampingVariablesIndex[index]; - int var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; Xmin[var] = 0; Xmax[var] = LINFINI_ANTARES; diff --git a/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp index 5e5f1b706b..b6ff1b8378 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp @@ -51,28 +51,25 @@ void OPT_InitialiserLesCoutsLineaireRampesThermiques(PROBLEME_HEBDO* problemeHeb const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; int var; - for (int Index = 0; Index < PaliersThermiquesDuPays.NombreDePaliersThermiques; Index++) + for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) { - if (PaliersThermiquesDuPays.clusterRampingVariablesIndex[Index] >= 0) + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] != -1) { int palier = PaliersThermiquesDuPays - .NumeroDuPalierDansLEnsembleDesPaliersThermiques[Index]; - - int rampingClusterIndex - = PaliersThermiquesDuPays.clusterRampingVariablesIndex[Index]; + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; var = CorrespondanceVarNativesVarOptim.powerRampingDecreaseIndex[palier]; if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) { ProblemeAResoudre->CoutLineaire[var] - = PaliersThermiquesDuPays.downwardRampingCost[rampingClusterIndex]; + = PaliersThermiquesDuPays.downwardRampingCost[index]; } var = CorrespondanceVarNativesVarOptim.powerRampingIncreaseIndex[palier]; if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) { ProblemeAResoudre->CoutLineaire[var] - = PaliersThermiquesDuPays.upwardRampingCost[rampingClusterIndex]; + = PaliersThermiquesDuPays.upwardRampingCost[index]; } } } diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index 11a9642418..bac58d3c0e 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -393,11 +393,10 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, .assign(nbPaliers, 0); problem.PaliersThermiquesDuPays[k].NomsDesPaliersThermiques.resize(nbPaliers); - problem.PaliersThermiquesDuPays[k].downwardRampingCost.assign(nRampingClusters, 0); - problem.PaliersThermiquesDuPays[k].upwardRampingCost.assign(nRampingClusters, 0); - problem.PaliersThermiquesDuPays[k].maxUpwardPowerRampingRate.assign(nRampingClusters, 0); - problem.PaliersThermiquesDuPays[k].maxDownwardPowerRampingRate.assign(nRampingClusters, 0); - problem.PaliersThermiquesDuPays[k].clusterRampingVariablesIndex.assign(nbPaliers, -1); + problem.PaliersThermiquesDuPays[k].downwardRampingCost.assign(nbPaliers, -1); + problem.PaliersThermiquesDuPays[k].upwardRampingCost.assign(nbPaliers, -1); + problem.PaliersThermiquesDuPays[k].maxUpwardPowerRampingRate.assign(nbPaliers, -1); + problem.PaliersThermiquesDuPays[k].maxDownwardPowerRampingRate.assign(nbPaliers, -1); problem.CaracteristiquesHydrauliques[k].CntEnergieH2OParIntervalleOptimise .assign(7, 0.); diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 91a3c557f3..c86719b191 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -282,7 +282,6 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, auto& pbPalier = problem.PaliersThermiquesDuPays[i]; pbPalier.NombreDePaliersThermiques = area.thermal.list.size(); - uint nRampingCluster = 0; for (uint clusterIndex = 0; clusterIndex != area.thermal.list.size(); ++clusterIndex) { @@ -306,16 +305,14 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, // ramping (if enabled) if (cluster.ramping) { - pbPalier.upwardRampingCost[nRampingCluster] + pbPalier.upwardRampingCost[clusterIndex] = cluster.ramping.value().powerIncreaseCost; - pbPalier.downwardRampingCost[nRampingCluster] + pbPalier.downwardRampingCost[clusterIndex] = cluster.ramping.value().powerDecreaseCost; - pbPalier.maxDownwardPowerRampingRate[nRampingCluster] + pbPalier.maxDownwardPowerRampingRate[clusterIndex] = cluster.ramping.value().maxDownwardPowerRampingRate; - pbPalier.maxUpwardPowerRampingRate[nRampingCluster] + pbPalier.maxUpwardPowerRampingRate[clusterIndex] = cluster.ramping.value().maxUpwardPowerRampingRate; - pbPalier.clusterRampingVariablesIndex[clusterIndex] = nRampingCluster; - nRampingCluster++; } pbPalier.PmaxDUnGroupeDuPalierThermique[clusterIndex] @@ -326,7 +323,6 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, : cluster.minStablePower; pbPalier.NomsDesPaliersThermiques[clusterIndex] = cluster.name().c_str(); } - pbPalier.numberOfRampingCluster = nRampingCluster; NombrePaliers += area.thermal.list.size(); } diff --git a/src/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/sim_structure_probleme_economique.h index 09766047bf..f6610775f9 100644 --- a/src/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/sim_structure_probleme_economique.h @@ -301,10 +301,6 @@ struct PALIERS_THERMIQUES std::vector upwardRampingCost; //! cost of 1 MW power decrease for the thermal cluster std::vector downwardRampingCost; - //! index of the ramping variables for each cluster (or -1 if the ramping is disabled for the cluster) - std::vector clusterRampingVariablesIndex; - //! number of clusters with ramping enabled - int numberOfRampingCluster; }; struct ENERGIES_ET_PUISSANCES_HYDRAULIQUES From ab1b701e5caf785a776416662338b4fe63e745cb Mon Sep 17 00:00:00 2001 From: sylvmara Date: Thu, 7 Mar 2024 10:40:03 +0100 Subject: [PATCH 17/22] Harmonisation of ramp checking --- src/solver/optimisation/constraints/PowerOutputVariation.cpp | 2 +- src/solver/optimisation/constraints/RampingIncreaseRate.cpp | 2 +- .../opt_construction_contraintes_rampes_thermiques.cpp | 2 +- .../opt_construction_variables_rampes_thermiques.cpp | 2 +- .../optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp | 2 +- .../optimisation/opt_gestion_des_couts_rampes_thermiques.cpp | 2 +- .../opt_nombre_min_groupes_demarres_couts_demarrage.cpp | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/solver/optimisation/constraints/PowerOutputVariation.cpp b/src/solver/optimisation/constraints/PowerOutputVariation.cpp index 2d7d3195c5..7ca5ae2362 100644 --- a/src/solver/optimisation/constraints/PowerOutputVariation.cpp +++ b/src/solver/optimisation/constraints/PowerOutputVariation.cpp @@ -6,7 +6,7 @@ void PowerOutputVariation::add(int pays, int cluster, int clusterIndex, int pdt, { const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; double maxUpwardPowerRampingRate - = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[rampingClusterIndex]; + = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[clusterIndex]; double pmaxDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.PmaxDUnGroupeDuPalierThermique[clusterIndex]; // constraint : P(t) - P(t-1) - u * M^+(t) - P^+ + P^- + u * M^-(t) = 0 builder.updateHourWithinWeek(pdt) diff --git a/src/solver/optimisation/constraints/RampingIncreaseRate.cpp b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp index dfb4a0f5c8..836ed1c7f9 100644 --- a/src/solver/optimisation/constraints/RampingIncreaseRate.cpp +++ b/src/solver/optimisation/constraints/RampingIncreaseRate.cpp @@ -6,7 +6,7 @@ void RampingIncreaseRate::add(int pays, int cluster, int clusterIndex, int pdt, { const PALIERS_THERMIQUES& PaliersThermiquesDuPays = problemeHebdo->PaliersThermiquesDuPays[pays]; double maxUpwardPowerRampingRate - = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[rampingClusterIndex]; + = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[clusterIndex]; double pmaxDUnGroupeDuPalierThermique = PaliersThermiquesDuPays.PmaxDUnGroupeDuPalierThermique[clusterIndex]; // constraint : P(t) - P(t-1) - R^+ * M(t) - u * M^+(t) < 0 diff --git a/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp b/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp index 1584c9dd15..9d38045f29 100644 --- a/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp @@ -25,7 +25,7 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireRampesThermiques(PRO constraintNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) { - if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] != -1) + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] >= 0 ) { RampingIncreaseRate rampingIncreaseRate(problemeHebdo); RampingDecreaseRate rampingDecreaseRate(problemeHebdo); diff --git a/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp index 9f6b1aab6a..ad65a58889 100644 --- a/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_construction_variables_rampes_thermiques.cpp @@ -26,7 +26,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireRampesThermiqu variableNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) { - if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] != -1) + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] >= 0 ) { const int palier = PaliersThermiquesDuPays .NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; diff --git a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp index 85ec67bdeb..0cc6db212c 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_rampes_thermiques.cpp @@ -51,7 +51,7 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireRampesThermiques(PROB for (int index = 0; index < maxThermalPlant; index++) { - if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] != -1) + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] >= 0) { const int palier = PaliersThermiquesDuPays .NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; diff --git a/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp b/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp index b6ff1b8378..bc026be48f 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_rampes_thermiques.cpp @@ -53,7 +53,7 @@ void OPT_InitialiserLesCoutsLineaireRampesThermiques(PROBLEME_HEBDO* problemeHeb for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) { - if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] != -1) + if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] >= 0 ) { int palier = PaliersThermiquesDuPays .NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; 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 2e0a33746b..e9590e4bac 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 @@ -184,7 +184,7 @@ void OPT_AjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO* pro OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage( problemeHebdo, NombreMinDeGroupesEnMarcheDuPalierThermique, pays, index); - int ramp = PaliersThermiquesDuPays.clusterRampingVariablesIndex[index]; + int ramp = PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index]; for (int pdtHebdo = 0; pdtHebdo < NombreDePasDeTempsProblemeHebdo; pdtHebdo++) @@ -192,7 +192,7 @@ void OPT_AjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO* pro // When using the ramping model, we must ensure that the NODU don't change during the 2nd optimization. // Without this, the solver may bypass the ramping constraints by partially starting/stopping units. if (NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo] - < NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo] || ramp >= 0) + < NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo] || ramp >= 0 ) NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo] = NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo]; From 50f7a489fb8a3f2ace0c2c5ae19861d4a4e8bd39 Mon Sep 17 00:00:00 2001 From: bencamus Date: Fri, 12 Apr 2024 16:44:40 +0200 Subject: [PATCH 18/22] removing ramping files that are useless with the last version of Antares --- .../opt_construction_contraintes_rampes.h | 4 -- ...truction_contraintes_rampes_thermiques.cpp | 46 ------------------- 2 files changed, 50 deletions(-) delete mode 100644 src/solver/optimisation/opt_construction_contraintes_rampes.h delete mode 100644 src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp diff --git a/src/solver/optimisation/opt_construction_contraintes_rampes.h b/src/solver/optimisation/opt_construction_contraintes_rampes.h deleted file mode 100644 index 566bdf27ac..0000000000 --- a/src/solver/optimisation/opt_construction_contraintes_rampes.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -class opt_construction_contraintes_rampes -{ -}; diff --git a/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp b/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp deleted file mode 100644 index 9d38045f29..0000000000 --- a/src/solver/optimisation/opt_construction_contraintes_rampes_thermiques.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "opt_structure_probleme_a_resoudre.h" - -#include "../simulation/sim_structure_donnees.h" -#include "../simulation/sim_structure_probleme_economique.h" - -#include "opt_fonctions.h" -#include "opt_rename_problem.h" -#include "constraints/RampingDecreaseRate.h" -#include "constraints/RampingIncreaseRate.h" -#include "constraints/PowerOutputVariation.h" - -#include - -void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireRampesThermiques(PROBLEME_HEBDO* problemeHebdo, bool Simulation) -{ - int nombreDePasDeTempsPourUneOptimisation = problemeHebdo->NombreDePasDeTempsPourUneOptimisation; - const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; - - ConstraintNamer constraintNamer(ProblemeAResoudre->NomDesContraintes); - - for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) - { - const PALIERS_THERMIQUES& PaliersThermiquesDuPays - = problemeHebdo->PaliersThermiquesDuPays[pays]; - constraintNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); - for (int index = 0; index < PaliersThermiquesDuPays.NombreDePaliersThermiques; index++) - { - if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] >= 0 ) - { - RampingIncreaseRate rampingIncreaseRate(problemeHebdo); - RampingDecreaseRate rampingDecreaseRate(problemeHebdo); - PowerOutputVariation powerOutputVariation(problemeHebdo); - - const int palier - = PaliersThermiquesDuPays.NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; - - for (int pdt = 0; pdt < nombreDePasDeTempsPourUneOptimisation; pdt++) - { - rampingIncreaseRate.add(pays, palier, index, pdt, Simulation); - rampingDecreaseRate.add(pays, palier, index, pdt, Simulation); - powerOutputVariation.add(pays, palier, index, pdt, Simulation); - } - } - } - } -} \ No newline at end of file From 554455d01bbc2d1d290d8ee6d4574eb9eb3a3666 Mon Sep 17 00:00:00 2001 From: bencamus Date: Tue, 16 Apr 2024 11:57:43 +0200 Subject: [PATCH 19/22] changing constraint equation related to power output variation of the ramping model to fix issue with ramping behavior + update of the output ramping cost to be aligned with the constraints --- src/solver/optimisation/CMakeLists.txt | 6 +- .../PowerOutputVariationDecrease.cpp | 38 ++++++++++ .../constraints/PowerOutputVariationGroup.cpp | 7 +- ...n.cpp => PowerOutputVariationIncrease.cpp} | 12 ++- .../PowerOutputVariationDecrease.h | 26 +++++++ .../constraints/PowerOutputVariationGroup.h | 3 +- ...ation.h => PowerOutputVariationIncrease.h} | 4 +- src/solver/variable/state.cpp | 75 +++++++++++-------- 8 files changed, 125 insertions(+), 46 deletions(-) create mode 100644 src/solver/optimisation/constraints/PowerOutputVariationDecrease.cpp rename src/solver/optimisation/constraints/{PowerOutputVariation.cpp => PowerOutputVariationIncrease.cpp} (76%) create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariationDecrease.h rename src/solver/optimisation/include/antares/solver/optimisation/constraints/{PowerOutputVariation.h => PowerOutputVariationIncrease.h} (76%) diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index 13ca855ee1..8f224d66e6 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -135,8 +135,10 @@ set(RTESOLVER_OPT constraints/RampingIncreaseRate.cpp include/antares/solver/optimisation/constraints/RampingDecreaseRate.h constraints/RampingDecreaseRate.cpp - include/antares/solver/optimisation/constraints/PowerOutputVariation.h - constraints/PowerOutputVariation.cpp + include/antares/solver/optimisation/constraints/PowerOutputVariationIncrease.h + constraints/PowerOutputVariationIncrease.cpp + include/antares/solver/optimisation/constraints/PowerOutputVariationDecrease.h + constraints/PowerOutputVariationDecrease.cpp include/antares/solver/optimisation/ProblemMatrixEssential.h ProblemMatrixEssential.cpp diff --git a/src/solver/optimisation/constraints/PowerOutputVariationDecrease.cpp b/src/solver/optimisation/constraints/PowerOutputVariationDecrease.cpp new file mode 100644 index 0000000000..ebad68ae28 --- /dev/null +++ b/src/solver/optimisation/constraints/PowerOutputVariationDecrease.cpp @@ -0,0 +1,38 @@ +#include "antares/solver/optimisation/constraints/PowerOutputVariationDecrease.h" + +void PowerOutputVariationDecrease::add(int pays, int index, int pdt) +{ + if (!data.Simulation) + { + int cluster = data.PaliersThermiquesDuPays[pays] + .NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; + double pmaxDUnGroupeDuPalierThermique + = data.PaliersThermiquesDuPays[pays].PmaxDUnGroupeDuPalierThermique[index]; + // constraint : P(t) - P(t-1) + P^- + u * M^-(t) >= 0 + builder.updateHourWithinWeek(pdt) + .DispatchableProduction(cluster, 1.0) + .DispatchableProduction( + cluster, -1.0, -1, builder.data.NombreDePasDeTempsPourUneOptimisation) + .ProductionDecreaseAboveMin(cluster, 1.0) + .NumberStoppingDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) + .greaterThan(); + + if (builder.NumberOfVariables() > 0) + { + ConstraintNamer namer(builder.data.NomDesContraintes); + + namer.UpdateTimeStep(builder.data.weekInTheYear * 168 + pdt); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + + namer.ProductionOutputVariation( + builder.data.nombreDeContraintes, + data.PaliersThermiquesDuPays[pays].NomsDesPaliersThermiques[index]); + } + builder.build(); + } + else + { + builder.data.NbTermesContraintesPourLesRampes += 4; + builder.data.nombreDeContraintes++; + } +} diff --git a/src/solver/optimisation/constraints/PowerOutputVariationGroup.cpp b/src/solver/optimisation/constraints/PowerOutputVariationGroup.cpp index aec175ff25..c6c0a9713a 100644 --- a/src/solver/optimisation/constraints/PowerOutputVariationGroup.cpp +++ b/src/solver/optimisation/constraints/PowerOutputVariationGroup.cpp @@ -38,11 +38,14 @@ void PowerOutputVariationGroup::BuildConstraints() { if (PaliersThermiquesDuPays.maxUpwardPowerRampingRate[index] >= 0) { - PowerOutputVariation powerOutputVariation(builder_, data); + PowerOutputVariationIncrease powerOutputVariationIncrease(builder_, data); + PowerOutputVariationDecrease powerOutputVariationDecrease(builder_, data); + for (int pdt = 0; pdt < problemeHebdo_->NombreDePasDeTempsPourUneOptimisation; pdt++) { - powerOutputVariation.add(pays, index, pdt); + powerOutputVariationIncrease.add(pays, index, pdt); + powerOutputVariationDecrease.add(pays, index, pdt); } } } diff --git a/src/solver/optimisation/constraints/PowerOutputVariation.cpp b/src/solver/optimisation/constraints/PowerOutputVariationIncrease.cpp similarity index 76% rename from src/solver/optimisation/constraints/PowerOutputVariation.cpp rename to src/solver/optimisation/constraints/PowerOutputVariationIncrease.cpp index ba700f6c1d..ca098c6fc4 100644 --- a/src/solver/optimisation/constraints/PowerOutputVariation.cpp +++ b/src/solver/optimisation/constraints/PowerOutputVariationIncrease.cpp @@ -1,21 +1,19 @@ -#include "antares/solver/optimisation/constraints/PowerOutputVariation.h" +#include "antares/solver/optimisation/constraints/PowerOutputVariationIncrease.h" -void PowerOutputVariation::add(int pays, int index, int pdt) +void PowerOutputVariationIncrease::add(int pays, int index, int pdt) { if (!data.Simulation) { int cluster = data.PaliersThermiquesDuPays[pays].NumeroDuPalierDansLEnsembleDesPaliersThermiques[index]; double pmaxDUnGroupeDuPalierThermique = data.PaliersThermiquesDuPays[pays].PmaxDUnGroupeDuPalierThermique[index]; - // constraint : P(t) - P(t-1) - u * M^+(t) - P^+ + P^- + u * M^-(t) = 0 + // constraint : P(t) - P(t-1) - u * M^+(t) - P^+ <= 0 builder.updateHourWithinWeek(pdt) .DispatchableProduction(cluster, 1.0) .DispatchableProduction(cluster, -1.0, -1, builder.data.NombreDePasDeTempsPourUneOptimisation) .NumberStartingDispatchableUnits(cluster, -pmaxDUnGroupeDuPalierThermique) .ProductionIncreaseAboveMin(cluster, -1.0) - .ProductionDecreaseAboveMin(cluster, 1.0) - .NumberStoppingDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) - .equalTo(); + .lessThan(); if (builder.NumberOfVariables() > 0) { @@ -32,7 +30,7 @@ void PowerOutputVariation::add(int pays, int index, int pdt) } else { - builder.data.NbTermesContraintesPourLesRampes += 5; + builder.data.NbTermesContraintesPourLesRampes += 4; builder.data.nombreDeContraintes++; } } diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariationDecrease.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariationDecrease.h new file mode 100644 index 0000000000..d5695b64af --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariationDecrease.h @@ -0,0 +1,26 @@ +#pragma once +#include "ConstraintBuilder.h" + +/*! + * represent 'RampingIncreaseRate' Constraint type + */ +class PowerOutputVariationDecrease : private ConstraintFactory +{ +public: + PowerOutputVariationDecrease(ConstraintBuilder& builder, StartUpCostsData& 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 Simulation : --- + */ + void add(int pays, int index, int pdt); + +private: + StartUpCostsData& data; +}; \ No newline at end of file diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariationGroup.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariationGroup.h index 6caa2be653..060348afc4 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariationGroup.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariationGroup.h @@ -22,7 +22,8 @@ #pragma once #include "AbstractStartUpCostsGroup.h" #include "ConstraintGroup.h" -#include "PowerOutputVariation.h" +#include "PowerOutputVariationIncrease.h" +#include "PowerOutputVariationDecrease.h" /** * @brief Group of PowerOutputVariationGroup constraints diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariation.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariationIncrease.h similarity index 76% rename from src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariation.h rename to src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariationIncrease.h index a7e6855c4c..5cddb40b68 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariation.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/PowerOutputVariationIncrease.h @@ -4,10 +4,10 @@ /*! * represent 'RampingIncreaseRate' Constraint type */ -class PowerOutputVariation : private ConstraintFactory +class PowerOutputVariationIncrease : private ConstraintFactory { public: - PowerOutputVariation(ConstraintBuilder& builder, StartUpCostsData& data) : + PowerOutputVariationIncrease(ConstraintBuilder& builder, StartUpCostsData& data) : ConstraintFactory(builder), data(data) { } diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index 4547becc2c..79364458e2 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -203,25 +203,28 @@ void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideInde if (unitCommitmentMode == Antares::Data::UnitCommitmentMode::ucHeuristicAccurate && thermalCluster->ramping) { - double startingProduction - = (newUnitCount <= previousUnitCount) - ? 0. - : (newUnitCount - previousUnitCount) - * thermal[area->index].pminOfAGroup[clusterAreaWideIndex]; - double rampingProduction - = p - thermal[area->index].productionLastHour[clusterAreaWideIndex] - - startingProduction; - - if (rampingProduction >= 0) - { - thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] - += rampingProduction * thermalCluster->ramping->powerIncreaseCost; - } - else - { + double startingStoppingProduction + = (newUnitCount - previousUnitCount) + * thermalCluster->nominalCapacityWithSpinning; + + double startingProduction = std::max(0., startingStoppingProduction); + double stoppingProduction = std::max(0., -startingStoppingProduction); + + double rampingIncrease + = std::max(p - thermal[area->index].productionLastHour[clusterAreaWideIndex] + - startingProduction, + 0.); + + double rampingDecrease + = std::max(thermal[area->index].productionLastHour[clusterAreaWideIndex] - p + - stoppingProduction, + 0.); + + thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] + += rampingIncrease * thermalCluster->ramping->powerIncreaseCost; + thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] - += -rampingProduction * thermalCluster->ramping->powerDecreaseCost; - } + += rampingDecrease * thermalCluster->ramping->powerDecreaseCost; } // Storing the new unit count for the next hour @@ -408,7 +411,8 @@ void State::yearEndBuildCalculateRampingCosts( thermalClusterLastProduction = thermalClusterProductionForYear[last_index]; } - double rampingStartupProduction = 0; + double startingStoppingProduction + = 0.; if (h >= startHourForCurrentYear + 1) // starting hour +1 (fron start hour) { @@ -416,22 +420,29 @@ void State::yearEndBuildCalculateRampingCosts( int delta = (maxDurationON == 0) ? ON_min[h] - ON_min[h - 1] : ON_opt[h] - ON_opt[h - 1]; - rampingStartupProduction = std::max(0, delta) * currentCluster->minStablePower; + startingStoppingProduction = delta + * currentCluster->nominalCapacityWithSpinning; + } + double startingProduction = std::max(0., startingStoppingProduction); + double stoppingProduction = std::max(0., -startingStoppingProduction); - double rampingProduction - = thermalClusterProduction - thermalClusterLastProduction - rampingStartupProduction; + double rampingIncrease = std::max( + thermalClusterProduction - thermalClusterLastProduction + - startingProduction, + 0.); + + double rampingDecrease = std::max( + thermalClusterLastProduction - thermalClusterProduction + - stoppingProduction, + 0.); + + thermalClusterRampingCostForYear[h] + = rampingIncrease * currentCluster->ramping->powerIncreaseCost; + + thermalClusterRampingCostForYear[h] + += rampingDecrease * currentCluster->ramping->powerDecreaseCost; - if (rampingProduction >= 0) - { - thermalClusterRampingCostForYear[h] - = rampingProduction * currentCluster->ramping->powerIncreaseCost; - } - else - { - thermalClusterRampingCostForYear[h] - = -rampingProduction * currentCluster->ramping->powerDecreaseCost; - } thermalClusterOperatingCostForYear[h] += thermalClusterRampingCostForYear[h]; } } From 3625bd26eb93f39421e7152b68154d7f6cd8df1a Mon Sep 17 00:00:00 2001 From: Florian OMNES Date: Fri, 3 May 2024 16:22:30 +0200 Subject: [PATCH 20/22] Temporarily enable build for CentOS7 --- .github/workflows/centos7.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/centos7.yml b/.github/workflows/centos7.yml index a2f6452ed1..4211f7fea3 100644 --- a/.github/workflows/centos7.yml +++ b/.github/workflows/centos7.yml @@ -5,6 +5,7 @@ on: types: [created] push: branches: + - feature/ramping_model_scalian - develop - dependabot/* From 44f722d9369f73c59e9d9e7244ef145804015019 Mon Sep 17 00:00:00 2001 From: bencamus Date: Wed, 15 May 2024 16:25:55 +0200 Subject: [PATCH 21/22] changing the variable caption from RAMP COST by plant to RAMP COST BY PLANT --- .../solver/variable/economy/rampingCostByDispatchablePlant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/variable/include/antares/solver/variable/economy/rampingCostByDispatchablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/rampingCostByDispatchablePlant.h index 634f824510..f0444326d2 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/rampingCostByDispatchablePlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/rampingCostByDispatchablePlant.h @@ -42,7 +42,7 @@ struct VCardRampingCostByDispatchablePlant //! Caption static std::string Caption() { - return "RAMP COST by plant"; + return "RAMP COST BY PLANT"; } //! Unit static std::string Unit() From e41d0b88f74f04a5965e2f2a970b740bd5943d91 Mon Sep 17 00:00:00 2001 From: bencamus Date: Mon, 26 Aug 2024 11:19:29 +0200 Subject: [PATCH 22/22] update the ramping constraint 18ter to remove breaking down thermal units as it is already included in the starting thermal units term --- src/solver/optimisation/constraints/RampingDecreaseRate.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/solver/optimisation/constraints/RampingDecreaseRate.cpp b/src/solver/optimisation/constraints/RampingDecreaseRate.cpp index 5021db5f77..972e62cc6c 100644 --- a/src/solver/optimisation/constraints/RampingDecreaseRate.cpp +++ b/src/solver/optimisation/constraints/RampingDecreaseRate.cpp @@ -16,7 +16,6 @@ void RampingDecreaseRate::add(int pays, int index, int pdt) .DispatchableProduction(cluster, -1.0, -1, builder.data.NombreDePasDeTempsPourUneOptimisation) .NumberOfDispatchableUnits(cluster, maxDownwardPowerRampingRate) .NumberStoppingDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) - .NumberBreakingDownDispatchableUnits(cluster, pmaxDUnGroupeDuPalierThermique) .greaterThan(); if (builder.NumberOfVariables() > 0)