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

For short-term storage cumulative constraints [ANT-1855] #2546

Merged
merged 48 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
11c120e
update
a-zakir Dec 19, 2024
f100200
update
a-zakir Dec 20, 2024
88698d4
read new folder
a-zakir Dec 20, 2024
ffb6a42
update outer-inner constraint count
a-zakir Dec 20, 2024
de7c893
update unpacked constraints
a-zakir Dec 20, 2024
1fcc874
update name of unpacked constraints
a-zakir Dec 20, 2024
c9c7711
Merge branch 'develop' into feature/variable-rhs-sts-new-constraint
a-zakir Dec 20, 2024
be9f174
update
a-zakir Dec 20, 2024
ef2b214
Merge branch 'feature/variable-rhs-sts-new-constraint' of https://git…
a-zakir Dec 20, 2024
11169e1
add UT
a-zakir Dec 20, 2024
cf2e4bc
add UT
a-zakir Dec 20, 2024
c0b684e
use tmp dir as test dir
a-zakir Dec 20, 2024
d2b66c9
add test
a-zakir Dec 20, 2024
8e7cab0
UPDATE
a-zakir Dec 23, 2024
8ca3d69
update tests
a-zakir Dec 23, 2024
dc7488a
Merge branch 'develop' into feature/variable-rhs-sts-new-constraint
payetvin Dec 31, 2024
4c84485
format
payetvin Dec 31, 2024
ebd2664
Add function loadHours
payetvin Dec 31, 2024
480c30f
rename loadconstrintfrominifile
payetvin Dec 31, 2024
9988829
add readRHS
payetvin Dec 31, 2024
77623b5
rename additional_constraints
payetvin Dec 31, 2024
8057164
format
payetvin Dec 31, 2024
fba0351
use a pair
payetvin Dec 31, 2024
5037c3e
use a class instead of struct
payetvin Dec 31, 2024
63d7935
rename files
payetvin Dec 31, 2024
c2ca5b7
few comments
payetvin Dec 31, 2024
309b537
format
payetvin Dec 31, 2024
57a8dd1
revert and update
a-zakir Jan 2, 2025
efd16e0
update
a-zakir Jan 2, 2025
5c4a438
split tests
a-zakir Jan 2, 2025
d5f0bca
on malformed rhs file
a-zakir Jan 2, 2025
bf3bd6e
update
a-zakir Jan 2, 2025
772434d
Add attribute `enabled` to additional constraints, adapt tests [ANT-1…
flomnes Jan 3, 2025
fe5ec25
add robustness tests
a-zakir Jan 6, 2025
f78e9c5
add robustness tests
a-zakir Jan 6, 2025
35f0d6a
update
a-zakir Jan 6, 2025
674155f
Format
flomnes Jan 6, 2025
31e92a0
Merge remote-tracking branch 'github/develop' into feature/variable-r…
flomnes Jan 6, 2025
d1dd983
Fix build
flomnes Jan 6, 2025
87d36c6
update
a-zakir Jan 6, 2025
2eb45b6
update
a-zakir Jan 6, 2025
bd6b47b
update vcpkg
a-zakir Jan 6, 2025
072d709
eliminate spaces
a-zakir Jan 6, 2025
89b260f
avoidable string copy
a-zakir Jan 6, 2025
6634097
test white spaces
a-zakir Jan 6, 2025
a1f7df7
test valid white spaces
a-zakir Jan 6, 2025
eb64775
format
a-zakir Jan 6, 2025
189d1b3
remove comments
a-zakir Jan 6, 2025
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
4 changes: 2 additions & 2 deletions src/libs/antares/study/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +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
include/antares/study/parts/short-term-storage/additionalConstraints.h
parts/short-term-storage/cluster.cpp
parts/short-term-storage/AdditionalConstraint.cpp
parts/short-term-storage/additionalConstraints.cpp
)
source_group("study\\part\\short-term-storage" FILES ${SRC_STUDY_PART_SHORT_TERM_SOTRAGE})

Expand Down
10 changes: 6 additions & 4 deletions src/libs/antares/study/area/list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1194,12 +1194,14 @@ bool AreaList::loadFromFolder(const StudyLoadOptions& options)

