Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding constraints on injection-witdrawal cumulation with constant RHS [ANT-1885] #2535

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/libs/antares/study/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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})

Expand Down Expand Up @@ -306,12 +308,12 @@ target_link_libraries(study
)

target_include_directories(study
PUBLIC
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>

# Make more than just study visible but it's the lesser evil for now
)

install(DIRECTORY include/antares
install(DIRECTORY include/antares
DESTINATION "include"
)
1 change: 1 addition & 0 deletions src/libs/antares/study/area/list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <https://opensource.org/license/mpl-2-0/>.
*/

#pragma once
#include <set>
#include <string>

namespace Antares::Data::ShortTermStorage
{

struct AdditionalConstraint
{
std::string name;
std::string cluster_id;
std::string variable;
std::string operatorType;
std::set<int> 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
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <antares/inifile/inifile.h>

#include "AdditionalConstraint.h"
#include "properties.h"
#include "series.h"

Expand All @@ -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> series = std::make_shared<Series>();
mutable Properties properties;
std::vector<AdditionalConstraint> additional_constraints;
};
} // namespace Antares::Data::ShortTermStorage
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@

#pragma once
#include <filesystem>
#include <map>
#include <string>

#include "AdditionalConstraint.h"
#include "cluster.h"

namespace Antares::Data::ShortTermStorage
Expand All @@ -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<STStorageCluster> storagesByIndex;

/// Number cumulative - constraint
std::size_t cumulativeConstraintCount() const;
};
} // namespace Antares::Data::ShortTermStorage
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class StudyRuntimeInfos
uint thermalPlantTotalCountMustRun;

uint shortTermStorageCount = 0;
uint shortTermStorageCumulativeConstraintCount = 0;

//! Override enable/disable TS generation per cluster
bool thermalTSRefresh = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <https://opensource.org/license/mpl-2-0/>.
*/
#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
2 changes: 0 additions & 2 deletions src/libs/antares/study/parts/short-term-storage/cluster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

namespace Antares::Data::ShortTermStorage
{

bool STStorageCluster::loadFromSection(const IniFile::Section& section)
{
if (!section.firstProperty)
Expand Down Expand Up @@ -92,5 +91,4 @@ bool STStorageCluster::saveSeries(const std::string& path) const
{
return series->saveToFolder(path);
}

} // namespace Antares::Data::ShortTermStorage
89 changes: 88 additions & 1 deletion src/libs/antares/study/parts/short-term-storage/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
#include "antares/study/parts/short-term-storage/container.h"

#include <algorithm>
#include <numeric>
#include <string>

#include <yuni/io/file.h>

#include <antares/logs/logs.h>
#include <antares/utils/utils.h>

#define SEP Yuni::IO::Separator

Expand Down Expand Up @@ -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<std::string>(clusterName);
constraint.cluster_id = transformNameIntoID(clusterName);
}
else if (key == "variable")
{
value.to<std::string>(constraint.variable);
}
else if (key == "operator")
{
value.to<std::string>(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<double>(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())
Expand Down Expand Up @@ -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,
Expand All @@ -123,5 +211,4 @@ uint STStorageInput::removeDisabledClusters()
{
return std::erase_if(storagesByIndex, [](const auto& c) { return !c.enabled(); });
}

} // namespace Antares::Data::ShortTermStorage
4 changes: 4 additions & 0 deletions src/libs/antares/study/runtime/runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand Down Expand Up @@ -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");
Expand Down
Loading
Loading