diff --git a/src/libs/antares/study/CMakeLists.txt b/src/libs/antares/study/CMakeLists.txt index 29a89fc631..e7336d020c 100644 --- a/src/libs/antares/study/CMakeLists.txt +++ b/src/libs/antares/study/CMakeLists.txt @@ -74,8 +74,8 @@ set(SRC_STUDY_PART_THERMAL include/antares/study/parts/thermal/cost_provider.h include/antares/study/parts/thermal/cluster.hxx parts/thermal/cluster.cpp - parts/thermal/scenarized_cost_provider.cpp - parts/thermal/constant_cost_provider.cpp + parts/thermal/scenarized_cost_provider.cpp + parts/thermal/constant_cost_provider.cpp include/antares/study/parts/thermal/cluster_list.h parts/thermal/cluster_list.cpp include/antares/study/parts/thermal/pollutant.h @@ -102,7 +102,9 @@ set(SRC_STUDY_PART_SHORT_TERM_STORAGE parts/short-term-storage/series.cpp include/antares/study/parts/short-term-storage/series.h include/antares/study/parts/short-term-storage/cluster.h + include/antares/study/parts/short-term-storage/AdditionalConstraint.h parts/short-term-storage/cluster.cpp + parts/short-term-storage/AdditionalConstraint.cpp ) source_group("study\\part\\short-term-storage" FILES ${SRC_STUDY_PART_SHORT_TERM_SOTRAGE}) @@ -306,12 +308,12 @@ target_link_libraries(study ) target_include_directories(study - PUBLIC + PUBLIC $ # Make more than just study visible but it's the lesser evil for now ) -install(DIRECTORY include/antares +install(DIRECTORY include/antares DESTINATION "include" ) diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index cf2624515f..7af3a6a5a7 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -1199,6 +1199,7 @@ bool AreaList::loadFromFolder(const StudyLoadOptions& options) fs::path folder = stsFolder / "clusters" / area->id.c_str(); ret = area->shortTermStorage.createSTStorageClustersFromIniFile(folder) && ret; + ret = area->shortTermStorage.LoadConstraintsFromIniFile(folder) && ret; } } else diff --git a/src/libs/antares/study/include/antares/study/parts/short-term-storage/AdditionalConstraint.h b/src/libs/antares/study/include/antares/study/parts/short-term-storage/AdditionalConstraint.h new file mode 100644 index 0000000000..e16b991a05 --- /dev/null +++ b/src/libs/antares/study/include/antares/study/parts/short-term-storage/AdditionalConstraint.h @@ -0,0 +1,53 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once +#include +#include + +namespace Antares::Data::ShortTermStorage +{ + +struct AdditionalConstraint +{ + std::string name; + std::string cluster_id; + std::string variable; + std::string operatorType; + std::set hours; + double rhs; + + unsigned int globalIndex = 0; + + struct ValidateResult + { + bool ok; + std::string error_msg; + }; + + ValidateResult validate() const; + +private: + bool isValidVariable() const; + bool isValidOperatorType() const; + bool isValidHoursRange() const; +}; +} // namespace Antares::Data::ShortTermStorage diff --git a/src/libs/antares/study/include/antares/study/parts/short-term-storage/cluster.h b/src/libs/antares/study/include/antares/study/parts/short-term-storage/cluster.h index b4074a28c8..df74a350b0 100644 --- a/src/libs/antares/study/include/antares/study/parts/short-term-storage/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/short-term-storage/cluster.h @@ -26,6 +26,7 @@ #include +#include "AdditionalConstraint.h" #include "properties.h" #include "series.h" @@ -35,17 +36,21 @@ class STStorageCluster { public: bool enabled() const; + bool validate() const; bool loadFromSection(const IniFile::Section& section); + bool loadSeries(const std::filesystem::path& folder) const; void saveProperties(IniFile& ini) const; + bool saveSeries(const std::string& path) const; std::string id; std::shared_ptr series = std::make_shared(); mutable Properties properties; + std::vector additional_constraints; }; } // namespace Antares::Data::ShortTermStorage diff --git a/src/libs/antares/study/include/antares/study/parts/short-term-storage/container.h b/src/libs/antares/study/include/antares/study/parts/short-term-storage/container.h index 90f8fafbce..d4e0233b5c 100644 --- a/src/libs/antares/study/include/antares/study/parts/short-term-storage/container.h +++ b/src/libs/antares/study/include/antares/study/parts/short-term-storage/container.h @@ -21,9 +21,9 @@ #pragma once #include -#include #include +#include "AdditionalConstraint.h" #include "cluster.h" namespace Antares::Data::ShortTermStorage @@ -32,18 +32,28 @@ class STStorageInput { public: bool validate() const; + /// 1. Read list.ini bool createSTStorageClustersFromIniFile(const std::filesystem::path& path); + /// 2. Read ALL series bool loadSeriesFromFolder(const std::filesystem::path& folder) const; + /// Number of enabled ST storages, ignoring disabled ST storages std::size_t count() const; + + bool LoadConstraintsFromIniFile(const std::filesystem::path& filePath); + /// erase disabled cluster from the vector uint removeDisabledClusters(); bool saveToFolder(const std::string& folder) const; + bool saveDataSeriesToFolder(const std::string& folder) const; std::vector storagesByIndex; + + /// Number cumulative - constraint + std::size_t cumulativeConstraintCount() const; }; } // namespace Antares::Data::ShortTermStorage diff --git a/src/libs/antares/study/include/antares/study/runtime/runtime.h b/src/libs/antares/study/include/antares/study/runtime/runtime.h index 858719ab27..fe394199df 100644 --- a/src/libs/antares/study/include/antares/study/runtime/runtime.h +++ b/src/libs/antares/study/include/antares/study/runtime/runtime.h @@ -110,6 +110,7 @@ class StudyRuntimeInfos uint thermalPlantTotalCountMustRun; uint shortTermStorageCount = 0; + uint shortTermStorageCumulativeConstraintCount = 0; //! Override enable/disable TS generation per cluster bool thermalTSRefresh = false; diff --git a/src/libs/antares/study/parts/short-term-storage/AdditionalConstraint.cpp b/src/libs/antares/study/parts/short-term-storage/AdditionalConstraint.cpp new file mode 100644 index 0000000000..2ca904041c --- /dev/null +++ b/src/libs/antares/study/parts/short-term-storage/AdditionalConstraint.cpp @@ -0,0 +1,65 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#include "antares/study/parts/short-term-storage/AdditionalConstraint.h" + +namespace Antares::Data::ShortTermStorage +{ +AdditionalConstraint::ValidateResult AdditionalConstraint::validate() const +{ + if (cluster_id.empty()) + { + return {false, "Cluster ID is empty."}; + } + + if (!isValidVariable()) + { + return {false, "Invalid variable type. Must be 'injection', 'withdrawal', or 'netting'."}; + } + + if (!isValidOperatorType()) + { + return {false, "Invalid operator type. Must be 'less', 'equal', or 'greater'."}; + } + + if (!isValidHoursRange()) + { + return {false, "Hours set contains invalid values. Must be between 1 and 168."}; + } + + return {true, ""}; +} + +bool AdditionalConstraint::isValidHoursRange() const +{ + // `hours` is a sorted set; begin() gives the smallest and prev(end()) gives the largest. + return !hours.empty() && *hours.begin() >= 1 && *std::prev(hours.end()) <= 168; +} + +bool AdditionalConstraint::isValidVariable() const +{ + return variable == "injection" || variable == "withdrawal" || variable == "netting"; +} + +bool AdditionalConstraint::isValidOperatorType() const +{ + return operatorType == "less" || operatorType == "equal" || operatorType == "greater"; +} +} // namespace Antares::Data::ShortTermStorage diff --git a/src/libs/antares/study/parts/short-term-storage/cluster.cpp b/src/libs/antares/study/parts/short-term-storage/cluster.cpp index 787d1c85e6..cbfb7e679f 100644 --- a/src/libs/antares/study/parts/short-term-storage/cluster.cpp +++ b/src/libs/antares/study/parts/short-term-storage/cluster.cpp @@ -28,7 +28,6 @@ namespace Antares::Data::ShortTermStorage { - bool STStorageCluster::loadFromSection(const IniFile::Section& section) { if (!section.firstProperty) @@ -92,5 +91,4 @@ bool STStorageCluster::saveSeries(const std::string& path) const { return series->saveToFolder(path); } - } // namespace Antares::Data::ShortTermStorage diff --git a/src/libs/antares/study/parts/short-term-storage/container.cpp b/src/libs/antares/study/parts/short-term-storage/container.cpp index bee1546ec4..39a958c5c7 100644 --- a/src/libs/antares/study/parts/short-term-storage/container.cpp +++ b/src/libs/antares/study/parts/short-term-storage/container.cpp @@ -22,11 +22,13 @@ #include "antares/study/parts/short-term-storage/container.h" #include +#include #include #include #include +#include #define SEP Yuni::IO::Separator @@ -73,6 +75,83 @@ bool STStorageInput::createSTStorageClustersFromIniFile(const fs::path& path) return true; } +bool STStorageInput::LoadConstraintsFromIniFile(const fs::path& parent_path) +{ + IniFile ini; + const auto pathIni = parent_path / "additional-constraints.ini"; + if (!ini.open(pathIni, false)) + { + logs.info() << "There is no: " << pathIni; + return true; + } + + for (auto* section = ini.firstSection; section; section = section->next) + { + AdditionalConstraint constraint; + constraint.name = section->name.c_str(); + for (auto* property = section->firstProperty; property; property = property->next) + { + const std::string key = property->key; + const auto value = property->value; + + if (key == "cluster") + { + // TODO do i have to transform the name to id? TransformNameIntoID + std::string clusterName; + value.to(clusterName); + constraint.cluster_id = transformNameIntoID(clusterName); + } + else if (key == "variable") + { + value.to(constraint.variable); + } + else if (key == "operator") + { + value.to(constraint.operatorType); + } + else if (key == "hours") + { + std::stringstream ss(value.c_str()); + std::string hour; + while (std::getline(ss, hour, ',')) + { + int hourVal = std::stoi(hour); + constraint.hours.insert(hourVal); + } + } + else if (key == "rhs") + { + property->value.to(constraint.rhs); + } + } + + if (auto ret = constraint.validate(); !ret.ok) + { + logs.error() << "Invalid constraint in section: " << section->name; + logs.error() << ret.error_msg; + return false; + } + + auto it = std::find_if(storagesByIndex.begin(), + storagesByIndex.end(), + [&constraint](const STStorageCluster& cluster) + { return cluster.id == constraint.cluster_id; }); + if (it == storagesByIndex.end()) + { + logs.warning() << " from file " << pathIni; + logs.warning() << "Constraint " << section->name + << " does not reference an existing cluster"; + return false; + } + else + { + it->additional_constraints.push_back(constraint); + } + } + + return true; +} + bool STStorageInput::loadSeriesFromFolder(const fs::path& folder) const { if (folder.empty()) @@ -113,6 +192,15 @@ bool STStorageInput::saveDataSeriesToFolder(const std::string& folder) const { return storage.saveSeries(folder + SEP + storage.id); }); } +std::size_t STStorageInput::cumulativeConstraintCount() const +{ + return std::accumulate(storagesByIndex.begin(), + storagesByIndex.end(), + 0, + [](int acc, const auto& cluster) + { return acc + cluster.additional_constraints.size(); }); +} + std::size_t STStorageInput::count() const { return std::ranges::count_if(storagesByIndex, @@ -123,5 +211,4 @@ uint STStorageInput::removeDisabledClusters() { return std::erase_if(storagesByIndex, [](const auto& c) { return !c.enabled(); }); } - } // namespace Antares::Data::ShortTermStorage diff --git a/src/libs/antares/study/runtime/runtime.cpp b/src/libs/antares/study/runtime/runtime.cpp index 3bca4404a5..32bfb0f28e 100644 --- a/src/libs/antares/study/runtime/runtime.cpp +++ b/src/libs/antares/study/runtime/runtime.cpp @@ -94,6 +94,8 @@ static void StudyRuntimeInfosInitializeAllAreas(Study& study, StudyRuntimeInfos& r.thermalPlantTotalCountMustRun += area.thermal.list.enabledAndMustRunCount(); r.shortTermStorageCount += area.shortTermStorage.count(); + r.shortTermStorageCumulativeConstraintCount += area.shortTermStorage + .cumulativeConstraintCount(); } } @@ -363,6 +365,8 @@ bool StudyRuntimeInfos::loadFromStudy(Study& study) logs.info() << " thermal clusters: " << thermalPlantTotalCount; logs.info() << " thermal clusters (must-run): " << thermalPlantTotalCountMustRun; logs.info() << " short-term storages: " << shortTermStorageCount; + logs.info() << " short-term storage cumulative constraints count: " + << shortTermStorageCumulativeConstraintCount; logs.info() << " binding constraints: " << study.bindingConstraints.activeConstraints().size(); logs.info() << " geographic trimming:" << (gd.geographicTrimming ? "true" : "false"); diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index 57194b388a..ec98f298e8 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -82,7 +82,9 @@ set(RTESOLVER_OPT include/antares/solver/optimisation/constraints/ShortTermStorageLevel.h constraints/ShortTermStorageLevel.cpp include/antares/solver/optimisation/constraints/ShortTermStorageCostVariation.h + include/antares/solver/optimisation/constraints/ShortTermStorageCumulation.h constraints/ShortTermStorageCostVariation.cpp + constraints/ShortTermStorageCumulation.cpp constraints/ShortTermStorageCostVariationInjectionForward.cpp constraints/ShortTermStorageCostVariationInjectionBackward.cpp constraints/ShortTermStorageCostVariationWithdrawalForward.cpp diff --git a/src/solver/optimisation/constraints/Group1.cpp b/src/solver/optimisation/constraints/Group1.cpp index 810b957aee..61de7cf2b3 100644 --- a/src/solver/optimisation/constraints/Group1.cpp +++ b/src/solver/optimisation/constraints/Group1.cpp @@ -22,6 +22,7 @@ #include "antares/solver/optimisation/constraints/Group1.h" #include "antares/solver/optimisation/constraints/ShortTermStorageCostVariation.h" +#include "antares/solver/optimisation/constraints/ShortTermStorageCumulation.h" AreaBalanceData Group1::GetAreaBalanceData() { @@ -49,6 +50,13 @@ ShortTermStorageData Group1::GetShortTermStorageData() }; } +ShortTermStorageCumulativeConstraintData Group1::GetShortTermStorageCumulativeConstraintData() +{ + return {problemeHebdo_->CorrespondanceCntNativesCntOptim, + problemeHebdo_->ShortTermStorage, + problemeHebdo_->CorrespondanceCntNativesCntOptimHebdomadaires}; +} + FlowDissociationData Group1::GetFlowDissociationData() { return {.CorrespondanceCntNativesCntOptim = problemeHebdo_->CorrespondanceCntNativesCntOptim, @@ -89,6 +97,11 @@ void Group1::BuildConstraints() ShortTermStorageCostVariationWithdrawalForward shortTermStorageCostVariationWithdrawalForward( builder_, shortTermStorageData); + + auto shortTermStorageCumulativeConstraintData = GetShortTermStorageCumulativeConstraintData(); + ShortTermStorageCumulation shortTermStorageCumulation(builder_, + shortTermStorageCumulativeConstraintData); + auto flowDissociationData = GetFlowDissociationData(); FlowDissociation flowDissociation(builder_, flowDissociationData); @@ -123,4 +136,9 @@ void Group1::BuildConstraints() bindingConstraintHour.add(pdt, cntCouplante); } } + + for (uint32_t pays = 0; pays < problemeHebdo_->NombreDePays; ++pays) + { + shortTermStorageCumulation.add(pays); + } } diff --git a/src/solver/optimisation/constraints/ShortTermStorageCumulation.cpp b/src/solver/optimisation/constraints/ShortTermStorageCumulation.cpp new file mode 100644 index 0000000000..f6e684db83 --- /dev/null +++ b/src/solver/optimisation/constraints/ShortTermStorageCumulation.cpp @@ -0,0 +1,157 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include "antares/solver/optimisation/constraints/ShortTermStorageCumulation.h" + +#include +#include + +class CumulationConstraint +{ +public: + virtual void build(ConstraintBuilder& builder, + unsigned int index, + const ::ShortTermStorage::PROPERTIES& input) const + = 0; + virtual std::string name() const = 0; + virtual ~CumulationConstraint() = default; +}; + +class WithdrawalCumulationConstraint: public CumulationConstraint +{ +public: + void build(ConstraintBuilder& builder, + unsigned int index, + const ::ShortTermStorage::PROPERTIES&) const override + { + builder.ShortTermStorageWithdrawal(index, 1.0); + } + + std::string name() const override + { + return "WithdrawalSum"; + } + + ~WithdrawalCumulationConstraint() override = default; +}; + +class InjectionCumulationConstraint: public CumulationConstraint +{ +public: + void build(ConstraintBuilder& builder, + unsigned int index, + const ::ShortTermStorage::PROPERTIES&) const override + { + builder.ShortTermStorageInjection(index, 1.0); + } + + std::string name() const override + { + return "InjectionSum"; + } + + ~InjectionCumulationConstraint() override = default; +}; + +class NettingCumulationConstraint: public CumulationConstraint +{ +public: + void build(ConstraintBuilder& builder, + unsigned int index, + const ::ShortTermStorage::PROPERTIES& input) const override + { + builder.ShortTermStorageInjection(index, input.injectionEfficiency) + .ShortTermStorageWithdrawal(index, -input.withdrawalEfficiency); + } + + std::string name() const override + { + return "NettingSum"; + } + + ~NettingCumulationConstraint() override = default; +}; + +std::unique_ptr cumulationConstraintFromVariable(const std::string& variable) +{ + if (variable == "withdrawal") + { + return std::make_unique(); + } + else if (variable == "injection") + { + return std::make_unique(); + } + else if (variable == "netting") + { + return std::make_unique(); + } + throw std::invalid_argument("Invalid cumulation constraint type"); +} + +char ConvertSense(const std::string& sense) +{ + if (sense == "greater") + { + return '>'; + } + else if (sense == "less") + { + return '<'; + } + else + { + return '='; + } +} + +void ShortTermStorageCumulation::add(int pays) +{ + ConstraintNamer namer(builder.data.NomDesContraintes); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + + for (const auto& storage: data.ShortTermStorage[pays]) + { + for (const auto& constraint: storage.additional_constraints) + { + // sum (var[h]) sign rhs, h in list provided by user where: + // var = injection for InjectionCumulationConstraint + // var = withdrawal for WithdrawalCumulationConstraint + // var = injectionEfficiency * injection - withdrawalEfficiency * withdrawal for Netting + auto constraintHelper = cumulationConstraintFromVariable(constraint.variable); + namer.ShortTermStorageCumulation(constraintHelper->name(), + builder.data.nombreDeContraintes, + storage.name, + constraint.name); + const auto index = storage.clusterGlobalIndex; + data.CorrespondanceCntNativesCntOptimHebdomadaires + .ShortTermStorageCumulation[constraint.globalIndex] + = builder.data.nombreDeContraintes; + + for (const auto& hour: constraint.hours) + { + builder.updateHourWithinWeek(hour - 1); + constraintHelper->build(builder, index, storage); + } + builder.SetOperator(ConvertSense(constraint.operatorType)).build(); + } + } +} diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h index b06af4614d..31019332d3 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h @@ -305,3 +305,8 @@ struct ShortTermStorageData const std::vector<::ShortTermStorage::AREA_INPUT>& ShortTermStorage; }; + +struct ShortTermStorageCumulativeConstraintData: ShortTermStorageData +{ + CORRESPONDANCES_DES_CONTRAINTES_HEBDOMADAIRES& CorrespondanceCntNativesCntOptimHebdomadaires; +}; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/Group1.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/Group1.h index e5134edb6e..c74567716e 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/Group1.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/Group1.h @@ -38,6 +38,9 @@ class Group1: public ConstraintGroup AreaBalanceData GetAreaBalanceData(); FictitiousLoadData GetFictitiousLoadData(); ShortTermStorageData GetShortTermStorageData(); + + ShortTermStorageCumulativeConstraintData GetShortTermStorageCumulativeConstraintData(); + FlowDissociationData GetFlowDissociationData(); BindingConstraintHourData GetBindingConstraintHourData(); }; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageCumulation.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageCumulation.h new file mode 100644 index 0000000000..2c4c540158 --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageCumulation.h @@ -0,0 +1,39 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once +#include "ConstraintBuilder.h" + +class ShortTermStorageCumulation: ConstraintFactory +{ +public: + ShortTermStorageCumulation(ConstraintBuilder& builder, + ShortTermStorageCumulativeConstraintData& data): + ConstraintFactory(builder), + data(data) + { + } + + void add(int pays); + +private: + ShortTermStorageCumulativeConstraintData& data; +}; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h index f05b6eb15a..c7c3dff284 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_rename_problem.h @@ -166,6 +166,11 @@ class ConstraintNamer: public Namer unsigned int constraint, const std::string& short_term_name); + void ShortTermStorageCumulation(const std::string& constraint_type, + unsigned int constraint, + const std::string& short_term_name, + const std::string& constraint_name); + private: void nameWithTimeGranularity(unsigned int constraint, const std::string& name, @@ -177,6 +182,11 @@ inline std::string TimeIdentifier(unsigned int timeStep, const std::string& time return timeStepType + "<" + std::to_string(timeStep) + ">"; } +inline std::string ShortTermStorageCumulationIdentifier(const std::string& name) +{ + return "Constraint<" + name + ">"; +} + inline std::string LocationIdentifier(const std::string& location, const std::string& locationType) { return locationType + "<" + location + ">"; diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp index d1a0f00ea2..79c29c58ab 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp @@ -144,12 +144,12 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* ProblemeAResoudre->NombreDeContraintes += 2; /* 2 constraints bounding the overall energy generated over the period (10a in the reference document) */ - ProblemeAResoudre - ->NombreDeContraintes++; /* 1 constraint setting the level variation over the period - (10b in the reference document) */ - ProblemeAResoudre - ->NombreDeContraintes++; /* 1 constraint bounding the overall energy pumped over the - period (10c in the reference document) */ + ProblemeAResoudre->NombreDeContraintes++; + /* 1 constraint setting the level variation over the period + (10b in the reference document) */ + ProblemeAResoudre->NombreDeContraintes++; + /* 1 constraint bounding the overall energy pumped over the + period (10c in the reference document) */ } if (!Pump && TurbEntreBornes && !MonitorHourlyLev) @@ -192,16 +192,16 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* ProblemeAResoudre->NombreDeContraintes += 2; /* 2 constraints bounding the overall energy generated over the period (10a in the reference document) */ - ProblemeAResoudre - ->NombreDeContraintes++; /* 1 constraint setting the level variation over the period - (10b in the reference document) */ - ProblemeAResoudre - ->NombreDeContraintes++; /* 1 constraint bounding the overall energy pumped over the - period (10c in the reference document) */ - ProblemeAResoudre->NombreDeContraintes - += nombreDePasDeTempsPourUneOptimisation; /* T constraints expressing the level hourly - variations (14a in the reference - document) */ + ProblemeAResoudre->NombreDeContraintes++; + /* 1 constraint setting the level variation over the period + (10b in the reference document) */ + ProblemeAResoudre->NombreDeContraintes++; + /* 1 constraint bounding the overall energy pumped over the + period (10c in the reference document) */ + ProblemeAResoudre->NombreDeContraintes += nombreDePasDeTempsPourUneOptimisation; + /* T constraints expressing the level hourly + variations (14a in the reference + document) */ } if (!Pump && !TurbEntreBornes && MonitorHourlyLev) { @@ -245,6 +245,10 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* ProblemeAResoudre->NombreDeContraintes += 2 * nombreDePasDeTempsPourUneOptimisation; } + if (!storage.additional_constraints.empty()) + { + ProblemeAResoudre->NombreDeContraintes += storage.additional_constraints.size(); + } } } } diff --git a/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp b/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp index 36bb303964..c04d416f00 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp @@ -43,6 +43,26 @@ static void shortTermStorageLevelsRHS( } } +static void shortTermStorageCumulationRHS( + const std::vector<::ShortTermStorage::AREA_INPUT>& shortTermStorageInput, + int numberOfAreas, + std::vector& SecondMembre, + const CORRESPONDANCES_DES_CONTRAINTES_HEBDOMADAIRES& CorrespondancesDesContraintesHebdomadaires) +{ + for (int areaIndex = 0; areaIndex < numberOfAreas; areaIndex++) + { + for (auto& storage: shortTermStorageInput[areaIndex]) + { + for (const auto& constraint: storage.additional_constraints) + { + int cnt = CorrespondancesDesContraintesHebdomadaires + .ShortTermStorageCumulation[constraint.globalIndex]; + SecondMembre[cnt] = constraint.rhs; + } + } + } +} + void OPT_InitialiserLeSecondMembreDuProblemeLineaire(PROBLEME_HEBDO* problemeHebdo, int PremierPdtDeLIntervalle, int DernierPdtDeLIntervalle, @@ -145,7 +165,6 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaire(PROBLEME_HEBDO* problemeHeb ProblemeAResoudre->SecondMembre, CorrespondanceCntNativesCntOptim, hourInTheYear); - for (uint32_t interco = 0; interco < problemeHebdo->NombreDInterconnexions; interco++) { if (const COUTS_DE_TRANSPORT& CoutDeTransport = problemeHebdo->CoutDeTransport[interco]; @@ -377,6 +396,10 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaire(PROBLEME_HEBDO* problemeHeb } } + shortTermStorageCumulationRHS(problemeHebdo->ShortTermStorage, + problemeHebdo->NombreDePays, + ProblemeAResoudre->SecondMembre, + problemeHebdo->CorrespondanceCntNativesCntOptimHebdomadaires); if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) { OPT_InitialiserLeSecondMembreDuProblemeLineaireCoutsDeDemarrage(problemeHebdo, diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index a92553e5e6..b385c0f8f5 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -35,9 +35,9 @@ const std::string AREA("area"); std::string BuildName(const std::string& name, const std::string& location, - const std::string& timeIdentifier) + const std::string& additional_identifier) { - std::string result = name + SEPARATOR + location + SEPARATOR + timeIdentifier; + std::string result = name + SEPARATOR + location + SEPARATOR + additional_identifier; std::replace(result.begin(), result.end(), ' ', '*'); return result; } @@ -414,3 +414,16 @@ void ConstraintNamer::ShortTermStorageCostVariation(const std::string& constrain TimeIdentifier(timeStep_, HOUR)), constraint); } + +void ConstraintNamer::ShortTermStorageCumulation(const std::string& constraint_type, + unsigned int constraint, + const std::string& short_term_name, + const std::string& constraint_name) +{ + targetUpdater_.UpdateTargetAtIndex( + BuildName(constraint_type, + LocationIdentifier(area_, AREA) + SEPARATOR + "ShortTermStorage" + "<" + + short_term_name + ">", + ShortTermStorageCumulationIdentifier(constraint_name)), + constraint); +} diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_alloc_probleme_hebdo.h b/src/solver/simulation/include/antares/solver/simulation/sim_alloc_probleme_hebdo.h index f1ed9bca0c..a4517115a8 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_alloc_probleme_hebdo.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_alloc_probleme_hebdo.h @@ -39,6 +39,8 @@ void SIM_AllocationLinks(PROBLEME_HEBDO& problem, void SIM_AllocationConstraints(PROBLEME_HEBDO& problem, const Antares::Data::Study& study, unsigned NombreDePasDeTemps); +void SIM_AllocationShortermStorageCumulation(PROBLEME_HEBDO& problem, + const Antares::Data::Study& study); void SIM_AllocateAreas(PROBLEME_HEBDO& problem, const Antares::Data::Study& study, diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index d24fb25bc4..35051ba2d5 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -111,6 +111,7 @@ struct CORRESPONDANCES_DES_CONTRAINTES_JOURNALIERES struct CORRESPONDANCES_DES_CONTRAINTES_HEBDOMADAIRES { std::vector NumeroDeContrainteDesContraintesCouplantes; + std::vector ShortTermStorageCumulation; }; struct VALEURS_DE_NTC_ET_RESISTANCES @@ -182,7 +183,7 @@ struct PROPERTIES bool penalizeVariationInjection; std::shared_ptr series; - + std::vector additional_constraints; int clusterGlobalIndex; std::string name; }; diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index d735191ff7..78785f0fd3 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -38,6 +38,7 @@ void SIM_AllocationProblemeHebdo(const Data::Study& study, SIM_AllocationProblemePasDeTemps(problem, study, NombreDePasDeTemps); SIM_AllocationLinks(problem, study.runtime.interconnectionsCount(), NombreDePasDeTemps); SIM_AllocationConstraints(problem, study, NombreDePasDeTemps); + SIM_AllocationShortermStorageCumulation(problem, study); SIM_AllocateAreas(problem, study, NombreDePasDeTemps); } catch (const std::bad_alloc& e) @@ -245,6 +246,13 @@ void SIM_AllocationLinks(PROBLEME_HEBDO& problem, const uint linkCount, unsigned } } +void SIM_AllocationShortermStorageCumulation(PROBLEME_HEBDO& problem, + const Antares::Data::Study& study) +{ + problem.CorrespondanceCntNativesCntOptimHebdomadaires.ShortTermStorageCumulation + .assign(study.runtime.shortTermStorageCumulativeConstraintCount, 0); +} + void SIM_AllocationConstraints(PROBLEME_HEBDO& problem, const Antares::Data::Study& study, unsigned NombreDePasDeTemps) diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 3d29d3ee42..786b1b5aa6 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -39,6 +39,7 @@ static void importShortTermStorages( std::vector<::ShortTermStorage::AREA_INPUT>& ShortTermStorageOut) { int clusterGlobalIndex = 0; + int clusterCumulativeConstraintGlobalIndex = 0; for (uint areaIndex = 0; areaIndex != areas.size(); areaIndex++) { ShortTermStorageOut[areaIndex].resize(areas[areaIndex]->shortTermStorage.count()); @@ -59,7 +60,12 @@ static void importShortTermStorages( toInsert.penalizeVariationInjection = st.properties.penalizeVariationInjection; toInsert.penalizeVariationWithdrawal = st.properties.penalizeVariationWithdrawal; toInsert.name = st.properties.name; - + toInsert.additional_constraints = st.additional_constraints; + for (auto& constraint: toInsert.additional_constraints) + { + constraint.globalIndex = clusterCumulativeConstraintGlobalIndex; + ++clusterCumulativeConstraintGlobalIndex; + } toInsert.series = st.series; // TODO add missing properties, or use the same struct