if (fs::exists(stsFolder))
{
for (const auto& [id, area]: areas)
for (const auto& area: areas | std::views::values)
{
fs::path folder = stsFolder / "clusters" / area->id.c_str();
fs::path cluster_folder = stsFolder / "clusters" / area->id.c_str();
ret = area->shortTermStorage.createSTStorageClustersFromIniFile(cluster_folder)
&& ret;

ret = area->shortTermStorage.createSTStorageClustersFromIniFile(folder) && ret;
ret = area->shortTermStorage.LoadConstraintsFromIniFile(folder) && ret;
const auto constraints_folder = stsFolder / "constraints" / area->id.c_str();
ret = area->shortTermStorage.loadAdditionalConstraints(constraints_folder) && ret;
}
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,46 @@
#pragma once
#include <set>
#include <string>
#include <vector>

namespace Antares::Data::ShortTermStorage
{

struct AdditionalConstraint
class SingleAdditionalConstraint
{
public:
std::set<int> hours;
unsigned int globalIndex = 0;
unsigned int localIndex = 0;
bool isValidHoursRange() const;
};

struct AdditionalConstraints
{
std::string name;
std::string cluster_id;
std::string variable;
std::string operatorType;
std::set<int> hours;
double rhs;
bool enabled = true;
std::vector<double> rhs;

unsigned int globalIndex = 0;
std::vector<SingleAdditionalConstraint> constraints;

struct ValidateResult
{
bool ok;
std::string error_msg;
};

// Number of enabled constraints
std::size_t enabledConstraints() const;

ValidateResult validate() const;

private:
bool isValidVariable() const;
bool isValidOperatorType() const;
bool isValidHoursRange() const;

bool isValidHours() const;
};
} // namespace Antares::Data::ShortTermStorage
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

#include <antares/inifile/inifile.h>

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

Expand All @@ -51,6 +51,6 @@ class STStorageCluster

std::shared_ptr<Series> series = std::make_shared<Series>();
mutable Properties properties;
std::vector<AdditionalConstraint> additional_constraints;
std::vector<AdditionalConstraints> additionalConstraints;
};
} // namespace Antares::Data::ShortTermStorage
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#include <filesystem>
#include <string>

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

namespace Antares::Data::ShortTermStorage
Expand All @@ -42,7 +41,7 @@ class STStorageInput
/// Number of enabled ST storages, ignoring disabled ST storages
std::size_t count() const;

bool LoadConstraintsFromIniFile(const std::filesystem::path& filePath);
bool loadAdditionalConstraints(const std::filesystem::path& filePath);

/// erase disabled cluster from the vector
uint removeDisabledClusters();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,5 @@ class Series

bool loadFile(const std::filesystem::path& folder, std::vector<double>& vect);
bool writeVectorToFile(const std::string& path, const std::vector<double>& vect);

void fillIfEmpty(std::vector<double>& v, double value);
} // namespace Antares::Data::ShortTermStorage
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
** 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"

#include "antares/study/parts/short-term-storage/additionalConstraints.h"

#include <algorithm>

namespace Antares::Data::ShortTermStorage
{
AdditionalConstraint::ValidateResult AdditionalConstraint::validate() const
AdditionalConstraints::ValidateResult AdditionalConstraints::validate() const
{
if (cluster_id.empty())
{
Expand All @@ -39,27 +42,39 @@ AdditionalConstraint::ValidateResult AdditionalConstraint::validate() const
return {false, "Invalid operator type. Must be 'less', 'equal', or 'greater'."};
}

if (!isValidHoursRange())
if (!isValidHours())
{
return {false, "Hours set contains invalid values. Must be between 1 and 168."};
return {false, "Hours sets contains invalid values. Must be between 1 and 168."};
}

return {true, ""};
}

bool AdditionalConstraint::isValidHoursRange() const
bool SingleAdditionalConstraint::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
bool AdditionalConstraints::isValidHours() const
{
return std::ranges::all_of(constraints,
[](const auto& constraint)
{ return constraint.isValidHoursRange(); });
}

bool AdditionalConstraints::isValidVariable() const
{
return variable == "injection" || variable == "withdrawal" || variable == "netting";
}

bool AdditionalConstraint::isValidOperatorType() const
bool AdditionalConstraints::isValidOperatorType() const
{
return operatorType == "less" || operatorType == "equal" || operatorType == "greater";
}

std::size_t AdditionalConstraints::enabledConstraints() const
{
return enabled ? constraints.size() : 0;
}
} // namespace Antares::Data::ShortTermStorage
149 changes: 117 additions & 32 deletions src/libs/antares/study/parts/short-term-storage/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

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

#include <yuni/io/file.h>
Expand Down Expand Up @@ -75,10 +76,80 @@ bool STStorageInput::createSTStorageClustersFromIniFile(const fs::path& path)
return true;
}

bool STStorageInput::LoadConstraintsFromIniFile(const fs::path& parent_path)
static bool loadHours(std::string hoursStr, AdditionalConstraints& additionalConstraints)
{
std::erase_if(hoursStr, ::isspace);
// Validate the entire string format
if (std::regex fullFormatRegex(R"(^(\[\d+(,\d+)*\])(,(\[\d+(,\d+)*\]))*$)");
!std::regex_match(hoursStr, fullFormatRegex))
{
logs.error() << "In constraint " << additionalConstraints.name
<< ": Input string does not match the required format: " << hoursStr << '\n';
return false;
}
// Split the `hours` field into multiple groups
std::regex groupRegex(R"(\[(.*?)\])");
// Match each group enclosed in square brackets
auto groupsBegin = std::sregex_iterator(hoursStr.begin(), hoursStr.end(), groupRegex);
auto groupsEnd = std::sregex_iterator();
unsigned int localIndex = 0;
for (auto it = groupsBegin; it != groupsEnd; ++it)
{
// Extract the contents of the square brackets
std::string group = (*it)[1].str();
std::stringstream ss(group);
std::string hour;
std::set<int> hourSet;
int hourVal;
while (std::getline(ss, hour, ','))
{
try
{
hourVal = std::stoi(hour);
hourSet.insert(hourVal);
}

catch (const std::invalid_argument& ex)
{
logs.error() << "In constraint " << additionalConstraints.name
<< " Hours sets contains invalid values: " << hour
<< "\n exception thrown: " << ex.what() << '\n';

return false;
}
catch (const std::out_of_range& ex)
{
logs.error() << "In constraint " << additionalConstraints.name
<< " Hours sets contains out of range values: " << hour
<< "\n exception thrown: " << ex.what() << '\n';
return false;
}
}
if (!hourSet.empty())
{
// Add this group to the `hours` vec
additionalConstraints.constraints.push_back(
{.hours = hourSet, .localIndex = localIndex});
++localIndex;
}
}
return true;
}

static bool readRHS(AdditionalConstraints& additionalConstraints, const fs::path& rhsPath)
{
const auto ret = loadFile(rhsPath, additionalConstraints.rhs);
if (ret)
{
fillIfEmpty(additionalConstraints.rhs, 0.0);
}
return ret;
}

bool STStorageInput::loadAdditionalConstraints(const fs::path& parentPath)
{
IniFile ini;
const auto pathIni = parent_path / "additional-constraints.ini";
const auto pathIni = parentPath / "additional-constraints.ini";
if (!ini.open(pathIni, false))
{
logs.info() << "There is no: " << pathIni;
Expand All @@ -87,55 +158,60 @@ bool STStorageInput::LoadConstraintsFromIniFile(const fs::path& parent_path)

for (auto* section = ini.firstSection; section; section = section->next)
{
AdditionalConstraint constraint;
constraint.name = section->name.c_str();
AdditionalConstraints additionalConstraints;
additionalConstraints.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);
additionalConstraints.cluster_id = transformNameIntoID(clusterName);
}
else if (key == "variable")
else if (key == "enabled")
{
value.to<std::string>(constraint.variable);
value.to<bool>(additionalConstraints.enabled);
}
else if (key == "operator")
else if (key == "variable")
{
value.to<std::string>(constraint.operatorType);
value.to<std::string>(additionalConstraints.variable);
}
else if (key == "hours")
else if (key == "operator")
{
std::stringstream ss(value.c_str());
std::string hour;
while (std::getline(ss, hour, ','))
{
int hourVal = std::stoi(hour);
constraint.hours.insert(hourVal);
}
value.to<std::string>(additionalConstraints.operatorType);
}
else if (key == "rhs")
else if (key == "hours" && !loadHours(value.c_str(), additionalConstraints))
{
property->value.to<double>(constraint.rhs);
return false;
}
}

if (auto ret = constraint.validate(); !ret.ok)
// We don't want load RHS and link the STS time if the constraint is disabled
if (!additionalConstraints.enabled)
{
return true;
}

if (const auto rhsPath = parentPath / ("rhs_" + additionalConstraints.name + ".txt");
!readRHS(additionalConstraints, rhsPath))
{
logs.error() << "Error while reading rhs file: " << rhsPath;
return false;
}

if (auto [ok, error_msg] = additionalConstraints.validate(); !ok)
{
logs.error() << "Invalid constraint in section: " << section->name;
logs.error() << ret.error_msg;
logs.error() << error_msg;
return false;
}

auto it = std::find_if(storagesByIndex.begin(),
storagesByIndex.end(),
[&constraint](const STStorageCluster& cluster)
{ return cluster.id == constraint.cluster_id; });
auto it = std::ranges::find_if(storagesByIndex,
[&additionalConstraints](const STStorageCluster& cluster)
{ return cluster.id == additionalConstraints.cluster_id; });
if (it == storagesByIndex.end())
{
logs.warning() << " from file " << pathIni;
Expand All @@ -145,7 +221,7 @@ bool STStorageInput::LoadConstraintsFromIniFile(const fs::path& parent_path)
}
else
{
it->additional_constraints.push_back(constraint);
it->additionalConstraints.push_back(additionalConstraints);
}
}

Expand Down Expand Up @@ -194,11 +270,20 @@ bool STStorageInput::saveDataSeriesToFolder(const std::string& folder) const

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(); });
return std::accumulate(
storagesByIndex.begin(),
storagesByIndex.end(),
0,
[](size_t outer_constraint_count, const auto& cluster)
{
return outer_constraint_count
+ std::accumulate(
cluster.additionalConstraints.begin(),
cluster.additionalConstraints.end(),
0,
[](size_t inner_constraint_count, const auto& additionalConstraints)
{ return inner_constraint_count + additionalConstraints.enabledConstraints(); });
});
}

std::size_t STStorageInput::count() const
Expand Down
Loading
Loading