From 9aa0e7fc3602d2749ff1fdc9c58d42c0d7a13115 Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Mon, 16 Sep 2024 14:19:40 +0200 Subject: [PATCH 001/103] Replace AddNode with SumNode (#2396) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In expressions, replace "AddNode" that takes only 2 operands, with "SumNode" that takes 0 to N operands. This will allow shallower trees. --------- Co-authored-by: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> Co-authored-by: Florian Omnès --- src/solver/expressions/CMakeLists.txt | 3 +- .../expressions/nodes/ExpressionsNodes.h | 2 +- .../nodes/NodesForwardDeclaration.h | 2 +- .../solver/expressions/nodes/SumNode.h | 88 ++++++++++++++++++ .../expressions/visitors/CloneVisitor.h | 2 +- .../expressions/visitors/CompareVisitor.h | 2 +- .../solver/expressions/visitors/EvalVisitor.h | 2 +- .../expressions/visitors/LinearityVisitor.h | 2 +- .../solver/expressions/visitors/NodeVisitor.h | 10 +-- .../expressions/visitors/PrintVisitor.h | 2 +- .../expressions/visitors/TimeIndexVisitor.h | 2 +- .../expressions/iterators/pre-order.cpp | 4 + .../nodes/AddNode.h => nodes/SumNode.cpp} | 31 ++++--- .../expressions/visitors/CloneVisitor.cpp | 13 ++- .../expressions/visitors/CompareVisitor.cpp | 19 +++- .../expressions/visitors/EvalVisitor.cpp | 11 ++- .../expressions/visitors/LinearityVisitor.cpp | 11 ++- .../expressions/visitors/PrintVisitor.cpp | 19 ++-- .../expressions/visitors/TimeIndexVisitor.cpp | 11 ++- .../solver/expressions/test_CloneVisitor.cpp | 20 +++-- .../expressions/test_CompareVisitor.cpp | 65 +++++++++++++- .../solver/expressions/test_DeepWideTrees.cpp | 8 +- .../src/solver/expressions/test_Iterators.cpp | 6 +- .../solver/expressions/test_LinearVisitor.cpp | 37 +++++++- .../expressions/test_PrintAndEvalNodes.cpp | 90 +++++++++++++++++-- .../expressions/test_SubstitutionVisitor.cpp | 6 +- .../expressions/test_TimeIndexVisitor.cpp | 6 +- .../src/solver/expressions/test_nodes.cpp | 2 +- 28 files changed, 397 insertions(+), 79 deletions(-) create mode 100644 src/solver/expressions/include/antares/solver/expressions/nodes/SumNode.h rename src/solver/expressions/{include/antares/solver/expressions/nodes/AddNode.h => nodes/SumNode.cpp} (72%) diff --git a/src/solver/expressions/CMakeLists.txt b/src/solver/expressions/CMakeLists.txt index 6ef342a633..b165529a9c 100644 --- a/src/solver/expressions/CMakeLists.txt +++ b/src/solver/expressions/CMakeLists.txt @@ -6,6 +6,7 @@ set(SRC_Expressions nodes/ComponentNode.cpp nodes/BinaryNode.cpp nodes/UnaryNode.cpp + nodes/SumNode.cpp visitors/CloneVisitor.cpp visitors/CompareVisitor.cpp @@ -17,7 +18,7 @@ set(SRC_Expressions visitors/SubstitutionVisitor.cpp visitors/InvalidNode.cpp - include/antares/solver/expressions/nodes/AddNode.h + include/antares/solver/expressions/nodes/SumNode.h include/antares/solver/expressions/nodes/BinaryNode.h include/antares/solver/expressions/nodes/ComparisonNode.h include/antares/solver/expressions/nodes/ComponentNode.h diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/ExpressionsNodes.h b/src/solver/expressions/include/antares/solver/expressions/nodes/ExpressionsNodes.h index 2ecf1fe001..1652e4003a 100644 --- a/src/solver/expressions/include/antares/solver/expressions/nodes/ExpressionsNodes.h +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/ExpressionsNodes.h @@ -19,7 +19,6 @@ ** along with Antares_Simulator. If not, see . */ #pragma once -#include #include #include #include @@ -32,4 +31,5 @@ #include #include #include +#include #include diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h b/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h index bc1b44b2a1..d1c653f991 100644 --- a/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h @@ -23,7 +23,7 @@ namespace Antares::Solver::Nodes { class Node; -class AddNode; +class SumNode; class SubtractionNode; class MultiplicationNode; class DivisionNode; diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/SumNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/SumNode.h new file mode 100644 index 0000000000..663954ada5 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/SumNode.h @@ -0,0 +1,88 @@ +/* +** 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 "antares/solver/expressions/nodes/Node.h" + +namespace Antares::Solver::Nodes +{ + +template +concept NodePtr = std::same_as; + +template +requires(std::convertible_to && ...) +std::vector createVector(T first, Args... args) +{ + return std::vector{first, args...}; +} + +class SumNode: public Node +{ +public: + template + explicit SumNode(NodePtr... operands) + { + if constexpr (sizeof...(NodePtr)) + { + operands_ = createVector(static_cast(operands)...); + } + } + + /** + * @brief Constructs a sum node with the specified operands. + * + * @param operands The operands, collected in a vector + */ + explicit SumNode(const std::vector& operands); + + /** + * @brief Constructs a sum node with the specified operands. Vector is moved. + * + * @param operands The operands, collected in a vector + */ + explicit SumNode(std::vector&& operands): + operands_(std::move(operands)) + { + } + + /** + * @brief Retrieves the operands of the sum. + * + * @return A vector of pointers to the operands of the sum. + */ + const std::vector& getOperands() const; + + Node* operator[](std::size_t idx) const; + + unsigned int size() const; + + std::string name() const override + { + return "SumNode"; + } + +private: + std::vector operands_ = {}; +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/CloneVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/CloneVisitor.h index caafab8df0..394a1449eb 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/CloneVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/CloneVisitor.h @@ -39,7 +39,7 @@ class CloneVisitor: public NodeVisitor explicit CloneVisitor(Registry& registry); std::string name() const override; - Nodes::Node* visit(const Nodes::AddNode* node) override; + Nodes::Node* visit(const Nodes::SumNode* node) override; Nodes::Node* visit(const Nodes::SubtractionNode* node) override; Nodes::Node* visit(const Nodes::MultiplicationNode* node) override; Nodes::Node* visit(const Nodes::DivisionNode* node) override; diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/CompareVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/CompareVisitor.h index 579eb8c2ed..446d538510 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/CompareVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/CompareVisitor.h @@ -34,7 +34,7 @@ class CompareVisitor: public NodeVisitor CompareVisitor() = default; std::string name() const override; - bool visit(const Nodes::AddNode* add, const Nodes::Node* other) override; + bool visit(const Nodes::SumNode* add, const Nodes::Node* other) override; bool visit(const Nodes::SubtractionNode* add, const Nodes::Node* other) override; bool visit(const Nodes::MultiplicationNode* add, const Nodes::Node* other) override; bool visit(const Nodes::DivisionNode* add, const Nodes::Node* other) override; diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/EvalVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/EvalVisitor.h index 0ec4ae6612..0486197852 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/EvalVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/EvalVisitor.h @@ -59,7 +59,7 @@ class EvalVisitor: public NodeVisitor private: const EvaluationContext context_; - double visit(const Nodes::AddNode* node) override; + double visit(const Nodes::SumNode* node) override; double visit(const Nodes::SubtractionNode* node) override; double visit(const Nodes::MultiplicationNode* node) override; double visit(const Nodes::DivisionNode* node) override; diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/LinearityVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/LinearityVisitor.h index 2db78786a9..3baa0abe81 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/LinearityVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/LinearityVisitor.h @@ -34,7 +34,7 @@ class LinearityVisitor: public NodeVisitor std::string name() const override; private: - LinearStatus visit(const Nodes::AddNode* add) override; + LinearStatus visit(const Nodes::SumNode* add) override; LinearStatus visit(const Nodes::SubtractionNode* add) override; LinearStatus visit(const Nodes::MultiplicationNode* add) override; LinearStatus visit(const Nodes::DivisionNode* add) override; diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h index 218987fa76..59001acf75 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h @@ -97,7 +97,7 @@ class NodeVisitor: public IName } const static auto nodeVisitList = NodeVisitsProvider::template NodesVisitList< - Nodes::AddNode, + Nodes::SumNode, Nodes::SubtractionNode, Nodes::MultiplicationNode, Nodes::DivisionNode, @@ -124,14 +124,14 @@ class NodeVisitor: public IName } /** - * @brief Visits an AddNode and processes its children. + * @brief Visits a SumNode and processes its children. * - * @param node A pointer to the AddNode to be visited. + * @param node A pointer to the SumNode to be visited. * @param args Additional arguments to be passed to the visitor's methods. * - * @return The result of processing the AddNode. + * @return The result of processing the SumNode. */ - virtual R visit(const Nodes::AddNode*, Args... args) = 0; + virtual R visit(const Nodes::SumNode*, Args... args) = 0; /** * @brief Visits a SubtractionNode and processes its children. * diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/PrintVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/PrintVisitor.h index abe19f8122..a7b09bc8c0 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/PrintVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/PrintVisitor.h @@ -33,7 +33,7 @@ class PrintVisitor: public NodeVisitor std::string name() const override; private: - std::string visit(const Nodes::AddNode* node) override; + std::string visit(const Nodes::SumNode* node) override; std::string visit(const Nodes::SubtractionNode* node) override; std::string visit(const Nodes::MultiplicationNode* node) override; std::string visit(const Nodes::DivisionNode* node) override; diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndexVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndexVisitor.h index 1b9c8ddd37..ebbfd9737a 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndexVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndexVisitor.h @@ -43,7 +43,7 @@ class TimeIndexVisitor: public NodeVisitor private: std::unordered_map context_; - TimeIndex visit(const Nodes::AddNode* add) override; + TimeIndex visit(const Nodes::SumNode* add) override; TimeIndex visit(const Nodes::SubtractionNode* add) override; TimeIndex visit(const Nodes::MultiplicationNode* add) override; TimeIndex visit(const Nodes::DivisionNode* add) override; diff --git a/src/solver/expressions/iterators/pre-order.cpp b/src/solver/expressions/iterators/pre-order.cpp index 5e8a968b31..57d27203a0 100644 --- a/src/solver/expressions/iterators/pre-order.cpp +++ b/src/solver/expressions/iterators/pre-order.cpp @@ -18,6 +18,10 @@ std::vector childrenLeftToRight(Node* node) { return {unary->child()}; } + else if (auto* sum = dynamic_cast(node)) + { + return sum->getOperands(); + } return {}; } } // namespace diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/AddNode.h b/src/solver/expressions/nodes/SumNode.cpp similarity index 72% rename from src/solver/expressions/include/antares/solver/expressions/nodes/AddNode.h rename to src/solver/expressions/nodes/SumNode.cpp index ea0e251607..d42668d06a 100644 --- a/src/solver/expressions/include/antares/solver/expressions/nodes/AddNode.h +++ b/src/solver/expressions/nodes/SumNode.cpp @@ -18,20 +18,29 @@ ** 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::Solver::Nodes { -class AddNode: public BinaryNode + +SumNode::SumNode(const std::vector& operands): + operands_(operands) +{ +} + +const std::vector& SumNode::getOperands() const +{ + return operands_; +} + +unsigned int SumNode::size() const +{ + return operands_.size(); +} + +Node* SumNode::operator[](std::size_t idx) const { -public: - using BinaryNode::BinaryNode; + return operands_[idx]; +} - std::string name() const override - { - return "AddNode"; - } -}; } // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/visitors/CloneVisitor.cpp b/src/solver/expressions/visitors/CloneVisitor.cpp index 36c53084e4..17875a82a1 100644 --- a/src/solver/expressions/visitors/CloneVisitor.cpp +++ b/src/solver/expressions/visitors/CloneVisitor.cpp @@ -28,9 +28,16 @@ CloneVisitor::CloneVisitor(Registry& registry): { } -Nodes::Node* CloneVisitor::visit(const Nodes::AddNode* node) -{ - return registry_.create(dispatch(node->left()), dispatch(node->right())); +Nodes::Node* CloneVisitor::visit(const Nodes::SumNode* node) +{ + std::vector clonedOperands; + clonedOperands.reserve(node->size()); + for (auto* operand: node->getOperands()) + { + clonedOperands.push_back(dispatch(operand)); + } + // Give ownership of clonedOperands to the caller + return registry_.create(std::move(clonedOperands)); } Nodes::Node* CloneVisitor::visit(const Nodes::SubtractionNode* node) diff --git a/src/solver/expressions/visitors/CompareVisitor.cpp b/src/solver/expressions/visitors/CompareVisitor.cpp index c7fc5c71dc..2a316fdf59 100644 --- a/src/solver/expressions/visitors/CompareVisitor.cpp +++ b/src/solver/expressions/visitors/CompareVisitor.cpp @@ -55,9 +55,24 @@ static bool compareEqualOperator(const T* node, const Antares::Solver::Nodes::No namespace Antares::Solver::Visitors { -bool CompareVisitor::visit(const Nodes::AddNode* node, const Nodes::Node* other) +bool CompareVisitor::visit(const Nodes::SumNode* node, const Nodes::Node* other) { - return compareBinaryNode(*this, node, other); + if (const auto* other_node = dynamic_cast(other)) + { + if (node->size() != other_node->size()) + { + return false; + } + for (std::size_t i = 0; i < node->size(); ++i) + { + if (!dispatch(node->getOperands()[i], other_node->getOperands()[i])) + { + return false; + } + } + return true; + } + return false; } bool CompareVisitor::visit(const Nodes::SubtractionNode* node, const Nodes::Node* other) diff --git a/src/solver/expressions/visitors/EvalVisitor.cpp b/src/solver/expressions/visitors/EvalVisitor.cpp index 336376fd4e..25c7973d90 100644 --- a/src/solver/expressions/visitors/EvalVisitor.cpp +++ b/src/solver/expressions/visitors/EvalVisitor.cpp @@ -21,6 +21,8 @@ #include "antares/solver/expressions/visitors/EvalVisitor.h" +#include + #include namespace Antares::Solver::Visitors @@ -30,9 +32,14 @@ EvalVisitor::EvalVisitor(EvaluationContext context): { } -double EvalVisitor::visit(const Nodes::AddNode* node) +double EvalVisitor::visit(const Nodes::SumNode* node) { - return dispatch(node->left()) + dispatch(node->right()); + auto operands = node->getOperands(); + return std::accumulate(std::begin(operands), + std::end(operands), + 0, + [this](double sum, Nodes::Node* operand) + { return sum + dispatch(operand); }); } double EvalVisitor::visit(const Nodes::SubtractionNode* node) diff --git a/src/solver/expressions/visitors/LinearityVisitor.cpp b/src/solver/expressions/visitors/LinearityVisitor.cpp index 902ae530fd..93df95b40c 100644 --- a/src/solver/expressions/visitors/LinearityVisitor.cpp +++ b/src/solver/expressions/visitors/LinearityVisitor.cpp @@ -21,15 +21,22 @@ #include "antares/solver/expressions/visitors/LinearityVisitor.h" +#include + #include #include namespace Antares::Solver::Visitors { -LinearStatus LinearityVisitor::visit(const Nodes::AddNode* node) +LinearStatus LinearityVisitor::visit(const Nodes::SumNode* node) { - return dispatch(node->left()) + dispatch(node->right()); + auto operands = node->getOperands(); + return std::accumulate(std::begin(operands), + std::end(operands), + LinearStatus::CONSTANT, + [this](LinearStatus sum, Nodes::Node* operand) + { return sum + dispatch(operand); }); } LinearStatus LinearityVisitor::visit(const Nodes::SubtractionNode* node) diff --git a/src/solver/expressions/visitors/PrintVisitor.cpp b/src/solver/expressions/visitors/PrintVisitor.cpp index dda167028c..b325ed7b75 100644 --- a/src/solver/expressions/visitors/PrintVisitor.cpp +++ b/src/solver/expressions/visitors/PrintVisitor.cpp @@ -19,17 +19,26 @@ ** along with Antares_Simulator. If not, see . */ #include +#include #include #include namespace Antares::Solver::Visitors { -std::string PrintVisitor::visit(const Nodes::AddNode* node) -{ - // Ici le compilateur (g++) a besoin de savoir qu'on veut le visit du type de base - // sinon erreur de compil 'fonction non trouvée' - return "(" + dispatch(node->left()) + "+" + dispatch(node->right()) + ")"; +std::string PrintVisitor::visit(const Nodes::SumNode* node) +{ + auto operands = node->getOperands(); + if (operands.empty()) + { + return "()"; + } + return std::accumulate(std::next(std::begin(operands)), + std::end(operands), + "(" + dispatch(operands[0]), + [this](std::string sum, Nodes::Node* operand) + { return sum + "+" + dispatch(operand); }) + + ")"; } std::string PrintVisitor::visit(const Nodes::SubtractionNode* node) diff --git a/src/solver/expressions/visitors/TimeIndexVisitor.cpp b/src/solver/expressions/visitors/TimeIndexVisitor.cpp index 5e23c68856..89bd84b000 100644 --- a/src/solver/expressions/visitors/TimeIndexVisitor.cpp +++ b/src/solver/expressions/visitors/TimeIndexVisitor.cpp @@ -19,15 +19,22 @@ ** along with Antares_Simulator. If not, see . */ +#include + #include #include namespace Antares::Solver::Visitors { -TimeIndex TimeIndexVisitor::visit(const Nodes::AddNode* add) +TimeIndex TimeIndexVisitor::visit(const Nodes::SumNode* node) { - return dispatch(add->left()) | dispatch(add->right()); + auto operands = node->getOperands(); + return std::accumulate(std::begin(operands), + std::end(operands), + TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO, + [this](TimeIndex sum, Nodes::Node* operand) + { return sum | dispatch(operand); }); } TimeIndex TimeIndexVisitor::visit(const Nodes::SubtractionNode* sub) diff --git a/src/tests/src/solver/expressions/test_CloneVisitor.cpp b/src/tests/src/solver/expressions/test_CloneVisitor.cpp index b78fe098c6..c251662b5a 100644 --- a/src/tests/src/solver/expressions/test_CloneVisitor.cpp +++ b/src/tests/src/solver/expressions/test_CloneVisitor.cpp @@ -40,21 +40,23 @@ BOOST_FIXTURE_TEST_CASE(cloneVisitor_With_Add_Neg_ComponentVariableNode, Registr std::string cp_para_name("par"), cp_para_id("id2"); ComponentVariableNode cpv(cpvar_id, cpvar_name); ComponentParameterNode cpp(cp_para_id, cp_para_name); - double num1 = 22.0, num2 = 8.; + double num1 = 22.0, num2 = 8., num3 = 77.; // (num1+num2) - Node* edge = create(create(num1), create(num2)); - // -((num1+num2)) + Node* edge = create(create(num1), + create(num2), + create(num3)); + // -((num1+num2+num3)) Node* negative_edge = create(edge); - // (-((num1+num2))+id1.var) - Node* add_node = create(negative_edge, &cpv); - // (-((-((num1+num2))+id1.var))+id2.par) == - // (-((-((22.000000+8.000000))+id1.var))+id2.par) - Node* root = create(create(add_node), &cpp); + // (-((num1+num2+num3))+id1.var) + Node* add_node = create(negative_edge, &cpv); + // (-((-((num1+num2+num3))+id1.var))+id2.par) == + // (-((-((22.000000+8.000000+77.000000))+id1.var))+id2.par) + Node* root = create(create(add_node), &cpp); PrintVisitor printVisitor; const auto printed = printVisitor.dispatch(root); - BOOST_CHECK_EQUAL(printed, "(-((-((22.000000+8.000000))+id1.var))+id2.par)"); + BOOST_CHECK_EQUAL(printed, "(-((-((22.000000+8.000000+77.000000))+id1.var))+id2.par)"); CloneVisitor cloneVisitor(*this); Node* cloned = cloneVisitor.dispatch(root); BOOST_CHECK_EQUAL(printed, printVisitor.dispatch(cloned)); diff --git a/src/tests/src/solver/expressions/test_CompareVisitor.cpp b/src/tests/src/solver/expressions/test_CompareVisitor.cpp index da814fdc13..373d1ff314 100644 --- a/src/tests/src/solver/expressions/test_CompareVisitor.cpp +++ b/src/tests/src/solver/expressions/test_CompareVisitor.cpp @@ -44,7 +44,7 @@ Node* ComparisonFixture::createSimpleExpression(double param) { Node* var1 = registry_.create(param); Node* param1 = registry_.create("param1"); - Node* expr = registry_.create(var1, param1); + Node* expr = registry_.create(var1, param1); return expr; } @@ -60,11 +60,11 @@ Node* ComparisonFixture::createComplexExpression() Node* comp = registry_.create("hello", "world"); Node* div = registry_.create(mult, comp); Node* div2 = registry_.create(div, simple); - Node* add = registry_.create(div, div2); + Node* add = registry_.create(div, div2, neg); Node* sub = registry_.create(add, neg); Node* cmp = registry_.create(sub, add); Node* pf = registry_.create("port", "field"); - Node* addf = registry_.create(pf, cmp); + Node* addf = registry_.create(pf, cmp); return addf; } @@ -130,4 +130,63 @@ BOOST_FIXTURE_TEST_CASE(CompareVisitor_name, Registry) CompareVisitor compareVisitor; BOOST_CHECK_EQUAL(compareVisitor.name(), "CompareVisitor"); } + +BOOST_FIXTURE_TEST_CASE(compare_empty_sums, ComparisonFixture) +{ + CompareVisitor compareVisitor; + Node* expr1 = registry_.create(); + Node* expr2 = registry_.create(); + BOOST_CHECK(compareVisitor.dispatch(expr1, expr2)); +} + +BOOST_FIXTURE_TEST_CASE(compare_different_size_sums, ComparisonFixture) +{ + CompareVisitor compareVisitor; + Node* literal1 = registry_.create(1.); + Node* literal2 = registry_.create(2.); + Node* expr1 = registry_.create(literal1, literal2); + Node* expr2 = registry_.create(literal1); + BOOST_CHECK(!compareVisitor.dispatch(expr1, expr2)); +} + +BOOST_FIXTURE_TEST_CASE(compare_different_sums, ComparisonFixture) +{ + CompareVisitor compareVisitor; + Node* literal1 = registry_.create(1.); + Node* literal2 = registry_.create(2.); + Node* literal3 = registry_.create(3.); + Node* expr1 = registry_.create(literal1, literal2); + Node* expr2 = registry_.create(literal1, literal3); + BOOST_CHECK(!compareVisitor.dispatch(expr1, expr2)); +} + +BOOST_FIXTURE_TEST_CASE(compare_same_sums, ComparisonFixture) +{ + CompareVisitor compareVisitor; + Node* literal1 = registry_.create(1.); + Node* literal2 = registry_.create(2.); + Node* literal3 = registry_.create(3.); + Node* expr1 = registry_.create(literal1, literal2, literal3); + Node* expr2 = registry_.create(literal1, literal2, literal3); + BOOST_CHECK(compareVisitor.dispatch(expr1, expr2)); +} + +BOOST_FIXTURE_TEST_CASE(compare_same_sums_different_nodes, ComparisonFixture) +{ + CompareVisitor compareVisitor; + Node* literal1 = registry_.create(1.); + Node* literal2 = registry_.create(2.); + Node* literal3 = registry_.create(2.); + Node* expr1 = registry_.create(literal1, literal2); + Node* expr2 = registry_.create(literal1, literal3); + BOOST_CHECK(compareVisitor.dispatch(expr1, expr2)); +} + +BOOST_FIXTURE_TEST_CASE(compare_sum_to_literal, ComparisonFixture) +{ + CompareVisitor compareVisitor; + Node* literal1 = registry_.create(1.); + Node* expr1 = registry_.create(literal1); + BOOST_CHECK(!compareVisitor.dispatch(expr1, literal1)); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/expressions/test_DeepWideTrees.cpp b/src/tests/src/solver/expressions/test_DeepWideTrees.cpp index 957996641b..311358bc67 100644 --- a/src/tests/src/solver/expressions/test_DeepWideTrees.cpp +++ b/src/tests/src/solver/expressions/test_DeepWideTrees.cpp @@ -60,13 +60,13 @@ BOOST_FIXTURE_TEST_CASE(deep_tree_odd, Registry) BOOST_CHECK_EQUAL(evalVisitor.dispatch(node), -42.); } -static Node* deepAddTree(Registry& registry, AddNode* root, int depth) +static Node* deepAddTree(Registry& registry, SumNode* root, int depth) { if (depth > 0) { Node* left = deepAddTree(registry, root, depth - 1); Node* right = deepAddTree(registry, root, depth - 1); - return registry.create(left, right); + return registry.create(left, right); } else { @@ -76,8 +76,8 @@ static Node* deepAddTree(Registry& registry, AddNode* root, int depth) BOOST_FIXTURE_TEST_CASE(binary_tree, Registry) { - // AddNode's children are not mutable, so we'll replace this empty root with an actual one - AddNode* root = create(nullptr, nullptr); + // SumNode's children are not mutable, so we'll replace this empty root with an actual one + SumNode* root = create(nullptr, nullptr); Node* node = deepAddTree(*this, root, 10); EvalVisitor evalVisitor; // We expect 1024 = 2^10 literal nodes, each carrying value 42. diff --git a/src/tests/src/solver/expressions/test_Iterators.cpp b/src/tests/src/solver/expressions/test_Iterators.cpp index df0a4ddd18..9460f5e465 100644 --- a/src/tests/src/solver/expressions/test_Iterators.cpp +++ b/src/tests/src/solver/expressions/test_Iterators.cpp @@ -21,8 +21,6 @@ #define WIN32_LEAN_AND_MEAN -#include - #include #include @@ -36,7 +34,7 @@ BOOST_AUTO_TEST_SUITE(_Iterator_) static Node* simpleExpression(Registry& registry) { - return registry.create(registry.create(2.), + return registry.create(registry.create(2.), registry.create(21.)); } @@ -129,7 +127,7 @@ BOOST_FIXTURE_TEST_CASE(distance_unary, Registry) BOOST_FIXTURE_TEST_CASE(distance_nullptr_is_3, Registry) { - AST ast(create(nullptr, create(2.))); + AST ast(create(nullptr, create(2.))); BOOST_CHECK_EQUAL(std::distance(ast.begin(), ast.end()), 3); } diff --git a/src/tests/src/solver/expressions/test_LinearVisitor.cpp b/src/tests/src/solver/expressions/test_LinearVisitor.cpp index 7bc67ce8ed..689035f0f7 100644 --- a/src/tests/src/solver/expressions/test_LinearVisitor.cpp +++ b/src/tests/src/solver/expressions/test_LinearVisitor.cpp @@ -200,7 +200,7 @@ BOOST_FIXTURE_TEST_CASE(comparison_nodes_non_lin_constant_is_constant, Registry< MultiplicationNode mult(&var1, &var2); BOOST_CHECK_EQUAL(linearVisitor.dispatch(&mult), LinearStatus::NON_LINEAR); - AddNode add(&mult, &var1); + SumNode add(&mult, &var1); Node* gt = create(&mult, &var2); BOOST_CHECK_EQUAL(linearVisitor.dispatch(gt), LinearStatus::NON_LINEAR); } @@ -217,7 +217,7 @@ BOOST_FIXTURE_TEST_CASE(simple_linear, Registry) // 20.*id.y Node* v = create(&literalNode2, &var2); // 10.*x+20.*id.y - Node* expr = create(u, v); + Node* expr = create(u, v); PrintVisitor printVisitor; BOOST_CHECK_EQUAL(printVisitor.dispatch(expr), "((10.000000*x)+(20.000000*id.y))"); @@ -280,7 +280,7 @@ BOOST_FIXTURE_TEST_CASE(simple_constant_expression, Registry) // 65.*p1 Node* mult = create(&var1, &par); // ((65.*p1)+port.field) - Node* expr = create(mult, &portFieldNode); + Node* expr = create(mult, &portFieldNode); BOOST_CHECK_EQUAL(printVisitor.dispatch(expr), "((65.000000*p1)+port.field)"); BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::CONSTANT); } @@ -290,4 +290,35 @@ BOOST_FIXTURE_TEST_CASE(LinearityVisitor_name, Registry) LinearityVisitor linearityVisitor; BOOST_CHECK_EQUAL(linearityVisitor.name(), "LinearityVisitor"); } + +BOOST_FIXTURE_TEST_CASE(sum_node_cases, Registry) +{ + LinearityVisitor linearVisitor; + + Node* expr = create(); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::CONSTANT); + + expr = create(create(41), create(4)); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::CONSTANT); + + expr = create( + create(create(5), create("a"))); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::LINEAR); + + expr = create(create(41), + create(create(5), + create("b"))); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::LINEAR); + + expr = create( + create(create("c"), create("d"))); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::NON_LINEAR); + + expr = create(create(41), + create(create(5), + create("e")), + create(create("f"), + create("g"))); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::NON_LINEAR); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/expressions/test_PrintAndEvalNodes.cpp b/src/tests/src/solver/expressions/test_PrintAndEvalNodes.cpp index 8ad5a49a60..74743b383c 100644 --- a/src/tests/src/solver/expressions/test_PrintAndEvalNodes.cpp +++ b/src/tests/src/solver/expressions/test_PrintAndEvalNodes.cpp @@ -59,16 +59,16 @@ Fixtures are used for the Registry that manages the memory allocations of nodes So instead of writing Registry mem; - Node* root = mem.create(mem.create(21), mem.create(2)); + Node* root = mem.create(mem.create(21), mem.create(2)); We can just write - Node* root = create(create(21), create(2)); + Node* root = create(create(21), create(2)); since create is short for this->create. */ BOOST_FIXTURE_TEST_CASE(print_add_two_literals, Registry) { - Node* root = create(create(21), create(2)); + Node* root = create(create(21), create(2)); PrintVisitor printVisitor; const auto printed = printVisitor.dispatch(root); @@ -77,15 +77,89 @@ BOOST_FIXTURE_TEST_CASE(print_add_two_literals, Registry) "(21.000000+2.000000)"); // TODO Number of decimals implementation dependent ? } +BOOST_FIXTURE_TEST_CASE(print_add_one_literal, Registry) +{ + Node* root = create(create(215)); + + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(root); + + BOOST_CHECK_EQUAL(printed, + "(215.000000)"); // TODO Number of decimals implementation dependent ? +} + +BOOST_FIXTURE_TEST_CASE(print_add_zero_literal, Registry) +{ + Node* root = create(); + + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(root); + + BOOST_CHECK_EQUAL(printed, "()"); +} + +BOOST_FIXTURE_TEST_CASE(print_add_six_literals, Registry) +{ + Node* root = create(create(21), + create(2), + create(34), + create(56), + create(12), + create(86)); + + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(root); + + BOOST_CHECK_EQUAL( + printed, + "(21.000000+2.000000+34.000000+56.000000+12.000000+86.000000)"); // TODO Number of decimals + // implementation dependent ? +} + BOOST_FIXTURE_TEST_CASE(eval_add_two_literals, Registry) { - Node* root = create(create(21), create(2)); + Node* root = create(create(21), create(2)); EvalVisitor evalVisitor; double eval = evalVisitor.dispatch(root); BOOST_CHECK_EQUAL(eval, 23.); } +BOOST_FIXTURE_TEST_CASE(eval_add_one_literal, Registry) +{ + Node* root = create(create(215)); + + EvalVisitor evalVisitor; + double eval = evalVisitor.dispatch(root); + + BOOST_CHECK_EQUAL(eval, 215.); +} + +BOOST_FIXTURE_TEST_CASE(eval_add_zero_literal, Registry) +{ + Node* root = create(); + + EvalVisitor evalVisitor; + double eval = evalVisitor.dispatch(root); + + BOOST_CHECK_EQUAL(eval, 0.); +} + +BOOST_FIXTURE_TEST_CASE(eval_add_six_literals, Registry) +{ + Node* root = create(create(21), + create(2), + create(34), + create(56), + create(12), + create(86)); + + EvalVisitor evalVisitor; + double eval = evalVisitor.dispatch(root); + + BOOST_CHECK_EQUAL(eval, 211.); +} + BOOST_FIXTURE_TEST_CASE(eval_negation_literal, Registry) { const double num = 1428.0; @@ -101,18 +175,18 @@ BOOST_FIXTURE_TEST_CASE(eval_Add_And_Negation_Nodes, Registry) const double num1 = 1428; const double num2 = 8241; Node* negative_num2 = create(create(num2)); - Node* root = create(create(num1), negative_num2); + Node* root = create(create(num1), negative_num2); EvalVisitor evalVisitor; double eval = evalVisitor.dispatch(root); BOOST_CHECK_EQUAL(eval, num1 - num2); } -BOOST_FIXTURE_TEST_CASE(Negative_of_AddNode, Registry) +BOOST_FIXTURE_TEST_CASE(Negative_of_SumNode, Registry) { const double num1 = 1428; const double num2 = 8241; - Node* add_node = create(create(num1), create(num2)); + Node* add_node = create(create(num1), create(num2)); Node* neg = create(add_node); EvalVisitor evalVisitor; double eval = evalVisitor.dispatch(neg); @@ -257,7 +331,7 @@ BOOST_FIXTURE_TEST_CASE(comparison_node, Registry) BOOST_AUTO_TEST_CASE(invalidNode) { - AddNode* null_node = nullptr; + SumNode* null_node = nullptr; EvalVisitor evalVisitor; BOOST_CHECK_THROW(evalVisitor.dispatch(null_node), InvalidNode); } diff --git a/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp b/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp index 8a4080fc0c..2dba4fbd3d 100644 --- a/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp +++ b/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp @@ -56,7 +56,7 @@ BOOST_FIXTURE_TEST_CASE(SubstitutionVisitor_substitute_one_node, Registry) auto* component_original = create("component1", "notInThere"); - Node* root = create(create("component1", "variable1"), + Node* root = create(create("component1", "variable1"), component_original); SubstitutionVisitor sub(*this, ctx); Node* subsd = sub.dispatch(root); @@ -65,10 +65,10 @@ BOOST_FIXTURE_TEST_CASE(SubstitutionVisitor_substitute_one_node, Registry) BOOST_CHECK_NE(root, subsd); // We expect to find a substituted node on the left - BOOST_CHECK_EQUAL(dynamic_cast(subsd)->left(), variables.first); + BOOST_CHECK_EQUAL((*dynamic_cast(subsd))[0], variables.first); // We expect to find an original node on the right - auto* right_substituted = dynamic_cast(subsd)->right(); + auto* right_substituted = (*dynamic_cast(subsd))[1]; BOOST_CHECK_NE(right_substituted, variables.first); BOOST_CHECK_NE(right_substituted, variables.second); diff --git a/src/tests/src/solver/expressions/test_TimeIndexVisitor.cpp b/src/tests/src/solver/expressions/test_TimeIndexVisitor.cpp index 21920db288..d95ae2f188 100644 --- a/src/tests/src/solver/expressions/test_TimeIndexVisitor.cpp +++ b/src/tests/src/solver/expressions/test_TimeIndexVisitor.cpp @@ -78,8 +78,8 @@ BOOST_FIXTURE_TEST_CASE(simple_time_dependant_expression, Registry) TimeIndex::VARYING_IN_SCENARIO_ONLY); BOOST_CHECK_EQUAL(timeIndexVisitor.dispatch(&variableNode1), TimeIndex::VARYING_IN_TIME_ONLY); - // addition of parameterNode1 and variableNode1 is time and scenario dependent - Node* expr = create(¶meterNode1, &variableNode1); + // addition of literalNode, parameterNode1 and variableNode1 is time and scenario dependent + Node* expr = create(&literalNode, ¶meterNode1, &variableNode1); BOOST_CHECK_EQUAL(timeIndexVisitor.dispatch(expr), TimeIndex::VARYING_IN_TIME_AND_SCENARIO); } @@ -97,7 +97,7 @@ static std::pair s_(Registry& registry) } static const std::vector (*)(Registry& registry)> - operator_ALL{&s_, + operator_ALL{&s_, &s_, &s_, &s_, diff --git a/src/tests/src/solver/expressions/test_nodes.cpp b/src/tests/src/solver/expressions/test_nodes.cpp index 01e4a5b41c..3078a9cfbe 100644 --- a/src/tests/src/solver/expressions/test_nodes.cpp +++ b/src/tests/src/solver/expressions/test_nodes.cpp @@ -68,7 +68,7 @@ BOOST_FIXTURE_TEST_CASE(nodes_name, Registry) auto literalNode = create(2024.2); std::map nodes = { {literalNode, "LiteralNode"}, - {create(literalNode, literalNode), "AddNode"}, + {create(literalNode, literalNode), "SumNode"}, {create(literalNode, literalNode), "SubtractionNode"}, {create(literalNode, literalNode), "MultiplicationNode"}, {create(literalNode, literalNode), "DivisionNode"}, From 5b8cd4a1f0857f79f09995fcb83f559eeb0c638e Mon Sep 17 00:00:00 2001 From: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Date: Wed, 18 Sep 2024 13:11:24 +0200 Subject: [PATCH 002/103] Local matching removal : remove unused thread_number / numSpace (#2404) --- .../include/antares/solver/optimisation/weekly_optimization.h | 3 +-- src/solver/optimisation/weekly_optimization.cpp | 2 -- src/solver/simulation/economy.cpp | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/solver/optimisation/include/antares/solver/optimisation/weekly_optimization.h b/src/solver/optimisation/include/antares/solver/optimisation/weekly_optimization.h index e86e3b9683..5521bb8751 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/weekly_optimization.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/weekly_optimization.h @@ -32,15 +32,14 @@ class WeeklyOptimization public: WeeklyOptimization(const OptimizationOptions& options, PROBLEME_HEBDO* problemeHebdo, - uint numSpace, IResultWriter& writer, Simulation::ISimulationObserver& simulationObserver); ~WeeklyOptimization() = default; void solve(); +private: Antares::Solver::Optimization::OptimizationOptions options_; PROBLEME_HEBDO* const problemeHebdo_ = nullptr; - const uint thread_number_ = 0; IResultWriter& writer_; std::reference_wrapper simulationObserver_; }; diff --git a/src/solver/optimisation/weekly_optimization.cpp b/src/solver/optimisation/weekly_optimization.cpp index 8546263b13..1def21d921 100644 --- a/src/solver/optimisation/weekly_optimization.cpp +++ b/src/solver/optimisation/weekly_optimization.cpp @@ -27,12 +27,10 @@ namespace Antares::Solver::Optimization { WeeklyOptimization::WeeklyOptimization(const OptimizationOptions& options, PROBLEME_HEBDO* problemeHebdo, - uint thread_number, IResultWriter& writer, Simulation::ISimulationObserver& simulationObserver): options_(options), problemeHebdo_(problemeHebdo), - thread_number_(thread_number), writer_(writer), simulationObserver_(simulationObserver) { diff --git a/src/solver/simulation/economy.cpp b/src/solver/simulation/economy.cpp index 5e97ccc192..b6edbc4f6f 100644 --- a/src/solver/simulation/economy.cpp +++ b/src/solver/simulation/economy.cpp @@ -85,7 +85,6 @@ bool Economy::simulationBegin() weeklyOptProblems_.emplace_back(options, &pProblemesHebdo[numSpace], - numSpace, resultWriter, simulationObserver_.get()); From e24124dc8bb4a5f6a652a347bdbe49b43cde4c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Wed, 18 Sep 2024 13:16:25 +0200 Subject: [PATCH 003/103] Add SumNode "wide" test (#2403) Co-authored-by: OMNES Florian --- .../src/solver/expressions/test_DeepWideTrees.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/tests/src/solver/expressions/test_DeepWideTrees.cpp b/src/tests/src/solver/expressions/test_DeepWideTrees.cpp index 311358bc67..cf3fabd84d 100644 --- a/src/tests/src/solver/expressions/test_DeepWideTrees.cpp +++ b/src/tests/src/solver/expressions/test_DeepWideTrees.cpp @@ -84,4 +84,17 @@ BOOST_FIXTURE_TEST_CASE(binary_tree, Registry) BOOST_CHECK_EQUAL(evalVisitor.dispatch(node), 42. * 1024); } +BOOST_FIXTURE_TEST_CASE(wide_sum_tree, Registry) +{ + const int nb_operands = 1'000; + std::vector operands(nb_operands); + for (auto& op: operands) + { + op = create(1.); + } + SumNode root(std::move(operands)); + EvalVisitor evalVisitor; + BOOST_CHECK_EQUAL(evalVisitor.dispatch(&root), nb_operands * 1.); +} + BOOST_AUTO_TEST_SUITE_END() From 8f6290298e91bdda618046066cdfc74c92b5bf03 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Fri, 20 Sep 2024 00:23:33 +0200 Subject: [PATCH 004/103] Modeler 2.4c: portfield substitution (#2406) Co-authored-by: OMNES Florian --- src/solver/expressions/CMakeLists.txt | 3 + .../visitors/PortfieldSubstitutionVisitor.h | 59 ++++++++++++++++++ .../visitors/PortfieldSubstitutionVisitor.cpp | 61 +++++++++++++++++++ src/tests/cucumber/conf.yaml | 1 + .../expressions/test_SubstitutionVisitor.cpp | 54 ++++++++++++++++ 5 files changed, 178 insertions(+) create mode 100644 src/solver/expressions/include/antares/solver/expressions/visitors/PortfieldSubstitutionVisitor.h create mode 100644 src/solver/expressions/visitors/PortfieldSubstitutionVisitor.cpp create mode 100644 src/tests/cucumber/conf.yaml diff --git a/src/solver/expressions/CMakeLists.txt b/src/solver/expressions/CMakeLists.txt index b165529a9c..2e917c4c79 100644 --- a/src/solver/expressions/CMakeLists.txt +++ b/src/solver/expressions/CMakeLists.txt @@ -16,6 +16,7 @@ set(SRC_Expressions visitors/TimeIndexVisitor.cpp visitors/PrintVisitor.cpp visitors/SubstitutionVisitor.cpp + visitors/PortfieldSubstitutionVisitor.cpp visitors/InvalidNode.cpp include/antares/solver/expressions/nodes/SumNode.h @@ -50,6 +51,7 @@ set(SRC_Expressions include/antares/solver/expressions/visitors/TimeIndexVisitor.h include/antares/solver/expressions/visitors/TimeIndex.h include/antares/solver/expressions/visitors/SubstitutionVisitor.h + include/antares/solver/expressions/visitors/PortfieldSubstitutionVisitor.h include/antares/solver/expressions/visitors/InvalidNode.h include/antares/solver/expressions/Registry.hxx @@ -67,6 +69,7 @@ target_include_directories(antares-solver-expressions target_link_libraries(antares-solver-expressions PUBLIC Antares::logs + Boost::headers ) diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/PortfieldSubstitutionVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/PortfieldSubstitutionVisitor.h new file mode 100644 index 0000000000..bd4a23cfbb --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/PortfieldSubstitutionVisitor.h @@ -0,0 +1,59 @@ +/* +** 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 "antares/solver/expressions/visitors/CloneVisitor.h" + +namespace Antares::Solver::Visitors +{ + +struct KeyHasher +{ + std::size_t operator()(const Nodes::PortFieldNode& n) const; +}; + +/** + * @brief Represents the context for performing substitutions in a syntax tree. + */ +struct PortfieldSubstitutionContext +{ + std::unordered_map portfield; +}; + +/** + * @brief Represents a visitor for substituting portfield nodes in a syntax tree. + */ +class PortfieldSubstitutionVisitor: public CloneVisitor +{ +public: + PortfieldSubstitutionVisitor(Registry& registry, + PortfieldSubstitutionContext& ctx); + + PortfieldSubstitutionContext& ctx_; + std::string name() const override; + +private: + // Only override visit method for PortField, clone the rest + Nodes::Node* visit(const Nodes::PortFieldNode* node) override; +}; +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/PortfieldSubstitutionVisitor.cpp b/src/solver/expressions/visitors/PortfieldSubstitutionVisitor.cpp new file mode 100644 index 0000000000..8a91361c5a --- /dev/null +++ b/src/solver/expressions/visitors/PortfieldSubstitutionVisitor.cpp @@ -0,0 +1,61 @@ +/* +** 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 + +#include +#include + +namespace Antares::Solver::Visitors +{ + +PortfieldSubstitutionVisitor::PortfieldSubstitutionVisitor(Registry& registry, + PortfieldSubstitutionContext& ctx): + CloneVisitor(registry), + ctx_(ctx) +{ +} + +Nodes::Node* PortfieldSubstitutionVisitor::visit(const Nodes::PortFieldNode* node) +{ + if (auto it = ctx_.portfield.find(*node); it != ctx_.portfield.end()) + { + return it->second; + } + + return CloneVisitor::visit(node); +} + +std::string PortfieldSubstitutionVisitor::name() const +{ + return "PortfieldSubstitutionVisitor"; +} + +std::size_t KeyHasher::operator()(const Nodes::PortFieldNode& n) const +{ + std::size_t seed = 0; + + boost::hash_combine(seed, boost::hash_value(n.getPortName())); + boost::hash_combine(seed, boost::hash_value(n.getFieldName())); + + return seed; +} + +} // namespace Antares::Solver::Visitors diff --git a/src/tests/cucumber/conf.yaml b/src/tests/cucumber/conf.yaml new file mode 100644 index 0000000000..c6149dcba6 --- /dev/null +++ b/src/tests/cucumber/conf.yaml @@ -0,0 +1 @@ +antares-solver : /home/payetvin/Antares_Simulator/_build/solver/antares-solver \ No newline at end of file diff --git a/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp b/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp index 2dba4fbd3d..a13d2392a8 100644 --- a/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp +++ b/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include @@ -87,3 +89,55 @@ BOOST_FIXTURE_TEST_CASE(SubstitutionVisitor_name, Registry) BOOST_CHECK_EQUAL(substitutionVisitor.name(), "SubstitutionVisitor"); } BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(_PortfieldSubstitutionVisitor_) + +class SubstitutionFixture: public Registry +{ +public: + Node* originalExpression() + { + Node* port1 = create("port", "literal"); + Node* port2 = create("another port", "not a literal"); + Node* root = create(port1, port2); + return root; + } + + Node* expectedExpressionAfterSubstitution() + { + Node* node1 = create(10); + Node* port2 = create("another port", "not a literal"); + Node* root = create(node1, port2); + return root; + } + + Node* substitute(Node* original) + { + PortfieldSubstitutionContext ctx; + ctx.portfield.emplace(PortFieldNode("port", "literal"), create(10)); + + PortfieldSubstitutionVisitor sub(*this, ctx); + return sub.dispatch(original); + } +}; + +BOOST_FIXTURE_TEST_CASE(PortfieldSubstitutionVisitor_simple, SubstitutionFixture) + +{ + Node* original = originalExpression(); + Node* substituted = substitute(original); + Node* expected = expectedExpressionAfterSubstitution(); + + CompareVisitor cmp; + BOOST_CHECK(cmp.dispatch(substituted, expected)); +} + +BOOST_FIXTURE_TEST_CASE(PortfieldSubstitutionVisitor_name, Registry) +{ + PortfieldSubstitutionContext ctx; + + PortfieldSubstitutionVisitor substitutionVisitor(*this, ctx); + BOOST_CHECK_EQUAL(substitutionVisitor.name(), "PortfieldSubstitutionVisitor"); +} + +BOOST_AUTO_TEST_SUITE_END() From f7e5af7390e37a5c4047f02cc3995d9ef791daa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20Mar=C3=A9chal?= <45510813+JasonMarechal25@users.noreply.github.com> Date: Fri, 20 Sep 2024 00:24:56 +0200 Subject: [PATCH 005/103] Fix or-tools integration (#2402) Update to properly handle new [or-tools-rte repository](https://github.com/rte-france/or-tools-rte) --- ortools_tag | 2 +- src/CMakeLists.txt | 25 ++++++++++++++----------- src/solver/simulation/CMakeLists.txt | 7 ++++--- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/ortools_tag b/ortools_tag index ef2956ed2d..88446ca998 100644 --- a/ortools_tag +++ b/ortools_tag @@ -1 +1 @@ -v9.10-rte1.0 \ No newline at end of file +v9.10-rte1.2 \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6631922410..43358fa472 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -207,8 +207,8 @@ find_package(sirius_solver REQUIRED) find_package(ortools) if(NOT ortools_FOUND OR BUILD_ORTOOLS) message(STATUS "OR-Tools tag ${ORTOOLS_TAG}") - FetchContent_Declare(ortools - GIT_REPOSITORY "https://github.com/rte-france/or-tools-rte" + FetchContent_Declare(ortools-rte + GIT_REPOSITORY "https://github.com/rte-france/or-tools-rte.git" GIT_TAG ${ORTOOLS_TAG} GIT_SHALLOW TRUE ) @@ -226,8 +226,11 @@ message(STATUS "OR-Tools tag ${ORTOOLS_TAG}") # In mode optimization error analysis, we call Sirius through or-tools # So we need to activate Sirius in or-tools configuration (OFF by default) set(USE_SIRIUS "ON" CACHE INTERNAL "") + set(ortools_REPO "https://github.com/google/or-tools.git") + string(REGEX MATCH "^[^-]+" OFFICIAL_TAG ${ORTOOLS_TAG}) + set(ortools_REF ${OFFICIAL_TAG}) - FetchContent_MakeAvailable(ortools) + FetchContent_MakeAvailable(ortools-rte) endif() find_package(minizip-ng QUIET) @@ -243,7 +246,7 @@ else () endif () #wxWidget not needed for all library find is done in ui CMakeLists.txt -if (VCPKG_TOOLCHAIN AND NOT BUILD_wxWidgets) +if (VCPKG_TOOLCHAIN AND NOT BUILD_wxWidgets) #Add cmake directory to CMAKE_MODULE_PATH to use specific FindwxWidgets package needed for vcpkg list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/wxWidgets") endif() @@ -294,7 +297,7 @@ OMESSAGE("") - + # Informations for NSIS if(WIN32 OR WIN64) if(MSVC) @@ -310,7 +313,7 @@ if(WIN32 OR WIN64) set(COMPILER_MARK "m") set(COMPILER_INCLUDE "mingw") endif(MSVC) - + set(CPACK_MODULE_PATH ${CMAKE_CURRENT_BINARY_DIR}/distrib/win32 ${CPACK_MODULE_PATH}) # Configure file with custom definitions for NSIS. @@ -318,17 +321,17 @@ if(WIN32 OR WIN64) ${PROJECT_SOURCE_DIR}/distrib/win32/version.cmake ${CMAKE_CURRENT_BINARY_DIR}/distrib/win32/version.nsh ) - + configure_file( ${PROJECT_SOURCE_DIR}/distrib/win32/build.template.cmake ${CMAKE_CURRENT_BINARY_DIR}/distrib/win32/build.nsh ) - + configure_file( ${PROJECT_SOURCE_DIR}/distrib/win32/make-zip-from-installer.cmake ${CMAKE_CURRENT_BINARY_DIR}/distrib/win32/make-zip-from-installer.bat ) - + SET(ANTARES_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) # Define system libraries so NSIS can package these files @@ -349,7 +352,7 @@ if(WIN32 OR WIN64) ${CMAKE_CURRENT_BINARY_DIR}/distrib/win32/NSIS.template.in @ONLY ) - + #Define cpack install script to checkout examples configure_file( ${PROJECT_SOURCE_DIR}/distrib/CMakeLists.txt.in @@ -368,7 +371,7 @@ else() if(CMAKE_SYSTEM_NAME MATCHES "Linux") get_linux_lsb_release_information() message(STATUS "Linux ${LSB_RELEASE_ID_SHORT} ${LSB_RELEASE_VERSION_SHORT} ${LSB_RELEASE_CODENAME_SHORT}") - set(CPACK_SYSTEM_NAME "${LSB_RELEASE_ID_SHORT}-${LSB_RELEASE_VERSION_SHORT}") + set(CPACK_SYSTEM_NAME "${LSB_RELEASE_ID_SHORT}-${LSB_RELEASE_VERSION_SHORT}") endif() #For now only test deb, need to define several CPACK variable diff --git a/src/solver/simulation/CMakeLists.txt b/src/solver/simulation/CMakeLists.txt index b54d722e17..8ba67f0e73 100644 --- a/src/solver/simulation/CMakeLists.txt +++ b/src/solver/simulation/CMakeLists.txt @@ -27,7 +27,7 @@ set(SRC_SIMULATION include/antares/solver/simulation/solver.hxx include/antares/solver/simulation/solver.data.h solver.data.cpp - include/antares/solver/simulation/simulation-run.h + include/antares/solver/simulation/simulation-run.h simulation-run.cpp include/antares/solver/simulation/common-eco-adq.h common-eco-adq.cpp @@ -45,8 +45,8 @@ set(SRC_SIMULATION adequacy_patch_runtime_data.cpp include/antares/solver/simulation/ITimeSeriesNumbersWriter.h TimeSeriesNumbersWriter.cpp - include/antares/solver/simulation/BindingConstraintsTimeSeriesNumbersWriter.h - include/antares/solver/simulation/ISimulationObserver.h + include/antares/solver/simulation/BindingConstraintsTimeSeriesNumbersWriter.h + include/antares/solver/simulation/ISimulationObserver.h ) source_group("simulation" FILES ${SRC_SIMULATION}) @@ -54,6 +54,7 @@ source_group("simulation" FILES ${SRC_SIMULATION}) # --- Library VARIABLES --- # add_library(antares-solver-simulation) +add_library(Antares::antares-solver-simulation ALIAS antares-solver-simulation) target_sources(antares-solver-simulation PRIVATE ${SRC_SIMULATION}) From c70a4ad9c10dfb684ab154b48ceaf8bc401194ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Fri, 20 Sep 2024 13:45:20 +0200 Subject: [PATCH 006/103] Partial revert following #2406 (#2409) Co-authored-by: OMNES Florian --- src/tests/cucumber/conf.yaml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/tests/cucumber/conf.yaml diff --git a/src/tests/cucumber/conf.yaml b/src/tests/cucumber/conf.yaml deleted file mode 100644 index c6149dcba6..0000000000 --- a/src/tests/cucumber/conf.yaml +++ /dev/null @@ -1 +0,0 @@ -antares-solver : /home/payetvin/Antares_Simulator/_build/solver/antares-solver \ No newline at end of file From fa2f3090815f6e00c9e96a6f2a4d0b642c55b7ec Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Fri, 20 Sep 2024 15:54:26 +0200 Subject: [PATCH 007/103] Remove last global variable (#2410) close #1719 --------- Co-authored-by: Guillaume PIERRE --- .../include/antares/study/runtime/runtime.h | 4 +-- src/libs/antares/study/runtime/runtime.cpp | 6 ++++ src/solver/application/application.cpp | 3 -- src/solver/hydro/management/daily.cpp | 1 - src/solver/hydro/management/management.cpp | 1 - src/solver/hydro/management/monthly.cpp | 1 - .../optimisation/QuadraticProblemMatrix.h | 6 +--- .../opt_calcul_des_pmin_MUT_MDT.cpp | 1 - .../optimisation/opt_chainage_intercos.cpp | 1 - ...onstruction_variables_couts_demarrages.cpp | 1 - ...truction_variables_optimisees_lineaire.cpp | 1 - ...ction_variables_optimisees_quadratique.cpp | 1 - .../opt_decompte_variables_et_contraintes.cpp | 1 - ...riables_et_contraintes_couts_demarrage.cpp | 1 - ...opt_gestion_des_bornes_cas_quadratique.cpp | 1 - .../opt_gestion_des_couts_cas_lineaire.cpp | 1 - .../opt_gestion_des_couts_cas_quadratique.cpp | 2 -- .../opt_gestion_des_couts_couts_demarrage.cpp | 1 - .../optimisation/opt_gestion_des_pmin.cpp | 1 - ...opt_gestion_second_membre_cas_lineaire.cpp | 1 - ..._gestion_second_membre_cas_quadratique.cpp | 1 - ..._gestion_second_membre_couts_demarrage.cpp | 1 - .../opt_init_contraintes_hydrauliques.cpp | 1 - ...pt_init_minmax_groupes_couts_demarrage.cpp | 1 - .../opt_liberation_problemes_simplexe.cpp | 1 - ...e_min_groupes_demarres_couts_demarrage.cpp | 1 - .../opt_numero_de_jour_du_pas_de_temps.cpp | 1 - .../optimisation/opt_optimisation_hebdo.cpp | 1 - .../opt_pilotage_optimisation_lineaire.cpp | 1 - .../opt_pilotage_optimisation_quadratique.cpp | 1 - .../opt_restaurer_les_donnees.cpp | 1 - ..._verification_presence_reserve_jmoins1.cpp | 1 - src/solver/simulation/CMakeLists.txt | 3 -- src/solver/simulation/common-eco-adq.cpp | 6 ++-- .../sim_extern_variables_globales.h | 25 ------------- .../antares/solver/simulation/simulation.h | 4 --- .../simulation/sim_alloc_probleme_hebdo.cpp | 1 - .../simulation/sim_allocation_tableaux.cpp | 36 ------------------- .../simulation/sim_calcul_economique.cpp | 1 - .../simulation/sim_variables_globales.cpp | 24 ------------- src/solver/ts-generator/hydro.cpp | 1 - .../antares/solver/variable/commons/hydro.h | 1 - .../antares/solver/variable/commons/join.h | 1 - .../antares/solver/variable/commons/load.h | 2 -- .../variable/commons/miscGenMinusRowPSP.h | 1 - .../antares/solver/variable/commons/psp.h | 1 - .../solver/variable/commons/rowBalance.h | 1 - .../antares/solver/variable/commons/solar.h | 1 - .../antares/solver/variable/commons/wind.h | 1 - .../antares/solver/variable/economy/balance.h | 1 - .../solver/variable/economy/links/flowQuad.h | 5 ++- .../include/antares/solver/variable/state.h | 1 - src/tests/inmemory-study/in-memory-study.cpp | 2 -- 53 files changed, 17 insertions(+), 150 deletions(-) delete mode 100644 src/solver/simulation/include/antares/solver/simulation/sim_extern_variables_globales.h delete mode 100644 src/solver/simulation/sim_allocation_tableaux.cpp delete mode 100644 src/solver/simulation/sim_variables_globales.cpp 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 d87761674f..858719ab27 100644 --- a/src/libs/antares/study/include/antares/study/runtime/runtime.h +++ b/src/libs/antares/study/include/antares/study/runtime/runtime.h @@ -131,10 +131,10 @@ class StudyRuntimeInfos */ bool quadraticOptimizationHasFailed; + std::vector> transitMoyenInterconnexionsRecalculQuadratique; + private: void initializeRangeLimits(const Study& study, StudyRangeLimits& limits); - //! Prepare all thermal clusters in 'must-run' mode - void initializeThermalClustersInMustRunMode(Study& study) const; void removeDisabledShortTermStorageClustersFromSolverComputations(Study& study); void removeAllRenewableClustersFromSolverComputations(Study& study); void disableAllFilters(Study& study); diff --git a/src/libs/antares/study/runtime/runtime.cpp b/src/libs/antares/study/runtime/runtime.cpp index 61be13d6cf..bef958919d 100644 --- a/src/libs/antares/study/runtime/runtime.cpp +++ b/src/libs/antares/study/runtime/runtime.cpp @@ -343,6 +343,12 @@ bool StudyRuntimeInfos::loadFromStudy(Study& study) // Check if some clusters request TS generation checkThermalTSGeneration(study); + transitMoyenInterconnexionsRecalculQuadratique.resize(interconnectionsCount()); + for (uint i = 0; i != interconnectionsCount(); i++) + { + transitMoyenInterconnexionsRecalculQuadratique[i].assign(HOURS_PER_YEAR, 0.); + } + if (not gd.geographicTrimming) { disableAllFilters(study); diff --git a/src/solver/application/application.cpp b/src/solver/application/application.cpp index 837971f279..346c67496a 100644 --- a/src/solver/application/application.cpp +++ b/src/solver/application/application.cpp @@ -229,9 +229,6 @@ void Application::readDataForTheStudy(Data::StudyLoadOptions& options) study.performTransformationsBeforeLaunchingSimulation(); ScenarioBuilderOwner(study).callScenarioBuilder(); - - // alloc global vectors - SIM_AllocationTableaux(study); } void Application::startSimulation(Data::StudyLoadOptions& options) diff --git a/src/solver/hydro/management/daily.cpp b/src/solver/hydro/management/daily.cpp index d7a2aab668..d8b94d2cf4 100644 --- a/src/solver/hydro/management/daily.cpp +++ b/src/solver/hydro/management/daily.cpp @@ -38,7 +38,6 @@ #include "antares/solver/hydro/daily2/h2o2_j_donnees_mensuelles.h" #include "antares/solver/hydro/daily2/h2o2_j_fonctions.h" #include "antares/solver/hydro/management/management.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" using namespace Yuni; diff --git a/src/solver/hydro/management/management.cpp b/src/solver/hydro/management/management.cpp index a43dd3161f..c4e716e0c4 100644 --- a/src/solver/hydro/management/management.cpp +++ b/src/solver/hydro/management/management.cpp @@ -28,7 +28,6 @@ #include #include #include -#include "antares/solver/simulation/sim_extern_variables_globales.h" namespace Antares { diff --git a/src/solver/hydro/management/monthly.cpp b/src/solver/hydro/management/monthly.cpp index 8afcd0e26f..b60235dd97 100644 --- a/src/solver/hydro/management/monthly.cpp +++ b/src/solver/hydro/management/monthly.cpp @@ -32,7 +32,6 @@ #include "antares/solver/hydro/management/management.h" #include "antares/solver/hydro/monthly/h2o_m_donnees_annuelles.h" #include "antares/solver/hydro/monthly/h2o_m_fonctions.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" using namespace Yuni; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/QuadraticProblemMatrix.h b/src/solver/optimisation/include/antares/solver/optimisation/QuadraticProblemMatrix.h index 31563498a3..417a20a064 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/QuadraticProblemMatrix.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/QuadraticProblemMatrix.h @@ -21,11 +21,7 @@ #pragma once -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "ProblemMatrixEssential.h" #include "constraints/ExchangeBalanceGroup.h" diff --git a/src/solver/optimisation/opt_calcul_des_pmin_MUT_MDT.cpp b/src/solver/optimisation/opt_calcul_des_pmin_MUT_MDT.cpp index 16212e0bfd..7ec46fb34f 100644 --- a/src/solver/optimisation/opt_calcul_des_pmin_MUT_MDT.cpp +++ b/src/solver/optimisation/opt_calcul_des_pmin_MUT_MDT.cpp @@ -23,7 +23,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/simulation.h" diff --git a/src/solver/optimisation/opt_chainage_intercos.cpp b/src/solver/optimisation/opt_chainage_intercos.cpp index 8d1f362ffd..6052091e12 100644 --- a/src/solver/optimisation/opt_chainage_intercos.cpp +++ b/src/solver/optimisation/opt_chainage_intercos.cpp @@ -20,7 +20,6 @@ */ #include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/simulation.h" void OPT_ChainagesDesIntercoPartantDUnNoeud(PROBLEME_HEBDO* problemeHebdo) diff --git a/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp b/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp index 98a259540d..d9a8ab2ff6 100644 --- a/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp +++ b/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp @@ -22,7 +22,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_rename_problem.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "spx_constantes_externes.h" #include "variables/VariableManagerUtils.h" diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp index 40736b5428..aee0553b58 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp @@ -23,7 +23,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_rename_problem.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "variables/VariableManagerUtils.h" diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp index 10018bf29d..3552081dd8 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp @@ -21,7 +21,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/simulation.h" diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp index 1f773bb9ea..1eebc32619 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp @@ -23,7 +23,6 @@ #include #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/simulation.h" using namespace Antares; diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp index ed4216b8a3..894358b4d0 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp @@ -22,7 +22,6 @@ #include "antares/solver/optimisation/LinearProblemMatrixStartUpCosts.h" #include "antares/solver/optimisation/constraints/constraint_builder_utils.h" #include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/simulation.h" void OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(PROBLEME_HEBDO* problemeHebdo) diff --git a/src/solver/optimisation/opt_gestion_des_bornes_cas_quadratique.cpp b/src/solver/optimisation/opt_gestion_des_bornes_cas_quadratique.cpp index e48672d22a..debfb77cfb 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_cas_quadratique.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_cas_quadratique.cpp @@ -23,7 +23,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/simulation.h" #include "pi_constantes_externes.h" 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 9831750143..945c4cff46 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp @@ -23,7 +23,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/simulation.h" diff --git a/src/solver/optimisation/opt_gestion_des_couts_cas_quadratique.cpp b/src/solver/optimisation/opt_gestion_des_couts_cas_quadratique.cpp index 4e3c137cf7..1aed52c0cb 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_cas_quadratique.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_cas_quadratique.cpp @@ -21,8 +21,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" -#include "antares/solver/simulation/simulation.h" #include "variables/VariableManagerUtils.h" diff --git a/src/solver/optimisation/opt_gestion_des_couts_couts_demarrage.cpp b/src/solver/optimisation/opt_gestion_des_couts_couts_demarrage.cpp index 3112f70e68..ddd82a5439 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_couts_demarrage.cpp @@ -21,7 +21,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/simulation.h" diff --git a/src/solver/optimisation/opt_gestion_des_pmin.cpp b/src/solver/optimisation/opt_gestion_des_pmin.cpp index 921371b0e3..3545863475 100644 --- a/src/solver/optimisation/opt_gestion_des_pmin.cpp +++ b/src/solver/optimisation/opt_gestion_des_pmin.cpp @@ -19,7 +19,6 @@ ** along with Antares_Simulator. If not, see . */ #include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/simulation.h" 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 3818f73e38..44e95a917c 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp @@ -21,7 +21,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" using namespace Antares; using namespace Antares::Data; diff --git a/src/solver/optimisation/opt_gestion_second_membre_cas_quadratique.cpp b/src/solver/optimisation/opt_gestion_second_membre_cas_quadratique.cpp index 44d6486041..dd56778c3f 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_cas_quadratique.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_cas_quadratique.cpp @@ -21,7 +21,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/simulation.h" void OPT_InitialiserLeSecondMembreDuProblemeQuadratique(PROBLEME_HEBDO* problemeHebdo, int PdtHebdo) diff --git a/src/solver/optimisation/opt_gestion_second_membre_couts_demarrage.cpp b/src/solver/optimisation/opt_gestion_second_membre_couts_demarrage.cpp index 215532e83e..101badf675 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_couts_demarrage.cpp @@ -22,7 +22,6 @@ #include #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" using namespace Antares; diff --git a/src/solver/optimisation/opt_init_contraintes_hydrauliques.cpp b/src/solver/optimisation/opt_init_contraintes_hydrauliques.cpp index c9f25e418f..49773e3e18 100644 --- a/src/solver/optimisation/opt_init_contraintes_hydrauliques.cpp +++ b/src/solver/optimisation/opt_init_contraintes_hydrauliques.cpp @@ -20,7 +20,6 @@ */ #include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/simulation.h" diff --git a/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp b/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp index 1ca75d33d2..2d47676ae4 100644 --- a/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp @@ -20,7 +20,6 @@ */ #include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/simulation.h" diff --git a/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp b/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp index df0a9b4e37..ff5ed8b393 100644 --- a/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp +++ b/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp @@ -21,7 +21,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/simulation.h" #include "antares/solver/utils/ortools_utils.h" 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 705fd63290..d4c13e828d 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 @@ -22,7 +22,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" extern "C" diff --git a/src/solver/optimisation/opt_numero_de_jour_du_pas_de_temps.cpp b/src/solver/optimisation/opt_numero_de_jour_du_pas_de_temps.cpp index 122c3a36d2..64c2d55a37 100644 --- a/src/solver/optimisation/opt_numero_de_jour_du_pas_de_temps.cpp +++ b/src/solver/optimisation/opt_numero_de_jour_du_pas_de_temps.cpp @@ -22,7 +22,6 @@ #include #include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/simulation.h" void OPT_NumeroDeJourDuPasDeTemps(PROBLEME_HEBDO* problemeHebdo) diff --git a/src/solver/optimisation/opt_optimisation_hebdo.cpp b/src/solver/optimisation/opt_optimisation_hebdo.cpp index d5d3abb5b2..67fe13faca 100644 --- a/src/solver/optimisation/opt_optimisation_hebdo.cpp +++ b/src/solver/optimisation/opt_optimisation_hebdo.cpp @@ -25,7 +25,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/ISimulationObserver.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" extern "C" { diff --git a/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp b/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp index de1732d43c..06e1909126 100644 --- a/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp +++ b/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp @@ -23,7 +23,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/ISimulationObserver.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" using Antares::Solver::Optimization::OptimizationOptions; diff --git a/src/solver/optimisation/opt_pilotage_optimisation_quadratique.cpp b/src/solver/optimisation/opt_pilotage_optimisation_quadratique.cpp index 4f2d37bf96..4da985a2b7 100644 --- a/src/solver/optimisation/opt_pilotage_optimisation_quadratique.cpp +++ b/src/solver/optimisation/opt_pilotage_optimisation_quadratique.cpp @@ -24,7 +24,6 @@ #include "antares/solver/optimisation/QuadraticProblemMatrix.h" #include "antares/solver/optimisation/constraints/constraint_builder_utils.h" #include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" extern "C" { #include "spx_fonctions.h" diff --git a/src/solver/optimisation/opt_restaurer_les_donnees.cpp b/src/solver/optimisation/opt_restaurer_les_donnees.cpp index ec701b1202..ace1e645c5 100644 --- a/src/solver/optimisation/opt_restaurer_les_donnees.cpp +++ b/src/solver/optimisation/opt_restaurer_les_donnees.cpp @@ -21,7 +21,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/simulation.h" diff --git a/src/solver/optimisation/opt_verification_presence_reserve_jmoins1.cpp b/src/solver/optimisation/opt_verification_presence_reserve_jmoins1.cpp index 52f3c92f19..e696c08bd7 100644 --- a/src/solver/optimisation/opt_verification_presence_reserve_jmoins1.cpp +++ b/src/solver/optimisation/opt_verification_presence_reserve_jmoins1.cpp @@ -21,7 +21,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/simulation.h" diff --git a/src/solver/simulation/CMakeLists.txt b/src/solver/simulation/CMakeLists.txt index 8ba67f0e73..17e511fac5 100644 --- a/src/solver/simulation/CMakeLists.txt +++ b/src/solver/simulation/CMakeLists.txt @@ -4,12 +4,9 @@ set(SRC_SIMULATION sim_alloc_probleme_hebdo.cpp include/antares/solver/simulation/sim_alloc_probleme_hebdo.h - sim_allocation_tableaux.cpp sim_calcul_economique.cpp - include/antares/solver/simulation/sim_extern_variables_globales.h include/antares/solver/simulation/sim_structure_donnees.h include/antares/solver/simulation/sim_structure_probleme_economique.h - sim_variables_globales.cpp include/antares/solver/simulation/sim_constants.h include/antares/solver/simulation/simulation.h include/antares/solver/simulation/solver.h diff --git a/src/solver/simulation/common-eco-adq.cpp b/src/solver/simulation/common-eco-adq.cpp index c9a9039ab6..5b46e35cce 100644 --- a/src/solver/simulation/common-eco-adq.cpp +++ b/src/solver/simulation/common-eco-adq.cpp @@ -109,7 +109,9 @@ static void RecalculDesEchangesMoyens(Data::Study& study, for (uint j = 0; j < study.runtime.interconnectionsCount(); ++j) { - transitMoyenInterconnexionsRecalculQuadratique[j][indx] = ntcValues.ValeurDuFlux[j]; + study.runtime.transitMoyenInterconnexionsRecalculQuadratique[j][indx] = ntcValues + .ValeurDuFlux + [j]; } } } @@ -169,7 +171,7 @@ void ComputeFlowQuad(Data::Study& study, for (uint i = 0; i < (uint)problem.NombreDePasDeTemps; ++i) { const uint indx = i + PasDeTempsDebut; - transitMoyenInterconnexionsRecalculQuadratique[j][indx] = 0; + study.runtime.transitMoyenInterconnexionsRecalculQuadratique[j][indx] = 0; } } } diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_extern_variables_globales.h b/src/solver/simulation/include/antares/solver/simulation/sim_extern_variables_globales.h deleted file mode 100644 index cfcc9ff1e6..0000000000 --- a/src/solver/simulation/include/antares/solver/simulation/sim_extern_variables_globales.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 - -extern std::vector> transitMoyenInterconnexionsRecalculQuadratique; diff --git a/src/solver/simulation/include/antares/solver/simulation/simulation.h b/src/solver/simulation/include/antares/solver/simulation/simulation.h index bf214beff6..296e3bab82 100644 --- a/src/solver/simulation/include/antares/solver/simulation/simulation.h +++ b/src/solver/simulation/include/antares/solver/simulation/simulation.h @@ -29,10 +29,6 @@ struct PROBLEME_HEBDO; -// TODO remove when global variables have been removed (looking at you, -// transitMoyenInterconnexionsRecalculQuadratique) -void SIM_AllocationTableaux(const Antares::Data::Study& study); - /*! ** \brief Alloue toutes les donnees d'un probleme hebdo */ diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index 57f84225b1..df829e70df 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -22,7 +22,6 @@ #include #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "antares/study/simulation.h" diff --git a/src/solver/simulation/sim_allocation_tableaux.cpp b/src/solver/simulation/sim_allocation_tableaux.cpp deleted file mode 100644 index ebb711804d..0000000000 --- a/src/solver/simulation/sim_allocation_tableaux.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -** 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 -#include "antares/solver/simulation/sim_extern_variables_globales.h" -#include "antares/study/simulation.h" - -using namespace Antares; - -void SIM_AllocationTableaux(const Data::Study& study) -{ - transitMoyenInterconnexionsRecalculQuadratique.resize(study.runtime.interconnectionsCount()); - - for (uint i = 0; i != study.runtime.interconnectionsCount(); i++) - { - transitMoyenInterconnexionsRecalculQuadratique[i].assign(HOURS_PER_YEAR, 0.); - } -} diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index f31d1e4523..193b4b9ddd 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -28,7 +28,6 @@ #include #include #include "antares/solver/simulation/adequacy_patch_runtime_data.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "antares/solver/simulation/simulation.h" #include "antares/study/fwd.h" diff --git a/src/solver/simulation/sim_variables_globales.cpp b/src/solver/simulation/sim_variables_globales.cpp deleted file mode 100644 index 1fdcc04fa3..0000000000 --- a/src/solver/simulation/sim_variables_globales.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* -** 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 - -std::vector> transitMoyenInterconnexionsRecalculQuadratique; diff --git a/src/solver/ts-generator/hydro.cpp b/src/solver/ts-generator/hydro.cpp index 6f5fd8dfc7..dd5af1a25e 100644 --- a/src/solver/ts-generator/hydro.cpp +++ b/src/solver/ts-generator/hydro.cpp @@ -27,7 +27,6 @@ #include #include "antares/solver/misc/cholesky.h" #include "antares/solver/misc/matrix-dp-make.h" -#include "antares/solver/simulation/sim_extern_variables_globales.h" using namespace Antares; diff --git a/src/solver/variable/include/antares/solver/variable/commons/hydro.h b/src/solver/variable/include/antares/solver/variable/commons/hydro.h index e0ebdd41e5..46f45aebf3 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/hydro.h +++ b/src/solver/variable/include/antares/solver/variable/commons/hydro.h @@ -21,7 +21,6 @@ #ifndef __SOLVER_VARIABLE_ECONOMY_TimeSeriesValuesHydro_H__ #define __SOLVER_VARIABLE_ECONOMY_TimeSeriesValuesHydro_H__ -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/variable/variable.h" namespace Antares diff --git a/src/solver/variable/include/antares/solver/variable/commons/join.h b/src/solver/variable/include/antares/solver/variable/commons/join.h index de27416213..37f048ec83 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/join.h +++ b/src/solver/variable/include/antares/solver/variable/commons/join.h @@ -21,7 +21,6 @@ #ifndef __SOLVER_VARIABLE_ECONOMY_Join_H__ #define __SOLVER_VARIABLE_ECONOMY_Join_H__ -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/variable/variable.h" namespace Antares diff --git a/src/solver/variable/include/antares/solver/variable/commons/load.h b/src/solver/variable/include/antares/solver/variable/commons/load.h index 3080f2f44a..46b7681e55 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/load.h +++ b/src/solver/variable/include/antares/solver/variable/commons/load.h @@ -21,8 +21,6 @@ #ifndef __SOLVER_VARIABLE_ECONOMY_TimeSeriesValuesLoad_H__ #define __SOLVER_VARIABLE_ECONOMY_TimeSeriesValuesLoad_H__ -#include "antares/solver/simulation/sim_extern_variables_globales.h" - #include "../variable.h" namespace Antares diff --git a/src/solver/variable/include/antares/solver/variable/commons/miscGenMinusRowPSP.h b/src/solver/variable/include/antares/solver/variable/commons/miscGenMinusRowPSP.h index acb74f7d9f..cd7f7d6ba5 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/miscGenMinusRowPSP.h +++ b/src/solver/variable/include/antares/solver/variable/commons/miscGenMinusRowPSP.h @@ -22,7 +22,6 @@ #define __SOLVER_VARIABLE_ECONOMY_MiscGenMinusRowPSP_H__ #include -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/variable/variable.h" namespace Antares diff --git a/src/solver/variable/include/antares/solver/variable/commons/psp.h b/src/solver/variable/include/antares/solver/variable/commons/psp.h index 06814e1800..856a4ac529 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/psp.h +++ b/src/solver/variable/include/antares/solver/variable/commons/psp.h @@ -22,7 +22,6 @@ #define __SOLVER_VARIABLE_ECONOMY_PSP_H__ #include -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/variable/variable.h" namespace Antares diff --git a/src/solver/variable/include/antares/solver/variable/commons/rowBalance.h b/src/solver/variable/include/antares/solver/variable/commons/rowBalance.h index 503d11f981..2dd2d31729 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/rowBalance.h +++ b/src/solver/variable/include/antares/solver/variable/commons/rowBalance.h @@ -22,7 +22,6 @@ #define __SOLVER_VARIABLE_ECONOMY_RowBalance_H__ #include -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/variable/variable.h" namespace Antares diff --git a/src/solver/variable/include/antares/solver/variable/commons/solar.h b/src/solver/variable/include/antares/solver/variable/commons/solar.h index c5ab16422d..ad5f6ca679 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/solar.h +++ b/src/solver/variable/include/antares/solver/variable/commons/solar.h @@ -21,7 +21,6 @@ #ifndef __SOLVER_VARIABLE_ECONOMY_TimeSeriesValuesSolar_H__ #define __SOLVER_VARIABLE_ECONOMY_TimeSeriesValuesSolar_H__ -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/variable/variable.h" namespace Antares diff --git a/src/solver/variable/include/antares/solver/variable/commons/wind.h b/src/solver/variable/include/antares/solver/variable/commons/wind.h index 3e0fda355b..d545311fef 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/wind.h +++ b/src/solver/variable/include/antares/solver/variable/commons/wind.h @@ -21,7 +21,6 @@ #ifndef __SOLVER_VARIABLE_ECONOMY_TimeSeriesValuesWind_H__ #define __SOLVER_VARIABLE_ECONOMY_TimeSeriesValuesWind_H__ -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/variable/variable.h" namespace Antares diff --git a/src/solver/variable/include/antares/solver/variable/economy/balance.h b/src/solver/variable/include/antares/solver/variable/economy/balance.h index 8547c075ae..6dda7c7b5c 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/balance.h +++ b/src/solver/variable/include/antares/solver/variable/economy/balance.h @@ -21,7 +21,6 @@ #ifndef __SOLVER_VARIABLE_ECONOMY_BALANCE_H__ #define __SOLVER_VARIABLE_ECONOMY_BALANCE_H__ -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/variable/variable.h" namespace Antares diff --git a/src/solver/variable/include/antares/solver/variable/economy/links/flowQuad.h b/src/solver/variable/include/antares/solver/variable/economy/links/flowQuad.h index b6de8329ae..a15d662293 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/links/flowQuad.h +++ b/src/solver/variable/include/antares/solver/variable/economy/links/flowQuad.h @@ -130,6 +130,7 @@ class FlowQuad: public Variable::IVariable, NextT, VCardFlowQuad { // Average on all years pNbHours = study.runtime.rangeLimits.hour[Data::rangeEnd] + 1; + transitMoyenInterco_ = &study.runtime.transitMoyenInterconnexionsRecalculQuadratique; AncestorType::pResults.initializeFromStudy(study); AncestorType::pResults.reset(); @@ -166,7 +167,7 @@ class FlowQuad: public Variable::IVariable, NextT, VCardFlowQuad { // Flow assessed over all MC years (linear) (void)::memcpy(pValuesForTheCurrentYear.hour, - transitMoyenInterconnexionsRecalculQuadratique[pLinkGlobalIndex].data(), + (*transitMoyenInterco_)[pLinkGlobalIndex].data(), sizeof(double) * pNbHours); // Compute all statistics for the current year (daily,weekly,monthly) @@ -268,6 +269,8 @@ class FlowQuad: public Variable::IVariable, NextT, VCardFlowQuad private: uint pLinkGlobalIndex; uint pNbHours; + std::vector>* transitMoyenInterco_; + //! Intermediate values for each year typename VCardType::IntermediateValuesType pValuesForTheCurrentYear; diff --git a/src/solver/variable/include/antares/solver/variable/state.h b/src/solver/variable/include/antares/solver/variable/state.h index eb3edda98c..cbd55f4949 100644 --- a/src/solver/variable/include/antares/solver/variable/state.h +++ b/src/solver/variable/include/antares/solver/variable/state.h @@ -28,7 +28,6 @@ #include #include -#include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" diff --git a/src/tests/inmemory-study/in-memory-study.cpp b/src/tests/inmemory-study/in-memory-study.cpp index cfe1c1d130..d889ed66c9 100644 --- a/src/tests/inmemory-study/in-memory-study.cpp +++ b/src/tests/inmemory-study/in-memory-study.cpp @@ -196,8 +196,6 @@ void SimulationHandler::create() resultWriter_, observer_); Antares::Solver::ScenarioBuilderOwner(study_).callScenarioBuilder(); - - SIM_AllocationTableaux(study_); } // ========================= From 777b041ecccf467a23300261f7d22226bb1fbd20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 23 Sep 2024 11:28:30 +0200 Subject: [PATCH 008/103] Remove unused code & #defines (#2412) Remove unused `SNPRINTF` macro & other defines --- .../study/binding_constraint/BindingConstraint.cpp | 7 +++---- .../daily/h2o_j_resoudre_le_probleme_lineaire.cpp | 10 ++-------- .../daily2/h2o2_j_resoudre_le_probleme_lineaire.cpp | 6 ------ .../monthly/h2o_m_resoudre_le_probleme_lineaire.cpp | 10 ++-------- .../optimisation/opt_alloc_probleme_a_optimiser.cpp | 6 ------ ..._nombre_min_groupes_demarres_couts_demarrage.cpp | 8 -------- src/solver/utils/mps_utils.cpp | 13 ------------- 7 files changed, 7 insertions(+), 53 deletions(-) diff --git a/src/libs/antares/study/binding_constraint/BindingConstraint.cpp b/src/libs/antares/study/binding_constraint/BindingConstraint.cpp index 36acdb1a59..abdce0befb 100644 --- a/src/libs/antares/study/binding_constraint/BindingConstraint.cpp +++ b/src/libs/antares/study/binding_constraint/BindingConstraint.cpp @@ -32,7 +32,6 @@ #include "antares/study/study.h" #include "antares/utils/utils.h" -using namespace Yuni; using namespace Antares; #define SEP IO::Separator @@ -48,7 +47,7 @@ namespace Antares::Data BindingConstraint::Operator BindingConstraint::StringToOperator(const AnyString& text) { - ShortString16 l(text); + Yuni::ShortString16 l(text); l.toLower(); if (l == "both" || l == "<>" || l == "><" || l == "< and >") @@ -74,7 +73,7 @@ BindingConstraint::Type BindingConstraint::StringToType(const AnyString& text) { if (!text.empty()) { - ShortString16 l(text); + Yuni::ShortString16 l(text); l.toLower(); switch (l.first()) { @@ -441,7 +440,7 @@ bool BindingConstraint::contains(const Area* area) const return false; } -void BindingConstraint::buildFormula(String& s) const +void BindingConstraint::buildFormula(Yuni::String& s) const { char tmp[42]; bool first = true; diff --git a/src/solver/hydro/daily/h2o_j_resoudre_le_probleme_lineaire.cpp b/src/solver/hydro/daily/h2o_j_resoudre_le_probleme_lineaire.cpp index 1786428cef..549fc1878a 100644 --- a/src/solver/hydro/daily/h2o_j_resoudre_le_probleme_lineaire.cpp +++ b/src/solver/hydro/daily/h2o_j_resoudre_le_probleme_lineaire.cpp @@ -19,17 +19,11 @@ ** along with Antares_Simulator. If not, see . */ +#include + #include "antares/solver/hydro/daily/h2o_j_donnees_mensuelles.h" #include "antares/solver/hydro/daily/h2o_j_fonctions.h" -#ifdef _MSC_VER -#define SNPRINTF sprintf_s -#else -#define SNPRINTF snprintf -#endif - -#include - void H2O_J_ResoudreLeProblemeLineaire(DONNEES_MENSUELLES* DonneesMensuelles, int NumeroDeProbleme) { PROBLEME_HYDRAULIQUE& ProblemeHydraulique = DonneesMensuelles->ProblemeHydraulique; diff --git a/src/solver/hydro/daily2/h2o2_j_resoudre_le_probleme_lineaire.cpp b/src/solver/hydro/daily2/h2o2_j_resoudre_le_probleme_lineaire.cpp index a0366dce53..80060310d3 100644 --- a/src/solver/hydro/daily2/h2o2_j_resoudre_le_probleme_lineaire.cpp +++ b/src/solver/hydro/daily2/h2o2_j_resoudre_le_probleme_lineaire.cpp @@ -22,12 +22,6 @@ #include "antares/solver/hydro/daily2/h2o2_j_donnees_mensuelles.h" #include "antares/solver/hydro/daily2/h2o2_j_fonctions.h" -#ifdef _MSC_VER -#define SNPRINTF sprintf_s -#else -#define SNPRINTF snprintf -#endif - void H2O2_J_ResoudreLeProblemeLineaire(DONNEES_MENSUELLES_ETENDUES& DonneesMensuelles, int NumeroDeProbleme) { diff --git a/src/solver/hydro/monthly/h2o_m_resoudre_le_probleme_lineaire.cpp b/src/solver/hydro/monthly/h2o_m_resoudre_le_probleme_lineaire.cpp index f65ec03e6e..62dfb84121 100644 --- a/src/solver/hydro/monthly/h2o_m_resoudre_le_probleme_lineaire.cpp +++ b/src/solver/hydro/monthly/h2o_m_resoudre_le_probleme_lineaire.cpp @@ -19,17 +19,11 @@ ** along with Antares_Simulator. If not, see . */ +#include + #include "antares/solver/hydro/monthly/h2o_m_donnees_annuelles.h" #include "antares/solver/hydro/monthly/h2o_m_fonctions.h" -#ifdef _MSC_VER -#define SNPRINTF sprintf_s -#else -#define SNPRINTF snprintf -#endif - -#include - void H2O_M_ResoudreLeProblemeLineaire(DONNEES_ANNUELLES& DonneesAnnuelles, int NumeroDeReservoir) { PROBLEME_HYDRAULIQUE& ProblemeHydraulique = DonneesAnnuelles.ProblemeHydraulique; diff --git a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp index d7e812e32d..f041b2471e 100644 --- a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp +++ b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp @@ -26,12 +26,6 @@ using namespace Antares; -#ifdef _MSC_VER -#define SNPRINTF sprintf_s -#else -#define SNPRINTF snprintf -#endif - void OPT_AllocateFromNumberOfVariableConstraints(PROBLEME_ANTARES_A_RESOUDRE* ProblemeAResoudre, int NbTermes) { 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 d4c13e828d..c1e013a3c8 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 @@ -18,7 +18,6 @@ ** You should have received a copy of the Mozilla Public Licence 2.0 ** along with Antares_Simulator. If not, see . */ -#include #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" @@ -32,13 +31,6 @@ extern "C" using namespace Antares; using namespace Antares::Data; -using namespace Yuni; - -#ifdef _MSC_VER -#define SNPRINTF sprintf_s -#else -#define SNPRINTF snprintf -#endif void OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO*, std::vector&, diff --git a/src/solver/utils/mps_utils.cpp b/src/solver/utils/mps_utils.cpp index 6780b84922..06b86f9a7c 100644 --- a/src/solver/utils/mps_utils.cpp +++ b/src/solver/utils/mps_utils.cpp @@ -26,15 +26,6 @@ using namespace Antares; using namespace Antares::Data; -using namespace Yuni; - -#ifdef _MSC_VER -#define SNPRINTF sprintf_s -#else -#define SNPRINTF snprintf -#endif - -constexpr size_t OPT_APPEL_SOLVEUR_BUFFER_SIZE = 256; /* ** Copyright 2007-2023 RTE @@ -71,10 +62,6 @@ constexpr size_t OPT_APPEL_SOLVEUR_BUFFER_SIZE = 256; #include "antares/solver/utils/filename.h" #include "antares/solver/utils/name_translator.h" -using namespace Yuni; - -#define SEP IO::Separator - class ProblemConverter { public: From 380ccd7df681393e0ff5bab2b6e3c0bd73c955af Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:52:43 +0200 Subject: [PATCH 009/103] Reset adequacy patch enabled (#2420) --- src/libs/antares/study/parameters/adq-patch-params.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/antares/study/parameters/adq-patch-params.cpp b/src/libs/antares/study/parameters/adq-patch-params.cpp index f0158b85e5..0cefe33482 100644 --- a/src/libs/antares/study/parameters/adq-patch-params.cpp +++ b/src/libs/antares/study/parameters/adq-patch-params.cpp @@ -153,6 +153,8 @@ void CurtailmentSharing::addProperties(IniFile::Section* section) const // ------------------------ void AdqPatchParams::reset() { + enabled = false; + curtailmentSharing.reset(); setToZeroOutsideInsideLinks = true; } From c4b9373aa47613b79f00d390e161e16de5861550 Mon Sep 17 00:00:00 2001 From: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:45:53 +0200 Subject: [PATCH 010/103] Headers files : remove useless inclusions in OPT (#2411) --- .../solver/hydro/management/management.h | 5 +--- src/solver/hydro/management/daily.cpp | 25 ++++++---------- src/solver/hydro/management/management.cpp | 3 -- src/solver/hydro/management/monthly.cpp | 29 +++++++------------ .../solver/optimisation/opt_fonctions.h | 1 - .../opt_alloc_probleme_a_optimiser.cpp | 3 +- .../opt_appel_solveur_lineaire.cpp | 29 +++++-------------- .../opt_appel_solveur_quadratique.cpp | 12 ++++---- .../opt_calcul_des_pmin_MUT_MDT.cpp | 7 +---- .../optimisation/opt_chainage_intercos.cpp | 3 +- ...onstruction_variables_couts_demarrages.cpp | 6 ++-- ...truction_variables_optimisees_lineaire.cpp | 6 ++-- ...ction_variables_optimisees_quadratique.cpp | 5 +--- .../opt_decompte_variables_et_contraintes.cpp | 7 ++--- ...riables_et_contraintes_couts_demarrage.cpp | 4 --- .../optimisation/opt_export_structure.cpp | 2 +- .../opt_gestion_des_bornes_cas_lineaire.cpp | 15 +++------- ...opt_gestion_des_bornes_cas_quadratique.cpp | 10 ++----- ...opt_gestion_des_bornes_couts_demarrage.cpp | 6 ---- .../opt_gestion_des_couts_cas_lineaire.cpp | 11 ++----- .../opt_gestion_des_couts_couts_demarrage.cpp | 5 +--- .../optimisation/opt_gestion_des_pmin.cpp | 5 ++-- ...opt_gestion_second_membre_cas_lineaire.cpp | 8 ++--- ..._gestion_second_membre_cas_quadratique.cpp | 4 +-- ..._gestion_second_membre_couts_demarrage.cpp | 11 +------ .../opt_init_contraintes_hydrauliques.cpp | 6 +--- ...pt_init_minmax_groupes_couts_demarrage.cpp | 6 +--- .../opt_liberation_problemes_simplexe.cpp | 17 ++++------- ...e_min_groupes_demarres_couts_demarrage.cpp | 15 ++-------- .../opt_numero_de_jour_du_pas_de_temps.cpp | 7 +---- .../optimisation/opt_optimisation_hebdo.cpp | 16 +++++----- .../opt_optimisation_lineaire.cpp | 6 ++-- .../opt_pilotage_optimisation_lineaire.cpp | 2 +- .../opt_pilotage_optimisation_quadratique.cpp | 6 ---- .../optimisation/opt_rename_problem.cpp | 2 +- .../opt_restaurer_les_donnees.cpp | 7 +---- ..._verification_presence_reserve_jmoins1.cpp | 9 +----- .../variables/VariableManagement.h | 1 - .../variables/VariableManagerUtils.h | 2 +- .../simulation/sim_calcul_economique.cpp | 4 +-- src/tools/ts-generator/main.cpp | 1 - 41 files changed, 90 insertions(+), 239 deletions(-) diff --git a/src/solver/hydro/include/antares/solver/hydro/management/management.h b/src/solver/hydro/include/antares/solver/hydro/management/management.h index 8f4cf12d01..63c20bd263 100644 --- a/src/solver/hydro/include/antares/solver/hydro/management/management.h +++ b/src/solver/hydro/include/antares/solver/hydro/management/management.h @@ -23,13 +23,11 @@ #include -#include - #include #include #include +#include #include "antares/date/date.h" -#include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/writer/i_writer.h" namespace Antares @@ -113,7 +111,6 @@ class HydroManagement final const Data::AreaList& areas_; const Date::Calendar& calendar_; const Data::Parameters& parameters_; - unsigned int maxNbYearsInParallel_ = 0; Solver::IResultWriter& resultWriter_; HYDRO_VENTILATION_RESULTS ventilationResults_; diff --git a/src/solver/hydro/management/daily.cpp b/src/solver/hydro/management/daily.cpp index d8b94d2cf4..8bf59df763 100644 --- a/src/solver/hydro/management/daily.cpp +++ b/src/solver/hydro/management/daily.cpp @@ -21,17 +21,12 @@ #include #include +#include #include #include -#include -#include -#include - #include #include -#include -#include #include #include "antares/solver/hydro/daily/h2o_j_donnees_mensuelles.h" #include "antares/solver/hydro/daily/h2o_j_fonctions.h" @@ -39,9 +34,7 @@ #include "antares/solver/hydro/daily2/h2o2_j_fonctions.h" #include "antares/solver/hydro/management/management.h" -using namespace Yuni; - -#define SEP IO::Separator +namespace fs = std::filesystem; namespace { @@ -135,8 +128,8 @@ struct DebugData void writeTurb(const std::string filename, uint y) const { - std::ostringstream buffer, path; - path << "debug" << SEP << "solver" << SEP << (1 + y) << SEP << filename; + std::ostringstream buffer; + auto path = fs::path("debug") / "solver" / std::to_string(1 + y) / filename; buffer << "\tTurbine\t\t\tOPP\t\t\t\tTurbine Cible\tDLE\t\t\t\tDLN\n"; for (uint day = 0; day != 365; ++day) @@ -148,7 +141,7 @@ struct DebugData buffer << '\n'; } auto buffer_str = buffer.str(); - pWriter.addEntryFromBuffer(path.str(), buffer_str); + pWriter.addEntryFromBuffer(path.string(), buffer_str); } void writeDailyDebugData(const Date::Calendar& calendar, @@ -156,9 +149,9 @@ struct DebugData uint y, const Data::AreaName& areaName) const { - std::ostringstream buffer, path; - path << "debug" << SEP << "solver" << SEP << (1 + y) << SEP << "daily." << areaName.c_str() - << ".txt"; + std::ostringstream buffer; + auto path = fs::path("debug") / "solver" / std::to_string(1 + y) / "daily." + / areaName.c_str() / ".txt"; buffer << "\tNiveau init : " << hydro_specific.monthly[initReservoirLvlMonth].MOL << "\n"; for (uint month = 0; month != MONTHS_PER_YEAR; ++month) @@ -217,7 +210,7 @@ struct DebugData } } auto buffer_str = buffer.str(); - pWriter.addEntryFromBuffer(path.str(), buffer_str); + pWriter.addEntryFromBuffer(path.string(), buffer_str); } }; diff --git a/src/solver/hydro/management/management.cpp b/src/solver/hydro/management/management.cpp index c4e716e0c4..b4327deee3 100644 --- a/src/solver/hydro/management/management.cpp +++ b/src/solver/hydro/management/management.cpp @@ -24,10 +24,7 @@ #include #include -#include #include -#include -#include namespace Antares { diff --git a/src/solver/hydro/management/monthly.cpp b/src/solver/hydro/management/monthly.cpp index b60235dd97..62658e277d 100644 --- a/src/solver/hydro/management/monthly.cpp +++ b/src/solver/hydro/management/monthly.cpp @@ -18,30 +18,22 @@ ** You should have received a copy of the Mozilla Public Licence 2.0 ** along with Antares_Simulator. If not, see . */ +#include #include #include #include -#include -#include -#include - #include -#include -#include #include "antares/solver/hydro/management/management.h" #include "antares/solver/hydro/monthly/h2o_m_donnees_annuelles.h" #include "antares/solver/hydro/monthly/h2o_m_fonctions.h" -using namespace Yuni; - -#define SEP IO::Separator +namespace fs = std::filesystem; namespace Antares { -template static void CheckHydroAllocationProblem(Data::Area& area, - ProblemT& problem, + DONNEES_ANNUELLES& problem, int initLevelMonth, double lvi) { @@ -206,10 +198,9 @@ void HydroManagement::prepareMonthlyOptimalGenerations(const double* random_rese { case OUI: { - if (Logs::Verbosity::Debug::enabled) - { - CheckHydroAllocationProblem(area, problem, initReservoirLvlMonth, lvi); - } +#ifndef NDEBUG + CheckHydroAllocationProblem(area, problem, initReservoirLvlMonth, lvi); +#endif for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { @@ -269,9 +260,9 @@ void HydroManagement::prepareMonthlyOptimalGenerations(const double* random_rese #endif if (parameters_.hydroDebug) { - std::ostringstream buffer, path; - path << "debug" << SEP << "solver" << SEP << (1 + y) << SEP << "monthly." << area.name - << ".txt"; + std::ostringstream buffer; + auto path = fs::path("debug") / "solver" / std::to_string(1 + y) / "monthly." + / area.name.c_str() / ".txt"; if (area.hydro.reservoirManagement) buffer << "Initial Reservoir Level\t" << lvi << "\n"; @@ -313,7 +304,7 @@ void HydroManagement::prepareMonthlyOptimalGenerations(const double* random_rese buffer << '\n'; } auto content = buffer.str(); - resultWriter_.addEntryFromBuffer(path.str(), content); + resultWriter_.addEntryFromBuffer(path.string(), content); } indexArea++; }); diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h index 5a2aead56f..f215ae5dd1 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h @@ -54,7 +54,6 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaire(PROBLEME_HEBDO*, int, int, void OPT_InitialiserLeSecondMembreDuProblemeQuadratique(PROBLEME_HEBDO*, int); void OPT_InitialiserLesCoutsLineaire(PROBLEME_HEBDO*, const int, const int); void OPT_InitialiserLesCoutsQuadratiques(PROBLEME_HEBDO*, int); -void OPT_ControleDesPminPmaxThermiques(PROBLEME_HEBDO*); bool OPT_AppelDuSolveurQuadratique(PROBLEME_ANTARES_A_RESOUDRE*, const int); using namespace Antares::Data::AdequacyPatch; diff --git a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp index f041b2471e..20b448bde7 100644 --- a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp +++ b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp @@ -20,11 +20,10 @@ */ #include -#include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" -using namespace Antares; +int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO*); void OPT_AllocateFromNumberOfVariableConstraints(PROBLEME_ANTARES_A_RESOUDRE* ProblemeAResoudre, int NbTermes) diff --git a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp index 2dd81809da..94eae39fc8 100644 --- a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp +++ b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp @@ -19,35 +19,23 @@ * along with Antares_Simulator. If not, see . */ -#include - -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_probleme_economique.h" -#include "antares/solver/simulation/simulation.h" -#include "antares/solver/utils/basis_status.h" - -extern "C" -{ -#include "spx_definition_arguments.h" -#include "spx_fonctions.h" -#include "srs_api.h" -} - #include +#include +#include #include #include +#include "antares/optimization-options/options.h" #include "antares/solver/infeasible-problem-analysis/unfeasible-pb-analyzer.h" +#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "antares/solver/utils/filename.h" #include "antares/solver/utils/mps_utils.h" using namespace operations_research; -using namespace Antares; -using namespace Antares::Data; -using namespace Yuni; using Antares::Solver::IResultWriter; +using Antares::Solver::Optimization::OptimizationOptions; class TimeMeasurement { @@ -267,11 +255,8 @@ static SimplexResult OPT_TryToCallSimplex(const OptimizationOptions& options, logs.info() << " Solver: Standard resolution failed"; logs.info() << " Solver: Retry in safe mode"; // second trial w/o scaling + logs.debug() << " solver: resetting"; - if (Logs::Verbosity::Debug::enabled) - { - logs.info() << " solver: resetting"; - } return {.success = false, .timeMeasure = timeMeasure, .mps_writer_factory = mps_writer_factory}; diff --git a/src/solver/optimisation/opt_appel_solveur_quadratique.cpp b/src/solver/optimisation/opt_appel_solveur_quadratique.cpp index a491294a06..d59c6d8779 100644 --- a/src/solver/optimisation/opt_appel_solveur_quadratique.cpp +++ b/src/solver/optimisation/opt_appel_solveur_quadratique.cpp @@ -21,24 +21,22 @@ #include -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" - /* pi_define.h doesn't include this header, yet it uses struct jmp_buf. It would be nice to remove this include, but would require to change pi_define.h, which isn't part of Antares */ -#include +#include extern "C" { -#include "pi_define.h" -#include "pi_definition_arguments.h" -#include "pi_fonctions.h" +#include +#include +#include } #include +#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" using namespace Antares; diff --git a/src/solver/optimisation/opt_calcul_des_pmin_MUT_MDT.cpp b/src/solver/optimisation/opt_calcul_des_pmin_MUT_MDT.cpp index 7ec46fb34f..1e07bbcbd7 100644 --- a/src/solver/optimisation/opt_calcul_des_pmin_MUT_MDT.cpp +++ b/src/solver/optimisation/opt_calcul_des_pmin_MUT_MDT.cpp @@ -19,12 +19,7 @@ ** along with Antares_Simulator. If not, see . */ -#include - -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" constexpr double ZERO_PMIN = 1.e-2; diff --git a/src/solver/optimisation/opt_chainage_intercos.cpp b/src/solver/optimisation/opt_chainage_intercos.cpp index 6052091e12..d7298d77dd 100644 --- a/src/solver/optimisation/opt_chainage_intercos.cpp +++ b/src/solver/optimisation/opt_chainage_intercos.cpp @@ -19,8 +19,7 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" void OPT_ChainagesDesIntercoPartantDUnNoeud(PROBLEME_HEBDO* problemeHebdo) { diff --git a/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp b/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp index d9a8ab2ff6..35fa3faa2e 100644 --- a/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp +++ b/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp @@ -19,11 +19,11 @@ * along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" +#include + #include "antares/solver/optimisation/opt_rename_problem.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" -#include "spx_constantes_externes.h" #include "variables/VariableManagerUtils.h" void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarrage( diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp index aee0553b58..c1aa0e2991 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp @@ -20,12 +20,14 @@ */ #include -#include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_rename_problem.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "variables/VariableManagerUtils.h" +void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, + bool); + void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaire(PROBLEME_HEBDO* problemeHebdo) { const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp index 3552081dd8..068ca7d878 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp @@ -19,10 +19,7 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "pi_constantes_externes.h" #include "variables/VariableManagerUtils.h" diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp index 1eebc32619..1df4f0b3df 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp @@ -20,13 +20,12 @@ */ #include -#include -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" using namespace Antares; +void OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(PROBLEME_HEBDO*); + int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* problemeHebdo) { const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp index 894358b4d0..22b10d3440 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes_couts_demarrage.cpp @@ -21,8 +21,6 @@ #include "antares/solver/optimisation/LinearProblemMatrixStartUpCosts.h" #include "antares/solver/optimisation/constraints/constraint_builder_utils.h" -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/simulation.h" void OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(PROBLEME_HEBDO* problemeHebdo) { @@ -37,6 +35,4 @@ void OPT_DecompteDesVariablesEtDesContraintesCoutsDeDemarrage(PROBLEME_HEBDO* pr OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarrage(problemeHebdo, true); - - return; } diff --git a/src/solver/optimisation/opt_export_structure.cpp b/src/solver/optimisation/opt_export_structure.cpp index 78f39cca47..c0f5a14b4c 100644 --- a/src/solver/optimisation/opt_export_structure.cpp +++ b/src/solver/optimisation/opt_export_structure.cpp @@ -21,7 +21,7 @@ #include "antares/solver/optimisation/opt_export_structure.h" -#include +#include #include "antares/solver/simulation/sim_structure_probleme_economique.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 3b9eb9132a..50c63133fc 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp @@ -20,20 +20,17 @@ */ #include +#include -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/adequacy_patch_runtime_data.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" -#include "spx_constantes_externes.h" #include "variables/VariableManagement.h" #include "variables/VariableManagerUtils.h" -using namespace Antares; -using namespace Antares::Data; - -using namespace Yuni; +void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, + const int, + const int); void OPT_MaxDesPmaxHydrauliques(PROBLEME_HEBDO* problemeHebdo) { @@ -57,8 +54,6 @@ void OPT_MaxDesPmaxHydrauliques(PROBLEME_HEBDO* problemeHebdo) problemeHebdo->CaracteristiquesHydrauliques[pays].MaxDesPmaxHydrauliques = pmaxHyd; } - - return; } double OPT_SommeDesPminThermiques(const PROBLEME_HEBDO* problemeHebdo, int Pays, uint pdtHebdo) @@ -505,6 +500,4 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); } - - return; } diff --git a/src/solver/optimisation/opt_gestion_des_bornes_cas_quadratique.cpp b/src/solver/optimisation/opt_gestion_des_bornes_cas_quadratique.cpp index debfb77cfb..6cdafb3638 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_cas_quadratique.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_cas_quadratique.cpp @@ -18,20 +18,14 @@ ** You should have received a copy of the Mozilla Public Licence 2.0 ** along with Antares_Simulator. If not, see . */ +#include -#include +#include "antares/solver/simulation/sim_structure_probleme_economique.h" -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/simulation.h" - -#include "pi_constantes_externes.h" #include "variables/VariableManagerUtils.h" #define ZERO_POUR_LES_VARIABLES_FIXES 1.e-6 -using namespace Yuni; - void OPT_InitialiserLesBornesDesVariablesDuProblemeQuadratique(PROBLEME_HEBDO* problemeHebdo, int PdtHebdo) { diff --git a/src/solver/optimisation/opt_gestion_des_bornes_couts_demarrage.cpp b/src/solver/optimisation/opt_gestion_des_bornes_couts_demarrage.cpp index e73cb62779..04359e1109 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_couts_demarrage.cpp @@ -19,17 +19,11 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" -#include "antares/solver/simulation/simulation.h" #include "variables/VariableManagement.h" #include "variables/VariableManagerUtils.h" -using namespace Yuni; - void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaireCoutsDeDemarrage( PROBLEME_HEBDO* problemeHebdo, const int PremierPdtDeLIntervalle, 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 945c4cff46..893575110d 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp @@ -19,15 +19,12 @@ ** along with Antares_Simulator. If not, see . */ -#include - -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "variables/VariableManagerUtils.h" +void OPT_InitialiserLesCoutsLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, const int, const int); + static void shortTermStorageCost( int PremierPdtDeLIntervalle, int DernierPdtDeLIntervalle, @@ -343,6 +340,4 @@ void OPT_InitialiserLesCoutsLineaire(PROBLEME_HEBDO* problemeHebdo, PremierPdtDeLIntervalle, DernierPdtDeLIntervalle); } - - return; } diff --git a/src/solver/optimisation/opt_gestion_des_couts_couts_demarrage.cpp b/src/solver/optimisation/opt_gestion_des_couts_couts_demarrage.cpp index ddd82a5439..7d1d128a4a 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_couts_demarrage.cpp @@ -19,10 +19,7 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "variables/VariableManagerUtils.h" diff --git a/src/solver/optimisation/opt_gestion_des_pmin.cpp b/src/solver/optimisation/opt_gestion_des_pmin.cpp index 3545863475..4989520e28 100644 --- a/src/solver/optimisation/opt_gestion_des_pmin.cpp +++ b/src/solver/optimisation/opt_gestion_des_pmin.cpp @@ -18,9 +18,8 @@ ** You should have received a copy of the Mozilla Public Licence 2.0 ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/simulation.h" + +#include "antares/solver/simulation/sim_structure_probleme_economique.h" #define ZERO 1.e-2 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 44e95a917c..a824066209 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp @@ -19,12 +19,10 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" -using namespace Antares; -using namespace Antares::Data; -using namespace Yuni; +double OPT_SommeDesPminThermiques(const PROBLEME_HEBDO*, int, uint); +void OPT_InitialiserLeSecondMembreDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, int, int); static void shortTermStorageLevelsRHS( const std::vector<::ShortTermStorage::AREA_INPUT>& shortTermStorageInput, diff --git a/src/solver/optimisation/opt_gestion_second_membre_cas_quadratique.cpp b/src/solver/optimisation/opt_gestion_second_membre_cas_quadratique.cpp index dd56778c3f..b9b0b19162 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_cas_quadratique.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_cas_quadratique.cpp @@ -19,9 +19,7 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" void OPT_InitialiserLeSecondMembreDuProblemeQuadratique(PROBLEME_HEBDO* problemeHebdo, int PdtHebdo) { diff --git a/src/solver/optimisation/opt_gestion_second_membre_couts_demarrage.cpp b/src/solver/optimisation/opt_gestion_second_membre_couts_demarrage.cpp index 101badf675..48003b697d 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_couts_demarrage.cpp @@ -19,14 +19,7 @@ ** along with Antares_Simulator. If not, see . */ -#include -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_donnees.h" - -using namespace Antares; -using namespace Antares::Data; -using namespace Yuni; +#include "antares/solver/simulation/sim_structure_probleme_economique.h" void OPT_InitialiserLeSecondMembreDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HEBDO* problemeHebdo, int PremierPdtDeLIntervalle, @@ -104,6 +97,4 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaireCoutsDeDemarrage(PROBLEME_HE } } } - - return; } diff --git a/src/solver/optimisation/opt_init_contraintes_hydrauliques.cpp b/src/solver/optimisation/opt_init_contraintes_hydrauliques.cpp index 49773e3e18..13a780192b 100644 --- a/src/solver/optimisation/opt_init_contraintes_hydrauliques.cpp +++ b/src/solver/optimisation/opt_init_contraintes_hydrauliques.cpp @@ -19,9 +19,7 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" void OPT_InitialiserLesContrainteDEnergieHydrauliqueParIntervalleOptimise( PROBLEME_HEBDO* problemeHebdo) @@ -138,6 +136,4 @@ void OPT_InitialiserLesContrainteDEnergieHydrauliqueParIntervalleOptimise( InflowForTimeInterval[intervalle] = InflowSum; } } - - return; } diff --git a/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp b/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp index 2d47676ae4..1ec2ddcc2e 100644 --- a/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_init_minmax_groupes_couts_demarrage.cpp @@ -19,9 +19,7 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" void OPT_InitialiserNombreMinEtMaxDeGroupesCoutsDeDemarrage(PROBLEME_HEBDO* problemeHebdo) { @@ -70,6 +68,4 @@ void OPT_InitialiserNombreMinEtMaxDeGroupesCoutsDeDemarrage(PROBLEME_HEBDO* prob } } } - - return; } diff --git a/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp b/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp index ff5ed8b393..b1df3a06c9 100644 --- a/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp +++ b/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp @@ -19,18 +19,13 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/simulation.h" -#include "antares/solver/utils/ortools_utils.h" +#include -extern "C" -{ -#include "spx_fonctions.h" -} +#include "antares/optimization-options/options.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" +#include "antares/solver/utils/ortools_utils.h" -using namespace Antares; +using namespace Antares::Solver::Optimization; void OPT_LiberationProblemesSimplexe(const OptimizationOptions& options, const PROBLEME_HEBDO* problemeHebdo) @@ -72,6 +67,4 @@ void OPT_LiberationProblemesSimplexe(const OptimizationOptions& options, } } } - - return; } 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 c1e013a3c8..ec0e7e9bd2 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 @@ -19,18 +19,9 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_donnees.h" +#include -extern "C" -{ -#include "spx_definition_arguments.h" -#include "spx_fonctions.h" -} - -using namespace Antares; -using namespace Antares::Data; +#include "antares/solver/simulation/sim_structure_probleme_economique.h" void OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO*, std::vector&, @@ -649,6 +640,4 @@ void OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage( printf("Pas de solution au probleme auxiliaire\n"); #endif } - - return; } diff --git a/src/solver/optimisation/opt_numero_de_jour_du_pas_de_temps.cpp b/src/solver/optimisation/opt_numero_de_jour_du_pas_de_temps.cpp index 64c2d55a37..95e5ed50ad 100644 --- a/src/solver/optimisation/opt_numero_de_jour_du_pas_de_temps.cpp +++ b/src/solver/optimisation/opt_numero_de_jour_du_pas_de_temps.cpp @@ -19,10 +19,7 @@ ** along with Antares_Simulator. If not, see . */ -#include - -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" void OPT_NumeroDeJourDuPasDeTemps(PROBLEME_HEBDO* problemeHebdo) { @@ -33,7 +30,6 @@ void OPT_NumeroDeJourDuPasDeTemps(PROBLEME_HEBDO* problemeHebdo) double X = pdtHebdo / problemeHebdo->NombreDePasDeTempsDUneJournee; problemeHebdo->NumeroDeJourDuPasDeTemps[pdtHebdo] = (int)floor(X); } - return; } void OPT_NumeroDIntervalleOptimiseDuPasDeTemps(PROBLEME_HEBDO* problemeHebdo) @@ -43,5 +39,4 @@ void OPT_NumeroDIntervalleOptimiseDuPasDeTemps(PROBLEME_HEBDO* problemeHebdo) double X = pdtHebdo / problemeHebdo->NombreDePasDeTempsPourUneOptimisation; problemeHebdo->NumeroDIntervalleOptimiseDuPasDeTemps[pdtHebdo] = (int)floor(X); } - return; } diff --git a/src/solver/optimisation/opt_optimisation_hebdo.cpp b/src/solver/optimisation/opt_optimisation_hebdo.cpp index 67fe13faca..8317514098 100644 --- a/src/solver/optimisation/opt_optimisation_hebdo.cpp +++ b/src/solver/optimisation/opt_optimisation_hebdo.cpp @@ -22,20 +22,20 @@ #include #include #include -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/ISimulationObserver.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" -extern "C" -{ -#include "spx_fonctions.h" -} - -using namespace Antares; using namespace Antares::Data; using Antares::Solver::Optimization::OptimizationOptions; +bool OPT_PilotageOptimisationLineaire(const OptimizationOptions&, + PROBLEME_HEBDO*, + Solver::IResultWriter&, + Solver::Simulation::ISimulationObserver&); +bool OPT_PilotageOptimisationQuadratique(PROBLEME_HEBDO*); +void OPT_LiberationProblemesSimplexe(const OptimizationOptions&, const PROBLEME_HEBDO*); + void OPT_OptimisationHebdomadaire(const OptimizationOptions& options, PROBLEME_HEBDO* pProblemeHebdo, Solver::IResultWriter& writer, diff --git a/src/solver/optimisation/opt_optimisation_lineaire.cpp b/src/solver/optimisation/opt_optimisation_lineaire.cpp index 8ff621b612..99669ad1ea 100644 --- a/src/solver/optimisation/opt_optimisation_lineaire.cpp +++ b/src/solver/optimisation/opt_optimisation_lineaire.cpp @@ -20,8 +20,6 @@ */ #include -#include "antares/solver/lps/LpsFromAntares.h" -#include "antares/solver/optimisation/HebdoProblemToLpsTranslator.h" #include "antares/solver/optimisation/LinearProblemMatrix.h" #include "antares/solver/optimisation/constraints/constraint_builder_utils.h" #include "antares/solver/optimisation/opt_export_structure.h" @@ -29,8 +27,8 @@ #include "antares/solver/simulation/ISimulationObserver.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "antares/solver/utils/filename.h" -using namespace Antares; -using namespace Yuni; + +using namespace Antares::Solver; using Antares::Solver::Optimization::OptimizationOptions; namespace diff --git a/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp b/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp index 06e1909126..8c95462332 100644 --- a/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp +++ b/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp @@ -21,8 +21,8 @@ #include "antares/optimization-options/options.h" #include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/ISimulationObserver.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" using Antares::Solver::Optimization::OptimizationOptions; diff --git a/src/solver/optimisation/opt_pilotage_optimisation_quadratique.cpp b/src/solver/optimisation/opt_pilotage_optimisation_quadratique.cpp index 4da985a2b7..1337fb763b 100644 --- a/src/solver/optimisation/opt_pilotage_optimisation_quadratique.cpp +++ b/src/solver/optimisation/opt_pilotage_optimisation_quadratique.cpp @@ -19,15 +19,9 @@ ** along with Antares_Simulator. If not, see . */ -#include - #include "antares/solver/optimisation/QuadraticProblemMatrix.h" #include "antares/solver/optimisation/constraints/constraint_builder_utils.h" #include "antares/solver/optimisation/opt_fonctions.h" -extern "C" -{ -#include "spx_fonctions.h" -} bool OPT_PilotageOptimisationQuadratique(PROBLEME_HEBDO* problemeHebdo) { diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index 85edf581b8..1324c54fd8 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -22,7 +22,7 @@ #include "antares/solver/optimisation/opt_rename_problem.h" #include -#include +#include const std::string HOUR("hour"); const std::string DAY("day"); diff --git a/src/solver/optimisation/opt_restaurer_les_donnees.cpp b/src/solver/optimisation/opt_restaurer_les_donnees.cpp index ace1e645c5..bd058e88d2 100644 --- a/src/solver/optimisation/opt_restaurer_les_donnees.cpp +++ b/src/solver/optimisation/opt_restaurer_les_donnees.cpp @@ -19,10 +19,7 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" void OPT_RestaurerLesDonnees(PROBLEME_HEBDO* problemeHebdo) { @@ -132,6 +129,4 @@ void OPT_RestaurerLesDonnees(PROBLEME_HEBDO* problemeHebdo) } } } - - return; } diff --git a/src/solver/optimisation/opt_verification_presence_reserve_jmoins1.cpp b/src/solver/optimisation/opt_verification_presence_reserve_jmoins1.cpp index e696c08bd7..6216b6fa1d 100644 --- a/src/solver/optimisation/opt_verification_presence_reserve_jmoins1.cpp +++ b/src/solver/optimisation/opt_verification_presence_reserve_jmoins1.cpp @@ -19,12 +19,7 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/simulation.h" - -#include "spx_fonctions.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" void OPT_VerifierPresenceReserveJmoins1(PROBLEME_HEBDO* problemeHebdo) { @@ -45,6 +40,4 @@ void OPT_VerifierPresenceReserveJmoins1(PROBLEME_HEBDO* problemeHebdo) } } } - - return; } diff --git a/src/solver/optimisation/variables/VariableManagement.h b/src/solver/optimisation/variables/VariableManagement.h index 1c3144aa0a..b5054a121c 100644 --- a/src/solver/optimisation/variables/VariableManagement.h +++ b/src/solver/optimisation/variables/VariableManagement.h @@ -1,6 +1,5 @@ #pragma once -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" namespace VariableManagement diff --git a/src/solver/optimisation/variables/VariableManagerUtils.h b/src/solver/optimisation/variables/VariableManagerUtils.h index 1597fac34b..7c06f72a43 100644 --- a/src/solver/optimisation/variables/VariableManagerUtils.h +++ b/src/solver/optimisation/variables/VariableManagerUtils.h @@ -2,4 +2,4 @@ #include "VariableManagement.h" -VariableManagement::VariableManager VariableManagerFromProblemHebdo(PROBLEME_HEBDO* problemeHebdo); +VariableManagement::VariableManager VariableManagerFromProblemHebdo(PROBLEME_HEBDO*); diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 193b4b9ddd..79e6635613 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -19,11 +19,10 @@ ** along with Antares_Simulator. If not, see . */ -#include +#include #include #include -#include #include #include #include @@ -31,7 +30,6 @@ #include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "antares/solver/simulation/simulation.h" #include "antares/study/fwd.h" -#include "antares/study/simulation.h" using namespace Antares; using namespace Antares::Data; diff --git a/src/tools/ts-generator/main.cpp b/src/tools/ts-generator/main.cpp index 3c883a078b..baece8ca45 100644 --- a/src/tools/ts-generator/main.cpp +++ b/src/tools/ts-generator/main.cpp @@ -28,7 +28,6 @@ #include #include "antares/tools/ts-generator/linksTSgenerator.h" #include "antares/tools/ts-generator/tsGenerationOptions.h" -using namespace Antares::TSGenerator; using namespace Antares::TSGenerator; From 895555d22e6e064a64949cc3d9197c00bf75a4ef Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Wed, 25 Sep 2024 11:42:23 +0200 Subject: [PATCH 011/103] bump simtest (#2398) --- simtest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simtest.json b/simtest.json index c1478f4703..03ea9af205 100644 --- a/simtest.json +++ b/simtest.json @@ -1,3 +1,3 @@ { - "version": "v9.2.0d" + "version": "v9.2.0e" } From 33f35bea919f2af01ea0d02fb64cc5cb29340f80 Mon Sep 17 00:00:00 2001 From: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:48:51 +0200 Subject: [PATCH 012/103] visualize ast with graphviz (#2399) output : ![out](https://github.com/user-attachments/assets/d59ee1db-8a49-4cfc-a3f1-ed2c6c503821) legends box-style could match those of the nodes --- src/solver/expressions/CMakeLists.txt | 7 +- .../nodes/NodesForwardDeclaration.h | 1 + .../solver/expressions/nodes/SumNode.h | 2 +- .../expressions/visitors/AstDOTStyleVisitor.h | 196 +++++++++++++ src/solver/expressions/nodes/SumNode.cpp | 2 +- .../visitors/AstDOTStyleVisitor.cpp | 259 ++++++++++++++++++ .../src/solver/expressions/CMakeLists.txt | 7 +- .../expressions/test_AstDOTStyleVisitor.cpp | 171 ++++++++++++ 8 files changed, 637 insertions(+), 8 deletions(-) create mode 100644 src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h create mode 100644 src/solver/expressions/visitors/AstDOTStyleVisitor.cpp create mode 100644 src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp diff --git a/src/solver/expressions/CMakeLists.txt b/src/solver/expressions/CMakeLists.txt index 2e917c4c79..0a222c2d49 100644 --- a/src/solver/expressions/CMakeLists.txt +++ b/src/solver/expressions/CMakeLists.txt @@ -16,6 +16,7 @@ set(SRC_Expressions visitors/TimeIndexVisitor.cpp visitors/PrintVisitor.cpp visitors/SubstitutionVisitor.cpp + visitors/AstDOTStyleVisitor.cpp visitors/PortfieldSubstitutionVisitor.cpp visitors/InvalidNode.cpp @@ -51,6 +52,7 @@ set(SRC_Expressions include/antares/solver/expressions/visitors/TimeIndexVisitor.h include/antares/solver/expressions/visitors/TimeIndex.h include/antares/solver/expressions/visitors/SubstitutionVisitor.h + include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h include/antares/solver/expressions/visitors/PortfieldSubstitutionVisitor.h include/antares/solver/expressions/visitors/InvalidNode.h @@ -73,10 +75,9 @@ target_link_libraries(antares-solver-expressions ) - add_library(antares-solver-expressions-iterators - iterators/pre-order.cpp - include/antares/solver/expressions/iterators/pre-order.h + iterators/pre-order.cpp + include/antares/solver/expressions/iterators/pre-order.h ) target_link_libraries(antares-solver-expressions-iterators PRIVATE antares-solver-expressions) diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h b/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h index d1c653f991..eb637e1d15 100644 --- a/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h @@ -23,6 +23,7 @@ namespace Antares::Solver::Nodes { class Node; +class BinaryNode; class SumNode; class SubtractionNode; class MultiplicationNode; diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/SumNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/SumNode.h index 663954ada5..25a3ae5091 100644 --- a/src/solver/expressions/include/antares/solver/expressions/nodes/SumNode.h +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/SumNode.h @@ -75,7 +75,7 @@ class SumNode: public Node Node* operator[](std::size_t idx) const; - unsigned int size() const; + size_t size() const; std::string name() const override { diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h new file mode 100644 index 0000000000..d7d3daac8f --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h @@ -0,0 +1,196 @@ +/* +** 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 + +#include "antares/solver/expressions/visitors/NodeVisitor.h" + +namespace Antares::Solver::Visitors +{ +/** + * @struct BoxStyle + * @brief Represents the style attributes for a box in a graph. + * + * This structure defines the visual properties of a box, such as its color, + * shape, and style, which are used to customize the appearance of nodes in a graph. + */ +struct BoxStyle +{ + /** + * @brief The color of the box. + * + * This attribute specifies the color of the box. It is a string view that + * should contain a valid color name or code. + */ + std::string_view color; + + /** + * @brief The shape of the box. + * + * This attribute specifies the shape of the box. It is a string view that + * should contain a valid shape description (e.g., "circle", "rectangle"). + */ + std::string_view shape; + + /** + * @brief The style of the box. + * + * This attribute specifies the style of the box. It is a string view that + * should contain a valid style description (e.g., "filled", "dotted"). + */ + std::string_view style; +}; + +/** + * @class AstDOTStyleVisitor + * @brief A visitor class for generating DOT style output for ASTs (Abstract Syntax Trees). + * + * This class extends the `NodeVisitor` template class to produce a DOT representation + * of a given AST. The DOT format is commonly used for graph visualization tools, + * such as Graphviz. The visitor generates the graph structure, including nodes and + * edges, and outputs it to a stream. + * + * @tparam NodeVisitor A base class template for visiting nodes. + * @tparam std::ostream& The type of the output stream where the DOT representation is written. + * */ +class AstDOTStyleVisitor: public NodeVisitor +{ +public: + /** + * @brief Default constructor. + */ + AstDOTStyleVisitor() = default; + + /** + * @brief Begins a new tree graph. + * + * Initializes the DOT graph representation and sets the tree name. + * + * @param os The output stream to which the DOT representation is written. + * @param tree_name The name of the tree graph. Defaults to "ExpressionTree". + */ + void NewTreeGraph(std::ostream& os, const std::string& tree_name = "ExpressionTree"); + + /** + * @brief Ends the current tree graph. + * + * Finalizes the DOT graph representation. + * + * @param os The output stream to which the DOT representation is written. + */ + void EndTreeGraph(std::ostream& os); + + /** + * @brief Returns the name of this visitor. + * + * @return A string representing the name of the visitor. + */ + std::string name() const override; + +private: + void visit(const Nodes::SumNode* node, std::ostream& os) override; + void visit(const Nodes::SubtractionNode* node, std::ostream& os) override; + void visit(const Nodes::MultiplicationNode* node, std::ostream& os) override; + void visit(const Nodes::DivisionNode* node, std::ostream& os) override; + void visit(const Nodes::EqualNode* node, std::ostream& os) override; + void visit(const Nodes::LessThanOrEqualNode* node, std::ostream& os) override; + void visit(const Nodes::GreaterThanOrEqualNode* node, std::ostream& os) override; + void visit(const Nodes::NegationNode* node, std::ostream& os) override; + void visit(const Nodes::VariableNode* node, std::ostream& os) override; + void visit(const Nodes::ParameterNode* node, std::ostream& os) override; + void visit(const Nodes::LiteralNode* node, std::ostream& os) override; + void visit(const Nodes::PortFieldNode* node, std::ostream& os) override; + void visit(const Nodes::ComponentVariableNode* node, std::ostream& os) override; + void visit(const Nodes::ComponentParameterNode* node, std::ostream& os) override; + + /** + * @brief Retrieves a unique ID for a given node. + * + * Generates or retrieves a unique identifier for the specified node. + * + * @param node The node for which to get the ID. + * @return An integer representing the unique ID of the node. + */ + unsigned int getNodeID(const Nodes::Node* node); + + /** + * @brief Emits a node to the output stream. + * + * Writes the DOT representation of a node to the output stream with its associated label + * and style. + * + * @param id The unique ID of the node. + * @param label The label to be used for the node. + * @param box_style The style to be applied to the node's box. + * @param os The output stream to which the node representation is written. + */ + void emitNode(unsigned int id, + const std::string& label, + const BoxStyle& box_style, + std::ostream& os); + + /** + * @brief Processes a binary operation node. + * + * Handles the specific case of binary operation nodes by emitting the appropriate + * DOT representation. + * + * @param node The binary operation node to be processed. + * @param label The label to be used for the node. + * @param box_style The style to be applied to the node's box. + * @param os The output stream to which the node representation is written. + */ + void processBinaryOperation(const Nodes::BinaryNode* node, + const std::string& label, + const BoxStyle& box_style, + std::ostream& os); + + /** + * @brief A map of nodes to their unique IDs. + * + * This map is used to keep track of assigned IDs for each node in the AST. + */ + std::map> nodeIds_; + + /** + * @brief Counter for generating unique node IDs. + * + * This counter is incremented each time a new node ID is needed. + */ + unsigned int nodeCount_ = 0; +}; + +/** + * @brief Outputs the DOT representation of a node to a stream. + * + * This operator overload facilitates the use of the `AstDOTStyleVisitor` with a node + * for direct streaming of the DOT representation. + * + * @param os The output stream to which the DOT representation is written. + * @param visitorExpr A pair consisting of the visitor and the node to be output. + * @return The output stream. + */ +std::ostream& operator<<(std::ostream& os, + const std::pair& visitorExpr); + +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/nodes/SumNode.cpp b/src/solver/expressions/nodes/SumNode.cpp index d42668d06a..ab1050a7da 100644 --- a/src/solver/expressions/nodes/SumNode.cpp +++ b/src/solver/expressions/nodes/SumNode.cpp @@ -33,7 +33,7 @@ const std::vector& SumNode::getOperands() const return operands_; } -unsigned int SumNode::size() const +size_t SumNode::size() const { return operands_.size(); } diff --git a/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp new file mode 100644 index 0000000000..063343f511 --- /dev/null +++ b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp @@ -0,0 +1,259 @@ +/* +** 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/expressions/visitors/AstDOTStyleVisitor.h" + +#include +#include + +#include + +namespace Antares::Solver::Visitors +{ +namespace NodeStyle +{ +static constexpr BoxStyle SumStyle{"aqua", "hexagon", "filled, solid"}; +static constexpr BoxStyle BinaryStyle{"aqua", "oval", "filled, rounded"}; +static constexpr BoxStyle ComparisonStyle{"yellow", "diamond", "filled"}; +static constexpr BoxStyle NegationStyle{"tomato", "invtriangle", "filled, solid"}; +static constexpr BoxStyle LiteralStyle{"lightgray", "box", "filled, solid"}; +static constexpr BoxStyle VariableStyle{"gold", "box", "filled, solid"}; +static constexpr BoxStyle ParameterStyle{"wheat", "box", "filled, solid"}; +static constexpr BoxStyle ComponentParameterStyle{"springgreen", "octagon", "filled, solid"}; +static constexpr BoxStyle ComponentVariableStyle{"goldenrod", "octagon", "filled, solid"}; +static constexpr BoxStyle PortFieldStyle{"olive", "component", "filled, solid"}; +} // namespace NodeStyle + +void ProcessElementLegend(const std::string& element_name, size_t size, std::ostream& os) +{ + os << "legend_" << element_name << " [ label =\" " << element_name << ": " << size << "\"]\n"; +} + +void AddFiliation(std::ostream& os, const std::string& parent_id, const std::string& child_id) +{ + os << "legend_" << parent_id << " -> " << "legend_" << child_id << " [style=invis];\n"; +} + +void GetLegend(const std::map>& nodeIds, + std::ostream& os) +{ + os << R"raw(subgraph cluster_legend { +label = "Legend"; +style = dashed; +fontsize = 16; +color = lightgrey; +node [shape=plaintext]; + +)raw"; + + auto order_nb_type = nodeIds.size(); + if (order_nb_type > 1) + { + for (auto it = nodeIds.begin(), next_it = std::next(it); next_it != nodeIds.end(); + ++it, ++next_it) + { + ProcessElementLegend(it->first, it->second.size(), os); + AddFiliation(os, it->first, next_it->first); + } + ProcessElementLegend(nodeIds.rbegin()->first, nodeIds.rbegin()->second.size(), os); + } + else if (order_nb_type == 1) + { + ProcessElementLegend(nodeIds.begin()->first, nodeIds.begin()->second.size(), os); + } + + os << "}\n"; +} + +void AstDOTStyleVisitor::visit(const Nodes::SumNode* node, std::ostream& os) +{ + auto id = getNodeID(node); + emitNode(id, "+", NodeStyle::SumStyle, os); + for (auto* child: node->getOperands()) + { + auto childId = getNodeID(child); + os << " " << id << " -> " << childId << ";\n"; + dispatch(child, os); + } +} + +void AstDOTStyleVisitor::visit(const Nodes::SubtractionNode* node, std::ostream& os) +{ + processBinaryOperation(node, "-", NodeStyle::BinaryStyle, os); +} + +void AstDOTStyleVisitor::visit(const Nodes::MultiplicationNode* node, std::ostream& os) +{ + processBinaryOperation(node, "*", NodeStyle::BinaryStyle, os); +} + +void AstDOTStyleVisitor::visit(const Nodes::DivisionNode* node, std::ostream& os) +{ + processBinaryOperation(node, "/", NodeStyle::BinaryStyle, os); +} + +void AstDOTStyleVisitor::visit(const Nodes::EqualNode* node, std::ostream& os) +{ + processBinaryOperation(node, "==", NodeStyle::ComparisonStyle, os); +} + +void AstDOTStyleVisitor::visit(const Nodes::LessThanOrEqualNode* node, std::ostream& os) +{ + processBinaryOperation(node, "<=", NodeStyle::ComparisonStyle, os); +} + +void AstDOTStyleVisitor::visit(const Nodes::GreaterThanOrEqualNode* node, std::ostream& os) +{ + processBinaryOperation(node, ">=", NodeStyle::ComparisonStyle, os); +} + +void AstDOTStyleVisitor::visit(const Nodes::VariableNode* node, std::ostream& os) +{ + auto id = getNodeID(node); + emitNode(id, "Var(" + node->value() + ")", NodeStyle::VariableStyle, os); +} + +void AstDOTStyleVisitor::visit(const Nodes::ParameterNode* node, std::ostream& os) +{ + auto id = getNodeID(node); + emitNode(id, "Param(" + node->value() + ")", NodeStyle::ParameterStyle, os); +} + +void AstDOTStyleVisitor::visit(const Nodes::LiteralNode* node, std::ostream& os) +{ + auto id = getNodeID(node); + emitNode(id, std::to_string(node->value()), NodeStyle::LiteralStyle, os); +} + +void AstDOTStyleVisitor::visit(const Nodes::NegationNode* node, std::ostream& os) +{ + auto id = getNodeID(node); + emitNode(id, "-", NodeStyle::NegationStyle, os); + auto childId = getNodeID(node->child()); + os << " " << id << " -> " << childId << ";\n"; + dispatch(node->child(), os); +} + +void AstDOTStyleVisitor::visit(const Nodes::PortFieldNode* node, std::ostream& os) +{ + auto id = getNodeID(node); + emitNode(id, + "PF(" + node->getPortName() + "," + node->getFieldName() + ")", + NodeStyle::PortFieldStyle, + os); +} + +void AstDOTStyleVisitor::visit(const Nodes::ComponentVariableNode* node, std::ostream& os) +{ + auto id = getNodeID(node); + emitNode(id, + "CV(" + node->getComponentId() + "," + node->getComponentName() + ")", + NodeStyle::ComponentVariableStyle, + os); +} + +void AstDOTStyleVisitor::visit(const Nodes::ComponentParameterNode* node, std::ostream& os) +{ + auto id = getNodeID(node); + emitNode(id, + "CP(" + node->getComponentId() + "," + node->getComponentName() + ")", + NodeStyle::ComponentParameterStyle, + os); +} + +std::string AstDOTStyleVisitor::name() const +{ + return "AstDOTStyleVisitor"; +} + +unsigned int AstDOTStyleVisitor::getNodeID(const Nodes::Node* node) +{ + const auto& node_name = node->name(); + if (nodeIds_.find(node_name) == nodeIds_.end()) + { + nodeIds_[node->name()][node] = ++nodeCount_; + } + else if (auto& id_map = nodeIds_[node_name]; id_map.find(node) == id_map.end()) + { + id_map[node] = ++nodeCount_; + } + + return nodeIds_[node->name()][node]; +} + +void AstDOTStyleVisitor::emitNode(unsigned int id, + const std::string& label, + const BoxStyle& box_style, + std::ostream& os) +{ + os << " " << id << " [label=\"" << label << "\", shape=\"" << box_style.shape << "\", style=\"" + << box_style.style << "\", color=\"" << box_style.color << "\"];\n"; +} + +// Process binary operation nodes like Add, Subtract, etc. +void AstDOTStyleVisitor::processBinaryOperation(const Nodes::BinaryNode* node, + const std::string& label, + const BoxStyle& box_style, + std::ostream& os) +{ + auto id = getNodeID(node); + emitNode(id, label, box_style, os); + + const Nodes::Node* left = node->left(); + const Nodes::Node* right = node->right(); + + auto leftId = getNodeID(left); + auto rightId = getNodeID(right); + + os << " " << id << " -> " << leftId << ";\n"; + os << " " << id << " -> " << rightId << ";\n"; + + dispatch(left, os); + dispatch(right, os); +} + +void AstDOTStyleVisitor::NewTreeGraph(std::ostream& os, const std::string& tree_name) +{ + os << "digraph " + tree_name + " {\n"; + os << "node[style = filled]\n"; +} + +void AstDOTStyleVisitor::EndTreeGraph(std::ostream& os) +{ + // Graph title showing the total number of nodes + os << "label=\"AST Diagram(Total nodes : " << nodeCount_ << ")\"\n"; + os << "labelloc = \"t\"\n"; + GetLegend(nodeIds_, os); + os << "}\n"; + nodeCount_ = 0; + nodeIds_.clear(); +} + +std::ostream& operator<<(std::ostream& os, + const std::pair& visitorExpr) +{ + auto& [visitor, root] = visitorExpr; + visitor.NewTreeGraph(os); + visitor.dispatch(root, os); + visitor.EndTreeGraph(os); + return os; +} +} // namespace Antares::Solver::Visitors diff --git a/src/tests/src/solver/expressions/CMakeLists.txt b/src/tests/src/solver/expressions/CMakeLists.txt index f2166a71ad..319e961a8d 100644 --- a/src/tests/src/solver/expressions/CMakeLists.txt +++ b/src/tests/src/solver/expressions/CMakeLists.txt @@ -11,15 +11,16 @@ target_sources(${EXECUTABLE_NAME} test_LinearVisitor.cpp test_CompareVisitor.cpp test_CloneVisitor.cpp - test_DeepWideTrees.cpp - test_Iterators.cpp + test_DeepWideTrees.cpp + test_Iterators.cpp + test_AstDOTStyleVisitor.cpp ) target_link_libraries(${EXECUTABLE_NAME} PRIVATE Boost::unit_test_framework antares-solver-expressions - antares-solver-expressions-iterators + antares-solver-expressions-iterators ) # Storing tests-ts-numbers under the folder Unit-tests in the IDE diff --git a/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp b/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp new file mode 100644 index 0000000000..7624374eff --- /dev/null +++ b/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp @@ -0,0 +1,171 @@ +/* + * 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 . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +#include +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; +using namespace Antares::Solver::Visitors; + +BOOST_AUTO_TEST_SUITE(_AstGraphVisitor_) + +class Fixture +{ +public: + Fixture() + { + } + + Node* makeExpression() + { + Node* literalNode = registry_.create(-40.); + Node* negationNode = registry_.create(literalNode); + Node* parameterNode = registry_.create("avogadro_constant"); + Node* multiplicationNode = registry_.create(negationNode, + parameterNode); + Node* variableNode = registry_.create("atoms_count"); + Node* divisionNode = registry_.create(variableNode, multiplicationNode); + Node* portFieldNode = registry_.create("gasStation", "1149"); + Node* sumNode = registry_.create(divisionNode, portFieldNode); + Node* componentVariableNode = registry_.create("1150", + "otherStation"); + Node* componentParameterNode = registry_.create("1151", + "otherConstant"); + Node* subtractionNode = registry_.create(componentVariableNode, + componentParameterNode); + Node* equalNode = registry_.create(subtractionNode, sumNode); + Node* literalNode2 = registry_.create(53.); + Node* lessThanOrEqualNode = registry_.create(literalNode2, equalNode); + Node* literalNode3 = registry_.create(54.); + Node* greaterThanOrEqualNode = registry_.create( + literalNode3, + lessThanOrEqualNode); + + return greaterThanOrEqualNode; + } + + static std::string expectedDotContent() + { + return R"raw(digraph ExpressionTree { +node[style = filled] + 1 [label=">=", shape="diamond", style="filled", color="yellow"]; + 1 -> 2; + 1 -> 3; + 2 [label="54.000000", shape="box", style="filled, solid", color="lightgray"]; + 3 [label="<=", shape="diamond", style="filled", color="yellow"]; + 3 -> 4; + 3 -> 5; + 4 [label="53.000000", shape="box", style="filled, solid", color="lightgray"]; + 5 [label="==", shape="diamond", style="filled", color="yellow"]; + 5 -> 6; + 5 -> 7; + 6 [label="-", shape="oval", style="filled, rounded", color="aqua"]; + 6 -> 8; + 6 -> 9; + 8 [label="CV(1150,otherStation)", shape="octagon", style="filled, solid", color="goldenrod"]; + 9 [label="CP(1151,otherConstant)", shape="octagon", style="filled, solid", color="springgreen"]; + 7 [label="+", shape="hexagon", style="filled, solid", color="aqua"]; + 7 -> 10; + 10 [label="/", shape="oval", style="filled, rounded", color="aqua"]; + 10 -> 11; + 10 -> 12; + 11 [label="Var(atoms_count)", shape="box", style="filled, solid", color="gold"]; + 12 [label="*", shape="oval", style="filled, rounded", color="aqua"]; + 12 -> 13; + 12 -> 14; + 13 [label="-", shape="invtriangle", style="filled, solid", color="tomato"]; + 13 -> 15; + 15 [label="-40.000000", shape="box", style="filled, solid", color="lightgray"]; + 14 [label="Param(avogadro_constant)", shape="box", style="filled, solid", color="wheat"]; + 7 -> 16; + 16 [label="PF(gasStation,1149)", shape="component", style="filled, solid", color="olive"]; +label="AST Diagram(Total nodes : 16)" +labelloc = "t" +subgraph cluster_legend { +label = "Legend"; +style = dashed; +fontsize = 16; +color = lightgrey; +node [shape=plaintext]; + +legend_ComponentParameterNode [ label =" ComponentParameterNode: 1"] +legend_ComponentParameterNode -> legend_ComponentVariableNode [style=invis]; +legend_ComponentVariableNode [ label =" ComponentVariableNode: 1"] +legend_ComponentVariableNode -> legend_DivisionNode [style=invis]; +legend_DivisionNode [ label =" DivisionNode: 1"] +legend_DivisionNode -> legend_EqualNode [style=invis]; +legend_EqualNode [ label =" EqualNode: 1"] +legend_EqualNode -> legend_GreaterThanOrEqualNode [style=invis]; +legend_GreaterThanOrEqualNode [ label =" GreaterThanOrEqualNode: 1"] +legend_GreaterThanOrEqualNode -> legend_LessThanOrEqualNode [style=invis]; +legend_LessThanOrEqualNode [ label =" LessThanOrEqualNode: 1"] +legend_LessThanOrEqualNode -> legend_LiteralNode [style=invis]; +legend_LiteralNode [ label =" LiteralNode: 3"] +legend_LiteralNode -> legend_MultiplicationNode [style=invis]; +legend_MultiplicationNode [ label =" MultiplicationNode: 1"] +legend_MultiplicationNode -> legend_NegationNode [style=invis]; +legend_NegationNode [ label =" NegationNode: 1"] +legend_NegationNode -> legend_ParameterNode [style=invis]; +legend_ParameterNode [ label =" ParameterNode: 1"] +legend_ParameterNode -> legend_PortFieldNode [style=invis]; +legend_PortFieldNode [ label =" PortFieldNode: 1"] +legend_PortFieldNode -> legend_SubtractionNode [style=invis]; +legend_SubtractionNode [ label =" SubtractionNode: 1"] +legend_SubtractionNode -> legend_SumNode [style=invis]; +legend_SumNode [ label =" SumNode: 1"] +legend_SumNode -> legend_VariableNode [style=invis]; +legend_VariableNode [ label =" VariableNode: 1"] +} +} +)raw"; + } + + Registry registry_; +}; + +BOOST_FIXTURE_TEST_CASE(tree_with_all_type_node, Fixture) +{ + std::ostringstream os; + + AstDOTStyleVisitor astGraphVisitor; + + std::pair pair1(astGraphVisitor, makeExpression()); + os << pair1; + + // read the content of os + BOOST_CHECK_EQUAL(expectedDotContent(), os.str()); +} + +BOOST_FIXTURE_TEST_CASE(AstDOTStyleVisitor_name, Registry) +{ + AstDOTStyleVisitor astGraphVisitor; + BOOST_CHECK_EQUAL(astGraphVisitor.name(), "AstDOTStyleVisitor"); +} + +BOOST_AUTO_TEST_SUITE_END() From abe3f99b8db9c42691b947075061c2d888f25373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Wed, 25 Sep 2024 16:32:19 +0200 Subject: [PATCH 013/103] Remove awkward operator<< overload, use operator() instead (#2427) --- .../expressions/visitors/AstDOTStyleVisitor.h | 25 ++++++++----------- .../visitors/AstDOTStyleVisitor.cpp | 11 +++----- .../expressions/test_AstDOTStyleVisitor.cpp | 4 +-- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h index d7d3daac8f..3b5ce8410e 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h @@ -107,6 +107,17 @@ class AstDOTStyleVisitor: public NodeVisitor */ std::string name() const override; + /** + * @brief Outputs the DOT representation of a node to a stream. + * + * This operator overload facilitates the use of the `AstDOTStyleVisitor` with a node + * for direct streaming of the DOT representation. + * + * @param os The output stream to which the DOT representation is written. + * @param root The root of the expression to be output. + */ + void operator()(std::ostream& os, Nodes::Node* root); + private: void visit(const Nodes::SumNode* node, std::ostream& os) override; void visit(const Nodes::SubtractionNode* node, std::ostream& os) override; @@ -179,18 +190,4 @@ class AstDOTStyleVisitor: public NodeVisitor */ unsigned int nodeCount_ = 0; }; - -/** - * @brief Outputs the DOT representation of a node to a stream. - * - * This operator overload facilitates the use of the `AstDOTStyleVisitor` with a node - * for direct streaming of the DOT representation. - * - * @param os The output stream to which the DOT representation is written. - * @param visitorExpr A pair consisting of the visitor and the node to be output. - * @return The output stream. - */ -std::ostream& operator<<(std::ostream& os, - const std::pair& visitorExpr); - } // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp index 063343f511..78a8e0be57 100644 --- a/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp +++ b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp @@ -247,13 +247,10 @@ void AstDOTStyleVisitor::EndTreeGraph(std::ostream& os) nodeIds_.clear(); } -std::ostream& operator<<(std::ostream& os, - const std::pair& visitorExpr) +void AstDOTStyleVisitor::operator()(std::ostream& os, Nodes::Node* root) { - auto& [visitor, root] = visitorExpr; - visitor.NewTreeGraph(os); - visitor.dispatch(root, os); - visitor.EndTreeGraph(os); - return os; + NewTreeGraph(os); + dispatch(root, os); + EndTreeGraph(os); } } // namespace Antares::Solver::Visitors diff --git a/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp b/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp index 7624374eff..1cf239cef8 100644 --- a/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp +++ b/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp @@ -154,9 +154,7 @@ BOOST_FIXTURE_TEST_CASE(tree_with_all_type_node, Fixture) std::ostringstream os; AstDOTStyleVisitor astGraphVisitor; - - std::pair pair1(astGraphVisitor, makeExpression()); - os << pair1; + astGraphVisitor(os, makeExpression()); // read the content of os BOOST_CHECK_EQUAL(expectedDotContent(), os.str()); From d174a1bd2f6ef89045645579a80c6cbbacf78b4d Mon Sep 17 00:00:00 2001 From: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:46:52 +0200 Subject: [PATCH 014/103] remove old Doxygen.txt files (#2428) --- src/libs/antares/Doxygen.txt | 1478 ---------------------------------- src/solver/Doxygen.txt | 1473 --------------------------------- 2 files changed, 2951 deletions(-) delete mode 100644 src/libs/antares/Doxygen.txt delete mode 100644 src/solver/Doxygen.txt diff --git a/src/libs/antares/Doxygen.txt b/src/libs/antares/Doxygen.txt deleted file mode 100644 index aeb41cf864..0000000000 --- a/src/libs/antares/Doxygen.txt +++ /dev/null @@ -1,1478 +0,0 @@ -# Doxyfile 1.5.7.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = AntaresLibs - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = ../../docs/developer/doxygen/libs - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = YES - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, -# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, -# Spanish, Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = YES - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = YES - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = YES - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = YES - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penality. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will rougly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = YES - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = YES - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = YES - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = YES - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -# doxygen. The layout file controls the global structure of the generated output files -# in an output format independent way. The create the layout file that represents -# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -# file name after the option, if omitted DoxygenLayout.xml will be used as the name -# of the layout file. - -LAYOUT_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = YES - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 - -FILE_PATTERNS = *.c \ - *.h \ - *.cc \ - *.hh \ - *.cpp \ - *.hxx - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = CMakeFiles - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = NO - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 4 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -# are set, an additional index file will be generated that can be used as input for -# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -# HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# Qt Help Project / Namespace. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# Qt Help Project / Virtual Folders. - -QHP_VIRTUAL_FOLDER = doc - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file . - -QHG_LOCATION = - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to FRAME, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. Other possible values -# for this tag are: HIERARCHIES, which will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list; -# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which -# disables this behavior completely. For backwards compatibility with previous -# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE -# respectively. - -GENERATE_TREEVIEW = NONE - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = YES - -# By default doxygen will write a font called FreeSans.ttf to the output -# directory and reference it in all dot files that doxygen generates. This -# font does not include all possible unicode characters however, so when you need -# these (or just want a differently looking font) you can specify the font name -# using DOT_FONTNAME. You need need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. - -DOT_FONTNAME = verdana - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. - -DOT_FONTPATH = /local/opt/usr/share/fonts/ttf - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = YES - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = YES - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = YES diff --git a/src/solver/Doxygen.txt b/src/solver/Doxygen.txt deleted file mode 100644 index 6832b18589..0000000000 --- a/src/solver/Doxygen.txt +++ /dev/null @@ -1,1473 +0,0 @@ -# Doxyfile 1.5.7.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = AntaresSolver - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = ../../docs/developer/doxygen/solver - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = YES - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, -# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, -# Spanish, Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = French - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = YES - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = YES - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = YES - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = YES - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penality. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will rougly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = YES - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = YES - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = YES - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = YES - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by -# doxygen. The layout file controls the global structure of the generated output files -# in an output format independent way. The create the layout file that represents -# doxygen's defaults, run doxygen with the -l option. You can optionally specify a -# file name after the option, if omitted DoxygenLayout.xml will be used as the name -# of the layout file. - -LAYOUT_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = YES - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 - -FILE_PATTERNS = *.c *.h *.cc *.hh *.cpp *.hxx - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = CMakeFiles - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = YES - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 4 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER -# are set, an additional index file will be generated that can be used as input for -# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated -# HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# Qt Help Project / Namespace. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# Qt Help Project / Virtual Folders. - -QHP_VIRTUAL_FOLDER = doc - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file . - -QHG_LOCATION = - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to FRAME, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. Other possible values -# for this tag are: HIERARCHIES, which will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list; -# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which -# disables this behavior completely. For backwards compatibility with previous -# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE -# respectively. - -GENERATE_TREEVIEW = NONE - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = YES - -# By default doxygen will write a font called FreeSans.ttf to the output -# directory and reference it in all dot files that doxygen generates. This -# font does not include all possible unicode characters however, so when you need -# these (or just want a differently looking font) you can specify the font name -# using DOT_FONTNAME. You need need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. - -DOT_FONTNAME = verdana - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. - -DOT_FONTPATH = /local/opt/usr/share/fonts/ttf - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = YES - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = YES - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 70 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = YES - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = YES From bc8e74cdd3dee561649a863613fdb09417291eee Mon Sep 17 00:00:00 2001 From: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:39:20 +0200 Subject: [PATCH 015/103] Visitor AST into DOT : trial for more clarity (#2426) Co-authored-by: Florian OMNES --- .../expressions/visitors/AstDOTStyleVisitor.h | 12 +++- .../visitors/AstDOTStyleVisitor.cpp | 70 ++++++++++--------- .../expressions/test_AstDOTStyleVisitor.cpp | 13 ++-- 3 files changed, 53 insertions(+), 42 deletions(-) diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h index 3b5ce8410e..8ca2e509c5 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h @@ -134,6 +134,9 @@ class AstDOTStyleVisitor: public NodeVisitor void visit(const Nodes::ComponentVariableNode* node, std::ostream& os) override; void visit(const Nodes::ComponentParameterNode* node, std::ostream& os) override; + void computeNumberNodesPerType(); + void makeLegend(std::ostream& os); + /** * @brief Retrieves a unique ID for a given node. * @@ -181,7 +184,14 @@ class AstDOTStyleVisitor: public NodeVisitor * * This map is used to keep track of assigned IDs for each node in the AST. */ - std::map> nodeIds_; + std::map nodeIds_; + + /** + * @brief A map associating a number of instances to a type name. + * + * This map is used to keep track of assigned IDs for each node in the AST. + */ + std::map nbNodesPerType_; /** * @brief Counter for generating unique node IDs. diff --git a/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp index 78a8e0be57..a1e3f6fbde 100644 --- a/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp +++ b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp @@ -18,13 +18,11 @@ ** You should have received a copy of the Mozilla Public Licence 2.0 ** along with Antares_Simulator. If not, see . */ - #include "antares/solver/expressions/visitors/AstDOTStyleVisitor.h" #include -#include -#include +#include "antares/solver/expressions/nodes/ExpressionsNodes.h" namespace Antares::Solver::Visitors { @@ -42,6 +40,16 @@ static constexpr BoxStyle ComponentVariableStyle{"goldenrod", "octagon", "filled static constexpr BoxStyle PortFieldStyle{"olive", "component", "filled, solid"}; } // namespace NodeStyle +void makeLegendTitle(std::ostream& os) +{ + os << "subgraph cluster_legend {\n" + << "label = \"Legend\";\n" + << "style = dashed;\n" + << "fontsize = 16;\n" + << "color = lightgrey;\n" + << "node [shape=plaintext];\n\n"; +} + void ProcessElementLegend(const std::string& element_name, size_t size, std::ostream& os) { os << "legend_" << element_name << " [ label =\" " << element_name << ": " << size << "\"]\n"; @@ -52,34 +60,20 @@ void AddFiliation(std::ostream& os, const std::string& parent_id, const std::str os << "legend_" << parent_id << " -> " << "legend_" << child_id << " [style=invis];\n"; } -void GetLegend(const std::map>& nodeIds, - std::ostream& os) +void AstDOTStyleVisitor::makeLegend(std::ostream& os) { - os << R"raw(subgraph cluster_legend { -label = "Legend"; -style = dashed; -fontsize = 16; -color = lightgrey; -node [shape=plaintext]; - -)raw"; - - auto order_nb_type = nodeIds.size(); - if (order_nb_type > 1) + if (nbNodesPerType_.empty()) { - for (auto it = nodeIds.begin(), next_it = std::next(it); next_it != nodeIds.end(); - ++it, ++next_it) - { - ProcessElementLegend(it->first, it->second.size(), os); - AddFiliation(os, it->first, next_it->first); - } - ProcessElementLegend(nodeIds.rbegin()->first, nodeIds.rbegin()->second.size(), os); + return; } - else if (order_nb_type == 1) + + ProcessElementLegend(nbNodesPerType_.begin()->first, nbNodesPerType_.begin()->second, os); + for (auto it = std::next(nbNodesPerType_.begin()); it != nbNodesPerType_.end(); ++it) { - ProcessElementLegend(nodeIds.begin()->first, nodeIds.begin()->second.size(), os); + auto prev_it = std::prev(it); + AddFiliation(os, prev_it->first, it->first); + ProcessElementLegend(it->first, it->second, os); } - os << "}\n"; } @@ -186,17 +180,19 @@ std::string AstDOTStyleVisitor::name() const unsigned int AstDOTStyleVisitor::getNodeID(const Nodes::Node* node) { - const auto& node_name = node->name(); - if (nodeIds_.find(node_name) == nodeIds_.end()) + if (nodeIds_.find(node) == nodeIds_.end()) { - nodeIds_[node->name()][node] = ++nodeCount_; + nodeIds_[node] = ++nodeCount_; } - else if (auto& id_map = nodeIds_[node_name]; id_map.find(node) == id_map.end()) + return nodeIds_[node]; +} + +void AstDOTStyleVisitor::computeNumberNodesPerType() +{ + for (const auto& [node, _]: nodeIds_) { - id_map[node] = ++nodeCount_; + nbNodesPerType_[node->name()]++; } - - return nodeIds_[node->name()][node]; } void AstDOTStyleVisitor::emitNode(unsigned int id, @@ -238,13 +234,19 @@ void AstDOTStyleVisitor::NewTreeGraph(std::ostream& os, const std::string& tree_ void AstDOTStyleVisitor::EndTreeGraph(std::ostream& os) { + computeNumberNodesPerType(); + // Graph title showing the total number of nodes os << "label=\"AST Diagram(Total nodes : " << nodeCount_ << ")\"\n"; os << "labelloc = \"t\"\n"; - GetLegend(nodeIds_, os); + + makeLegendTitle(os); + makeLegend(os); os << "}\n"; + nodeCount_ = 0; nodeIds_.clear(); + nbNodesPerType_.clear(); } void AstDOTStyleVisitor::operator()(std::ostream& os, Nodes::Node* root) diff --git a/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp b/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp index 1cf239cef8..09f80008f3 100644 --- a/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp +++ b/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp @@ -21,8 +21,6 @@ #define WIN32_LEAN_AND_MEAN -#include - #include #include @@ -149,15 +147,16 @@ legend_VariableNode [ label =" VariableNode: 1"] Registry registry_; }; -BOOST_FIXTURE_TEST_CASE(tree_with_all_type_node, Fixture) +BOOST_FIXTURE_TEST_CASE( + dot_visitor_is_run_on_complex_expression___resulting_dot_content_as_expected, + Fixture) { - std::ostringstream os; + std::ostringstream dotContentStream; AstDOTStyleVisitor astGraphVisitor; - astGraphVisitor(os, makeExpression()); + astGraphVisitor(dotContentStream, makeExpression()); - // read the content of os - BOOST_CHECK_EQUAL(expectedDotContent(), os.str()); + BOOST_CHECK_EQUAL(dotContentStream.str(), expectedDotContent()); } BOOST_FIXTURE_TEST_CASE(AstDOTStyleVisitor_name, Registry) From 1d75f0886cc58a9e324be89b6d8fabc835a3bfed Mon Sep 17 00:00:00 2001 From: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:49:04 +0200 Subject: [PATCH 016/103] AST to DOT : forgotten commit (#2429) Co-authored-by: Florian OMNES --- src/solver/expressions/visitors/AstDOTStyleVisitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp index a1e3f6fbde..59ce151f06 100644 --- a/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp +++ b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp @@ -191,7 +191,7 @@ void AstDOTStyleVisitor::computeNumberNodesPerType() { for (const auto& [node, _]: nodeIds_) { - nbNodesPerType_[node->name()]++; + ++nbNodesPerType_[node->name()]; } } From f3922b266e29086337e5c61a26b4689b43a8e7d0 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:19:19 +0200 Subject: [PATCH 017/103] Better handling of discontinued parameters (#2414) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Florian Omnès --- src/libs/antares/study/parameters.cpp | 23 +++++++++++++++---- .../study/parameters/adq-patch-params.cpp | 23 +------------------ 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/libs/antares/study/parameters.cpp b/src/libs/antares/study/parameters.cpp index 628237bbef..72be2dd7b4 100644 --- a/src/libs/antares/study/parameters.cpp +++ b/src/libs/antares/study/parameters.cpp @@ -1111,15 +1111,30 @@ static bool SGDIntLoadFamily_Legacy(Parameters& d, if (key == "initial-reservoir-levels") // ignored since 9.2 { - if (version >= StudyVersion(9, 2)) + if (value == "hot start") { logs.warning() << "Option initial-reservoir-levels is deprecated, please remove it from the study"; } - else if (value == "hot start") + return true; + } + + if (key == "set-to-null-ntc-between-physical-out-for-first-step") // ignored since 9.2 + { + if (value == "false") { - logs.warning() - << "Hydro hot start not supported with this solver, please use a version < 9.2"; + logs.warning() << "Parameter set-to-null-ntc-between-physical-out-for-first-step " + " is deprecated, please remove it from the study"; + } + return true; + } + + if (key == "enable-first-step") // ignored since 9.2 + { + if (value == "true") + { + logs.warning() << "Parameter enable-first-step is deprecated, please remove it from" + " the study"; } return true; } diff --git a/src/libs/antares/study/parameters/adq-patch-params.cpp b/src/libs/antares/study/parameters/adq-patch-params.cpp index 0cefe33482..ebf6de321e 100644 --- a/src/libs/antares/study/parameters/adq-patch-params.cpp +++ b/src/libs/antares/study/parameters/adq-patch-params.cpp @@ -27,27 +27,6 @@ namespace Antares::Data::AdequacyPatch { -// ------------------- -// Local matching -// ------------------- - -static bool legacyLocalMatchingKeys(const Yuni::String& key) -{ - if (key == "set-to-null-ntc-between-physical-out-for-first-step") - { - logs.warning() << "Parameter set-to-null-ntc-between-physical-out-for-first-step not " - "supported with this solver version, use a version < 9.2"; - return true; - } - if (key == "enable-first-step") - { - logs.warning() << "Parameter enable-first-step not supported with this solver version, use " - "a version < 9.2"; - return true; - } - return false; -} - // ----------------------- // Curtailment sharing // ----------------------- @@ -120,7 +99,7 @@ bool CurtailmentSharing::updateFromKeyValue(const Yuni::String& key, const Yuni: return value.to(thresholdVarBoundsRelaxation); } - return legacyLocalMatchingKeys(key); + return false; } const char* PriceTakingOrderToString(AdequacyPatch::AdqPatchPTO pto) From 8ce6107b7721213fd2cf987ac425bdb7fc143a19 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:46:48 +0200 Subject: [PATCH 018/103] Modeler 2.4c: PortFieldSum and substitution (#2415) Co-authored-by: Florian OMNES --- src/solver/expressions/CMakeLists.txt | 13 +++- src/solver/expressions/hashable.cpp | 49 +++++++++++++ .../antares/solver/expressions/hashable.h | 43 ++++++++++++ .../expressions/nodes/ExpressionsNodes.h | 1 + .../nodes/NodesForwardDeclaration.h | 1 + .../solver/expressions/nodes/PortFieldNode.h | 3 +- .../expressions/nodes/PortFieldSumNode.h | 68 ++++++++++++++++++ .../expressions/visitors/AstDOTStyleVisitor.h | 1 + .../expressions/visitors/CloneVisitor.h | 1 + .../expressions/visitors/CompareVisitor.h | 1 + .../solver/expressions/visitors/EvalVisitor.h | 1 + .../expressions/visitors/LinearityVisitor.h | 1 + .../solver/expressions/visitors/NodeVisitor.h | 11 +++ ...sitor.h => PortFieldSubstitutionVisitor.h} | 17 ++--- .../PortFieldSumSubstitutionVisitor.h | 57 +++++++++++++++ .../expressions/visitors/PrintVisitor.h | 1 + .../expressions/visitors/TimeIndexVisitor.h | 1 + .../expressions/nodes/PortFieldNode.cpp | 1 + .../expressions/nodes/PortFieldSumNode.cpp | 41 +++++++++++ .../visitors/AstDOTStyleVisitor.cpp | 9 +++ .../expressions/visitors/CloneVisitor.cpp | 12 +++- .../expressions/visitors/CompareVisitor.cpp | 5 ++ .../expressions/visitors/EvalVisitor.cpp | 5 ++ .../expressions/visitors/LinearityVisitor.cpp | 5 ++ ...r.cpp => PortFieldSubstitutionVisitor.cpp} | 23 ++---- .../PortFieldSumSubstitutionVisitor.cpp | 51 ++++++++++++++ .../expressions/visitors/PrintVisitor.cpp | 5 ++ .../expressions/visitors/TimeIndexVisitor.cpp | 5 ++ .../expressions/test_AstDOTStyleVisitor.cpp | 11 ++- .../expressions/test_CompareVisitor.cpp | 3 +- .../solver/expressions/test_LinearVisitor.cpp | 5 ++ .../expressions/test_PrintAndEvalNodes.cpp | 10 +++ .../expressions/test_SubstitutionVisitor.cpp | 70 +++++++++++++++++-- .../expressions/test_TimeIndexVisitor.cpp | 1 + .../src/solver/expressions/test_nodes.cpp | 13 +++- 35 files changed, 498 insertions(+), 47 deletions(-) create mode 100644 src/solver/expressions/hashable.cpp create mode 100644 src/solver/expressions/include/antares/solver/expressions/hashable.h create mode 100644 src/solver/expressions/include/antares/solver/expressions/nodes/PortFieldSumNode.h rename src/solver/expressions/include/antares/solver/expressions/visitors/{PortfieldSubstitutionVisitor.h => PortFieldSubstitutionVisitor.h} (77%) create mode 100644 src/solver/expressions/include/antares/solver/expressions/visitors/PortFieldSumSubstitutionVisitor.h create mode 100644 src/solver/expressions/nodes/PortFieldSumNode.cpp rename src/solver/expressions/visitors/{PortfieldSubstitutionVisitor.cpp => PortFieldSubstitutionVisitor.cpp} (67%) create mode 100644 src/solver/expressions/visitors/PortFieldSumSubstitutionVisitor.cpp diff --git a/src/solver/expressions/CMakeLists.txt b/src/solver/expressions/CMakeLists.txt index 0a222c2d49..df56047769 100644 --- a/src/solver/expressions/CMakeLists.txt +++ b/src/solver/expressions/CMakeLists.txt @@ -3,6 +3,7 @@ project(Expressions) set(SRC_Expressions nodes/PortFieldNode.cpp + nodes/PortFieldSumNode.cpp nodes/ComponentNode.cpp nodes/BinaryNode.cpp nodes/UnaryNode.cpp @@ -16,10 +17,13 @@ set(SRC_Expressions visitors/TimeIndexVisitor.cpp visitors/PrintVisitor.cpp visitors/SubstitutionVisitor.cpp + visitors/PortFieldSubstitutionVisitor.cpp + visitors/PortFieldSumSubstitutionVisitor.cpp visitors/AstDOTStyleVisitor.cpp - visitors/PortfieldSubstitutionVisitor.cpp visitors/InvalidNode.cpp + hashable.cpp + include/antares/solver/expressions/nodes/SumNode.h include/antares/solver/expressions/nodes/BinaryNode.h include/antares/solver/expressions/nodes/ComparisonNode.h @@ -37,6 +41,7 @@ set(SRC_Expressions include/antares/solver/expressions/nodes/NodesForwardDeclaration.h include/antares/solver/expressions/nodes/ParameterNode.h include/antares/solver/expressions/nodes/PortFieldNode.h + include/antares/solver/expressions/nodes/PortFieldSumNode.h include/antares/solver/expressions/nodes/SubtractionNode.h include/antares/solver/expressions/nodes/UnaryNode.h include/antares/solver/expressions/nodes/VariableNode.h @@ -52,12 +57,14 @@ set(SRC_Expressions include/antares/solver/expressions/visitors/TimeIndexVisitor.h include/antares/solver/expressions/visitors/TimeIndex.h include/antares/solver/expressions/visitors/SubstitutionVisitor.h + include/antares/solver/expressions/visitors/PortFieldSubstitutionVisitor.h + include/antares/solver/expressions/visitors/PortFieldSumSubstitutionVisitor.h include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h - include/antares/solver/expressions/visitors/PortfieldSubstitutionVisitor.h include/antares/solver/expressions/visitors/InvalidNode.h include/antares/solver/expressions/Registry.hxx include/antares/solver/expressions/IName.h + include/antares/solver/expressions/hashable.h ) source_group("expressions" FILES ${SRC_Expressions}) @@ -72,7 +79,7 @@ target_link_libraries(antares-solver-expressions PUBLIC Antares::logs Boost::headers - ) +) add_library(antares-solver-expressions-iterators diff --git a/src/solver/expressions/hashable.cpp b/src/solver/expressions/hashable.cpp new file mode 100644 index 0000000000..3757ed4547 --- /dev/null +++ b/src/solver/expressions/hashable.cpp @@ -0,0 +1,49 @@ +/* +** 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 + +#include + +namespace Antares::Solver +{ + +Hashable::Hashable(const std::string& s1, const std::string& s2): + s1(s1), + s2(s2) +{ +} + +bool Hashable::operator==(const Hashable& other) const +{ + return s1 == other.s1 && s2 == other.s2; +} + +std::size_t PortFieldHash::operator()(const Hashable& n) const +{ + std::size_t seed = 0; + + boost::hash_combine(seed, boost::hash_value(n.s1)); + boost::hash_combine(seed, boost::hash_value(n.s2)); + + return seed; +} + +} // namespace Antares::Solver diff --git a/src/solver/expressions/include/antares/solver/expressions/hashable.h b/src/solver/expressions/include/antares/solver/expressions/hashable.h new file mode 100644 index 0000000000..1548d6be65 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/hashable.h @@ -0,0 +1,43 @@ +/* +** 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 + +namespace Antares::Solver +{ +class Hashable +{ +public: + Hashable(const std::string& s1, const std::string& s2); + ~Hashable() = default; + + bool operator==(const Hashable& other) const; + + const std::string& s1; + const std::string& s2; +}; + +struct PortFieldHash +{ + std::size_t operator()(const Hashable& n) const; +}; + +} // namespace Antares::Solver diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/ExpressionsNodes.h b/src/solver/expressions/include/antares/solver/expressions/nodes/ExpressionsNodes.h index 1652e4003a..7909f5ffb6 100644 --- a/src/solver/expressions/include/antares/solver/expressions/nodes/ExpressionsNodes.h +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/ExpressionsNodes.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h b/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h index eb637e1d15..f9124c3d91 100644 --- a/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h @@ -39,4 +39,5 @@ class ComponentParameterNode; class ParameterNode; class VariableNode; class PortFieldNode; +class PortFieldSumNode; } // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/PortFieldNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/PortFieldNode.h index 32895d3be5..762f37a1c3 100644 --- a/src/solver/expressions/include/antares/solver/expressions/nodes/PortFieldNode.h +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/PortFieldNode.h @@ -21,6 +21,7 @@ #pragma once #include +#include #include namespace Antares::Solver::Nodes @@ -28,7 +29,7 @@ namespace Antares::Solver::Nodes /** * @brief Represents a port field node in a syntax tree. */ -class PortFieldNode: public Node +class PortFieldNode: public Node, public Hashable { public: /** diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/PortFieldSumNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/PortFieldSumNode.h new file mode 100644 index 0000000000..eda6372e0f --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/PortFieldSumNode.h @@ -0,0 +1,68 @@ +/* +** 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 +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a port field node where the expression is a sum. + */ +class PortFieldSumNode: public Node, public Hashable +{ +public: + /** + * @brief Constructs a port field sum node with the specified port and field names. + * + * @param port_name The port name. + * @param field_name The field name. + */ + explicit PortFieldSumNode(const std::string& port_name, const std::string& field_name); + + /** + * @brief Retrieves the port name. + * + * @return The port name. + */ + const std::string& getPortName() const; + + /** + * @brief Retrieves the field name. + * + * @return The field name. + */ + const std::string& getFieldName() const; + + bool operator==(const PortFieldSumNode& other) const = default; + + std::string name() const override + { + return "PortFieldSumNode"; + } + +private: + std::string port_name_; + std::string field_name_; +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h index 8ca2e509c5..a8e4e1ff43 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h @@ -131,6 +131,7 @@ class AstDOTStyleVisitor: public NodeVisitor void visit(const Nodes::ParameterNode* node, std::ostream& os) override; void visit(const Nodes::LiteralNode* node, std::ostream& os) override; void visit(const Nodes::PortFieldNode* node, std::ostream& os) override; + void visit(const Nodes::PortFieldSumNode* node, std::ostream& os) override; void visit(const Nodes::ComponentVariableNode* node, std::ostream& os) override; void visit(const Nodes::ComponentParameterNode* node, std::ostream& os) override; diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/CloneVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/CloneVisitor.h index 394a1449eb..ff5ac538a2 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/CloneVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/CloneVisitor.h @@ -51,6 +51,7 @@ class CloneVisitor: public NodeVisitor Nodes::Node* visit(const Nodes::ParameterNode* node) override; Nodes::Node* visit(const Nodes::LiteralNode* node) override; Nodes::Node* visit(const Nodes::PortFieldNode* node) override; + Nodes::Node* visit(const Nodes::PortFieldSumNode* node) override; Nodes::Node* visit(const Nodes::ComponentVariableNode* node) override; Nodes::Node* visit(const Nodes::ComponentParameterNode* node) override; diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/CompareVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/CompareVisitor.h index 446d538510..ec19095b02 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/CompareVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/CompareVisitor.h @@ -46,6 +46,7 @@ class CompareVisitor: public NodeVisitor bool visit(const Nodes::ParameterNode* param, const Nodes::Node* other) override; bool visit(const Nodes::LiteralNode* param, const Nodes::Node* other) override; bool visit(const Nodes::PortFieldNode* port_field_node, const Nodes::Node* other) override; + bool visit(const Nodes::PortFieldSumNode* port_field_node, const Nodes::Node* other) override; bool visit(const Nodes::ComponentVariableNode* component_node, const Nodes::Node* other) override; bool visit(const Nodes::ComponentParameterNode* component_node, diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/EvalVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/EvalVisitor.h index 0486197852..5dbc1c06ed 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/EvalVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/EvalVisitor.h @@ -71,6 +71,7 @@ class EvalVisitor: public NodeVisitor double visit(const Nodes::ParameterNode* node) override; double visit(const Nodes::LiteralNode* node) override; double visit(const Nodes::PortFieldNode* node) override; + double visit(const Nodes::PortFieldSumNode* node) override; double visit(const Nodes::ComponentVariableNode* node) override; double visit(const Nodes::ComponentParameterNode* node) override; }; diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/LinearityVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/LinearityVisitor.h index 3baa0abe81..8355d27734 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/LinearityVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/LinearityVisitor.h @@ -46,6 +46,7 @@ class LinearityVisitor: public NodeVisitor LinearStatus visit(const Nodes::ParameterNode* param) override; LinearStatus visit(const Nodes::LiteralNode* lit) override; LinearStatus visit(const Nodes::PortFieldNode* port_field_node) override; + LinearStatus visit(const Nodes::PortFieldSumNode* port_field_node) override; LinearStatus visit(const Nodes::ComponentVariableNode* component_variable_node) override; LinearStatus visit(const Nodes::ComponentParameterNode* component_parameter_node) override; }; diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h index 59001acf75..9b88019376 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h @@ -109,6 +109,7 @@ class NodeVisitor: public IName Nodes::VariableNode, Nodes::LiteralNode, Nodes::PortFieldNode, + Nodes::PortFieldSumNode, Nodes::ComponentVariableNode, Nodes::ComponentParameterNode>(); @@ -239,6 +240,16 @@ class NodeVisitor: public IName */ virtual R visit(const Nodes::PortFieldNode*, Args... args) = 0; + /** + * @brief Visits a PortFieldSumNode. + * + * @param node A pointer to the PortFieldSumNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the PortFieldSumNode. + */ + virtual R visit(const Nodes::PortFieldSumNode*, Args... args) = 0; + /** * @brief Visits a ComponentVariableNode. * diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/PortfieldSubstitutionVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/PortFieldSubstitutionVisitor.h similarity index 77% rename from src/solver/expressions/include/antares/solver/expressions/visitors/PortfieldSubstitutionVisitor.h rename to src/solver/expressions/include/antares/solver/expressions/visitors/PortFieldSubstitutionVisitor.h index bd4a23cfbb..ce897945ea 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/PortfieldSubstitutionVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/PortFieldSubstitutionVisitor.h @@ -27,29 +27,24 @@ namespace Antares::Solver::Visitors { -struct KeyHasher -{ - std::size_t operator()(const Nodes::PortFieldNode& n) const; -}; - /** * @brief Represents the context for performing substitutions in a syntax tree. */ -struct PortfieldSubstitutionContext +struct PortFieldSubstitutionContext { - std::unordered_map portfield; + std::unordered_map portfield; }; /** * @brief Represents a visitor for substituting portfield nodes in a syntax tree. */ -class PortfieldSubstitutionVisitor: public CloneVisitor +class PortFieldSubstitutionVisitor: public CloneVisitor { public: - PortfieldSubstitutionVisitor(Registry& registry, - PortfieldSubstitutionContext& ctx); + PortFieldSubstitutionVisitor(Registry& registry, + PortFieldSubstitutionContext& ctx); - PortfieldSubstitutionContext& ctx_; + PortFieldSubstitutionContext& ctx_; std::string name() const override; private: diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/PortFieldSumSubstitutionVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/PortFieldSumSubstitutionVisitor.h new file mode 100644 index 0000000000..4444da94e6 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/PortFieldSumSubstitutionVisitor.h @@ -0,0 +1,57 @@ +/* +** 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 "antares/solver/expressions/visitors/CloneVisitor.h" + +namespace Antares::Solver::Visitors +{ + +/** + * @brief Represents the context for performing substitutions in a syntax tree. + */ +struct PortFieldSumSubstitutionContext +{ + std::unordered_map, PortFieldHash> + portfieldSum; +}; + +/** + * @brief Represents a visitor for substituting portfield sum nodes in a syntax tree. + */ +class PortFieldSumSubstitutionVisitor: public CloneVisitor +{ +public: + PortFieldSumSubstitutionVisitor(Registry& registry, + PortFieldSumSubstitutionContext& ctx); + + std::string name() const override; + +private: + // Only override visit method for PortFieldSum, clone the rest + Nodes::Node* visit(const Nodes::PortFieldSumNode* node) override; + + Registry& registry_; + PortFieldSumSubstitutionContext& ctx_; +}; +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/PrintVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/PrintVisitor.h index a7b09bc8c0..dfcca80823 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/PrintVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/PrintVisitor.h @@ -45,6 +45,7 @@ class PrintVisitor: public NodeVisitor std::string visit(const Nodes::ParameterNode* node) override; std::string visit(const Nodes::LiteralNode* node) override; std::string visit(const Nodes::PortFieldNode* node) override; + std::string visit(const Nodes::PortFieldSumNode* node) override; std::string visit(const Nodes::ComponentVariableNode* node) override; std::string visit(const Nodes::ComponentParameterNode* node) override; }; diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndexVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndexVisitor.h index ebbfd9737a..a52fd45e04 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndexVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndexVisitor.h @@ -55,6 +55,7 @@ class TimeIndexVisitor: public NodeVisitor TimeIndex visit(const Nodes::ParameterNode* param) override; TimeIndex visit(const Nodes::LiteralNode* lit) override; TimeIndex visit(const Nodes::PortFieldNode* port_field_node) override; + TimeIndex visit(const Nodes::PortFieldSumNode* port_field_node) override; TimeIndex visit(const Nodes::ComponentVariableNode* component_variable_node) override; TimeIndex visit(const Nodes::ComponentParameterNode* component_parameter_node) override; }; diff --git a/src/solver/expressions/nodes/PortFieldNode.cpp b/src/solver/expressions/nodes/PortFieldNode.cpp index 2490977c6e..15ca1ff39c 100644 --- a/src/solver/expressions/nodes/PortFieldNode.cpp +++ b/src/solver/expressions/nodes/PortFieldNode.cpp @@ -23,6 +23,7 @@ namespace Antares::Solver::Nodes { PortFieldNode::PortFieldNode(const std::string& port_name, const std::string& field_name): + Hashable(port_name_, field_name_), port_name_(port_name), field_name_(field_name) { diff --git a/src/solver/expressions/nodes/PortFieldSumNode.cpp b/src/solver/expressions/nodes/PortFieldSumNode.cpp new file mode 100644 index 0000000000..b396ebfbb6 --- /dev/null +++ b/src/solver/expressions/nodes/PortFieldSumNode.cpp @@ -0,0 +1,41 @@ +/* +** 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 + +namespace Antares::Solver::Nodes +{ +PortFieldSumNode::PortFieldSumNode(const std::string& port_name, const std::string& field_name): + Hashable(port_name_, field_name_), + port_name_(port_name), + field_name_(field_name) +{ +} + +const std::string& PortFieldSumNode::getPortName() const +{ + return port_name_; +} + +const std::string& PortFieldSumNode::getFieldName() const +{ + return field_name_; +} +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp index 59ce151f06..fb74a129df 100644 --- a/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp +++ b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp @@ -155,6 +155,15 @@ void AstDOTStyleVisitor::visit(const Nodes::PortFieldNode* node, std::ostream& o os); } +void AstDOTStyleVisitor::visit(const Nodes::PortFieldSumNode* node, std::ostream& os) +{ + auto id = getNodeID(node); + emitNode(id, + "PFSUM(" + node->getPortName() + "," + node->getFieldName() + ")", + NodeStyle::PortFieldStyle, + os); +} + void AstDOTStyleVisitor::visit(const Nodes::ComponentVariableNode* node, std::ostream& os) { auto id = getNodeID(node); diff --git a/src/solver/expressions/visitors/CloneVisitor.cpp b/src/solver/expressions/visitors/CloneVisitor.cpp index 17875a82a1..7d538c0800 100644 --- a/src/solver/expressions/visitors/CloneVisitor.cpp +++ b/src/solver/expressions/visitors/CloneVisitor.cpp @@ -94,10 +94,16 @@ Nodes::Node* CloneVisitor::visit(const Nodes::LiteralNode* literalNode) return registry_.create(literalNode->value()); } -Nodes::Node* CloneVisitor::visit(const Nodes::PortFieldNode* port_field_node) +Nodes::Node* CloneVisitor::visit(const Nodes::PortFieldNode* portfieldNode) { - return registry_.create(port_field_node->getPortName(), - port_field_node->getFieldName()); + return registry_.create(portfieldNode->getPortName(), + portfieldNode->getFieldName()); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::PortFieldSumNode* portfieldSumNode) +{ + return registry_.create(portfieldSumNode->getPortName(), + portfieldSumNode->getFieldName()); } Nodes::Node* CloneVisitor::visit(const Nodes::ComponentVariableNode* component_variable_node) diff --git a/src/solver/expressions/visitors/CompareVisitor.cpp b/src/solver/expressions/visitors/CompareVisitor.cpp index 2a316fdf59..5fa4a090e6 100644 --- a/src/solver/expressions/visitors/CompareVisitor.cpp +++ b/src/solver/expressions/visitors/CompareVisitor.cpp @@ -134,6 +134,11 @@ bool CompareVisitor::visit(const Nodes::PortFieldNode* node, const Nodes::Node* return compareEqualOperator(node, other); } +bool CompareVisitor::visit(const Nodes::PortFieldSumNode* node, const Nodes::Node* other) +{ + return compareEqualOperator(node, other); +} + bool CompareVisitor::visit(const Nodes::ComponentVariableNode* node, const Nodes::Node* other) { return compareEqualOperator(node, other); diff --git a/src/solver/expressions/visitors/EvalVisitor.cpp b/src/solver/expressions/visitors/EvalVisitor.cpp index 25c7973d90..4d0b45e119 100644 --- a/src/solver/expressions/visitors/EvalVisitor.cpp +++ b/src/solver/expressions/visitors/EvalVisitor.cpp @@ -112,6 +112,11 @@ double EvalVisitor::visit(const Nodes::PortFieldNode* node) throw EvalVisitorNotImplemented(name(), node->name()); } +double EvalVisitor::visit(const Nodes::PortFieldSumNode* node) +{ + throw EvalVisitorNotImplemented(name(), node->name()); +} + double EvalVisitor::visit(const Nodes::ComponentVariableNode* node) { throw EvalVisitorNotImplemented(name(), node->name()); diff --git a/src/solver/expressions/visitors/LinearityVisitor.cpp b/src/solver/expressions/visitors/LinearityVisitor.cpp index 93df95b40c..51fddfaffd 100644 --- a/src/solver/expressions/visitors/LinearityVisitor.cpp +++ b/src/solver/expressions/visitors/LinearityVisitor.cpp @@ -94,6 +94,11 @@ LinearStatus LinearityVisitor::visit(const Nodes::PortFieldNode*) return LinearStatus::CONSTANT; } +LinearStatus LinearityVisitor::visit(const Nodes::PortFieldSumNode*) +{ + return LinearStatus::CONSTANT; +} + LinearStatus LinearityVisitor::visit([[maybe_unused]] const Nodes::ComponentVariableNode*) { return LinearStatus::LINEAR; diff --git a/src/solver/expressions/visitors/PortfieldSubstitutionVisitor.cpp b/src/solver/expressions/visitors/PortFieldSubstitutionVisitor.cpp similarity index 67% rename from src/solver/expressions/visitors/PortfieldSubstitutionVisitor.cpp rename to src/solver/expressions/visitors/PortFieldSubstitutionVisitor.cpp index 8a91361c5a..d7dc95c5f1 100644 --- a/src/solver/expressions/visitors/PortfieldSubstitutionVisitor.cpp +++ b/src/solver/expressions/visitors/PortFieldSubstitutionVisitor.cpp @@ -18,22 +18,21 @@ ** You should have received a copy of the Mozilla Public Licence 2.0 ** along with Antares_Simulator. If not, see . */ -#include #include -#include +#include namespace Antares::Solver::Visitors { -PortfieldSubstitutionVisitor::PortfieldSubstitutionVisitor(Registry& registry, - PortfieldSubstitutionContext& ctx): +PortFieldSubstitutionVisitor::PortFieldSubstitutionVisitor(Registry& registry, + PortFieldSubstitutionContext& ctx): CloneVisitor(registry), ctx_(ctx) { } -Nodes::Node* PortfieldSubstitutionVisitor::visit(const Nodes::PortFieldNode* node) +Nodes::Node* PortFieldSubstitutionVisitor::visit(const Nodes::PortFieldNode* node) { if (auto it = ctx_.portfield.find(*node); it != ctx_.portfield.end()) { @@ -43,19 +42,9 @@ Nodes::Node* PortfieldSubstitutionVisitor::visit(const Nodes::PortFieldNode* nod return CloneVisitor::visit(node); } -std::string PortfieldSubstitutionVisitor::name() const +std::string PortFieldSubstitutionVisitor::name() const { - return "PortfieldSubstitutionVisitor"; -} - -std::size_t KeyHasher::operator()(const Nodes::PortFieldNode& n) const -{ - std::size_t seed = 0; - - boost::hash_combine(seed, boost::hash_value(n.getPortName())); - boost::hash_combine(seed, boost::hash_value(n.getFieldName())); - - return seed; + return "PortFieldSubstitutionVisitor"; } } // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/PortFieldSumSubstitutionVisitor.cpp b/src/solver/expressions/visitors/PortFieldSumSubstitutionVisitor.cpp new file mode 100644 index 0000000000..cc984e1a43 --- /dev/null +++ b/src/solver/expressions/visitors/PortFieldSumSubstitutionVisitor.cpp @@ -0,0 +1,51 @@ +/* +** 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 +#include + +namespace Antares::Solver::Visitors +{ + +PortFieldSumSubstitutionVisitor::PortFieldSumSubstitutionVisitor( + Registry& registry, + PortFieldSumSubstitutionContext& ctx): + CloneVisitor(registry), + registry_(registry), + ctx_(ctx) +{ +} + +Nodes::Node* PortFieldSumSubstitutionVisitor::visit(const Nodes::PortFieldSumNode* node) +{ + if (auto it = ctx_.portfieldSum.find(*node); it != ctx_.portfieldSum.end()) + { + return registry_.create(it->second); + } + + return CloneVisitor::visit(node); +} + +std::string PortFieldSumSubstitutionVisitor::name() const +{ + return "PortFieldSumSubstitutionVisitor"; +} + +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/PrintVisitor.cpp b/src/solver/expressions/visitors/PrintVisitor.cpp index b325ed7b75..6e3a2992b3 100644 --- a/src/solver/expressions/visitors/PrintVisitor.cpp +++ b/src/solver/expressions/visitors/PrintVisitor.cpp @@ -96,6 +96,11 @@ std::string PrintVisitor::visit(const Nodes::PortFieldNode* node) return node->getPortName() + "." + node->getFieldName(); } +std::string PrintVisitor::visit(const Nodes::PortFieldSumNode* node) +{ + return node->getPortName() + "." + node->getFieldName(); +} + std::string PrintVisitor::visit(const Nodes::ComponentVariableNode* node) { return node->getComponentId() + "." + node->getComponentName(); diff --git a/src/solver/expressions/visitors/TimeIndexVisitor.cpp b/src/solver/expressions/visitors/TimeIndexVisitor.cpp index 89bd84b000..c81430e67d 100644 --- a/src/solver/expressions/visitors/TimeIndexVisitor.cpp +++ b/src/solver/expressions/visitors/TimeIndexVisitor.cpp @@ -92,6 +92,11 @@ TimeIndex TimeIndexVisitor::visit(const Nodes::PortFieldNode* port_field_node) return context_.at(port_field_node); } +TimeIndex TimeIndexVisitor::visit(const Nodes::PortFieldSumNode* port_field_node) +{ + return context_.at(port_field_node); +} + TimeIndex TimeIndexVisitor::visit(const Nodes::ComponentVariableNode* component_variable_node) { return context_.at(component_variable_node); diff --git a/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp b/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp index 09f80008f3..c227cda025 100644 --- a/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp +++ b/src/tests/src/solver/expressions/test_AstDOTStyleVisitor.cpp @@ -50,7 +50,8 @@ class Fixture Node* variableNode = registry_.create("atoms_count"); Node* divisionNode = registry_.create(variableNode, multiplicationNode); Node* portFieldNode = registry_.create("gasStation", "1149"); - Node* sumNode = registry_.create(divisionNode, portFieldNode); + Node* portFieldSumNode = registry_.create("portfield", "sum"); + Node* sumNode = registry_.create(divisionNode, portFieldNode, portFieldSumNode); Node* componentVariableNode = registry_.create("1150", "otherStation"); Node* componentParameterNode = registry_.create("1151", @@ -103,7 +104,9 @@ node[style = filled] 14 [label="Param(avogadro_constant)", shape="box", style="filled, solid", color="wheat"]; 7 -> 16; 16 [label="PF(gasStation,1149)", shape="component", style="filled, solid", color="olive"]; -label="AST Diagram(Total nodes : 16)" + 7 -> 17; + 17 [label="PFSUM(portfield,sum)", shape="component", style="filled, solid", color="olive"]; +label="AST Diagram(Total nodes : 17)" labelloc = "t" subgraph cluster_legend { label = "Legend"; @@ -133,7 +136,9 @@ legend_NegationNode -> legend_ParameterNode [style=invis]; legend_ParameterNode [ label =" ParameterNode: 1"] legend_ParameterNode -> legend_PortFieldNode [style=invis]; legend_PortFieldNode [ label =" PortFieldNode: 1"] -legend_PortFieldNode -> legend_SubtractionNode [style=invis]; +legend_PortFieldNode -> legend_PortFieldSumNode [style=invis]; +legend_PortFieldSumNode [ label =" PortFieldSumNode: 1"] +legend_PortFieldSumNode -> legend_SubtractionNode [style=invis]; legend_SubtractionNode [ label =" SubtractionNode: 1"] legend_SubtractionNode -> legend_SumNode [style=invis]; legend_SumNode [ label =" SumNode: 1"] diff --git a/src/tests/src/solver/expressions/test_CompareVisitor.cpp b/src/tests/src/solver/expressions/test_CompareVisitor.cpp index 373d1ff314..b0da099b80 100644 --- a/src/tests/src/solver/expressions/test_CompareVisitor.cpp +++ b/src/tests/src/solver/expressions/test_CompareVisitor.cpp @@ -64,7 +64,8 @@ Node* ComparisonFixture::createComplexExpression() Node* sub = registry_.create(add, neg); Node* cmp = registry_.create(sub, add); Node* pf = registry_.create("port", "field"); - Node* addf = registry_.create(pf, cmp); + Node* pfsum = registry_.create("port", "sum"); + Node* addf = registry_.create(pf, pfsum, cmp); return addf; } diff --git a/src/tests/src/solver/expressions/test_LinearVisitor.cpp b/src/tests/src/solver/expressions/test_LinearVisitor.cpp index 689035f0f7..590a6e4e85 100644 --- a/src/tests/src/solver/expressions/test_LinearVisitor.cpp +++ b/src/tests/src/solver/expressions/test_LinearVisitor.cpp @@ -276,6 +276,7 @@ BOOST_FIXTURE_TEST_CASE(simple_constant_expression, Registry) // Port field PortFieldNode portFieldNode("port", "field"); + PortFieldSumNode portFieldSumNode("port", "sum"); // 65.*p1 Node* mult = create(&var1, &par); @@ -283,6 +284,10 @@ BOOST_FIXTURE_TEST_CASE(simple_constant_expression, Registry) Node* expr = create(mult, &portFieldNode); BOOST_CHECK_EQUAL(printVisitor.dispatch(expr), "((65.000000*p1)+port.field)"); BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::CONSTANT); + + Node* expr2 = create(mult, &portFieldSumNode); + BOOST_CHECK_EQUAL(printVisitor.dispatch(expr2), "((65.000000*p1)+port.sum)"); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr2), LinearStatus::CONSTANT); } BOOST_FIXTURE_TEST_CASE(LinearityVisitor_name, Registry) diff --git a/src/tests/src/solver/expressions/test_PrintAndEvalNodes.cpp b/src/tests/src/solver/expressions/test_PrintAndEvalNodes.cpp index 74743b383c..8ea1a61b1e 100644 --- a/src/tests/src/solver/expressions/test_PrintAndEvalNodes.cpp +++ b/src/tests/src/solver/expressions/test_PrintAndEvalNodes.cpp @@ -203,6 +203,15 @@ BOOST_FIXTURE_TEST_CASE(print_port_field_node, Registry) BOOST_CHECK_EQUAL(printed, "august.2024"); } +BOOST_FIXTURE_TEST_CASE(print_port_field_sum_node, Registry) +{ + PortFieldSumNode pt_fd("august", "2024"); + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(&pt_fd); + + BOOST_CHECK_EQUAL(printed, "august.2024"); +} + BOOST_FIXTURE_TEST_CASE(evaluate_param, Registry) { ParameterNode root("my-param"); @@ -345,6 +354,7 @@ BOOST_FIXTURE_TEST_CASE(NotEvaluableNodes, Registry) create(&literalNode, &literalNode), create(&literalNode, &literalNode), create(name, name), + create(name, name), create(component_id, name), create(component_id, name)}; EvalVisitor evalVisitor; diff --git a/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp b/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp index a13d2392a8..dc310c7aa1 100644 --- a/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp +++ b/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp @@ -26,7 +26,8 @@ #include #include #include -#include +#include +#include #include #include @@ -113,10 +114,12 @@ class SubstitutionFixture: public Registry Node* substitute(Node* original) { - PortfieldSubstitutionContext ctx; - ctx.portfield.emplace(PortFieldNode("port", "literal"), create(10)); + PortFieldSubstitutionContext ctx; + ctx.portfield.emplace(std::piecewise_construct, + std::forward_as_tuple("port", "literal"), + std::forward_as_tuple(create(10))); - PortfieldSubstitutionVisitor sub(*this, ctx); + PortFieldSubstitutionVisitor sub(*this, ctx); return sub.dispatch(original); } }; @@ -134,10 +137,63 @@ BOOST_FIXTURE_TEST_CASE(PortfieldSubstitutionVisitor_simple, SubstitutionFixture BOOST_FIXTURE_TEST_CASE(PortfieldSubstitutionVisitor_name, Registry) { - PortfieldSubstitutionContext ctx; + PortFieldSubstitutionContext ctx; - PortfieldSubstitutionVisitor substitutionVisitor(*this, ctx); - BOOST_CHECK_EQUAL(substitutionVisitor.name(), "PortfieldSubstitutionVisitor"); + PortFieldSubstitutionVisitor substitutionVisitor(*this, ctx); + BOOST_CHECK_EQUAL(substitutionVisitor.name(), "PortFieldSubstitutionVisitor"); +} + +class SumSubstitutionFixture: public Registry +{ +public: + Node* originalExpression() + { + Node* port1 = create("port", "sum of literal"); + Node* port2 = create("another port", "another field"); + Node* root = create(port1, port2); + return root; + } + + Node* expectedExpressionAfterSubstitution() + { + Node* node1 = create(create(12), create(7)); + Node* port2 = create("another port", "another field"); + Node* root = create(node1, port2); + return root; + } + + Node* substitute(Node* original) + { + PortFieldSumSubstitutionContext ctx; + Node* sum1 = create(12); + Node* sum2 = create(7); + std::vector v = {sum1, sum2}; + ctx.portfieldSum.emplace(std::piecewise_construct, + std::forward_as_tuple("port", "sum of literal"), + std::forward_as_tuple(v)); + + PortFieldSumSubstitutionVisitor sub(*this, ctx); + return sub.dispatch(original); + } +}; + +BOOST_FIXTURE_TEST_CASE(PortFieldSumSubstitutionVisitor_simple, SumSubstitutionFixture) + +{ + Node* original = originalExpression(); + Node* substituted = substitute(original); + Node* expected = expectedExpressionAfterSubstitution(); + + CompareVisitor cmp; + BOOST_CHECK(cmp.dispatch(substituted, expected)); +} + +BOOST_FIXTURE_TEST_CASE(PortfieldSumSubstitutionVisitor_name, Registry) +{ + PortFieldSumSubstitutionContext ctx; + + PortFieldSumSubstitutionVisitor substitutionVisitor(*this, ctx); + BOOST_CHECK_EQUAL(substitutionVisitor.name(), "PortFieldSumSubstitutionVisitor"); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/expressions/test_TimeIndexVisitor.cpp b/src/tests/src/solver/expressions/test_TimeIndexVisitor.cpp index d95ae2f188..030318d517 100644 --- a/src/tests/src/solver/expressions/test_TimeIndexVisitor.cpp +++ b/src/tests/src/solver/expressions/test_TimeIndexVisitor.cpp @@ -128,6 +128,7 @@ static Node* singleNode(Registry& registry) static const std::vector& registry)> singleNode_ALL{ &singleNode, + &singleNode, &singleNode, &singleNode}; diff --git a/src/tests/src/solver/expressions/test_nodes.cpp b/src/tests/src/solver/expressions/test_nodes.cpp index 3078a9cfbe..b21caac631 100644 --- a/src/tests/src/solver/expressions/test_nodes.cpp +++ b/src/tests/src/solver/expressions/test_nodes.cpp @@ -63,6 +63,16 @@ BOOST_AUTO_TEST_CASE(PortFieldNodeTest) BOOST_CHECK_EQUAL(portFieldNode1 == portFieldNode2, false); } +BOOST_AUTO_TEST_CASE(PortFieldSumNodeTest) +{ + std::string portName1("p1"); + std::string fieldName1("f1"); + + PortFieldSumNode pfs(portName1, fieldName1); + BOOST_CHECK_EQUAL(pfs.getPortName(), portName1); + BOOST_CHECK_EQUAL(pfs.getFieldName(), fieldName1); +} + BOOST_FIXTURE_TEST_CASE(nodes_name, Registry) { auto literalNode = create(2024.2); @@ -82,7 +92,8 @@ BOOST_FIXTURE_TEST_CASE(nodes_name, Registry) "ComponentParameterNode"}, {create(literalNode->name()), "ParameterNode"}, {create(literalNode->name()), "VariableNode"}, - {create(literalNode->name(), literalNode->name()), "PortFieldNode"}}; + {create(literalNode->name(), literalNode->name()), "PortFieldNode"}, + {create(literalNode->name(), literalNode->name()), "PortFieldSumNode"}}; for (auto [node, name]: nodes) { From f20ffc8f104cec8b96795e8cdf02d920f4b5fb08 Mon Sep 17 00:00:00 2001 From: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:01:29 +0200 Subject: [PATCH 019/103] API modeler - 1.1.b (#2391) The goal of this PR is to introduce and unit test class **LinearProblemBuilder**. This class is an orchestration class, and therefore makes other classes collaborate. What was done : - Remove **LinearProblemBuilder::solve()** : this method was planned in the specifications, but it extends the builder responsibility scope. Once modified by the builder, the problem can be solved by calling its own **solve()** method. - Add methods **numVariables()** and **numConstraints()** to base class **ILinearProblem** for unit tests reason. - **CMakeLists.txt** file for modeler API was split into 2 **\*.cmake** files - **Trial for a dependency simplification** : In the original / specified architecture, **LinearProblemBuilder** collaborates with classes : - **LinearProblemData** - **ILinearProblem** (interface for LP) - **LinearProblemFiller** : this class also depends on previous classes Here, we allowed ourselves to reduce dependencies of this builder class (is this simplification relevant ?) : class **LinearProblemBuilder** currently only depends on **LinearProblemFiller**, while fillers keeps its planned dependencies on **LinearProblemData** and **ILinearProblem**. Indeed, any filler is in charge to modify problem (using LP data), the but the builder only manipulates fillers. - **Mocking fillers** : fillers are the entities responsible for creating variables and constraints in the linear problem. To do that, they need the LP itself as well as the LP data (see fillers constructor). We created an abstract base filler. All concrete filler inherit from it. Class **LinearProblemBuilder** is constructed from a vector of fillers. - Several unit tests were created for class **LinearProblemBuilder** --------- Co-authored-by: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> --- src/solver/modeler/api/CMakeLists.txt | 3 +- .../solver/modeler/api/linearProblem.h | 2 + .../solver/modeler/api/linearProblemBuilder.h | 9 +- .../solver/modeler/api/linearProblemFiller.h | 9 +- .../modeler/api/linearProblemBuilder.cpp | 21 ++++ src/solver/modeler/ortoolsImpl/CMakeLists.txt | 2 +- .../modeler/ortoolsImpl/linearProblem.h | 3 +- .../modeler/ortoolsImpl/linearProblem.cpp | 10 ++ .../src/solver/modeler/api/CMakeLists.txt | 16 ++- .../api/mock-fillers/OneConstraintFiller.h | 30 +++++ .../modeler/api/mock-fillers/OneVarFiller.h | 35 ++++++ .../TwoVarsTwoConstraintsFiller.h | 33 +++++ .../modeler/api/testModelerLPbuilder.cpp | 115 ++++++++++++++++++ ...> testModelerLinearProblemWithOrtools.cpp} | 1 - .../src/solver/modeler/api/test_main.cpp | 26 ++++ 15 files changed, 298 insertions(+), 17 deletions(-) create mode 100644 src/solver/modeler/api/linearProblemBuilder.cpp create mode 100644 src/tests/src/solver/modeler/api/mock-fillers/OneConstraintFiller.h create mode 100644 src/tests/src/solver/modeler/api/mock-fillers/OneVarFiller.h create mode 100644 src/tests/src/solver/modeler/api/mock-fillers/TwoVarsTwoConstraintsFiller.h create mode 100644 src/tests/src/solver/modeler/api/testModelerLPbuilder.cpp rename src/tests/src/solver/modeler/api/{testApiOrtoolsLinearProblem.cpp => testModelerLinearProblemWithOrtools.cpp} (99%) create mode 100644 src/tests/src/solver/modeler/api/test_main.cpp diff --git a/src/solver/modeler/api/CMakeLists.txt b/src/solver/modeler/api/CMakeLists.txt index 049c2dfa8e..41789ae9cb 100644 --- a/src/solver/modeler/api/CMakeLists.txt +++ b/src/solver/modeler/api/CMakeLists.txt @@ -1,4 +1,4 @@ -set(PROJ optim_api) +set(PROJ modeler_api) set(SRC_API include/antares/solver/modeler/api/mipVariable.h @@ -14,6 +14,7 @@ set(SRC_API include/antares/solver/modeler/api/linearProblemBuilder.h linearProblemData.cpp + linearProblemBuilder.cpp ) add_library(${PROJ} ${SRC_API}) diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h index b997242ec7..38006291e0 100644 --- a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h @@ -47,10 +47,12 @@ class ILinearProblem /// Create a integer variable virtual IMipVariable* addIntVariable(double lb, double ub, const std::string& name) = 0; virtual IMipVariable* getVariable(const std::string& name) const = 0; + virtual int variableCount() const = 0; /// Add a bounded constraint to the problem virtual IMipConstraint* addConstraint(double lb, double ub, const std::string& name) = 0; virtual IMipConstraint* getConstraint(const std::string& name) const = 0; + virtual int constraintCount() const = 0; /// Set the objective coefficient for a given variable virtual void setObjectiveCoefficient(IMipVariable* var, double coefficient) = 0; diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemBuilder.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemBuilder.h index b4131d4f6b..c5b4419113 100644 --- a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemBuilder.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemBuilder.h @@ -24,7 +24,6 @@ #include #include "linearProblemFiller.h" -#include "mipSolution.h" namespace Antares::Solver::Modeler::Api { @@ -32,9 +31,11 @@ namespace Antares::Solver::Modeler::Api class LinearProblemBuilder { public: - virtual void LinearProblemBuilder(std::vector fillers) = 0; - virtual void build(LinearProblemData* data) = 0; - virtual MipSolution* solve() = 0; + explicit LinearProblemBuilder(const std::vector& fillers); + void build(ILinearProblem& pb, LinearProblemData& data); + +private: + const std::vector& fillers_; }; } // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemFiller.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemFiller.h index b337dea247..aad1fa3ce6 100644 --- a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemFiller.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemFiller.h @@ -21,6 +21,8 @@ #pragma once +#include + #include #include @@ -30,9 +32,10 @@ namespace Antares::Solver::Modeler::Api class LinearProblemFiller { public: - virtual void addVariables(LinearProblem* problem, LinearProblemData* data) = 0; - virtual void addConstraints(LinearProblem* problem, LinearProblemData* data) = 0; - virtual void addObjectiveCoefficients(LinearProblem* problem, LinearProblemData* data) = 0; + virtual void addVariables(ILinearProblem& pb, LinearProblemData& data) = 0; + virtual void addConstraints(ILinearProblem& pb, LinearProblemData& data) = 0; + virtual void addObjective(ILinearProblem& pb, LinearProblemData& data) = 0; + virtual ~LinearProblemFiller() = default; }; } // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/api/linearProblemBuilder.cpp b/src/solver/modeler/api/linearProblemBuilder.cpp new file mode 100644 index 0000000000..f9d6103152 --- /dev/null +++ b/src/solver/modeler/api/linearProblemBuilder.cpp @@ -0,0 +1,21 @@ +#include +#include + +#include + +namespace Antares::Solver::Modeler::Api +{ + +LinearProblemBuilder::LinearProblemBuilder(const std::vector& fillers): + fillers_(fillers) +{ +} + +void LinearProblemBuilder::build(ILinearProblem& pb, LinearProblemData& data) +{ + std::ranges::for_each(fillers_, [&](const auto& filler) { filler->addVariables(pb, data); }); + std::ranges::for_each(fillers_, [&](const auto& filler) { filler->addConstraints(pb, data); }); + std::ranges::for_each(fillers_, [&](const auto& filler) { filler->addObjective(pb, data); }); +} + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/ortoolsImpl/CMakeLists.txt b/src/solver/modeler/ortoolsImpl/CMakeLists.txt index ef94b552cc..309fb67fa8 100644 --- a/src/solver/modeler/ortoolsImpl/CMakeLists.txt +++ b/src/solver/modeler/ortoolsImpl/CMakeLists.txt @@ -23,7 +23,7 @@ add_library(Antares::${PROJ} ALIAS ${PROJ}) target_link_libraries(${PROJ} PUBLIC - Antares::optim_api + Antares::modeler_api Antares::logs Antares::solverUtils ortools::ortools diff --git a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h index 6a34ccfcc5..d4e6e52c02 100644 --- a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h +++ b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h @@ -44,11 +44,12 @@ class OrtoolsLinearProblem final: public Api::ILinearProblem OrtoolsMipVariable* addNumVariable(double lb, double ub, const std::string& name) override; OrtoolsMipVariable* addIntVariable(double lb, double ub, const std::string& name) override; - OrtoolsMipVariable* getVariable(const std::string& name) const override; + int variableCount() const override; OrtoolsMipConstraint* addConstraint(double lb, double ub, const std::string& name) override; OrtoolsMipConstraint* getConstraint(const std::string& name) const override; + int constraintCount() const override; void setObjectiveCoefficient(Api::IMipVariable* var, double coefficient) override; double getObjectiveCoefficient(const Api::IMipVariable* var) const override; diff --git a/src/solver/modeler/ortoolsImpl/linearProblem.cpp b/src/solver/modeler/ortoolsImpl/linearProblem.cpp index 7c6593fa52..1d8bf981bc 100644 --- a/src/solver/modeler/ortoolsImpl/linearProblem.cpp +++ b/src/solver/modeler/ortoolsImpl/linearProblem.cpp @@ -93,6 +93,11 @@ OrtoolsMipVariable* OrtoolsLinearProblem::getVariable(const std::string& name) c return variables_.at(name).get(); } +int OrtoolsLinearProblem::variableCount() const +{ + return mpSolver_->NumVariables(); +} + OrtoolsMipConstraint* OrtoolsLinearProblem::addConstraint(double lb, double ub, const std::string& name) @@ -120,6 +125,11 @@ OrtoolsMipConstraint* OrtoolsLinearProblem::getConstraint(const std::string& nam return constraints_.at(name).get(); } +int OrtoolsLinearProblem::constraintCount() const +{ + return mpSolver_->NumConstraints(); +} + static const operations_research::MPVariable* getMpVar(const Api::IMipVariable* var) { diff --git a/src/tests/src/solver/modeler/api/CMakeLists.txt b/src/tests/src/solver/modeler/api/CMakeLists.txt index 0299f3ec0b..ae048140aa 100644 --- a/src/tests/src/solver/modeler/api/CMakeLists.txt +++ b/src/tests/src/solver/modeler/api/CMakeLists.txt @@ -1,6 +1,12 @@ -set(EXECUTABLE_NAME tests-modeler-api-ortools) -add_executable(${EXECUTABLE_NAME} testApiOrtoolsLinearProblem.cpp) +set(EXECUTABLE_NAME unit-tests-for-modeler-api) +add_executable(${EXECUTABLE_NAME}) +target_sources(${EXECUTABLE_NAME} + PRIVATE + test_main.cpp + testModelerLinearProblemWithOrtools.cpp + testModelerLPbuilder.cpp +) target_include_directories(${EXECUTABLE_NAME} PRIVATE "${src_solver_optimisation}" @@ -12,9 +18,7 @@ target_link_libraries(${EXECUTABLE_NAME} Antares::modeler-ortools-impl ) -# Storing tests-ts-numbers under the folder Unit-tests in the IDE set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) +add_test(NAME ${EXECUTABLE_NAME} COMMAND ${EXECUTABLE_NAME}) +set_property(TEST ${EXECUTABLE_NAME} PROPERTY LABELS unit) -add_test(NAME test-modeler-api-ortools COMMAND ${EXECUTABLE_NAME}) - -set_property(TEST test-modeler-api-ortools PROPERTY LABELS unit) diff --git a/src/tests/src/solver/modeler/api/mock-fillers/OneConstraintFiller.h b/src/tests/src/solver/modeler/api/mock-fillers/OneConstraintFiller.h new file mode 100644 index 0000000000..cb1f9db3e9 --- /dev/null +++ b/src/tests/src/solver/modeler/api/mock-fillers/OneConstraintFiller.h @@ -0,0 +1,30 @@ +#pragma once + +#include "antares/solver/modeler/api/linearProblemFiller.h" + +namespace Antares::Solver::Modeler::Api +{ + +class OneConstraintFiller: public LinearProblemFiller +{ +public: + explicit OneConstraintFiller() = default; + void addVariables(ILinearProblem& pb, LinearProblemData& data) override; + void addConstraints(ILinearProblem& pb, LinearProblemData& data) override; + void addObjective(ILinearProblem& pb, LinearProblemData& data) override; +}; + +void OneConstraintFiller::addVariables(ILinearProblem& pb, LinearProblemData& data) +{ +} + +void OneConstraintFiller::addConstraints(ILinearProblem& pb, LinearProblemData& data) +{ + pb.addConstraint(1, 2, "constraint-by-OneConstraintFiller"); +} + +void OneConstraintFiller::addObjective(ILinearProblem& pb, LinearProblemData& data) +{ +} + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/tests/src/solver/modeler/api/mock-fillers/OneVarFiller.h b/src/tests/src/solver/modeler/api/mock-fillers/OneVarFiller.h new file mode 100644 index 0000000000..5d2ba08b55 --- /dev/null +++ b/src/tests/src/solver/modeler/api/mock-fillers/OneVarFiller.h @@ -0,0 +1,35 @@ +#pragma once + +#include "antares/solver/modeler/api/linearProblemFiller.h" + +namespace Antares::Solver::Modeler::Api +{ + +class OneVarFiller: public LinearProblemFiller +{ +public: + explicit OneVarFiller() = default; + void addVariables(ILinearProblem& pb, LinearProblemData& data) override; + void addConstraints(ILinearProblem& pb, LinearProblemData& data) override; + void addObjective(ILinearProblem& pb, LinearProblemData& data) override; + +private: + std::string added_var_name_ = "var-by-OneVarFiller"; +}; + +void OneVarFiller::addVariables(ILinearProblem& pb, LinearProblemData& data) +{ + pb.addNumVariable(0, 1, added_var_name_); +} + +void OneVarFiller::addConstraints(ILinearProblem& pb, LinearProblemData& data) +{ +} + +void OneVarFiller::addObjective(ILinearProblem& pb, LinearProblemData& data) +{ + auto* var = pb.getVariable(added_var_name_); + pb.setObjectiveCoefficient(var, 1); +} + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/tests/src/solver/modeler/api/mock-fillers/TwoVarsTwoConstraintsFiller.h b/src/tests/src/solver/modeler/api/mock-fillers/TwoVarsTwoConstraintsFiller.h new file mode 100644 index 0000000000..e8671644df --- /dev/null +++ b/src/tests/src/solver/modeler/api/mock-fillers/TwoVarsTwoConstraintsFiller.h @@ -0,0 +1,33 @@ +#pragma once + +#include "antares/solver/modeler/api/linearProblemFiller.h" + +namespace Antares::Solver::Modeler::Api +{ + +class TwoVarsTwoConstraintsFiller: public LinearProblemFiller +{ +public: + explicit TwoVarsTwoConstraintsFiller() = default; + void addVariables(ILinearProblem& pb, LinearProblemData& data) override; + void addConstraints(ILinearProblem& pb, LinearProblemData& data) override; + void addObjective(ILinearProblem& pb, LinearProblemData& data) override; +}; + +void TwoVarsTwoConstraintsFiller::addVariables(ILinearProblem& pb, LinearProblemData& data) +{ + pb.addNumVariable(0, 1, "var-1-by-TwoVarsTwoConstraintsFiller"); + pb.addNumVariable(0, 3, "var-2-by-TwoVarsTwoConstraintsFiller"); +} + +void TwoVarsTwoConstraintsFiller::addConstraints(ILinearProblem& pb, LinearProblemData& data) +{ + pb.addConstraint(1, 2, "constr-1-by-TwoVarsTwoConstraintsFiller"); + pb.addConstraint(1, 3, "constr-2-by-TwoVarsTwoConstraintsFiller"); +} + +void TwoVarsTwoConstraintsFiller::addObjective(ILinearProblem& pb, LinearProblemData& data) +{ +} + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/tests/src/solver/modeler/api/testModelerLPbuilder.cpp b/src/tests/src/solver/modeler/api/testModelerLPbuilder.cpp new file mode 100644 index 0000000000..ccdccf251a --- /dev/null +++ b/src/tests/src/solver/modeler/api/testModelerLPbuilder.cpp @@ -0,0 +1,115 @@ +/* + * 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 . + */ +#define WIN32_LEAN_AND_MEAN + +#include + +#include +#include + +#include "mock-fillers/OneConstraintFiller.h" +#include "mock-fillers/OneVarFiller.h" +#include "mock-fillers/TwoVarsTwoConstraintsFiller.h" + +using namespace Antares::Solver::Modeler::Api; +using namespace Antares::Solver::Modeler::OrtoolsImpl; + +struct Fixture +{ + Fixture() + { + pb = std::make_unique(false, "sirius"); + } + + std::vector fillers; + LinearProblemData LP_Data; + std::unique_ptr pb; +}; + +BOOST_AUTO_TEST_SUITE(tests_on_linear_problem_builder) + +BOOST_FIXTURE_TEST_CASE(no_filler_given_to_builder___nothing_built, Fixture) +{ + LinearProblemBuilder lpBuilder(fillers); + lpBuilder.build(*pb, LP_Data); + + BOOST_CHECK_EQUAL(pb->variableCount(), 0); + BOOST_CHECK_EQUAL(pb->constraintCount(), 0); +} + +BOOST_FIXTURE_TEST_CASE(one_var_filler___the_var_is_built, Fixture) +{ + auto oneVarFiller = std::make_unique(); + fillers = {oneVarFiller.get()}; + + LinearProblemBuilder lpBuilder(fillers); + lpBuilder.build(*pb, LP_Data); + + BOOST_CHECK_EQUAL(pb->variableCount(), 1); + BOOST_CHECK_EQUAL(pb->constraintCount(), 0); + auto* var = pb->getVariable("var-by-OneVarFiller"); + BOOST_CHECK(var); + BOOST_CHECK_EQUAL(pb->getObjectiveCoefficient(var), 1); +} + +BOOST_FIXTURE_TEST_CASE(one_constraint_filler___the_constraint_is_built, Fixture) +{ + auto oneConstrFiller = std::make_unique(); + fillers = {oneConstrFiller.get()}; + + LinearProblemBuilder lpBuilder(fillers); + lpBuilder.build(*pb, LP_Data); + + BOOST_CHECK_EQUAL(pb->variableCount(), 0); + BOOST_CHECK_EQUAL(pb->constraintCount(), 1); + BOOST_CHECK(pb->getConstraint("constraint-by-OneConstraintFiller")); +} + +BOOST_FIXTURE_TEST_CASE(two_fillers_given_to_builder___all_is_built, Fixture) +{ + auto oneVarFiller = std::make_unique(); + auto oneConstrFiller = std::make_unique(); + + fillers = {oneVarFiller.get(), oneConstrFiller.get()}; + + LinearProblemBuilder lpBuilder(fillers); + lpBuilder.build(*pb, LP_Data); + + BOOST_CHECK_EQUAL(pb->constraintCount(), 1); + BOOST_CHECK(pb->getConstraint("constraint-by-OneConstraintFiller")); + BOOST_CHECK_EQUAL(pb->variableCount(), 1); +} + +BOOST_FIXTURE_TEST_CASE(three_fillers_given_to_builder___3_vars_3_constr_are_built, Fixture) +{ + auto oneVarFiller = std::make_unique(); + auto oneConstrFiller = std::make_unique(); + auto twoVarsTwoConstrFiller = std::make_unique(); + fillers = {oneVarFiller.get(), oneConstrFiller.get(), twoVarsTwoConstrFiller.get()}; + + LinearProblemBuilder lpBuilder(fillers); + lpBuilder.build(*pb, LP_Data); + + BOOST_CHECK_EQUAL(pb->variableCount(), 3); + BOOST_CHECK_EQUAL(pb->constraintCount(), 3); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/modeler/api/testApiOrtoolsLinearProblem.cpp b/src/tests/src/solver/modeler/api/testModelerLinearProblemWithOrtools.cpp similarity index 99% rename from src/tests/src/solver/modeler/api/testApiOrtoolsLinearProblem.cpp rename to src/tests/src/solver/modeler/api/testModelerLinearProblemWithOrtools.cpp index 06bbcb6669..7c1f8f84e3 100644 --- a/src/tests/src/solver/modeler/api/testApiOrtoolsLinearProblem.cpp +++ b/src/tests/src/solver/modeler/api/testModelerLinearProblemWithOrtools.cpp @@ -18,7 +18,6 @@ * You should have received a copy of the Mozilla Public Licence 2.0 * along with Antares_Simulator. If not, see . */ -#define BOOST_TEST_MODULE test modeler api ortools #define WIN32_LEAN_AND_MEAN diff --git a/src/tests/src/solver/modeler/api/test_main.cpp b/src/tests/src/solver/modeler/api/test_main.cpp new file mode 100644 index 0000000000..0d5864e717 --- /dev/null +++ b/src/tests/src/solver/modeler/api/test_main.cpp @@ -0,0 +1,26 @@ +/* + * 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 . + */ + +#define BOOST_TEST_MODULE test modeler api + +#define WIN32_LEAN_AND_MEAN + +#include From 63a14a89667242087bdddba4d1a283b9d3daab40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 30 Sep 2024 10:19:06 +0200 Subject: [PATCH 020/103] [DOC] Add changelog for branch 8.8.x (#2441) --- docs/developer-guide/CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/developer-guide/CHANGELOG.md b/docs/developer-guide/CHANGELOG.md index 880f5dc220..a8ca144e86 100644 --- a/docs/developer-guide/CHANGELOG.md +++ b/docs/developer-guide/CHANGELOG.md @@ -89,6 +89,24 @@ toc_depth: 2 * Fix invalid index causing segfault in `test-study` test (#1902) ## Branch 8.8.x (end of support 12/2025) +### 8.8.10 (09/2024) + +#### Bugfix (adequacy patch) +* Force enable-first-step=false [ANT-2218] (#2419) +* Adequacy patch CSR - revamp output variables [ANT-1932] (#2421) +* Place CSR after hydro remix [ANT-2070] (#2407) + +#### Bugfix (other) +* Use OR-Tools v9.11-rte1.1 [ANT-2069] (#2418) + +## 8.8.9 (09/2024) +* Revert "Fix bug hydro heuristic with mingen (ANT-1825) (#2258)" + +## 8.8.8 (09/2024) +#### Bugfix +* Timeseries generation stored in input (#2180) +* Fix bug hydro heuristic with mingen (ANT-1825) (#2258) + ### 8.8.7 (07/2024) #### Improvements - Add OR-Tools solver option for batchrun tool (#1981) From fe29d3791da83594a1a156535028156398983dca Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:53:43 +0200 Subject: [PATCH 021/103] Modeleur 2.1: Lib for modeling objects [ANT-1877] (#2383) Add basic classes and structures to represent a model library --- src/solver/CMakeLists.txt | 1 + src/solver/libModelObject/CMakeLists.txt | 32 ++++++++++ .../solver/libObjectModel/constraint.h | 43 +++++++++++++ .../solver/libObjectModel/expression.h | 35 +++++++++++ .../antares/solver/libObjectModel/library.h | 46 ++++++++++++++ .../antares/solver/libObjectModel/model.h | 60 +++++++++++++++++++ .../antares/solver/libObjectModel/parameter.h | 48 +++++++++++++++ .../antares/solver/libObjectModel/port.h | 41 +++++++++++++ .../antares/solver/libObjectModel/portField.h | 34 +++++++++++ .../libObjectModel/portFieldDefinition.h | 40 +++++++++++++ .../antares/solver/libObjectModel/portType.h | 44 ++++++++++++++ .../antares/solver/libObjectModel/valueType.h | 34 +++++++++++ .../antares/solver/libObjectModel/variable.h | 46 ++++++++++++++ src/solver/libModelObject/model.cpp | 32 ++++++++++ 14 files changed, 536 insertions(+) create mode 100644 src/solver/libModelObject/CMakeLists.txt create mode 100644 src/solver/libModelObject/include/antares/solver/libObjectModel/constraint.h create mode 100644 src/solver/libModelObject/include/antares/solver/libObjectModel/expression.h create mode 100644 src/solver/libModelObject/include/antares/solver/libObjectModel/library.h create mode 100644 src/solver/libModelObject/include/antares/solver/libObjectModel/model.h create mode 100644 src/solver/libModelObject/include/antares/solver/libObjectModel/parameter.h create mode 100644 src/solver/libModelObject/include/antares/solver/libObjectModel/port.h create mode 100644 src/solver/libModelObject/include/antares/solver/libObjectModel/portField.h create mode 100644 src/solver/libModelObject/include/antares/solver/libObjectModel/portFieldDefinition.h create mode 100644 src/solver/libModelObject/include/antares/solver/libObjectModel/portType.h create mode 100644 src/solver/libModelObject/include/antares/solver/libObjectModel/valueType.h create mode 100644 src/solver/libModelObject/include/antares/solver/libObjectModel/variable.h create mode 100644 src/solver/libModelObject/model.cpp diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 37d0f4c003..28b51b11bd 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -21,6 +21,7 @@ add_subdirectory(utils) add_subdirectory(variable) add_subdirectory(modeler) add_subdirectory(expressions) +add_subdirectory(libModelObject) # # Resource file for Windows diff --git a/src/solver/libModelObject/CMakeLists.txt b/src/solver/libModelObject/CMakeLists.txt new file mode 100644 index 0000000000..ce2ae94d35 --- /dev/null +++ b/src/solver/libModelObject/CMakeLists.txt @@ -0,0 +1,32 @@ +project(LibObjectModel) + +set(SRC_model + model.cpp + + include/antares/solver/libObjectModel/library.h + include/antares/solver/libObjectModel/model.h + include/antares/solver/libObjectModel/parameter.h + include/antares/solver/libObjectModel/valueType.h + include/antares/solver/libObjectModel/variable.h + include/antares/solver/libObjectModel/constraint.h + include/antares/solver/libObjectModel/expression.h + include/antares/solver/libObjectModel/port.h + include/antares/solver/libObjectModel/portField.h + include/antares/solver/libObjectModel/portFieldDefinition.h + include/antares/solver/libObjectModel/portType.h +) + +source_group("libObjectModel" FILES ${SRC_model}) +add_library(antares-solver-libObjectModel + ${SRC_model}) + +target_include_directories(antares-solver-libObjectModel + PUBLIC + $ +) +target_link_libraries(antares-solver-libObjectModel + PUBLIC +) +install(DIRECTORY include/antares + DESTINATION "include" +) diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/constraint.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/constraint.h new file mode 100644 index 0000000000..fbf28a3a89 --- /dev/null +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/constraint.h @@ -0,0 +1,43 @@ +/* +** 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 "expression.h" +#include "parameter.h" + +namespace Antares::Solver::ObjectModel +{ + +/// A constraint linking variables and parameters of a model together +class Constraint +{ +public: + Constraint(); + ~Constraint() = default; + +private: + std::string name_; + Expression expression_; +}; + +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/expression.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/expression.h new file mode 100644 index 0000000000..c83165ee09 --- /dev/null +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/expression.h @@ -0,0 +1,35 @@ +/* +** 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 + +namespace Antares::Solver::ObjectModel +{ + +class Expression +{ +public: + Expression(); + ~Expression() = default; +}; + +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/library.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/library.h new file mode 100644 index 0000000000..9752aeb0f0 --- /dev/null +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/library.h @@ -0,0 +1,46 @@ +/* +** 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 "model.h" +#include "portType.h" + +namespace Antares::Solver::ObjectModel +{ + +/// A library is a collection of models +class Library +{ +public: + Library(); + ~Library() = default; + +private: + std::string id_; + std::string description_; + + std::map portTypes_; + std::map models_; +}; + +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/model.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/model.h new file mode 100644 index 0000000000..0cdeb0bb92 --- /dev/null +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/model.h @@ -0,0 +1,60 @@ +/* +** 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 + +#include "constraint.h" +#include "expression.h" +#include "parameter.h" +#include "port.h" +#include "variable.h" + +namespace Antares::Solver::ObjectModel +{ + +/** + * Defines a model that can be referenced by actual components. + * A model defines the behaviour of those components. + */ +class Model +{ +public: + Model(); + ~Model() = default; + + std::vector getConstraints(); + +private: + std::string id_; + Expression objective_; + + std::map parameters_; + std::map variables_; + + std::map constraints_; + std::map bindingConstraints_; + + std::map ports_; +}; + +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/parameter.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/parameter.h new file mode 100644 index 0000000000..55be8984e0 --- /dev/null +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/parameter.h @@ -0,0 +1,48 @@ +/* +** 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 "valueType.h" + +namespace Antares::Solver::ObjectModel +{ + +/** + * A parameter of the model: a parameter is mainly defined by a name and expected type. + * When the model is instantiated as a component, a value must be provided for + * parameters, either as constant values or timeseries-based values. + */ +class Parameter +{ +public: + Parameter(); + ~Parameter() = default; + +private: + std::string name_; + ValueType type_; + bool timeDependent_ = true; // optional at construction + bool scenarioDependent_ = true; // optional at construction +}; + +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/port.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/port.h new file mode 100644 index 0000000000..ddf89277cd --- /dev/null +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/port.h @@ -0,0 +1,41 @@ +/* +** 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 "portType.h" + +namespace Antares::Solver::ObjectModel +{ + +class Port +{ +public: + Port(); + ~Port() = default; + +private: + std::string name_; + PortType type_; +}; + +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/portField.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/portField.h new file mode 100644 index 0000000000..4484f62230 --- /dev/null +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/portField.h @@ -0,0 +1,34 @@ +/* +** 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 + +namespace Antares::Solver::ObjectModel +{ + +class PortField +{ +private: + std::string name; +}; + +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/portFieldDefinition.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/portFieldDefinition.h new file mode 100644 index 0000000000..9e22622d89 --- /dev/null +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/portFieldDefinition.h @@ -0,0 +1,40 @@ +/* +** 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 "port.h" +#include "portType.h" + +namespace Antares::Solver::ObjectModel +{ + +class PortFieldDefinition +{ + PortFieldDefinition(); + ~PortFieldDefinition() = default; + +private: + Port port_; + PortField field_; + Expression definition_; +}; + +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/portType.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/portType.h new file mode 100644 index 0000000000..662cbb7041 --- /dev/null +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/portType.h @@ -0,0 +1,44 @@ +/* +** 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 + +#include "portField.h" + +namespace Antares::Solver::ObjectModel +{ + +class PortType +{ +public: + PortType(); + ~PortType() = default; + +private: + std::string id_; + std::string description_; + + std::vector fields_; +}; + +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/valueType.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/valueType.h new file mode 100644 index 0000000000..feeac17b1e --- /dev/null +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/valueType.h @@ -0,0 +1,34 @@ +/* +** 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 + +namespace Antares::Solver::ObjectModel +{ + +/// Type of value held by variables or parameters +enum class ValueType +{ + FLOAT, + INTEGER, + BOOL +}; + +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/variable.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/variable.h new file mode 100644 index 0000000000..51665508ed --- /dev/null +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/variable.h @@ -0,0 +1,46 @@ +/* +** 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 "expression.h" +#include "parameter.h" +#include "valueType.h" + +namespace Antares::Solver::ObjectModel +{ + +/// A decision variable of the model +class Variable +{ +public: + Variable(); + ~Variable() = default; + +private: + std::string name_; + ValueType type_; + Expression lowerBound_; + Expression upperBound_; +}; + +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/model.cpp b/src/solver/libModelObject/model.cpp new file mode 100644 index 0000000000..19378317f8 --- /dev/null +++ b/src/solver/libModelObject/model.cpp @@ -0,0 +1,32 @@ +/* +** 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 + +namespace Antares::Solver::ObjectModel +{ + +std::vector getConstraints() +{ + return std::vector(); +} + +} // namespace Antares::Solver::ObjectModel From e7ca4c1f589497b582e880059392162c840c7bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 30 Sep 2024 15:00:24 +0200 Subject: [PATCH 022/103] Fix broken ToC for changelog (#2443) --- docs/developer-guide/CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/developer-guide/CHANGELOG.md b/docs/developer-guide/CHANGELOG.md index a8ca144e86..6430d1b2e5 100644 --- a/docs/developer-guide/CHANGELOG.md +++ b/docs/developer-guide/CHANGELOG.md @@ -90,7 +90,6 @@ toc_depth: 2 ## Branch 8.8.x (end of support 12/2025) ### 8.8.10 (09/2024) - #### Bugfix (adequacy patch) * Force enable-first-step=false [ANT-2218] (#2419) * Adequacy patch CSR - revamp output variables [ANT-1932] (#2421) @@ -99,10 +98,10 @@ toc_depth: 2 #### Bugfix (other) * Use OR-Tools v9.11-rte1.1 [ANT-2069] (#2418) -## 8.8.9 (09/2024) +### 8.8.9 (09/2024) * Revert "Fix bug hydro heuristic with mingen (ANT-1825) (#2258)" -## 8.8.8 (09/2024) +### 8.8.8 (09/2024) #### Bugfix * Timeseries generation stored in input (#2180) * Fix bug hydro heuristic with mingen (ANT-1825) (#2258) From ac5218c34b97e37c338697c2467e4704e2be7c00 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Mon, 30 Sep 2024 15:09:44 +0200 Subject: [PATCH 023/103] Init test repo after the build (#2444) --- .github/workflows/windows-vcpkg.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/windows-vcpkg.yml b/.github/workflows/windows-vcpkg.yml index e5cf8fea3f..5fb4b19603 100644 --- a/.github/workflows/windows-vcpkg.yml +++ b/.github/workflows/windows-vcpkg.yml @@ -110,14 +110,6 @@ jobs: - name: Install pip dependencies if necessary run: pip install -r src/tests/examples/requirements.txt - - name: Init submodule Antares_Simulator_Tests - run: | - git submodule update --init --remote src/tests/resources/Antares_Simulator_Tests - - - name: Init submodule Antares_Simulator_Tests_NR - run: | - git submodule update --init --remote src/tests/resources/Antares_Simulator_Tests_NR - - name: Enable git longpaths run: git config --system core.longpaths true @@ -152,6 +144,14 @@ jobs: run: | echo "SIMTEST=${{ fromJson(env.SIMTEST_JSON).version }}" >> $GITHUB_ENV + - name: Init submodule Antares_Simulator_Tests + run: | + git submodule update --init --remote src/tests/resources/Antares_Simulator_Tests + + - name: Init submodule Antares_Simulator_Tests_NR + run: | + git submodule update --init --remote src/tests/resources/Antares_Simulator_Tests_NR + - name: Run named mps tests if: ${{ env.RUN_SIMPLE_TESTS == 'true' && ! cancelled() }} uses: ./.github/workflows/run-tests From 2d77d8721ba8bd3d02c3b04d4cc7ad2435c42579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20Mar=C3=A9chal?= <45510813+JasonMarechal25@users.noreply.github.com> Date: Tue, 1 Oct 2024 18:07:36 +0200 Subject: [PATCH 024/103] [ANT-2206] Parse yaml (#2433) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Parse user models described as CPP - Expect to read one library per content - Only accept yaml content as std::string - Output object is Antares::Solver::ModelParser::Library - CMake : remove WITH_YAMLCPP (always ON) --------- Co-authored-by: Florian Omnès --- src/CMakeLists.txt | 3 - src/solver/CMakeLists.txt | 30 +- src/solver/expressions/CMakeLists.txt | 11 +- src/solver/modelParser/CMakeLists.txt | 27 + src/solver/modelParser/encoders.hxx | 167 ++++++ .../antares/solver/modelParser/model.h | 91 +++ .../antares/solver/modelParser/parser.h | 36 ++ src/solver/modelParser/parser.cpp | 38 ++ src/tests/src/libs/antares/CMakeLists.txt | 4 +- src/tests/src/solver/CMakeLists.txt | 9 +- .../src/solver/expressions/CMakeLists.txt | 4 +- .../src/solver/modelParser/CMakeLists.txt | 23 + .../solver/modelParser/testModelParser.cpp | 521 ++++++++++++++++++ src/vcpkg.json | 7 +- 14 files changed, 938 insertions(+), 33 deletions(-) create mode 100644 src/solver/modelParser/CMakeLists.txt create mode 100644 src/solver/modelParser/encoders.hxx create mode 100644 src/solver/modelParser/include/antares/solver/modelParser/model.h create mode 100644 src/solver/modelParser/include/antares/solver/modelParser/parser.h create mode 100644 src/solver/modelParser/parser.cpp create mode 100644 src/tests/src/solver/modelParser/CMakeLists.txt create mode 100644 src/tests/src/solver/modelParser/testModelParser.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 43358fa472..e93c5fcd58 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -186,9 +186,6 @@ message(STATUS "Build OR-Tools: ${BUILD_ORTOOLS}") option(WITH_ANTLR4 "With antlr4" OFF) message(STATUS "With antlr4: ${WITH_ANTLR4}") -option(WITH_YAMLCPP "With yaml-cpp" OFF) -message(STATUS "With yaml-cpp: ${WITH_YAMLCPP}") - option(BUILD_MERSENNE_TWISTER_PYBIND11 "Build pybind11 bindings for Mersenne-Twister" OFF) if (${BUILD_MERSENNE_TWISTER_PYBIND11}) find_package(pybind11 REQUIRED) diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 28b51b11bd..d579606350 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -9,19 +9,20 @@ endif (MSVC) add_subdirectory(application) add_subdirectory(constraints-builder) +add_subdirectory(expressions) add_subdirectory(hydro) add_subdirectory(infeasible-problem-analysis) +add_subdirectory(libModelObject) add_subdirectory(lps) add_subdirectory(misc) +add_subdirectory(modelParser) +add_subdirectory(modeler) add_subdirectory(optimisation) add_subdirectory(signal-handling) add_subdirectory(simulation) add_subdirectory(ts-generator) add_subdirectory(utils) add_subdirectory(variable) -add_subdirectory(modeler) -add_subdirectory(expressions) -add_subdirectory(libModelObject) # # Resource file for Windows @@ -56,25 +57,26 @@ add_library(solver-lib INTERFACE add_executable(antares-solver main.cpp ${SRCS} + modelParser/encoders.hxx ) set_target_properties(antares-solver PROPERTIES OUTPUT_NAME ${exec_name}) set(ANTARES_SOLVER_LIBS - Antares::args_helper - Antares::date - Antares::benchmarking - Antares::result_writer - Antares::sys - Antares::infoCollection - Antares::checks - Antares::misc + Antares::args_helper + Antares::date + Antares::benchmarking + Antares::result_writer + Antares::sys + Antares::infoCollection + Antares::checks + Antares::misc Antares::optimization-options Antares::signal-handling Antares::locale - yuni-static-uuid - yuni-static-core - ${CMAKE_THREADS_LIBS_INIT} + yuni-static-uuid + yuni-static-core + ${CMAKE_THREADS_LIBS_INIT} ) set(ANTARES_SOLVER_LIBS ${ANTARES_SOLVER_LIBS} diff --git a/src/solver/expressions/CMakeLists.txt b/src/solver/expressions/CMakeLists.txt index df56047769..5f30a6779d 100644 --- a/src/solver/expressions/CMakeLists.txt +++ b/src/solver/expressions/CMakeLists.txt @@ -68,26 +68,27 @@ set(SRC_Expressions ) source_group("expressions" FILES ${SRC_Expressions}) -add_library(antares-solver-expressions +add_library(solver-expressions ${SRC_Expressions}) +add_library(Antares::solver-expressions ALIAS solver-expressions) -target_include_directories(antares-solver-expressions +target_include_directories(solver-expressions PUBLIC $ ) -target_link_libraries(antares-solver-expressions +target_link_libraries(solver-expressions PUBLIC Antares::logs Boost::headers ) -add_library(antares-solver-expressions-iterators +add_library(solver-expressions-iterators iterators/pre-order.cpp include/antares/solver/expressions/iterators/pre-order.h ) -target_link_libraries(antares-solver-expressions-iterators PRIVATE antares-solver-expressions) +target_link_libraries(solver-expressions-iterators PRIVATE solver-expressions) install(DIRECTORY include/antares DESTINATION "include" diff --git a/src/solver/modelParser/CMakeLists.txt b/src/solver/modelParser/CMakeLists.txt new file mode 100644 index 0000000000..efc5baca38 --- /dev/null +++ b/src/solver/modelParser/CMakeLists.txt @@ -0,0 +1,27 @@ +find_package(yaml-cpp REQUIRED) + +set(SOURCES + parser.cpp + #encoders.hxx + include/antares/solver/modelParser/parser.h +) + +# Create the library +add_library(modelParser STATIC ${SOURCES}) +add_library(Antares::modelParser ALIAS modelParser) + +# Specify include directories +target_include_directories(modelParser + PUBLIC + $ +) + +# Link dependencies (if any) +target_link_libraries(modelParser + PRIVATE + yaml-cpp +) + +install(DIRECTORY include/antares + DESTINATION "include" +) \ No newline at end of file diff --git a/src/solver/modelParser/encoders.hxx b/src/solver/modelParser/encoders.hxx new file mode 100644 index 0000000000..61e22e9bc9 --- /dev/null +++ b/src/solver/modelParser/encoders.hxx @@ -0,0 +1,167 @@ + +/* + * 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 "antares/solver/modelParser/model.h" + +#include "yaml-cpp/yaml.h" + +// Implement convert specializations +namespace YAML +{ +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::ModelParser::Parameter& rhs) + { + if (!node.IsMap()) + { + return false; + } + rhs.name = node["name"].as(); + rhs.time_dependent = node["time-dependent"].as(); + rhs.scenario_dependent = node["scenario-dependent"].as(); + return true; + } +}; + +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::ModelParser::Variable& rhs) + { + if (!node.IsMap()) + { + return false; + } + rhs.name = node["name"].as(); + rhs.lower_bound = node["lower-bound"].as(); + rhs.upper_bound = node["upper-bound"].as(); + return true; + } +}; + +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::ModelParser::Port& rhs) + { + if (!node.IsMap()) + { + return false; + } + rhs.name = node["name"].as(); + rhs.type = node["type"].as(); + return true; + } +}; + +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::ModelParser::PortFieldDefinition& rhs) + { + if (!node.IsMap()) + { + return false; + } + rhs.port = node["port"].as(); + rhs.field = node["field"].as(); + rhs.definition = node["definition"].as(); + return true; + } +}; + +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::ModelParser::Constraint& rhs) + { + if (!node.IsMap()) + { + return false; + } + rhs.name = node["name"].as(); + rhs.expression = node["expression"].as(); + return true; + } +}; + +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::ModelParser::Model& rhs) + { + if (!node.IsMap()) + { + return false; + } + rhs.id = node["id"].as(); + rhs.description = node["description"].as(); + rhs.parameters = node["parameters"] + .as>(); + rhs.variables = node["variables"].as>(); + rhs.ports = node["ports"].as>(); + rhs.port_field_definitions = node["port-field-definitions"] + .as>(); + rhs.constraints = node["constraints"] + .as>(); + rhs.objective = node["objective"].as(); + return true; + } +}; + +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::ModelParser::PortType& rhs) + { + if (!node.IsMap()) + { + return false; + } + rhs.id = node["id"].as(); + rhs.description = node["description"].as(); + for (const auto& field: node["fields"]) + { + rhs.fields.push_back(field["name"].as()); + } + return true; + } +}; + +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::ModelParser::Library& rhs) + { + rhs.id = node["id"].as(); + rhs.description = node["description"].as(); + rhs.port_types = node["port-types"] + .as>(); + rhs.models = node["models"].as>(); + return true; + } +}; +} // namespace YAML diff --git a/src/solver/modelParser/include/antares/solver/modelParser/model.h b/src/solver/modelParser/include/antares/solver/modelParser/model.h new file mode 100644 index 0000000000..44b15584f5 --- /dev/null +++ b/src/solver/modelParser/include/antares/solver/modelParser/model.h @@ -0,0 +1,91 @@ + +/* + * 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::Solver::ModelParser +{ +// Define structures +struct Parameter +{ + std::string name; + bool time_dependent; + bool scenario_dependent; +}; + +struct Variable +{ + std::string name; + double lower_bound; + double upper_bound; +}; + +struct Port +{ + std::string name; + std::string type; +}; + +struct PortFieldDefinition +{ + std::string port; + std::string field; + std::string definition; +}; + +struct Constraint +{ + std::string name; + std::string expression; +}; + +struct Model +{ + std::string id; + std::string description; + std::vector parameters; + std::vector variables; + std::vector ports; + std::vector port_field_definitions; + std::vector constraints; + std::string objective; +}; + +struct PortType +{ + std::string id; + std::string description; + // Small optimization: we only need the name of the fields + // No need for an intermediate struct "field" with just a string "name" member + std::vector fields; +}; + +struct Library +{ + std::string id; + std::string description; + std::vector port_types; + std::vector models; +}; +} // namespace Antares::Solver::ModelParser diff --git a/src/solver/modelParser/include/antares/solver/modelParser/parser.h b/src/solver/modelParser/include/antares/solver/modelParser/parser.h new file mode 100644 index 0000000000..1447af9f2b --- /dev/null +++ b/src/solver/modelParser/include/antares/solver/modelParser/parser.h @@ -0,0 +1,36 @@ + +/* + * 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 "antares/solver/modelParser/model.h" + +namespace Antares::Solver::ModelParser +{ +class Parser +{ +public: + Parser() = default; + ~Parser() = default; + + Library parse(const std::string& content); +}; +} // namespace Antares::Solver::ModelParser diff --git a/src/solver/modelParser/parser.cpp b/src/solver/modelParser/parser.cpp new file mode 100644 index 0000000000..f4c1f9e515 --- /dev/null +++ b/src/solver/modelParser/parser.cpp @@ -0,0 +1,38 @@ +/* + * 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/modelParser/parser.h" + +#include "antares/solver/modelParser/model.h" + +#include "encoders.hxx" + +namespace Antares::Solver::ModelParser +{ +Library Parser::parse(const std::string& content) +{ + YAML::Node root = YAML::Load(content); + + Library library = root["library"].as(); + + return library; +} +} // namespace Antares::Solver::ModelParser diff --git a/src/tests/src/libs/antares/CMakeLists.txt b/src/tests/src/libs/antares/CMakeLists.txt index 875ff5e374..654f897b0a 100644 --- a/src/tests/src/libs/antares/CMakeLists.txt +++ b/src/tests/src/libs/antares/CMakeLists.txt @@ -4,9 +4,7 @@ add_subdirectory(study) add_subdirectory(benchmarking) add_subdirectory(inifile) -if(WITH_YAMLCPP) - add_subdirectory(yaml-parser) -endif() +add_subdirectory(yaml-parser) if(WITH_ANTLR4) add_subdirectory(antlr4-interface) diff --git a/src/tests/src/solver/CMakeLists.txt b/src/tests/src/solver/CMakeLists.txt index bf920cb80b..2152a8e1bf 100644 --- a/src/tests/src/solver/CMakeLists.txt +++ b/src/tests/src/solver/CMakeLists.txt @@ -1,7 +1,8 @@ -add_subdirectory(simulation) -add_subdirectory(optimisation) -add_subdirectory(utils) +add_subdirectory(expressions) add_subdirectory(infeasible-problem-analysis) add_subdirectory(lps) +add_subdirectory(modelParser) add_subdirectory(modeler) -add_subdirectory(expressions) +add_subdirectory(optimisation) +add_subdirectory(simulation) +add_subdirectory(utils) diff --git a/src/tests/src/solver/expressions/CMakeLists.txt b/src/tests/src/solver/expressions/CMakeLists.txt index 319e961a8d..4eeca6d0fe 100644 --- a/src/tests/src/solver/expressions/CMakeLists.txt +++ b/src/tests/src/solver/expressions/CMakeLists.txt @@ -19,8 +19,8 @@ target_sources(${EXECUTABLE_NAME} target_link_libraries(${EXECUTABLE_NAME} PRIVATE Boost::unit_test_framework - antares-solver-expressions - antares-solver-expressions-iterators + solver-expressions + solver-expressions-iterators ) # Storing tests-ts-numbers under the folder Unit-tests in the IDE diff --git a/src/tests/src/solver/modelParser/CMakeLists.txt b/src/tests/src/solver/modelParser/CMakeLists.txt new file mode 100644 index 0000000000..11123853b0 --- /dev/null +++ b/src/tests/src/solver/modelParser/CMakeLists.txt @@ -0,0 +1,23 @@ +# Add source files +set(SOURCE_FILES + testModelParser.cpp +) + +# Add executable +add_executable(TestModelParser ${SOURCE_FILES}) + +# Link libraries +target_link_libraries(TestModelParser + PRIVATE + Boost::unit_test_framework + Antares::modelParser +) + +# Storing test-toybox under the folder Unit-tests in the IDE +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) + +# Add the test +add_test(NAME TestModelParser COMMAND TestModelParser) + +# Set test properties +set_property(TEST TestModelParser PROPERTY LABELS unit) \ No newline at end of file diff --git a/src/tests/src/solver/modelParser/testModelParser.cpp b/src/tests/src/solver/modelParser/testModelParser.cpp new file mode 100644 index 0000000000..dff40144fb --- /dev/null +++ b/src/tests/src/solver/modelParser/testModelParser.cpp @@ -0,0 +1,521 @@ +/* + * 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 . + */ + +#define BOOST_TEST_MODULE modelParser + +#define WIN32_LEAN_AND_MEAN + +#include + +#include "antares/solver/modelParser/parser.h" + +using namespace std::string_literals; + +// Test empty library +BOOST_AUTO_TEST_CASE(test_empty_library) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "" + description: "" + port-types: [] + models: [] + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_CHECK(libraryObj.id.empty()); + BOOST_CHECK(libraryObj.description.empty()); + BOOST_CHECK(libraryObj.port_types.empty()); + BOOST_CHECK(libraryObj.models.empty()); +} + +// Test library with id and description +BOOST_AUTO_TEST_CASE(test_library_id_description) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "test_id" + description: "test_description" + port-types: [] + models: [] + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_CHECK_EQUAL(libraryObj.id, "test_id"); + BOOST_CHECK_EQUAL(libraryObj.description, "test_description"); + BOOST_CHECK(libraryObj.port_types.empty()); + BOOST_CHECK(libraryObj.models.empty()); +} + +// Test library with port types +BOOST_AUTO_TEST_CASE(test_library_port_types) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: + - id: "porttype_id" + description: "porttype_description" + fields: + - name: "port_name" + models: [] + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.port_types.size(), 1); + BOOST_CHECK_EQUAL(libraryObj.port_types[0].id, "porttype_id"); + BOOST_CHECK_EQUAL(libraryObj.port_types[0].description, "porttype_description"); + BOOST_REQUIRE_EQUAL(libraryObj.port_types[0].fields.size(), 1); + BOOST_CHECK_EQUAL(libraryObj.port_types[0].fields[0], "port_name"); +} + +// Test library with multiple port types +BOOST_AUTO_TEST_CASE(test_library_multiple_port_types) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: + - id: "porttype_id1" + description: "porttype_description1" + fields: + - name: "port_name1" + - id: "porttype_id2" + description: "porttype_description2" + fields: + - name: "port_name2" + models: [] + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.port_types.size(), 2); + BOOST_CHECK_EQUAL(libraryObj.port_types[0].id, "porttype_id1"); + BOOST_CHECK_EQUAL(libraryObj.port_types[0].description, "porttype_description1"); + BOOST_REQUIRE_EQUAL(libraryObj.port_types[0].fields.size(), 1); + BOOST_CHECK_EQUAL(libraryObj.port_types[0].fields[0], "port_name1"); + BOOST_CHECK_EQUAL(libraryObj.port_types[1].id, "porttype_id2"); + BOOST_CHECK_EQUAL(libraryObj.port_types[1].description, "porttype_description2"); + BOOST_REQUIRE_EQUAL(libraryObj.port_types[1].fields.size(), 1); + BOOST_CHECK_EQUAL(libraryObj.port_types[1].fields[0], "port_name2"); +} + +// Test library with models +BOOST_AUTO_TEST_CASE(test_library_models) +{ + Antares::Solver::ModelParser::Parser parser; + const std::string library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: [] + variables: [] + ports: [] + port-field-definitions: [] + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_CHECK_EQUAL(libraryObj.models[0].id, "model_id"); + BOOST_CHECK_EQUAL(libraryObj.models[0].description, "model_description"); + auto& model = libraryObj.models[0]; + BOOST_CHECK(model.parameters.empty()); + BOOST_CHECK(model.variables.empty()); + BOOST_CHECK(model.ports.empty()); + BOOST_CHECK(model.port_field_definitions.empty()); + BOOST_CHECK(model.constraints.empty()); + BOOST_CHECK_EQUAL(libraryObj.models[0].objective, "objective"); +} + +// Test library with multiple models +BOOST_AUTO_TEST_CASE(test_library_multiple_models) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id1" + description: "model_description1" + parameters: [] + variables: [] + ports: [] + port-field-definitions: [] + constraints: [] + objective: "objective1" + - id: "model_id2" + description: "model_description2" + parameters: [] + variables: [] + ports: [] + port-field-definitions: [] + constraints: [] + objective: "objective2" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 2); + BOOST_CHECK_EQUAL(libraryObj.models[0].id, "model_id1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].description, "model_description1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].objective, "objective1"); + BOOST_CHECK_EQUAL(libraryObj.models[1].id, "model_id2"); + BOOST_CHECK_EQUAL(libraryObj.models[1].description, "model_description2"); + BOOST_CHECK_EQUAL(libraryObj.models[1].objective, "objective2"); +} + +// Test library with one model containing parameters +BOOST_AUTO_TEST_CASE(test_library_model_parameters) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: + - name: "param_name" + time-dependent: false + scenario-dependent: false + variables: [] + ports: [] + port-field-definitions: [] + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_REQUIRE_EQUAL(libraryObj.models[0].parameters.size(), 1); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].name, "param_name"); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].time_dependent, false); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].scenario_dependent, false); +} + +// Test library with one model containing multiple parameters +BOOST_AUTO_TEST_CASE(test_library_model_multiple_parameters) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: + - name: "param_name1" + time-dependent: false + scenario-dependent: false + - name: "param_name2" + time-dependent: true + scenario-dependent: true + variables: [] + ports: [] + port-field-definitions: [] + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_REQUIRE_EQUAL(libraryObj.models[0].parameters.size(), 2); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].name, "param_name1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].time_dependent, false); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].scenario_dependent, false); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[1].name, "param_name2"); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[1].time_dependent, true); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[1].scenario_dependent, true); +} + +// Test library with one model containing variables +BOOST_AUTO_TEST_CASE(test_library_model_variables) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: [] + variables: + - name: "var_name" + lower-bound: 0 + upper-bound: 1 + ports: [] + port-field-definitions: [] + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_REQUIRE_EQUAL(libraryObj.models[0].variables.size(), 1); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].name, "var_name"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].lower_bound, 0); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].upper_bound, 1); +} + +// Test library with one model containing multiple variables +BOOST_AUTO_TEST_CASE(test_library_model_multiple_variables) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: [] + variables: + - name: "var_name1" + lower-bound: 0 + upper-bound: 1 + - name: "var_name2" + lower-bound: -1 + upper-bound: 2 + ports: [] + port-field-definitions: [] + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_REQUIRE_EQUAL(libraryObj.models[0].variables.size(), 2); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].name, "var_name1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].lower_bound, 0); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].upper_bound, 1); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[1].name, "var_name2"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[1].lower_bound, -1); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[1].upper_bound, 2); +} + +// Test library with one model containing ports +BOOST_AUTO_TEST_CASE(test_library_model_ports) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: [] + variables: [] + ports: + - name: "port_name" + type: "port_type" + port-field-definitions: [] + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_REQUIRE_EQUAL(libraryObj.models[0].ports.size(), 1); + BOOST_CHECK_EQUAL(libraryObj.models[0].ports[0].name, "port_name"); + BOOST_CHECK_EQUAL(libraryObj.models[0].ports[0].type, "port_type"); +} + +// Test library with one model containing multiple ports +BOOST_AUTO_TEST_CASE(test_library_model_multiple_ports) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: [] + variables: [] + ports: + - name: "port_name1" + type: "port_type1" + - name: "port_name2" + type: "port_type2" + port-field-definitions: [] + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_REQUIRE_EQUAL(libraryObj.models[0].ports.size(), 2); + BOOST_CHECK_EQUAL(libraryObj.models[0].ports[0].name, "port_name1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].ports[0].type, "port_type1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].ports[1].name, "port_name2"); + BOOST_CHECK_EQUAL(libraryObj.models[0].ports[1].type, "port_type2"); +} + +// Test library with one model containing port field definitions +BOOST_AUTO_TEST_CASE(test_library_model_port_field_definitions) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: [] + variables: [] + ports: [] + port-field-definitions: + - port: "port_name" + field: "field_name" + definition: "definition" + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_REQUIRE_EQUAL(libraryObj.models[0].port_field_definitions.size(), 1); + BOOST_CHECK_EQUAL(libraryObj.models[0].port_field_definitions[0].port, "port_name"); + BOOST_CHECK_EQUAL(libraryObj.models[0].port_field_definitions[0].field, "field_name"); + BOOST_CHECK_EQUAL(libraryObj.models[0].port_field_definitions[0].definition, "definition"); +} + +// Test library with one model containing multiple port field definitions +BOOST_AUTO_TEST_CASE(test_library_model_multiple_port_field_definitions) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: [] + variables: [] + ports: [] + port-field-definitions: + - port: "port_name1" + field: "field_name1" + definition: "definition1" + - port: "port_name2" + field: "field_name2" + definition: "definition2" + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_REQUIRE_EQUAL(libraryObj.models[0].port_field_definitions.size(), 2); + BOOST_CHECK_EQUAL(libraryObj.models[0].port_field_definitions[0].port, "port_name1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].port_field_definitions[0].field, "field_name1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].port_field_definitions[0].definition, "definition1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].port_field_definitions[1].port, "port_name2"); + BOOST_CHECK_EQUAL(libraryObj.models[0].port_field_definitions[1].field, "field_name2"); + BOOST_CHECK_EQUAL(libraryObj.models[0].port_field_definitions[1].definition, "definition2"); +} + +// Test library with one model containing constraints +BOOST_AUTO_TEST_CASE(test_library_model_constraints) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: [] + variables: [] + ports: [] + port-field-definitions: [] + constraints: + - name: "constraint_name" + expression: "expression" + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_REQUIRE_EQUAL(libraryObj.models[0].constraints.size(), 1); + BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[0].name, "constraint_name"); + BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[0].expression, "expression"); +} + +// Test library with one model containing multiple constraints +BOOST_AUTO_TEST_CASE(test_library_model_multiple_constraints) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: [] + variables: [] + ports: [] + port-field-definitions: [] + constraints: + - name: "constraint_name1" + expression: "expression1" + - name: "constraint_name2" + expression: "expression2" + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_REQUIRE_EQUAL(libraryObj.models[0].constraints.size(), 2); + BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[0].name, "constraint_name1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[0].expression, "expression1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[1].name, "constraint_name2"); + BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[1].expression, "expression2"); +} + +// Test error when model is not a map +BOOST_AUTO_TEST_CASE(test_error_model_not_map) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: "not a map" + )"s; + BOOST_CHECK_THROW(parser.parse(library), std::runtime_error); +} diff --git a/src/vcpkg.json b/src/vcpkg.json index 08acfb9e79..b87c13d7b3 100644 --- a/src/vcpkg.json +++ b/src/vcpkg.json @@ -12,8 +12,8 @@ }, "dependencies": [ { - "name": "sirius-solver", - "version>=": "1.5" + "name": "sirius-solver", + "version>=": "1.5" }, { "name": "wxwidgets", @@ -34,6 +34,9 @@ "features": [ "zlib" ] + }, + { + "name": "yaml-cpp" } ] } From 723f66581e7608374ce8e73253b2124fe7da2c50 Mon Sep 17 00:00:00 2001 From: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Date: Thu, 3 Oct 2024 09:45:46 +0200 Subject: [PATCH 025/103] Fix a crash occurring when first year not played (#2449) --- .../antares/solver/simulation/solver.hxx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/solver/simulation/include/antares/solver/simulation/solver.hxx b/src/solver/simulation/include/antares/solver/simulation/solver.hxx index c8ca4775df..6b948a4b9a 100644 --- a/src/solver/simulation/include/antares/solver/simulation/solver.hxx +++ b/src/solver/simulation/include/antares/solver/simulation/solver.hxx @@ -51,7 +51,7 @@ public: randomNumbers& pRandomForParallelYears, bool pPerformCalculations, Data::Study& pStudy, - Variable::State& pState, + std::vector& pStates, bool pYearByYear, Benchmarking::DurationCollector& durationCollector, IResultWriter& resultWriter, @@ -65,14 +65,13 @@ public: randomForParallelYears(pRandomForParallelYears), performCalculations(pPerformCalculations), study(pStudy), - state(pState), + states(pStates), yearByYear(pYearByYear), pDurationCollector(durationCollector), pResultWriter(resultWriter), simulationObserver_(simulationObserver), hydroManagement(study.areas, study.parameters, study.calendar, resultWriter) { - scratchmap = study.areas.buildScratchMap(numSpace); } yearJob(const yearJob&) = delete; @@ -89,13 +88,12 @@ private: randomNumbers& randomForParallelYears; bool performCalculations; Data::Study& study; - Variable::State& state; + std::vector& states; bool yearByYear; Benchmarking::DurationCollector& pDurationCollector; IResultWriter& pResultWriter; std::reference_wrapper simulationObserver_; HydroManagement hydroManagement; - Antares::Data::Area::ScratchMap scratchmap; private: /* @@ -147,17 +145,18 @@ public: // 1 - Applying random levels for current year auto randomReservoirLevel = randomForCurrentYear.pReservoirLevels; - // 2 - Preparing the Time-series numbers - // removed + // Getting the scratchMap associated to the current year + Antares::Data::Area::ScratchMap scratchmap = study.areas.buildScratchMap(numSpace); // 3 - Preparing data related to Clusters in 'must-run' mode simulation_->prepareClustersInMustRunMode(scratchmap, y); // 4 - Hydraulic ventilation - pDurationCollector("hydro_ventilation") << [this, &randomReservoirLevel] + pDurationCollector("hydro_ventilation") << [this, &scratchmap, &randomReservoirLevel] { hydroManagement.makeVentilation(randomReservoirLevel.data(), y, scratchmap); }; // Updating the state + auto& state = states[numSpace]; state.year = y; // 5 - Resetting all variables for the output @@ -1025,7 +1024,7 @@ void ISimulation::loopThroughYears(uint firstYear, randomForParallelYears, performCalculations, study, - state[numSpace], + state, pYearByYear, pDurationCollector, pResultWriter, From ad66898d7cf80bd24aa735b3b6ba4758020eb4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Thu, 3 Oct 2024 11:12:42 +0200 Subject: [PATCH 026/103] Use OR-Tools v9.11-rte1.1 [ANT-2069] (#2437) OR-Tools 9.11-rte1.1 fixes 2 bugs - Locale is changed unexpectedly - Generic/specific parameters for XPRESS --- ortools_tag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ortools_tag b/ortools_tag index 88446ca998..4121b49d4c 100644 --- a/ortools_tag +++ b/ortools_tag @@ -1 +1 @@ -v9.10-rte1.2 \ No newline at end of file +v9.11-rte1.1 \ No newline at end of file From da70910e896da4894c1e1fc53d82f0195628bd0a Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Fri, 4 Oct 2024 14:45:54 +0200 Subject: [PATCH 027/103] Cucumber: add short tests & refactor some steps (#2382) --- .../cucumber/features/medium_tests.feature | 2 +- .../cucumber/features/short_tests.feature | 110 ++++++++++++++++-- .../cucumber/features/steps/assertions.py | 3 +- .../cucumber/features/steps/context_utils.py | 22 ---- .../cucumber/features/steps/output_utils.py | 37 ------ .../features/steps/simulator_utils.py | 24 ++-- src/tests/cucumber/features/steps/steps.py | 108 +++++++++++++---- .../features/steps/study_input_handler.py | 32 ++++- .../features/steps/study_output_handler.py | 84 +++++++++++++ src/tests/cucumber/requirements.txt | 3 +- 10 files changed, 316 insertions(+), 109 deletions(-) delete mode 100644 src/tests/cucumber/features/steps/context_utils.py delete mode 100644 src/tests/cucumber/features/steps/output_utils.py create mode 100644 src/tests/cucumber/features/steps/study_output_handler.py diff --git a/src/tests/cucumber/features/medium_tests.feature b/src/tests/cucumber/features/medium_tests.feature index 98e8a6fb26..fd11932be4 100644 --- a/src/tests/cucumber/features/medium_tests.feature +++ b/src/tests/cucumber/features/medium_tests.feature @@ -4,7 +4,7 @@ Feature: medium tests Scenario: 035 Mixed Expansion - Smart grid model 2 Given the study path is "medium-tests/035 Mixed Expansion - Smart grid model 2" When I run antares simulator - Then the simulation takes less than 15 seconds + Then the simulation takes less than 30 seconds And the simulation succeeds And the expected value of the annual system cost is 3.725e+10 And the minimum annual system cost is 3.642e+10 diff --git a/src/tests/cucumber/features/short_tests.feature b/src/tests/cucumber/features/short_tests.feature index 8a1d65d6c7..cb6a9cebbc 100644 --- a/src/tests/cucumber/features/short_tests.feature +++ b/src/tests/cucumber/features/short_tests.feature @@ -6,9 +6,7 @@ Feature: short tests When I run antares simulator Then the simulation takes less than 5 seconds And the simulation succeeds - And the annual system cost is - | EXP | STD | MIN | MAX | - | 0 | 0 | 0 | 0 | + And the annual system cost is 0 @fast @short Scenario: 002 Thermal fleet - Base @@ -16,11 +14,9 @@ Feature: short tests When I run antares simulator Then the simulation takes less than 5 seconds And the simulation succeeds - And the annual system cost is - | EXP | STD | MIN | MAX | - | 2.729e+7 | 0 | 2.729e+7 | 2.729e+7 | + And the annual system cost is 2.729e+7 And in area "AREA", during year 1, loss of load lasts 1 hours - And in area "AREA", unsupplied energy on "02 JAN 09:00" of year 1 is of 52 MW + And in area "AREA", unsupplied energy on "2 JAN 09:00" of year 1 is of 52 MW @fast @short Scenario: 003 Thermal fleet - Must-run @@ -28,11 +24,103 @@ Feature: short tests When I run antares simulator Then the simulation takes less than 5 seconds And the simulation succeeds - And the annual system cost is - | EXP | STD | MIN | MAX | - | 2.751e+7 | 0 | 2.751e+7 | 2.751e+7 | + And the annual system cost is 2.751e+7 + And in area "AREA", during year 1, loss of load lasts 1 hours + And in area "AREA", unsupplied energy on "2 JAN 09:00" of year 1 is of 52 MW + And in area "AREA", during year 1, hourly production of "non-dispatchable semi base" is always equal to 300 MWh + + @fast @short + Scenario: 004 Thermal fleet - Partial must-run + Given the study path is "short-tests/004 Thermal fleet - Partial must-run" + When I run antares simulator + Then the simulation takes less than 5 seconds + And the simulation succeeds + And the annual system cost is 2.751e+7 + And in area "AREA", during year 1, loss of load lasts 1 hours + And in area "AREA", unsupplied energy on "2 JAN 09:00" of year 1 is of 52 MW + And in area "AREA", during year 1, hourly production of "semi base" is always greater than 300 MWh + + @fast @short + Scenario: 005 Thermal fleet - Minimum stable power and min up down times + Given the study path is "short-tests/005 Thermal fleet - Minimum stable power and min up down times" + When I run antares simulator + Then the simulation takes less than 5 seconds + And the simulation succeeds + And the annual system cost is 2.75816e+07 + And in area "AREA", the units of "base" produce between 400 and 900 MWh hourly + And in area "AREA", the units of "semi base" produce between 100 and 300 MWh hourly + And in area "AREA", the units of "peak" produce between 10 and 100 MWh hourly + # Ideally, we would also check min up & down durations in this test. But is not possible, since clusters defined + # in this test have a unitcount > 1 + # TODO : create similar tests with unitcount = 1, and implement the following steps: + # And in area "AREA", unit "base" respects a minimum up duration of 24 hours, and a minimum down duration of 24 hours + # And in area "AREA", unit "semi base" respects a minimum up duration of 6 hours, and a minimum down duration of 12 hours + # And in area "AREA", unit "peak" respects a minimum up duration of 2 hours, and a minimum down duration of 2 hours + + @fast @short + Scenario: 006 Thermal fleet - Extra costs + # Like previous test, but with extra non-proportional (NP) costs + # NP costs = 1756400 ; OP costs = 2.75816e+07 (like test 5) => Total cost = 2.9338e+07 + Given the study path is "short-tests/006 Thermal fleet - Extra costs" + When I run antares simulator + Then the simulation takes less than 5 seconds + And the simulation succeeds + And the annual system cost is 2.9338e+07 + And in area "AREA", during year 1, total non-proportional cost is 1756400 + And in area "AREA", the units of "base" produce between 400 and 900 MWh hourly + And in area "AREA", the units of "semi base" produce between 100 and 300 MWh hourly + And in area "AREA", the units of "peak" produce between 10 and 100 MWh hourly + # Ideally, we would also check min up & down durations in this test. But is not possible, since clusters defined + # in this test have a unitcount > 1 + # TODO : create similar tests with unitcount = 1, and implement the following steps: + # And in area "AREA", unit "base" respects a minimum up duration of 24 hours, and a minimum down duration of 24 hours + # And in area "AREA", unit "semi base" respects a minimum up duration of 6 hours, and a minimum down duration of 12 hours + # And in area "AREA", unit "peak" respects a minimum up duration of 2 hours, and a minimum down duration of 2 hours + + @fast @short + Scenario: 007 Thermal fleet - Fast unit commitment + # This example is the first of a set of two that are comparing the two unit-commitment modes of Antares. + # Fast mode + # => overall cost is not great, there are a lot of startups, and min up & down time are considered equal + Given the study path is "short-tests/007 Thermal fleet - Fast unit commitment" + When I run antares simulator + Then the simulation takes less than 5 seconds + And the simulation succeeds + And the annual system cost is 2.98912e+07 + And in area "AREA", during year 1, total non-proportional cost is 1861400 + And in area "AREA", the units of "base" produce between 400 and 900 MWh hourly + And in area "AREA", the units of "semi base" produce between 100 and 300 MWh hourly + And in area "AREA", the units of "peak" produce between 10 and 100 MWh hourly + And in area "AREA", during year 1, loss of load lasts 1 hours + And in area "AREA", unsupplied energy on "2 JAN 09:00" of year 1 is of 52 MW + # Ideally, we would also check min up & down durations in this test. But is not possible, since clusters defined + # in this test have a unitcount > 1 + # TODO : create similar tests with unitcount = 1, and implement the following steps: + # And in area "AREA", unit "base" respects a minimum up duration of 24 hours, and a minimum down duration of 24 hours + # And in area "AREA", unit "semi base" respects a minimum up duration of 12 hours, and a minimum down duration of 12 hours + # And in area "AREA", unit "peak" respects a minimum up duration of 2 hours, and a minimum down duration of 2 hours + + @fast @short + Scenario: 008 Thermal fleet - Accurate unit commitment + # Like previous test, but with unit commitment + # => overall cost is better, there are less startups, and min up & down time are not equal + Given the study path is "short-tests/008 Thermal fleet - Accurate unit commitment" + When I run antares simulator + Then the simulation takes less than 5 seconds + And the simulation succeeds + And the annual system cost is 2.97339e+07 + And in area "AREA", during year 1, total non-proportional cost is 1680900 + And in area "AREA", the units of "base" produce between 400 and 900 MWh hourly + And in area "AREA", the units of "semi base" produce between 100 and 300 MWh hourly + And in area "AREA", the units of "peak" produce between 10 and 100 MWh hourly And in area "AREA", during year 1, loss of load lasts 1 hours - And in area "AREA", unsupplied energy on "02 JAN 09:00" of year 1 is of 52 MW + And in area "AREA", unsupplied energy on "2 JAN 09:00" of year 1 is of 52 MW + # Ideally, we would also check min up & down durations in this test. But is not possible, since clusters defined + # in this test have a unitcount > 1 + # TODO : create similar tests with unitcount = 1, and implement the following steps: + # And in area "AREA", unit "base" respects a minimum up duration of 24 hours, and a minimum down duration of 24 hours + # And in area "AREA", unit "semi base" respects a minimum up duration of 6 hours, and a minimum down duration of 12 hours + # And in area "AREA", unit "peak" respects a minimum up duration of 2 hours, and a minimum down duration of 2 hours @fast @short Scenario: 021 Four areas - DC law diff --git a/src/tests/cucumber/features/steps/assertions.py b/src/tests/cucumber/features/steps/assertions.py index dda7d0232c..01ddb6ed99 100644 --- a/src/tests/cucumber/features/steps/assertions.py +++ b/src/tests/cucumber/features/steps/assertions.py @@ -1,4 +1,5 @@ # Custom assertions def assert_double_close(expected, actual, relative_tolerance): - assert abs((actual - expected) / max(1e-6, expected)) <= relative_tolerance \ No newline at end of file + assert abs((actual - expected) / max(1e-6, expected)) <= relative_tolerance, \ + f"Values are not close: expected = {expected} ; actual = {actual}" \ No newline at end of file diff --git a/src/tests/cucumber/features/steps/context_utils.py b/src/tests/cucumber/features/steps/context_utils.py deleted file mode 100644 index 5a7af9dfe3..0000000000 --- a/src/tests/cucumber/features/steps/context_utils.py +++ /dev/null @@ -1,22 +0,0 @@ -# Manage cached output data in "context" object - -from output_utils import * - -def get_annual_system_cost(context): - if context.annual_system_cost is None: - context.annual_system_cost = parse_annual_system_cost(context.output_path) - return context.annual_system_cost - -def get_hourly_values_for_specific_hour(context, area : str, year : int, date : str): - df = get_hourly_values(context, area, year) - day, month, hour = date.split(" ") - return df.loc[(df['Unnamed: 2'] == int(day)) & (df['Unnamed: 3'] == month) & (df['Unnamed: 4'] == hour)] - -def get_hourly_values(context, area : str, year : int): - if context.hourly_values is None: - context.hourly_values = {} - if area not in context.hourly_values: - context.hourly_values[area] = {} - if year not in context.hourly_values[area]: - context.hourly_values[area][year] = parse_hourly_values(context.output_path, area, year) - return context.hourly_values[area][year] \ No newline at end of file diff --git a/src/tests/cucumber/features/steps/output_utils.py b/src/tests/cucumber/features/steps/output_utils.py deleted file mode 100644 index 778a1d36b9..0000000000 --- a/src/tests/cucumber/features/steps/output_utils.py +++ /dev/null @@ -1,37 +0,0 @@ -# Antares outputs parsing - -import os -import pandas -import configparser - -def parse_output_folder_from_logs(logs: bytes) -> str: - for line in logs.splitlines(): - if b'Output folder : ' in line: - return line.split(b'Output folder : ')[1].decode('ascii') - raise LookupError("Could not parse output folder in output logs") - - -def parse_annual_system_cost(output_path: str) -> dict: - file = open(os.path.join(output_path, "annualSystemCost.txt"), 'r') - keys = ["EXP", "STD", "MIN", "MAX"] - annual_system_cost = {} - for line in file.readlines(): - for key in keys: - if key in line: - annual_system_cost[key] = float(line.split(key + " : ")[1]) - return annual_system_cost - - -def parse_simu_time(output_path: str) -> float: - execution_info = configparser.ConfigParser() - execution_info.read(os.path.join(output_path, "execution_info.ini")) - return float(execution_info['durations_ms']['total']) / 1000 - - -def parse_hourly_values(output_path: str, area: str, year: int): - return read_csv(os.path.join(output_path, "economy", "mc-ind", f"{year:05d}", "areas", area, "values-hourly.txt")) - - -def read_csv(file_name): - ignore_rows = [0, 1, 2, 3, 5, 6] - return pandas.read_csv(file_name, skiprows=ignore_rows, sep='\t', low_memory=False) \ No newline at end of file diff --git a/src/tests/cucumber/features/steps/simulator_utils.py b/src/tests/cucumber/features/steps/simulator_utils.py index 91da69a5ad..68f48df180 100644 --- a/src/tests/cucumber/features/steps/simulator_utils.py +++ b/src/tests/cucumber/features/steps/simulator_utils.py @@ -1,35 +1,37 @@ # Methods to run Antares simulator import subprocess -import glob import yaml from pathlib import Path from study_input_handler import study_input_handler -from output_utils import parse_output_folder_from_logs +from study_output_handler import study_output_handler def get_solver_path(): with open("conf.yaml") as file: - content = yaml.full_load(file) + content = yaml.full_load(file) return content.get("antares-solver") -SOLVER_PATH = get_solver_path() # we only need to run this once + +SOLVER_PATH = get_solver_path() # we only need to run this once def run_simulation(context): - activate_simu_outputs(context) # TODO : remove this and update studies instead + init_simu(context) command = build_antares_solver_command(context) print(f"Running command: {command}") process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) out, err = process.communicate() context.output_path = parse_output_folder_from_logs(out) context.return_code = process.returncode - context.annual_system_cost = None - context.hourly_values = None + context.soh = study_output_handler(context.output_path) -def activate_simu_outputs(context): +def init_simu(context): sih = study_input_handler(Path(context.study_path)) + # read metadata + context.nbyears = int(sih.get_value(variable="nbyears", file_nick_name="general")) + # activate year-by-year results # TODO : remove this and update studies instead sih.set_value(variable="synthesis", value="true", file_nick_name="general") sih.set_value(variable="year-by-year", value="true", file_nick_name="general") @@ -45,3 +47,9 @@ def build_antares_solver_command(context): command.append('--force-parallel=4') return command + +def parse_output_folder_from_logs(logs: bytes) -> str: + for line in logs.splitlines(): + if b'Output folder : ' in line: + return line.split(b'Output folder : ')[1].decode('ascii') + raise LookupError("Could not parse output folder in output logs") diff --git a/src/tests/cucumber/features/steps/steps.py b/src/tests/cucumber/features/steps/steps.py index f49bed8868..ef9ede4c2b 100644 --- a/src/tests/cucumber/features/steps/steps.py +++ b/src/tests/cucumber/features/steps/steps.py @@ -1,14 +1,18 @@ # Gherkins test steps definitions import os +import pathlib + from behave import * -from simulator_utils import * + from assertions import * -from context_utils import * +from simulator_utils import * + @given('the study path is "{string}"') def study_path_is(context, string): - context.study_path = os.path.join("..", "resources", "Antares_Simulator_Tests_NR" , string.replace("/", os.sep)) + context.study_path = os.path.join("..", "resources", "Antares_Simulator_Tests_NR", string.replace("/", os.sep)) + @when('I run antares simulator') def run_antares(context): @@ -18,50 +22,104 @@ def run_antares(context): context.parallel = False run_simulation(context) + +def after_feature(context, feature): + # post-processing a test: clean up output files to avoid taking up all the disk space + if (context.output_path != None): + pathlib.Path.rmdir(context.output_path) + + @then('the simulation succeeds') def simu_success(context): assert context.return_code == 0 + @then('the simulation fails') def simu_success(context): assert context.return_code != 0 -@then('the expected value of the annual system cost is {value}') + +@then('the expected value of the annual system cost is {value:g}') def check_annual_cost_expected(context, value): - assert_double_close(float(value), get_annual_system_cost(context)["EXP"], 0.001) + assert_double_close(value, context.soh.get_annual_system_cost()["EXP"], 0.001) -@then('the minimum annual system cost is {value}') + +@then('the minimum annual system cost is {value:g}') def check_annual_cost_min(context, value): - assert_double_close(float(value), get_annual_system_cost(context)["MIN"], 0.001) + assert_double_close(value, context.soh.get_annual_system_cost()["MIN"], 0.001) + -@then('the maximum annual system cost is {value}') +@then('the maximum annual system cost is {value:g}') def check_annual_cost_max(context, value): - assert_double_close(float(value), get_annual_system_cost(context)["MAX"], 0.001) + assert_double_close(value, context.soh.get_annual_system_cost()["MAX"], 0.001) + @then('the annual system cost is') def check_annual_cost(context): for row in context.table: - assert_double_close(float(row["EXP"]), get_annual_system_cost(context)["EXP"], 0.001) - assert_double_close(float(row["STD"]), get_annual_system_cost(context)["STD"], 0.001) - assert_double_close(float(row["MIN"]), get_annual_system_cost(context)["MIN"], 0.001) - assert_double_close(float(row["MAX"]), get_annual_system_cost(context)["MAX"], 0.001) + assert_double_close(float(row["EXP"]), context.soh.get_annual_system_cost()["EXP"], 0.001) + assert_double_close(float(row["STD"]), context.soh.get_annual_system_cost()["STD"], 0.001) + assert_double_close(float(row["MIN"]), context.soh.get_annual_system_cost()["MIN"], 0.001) + assert_double_close(float(row["MAX"]), context.soh.get_annual_system_cost()["MAX"], 0.001) + + +@then('the annual system cost is {one_year_value:g}') +def check_annual_cost(context, one_year_value): + assert_double_close(one_year_value, context.soh.get_annual_system_cost()["EXP"], 0.001) + assert_double_close(0, context.soh.get_annual_system_cost()["STD"], 0.001) + assert_double_close(one_year_value, context.soh.get_annual_system_cost()["MIN"], 0.001) + assert_double_close(one_year_value, context.soh.get_annual_system_cost()["MAX"], 0.001) + -@then('the simulation takes less than {seconds} seconds') +@then('the simulation takes less than {seconds:g} seconds') def check_simu_time(context, seconds): - actual_simu_time = parse_simu_time(context.output_path) - assert actual_simu_time <= float(seconds) + assert context.soh.get_simu_time() <= seconds -@then('in area "{area}", during year {year}, loss of load lasts {lold_hours} hours') + +@then('in area "{area}", during year {year:d}, loss of load lasts {lold_hours:d} hours') def check_lold_duration(context, area, year, lold_hours): - assert int(lold_hours) == get_hourly_values(context, area.lower(), int(year))["LOLD"].sum() + assert lold_hours == context.soh.get_loss_of_load_duration_h(area, year) + -@then('in area "{area}", unsupplied energy on "{date}" of year {year} is of {lold_value_mw} MW') +@then('in area "{area}", unsupplied energy on "{date}" of year {year:d} is of {lold_value_mw:g} MW') def check_lold_value(context, area, date, year, lold_value_mw): - actual_unsp_energ = get_hourly_values_for_specific_hour(context, area.lower(), int(year), date)["UNSP. ENRG"].sum() - assert_double_close(float(lold_value_mw), actual_unsp_energ, 0.001) + actual_unsp_energ = context.soh.get_unsupplied_energy_mwh(area, year, date) + assert_double_close(lold_value_mw, actual_unsp_energ, 0.001) + + +@then( + 'in area "{area}", during year {year:d}, hourly production of "{prod_name}" is always {comparator_and_hourly_prod} MWh') +def check_prod_for_specific_year(context, area, year, prod_name, comparator_and_hourly_prod): + expected_prod = float(comparator_and_hourly_prod.split(" ")[-1]) + actual_hourly_prod = context.soh.get_hourly_prod_mwh(area, year, prod_name) + if "greater than" in comparator_and_hourly_prod: + ok = actual_hourly_prod >= expected_prod + elif "equal to" in comparator_and_hourly_prod: + ok = actual_hourly_prod - expected_prod <= 1e-6 + else: + raise NotImplementedError(f"Unknown comparator '{comparator_and_hourly_prod}'") + if "zero or" in comparator_and_hourly_prod: + ok = ok | (actual_hourly_prod == 0) + assert ok.all() + + +@then('in area "{area}", hourly production of "{prod_name}" is always {comparator_and_hourly_prod} MWh') +def check_prod_for_all_years(context, area, prod_name, comparator_and_hourly_prod): + for year in range(1, context.nbyears + 1): + check_prod_for_specific_year(context, area, year, prod_name, comparator_and_hourly_prod) + + +@step('in area "{area}", during year {year:d}, total non-proportional cost is {np_cost:g}') +def check_np_cost_for_specific_year(context, area, year, np_cost): + assert_double_close(np_cost, context.soh.get_non_proportional_cost(area, year), 1e-6) -def after_feature(context, feature): - # post-processing a test: clean up output files to avoid taking up all the disk space - if (context.output_path != None): - pathlib.Path.rmdir(context.output_path) +@then('in area "{area}", the units of "{prod_name}" produce between {min_p:g} and {max_p:g} MWh hourly') +def check_pmin_pmax(context, area, prod_name, min_p, max_p): + for year in range(1, context.nbyears + 1): + actual_hourly_prod = context.soh.get_hourly_prod_mwh(area, year, prod_name) + actual_n_dispatched_units = context.soh.get_hourly_n_dispatched_units(area, year, prod_name) + assert (actual_hourly_prod <= actual_n_dispatched_units.apply( + lambda n: n * max_p)).all(), f"max_p constraint not respected during year {year}" + assert (actual_hourly_prod >= actual_n_dispatched_units.apply( + lambda n: n * min_p)).all(), f"min_p constraint not respected during year {year}" diff --git a/src/tests/cucumber/features/steps/study_input_handler.py b/src/tests/cucumber/features/steps/study_input_handler.py index 90f27d7221..b6f83bfe04 100644 --- a/src/tests/cucumber/features/steps/study_input_handler.py +++ b/src/tests/cucumber/features/steps/study_input_handler.py @@ -1,6 +1,3 @@ -# Currently used to activate simulation outputs -# TODO : remove this and update parameters in simulation input files - import os @@ -12,6 +9,35 @@ def __init__(self, study_root_directory): self.files_path["desktop"] = self.study_root_dir / "Desktop.ini" self.files_path["general"] = self.study_root_dir / "settings" / "generaldata.ini" self.files_path["study"] = self.study_root_dir / "study.antares" + self.files_path["thermal"] = self.study_root_dir / "study.antares" + + def get_value(self, variable, file_nick_name): + # File path + file = self.files_path[file_nick_name] + + # Reading the file content (content in) + with open(file) as f: + # Searching variable and setting its value in a tmp content + for line in f: + if line.strip().startswith(variable): + return line.split('=')[1].strip() + + def get_input(self, input_file, section, variable): + # File path + file = self.study_root_dir / "input" / input_file.replace("/", os.sep) + correct_section = False + # Reading the file content (content in) + with open(file) as f: + # Searching variable and setting its value in a tmp content + for line in f: + if line.startswith("["): + if f"[{section}]" in line: + correct_section = True + else: + correct_section = False + else: + if correct_section and line.strip().startswith(variable): + return line.split('=')[1].strip() def set_value(self, variable, value, file_nick_name): # File path diff --git a/src/tests/cucumber/features/steps/study_output_handler.py b/src/tests/cucumber/features/steps/study_output_handler.py new file mode 100644 index 0000000000..1c20e5bf08 --- /dev/null +++ b/src/tests/cucumber/features/steps/study_output_handler.py @@ -0,0 +1,84 @@ +# Antares outputs parsing + +import os +import pandas as pd +import configparser +from enum import Enum + + +class result_type(Enum): + VALUES = "values" + DETAILS = "details" + + +class study_output_handler: + + def __init__(self, study_output_path): + self.study_output_path = study_output_path + self.annual_system_cost = None + self.hourly_results = {result_type.VALUES: None, result_type.DETAILS: None} + + def get_annual_system_cost(self): + if self.annual_system_cost is None: + self.__parse_annual_system_cost() + return self.annual_system_cost + + def __parse_annual_system_cost(self): + file = open(os.path.join(self.study_output_path, "annualSystemCost.txt"), 'r') + keys = ["EXP", "STD", "MIN", "MAX"] + annual_system_cost = {} + for line in file.readlines(): + for key in keys: + if key in line: + annual_system_cost[key] = float(line.split(key + " : ")[1]) + self.annual_system_cost = annual_system_cost + + def get_simu_time(self) -> float: + execution_info = configparser.ConfigParser() + execution_info.read(os.path.join(self.study_output_path, "execution_info.ini")) + return float(execution_info['durations_ms']['total']) / 1000 + + def __read_csv(self, file_name) -> pd.DataFrame: + ignore_rows = [0, 1, 2, 3, 6] + absolute_path = os.path.join(self.study_output_path, file_name.replace("/", os.sep)) + return pd.read_csv(absolute_path, header=[0, 1], skiprows=ignore_rows, sep='\t', low_memory=False) + + def __if_none_then_parse(self, rs: result_type, area, year, file_name: str): + if self.hourly_results[rs] is None: + self.hourly_results[rs] = {} + if area not in self.hourly_results[rs]: + self.hourly_results[rs][area] = {} + if year not in self.hourly_results[rs][area]: + # parse file + self.hourly_results[rs][area][year] = self.__read_csv( + f"economy/mc-ind/{year:05d}/areas/{area}/{file_name}") + # add datetime column by concatenating unnamed columns 2 (day), 3 (month), 4 (hour) + cols = ['Unnamed: 2_level_0', 'Unnamed: 3_level_0', 'Unnamed: 4_level_0'] + self.hourly_results[rs][area][year]["datetime"] = self.hourly_results[rs][area][year][cols].apply( + lambda row: ' '.join(row.values.astype(str)), axis=1) + return self.hourly_results[rs][area][year] + + def __get_values_hourly(self, area: str, year: int): + return self.__if_none_then_parse(result_type.VALUES, area.lower(), year, "values-hourly.txt") + + def __get_values_hourly_for_specific_hour(self, area: str, year: int, datetime: str): + df = self.__get_values_hourly(area, year) + return df.loc[df['datetime'] == datetime] + + def __get_details_hourly(self, area: str, year: int): + return self.__if_none_then_parse(result_type.DETAILS, area.lower(), year, "details-hourly.txt") + + def get_hourly_prod_mwh(self, area: str, year: int, prod_name: str) -> pd.Series: + return self.__get_details_hourly(area, year)[prod_name]['MWh'] + + def get_hourly_n_dispatched_units(self, area: str, year: int, prod_name: str) -> pd.Series: + return self.__get_details_hourly(area, year)[prod_name]['NODU'] + + def get_loss_of_load_duration_h(self, area: str, year: int) -> int: + return self.__get_values_hourly(area, year)["LOLD"]["Hours"].sum() + + def get_unsupplied_energy_mwh(self, area: str, year: int, date: str) -> float: + return self.__get_values_hourly_for_specific_hour(area, year, date)["UNSP. ENRG"]["MWh"].sum() + + def get_non_proportional_cost(self, area: str, year: int) -> float: + return self.__get_values_hourly(area, year)["NP COST"]["Euro"].sum() diff --git a/src/tests/cucumber/requirements.txt b/src/tests/cucumber/requirements.txt index fd5e363e68..2e68e9859a 100644 --- a/src/tests/cucumber/requirements.txt +++ b/src/tests/cucumber/requirements.txt @@ -1,2 +1,3 @@ behave -pyyaml \ No newline at end of file +pyyaml +pandas \ No newline at end of file From dbae58451b387d5ddb4f1aaab2ee7a086f302174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 7 Oct 2024 11:04:56 +0200 Subject: [PATCH 028/103] Update .gitignore (#2439) Add new files to ignore, remove obsolete entries (licence, etc.). --- .gitignore | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 1a35b988bf..5351e0931d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ - -antares-[0-9].[0-9]-* - .*.sw[a-z] *~ Makefile @@ -21,7 +18,11 @@ Makefile *.layout src/.vs +# Config src/config/include/antares/config/config.h +config.h +src/tests/cucumber/conf.yaml + # Yuni src/ext/yuni/src/ProfileBuild.cmake @@ -49,13 +50,7 @@ src/distrib/unix/rpm/pkginfo-* src/distrib/unix/rpm/*.rpm src/distrib/changelog.txt -src/license/keys/rsakey2code -src/script/v8/libs/* -/src/antares.VC.VC.opendb -/src/antares.VC.db - _build* -buildDebian .vscode/ *.dll .idea/ From 39b5c29a9c01c344f2898acd77684f68dcdb2a2a Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Mon, 7 Oct 2024 15:39:26 +0200 Subject: [PATCH 029/103] Using filesystem path [ANT-1999] (#2435) --- src/api/API.cpp | 2 +- .../series/include/antares/series/series.h | 2 +- src/libs/antares/series/series.cpp | 4 +- src/libs/antares/study/area/links.cpp | 4 +- src/libs/antares/study/area/list.cpp | 123 +++++++++--------- .../antares/study/cleaner/cleaner-v20.cpp | 4 +- src/libs/antares/study/header.cpp | 2 +- .../study/include/antares/study/area/area.h | 2 +- .../study/include/antares/study/header.h | 2 +- .../antares/study/parts/common/cluster.h | 2 +- .../antares/study/parts/common/cluster_list.h | 2 +- .../antares/study/parts/hydro/series.h | 6 +- .../study/parts/short-term-storage/cluster.h | 3 +- .../parts/short-term-storage/container.h | 2 +- .../study/parts/short-term-storage/series.h | 6 +- .../study/parts/thermal/cluster_list.h | 7 +- .../antares/study/parts/thermal/ecoInput.h | 2 +- .../study/include/antares/study/study.h | 24 ++-- src/libs/antares/study/load.cpp | 10 +- .../antares/study/parts/common/cluster.cpp | 11 +- .../study/parts/common/cluster_list.cpp | 2 +- src/libs/antares/study/parts/hydro/series.cpp | 8 +- .../parts/short-term-storage/cluster.cpp | 2 +- .../parts/short-term-storage/container.cpp | 7 +- .../study/parts/short-term-storage/series.cpp | 22 ++-- .../study/parts/thermal/cluster_list.cpp | 33 ++--- .../antares/study/parts/thermal/ecoInput.cpp | 6 +- src/libs/antares/study/save.cpp | 20 +-- src/libs/antares/study/study.cpp | 56 ++++---- src/libs/antares/study/study.extra.cpp | 5 +- .../utils/include/antares/utils/utils.h | 3 +- src/libs/antares/utils/utils.cpp | 13 +- .../antares/writer/immediate_file_writer.cpp | 2 +- .../include/antares/writer/writer_factory.h | 5 +- .../writer/private/immediate_file_writer.h | 5 +- src/libs/antares/writer/private/zip_writer.h | 6 +- src/libs/antares/writer/writer_factory.cpp | 7 +- src/libs/antares/writer/zip_writer.cpp | 18 ++- src/solver/application/application.cpp | 2 +- src/solver/constraints-builder/cbuilder.cpp | 2 +- .../antares/solver/simulation/solver.hxx | 4 +- .../antares/solver/ts-generator/prepro.h | 2 +- src/solver/ts-generator/prepro.cpp | 9 +- src/solver/ts-generator/xcast/xcast.cpp | 1 - .../antares/study/output-folder/study.cpp | 88 ++++++------- src/tools/ts-generator/linksTSgenerator.cpp | 3 +- src/tools/ts-generator/main.cpp | 2 +- src/tools/vacuum/antares-study.cpp | 2 +- src/ui/simulator/application/main/main.cpp | 2 +- src/ui/simulator/application/main/menu.cpp | 4 +- src/ui/simulator/application/study.cpp | 23 ++-- .../toolbox/components/mainpanel.cpp | 2 +- .../handler/com.rte-france.antares.study.cpp | 2 +- .../simulator/windows/analyzer/analyzer.cpp | 6 +- src/ui/simulator/windows/exportmap.cpp | 7 +- .../memorystatistics/memorystatistics.cpp | 4 +- src/ui/simulator/windows/saveas.cpp | 2 +- 57 files changed, 312 insertions(+), 295 deletions(-) diff --git a/src/api/API.cpp b/src/api/API.cpp index 3580f34752..c1ba723925 100644 --- a/src/api/API.cpp +++ b/src/api/API.cpp @@ -88,7 +88,7 @@ SimulationResults APIInternal::execute() const // Importing Time-Series if asked study_->importTimeseriesIntoInput(); - return {.simulationPath = study_->folderOutput.c_str(), + return {.simulationPath = study_->folderOutput, .antares_problems = simulationObserver.acquireLps(), .error{}}; } diff --git a/src/libs/antares/series/include/antares/series/series.h b/src/libs/antares/series/include/antares/series/series.h index 939b25e40d..f762e710fa 100644 --- a/src/libs/antares/series/include/antares/series/series.h +++ b/src/libs/antares/series/include/antares/series/series.h @@ -74,7 +74,7 @@ class TimeSeries ** \param average used to average timeseries ** \return A non-zero value if the operation succeeded, 0 otherwise */ - bool loadFromFile(const std::string& path, const bool average); + bool loadFromFile(const std::filesystem::path& path, const bool average); /*! ** \brief Save time series to a file ** diff --git a/src/libs/antares/series/series.cpp b/src/libs/antares/series/series.cpp index 03894a9c50..4c0cca690e 100644 --- a/src/libs/antares/series/series.cpp +++ b/src/libs/antares/series/series.cpp @@ -115,11 +115,11 @@ TimeSeries::TimeSeries(TimeSeriesNumbers& tsNumbers): { } -bool TimeSeries::loadFromFile(const std::string& path, const bool average) +bool TimeSeries::loadFromFile(const std::filesystem::path& path, const bool average) { bool ret = true; Matrix<>::BufferType dataBuffer; - ret = timeSeries.loadFromCSVFile(path, 1, HOURS_PER_YEAR, &dataBuffer) && ret; + ret = timeSeries.loadFromCSVFile(path.string(), 1, HOURS_PER_YEAR, &dataBuffer) && ret; if (average) { diff --git a/src/libs/antares/study/area/links.cpp b/src/libs/antares/study/area/links.cpp index f7b722da49..97668638e0 100644 --- a/src/libs/antares/study/area/links.cpp +++ b/src/libs/antares/study/area/links.cpp @@ -125,11 +125,11 @@ bool AreaLink::linkLoadTimeSeries_for_version_820_and_later(const AnyString& fol // Read link's direct capacities time series filename.clear() << capacitiesFolder << SEP << with->id << "_direct.txt"; - success = directCapacities.loadFromFile(filename, false) && success; + success = directCapacities.loadFromFile(filename.c_str(), false) && success; // Read link's indirect capacities time series filename.clear() << capacitiesFolder << SEP << with->id << "_indirect.txt"; - success = indirectCapacities.loadFromFile(filename, false) && success; + success = indirectCapacities.loadFromFile(filename.c_str(), false) && success; return success; } diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index cee20dc5d5..0f95023f33 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -535,7 +535,7 @@ Area* AreaListAddFromNames(AreaList& list, const AnyString& name, const AnyStrin return nullptr; } -bool AreaList::loadListFromFile(const AnyString& filename) +bool AreaList::loadListFromFile(const fs::path& filename) { std::ifstream file(filename); if (!file.is_open()) @@ -833,8 +833,12 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, const auto studyVersion = study.header.version; // DSM, Reserves, D-1 - buffer.clear() << study.folderInput << SEP << "reserves" << SEP << area.id << ".txt"; - ret = area.reserves.loadFromCSVFile(buffer, fhrMax, HOURS_PER_YEAR, Matrix<>::optFixedSize) + fs::path reservesPath = (study.folderInput / "reserves" / area.id.to()) + .replace_extension("txt"); + ret = area.reserves.loadFromCSVFile(reservesPath.string(), + fhrMax, + HOURS_PER_YEAR, + Matrix<>::optFixedSize) && ret; // Optimzation preferences @@ -855,9 +859,13 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, } // Fatal hors hydro - Misc Gen. - buffer.clear() << study.folderInput << SEP << "misc-gen" << SEP << "miscgen-" << area.id - << ".txt"; - ret = area.miscGen.loadFromCSVFile(buffer, fhhMax, HOURS_PER_YEAR, Matrix<>::optFixedSize) + std::string miscgenName = "miscgen-" + area.id + ".txt"; + fs::path miscgenPath = study.folderInput / "misc-gen" / miscgenName; + + ret = area.miscGen.loadFromCSVFile(miscgenPath.string(), + fhhMax, + HOURS_PER_YEAR, + Matrix<>::optFixedSize) && ret; // Check misc gen @@ -868,11 +876,11 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, // Links { - fs::path folder = fs::path(study.folderInput.c_str()) / "links" / area.id.c_str(); + fs::path folder = study.folderInput / "links" / area.id.c_str(); ret = AreaLinksLoadFromFolder(study, list, &area, folder) && ret; } - // UI + // TODO remove with GUI if (JIT::usedFromGUI) { if (!area.ui) @@ -890,15 +898,15 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, if (area.load.prepro) // Prepro { // if changes are required, please update reloadXCastData() - buffer.clear() << study.folderInput << SEP << "load" << SEP << "prepro" << SEP - << area.id; - ret = area.load.prepro->loadFromFolder(buffer) && ret; + fs::path loadPath = study.folderInput / "load" / "prepro" / area.id.to(); + ret = area.load.prepro->loadFromFolder(loadPath.string()) && ret; } if (!options.loadOnlyNeeded || !area.load.prepro) // Series { - buffer.clear() << study.folderInput << SEP << "load" << SEP << "series" << SEP - << "load_" << area.id << ".txt"; - ret = area.load.series.loadFromFile(buffer.c_str(), averageTs) && ret; + std::string loadId = "load_" + area.id + ".txt"; + fs::path loadSeriesPath = study.folderInput / "load" / "series" / loadId; + + ret = area.load.series.loadFromFile(loadSeriesPath, averageTs) && ret; } } @@ -907,52 +915,50 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, if (area.solar.prepro) // Prepro { // if changes are required, please update reloadXCastData() - buffer.clear() << study.folderInput << SEP << "solar" << SEP << "prepro" << SEP - << area.id; - ret = area.solar.prepro->loadFromFolder(buffer) && ret; + fs::path solarPath = study.folderInput / "solar" / "prepro" / area.id.to(); + ret = area.solar.prepro->loadFromFolder(solarPath.string()) && ret; } if (!options.loadOnlyNeeded || !area.solar.prepro) // Series { - buffer.clear() << study.folderInput << SEP << "solar" << SEP << "series" << SEP - << "solar_" << area.id << ".txt"; - ret = area.solar.series.loadFromFile(buffer.c_str(), averageTs) && ret; + std::string solarId = "solar_" + area.id + ".txt"; + fs::path solarPath = study.folderInput / "solar" / "series" / solarId; + ret = area.solar.series.loadFromFile(solarPath, averageTs) && ret; } } // Hydro { // Allocation - buffer.clear() << study.folderInput << SEP << "hydro" << SEP << "allocation" << SEP - << area.id << ".ini"; - ret = area.hydro.allocation.loadFromFile(area.id, buffer.c_str()) && ret; + std::string areaIdIni = area.id + ".ini"; + fs::path hydroAlloc = study.folderInput / "hydro" / "allocation" / areaIdIni; + ret = area.hydro.allocation.loadFromFile(area.id, hydroAlloc) && ret; + + fs::path pathHydro = study.folderInput / "hydro"; + fs::path hydroSeries = pathHydro / "series"; if (area.hydro.prepro) /* Hydro */ { // if changes are required, please update reloadXCastData() - buffer.clear() << study.folderInput << SEP << "hydro" << SEP << "prepro"; - ret = area.hydro.prepro->loadFromFolder(study, area.id, buffer.c_str()) && ret; + fs::path hydroPrepro = pathHydro / "prepro"; + ret = area.hydro.prepro->loadFromFolder(study, area.id, hydroPrepro.string()) && ret; ret = area.hydro.prepro->validate(area.id) && ret; } if (!options.loadOnlyNeeded || !area.hydro.prepro) // Series { - buffer.clear() << study.folderInput << SEP << "hydro" << SEP << "series"; - ret = area.hydro.series->loadGenerationTS(area.id, buffer, studyVersion) && ret; + ret = area.hydro.series->loadGenerationTS(area.id, hydroSeries, studyVersion) && ret; } if (studyVersion < StudyVersion(9, 1)) { - buffer.clear() << study.folderInput << SEP << "hydro"; - HydroMaxTimeSeriesReader reader(area.hydro, area.id.to(), area.name.to()); - ret = reader.read(buffer, study.usedByTheSolver) && ret; + ret = reader.read(pathHydro.string(), study.usedByTheSolver) && ret; } else { - buffer.clear() << study.folderInput << SEP << "hydro" << SEP << "series"; - ret = area.hydro.series->LoadMaxPower(area.id, buffer) && ret; + ret = area.hydro.series->LoadMaxPower(area.id, hydroSeries) && ret; } area.hydro.series->resizeTSinDeratedMode(study.parameters.derated, @@ -965,26 +971,25 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, if (area.wind.prepro) // Prepro { // if changes are required, please update reloadXCastData() - buffer.clear() << study.folderInput << SEP << "wind" << SEP << "prepro" << SEP - << area.id; - ret = area.wind.prepro->loadFromFolder(buffer) && ret; + fs::path windPath = study.folderInput / "wind" / "prepro" / area.id.to(); + ret = area.wind.prepro->loadFromFolder(windPath.string()) && ret; } if (!options.loadOnlyNeeded || !area.wind.prepro) // Series { - buffer.clear() << study.folderInput << SEP << "wind" << SEP << "series" << SEP - << "wind_" << area.id << ".txt"; - ret = area.wind.series.loadFromFile(buffer.c_str(), averageTs) && ret; + std::string windId = "wind_" + area.id + ".txt"; + fs::path windPath = study.folderInput / "wind" / "series" / windId; + ret = area.wind.series.loadFromFile(windPath, averageTs) && ret; } } // Thermal cluster list { - buffer.clear() << study.folderInput << SEP << "thermal" << SEP << "prepro"; - ret = area.thermal.list.loadPreproFromFolder(study, buffer) && ret; + fs::path preproPath = study.folderInput / "thermal" / "prepro"; + ret = area.thermal.list.loadPreproFromFolder(study, preproPath) && ret; ret = area.thermal.list.validatePrepro(study) && ret; - buffer.clear() << study.folderInput << SEP << "thermal" << SEP << "series"; - ret = area.thermal.list.loadDataSeriesFromFolder(study, buffer) && ret; - ret = area.thermal.list.loadEconomicCosts(study, buffer) && ret; + fs::path seriesPath = study.folderInput / "thermal" / "series"; + ret = area.thermal.list.loadDataSeriesFromFolder(study, seriesPath) && ret; + ret = area.thermal.list.loadEconomicCosts(study, seriesPath) && ret; // In adequacy mode, all thermal clusters must be in 'mustrun' mode if (study.usedByTheSolver && study.parameters.mode == SimulationMode::Adequacy) @@ -996,34 +1001,35 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, // Short term storage if (studyVersion >= StudyVersion(8, 6)) { - buffer.clear() << study.folderInput << SEP << "st-storage" << SEP << "series" << SEP - << area.id; + fs::path seriesPath = study.folderInput / "st-storage" / "series" + / area.id.to(); - ret = area.shortTermStorage.loadSeriesFromFolder(buffer.c_str()) && ret; + ret = area.shortTermStorage.loadSeriesFromFolder(seriesPath) && ret; ret = area.shortTermStorage.validate() && ret; } // Renewable cluster list if (studyVersion >= StudyVersion(8, 1)) { - buffer.clear() << study.folderInput << SEP << "renewables" << SEP << "series"; - ret = area.renewable.list.loadDataSeriesFromFolder(study, buffer) && ret; + fs::path seriesPath = study.folderInput / "renewables" / "series"; + ret = area.renewable.list.loadDataSeriesFromFolder(study, seriesPath) && ret; } // Adequacy patch readAdqPatchMode(study, area, buffer); // Nodal Optimization - buffer.clear() << study.folderInput << SEP << "areas" << SEP << area.id << SEP - << "optimization.ini"; + fs::path nodalPath = study.folderInput / "areas" / area.id.to() + / "optimization.ini"; + IniFile ini; - if (!ini.open(buffer)) + if (!ini.open(nodalPath)) { return false; } ini.each( - [&area, &buffer](const IniFile::Section& section) + [&area, &nodalPath](const IniFile::Section& section) { for (auto* p = section.firstProperty; p; p = p->next) { @@ -1084,7 +1090,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, continue; } - logs.warning() << buffer << ": Unknown property '" << p->key << "'"; + logs.warning() << nodalPath << ": Unknown property '" << p->key << "'"; } }); @@ -1139,16 +1145,15 @@ bool AreaList::loadFromFolder(const StudyLoadOptions& options) // Load the list of all available areas { logs.info() << "Loading the list of areas..."; - buffer.clear() << pStudy.folderInput << SEP << "areas" << SEP << "list." - << pStudy.inputExtension; - ret = loadListFromFile(buffer) && ret; + fs::path areaListPath = pStudy.folderInput / "areas" / "list.txt"; + ret = loadListFromFile(areaListPath) && ret; } // Hydro { logs.info() << "Loading global hydro data..."; - buffer.clear() << pStudy.folderInput << SEP << "hydro"; - ret = PartHydro::LoadFromFolder(pStudy, buffer) && ret; + fs::path hydroPath = pStudy.folderInput / "hydro"; + ret = PartHydro::LoadFromFolder(pStudy, hydroPath.string()) && ret; ret = PartHydro::validate(pStudy) && ret; } @@ -1178,7 +1183,7 @@ bool AreaList::loadFromFolder(const StudyLoadOptions& options) if (studyVersion >= StudyVersion(8, 6)) { logs.info() << "Loading short term storage clusters..."; - fs::path stsFolder = fs::path(pStudy.folderInput.c_str()) / "st-storage"; + fs::path stsFolder = pStudy.folderInput / "st-storage"; if (fs::exists(stsFolder)) { diff --git a/src/libs/antares/study/cleaner/cleaner-v20.cpp b/src/libs/antares/study/cleaner/cleaner-v20.cpp index f2fa71b17d..a76d2e2264 100644 --- a/src/libs/antares/study/cleaner/cleaner-v20.cpp +++ b/src/libs/antares/study/cleaner/cleaner-v20.cpp @@ -232,7 +232,7 @@ void listOfFilesAnDirectoriesToKeepForLinks(PathList& p, const Area* area, Strin bool listOfFilesAnDirectoriesToKeep(StudyCleaningInfos* infos) { auto* study = new Study(); - study->relocate(infos->folder); + study->relocate(infos->folder.c_str()); PathList& e = infos->exclude; PathList& p = infos->postExclude; @@ -315,7 +315,7 @@ bool listOfFilesAnDirectoriesToKeep(StudyCleaningInfos* infos) logs.info() << " :: analyzing the study data"; logs.verbosityLevel = Logs::Verbosity::Warning::level; - if (arealist->loadListFromFile(buffer)) + if (arealist->loadListFromFile(buffer.c_str())) { // restoring standard verbosity level logs.verbosityLevel = Logs::Verbosity::Debug::level; diff --git a/src/libs/antares/study/header.cpp b/src/libs/antares/study/header.cpp index ae44e94ad5..01eb552d08 100644 --- a/src/libs/antares/study/header.cpp +++ b/src/libs/antares/study/header.cpp @@ -179,7 +179,7 @@ bool StudyHeader::internalLoadFromINIFile(const IniFile& ini, bool warnings) return false; } -bool StudyHeader::loadFromFile(const AnyString& filename, bool warnings) +bool StudyHeader::loadFromFile(const fs::path& filename, bool warnings) { // (Re)Initialize the internal settings reset(); diff --git a/src/libs/antares/study/include/antares/study/area/area.h b/src/libs/antares/study/include/antares/study/area/area.h index 7550d9840f..fea12cea10 100644 --- a/src/libs/antares/study/include/antares/study/area/area.h +++ b/src/libs/antares/study/include/antares/study/area/area.h @@ -456,7 +456,7 @@ class AreaList final: public Yuni::NonCopyable ** \param filename The file to read ** \return A non-zero value if the operation was successful, 0 otherwise */ - bool loadListFromFile(const AnyString& filename); + bool loadListFromFile(const std::filesystem::path& filename); /*! ** \brief Save all informations about areas into a folder (-> input/generalData) diff --git a/src/libs/antares/study/include/antares/study/header.h b/src/libs/antares/study/include/antares/study/header.h index aea7e0f35c..d4448466ea 100644 --- a/src/libs/antares/study/include/antares/study/header.h +++ b/src/libs/antares/study/include/antares/study/header.h @@ -83,7 +83,7 @@ class StudyHeader final ** \param warnings Enable warnings/errors ** \return True if the operation succeeded, false otherwise */ - bool loadFromFile(const AnyString& filename, bool warnings = true); + bool loadFromFile(const std::filesystem::path& filename, bool warnings = true); /*! ** \brief Save a study header into a file diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster.h b/src/libs/antares/study/include/antares/study/parts/common/cluster.h index 53e5d115d6..644e4f3296 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster.h @@ -105,7 +105,7 @@ class Cluster virtual void reset(); bool saveDataSeriesToFolder(const AnyString& folder) const; - bool loadDataSeriesFromFolder(Study& s, const AnyString& folder); + bool loadDataSeriesFromFolder(Study& s, const std::filesystem::path& folder); uint unitCount = 0; diff --git a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h index 8c06990ddd..a1e4136cf9 100644 --- a/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/common/cluster_list.h @@ -132,7 +132,7 @@ class ClusterList /// \name IO functions /// @{ - bool loadDataSeriesFromFolder(Study& study, const AnyString& folder); + bool loadDataSeriesFromFolder(Study& study, const std::filesystem::path& folder); bool saveDataSeriesToFolder(const AnyString& folder) const; diff --git a/src/libs/antares/study/include/antares/study/parts/hydro/series.h b/src/libs/antares/study/include/antares/study/parts/hydro/series.h index 431f14905c..343e49e266 100644 --- a/src/libs/antares/study/include/antares/study/parts/hydro/series.h +++ b/src/libs/antares/study/include/antares/study/parts/hydro/series.h @@ -71,10 +71,12 @@ class DataSeriesHydro // Loading hydro time series collection // Returned boolean : reading from file failed - bool loadGenerationTS(const AreaName& areaID, const AnyString& folder, StudyVersion version); + bool loadGenerationTS(const AreaName& areaID, + const std::filesystem::path& folder, + StudyVersion version); // Loading hydro max generation and mqx pumping TS's - bool LoadMaxPower(const AreaName& areaID, const AnyString& folder); + bool LoadMaxPower(const AreaName& areaID, const std::filesystem::path& folder); void buildHourlyMaxPowerFromDailyTS(const Matrix::ColumnType& DailyMaxGenPower, const Matrix::ColumnType& DailyMaxPumpPower); 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 cc9af74015..b4074a28c8 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 @@ -20,6 +20,7 @@ */ #pragma once +#include #include #include @@ -37,7 +38,7 @@ class STStorageCluster bool validate() const; bool loadFromSection(const IniFile::Section& section); - bool loadSeries(const std::string& folder) const; + bool loadSeries(const std::filesystem::path& folder) const; void saveProperties(IniFile& ini) const; bool saveSeries(const std::string& path) const; 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 d2469032dc..90f8fafbce 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 @@ -35,7 +35,7 @@ class STStorageInput /// 1. Read list.ini bool createSTStorageClustersFromIniFile(const std::filesystem::path& path); /// 2. Read ALL series - bool loadSeriesFromFolder(const std::string& folder) const; + bool loadSeriesFromFolder(const std::filesystem::path& folder) const; /// Number of enabled ST storages, ignoring disabled ST storages std::size_t count() const; /// erase disabled cluster from the vector diff --git a/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h b/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h index 238a25d425..9e053b0054 100644 --- a/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h +++ b/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h @@ -19,6 +19,8 @@ ** along with Antares_Simulator. If not, see . */ #pragma once + +#include #include #include @@ -31,7 +33,7 @@ class Series bool validate(const std::string& id = "") const; // load all series files with folder path - bool loadFromFolder(const std::string& folder); + bool loadFromFolder(const std::filesystem::path& folder); void fillDefaultSeriesIfEmpty(); bool saveToFolder(const std::string& folder) const; @@ -55,7 +57,7 @@ class Series bool validateLowerRuleCurve(const std::string&) const; }; -bool loadFile(const std::string& folder, std::vector& vect); +bool loadFile(const std::filesystem::path& folder, std::vector& vect); bool writeVectorToFile(const std::string& path, const std::vector& vect); } // namespace Antares::Data::ShortTermStorage diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h index 9f091defda..af3e096225 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h @@ -20,6 +20,7 @@ */ #pragma once +#include #include #include "../common/cluster_list.h" @@ -43,7 +44,7 @@ class ThermalClusterList: public ClusterList ** \brief Get the size (bytes) occupied in memory by a `ThermalClusterList` structure ** \return A size (in bytes) */ - bool loadFromFolder(Study& s, const AnyString& folder, Area* area); + bool loadFromFolder(Study& s, const std::filesystem::path& folder, Area* area); //! \name Constructor & Destructor //@{ @@ -112,12 +113,12 @@ class ThermalClusterList: public ClusterList ** \param folder The target folder ** \return A non-zero value if the operation succeeded, 0 otherwise */ - bool loadPreproFromFolder(Study& s, const AnyString& folder); + bool loadPreproFromFolder(Study& s, const std::filesystem::path& folder); bool validatePrepro(const Study& study); bool validateClusters(const Parameters& param) const; - bool loadEconomicCosts(Study& s, const AnyString& folder); + bool loadEconomicCosts(Study& s, const std::filesystem::path& folder); bool savePreproToFolder(const AnyString& folder) const; bool saveEconomicCosts(const AnyString& folder) const; diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/ecoInput.h b/src/libs/antares/study/include/antares/study/parts/thermal/ecoInput.h index ef31c31f66..c0456b8653 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/ecoInput.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/ecoInput.h @@ -63,7 +63,7 @@ class EconomicInputData ** \param folder The source folder ** \return A non-zero value if the operation succeeded, 0 otherwise */ - bool loadFromFolder(Study& study, const std::string& folder); + bool loadFromFolder(Study& study, const std::filesystem::path& folder); /*! ** \brief Save settings used by the thermal prepro to a folder diff --git a/src/libs/antares/study/include/antares/study/study.h b/src/libs/antares/study/include/antares/study/study.h index 0a7dd0eb31..9b348a28f5 100644 --- a/src/libs/antares/study/include/antares/study/study.h +++ b/src/libs/antares/study/include/antares/study/study.h @@ -141,7 +141,7 @@ class Study: public Yuni::NonCopyable, public LayerData ** This method does not have any effect except modifying ** internal variables (`folder`, `folderInput`, ...). */ - void relocate(const std::string& newFolder); + void relocate(const std::filesystem::path& newFolder); /*! ** \brief Load a study from a folder @@ -455,13 +455,13 @@ class Study: public Yuni::NonCopyable, public LayerData //! \name Paths //@{ //! The source folder of the study - YString folder; + std::filesystem::path folder; //! The input folder - YString folderInput; + std::filesystem::path folderInput; //! The output folder - YString folderOutput; + std::filesystem::path folderOutput; //! The settings folder - YString folderSettings; + std::filesystem::path folderSettings; //@} //! \name Simulation @@ -633,7 +633,7 @@ class Study: public Yuni::NonCopyable, public LayerData //! Load a study from a folder bool internalLoadFromFolder(const std::filesystem::path& path, const StudyLoadOptions& options); //! Load the study header - bool internalLoadHeader(const YString& folder); + bool internalLoadHeader(const std::filesystem::path& folder); //! Load all correlation matrices bool internalLoadCorrelationMatrices(const StudyLoadOptions& options); //! Load all binding constraints @@ -642,7 +642,7 @@ class Study: public Yuni::NonCopyable, public LayerData bool internalLoadSets(); //@} - bool internalLoadIni(const YString& path, const StudyLoadOptions& options); + bool internalLoadIni(const std::filesystem::path& path, const StudyLoadOptions& options); void parameterFiller(const StudyLoadOptions& options); @@ -659,11 +659,11 @@ class Study: public Yuni::NonCopyable, public LayerData */ extern YString StudyIconFile; -YString StudyCreateOutputPath(SimulationMode mode, - ResultFormat fmt, - const YString& folder, - const YString& label, - int64_t startTime); +std::filesystem::path StudyCreateOutputPath(SimulationMode mode, + ResultFormat fmt, + const std::filesystem::path& folder, + const std::string& label, + const std::tm& startTime); } // namespace Antares::Data #include "study.hxx" diff --git a/src/libs/antares/study/load.cpp b/src/libs/antares/study/load.cpp index 626cb3564d..c6b61a6e61 100644 --- a/src/libs/antares/study/load.cpp +++ b/src/libs/antares/study/load.cpp @@ -37,11 +37,11 @@ namespace Antares { namespace Data { -bool Study::internalLoadHeader(const String& path) +bool Study::internalLoadHeader(const fs::path& path) { // Header - buffer.clear() << path << SEP << "study.antares"; - if (!header.loadFromFile(buffer)) + auto headerPath = path / "study.antares"; + if (!header.loadFromFile(headerPath)) { logs.error() << path << ": impossible to open the header file"; return false; @@ -63,7 +63,7 @@ bool Study::loadFromFolder(const std::string& path, const StudyLoadOptions& opti return internalLoadFromFolder(normPath, options); } -bool Study::internalLoadIni(const String& path, const StudyLoadOptions& options) +bool Study::internalLoadIni(const fs::path& path, const StudyLoadOptions& options) { if (!internalLoadHeader(path)) { @@ -197,7 +197,7 @@ bool Study::internalLoadFromFolder(const fs::path& path, const StudyLoadOptions& this->bufferLoadingTS.reserve(2096); assert(this->bufferLoadingTS.capacity() > 0); - if (!internalLoadIni(path.string(), options)) + if (!internalLoadIni(path, options)) { return false; } diff --git a/src/libs/antares/study/parts/common/cluster.cpp b/src/libs/antares/study/parts/common/cluster.cpp index 9b38aa3c08..4aa44485fa 100644 --- a/src/libs/antares/study/parts/common/cluster.cpp +++ b/src/libs/antares/study/parts/common/cluster.cpp @@ -27,6 +27,8 @@ #include #include "antares/study/study.h" +namespace fs = std::filesystem; + namespace Antares::Data { Cluster::Cluster(Area* parent): @@ -84,7 +86,7 @@ bool Cluster::saveDataSeriesToFolder(const AnyString& folder) const return series.timeSeries.saveToCSVFile(buffer, precision()); } -bool Cluster::loadDataSeriesFromFolder(Study& s, const AnyString& folder) +bool Cluster::loadDataSeriesFromFolder(Study& s, const fs::path& folder) { if (folder.empty()) { @@ -94,9 +96,10 @@ bool Cluster::loadDataSeriesFromFolder(Study& s, const AnyString& folder) auto& buffer = s.bufferLoadingTS; bool ret = true; - buffer.clear() << folder << SEP << parentArea->id << SEP << id() << SEP << "series." - << s.inputExtension; - ret = series.timeSeries.loadFromCSVFile(buffer, 1, HOURS_PER_YEAR, &s.dataBuffer) && ret; + fs::path seriesPath = folder / parentArea->id.to() / id() / "series.txt"; + + ret = series.timeSeries.loadFromCSVFile(seriesPath.string(), 1, HOURS_PER_YEAR, &s.dataBuffer) + && ret; if (s.usedByTheSolver && s.parameters.derated) { diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index 9c39ca7c8b..b8e16c5081 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -261,7 +261,7 @@ bool ClusterList::saveDataSeriesToFolder(const AnyString& folder) cons } template -bool ClusterList::loadDataSeriesFromFolder(Study& s, const AnyString& folder) +bool ClusterList::loadDataSeriesFromFolder(Study& s, const std::filesystem::path& folder) { return std::ranges::all_of(allClusters_, [&s, &folder](auto c) diff --git a/src/libs/antares/study/parts/hydro/series.cpp b/src/libs/antares/study/parts/hydro/series.cpp index 8c73772565..52a087b975 100644 --- a/src/libs/antares/study/parts/hydro/series.cpp +++ b/src/libs/antares/study/parts/hydro/series.cpp @@ -32,6 +32,8 @@ using namespace Yuni; +namespace fs = std::filesystem; + #define SEP IO::Separator namespace Antares::Data @@ -39,7 +41,7 @@ namespace Antares::Data static bool loadTSfromFile(Matrix& ts, const AreaName& areaID, - const AnyString& folder, + const fs::path& folder, const std::string& filename, unsigned int height) { @@ -140,7 +142,7 @@ void DataSeriesHydro::markAsModified() const } bool DataSeriesHydro::loadGenerationTS(const AreaName& areaID, - const AnyString& folder, + const fs::path& folder, StudyVersion studyVersion) { timeseriesNumbers.clear(); @@ -155,7 +157,7 @@ bool DataSeriesHydro::loadGenerationTS(const AreaName& areaID, return ret; } -bool DataSeriesHydro::LoadMaxPower(const AreaName& areaID, const AnyString& folder) +bool DataSeriesHydro::LoadMaxPower(const AreaName& areaID, const fs::path& folder) { bool ret = true; YString filepath; 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 fc2ee8c263..787d1c85e6 100644 --- a/src/libs/antares/study/parts/short-term-storage/cluster.cpp +++ b/src/libs/antares/study/parts/short-term-storage/cluster.cpp @@ -76,7 +76,7 @@ bool STStorageCluster::validate() const return properties.validate() && series->validate(id); } -bool STStorageCluster::loadSeries(const std::string& folder) const +bool STStorageCluster::loadSeries(const std::filesystem::path& folder) const { bool ret = series->loadFromFolder(folder); series->fillDefaultSeriesIfEmpty(); // fill series if no file series 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 9a27233064..bee1546ec4 100644 --- a/src/libs/antares/study/parts/short-term-storage/container.cpp +++ b/src/libs/antares/study/parts/short-term-storage/container.cpp @@ -22,7 +22,6 @@ #include "antares/study/parts/short-term-storage/container.h" #include -#include #include #include @@ -74,7 +73,7 @@ bool STStorageInput::createSTStorageClustersFromIniFile(const fs::path& path) return true; } -bool STStorageInput::loadSeriesFromFolder(const std::string& folder) const +bool STStorageInput::loadSeriesFromFolder(const fs::path& folder) const { if (folder.empty()) { @@ -85,8 +84,8 @@ bool STStorageInput::loadSeriesFromFolder(const std::string& folder) const for (auto& cluster: storagesByIndex) { - const std::string buffer(folder + SEP + cluster.id); - ret = cluster.loadSeries(buffer) && ret; + fs::path seriesFolder = folder / cluster.id; + ret = cluster.loadSeries(seriesFolder) && ret; } return ret; diff --git a/src/libs/antares/study/parts/short-term-storage/series.cpp b/src/libs/antares/study/parts/short-term-storage/series.cpp index 43354fff88..ab58f29f9c 100644 --- a/src/libs/antares/study/parts/short-term-storage/series.cpp +++ b/src/libs/antares/study/parts/short-term-storage/series.cpp @@ -33,24 +33,26 @@ namespace Antares::Data::ShortTermStorage { -bool Series::loadFromFolder(const std::string& folder) +namespace fs = std::filesystem; + +bool Series::loadFromFolder(const fs::path& folder) { bool ret = true; - ret = loadFile(folder + SEP + "PMAX-injection.txt", maxInjectionModulation) && ret; - ret = loadFile(folder + SEP + "PMAX-withdrawal.txt", maxWithdrawalModulation) && ret; - ret = loadFile(folder + SEP + "inflows.txt", inflows) && ret; - ret = loadFile(folder + SEP + "lower-rule-curve.txt", lowerRuleCurve) && ret; - ret = loadFile(folder + SEP + "upper-rule-curve.txt", upperRuleCurve) && ret; + ret = loadFile(folder / "PMAX-injection.txt", maxInjectionModulation) && ret; + ret = loadFile(folder / "PMAX-withdrawal.txt", maxWithdrawalModulation) && ret; + ret = loadFile(folder / "inflows.txt", inflows) && ret; + ret = loadFile(folder / "lower-rule-curve.txt", lowerRuleCurve) && ret; + ret = loadFile(folder / "upper-rule-curve.txt", upperRuleCurve) && ret; - ret = loadFile(folder + SEP + "cost-injection.txt", costInjection) && ret; - ret = loadFile(folder + SEP + "cost-withdrawal.txt", costWithdrawal) && ret; - ret = loadFile(folder + SEP + "cost-level.txt", costLevel) && ret; + ret = loadFile(folder / "cost-injection.txt", costInjection) && ret; + ret = loadFile(folder / "cost-withdrawal.txt", costWithdrawal) && ret; + ret = loadFile(folder / "cost-level.txt", costLevel) && ret; return ret; } -bool loadFile(const std::string& path, std::vector& vect) +bool loadFile(const fs::path& path, std::vector& vect) { logs.debug() << " :: loading file " << path; diff --git a/src/libs/antares/study/parts/thermal/cluster_list.cpp b/src/libs/antares/study/parts/thermal/cluster_list.cpp index 1b46282504..05dec064cc 100644 --- a/src/libs/antares/study/parts/thermal/cluster_list.cpp +++ b/src/libs/antares/study/parts/thermal/cluster_list.cpp @@ -45,6 +45,8 @@ namespace Data { using namespace Yuni; +namespace fs = std::filesystem; + ThermalClusterList::ThermalClusterList() { } @@ -94,7 +96,7 @@ unsigned int ThermalClusterList::enabledAndMustRunCount() const [](auto c) { return c->isEnabled() && c->isMustRun(); }); } -bool ThermalClusterList::loadFromFolder(Study& study, const AnyString& folder, Area* area) +bool ThermalClusterList::loadFromFolder(Study& study, const fs::path& folder, Area* area) { assert(area && "A parent area is required"); @@ -102,9 +104,8 @@ bool ThermalClusterList::loadFromFolder(Study& study, const AnyString& folder, A logs.info() << "Loading thermal configuration for the area " << area->name; // Open the ini file - study.buffer.clear() << folder << SEP << "list.ini"; IniFile ini; - if (!ini.open(study.buffer)) + if (!ini.open(folder / "list.ini")) { return false; } @@ -116,8 +117,6 @@ bool ThermalClusterList::loadFromFolder(Study& study, const AnyString& folder, A return ret; } - String modulationFile; - for (auto* section = ini.firstSection; section; section = section->next) { if (section->name.empty()) @@ -150,16 +149,15 @@ bool ThermalClusterList::loadFromFolder(Study& study, const AnyString& folder, A // allow startup cost between [-5 000 000 ;-5 000 000] (was [-50 000;50 000]) // Modulation - modulationFile.clear() << folder << SEP << ".." << SEP << ".." << SEP << "prepro" << SEP - << cluster->parentArea->id << SEP << cluster->id() << SEP - << "modulation." << study.inputExtension; + auto modulationFile = folder.parent_path().parent_path() / "prepro" + / cluster->parentArea->id.c_str() / cluster->id() / "modulation.txt"; enum { options = Matrix<>::optFixedSize, }; - ret = cluster->modulation.loadFromCSVFile(modulationFile, + ret = cluster->modulation.loadFromCSVFile(modulationFile.string(), thermalModulationMax, HOURS_PER_YEAR, options) @@ -580,17 +578,16 @@ bool ThermalClusterList::saveEconomicCosts(const AnyString& folder) const return ret; } -bool ThermalClusterList::loadPreproFromFolder(Study& study, const AnyString& folder) +bool ThermalClusterList::loadPreproFromFolder(Study& study, const fs::path& folder) { - Clob buffer; auto hasPrepro = [](auto c) { return (bool)c->prepro; }; - auto loadPrepro = [&buffer, &folder, &study](auto& c) + auto loadPrepro = [&folder, &study](auto& c) { assert(c->parentArea && "cluster: invalid parent area"); - buffer.clear() << folder << SEP << c->parentArea->id << SEP << c->id(); - return c->prepro->loadFromFolder(study, buffer); + auto preproPath = folder / c->parentArea->id.c_str() / c->id(); + return c->prepro->loadFromFolder(study, preproPath); }; return std::ranges::all_of(allClusters_ | std::views::filter(hasPrepro), loadPrepro); @@ -624,17 +621,15 @@ bool ThermalClusterList::validatePrepro(const Study& study) }); } -bool ThermalClusterList::loadEconomicCosts(Study& study, const AnyString& folder) +bool ThermalClusterList::loadEconomicCosts(Study& study, const fs::path& folder) { return std::ranges::all_of(allClusters_, [&study, folder](const auto& c) { assert(c->parentArea && "cluster: invalid parent area"); - Clob buffer; - buffer.clear() - << folder << SEP << c->parentArea->id << SEP << c->id(); + auto filePath = folder / c->parentArea->id.c_str() / c->id(); - bool result = c->ecoInput.loadFromFolder(study, buffer); + bool result = c->ecoInput.loadFromFolder(study, filePath); c->ComputeCostTimeSeries(); return result; }); diff --git a/src/libs/antares/study/parts/thermal/ecoInput.cpp b/src/libs/antares/study/parts/thermal/ecoInput.cpp index 30904256cd..c64b65a33d 100644 --- a/src/libs/antares/study/parts/thermal/ecoInput.cpp +++ b/src/libs/antares/study/parts/thermal/ecoInput.cpp @@ -64,7 +64,7 @@ bool EconomicInputData::saveToFolder(const AnyString& folder) const return false; } -bool EconomicInputData::loadFromFolder(Study& study, const std::string& folder) +bool EconomicInputData::loadFromFolder(Study& study, const fs::path& folder) { bool ret = true; @@ -72,7 +72,7 @@ bool EconomicInputData::loadFromFolder(Study& study, const std::string& folder) { Yuni::Clob dataBuffer; - fs::path filename = fs::path(folder) / "fuelCost.txt"; + fs::path filename = folder / "fuelCost.txt"; if (fs::exists(filename)) { ret = fuelcost.loadFromCSVFile(filename.string(), @@ -87,7 +87,7 @@ bool EconomicInputData::loadFromFolder(Study& study, const std::string& folder) } } - filename = fs::path(folder) / "CO2Cost.txt"; + filename = folder / "CO2Cost.txt"; if (fs::exists(filename)) { ret = co2cost.loadFromCSVFile(filename.string(), diff --git a/src/libs/antares/study/save.cpp b/src/libs/antares/study/save.cpp index cd6de7d1b3..656c4b5c2f 100644 --- a/src/libs/antares/study/save.cpp +++ b/src/libs/antares/study/save.cpp @@ -54,7 +54,7 @@ bool Study::resetFolderIcon() const #ifdef YUNI_OS_WINDOWS { // The file should be closed at this point - Yuni::WString wbuffer(folder); + Yuni::WString wbuffer(folder.string()); if (not wbuffer.empty()) { SetFileAttributesW(wbuffer.c_str(), FILE_ATTRIBUTE_SYSTEM); @@ -103,28 +103,28 @@ bool Study::saveToFolder(const AnyString& newfolder) // Trying to create a few important folders logs.info() << "Preparing folders..."; { - const String backupFolder = this->folder; + const auto backupFolder = this->folder; // Changing the paths - relocate(location); + relocate(location.c_str()); // Output - if (not IO::Directory::Create(folderInput)) + if (not IO::Directory::Create(folderInput.string())) { logs.error() << "I/O error: impossible to create the folder '" << folderInput << "'"; - relocate(backupFolder); + relocate(backupFolder.string()); return false; } - if (not IO::Directory::Create(folderSettings)) + if (not IO::Directory::Create(folderSettings.string())) { logs.error() << "I/O error: impossible to create the folder '" << folderSettings << "'"; - relocate(backupFolder); + relocate(backupFolder.string()); return false; } - if (not IO::Directory::Create(folderOutput)) + if (not IO::Directory::Create(folderOutput.string())) { logs.error() << "I/O error: impossible to create the folder '" << folderOutput << "'"; - relocate(backupFolder); + relocate(backupFolder.string()); return false; } } @@ -214,7 +214,7 @@ bool Study::saveToFolder(const AnyString& newfolder) ret = parameters.saveToFile(buffer) and ret; // All areas - ret = areas.saveToFolder(folder) and ret; + ret = areas.saveToFolder(folder.string()) and ret; // Layers buffer.clear() << folder << SEP << "layers"; diff --git a/src/libs/antares/study/study.cpp b/src/libs/antares/study/study.cpp index 29f22e9bf5..1b5493e750 100644 --- a/src/libs/antares/study/study.cpp +++ b/src/libs/antares/study/study.cpp @@ -24,6 +24,7 @@ #include #include #include // For use of floor(...) and ceil(...) +#include #include #include // std::ostringstream #include @@ -123,10 +124,10 @@ void Study::clear() // no folder ClearAndShrink(header.caption); ClearAndShrink(header.author); - ClearAndShrink(folder); - ClearAndShrink(folderInput); - ClearAndShrink(folderOutput); - ClearAndShrink(folderSettings); + folder.clear(); + folderInput.clear(); + folderOutput.clear(); + folderSettings.clear(); inputExtension.clear(); } @@ -186,12 +187,11 @@ void Study::reduceMemoryUsage() ClearAndShrink(bufferLoadingTS); } +// TODO remove with GUI uint64_t Study::memoryUsage() const { - return folder.capacity() - // Folders paths - + folderInput.capacity() + folderOutput.capacity() + folderSettings.capacity() - + buffer.capacity() + dataBuffer.capacity() + return buffer.capacity() // Folders paths + + dataBuffer.capacity() + bufferLoadingTS.capacity() // Simulation + simulationComments.memoryUsage() @@ -453,11 +453,11 @@ static std::string getOutputSuffix(ResultFormat fmt) } } -YString StudyCreateOutputPath(SimulationMode mode, - ResultFormat fmt, - const YString& outputRoot, - const YString& label, - int64_t startTime) +fs::path StudyCreateOutputPath(SimulationMode mode, + ResultFormat fmt, + const fs::path& baseOutFolder, + const std::string& label, + const std::tm& startTime) { if (fmt == ResultFormat::inMemory) { @@ -466,12 +466,9 @@ YString StudyCreateOutputPath(SimulationMode mode, auto suffix = getOutputSuffix(fmt); - YString folderOutput; - // Determining the new output folder // This folder is composed by the name of the simulation + the current date/time - folderOutput.clear() << outputRoot << SEP; - DateTime::TimestampToString(folderOutput, "%Y%m%d-%H%M", startTime, false); + fs::path folderOutput = baseOutFolder / formatTime(startTime, "%Y%m%d-%H%M"); switch (mode) { @@ -491,10 +488,10 @@ YString StudyCreateOutputPath(SimulationMode mode, // Folder output if (not label.empty()) { - folderOutput << '-' << transformNameIntoID(label); + folderOutput += '-' + transformNameIntoID(label); } - std::string outpath = folderOutput + suffix; + std::string outpath = folderOutput.string() + suffix; // avoid creating the same output twice if (fs::exists(outpath)) { @@ -503,30 +500,27 @@ YString StudyCreateOutputPath(SimulationMode mode, do { ++index; - newpath = folderOutput + '-' + std::to_string(index) + suffix; + newpath = folderOutput.string() + '-' + std::to_string(index) + suffix; } while (fs::exists(newpath) and index < 2000); - folderOutput << '-' << index; + folderOutput += '-' + std::to_string(index); } return folderOutput; } void Study::prepareOutput() { - pStartTime = DateTime::Now(); - if (parameters.noOutput || !usedByTheSolver) { return; } - - buffer.clear() << folder << SEP << "output"; + fs::path baseFolderOutput = folder / "output"; folderOutput = StudyCreateOutputPath(parameters.mode, parameters.resultFormat, - buffer, + baseFolderOutput, simulationComments.name, - pStartTime); + getCurrentTime()); logs.info() << " Output folder : " << folderOutput; } @@ -1185,12 +1179,12 @@ void Study::markAsModified() const setsOfAreas.markAsModified(); } -void Study::relocate(const std::string& newFolder) +void Study::relocate(const fs::path& newFolder) { folder = newFolder; - folderInput.clear() << newFolder << SEP << "input"; - folderOutput.clear() << newFolder << SEP << "output"; - folderSettings.clear() << newFolder << SEP << "settings"; + folderInput = newFolder / "input"; + folderOutput = newFolder / "output"; + folderSettings = newFolder / "settings"; } void Study::resizeAllTimeseriesNumbers(uint n) diff --git a/src/libs/antares/study/study.extra.cpp b/src/libs/antares/study/study.extra.cpp index fdfb6eb2d3..e3ff6b46fd 100644 --- a/src/libs/antares/study/study.extra.cpp +++ b/src/libs/antares/study/study.extra.cpp @@ -82,12 +82,13 @@ bool Study::modifyAreaNameIfAlreadyTaken(AreaName& out, const AreaName& basename return true; } +// TODO VP: remove with GUI bool Study::TitleFromStudyFolder(const AnyString& folder, String& out, bool warnings) { String b; b << folder << IO::Separator << "study.antares"; StudyHeader header; - if (header.loadFromFile(b, warnings)) + if (header.loadFromFile(b.c_str(), warnings)) { out = header.caption; return true; @@ -107,7 +108,7 @@ bool Study::IsRootStudy(const AnyString& folder, String& buffer) { buffer.clear() << folder << IO::Separator << "study.antares"; StudyHeader header; - return (header.loadFromFile(buffer, false)); + return (header.loadFromFile(buffer.c_str(), false)); } bool Study::IsInsideStudyFolder(const AnyString& path, String& location, String& title) diff --git a/src/libs/antares/utils/include/antares/utils/utils.h b/src/libs/antares/utils/include/antares/utils/utils.h index a2f50a2e54..47695188a7 100644 --- a/src/libs/antares/utils/include/antares/utils/utils.h +++ b/src/libs/antares/utils/include/antares/utils/utils.h @@ -38,7 +38,8 @@ template void TransformNameIntoID(const AnyString& name, StringT& out); std::string transformNameIntoID(const std::string& name); -std::string FormattedTime(const std::string& format); +std::tm getCurrentTime(); +std::string formatTime(const std::tm& localTime, const std::string& format); /*! ** \brief Beautify a name, for renaming an area for example diff --git a/src/libs/antares/utils/utils.cpp b/src/libs/antares/utils/utils.cpp index 92be168726..fc8ef1d309 100644 --- a/src/libs/antares/utils/utils.cpp +++ b/src/libs/antares/utils/utils.cpp @@ -96,16 +96,19 @@ void BeautifyName(std::string& out, const std::string& oldname) out = yuniOut.c_str(); } -std::string FormattedTime(const std::string& format) +std::tm getCurrentTime() { using namespace std::chrono; auto time = system_clock::to_time_t(system_clock::now()); - std::tm local_time = *std::localtime(&time); + return *std::localtime(&time); +} - char time_buffer[256]; - std::strftime(time_buffer, sizeof(time_buffer), format.c_str(), &local_time); +std::string formatTime(const std::tm& localTime, const std::string& format) +{ + char timeBuffer[256]; + std::strftime(timeBuffer, sizeof(timeBuffer), format.c_str(), &localTime); - return std::string(time_buffer); + return std::string(timeBuffer); } std::vector> splitStringIntoPairs(const std::string& s, diff --git a/src/libs/antares/writer/immediate_file_writer.cpp b/src/libs/antares/writer/immediate_file_writer.cpp index f67e3740e8..3554598de3 100644 --- a/src/libs/antares/writer/immediate_file_writer.cpp +++ b/src/libs/antares/writer/immediate_file_writer.cpp @@ -32,7 +32,7 @@ namespace Antares { namespace Solver { -ImmediateFileResultWriter::ImmediateFileResultWriter(const char* folderOutput): +ImmediateFileResultWriter::ImmediateFileResultWriter(const fs::path& folderOutput): pOutputFolder(folderOutput) { } diff --git a/src/libs/antares/writer/include/antares/writer/writer_factory.h b/src/libs/antares/writer/include/antares/writer/writer_factory.h index 8e2d76cef7..7d33dcaee1 100644 --- a/src/libs/antares/writer/include/antares/writer/writer_factory.h +++ b/src/libs/antares/writer/include/antares/writer/writer_factory.h @@ -21,7 +21,8 @@ #pragma once -#include +#include + #include #include "i_writer.h" @@ -35,7 +36,7 @@ class DurationCollector; namespace Antares::Solver { IResultWriter::Ptr resultWriterFactory(Antares::Data::ResultFormat fmt, - const YString& folderOutput, + const std::filesystem::path& folderOutput, std::shared_ptr qs, Benchmarking::DurationCollector& duration_collector); } diff --git a/src/libs/antares/writer/private/immediate_file_writer.h b/src/libs/antares/writer/private/immediate_file_writer.h index 1f4decc786..1711bbfe96 100644 --- a/src/libs/antares/writer/private/immediate_file_writer.h +++ b/src/libs/antares/writer/private/immediate_file_writer.h @@ -20,6 +20,7 @@ */ #pragma once +#include #include #include @@ -31,7 +32,7 @@ namespace Antares::Solver class ImmediateFileResultWriter: public IResultWriter { public: - ImmediateFileResultWriter(const char* folderOutput); + ImmediateFileResultWriter(const std::filesystem::path& folderOutput); virtual ~ImmediateFileResultWriter(); // Write to file immediately, creating directories if needed void addEntryFromBuffer(const std::string& entryPath, Yuni::Clob& entryContent) override; @@ -43,6 +44,6 @@ class ImmediateFileResultWriter: public IResultWriter void finalize(bool verbose) override; private: - std::string pOutputFolder; + const std::filesystem::path pOutputFolder; }; } // namespace Antares::Solver diff --git a/src/libs/antares/writer/private/zip_writer.h b/src/libs/antares/writer/private/zip_writer.h index 3b9256f3e8..f24c353018 100644 --- a/src/libs/antares/writer/private/zip_writer.h +++ b/src/libs/antares/writer/private/zip_writer.h @@ -49,7 +49,7 @@ class ZipWriteJob { public: ZipWriteJob(ZipWriter& writer, - std::string entryPath, + const std::string& entryPath, ContentT& content, Benchmarking::DurationCollector& duration_collector); void writeEntry(); @@ -78,7 +78,7 @@ class ZipWriter: public IResultWriter { public: ZipWriter(std::shared_ptr qs, - const char* archivePath, + const std::filesystem::path& archivePath, Benchmarking::DurationCollector& duration_collector); virtual ~ZipWriter(); void addEntryFromBuffer(const std::string& entryPath, Yuni::Clob& entryContent) override; @@ -101,7 +101,7 @@ class ZipWriter: public IResultWriter // State, to allow/prevent new jobs being added to the queue ZipState pState; // Absolute path to the archive - const std::string pArchivePath; + const std::filesystem::path pArchivePath; // Benchmarking. Passed to jobs Benchmarking::DurationCollector& pDurationCollector; diff --git a/src/libs/antares/writer/writer_factory.cpp b/src/libs/antares/writer/writer_factory.cpp index ec5acd03d2..d8fc957510 100644 --- a/src/libs/antares/writer/writer_factory.cpp +++ b/src/libs/antares/writer/writer_factory.cpp @@ -28,20 +28,21 @@ namespace Antares::Solver { IResultWriter::Ptr resultWriterFactory(Antares::Data::ResultFormat fmt, - const YString& folderOutput, + const std::filesystem::path& folderOutput, std::shared_ptr qs, Benchmarking::DurationCollector& duration_collector) { using namespace Antares::Data; + switch (fmt) { case zipArchive: - return std::make_shared(qs, folderOutput.c_str(), duration_collector); + return std::make_shared(qs, folderOutput, duration_collector); case inMemory: return std::make_shared(duration_collector); case legacyFilesDirectories: default: - return std::make_shared(folderOutput.c_str()); + return std::make_shared(folderOutput); } } } // namespace Antares::Solver diff --git a/src/libs/antares/writer/zip_writer.cpp b/src/libs/antares/writer/zip_writer.cpp index ddfee2918e..007524377a 100644 --- a/src/libs/antares/writer/zip_writer.cpp +++ b/src/libs/antares/writer/zip_writer.cpp @@ -54,13 +54,13 @@ static void logErrorAndThrow [[noreturn]] (const std::string& errorMessage) // Class ZipWriteJob template ZipWriteJob::ZipWriteJob(ZipWriter& writer, - std::string entryPath, + const std::string& entryPath, ContentT& content, Benchmarking::DurationCollector& duration_collector): pZipHandle(writer.pZipHandle), pZipMutex(writer.pZipMutex), pState(writer.pState), - pEntryPath(std::move(entryPath)), + pEntryPath(entryPath), pContent(std::move(content)), pDurationCollector(duration_collector) { @@ -114,18 +114,22 @@ void ZipWriteJob::writeEntry() // Class ZipWriter ZipWriter::ZipWriter(std::shared_ptr qs, - const char* archivePath, + const fs::path& archivePath, Benchmarking::DurationCollector& duration_collector): pQueueService(qs), pState(ZipState::can_receive_data), - pArchivePath(std::string(archivePath) + ".zip"), + pArchivePath(archivePath.string() + ".zip"), pDurationCollector(duration_collector) { pZipHandle = mz_zip_writer_create(); - if (int32_t ret = mz_zip_writer_open_file(pZipHandle, pArchivePath.c_str(), 0, 0); ret != MZ_OK) + + // conversion in 2 steps to avoid weird behavior differences for linux and windows + std::string tmpStr = pArchivePath.string(); + const char* outputCStr = tmpStr.c_str(); + if (int32_t ret = mz_zip_writer_open_file(pZipHandle, outputCStr, 0, 0); ret != MZ_OK) { - logErrorAndThrow("Error opening zip file " + pArchivePath + " (" + std::to_string(ret) - + ")"); + logErrorAndThrow("Error opening zip file " + pArchivePath.string() + " (" + + std::to_string(ret) + ")"); } // TODO : make level of compression configurable mz_zip_writer_set_compress_level(pZipHandle, MZ_COMPRESS_LEVEL_FAST); diff --git a/src/solver/application/application.cpp b/src/solver/application/application.cpp index 346c67496a..335a6a2c98 100644 --- a/src/solver/application/application.cpp +++ b/src/solver/application/application.cpp @@ -405,7 +405,7 @@ void Application::resetLogFilename() const } logfile /= "solver-"; // append the filename - logfile += FormattedTime("%Y%m%d-%H%M%S") + logfile += formatTime(getCurrentTime(), "%Y%m%d-%H%M%S") + ".log"; // complete filename with timestamp and extension // Assigning the log filename diff --git a/src/solver/constraints-builder/cbuilder.cpp b/src/solver/constraints-builder/cbuilder.cpp index 5c02947a6f..0fb88a0a9c 100644 --- a/src/solver/constraints-builder/cbuilder.cpp +++ b/src/solver/constraints-builder/cbuilder.cpp @@ -295,7 +295,7 @@ bool CBuilder::runConstraintsBuilder(bool standalone) if (standalone) { - pStudy.saveToFolder(pStudy.folder); + pStudy.saveToFolder(pStudy.folder.string()); } // return result; return result; diff --git a/src/solver/simulation/include/antares/solver/simulation/solver.hxx b/src/solver/simulation/include/antares/solver/simulation/solver.hxx index 6b948a4b9a..7f4a63ab82 100644 --- a/src/solver/simulation/include/antares/solver/simulation/solver.hxx +++ b/src/solver/simulation/include/antares/solver/simulation/solver.hxx @@ -457,8 +457,8 @@ void ISimulation::regenerateTimeSeries(uint year) bool doWeWrite = archive && !study.parameters.noOutput; if (doWeWrite) { - fs::path savePath = fs::path(study.folderOutput.to()) / "ts-generator" - / "thermal" / "mc-" / std::to_string(year); + fs::path savePath = study.folderOutput / "ts-generator" / "thermal" / "mc-" + / std::to_string(year); writeThermalTimeSeries(clusters, savePath); } diff --git a/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h b/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h index 4d93f56f8a..850463b580 100644 --- a/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h +++ b/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h @@ -80,7 +80,7 @@ class PreproAvailability ** \param folder The source folder ** \return A non-zero value if the operation succeeded, 0 otherwise */ - bool loadFromFolder(Study& study, const AnyString& folder); + bool loadFromFolder(Study& study, const std::filesystem::path& folder); /*! ** \brief Validate most settings against min/max rules diff --git a/src/solver/ts-generator/prepro.cpp b/src/solver/ts-generator/prepro.cpp index b093d4b837..b26faefb50 100644 --- a/src/solver/ts-generator/prepro.cpp +++ b/src/solver/ts-generator/prepro.cpp @@ -59,14 +59,11 @@ bool PreproAvailability::saveToFolder(const AnyString& folder) const return false; } -bool PreproAvailability::loadFromFolder(Study& study, const AnyString& folder) +bool PreproAvailability::loadFromFolder(Study& study, const std::filesystem::path& folder) { - auto& buffer = study.bufferLoadingTS; - - buffer.clear() << folder << SEP << "data.txt"; - + auto filePath = folder / "data.txt"; // standard loading - return data.loadFromCSVFile(buffer, + return data.loadFromCSVFile(filePath.string(), preproAvailabilityMax, DAYS_PER_YEAR, Matrix<>::optFixedSize, diff --git a/src/solver/ts-generator/xcast/xcast.cpp b/src/solver/ts-generator/xcast/xcast.cpp index 2c8a391a22..3f42862cb5 100644 --- a/src/solver/ts-generator/xcast/xcast.cpp +++ b/src/solver/ts-generator/xcast/xcast.cpp @@ -73,7 +73,6 @@ void XCast::exportTimeSeriesToTheOutput(Progression::Task& progression, Predicat String output; String filename; - output.reserve(study.folderOutput.size() + 80); output << "ts-generator" << SEP << predicate.timeSeriesName() << SEP << "mc-" << year; filename.reserve(output.size() + 80); diff --git a/src/tests/src/libs/antares/study/output-folder/study.cpp b/src/tests/src/libs/antares/study/output-folder/study.cpp index 1675ae7909..c04565ec2e 100644 --- a/src/tests/src/libs/antares/study/output-folder/study.cpp +++ b/src/tests/src/libs/antares/study/output-folder/study.cpp @@ -76,14 +76,14 @@ BOOST_FIXTURE_TEST_CASE(economy_legacyfiles_emptylabel, Fixture) { SimulationMode mode = SimulationMode::Economy; ResultFormat fmt = legacyFilesDirectories; - const YString label = ""; - const int64_t startTime = 1; - const YString expectedOutput = (outputRoot / "19700101-0000eco").string(); - const YString actualOutput = StudyCreateOutputPath(mode, - fmt, - outputRoot.string(), - label, - startTime); + const std::string label = ""; + const time_t startTime = 1; + const fs::path expectedOutput = outputRoot / "19700101-0000eco"; + const fs::path actualOutput = StudyCreateOutputPath(mode, + fmt, + outputRoot, + label, + *localtime(&startTime)); BOOST_CHECK_EQUAL(actualOutput, expectedOutput); } @@ -91,14 +91,14 @@ BOOST_FIXTURE_TEST_CASE(economy_legacyfiles_label_now, Fixture) { SimulationMode mode = SimulationMode::Economy; ResultFormat fmt = legacyFilesDirectories; - const YString label = "test"; - const int64_t startTime = 1672391667; - const YString expectedOutput = (outputRoot / "20221230-0914eco-test").string(); - const YString actualOutput = StudyCreateOutputPath(mode, - fmt, - outputRoot.string(), - label, - startTime); + const std::string label = "test"; + const time_t startTime = 1672391667; + const fs::path expectedOutput = outputRoot / "20221230-0914eco-test"; + const fs::path actualOutput = StudyCreateOutputPath(mode, + fmt, + outputRoot, + label, + *localtime(&startTime)); BOOST_CHECK_EQUAL(actualOutput, expectedOutput); } @@ -106,23 +106,23 @@ BOOST_FIXTURE_TEST_CASE(adequacy_legacyfiles_label_now, Fixture) { SimulationMode mode = SimulationMode::Adequacy; ResultFormat fmt = legacyFilesDirectories; - const YString label = "test"; - const int64_t startTime = 1672391667; - const YString expectedOutput = (outputRoot / "20221230-0914adq-test").string(); - const YString actualOutput = StudyCreateOutputPath(mode, - fmt, - outputRoot.string(), - label, - startTime); + const std::string label = "test"; + const time_t startTime = 1672391667; + const fs::path expectedOutput = outputRoot / "20221230-0914adq-test"; + const fs::path actualOutput = StudyCreateOutputPath(mode, + fmt, + outputRoot, + label, + *localtime(&startTime)); BOOST_CHECK_EQUAL(actualOutput, expectedOutput); fs::create_directory(outputRoot / "20221230-0914adq-test"); - const YString expectedOutput_suffix = (outputRoot / "20221230-0914adq-test-2").string(); - const YString actualOutput_suffix = StudyCreateOutputPath(mode, - fmt, - outputRoot.string(), - label, - startTime); + const fs::path expectedOutput_suffix = outputRoot / "20221230-0914adq-test-2"; + const fs::path actualOutput_suffix = StudyCreateOutputPath(mode, + fmt, + outputRoot, + label, + *localtime(&startTime)); BOOST_CHECK_EQUAL(actualOutput_suffix, expectedOutput_suffix); } @@ -130,25 +130,25 @@ BOOST_FIXTURE_TEST_CASE(adequacy_zip_label_now, Fixture) { SimulationMode mode = SimulationMode::Adequacy; ResultFormat fmt = zipArchive; - const YString label = "test"; - const int64_t startTime = 1672391667; - const YString expectedOutput = (outputRoot / "20221230-0914adq-test").string(); - const YString actualOutput = StudyCreateOutputPath(mode, - fmt, - outputRoot.string(), - label, - startTime); + const std::string label = "test"; + const time_t startTime = 1672391667; + const fs::path expectedOutput = outputRoot / "20221230-0914adq-test"; + const fs::path actualOutput = StudyCreateOutputPath(mode, + fmt, + outputRoot, + label, + *localtime(&startTime)); BOOST_CHECK_EQUAL(actualOutput, expectedOutput); std::ofstream zip_file(outputRoot / "20221230-0914adq-test.zip"); zip_file << "I am a zip file. Well, not really."; - const YString expectedOutput_suffix = (outputRoot / "20221230-0914adq-test-2").string(); - const YString actualOutput_suffix = StudyCreateOutputPath(mode, - fmt, - outputRoot.string(), - label, - startTime); + const fs::path expectedOutput_suffix = outputRoot / "20221230-0914adq-test-2"; + const fs::path actualOutput_suffix = StudyCreateOutputPath(mode, + fmt, + outputRoot, + label, + *localtime(&startTime)); BOOST_CHECK_EQUAL(actualOutput_suffix, expectedOutput_suffix); } diff --git a/src/tools/ts-generator/linksTSgenerator.cpp b/src/tools/ts-generator/linksTSgenerator.cpp index a200386a7e..9eaa481268 100644 --- a/src/tools/ts-generator/linksTSgenerator.cpp +++ b/src/tools/ts-generator/linksTSgenerator.cpp @@ -337,7 +337,8 @@ void LinksTSgenerator::extractLinksSpecificTSparameters() bool LinksTSgenerator::generate() { - auto saveTSpath = fs::path(studyFolder_) / "output" / FormattedTime("%Y%m%d-%H%M"); + auto saveTSpath = fs::path(studyFolder_) / "output" + / formatTime(getCurrentTime(), "%Y%m%d-%H%M"); saveTSpath /= "ts-generator"; saveTSpath /= "links"; diff --git a/src/tools/ts-generator/main.cpp b/src/tools/ts-generator/main.cpp index baece8ca45..70f7d67ea7 100644 --- a/src/tools/ts-generator/main.cpp +++ b/src/tools/ts-generator/main.cpp @@ -108,7 +108,7 @@ int main(int argc, const char* argv[]) // === Writing generated TS on disk === auto thermalSavePath = fs::path(settings.studyFolder) / "output" - / FormattedTime("%Y%m%d-%H%M"); + / formatTime(getCurrentTime(), "%Y%m%d-%H%M"); thermalSavePath /= "ts-generator"; thermalSavePath /= "thermal"; writeThermalTimeSeries(clusters, thermalSavePath); diff --git a/src/tools/vacuum/antares-study.cpp b/src/tools/vacuum/antares-study.cpp index aaa7a0dc04..7e3762989c 100644 --- a/src/tools/vacuum/antares-study.cpp +++ b/src/tools/vacuum/antares-study.cpp @@ -93,7 +93,7 @@ bool AntaresStudyAnalyzerJob::shouldBeDestroyed() const // there is no need to perform additional tests on the logs // or on the outputs Data::StudyHeader header; - if (not header.loadFromFile(filename, false)) + if (not header.loadFromFile(filename.c_str(), false)) { logs.info() << " delete study " << folder << " [invalid header]"; return true; diff --git a/src/ui/simulator/application/main/main.cpp b/src/ui/simulator/application/main/main.cpp index 31865edc53..137b009c2b 100644 --- a/src/ui/simulator/application/main/main.cpp +++ b/src/ui/simulator/application/main/main.cpp @@ -876,7 +876,7 @@ void ApplWnd::evtOnUpdateInterfaceAfterLoadedStudy(wxCommandEvent&) { Menu::AddRecentFile(menuRecentFiles(), wxStringFromUTF8(study.header.caption), - wxStringFromUTF8(study.folder)); + wxStringFromUTF8(study.folder.string())); } // User notes diff --git a/src/ui/simulator/application/main/menu.cpp b/src/ui/simulator/application/main/menu.cpp index 26dbbd1d56..11121bce3c 100644 --- a/src/ui/simulator/application/main/menu.cpp +++ b/src/ui/simulator/application/main/menu.cpp @@ -626,9 +626,9 @@ void ApplWnd::evtOnOpenStudyFolderInExplorer(wxCommandEvent&) { if (System::windows) wxExecute(wxString(wxT("explorer.exe \"")) - << wxStringFromUTF8(study->folder) << wxT("\"")); + << wxStringFromUTF8(study->folder.string()) << wxT("\"")); else - wxExecute(wxString(wxT("xdg-open \"")) << wxStringFromUTF8(study->folder) << wxT("\"")); + wxExecute(wxString(wxT("xdg-open \"")) << wxStringFromUTF8(study->folder.string()) << wxT("\"")); } } diff --git a/src/ui/simulator/application/study.cpp b/src/ui/simulator/application/study.cpp index c71e4de6ca..e2b5a1416f 100644 --- a/src/ui/simulator/application/study.cpp +++ b/src/ui/simulator/application/study.cpp @@ -156,12 +156,12 @@ static void finalizeSaveExport(Data::Study::Ptr study, Forms::ApplWnd& frame) { Menu::AddRecentFile(frame.menuRecentFiles(), wxStringFromUTF8(study->header.caption), - wxStringFromUTF8(study->folder)); + wxStringFromUTF8(study->folder.string())); // Rebuild the menu Menu::RebuildRecentFiles(frame.menuRecentFiles()); - gLastOpenedStudyFolder = wxStringFromUTF8(study->folder); + gLastOpenedStudyFolder = wxStringFromUTF8(study->folder.string()); RefreshListOfOutputsForTheCurrentStudy(); @@ -811,12 +811,12 @@ SaveResult SaveStudy() // Reset the entries Menu::AddRecentFile(mainFrm.menuRecentFiles(), wxStringFromUTF8(study.header.caption), - wxStringFromUTF8(study.folder)); + wxStringFromUTF8(study.folder.string())); - mainFrm.SetStatusText(wxString() << wxT(" Saving ") << wxStringFromUTF8(study.folder)); + mainFrm.SetStatusText(wxString() << wxT(" Saving ") << wxStringFromUTF8(study.folder.string())); // Save the study - auto* job = new JobSaveStudy(studyptr, study.folder); + auto* job = new JobSaveStudy(studyptr, study.folder.string()); if (shouldInvalidateStudy) job->shouldInvalidateStudy(); job->run(); @@ -839,11 +839,11 @@ SaveResult SaveStudy() Menu::AddRecentFile(mainFrm.menuRecentFiles(), wxStringFromUTF8(study.header.caption), - wxStringFromUTF8(study.folder)); + wxStringFromUTF8(study.folder.string())); // Rebuild the menu Menu::RebuildRecentFiles(mainFrm.menuRecentFiles()); - gLastOpenedStudyFolder = wxStringFromUTF8(study.folder); + gLastOpenedStudyFolder = wxStringFromUTF8(study.folder.string()); RefreshListOfOutputsForTheCurrentStudy(); @@ -874,7 +874,7 @@ SaveResult SaveStudyAs(const String& path, bool copyoutput, bool copyuserdata, b if (!study->folder.empty()) { - String oldP = study->folder; + String oldP = study->folder.string(); String newP = newPath; newP.removeTrailingSlash(); oldP.removeTrailingSlash(); @@ -1049,7 +1049,7 @@ void OpenStudyFromFolder(wxString folder) { Menu::AddRecentFile(mainFrm.menuRecentFiles(), wxStringFromUTF8(study->header.caption), - wxStringFromUTF8(study->folder)); + wxStringFromUTF8(study->folder.string())); } } // Lock the window to prevent flickering @@ -1115,7 +1115,7 @@ void RunSimulationOnTheStudy(Data::Study::Ptr study, { // Logs - mainFrm.SetStatusText(wxString() << wxT(" Running ") << wxStringFromUTF8(study->folder)); + mainFrm.SetStatusText(wxString() << wxT(" Running ") << wxStringFromUTF8(study->folder.string())); logs.info(); logs.checkpoint() << "Launching the simulation"; @@ -1200,7 +1200,8 @@ void RunSimulationOnTheStudy(Data::Study::Ptr study, cmd << ' '; // The input data - AppendWithQuotes(cmd, study->folder); + String s = study->folder.string(); + AppendWithQuotes(cmd, s); // Parallel mode chosen ? if (features == Solver::parallel) diff --git a/src/ui/simulator/toolbox/components/mainpanel.cpp b/src/ui/simulator/toolbox/components/mainpanel.cpp index 1bdbbb42ba..5b5a25e90d 100644 --- a/src/ui/simulator/toolbox/components/mainpanel.cpp +++ b/src/ui/simulator/toolbox/components/mainpanel.cpp @@ -169,7 +169,7 @@ void MainPanel::onDraw(wxPaintEvent&) if (study->folder.empty()) addProperty(dc, wxT("from "), wxT(""), size, posY); else - addProperty(dc, wxT("from "), wxStringFromUTF8(study->folder), size, posY); + addProperty(dc, wxT("from "), wxStringFromUTF8(study->folder.string()), size, posY); } // Checking if the actual height of the control is the good one diff --git a/src/ui/simulator/toolbox/ext-source/handler/com.rte-france.antares.study.cpp b/src/ui/simulator/toolbox/ext-source/handler/com.rte-france.antares.study.cpp index 831cb2c091..13637cad0e 100644 --- a/src/ui/simulator/toolbox/ext-source/handler/com.rte-france.antares.study.cpp +++ b/src/ui/simulator/toolbox/ext-source/handler/com.rte-france.antares.study.cpp @@ -506,7 +506,7 @@ void AntaresStudy(Data::Study::Ptr target, // If the path of the study where items should be extracted is the same than the current opened // study, we can directly use it - if (!path || path == target->folder) + if (!path || path == target->folder.string()) { context->extStudy = target; diff --git a/src/ui/simulator/windows/analyzer/analyzer.cpp b/src/ui/simulator/windows/analyzer/analyzer.cpp index 47d223f2fa..1f2238ce51 100644 --- a/src/ui/simulator/windows/analyzer/analyzer.cpp +++ b/src/ui/simulator/windows/analyzer/analyzer.cpp @@ -534,7 +534,7 @@ void AnalyzerWizard::ResetLastFolderToCurrentStudyUser() if (!IO::Directory::Exists(newvalue)) { // If the user folder does not exist, fallback to the study folder - gLastFolderForTSAnalyzer = wxStringFromUTF8(study.folder); + gLastFolderForTSAnalyzer = wxStringFromUTF8(study.folder.string()); } else gLastFolderForTSAnalyzer = wxStringFromUTF8(newvalue); @@ -1393,7 +1393,7 @@ bool AnalyzerWizard::saveToFile(const String& filename) const auto* mainSection = ini.addSection(".general"); // Study - mainSection->add("study", study.folder); + mainSection->add("study", study.folder.string()); // Tmp wxStringToString(pPathTemp->GetValue(), tmp); mainSection->add("temporary", tmp); @@ -1601,7 +1601,7 @@ void AnalyzerWizard::onBrowseReset(wxCommandEvent&) if (pUpdating or not CurrentStudyIsValid()) return; auto& study = *GetCurrentStudy(); - wxString path = wxStringFromUTF8(study.folder); + wxString path = wxStringFromUTF8(study.folder.string()); path << IO::Constant::Separator << wxT("user"); browseDataFolder(path); } diff --git a/src/ui/simulator/windows/exportmap.cpp b/src/ui/simulator/windows/exportmap.cpp index 6d843c45c7..c371eeef22 100644 --- a/src/ui/simulator/windows/exportmap.cpp +++ b/src/ui/simulator/windows/exportmap.cpp @@ -239,12 +239,13 @@ void ExportMap::internalCreateComponents() if (not pStudy->folder.empty() && defaultPath == wxEmptyString) { // Get the parent folder - folderPath = pStudy->folder + SEP << "maps"; + String f = pStudy->folder.string(); + folderPath = f << SEP << "maps"; if (not IO::Directory::Exists(folderPath)) { - folderPath = pStudy->folder; - uint sepPos = pStudy->folder.find_last_of(SEP); + folderPath = f; + uint sepPos = f.find_last_of(SEP); if (sepPos != YString::npos) { // found it diff --git a/src/ui/simulator/windows/memorystatistics/memorystatistics.cpp b/src/ui/simulator/windows/memorystatistics/memorystatistics.cpp index b42d93489a..649ebfb972 100644 --- a/src/ui/simulator/windows/memorystatistics/memorystatistics.cpp +++ b/src/ui/simulator/windows/memorystatistics/memorystatistics.cpp @@ -307,10 +307,10 @@ void MemoryStatistics::refreshInformation() { s.clear(); CString<5, false> driveletter; - driveletter += study->folder[0]; + driveletter += study->folder.string()[0]; s << wxStringFromUTF8(driveletter) << wxT(": "); - uint64_t diskFree = DiskFreeSpace(study->folder); + uint64_t diskFree = DiskFreeSpace(study->folder.string()); if (diskFree == (uint64_t)-1) s << wxT("N/A"); else diff --git a/src/ui/simulator/windows/saveas.cpp b/src/ui/simulator/windows/saveas.cpp index 0fba0f4719..06935b07f0 100644 --- a/src/ui/simulator/windows/saveas.cpp +++ b/src/ui/simulator/windows/saveas.cpp @@ -243,7 +243,7 @@ void SaveAs::internalCreateComponents() if (not pStudy->folder.empty()) { // Get the parent folder - wxString s = wxStringFromUTF8(pStudy->folder); + wxString s = wxStringFromUTF8(pStudy->folder.string()); size_t p = s.find_last_of(wxT("\\/")); if (p != std::string::npos) pFolder->SetValue(s.substr(0, p)); From af9f5598752b03a7b00cfb27e8fa8a7db99d8ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20Mar=C3=A9chal?= <45510813+JasonMarechal25@users.noreply.github.com> Date: Tue, 8 Oct 2024 11:49:22 +0200 Subject: [PATCH 030/103] [ANT-2206] yaml to model (#2431) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Expose `Antares::Solver::ObjectModel::Library Antares::Solver::ModelConverter::convert(const Antares::Solver::ModelParser::Library& library)` # Implementation details Convert a Library resulting from yaml parsing to a library in the context ob ObjectModel Use builder pattern to construct complexes object such as library and models Declaring a lib ModelConverter as the same level as ObjectModel and ObjectParser prevent either from depending on both. Conceptually they're independent from each others Defines two ValueType enums in two different contexts. Allow for diverging evolution # Limitations - [ANT-2228](https://gopro-tickets.rte-france.com/browse/ANT-2228) Gérer les exception de champs superflus - [ANT-2230](https://gopro-tickets.rte-france.com/browse/ANT-2230) Gérer les champs optionnels - [ANT-2233](https://gopro-tickets.rte-france.com/browse/ANT-2233) Pour les valueType, gérer la capitalisation - [ANT-2233](https://gopro-tickets.rte-france.com/browse/ANT-2233) value_type pour les Parameters - [ANT-2235](https://gopro-tickets.rte-france.com/browse/ANT-2235) contraintes et binding_constraints - [ANT-2236](https://gopro-tickets.rte-france.com/browse/ANT-2236) Constraintes et expressions, inadéquation models/yaml - Ports are not handled in the scope of this PR/ANT-2206 --------- Co-authored-by: Vincent Payet Co-authored-by: payetvin <113102157+payetvin@users.noreply.github.com> Co-authored-by: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Co-authored-by: Florian OMNES --- src/solver/CMakeLists.txt | 1 + src/solver/libModelObject/CMakeLists.txt | 2 + .../solver/libObjectModel/constraint.h | 19 +- .../solver/libObjectModel/expression.h | 16 +- .../antares/solver/libObjectModel/library.h | 50 +++- .../antares/solver/libObjectModel/model.h | 51 +++- .../antares/solver/libObjectModel/parameter.h | 55 +++- .../antares/solver/libObjectModel/port.h | 13 +- .../antares/solver/libObjectModel/portField.h | 13 +- .../antares/solver/libObjectModel/portType.h | 25 +- .../antares/solver/libObjectModel/variable.h | 31 +- src/solver/libModelObject/library.cpp | 101 +++++++ src/solver/libModelObject/model.cpp | 110 ++++++- src/solver/modelConverter/CMakeLists.txt | 25 ++ .../solver/modelConverter/modelConverter.h | 41 +++ src/solver/modelConverter/modelConverter.cpp | 211 ++++++++++++++ src/solver/modelParser/CMakeLists.txt | 2 +- src/solver/modelParser/encoders.hxx | 53 +++- .../solver/modelParser/{model.h => Library.h} | 58 +++- .../antares/solver/modelParser/parser.h | 2 +- src/solver/modelParser/parser.cpp | 2 +- .../src/solver/modelParser/CMakeLists.txt | 3 + .../solver/modelParser/testModelParser.cpp | 176 ++++++++---- .../modelParser/testModelTranslator.cpp | 270 ++++++++++++++++++ 24 files changed, 1227 insertions(+), 103 deletions(-) create mode 100644 src/solver/libModelObject/library.cpp create mode 100644 src/solver/modelConverter/CMakeLists.txt create mode 100644 src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h create mode 100644 src/solver/modelConverter/modelConverter.cpp rename src/solver/modelParser/include/antares/solver/modelParser/{model.h => Library.h} (66%) create mode 100644 src/tests/src/solver/modelParser/testModelTranslator.cpp diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index d579606350..be643ebecb 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -15,6 +15,7 @@ add_subdirectory(infeasible-problem-analysis) add_subdirectory(libModelObject) add_subdirectory(lps) add_subdirectory(misc) +add_subdirectory(modelConverter) add_subdirectory(modelParser) add_subdirectory(modeler) add_subdirectory(optimisation) diff --git a/src/solver/libModelObject/CMakeLists.txt b/src/solver/libModelObject/CMakeLists.txt index ce2ae94d35..bb489afd7e 100644 --- a/src/solver/libModelObject/CMakeLists.txt +++ b/src/solver/libModelObject/CMakeLists.txt @@ -1,6 +1,7 @@ project(LibObjectModel) set(SRC_model + library.cpp model.cpp include/antares/solver/libObjectModel/library.h @@ -19,6 +20,7 @@ set(SRC_model source_group("libObjectModel" FILES ${SRC_model}) add_library(antares-solver-libObjectModel ${SRC_model}) +add_library(Antares::antares-solver-libObjectModel ALIAS antares-solver-libObjectModel) target_include_directories(antares-solver-libObjectModel PUBLIC diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/constraint.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/constraint.h index fbf28a3a89..5a66ee8571 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/constraint.h +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/constraint.h @@ -32,11 +32,24 @@ namespace Antares::Solver::ObjectModel class Constraint { public: - Constraint(); - ~Constraint() = default; + Constraint(std::string name, Expression expression): + id_(std::move(name)), + expression_(std::move(expression)) + { + } + + const std::string& Id() const + { + return id_; + } + + Expression expression() const + { + return expression_; + } private: - std::string name_; + std::string id_; Expression expression_; }; diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/expression.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/expression.h index c83165ee09..87fefbc8c5 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/expression.h +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/expression.h @@ -28,8 +28,20 @@ namespace Antares::Solver::ObjectModel class Expression { public: - Expression(); - ~Expression() = default; + Expression() = default; + + explicit Expression(std::string value): + value_(std::move(value)) + { + } + + const std::string& Value() const + { + return value_; + } + +private: + std::string value_; }; } // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/library.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/library.h index 9752aeb0f0..1be9d63815 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/library.h +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/library.h @@ -20,7 +20,8 @@ */ #pragma once -#include +#include +#include #include "model.h" #include "portType.h" @@ -32,15 +33,56 @@ namespace Antares::Solver::ObjectModel class Library { public: - Library(); + Library() = default; ~Library() = default; + const std::string& Id() const + { + return id_; + } + + const std::string& Description() const + { + return description_; + } + + const std::unordered_map& PortTypes() const + { + return portTypes_; + } + + const std::unordered_map& Models() const + { + return models_; + } + private: + friend class LibraryBuilder; + std::string id_; std::string description_; - std::map portTypes_; - std::map models_; + std::unordered_map portTypes_; + std::unordered_map models_; +}; + +/** + * @brief Builder for the Library class + * Follow builder pattern: + * builder.Library().withId("id").withDescription("description").withPortTypes(portList).withModels(modelList).build(); + */ +class LibraryBuilder +{ +public: + LibraryBuilder& withId(const std::string& id); + LibraryBuilder& withDescription(const std::string& description); + LibraryBuilder& withPortTypes(std::vector&& portTypes); + LibraryBuilder& withModels(std::vector&& models); + + Library build(); + +private: + Library library_; }; } // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/model.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/model.h index 0cdeb0bb92..c76b22cd35 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/model.h +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/model.h @@ -39,22 +39,61 @@ namespace Antares::Solver::ObjectModel class Model { public: - Model(); - ~Model() = default; + const std::string& Id() const + { + return id_; + } - std::vector getConstraints(); + Expression Objective() const + { + return objective_; + } + + const std::map& getConstraints() const + { + return constraints_; + } + + const std::map& Parameters() const + { + return parameters_; + } + + const std::map& Variables() const + { + return variables_; + } + + const std::map& Ports() const + { + return ports_; + } private: + friend class ModelBuilder; std::string id_; Expression objective_; std::map parameters_; std::map variables_; - std::map constraints_; - std::map bindingConstraints_; - std::map ports_; }; +class ModelBuilder +{ +public: + ModelBuilder& withId(std::string_view id); + ModelBuilder& withObjective(Expression objective); + ModelBuilder& withParameters(std::vector&& parameters); + ModelBuilder& withVariables(std::vector&& variables); + ModelBuilder& withPorts(std::vector&& ports); + Model build(); + + ModelBuilder& withConstraints(std::vector&& constraints); + +private: + Model model_; +}; + } // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/parameter.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/parameter.h index 55be8984e0..ec25ff632e 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/parameter.h +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/parameter.h @@ -35,14 +35,59 @@ namespace Antares::Solver::ObjectModel class Parameter { public: - Parameter(); - ~Parameter() = default; + /** Using enum class to avoid primitive obsession. Mainly prevent headhaches when reading + * Parameter("Param", ValueType::FLOAT, false, true) + * Avoid mixing wich value is which boolean parameter + */ + + enum class TimeDependent : bool + { + NO = false, + YES = true + }; + + enum class ScenarioDependent : bool + { + NO = false, + YES = true + }; + + explicit Parameter(std::string id, + ValueType type, + TimeDependent timeDependent, + ScenarioDependent scenarioDependent): + id_(std::move(id)), + type_(type), + timeDependent_(timeDependent), + scenarioDependent_(scenarioDependent) + { + } + + const std::string& Id() const + { + return id_; + } + + ValueType Type() const + { + return type_; + } + + bool isTimeDependent() const + { + return timeDependent_ == TimeDependent::YES; + } + + bool isScenarioDependent() const + { + return scenarioDependent_ == ScenarioDependent::YES; + } private: - std::string name_; + std::string id_; ValueType type_; - bool timeDependent_ = true; // optional at construction - bool scenarioDependent_ = true; // optional at construction + TimeDependent timeDependent_ = TimeDependent::YES; // optional at construction + ScenarioDependent scenarioDependent_ = ScenarioDependent::YES; // optional at construction }; } // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/port.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/port.h index ddf89277cd..da8dc3d99f 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/port.h +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/port.h @@ -30,11 +30,18 @@ namespace Antares::Solver::ObjectModel class Port { public: - Port(); - ~Port() = default; + const std::string& Id() const + { + return id_; + } + + PortType Type() const + { + return type_; + } private: - std::string name_; + std::string id_; PortType type_; }; diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/portField.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/portField.h index 4484f62230..78325db1af 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/portField.h +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/portField.h @@ -27,8 +27,19 @@ namespace Antares::Solver::ObjectModel class PortField { +public: + explicit PortField(const std::string& id): + id_(id) + { + } + + const std::string& Id() const + { + return id_; + } + private: - std::string name; + std::string id_; }; } // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/portType.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/portType.h index 662cbb7041..8fbfb15dca 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/portType.h +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/portType.h @@ -31,8 +31,29 @@ namespace Antares::Solver::ObjectModel class PortType { public: - PortType(); - ~PortType() = default; + PortType(const std::string& id, + const std::string& description, + std::vector&& fields): + id_(id), + description_(description), + fields_(std::move(fields)) + { + } + + const std::string& Id() const + { + return id_; + } + + const std::string& Description() const + { + return description_; + } + + const std::vector& Fields() const + { + return fields_; + } private: std::string id_; diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/variable.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/variable.h index 51665508ed..44d5762b1d 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/variable.h +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/variable.h @@ -33,11 +33,36 @@ namespace Antares::Solver::ObjectModel class Variable { public: - Variable(); - ~Variable() = default; + Variable(std::string id, Expression lower_bound, Expression upper_bound, ValueType type): + id_(std::move(id)), + type_(type), + lowerBound_(lower_bound), + upperBound_(upper_bound) + { + } + + const std::string& Id() const + { + return id_; + } + + ValueType Type() const + { + return type_; + } + + Expression LowerBound() const + { + return lowerBound_; + } + + Expression UpperBound() const + { + return upperBound_; + } private: - std::string name_; + std::string id_; ValueType type_; Expression lowerBound_; Expression upperBound_; diff --git a/src/solver/libModelObject/library.cpp b/src/solver/libModelObject/library.cpp new file mode 100644 index 0000000000..c531cd223d --- /dev/null +++ b/src/solver/libModelObject/library.cpp @@ -0,0 +1,101 @@ +/* + * 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/libObjectModel/library.h" + +#include +#include +#include +#include + +namespace Antares::Solver::ObjectModel +{ + +/** + * \brief Sets the ID of the library. + * + * \param id The ID to set. + * \return Reference to the LibraryBuilder object. + */ +LibraryBuilder& LibraryBuilder::withId(const std::string& id) +{ + library_.id_ = id; + return *this; +} + +/** + * \brief Sets the description of the library. + * + * \param description The description to set. + * \return Reference to the LibraryBuilder object. + */ +LibraryBuilder& LibraryBuilder::withDescription(const std::string& description) +{ + library_.description_ = description; + return *this; +} + +/** + * \brief Sets the port types of the library. + * + * \param portTypes A vector of PortType objects to set. + * \return Reference to the LibraryBuilder object. + * + * inputs it not garanteed to be valid after the call + */ +LibraryBuilder& LibraryBuilder::withPortTypes(std::vector&& portTypes) +{ + std::transform(portTypes.begin(), + portTypes.end(), + std::inserter(library_.portTypes_, library_.portTypes_.end()), + [](/*Non const to prevent copy*/ PortType& portType) + { return std::make_pair(portType.Id(), std::move(portType)); }); + return *this; +} + +/** + * \brief Sets the models of the library. + * + * \param models A vector of Model objects to set. + * \return Reference to the LibraryBuilder object. + * + * inputs it not garanteed to be valid after the call + */ +LibraryBuilder& LibraryBuilder::withModels(std::vector&& models) +{ + std::transform(models.begin(), + models.end(), + std::inserter(library_.models_, library_.models_.end()), + [](/*Non const to prevent copy*/ Model& model) + { return std::make_pair(model.Id(), std::move(model)); }); + return *this; +} + +/** + * \brief Returns the Library object. + * + * \return The constructed Library object. + */ +Library LibraryBuilder::build() +{ + return library_; +} +} // namespace Antares::Solver::ObjectModel diff --git a/src/solver/libModelObject/model.cpp b/src/solver/libModelObject/model.cpp index 19378317f8..bfb79e6882 100644 --- a/src/solver/libModelObject/model.cpp +++ b/src/solver/libModelObject/model.cpp @@ -19,14 +19,120 @@ ** along with Antares_Simulator. If not, see . */ +#include +#include +#include +#include + #include namespace Antares::Solver::ObjectModel { -std::vector getConstraints() +/** + * \brief Builds and returns the Model object. + * + * \return The constructed Model object. + */ +Model ModelBuilder::build() +{ + return model_; +} + +/** + * \brief Sets the ID of the model. + * + * \param id The ID to set. + * \return Reference to the ModelBuilder object. + */ +ModelBuilder& ModelBuilder::withId(std::string_view id) +{ + model_.id_ = id; + return *this; +} + +/** + * \brief Sets the objective of the model. + * + * \param objective The Expression object representing the objective. + * \return Reference to the ModelBuilder object. + */ +ModelBuilder& ModelBuilder::withObjective(Expression objective) +{ + model_.objective_ = objective; + return *this; +} + +/** + * \brief Sets the parameters of the model. + * + * \param parameters A vector of Parameter objects to set. + * \return Reference to the ModelBuilder object. + * + * inputs it not garanteed to be valid after the call + */ +ModelBuilder& ModelBuilder::withParameters(std::vector&& parameters) +{ + std::transform(parameters.begin(), + parameters.end(), + std::inserter(model_.parameters_, model_.parameters_.end()), + [](/*Non const to prevent copy*/ Parameter& parameter) + { return std::make_pair(parameter.Id(), std::move(parameter)); }); + return *this; +} + +/** + * \brief Sets the variables of the model. + * + * \param variables A vector of Variable objects to set. + * \return Reference to the ModelBuilder object. + * + * inputs it not garanteed to be valid after the call + */ +ModelBuilder& ModelBuilder::withVariables(std::vector&& variables) +{ + std::transform(variables.begin(), + variables.end(), + std::inserter(model_.variables_, model_.variables_.end()), + [](/*Non const to prevent copy*/ Variable& variable) + { return std::make_pair(variable.Id(), std::move(variable)); }); + return *this; +} + +/** + * \brief Sets the ports of the model. + * + * \param ports A vector of Port objects to set. + * \return Reference to the ModelBuilder object. + * + * inputs it not garanteed to be valid after the call + */ +ModelBuilder& ModelBuilder::withPorts(std::vector&& ports) +{ + std::transform(ports.begin(), + ports.end(), + std::inserter(model_.ports_, model_.ports_.end()), + [](/*Non const to prevent copy*/ Port& port) + { return std::make_pair(port.Id(), std::move(port)); }); + return *this; +} + +/** + * \brief Sets the ID of the library. + * + * \param id The ID to set. + * \return Reference to the LibraryBuilder object. + * + * inputs it not garanteed to be valid after the call + */ +ModelBuilder& ModelBuilder::withConstraints(std::vector&& constraints) { - return std::vector(); + std::transform(constraints.begin(), + constraints.end(), + std::inserter(model_.constraints_, model_.constraints_.end()), + [](/*Non const to prevent copy*/ Constraint& constraint) + { return std::make_pair(constraint.Id(), std::move(constraint)); }); + return *this; } } // namespace Antares::Solver::ObjectModel diff --git a/src/solver/modelConverter/CMakeLists.txt b/src/solver/modelConverter/CMakeLists.txt new file mode 100644 index 0000000000..d679c3f7ff --- /dev/null +++ b/src/solver/modelConverter/CMakeLists.txt @@ -0,0 +1,25 @@ +set(SOURCES + modelConverter.cpp + include/antares/solver/modelConverter/modelConverter.h +) + +# Create the library +add_library(modelConverter STATIC ${SOURCES}) +add_library(Antares::modelConverter ALIAS modelConverter) + +# Specify include directories +target_include_directories(modelConverter + PUBLIC + $ +) + +# Link dependencies (if any) +target_link_libraries(modelConverter + PRIVATE + Antares::antares-solver-libObjectModel + Antares::modelParser +) + +install(DIRECTORY include/antares + DESTINATION "include" +) \ No newline at end of file diff --git a/src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h b/src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h new file mode 100644 index 0000000000..4d2212b749 --- /dev/null +++ b/src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h @@ -0,0 +1,41 @@ + +/* + * 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 + +namespace Antares::Solver +{ +namespace ObjectModel +{ +class Library; +} + +namespace ModelParser +{ +class Library; +} +} // namespace Antares::Solver + +namespace Antares::Solver::ModelConverter +{ +Antares::Solver::ObjectModel::Library convert(const Antares::Solver::ModelParser::Library& library); +} diff --git a/src/solver/modelConverter/modelConverter.cpp b/src/solver/modelConverter/modelConverter.cpp new file mode 100644 index 0000000000..82cab77b92 --- /dev/null +++ b/src/solver/modelConverter/modelConverter.cpp @@ -0,0 +1,211 @@ +/* + * 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/modelConverter/modelConverter.h" + +#include + +#include "antares/solver/libObjectModel/constraint.h" +#include "antares/solver/libObjectModel/library.h" +#include "antares/solver/libObjectModel/model.h" +#include "antares/solver/libObjectModel/parameter.h" +#include "antares/solver/libObjectModel/port.h" +#include "antares/solver/libObjectModel/portType.h" +#include "antares/solver/libObjectModel/variable.h" +#include "antares/solver/modelParser/Library.h" + +namespace Antares::Solver::ModelConverter +{ + +/** + * \brief Converts parameters from ModelParser::Model to ObjectModel::Parameter. + * + * \param model The ModelParser::Model object containing parameters. + * \return A vector of ObjectModel::Parameter objects. + */ +std::vector convertTypes( + const Antares::Solver::ModelParser::Library& library) +{ + // Convert portTypes to Antares::Solver::ObjectModel::PortType + std::vector out; + for (const auto& portType: library.port_types) + { + std::vector fields; + for (const auto& field: portType.fields) + { + fields.emplace_back(Antares::Solver::ObjectModel::PortField{field}); + } + Antares::Solver::ObjectModel::PortType portTypeModel(portType.id, + portType.description, + std::move(fields)); + out.emplace_back(std::move(portTypeModel)); + } + return out; +} + +/** + * \brief Converts a ModelParser::ValueType to an ObjectModel::ValueType. + * + * \param type The ModelParser::ValueType to convert. + * \return The corresponding ObjectModel::ValueType. + * \throws std::runtime_error if the type is unknown. + */ +std::vector convertParameters( + const Antares::Solver::ModelParser::Model& model) +{ + std::vector parameters; + for (const auto& parameter: model.parameters) + { + parameters.emplace_back(Antares::Solver::ObjectModel::Parameter{ + parameter.id, + Antares::Solver::ObjectModel::ValueType::FLOAT, // TODO: change to correct type + static_cast( + parameter.time_dependent), + static_cast( + parameter.scenario_dependent)}); + } + return parameters; +} + +/** + * \brief Converts variables from ModelParser::Model to ObjectModel::Variable. + * + * \param model The ModelParser::Model object containing variables. + * \return A vector of ObjectModel::Variable objects. + */ +Antares::Solver::ObjectModel::ValueType convertType(Antares::Solver::ModelParser::ValueType type) +{ + using namespace std::string_literals; + switch (type) + { + case Antares::Solver::ModelParser::ValueType::FLOAT: + return Antares::Solver::ObjectModel::ValueType::FLOAT; + case Antares::Solver::ModelParser::ValueType::INTEGER: + return Antares::Solver::ObjectModel::ValueType::INTEGER; + case Antares::Solver::ModelParser::ValueType::BOOL: + return Antares::Solver::ObjectModel::ValueType::BOOL; + default: + throw std::runtime_error("Unknown type: " + Antares::Solver::ModelParser::toString(type)); + } +} + +/** + * \brief Converts ports from ModelParser::Model to ObjectModel::Port. + * + * \param model The ModelParser::Model object containing ports. + * \return A vector of ObjectModel::Port objects. + */ +std::vector convertVariables( + const Antares::Solver::ModelParser::Model& model) +{ + std::vector variables; + for (const auto& variable: model.variables) + { + variables.emplace_back(Antares::Solver::ObjectModel::Variable{ + variable.id, + Antares::Solver::ObjectModel::Expression{variable.lower_bound}, + Antares::Solver::ObjectModel::Expression{variable.upper_bound}, + convertType(variable.variable_type)}); + } + return variables; +} + +/** + * \brief Converts constraints from ModelParser::Model to ObjectModel::Constraint. + * + * \param model The ModelParser::Model object containing constraints. + * \return A vector of ObjectModel::Constraint objects. + */ +std::vector convertPorts( + const Antares::Solver::ModelParser::Model& model) +{ + std::vector ports; + for (const auto& port: model.ports) + { + // ports.emplace_back(Antares::Solver::ObjectModel::Port{port.name, port.type}); + } + return ports; +} + +std::vector convertConstraints( + const Antares::Solver::ModelParser::Model& model) +{ + std::vector constraints; + for (const auto& constraint: model.constraints) + { + constraints.emplace_back(Antares::Solver::ObjectModel::Constraint{ + constraint.id, + Antares::Solver::ObjectModel::Expression{constraint.expression}}); + } + return constraints; +} + +/** + * \brief Converts models from ModelParser::Library to ObjectModel::Model. + * + * \param library The ModelParser::Library object containing models. + * \return A vector of ObjectModel::Model objects. + */ +std::vector convertModels( + const Antares::Solver::ModelParser::Library& library) +{ + std::vector models; + for (const auto& model: library.models) + { + Antares::Solver::ObjectModel::ModelBuilder modelBuilder; + std::vector parameters = convertParameters(model); + std::vector variables = convertVariables(model); + std::vector ports = convertPorts(model); + std::vector constraints = convertConstraints( + model); + + auto modelObj = modelBuilder.withId(model.id) + .withObjective(Antares::Solver::ObjectModel::Expression{model.objective}) + .withParameters(std::move(parameters)) + .withVariables(std::move(variables)) + .withPorts(std::move(ports)) + .withConstraints(std::move(constraints)) + .build(); + models.emplace_back(std::move(modelObj)); + } + return models; +} + +/** + * \brief Converts a ModelParser::Library object to an ObjectModel::Library object. + * + * \param library The ModelParser::Library object to convert. + * \return The corresponding ObjectModel::Library object. + */ +Antares::Solver::ObjectModel::Library convert(const Antares::Solver::ModelParser::Library& library) +{ + Antares::Solver::ObjectModel::LibraryBuilder builder; + std::vector portTypes = convertTypes(library); + std::vector models = convertModels(library); + Antares::Solver::ObjectModel::Library lib = builder.withId(library.id) + .withDescription(library.description) + .withPortTypes(std::move(portTypes)) + .withModels(std::move(models)) + .build(); + return lib; +} + +} // namespace Antares::Solver::ModelConverter diff --git a/src/solver/modelParser/CMakeLists.txt b/src/solver/modelParser/CMakeLists.txt index efc5baca38..1881ba78fa 100644 --- a/src/solver/modelParser/CMakeLists.txt +++ b/src/solver/modelParser/CMakeLists.txt @@ -2,7 +2,7 @@ find_package(yaml-cpp REQUIRED) set(SOURCES parser.cpp - #encoders.hxx + encoders.hxx include/antares/solver/modelParser/parser.h ) diff --git a/src/solver/modelParser/encoders.hxx b/src/solver/modelParser/encoders.hxx index 61e22e9bc9..940cc9ac88 100644 --- a/src/solver/modelParser/encoders.hxx +++ b/src/solver/modelParser/encoders.hxx @@ -22,7 +22,7 @@ #pragma once -#include "antares/solver/modelParser/model.h" +#include "antares/solver/modelParser/Library.h" #include "yaml-cpp/yaml.h" @@ -38,13 +38,42 @@ struct convert { return false; } - rhs.name = node["name"].as(); + rhs.id = node["id"].as(); rhs.time_dependent = node["time-dependent"].as(); rhs.scenario_dependent = node["scenario-dependent"].as(); return true; } }; +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::ModelParser::ValueType& rhs) + { + if (!node.IsScalar()) + { + return false; + } + if (node.as() == "FLOAT") + { + rhs = Antares::Solver::ModelParser::ValueType::FLOAT; + } + else if (node.as() == "INTEGER") + { + rhs = Antares::Solver::ModelParser::ValueType::INTEGER; + } + else if (node.as() == "BOOL") + { + rhs = Antares::Solver::ModelParser::ValueType::BOOL; + } + else + { + return false; + } + return true; + } +}; + template<> struct convert { @@ -54,9 +83,11 @@ struct convert { return false; } - rhs.name = node["name"].as(); - rhs.lower_bound = node["lower-bound"].as(); - rhs.upper_bound = node["upper-bound"].as(); + rhs.id = node["id"].as(); + rhs.lower_bound = node["lower-bound"].as(); + rhs.upper_bound = node["upper-bound"].as(); + rhs.variable_type = node["variable-type"].as( + Antares::Solver::ModelParser::ValueType::FLOAT); return true; } }; @@ -70,7 +101,7 @@ struct convert { return false; } - rhs.name = node["name"].as(); + rhs.id = node["id"].as(); rhs.type = node["type"].as(); return true; } @@ -101,7 +132,7 @@ struct convert { return false; } - rhs.name = node["name"].as(); + rhs.id = node["id"].as(); rhs.expression = node["expression"].as(); return true; } @@ -117,7 +148,7 @@ struct convert return false; } rhs.id = node["id"].as(); - rhs.description = node["description"].as(); + rhs.description = node["description"].as(""); rhs.parameters = node["parameters"] .as>(); rhs.variables = node["variables"].as>(); @@ -142,10 +173,10 @@ struct convert return false; } rhs.id = node["id"].as(); - rhs.description = node["description"].as(); + rhs.description = node["description"].as(""); for (const auto& field: node["fields"]) { - rhs.fields.push_back(field["name"].as()); + rhs.fields.push_back(field["id"].as()); } return true; } @@ -157,7 +188,7 @@ struct convert static bool decode(const Node& node, Antares::Solver::ModelParser::Library& rhs) { rhs.id = node["id"].as(); - rhs.description = node["description"].as(); + rhs.description = node["description"].as(""); rhs.port_types = node["port-types"] .as>(); rhs.models = node["models"].as>(); diff --git a/src/solver/modelParser/include/antares/solver/modelParser/model.h b/src/solver/modelParser/include/antares/solver/modelParser/Library.h similarity index 66% rename from src/solver/modelParser/include/antares/solver/modelParser/model.h rename to src/solver/modelParser/include/antares/solver/modelParser/Library.h index 44b15584f5..d806cb1c3f 100644 --- a/src/solver/modelParser/include/antares/solver/modelParser/model.h +++ b/src/solver/modelParser/include/antares/solver/modelParser/Library.h @@ -21,6 +21,7 @@ */ #pragma once +#include #include #include @@ -29,21 +30,66 @@ namespace Antares::Solver::ModelParser // Define structures struct Parameter { - std::string name; + std::string id; bool time_dependent; bool scenario_dependent; }; +enum class ValueType +{ + FLOAT, + INTEGER, + BOOL +}; + +inline std::string toString(const ValueType& value_type) +{ + using namespace std::string_literals; + switch (value_type) + { + case ValueType::FLOAT: + return "FLOAT"s; + case ValueType::INTEGER: + return "INTEGER"s; + case ValueType::BOOL: + return "BOOL"s; + default: + return "UNKNOWN"s; + } +} + +inline std::ostream& operator<<(std::ostream& os, const ValueType& value_type) +{ + using namespace std::string_literals; + switch (value_type) + { + case ValueType::FLOAT: + os << "FLOAT"s; + break; + case ValueType::INTEGER: + os << "INTEGER"s; + break; + case ValueType::BOOL: + os << "BOOL"s; + break; + default: + os << "UNKNOWN"s; + break; + } + return os; +} + struct Variable { - std::string name; - double lower_bound; - double upper_bound; + std::string id; + std::string lower_bound; + std::string upper_bound; + ValueType variable_type; }; struct Port { - std::string name; + std::string id; std::string type; }; @@ -56,7 +102,7 @@ struct PortFieldDefinition struct Constraint { - std::string name; + std::string id; std::string expression; }; diff --git a/src/solver/modelParser/include/antares/solver/modelParser/parser.h b/src/solver/modelParser/include/antares/solver/modelParser/parser.h index 1447af9f2b..0c042ce027 100644 --- a/src/solver/modelParser/include/antares/solver/modelParser/parser.h +++ b/src/solver/modelParser/include/antares/solver/modelParser/parser.h @@ -21,7 +21,7 @@ */ #pragma once -#include "antares/solver/modelParser/model.h" +#include "antares/solver/modelParser/Library.h" namespace Antares::Solver::ModelParser { diff --git a/src/solver/modelParser/parser.cpp b/src/solver/modelParser/parser.cpp index f4c1f9e515..13d1b120eb 100644 --- a/src/solver/modelParser/parser.cpp +++ b/src/solver/modelParser/parser.cpp @@ -21,7 +21,7 @@ #include "antares/solver/modelParser/parser.h" -#include "antares/solver/modelParser/model.h" +#include "antares/solver/modelParser/Library.h" #include "encoders.hxx" diff --git a/src/tests/src/solver/modelParser/CMakeLists.txt b/src/tests/src/solver/modelParser/CMakeLists.txt index 11123853b0..fc65d70e93 100644 --- a/src/tests/src/solver/modelParser/CMakeLists.txt +++ b/src/tests/src/solver/modelParser/CMakeLists.txt @@ -1,6 +1,7 @@ # Add source files set(SOURCE_FILES testModelParser.cpp + testModelTranslator.cpp ) # Add executable @@ -10,7 +11,9 @@ add_executable(TestModelParser ${SOURCE_FILES}) target_link_libraries(TestModelParser PRIVATE Boost::unit_test_framework + Antares::modelConverter Antares::modelParser + Antares::antares-solver-libObjectModel ) # Storing test-toybox under the folder Unit-tests in the IDE diff --git a/src/tests/src/solver/modelParser/testModelParser.cpp b/src/tests/src/solver/modelParser/testModelParser.cpp index dff40144fb..9e94dd2d52 100644 --- a/src/tests/src/solver/modelParser/testModelParser.cpp +++ b/src/tests/src/solver/modelParser/testModelParser.cpp @@ -30,7 +30,7 @@ using namespace std::string_literals; // Test empty library -BOOST_AUTO_TEST_CASE(test_empty_library) +BOOST_AUTO_TEST_CASE(EmpyLibrary_is_valid) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(test_empty_library) } // Test library with id and description -BOOST_AUTO_TEST_CASE(test_library_id_description) +BOOST_AUTO_TEST_CASE(library_id_and_description_parsed_properly) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -61,12 +61,10 @@ BOOST_AUTO_TEST_CASE(test_library_id_description) Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); BOOST_CHECK_EQUAL(libraryObj.id, "test_id"); BOOST_CHECK_EQUAL(libraryObj.description, "test_description"); - BOOST_CHECK(libraryObj.port_types.empty()); - BOOST_CHECK(libraryObj.models.empty()); } // Test library with port types -BOOST_AUTO_TEST_CASE(test_library_port_types) +BOOST_AUTO_TEST_CASE(port_types_properly_parsed) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -77,7 +75,7 @@ BOOST_AUTO_TEST_CASE(test_library_port_types) - id: "porttype_id" description: "porttype_description" fields: - - name: "port_name" + - id: "port_name" models: [] )"s; Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); @@ -89,7 +87,7 @@ BOOST_AUTO_TEST_CASE(test_library_port_types) } // Test library with multiple port types -BOOST_AUTO_TEST_CASE(test_library_multiple_port_types) +BOOST_AUTO_TEST_CASE(library_can_contain_multiple_port_types) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -100,11 +98,11 @@ BOOST_AUTO_TEST_CASE(test_library_multiple_port_types) - id: "porttype_id1" description: "porttype_description1" fields: - - name: "port_name1" + - id: "port_name1" - id: "porttype_id2" description: "porttype_description2" fields: - - name: "port_name2" + - id: "port_name2" models: [] )"s; Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); @@ -120,7 +118,7 @@ BOOST_AUTO_TEST_CASE(test_library_multiple_port_types) } // Test library with models -BOOST_AUTO_TEST_CASE(test_library_models) +BOOST_AUTO_TEST_CASE(models_properly_parsed) { Antares::Solver::ModelParser::Parser parser; const std::string library = R"( @@ -152,7 +150,7 @@ BOOST_AUTO_TEST_CASE(test_library_models) } // Test library with multiple models -BOOST_AUTO_TEST_CASE(test_library_multiple_models) +BOOST_AUTO_TEST_CASE(library_can_contain_multiple_models) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -189,7 +187,7 @@ BOOST_AUTO_TEST_CASE(test_library_multiple_models) } // Test library with one model containing parameters -BOOST_AUTO_TEST_CASE(test_library_model_parameters) +BOOST_AUTO_TEST_CASE(parameters_properly_parsed) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -201,7 +199,7 @@ BOOST_AUTO_TEST_CASE(test_library_model_parameters) - id: "model_id" description: "model_description" parameters: - - name: "param_name" + - id: "param_name" time-dependent: false scenario-dependent: false variables: [] @@ -213,13 +211,13 @@ BOOST_AUTO_TEST_CASE(test_library_model_parameters) Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); BOOST_REQUIRE_EQUAL(libraryObj.models[0].parameters.size(), 1); - BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].name, "param_name"); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].id, "param_name"); BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].time_dependent, false); BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].scenario_dependent, false); } // Test library with one model containing multiple parameters -BOOST_AUTO_TEST_CASE(test_library_model_multiple_parameters) +BOOST_AUTO_TEST_CASE(model_can_contain_multiple_parameters) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -231,10 +229,10 @@ BOOST_AUTO_TEST_CASE(test_library_model_multiple_parameters) - id: "model_id" description: "model_description" parameters: - - name: "param_name1" + - id: "param_name1" time-dependent: false scenario-dependent: false - - name: "param_name2" + - id: "param_name2" time-dependent: true scenario-dependent: true variables: [] @@ -246,16 +244,16 @@ BOOST_AUTO_TEST_CASE(test_library_model_multiple_parameters) Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); BOOST_REQUIRE_EQUAL(libraryObj.models[0].parameters.size(), 2); - BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].name, "param_name1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].id, "param_name1"); BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].time_dependent, false); BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[0].scenario_dependent, false); - BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[1].name, "param_name2"); + BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[1].id, "param_name2"); BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[1].time_dependent, true); BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[1].scenario_dependent, true); } // Test library with one model containing variables -BOOST_AUTO_TEST_CASE(test_library_model_variables) +BOOST_AUTO_TEST_CASE(variables_properly_parsed) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -268,7 +266,7 @@ BOOST_AUTO_TEST_CASE(test_library_model_variables) description: "model_description" parameters: [] variables: - - name: "var_name" + - id: "var_name" lower-bound: 0 upper-bound: 1 ports: [] @@ -279,13 +277,13 @@ BOOST_AUTO_TEST_CASE(test_library_model_variables) Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); BOOST_REQUIRE_EQUAL(libraryObj.models[0].variables.size(), 1); - BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].name, "var_name"); - BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].lower_bound, 0); - BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].upper_bound, 1); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].id, "var_name"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].lower_bound, "0"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].upper_bound, "1"); } // Test library with one model containing multiple variables -BOOST_AUTO_TEST_CASE(test_library_model_multiple_variables) +BOOST_AUTO_TEST_CASE(model_can_contain_multiple_variables) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -298,10 +296,10 @@ BOOST_AUTO_TEST_CASE(test_library_model_multiple_variables) description: "model_description" parameters: [] variables: - - name: "var_name1" + - id: "var_name1" lower-bound: 0 upper-bound: 1 - - name: "var_name2" + - id: "var_name2" lower-bound: -1 upper-bound: 2 ports: [] @@ -312,16 +310,90 @@ BOOST_AUTO_TEST_CASE(test_library_model_multiple_variables) Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); BOOST_REQUIRE_EQUAL(libraryObj.models[0].variables.size(), 2); - BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].name, "var_name1"); - BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].lower_bound, 0); - BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].upper_bound, 1); - BOOST_CHECK_EQUAL(libraryObj.models[0].variables[1].name, "var_name2"); - BOOST_CHECK_EQUAL(libraryObj.models[0].variables[1].lower_bound, -1); - BOOST_CHECK_EQUAL(libraryObj.models[0].variables[1].upper_bound, 2); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].id, "var_name1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].lower_bound, "0"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].upper_bound, "1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[1].id, "var_name2"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[1].lower_bound, "-1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[1].upper_bound, "2"); +} + +// variable bounds are strings expressions +BOOST_AUTO_TEST_CASE(variables_bounds_are_literals) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: [] + variables: + - id: "var_name" + lower-bound: "near-zero" + upper-bound: "pmax" + ports: [] + port-field-definitions: [] + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].id, "var_name"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].lower_bound, "near-zero"); + BOOST_CHECK_EQUAL(libraryObj.models[0].variables[0].upper_bound, "pmax"); +} + +// variable variable-type +BOOST_AUTO_TEST_CASE(variable_types_can_be_integer_bool_float_default_to_float) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: [] + variables: + - id: "var1" + lower-bound: 0 + upper-bound: 1 + variable-type: "BOOL" + - id: "var2" + lower-bound: 0 + upper-bound: 1 + variable-type: "INTEGER" + - id: "var3" + lower-bound: 0 + upper-bound: 1 + variable-type: "FLOAT" + - id: "var4" + lower-bound: 0 + upper-bound: 1 + ports: [] + port-field-definitions: [] + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + auto& model = libraryObj.models[0]; + auto& var1 = model.variables[0]; + auto& var2 = model.variables[1]; + auto& var3 = model.variables[2]; + auto& var4 = model.variables[3]; + BOOST_CHECK_EQUAL(var1.variable_type, Antares::Solver::ModelParser::ValueType::BOOL); + BOOST_CHECK_EQUAL(var2.variable_type, Antares::Solver::ModelParser::ValueType::INTEGER); + BOOST_CHECK_EQUAL(var3.variable_type, Antares::Solver::ModelParser::ValueType::FLOAT); + BOOST_CHECK_EQUAL(var4.variable_type, Antares::Solver::ModelParser::ValueType::FLOAT); } // Test library with one model containing ports -BOOST_AUTO_TEST_CASE(test_library_model_ports) +BOOST_AUTO_TEST_CASE(ports_are_properly_parsed) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -335,7 +407,7 @@ BOOST_AUTO_TEST_CASE(test_library_model_ports) parameters: [] variables: [] ports: - - name: "port_name" + - id: "port_name" type: "port_type" port-field-definitions: [] constraints: [] @@ -344,12 +416,12 @@ BOOST_AUTO_TEST_CASE(test_library_model_ports) Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); BOOST_REQUIRE_EQUAL(libraryObj.models[0].ports.size(), 1); - BOOST_CHECK_EQUAL(libraryObj.models[0].ports[0].name, "port_name"); + BOOST_CHECK_EQUAL(libraryObj.models[0].ports[0].id, "port_name"); BOOST_CHECK_EQUAL(libraryObj.models[0].ports[0].type, "port_type"); } // Test library with one model containing multiple ports -BOOST_AUTO_TEST_CASE(test_library_model_multiple_ports) +BOOST_AUTO_TEST_CASE(model_can_conatin_multiple_ports) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -363,9 +435,9 @@ BOOST_AUTO_TEST_CASE(test_library_model_multiple_ports) parameters: [] variables: [] ports: - - name: "port_name1" + - id: "port_name1" type: "port_type1" - - name: "port_name2" + - id: "port_name2" type: "port_type2" port-field-definitions: [] constraints: [] @@ -374,14 +446,14 @@ BOOST_AUTO_TEST_CASE(test_library_model_multiple_ports) Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); BOOST_REQUIRE_EQUAL(libraryObj.models[0].ports.size(), 2); - BOOST_CHECK_EQUAL(libraryObj.models[0].ports[0].name, "port_name1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].ports[0].id, "port_name1"); BOOST_CHECK_EQUAL(libraryObj.models[0].ports[0].type, "port_type1"); - BOOST_CHECK_EQUAL(libraryObj.models[0].ports[1].name, "port_name2"); + BOOST_CHECK_EQUAL(libraryObj.models[0].ports[1].id, "port_name2"); BOOST_CHECK_EQUAL(libraryObj.models[0].ports[1].type, "port_type2"); } // Test library with one model containing port field definitions -BOOST_AUTO_TEST_CASE(test_library_model_port_field_definitions) +BOOST_AUTO_TEST_CASE(model_port_fileds_properly_parsed) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -411,7 +483,7 @@ BOOST_AUTO_TEST_CASE(test_library_model_port_field_definitions) } // Test library with one model containing multiple port field definitions -BOOST_AUTO_TEST_CASE(test_library_model_multiple_port_field_definitions) +BOOST_AUTO_TEST_CASE(model_can_contain_multiple_portfields) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -447,7 +519,7 @@ BOOST_AUTO_TEST_CASE(test_library_model_multiple_port_field_definitions) } // Test library with one model containing constraints -BOOST_AUTO_TEST_CASE(test_library_model_constraints) +BOOST_AUTO_TEST_CASE(constraints_properly_parsed) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -463,19 +535,19 @@ BOOST_AUTO_TEST_CASE(test_library_model_constraints) ports: [] port-field-definitions: [] constraints: - - name: "constraint_name" + - id: "constraint_name" expression: "expression" objective: "objective" )"s; Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); BOOST_REQUIRE_EQUAL(libraryObj.models[0].constraints.size(), 1); - BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[0].name, "constraint_name"); + BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[0].id, "constraint_name"); BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[0].expression, "expression"); } // Test library with one model containing multiple constraints -BOOST_AUTO_TEST_CASE(test_library_model_multiple_constraints) +BOOST_AUTO_TEST_CASE(model_can_contain_multiple_constraints) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( @@ -491,23 +563,23 @@ BOOST_AUTO_TEST_CASE(test_library_model_multiple_constraints) ports: [] port-field-definitions: [] constraints: - - name: "constraint_name1" + - id: "constraint_name1" expression: "expression1" - - name: "constraint_name2" + - id: "constraint_name2" expression: "expression2" objective: "objective" )"s; Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); BOOST_REQUIRE_EQUAL(libraryObj.models[0].constraints.size(), 2); - BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[0].name, "constraint_name1"); + BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[0].id, "constraint_name1"); BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[0].expression, "expression1"); - BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[1].name, "constraint_name2"); + BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[1].id, "constraint_name2"); BOOST_CHECK_EQUAL(libraryObj.models[0].constraints[1].expression, "expression2"); } // Test error when model is not a map -BOOST_AUTO_TEST_CASE(test_error_model_not_map) +BOOST_AUTO_TEST_CASE(model_is_not_scalar) { Antares::Solver::ModelParser::Parser parser; const auto library = R"( diff --git a/src/tests/src/solver/modelParser/testModelTranslator.cpp b/src/tests/src/solver/modelParser/testModelTranslator.cpp new file mode 100644 index 0000000000..b8a3149997 --- /dev/null +++ b/src/tests/src/solver/modelParser/testModelTranslator.cpp @@ -0,0 +1,270 @@ +/* + * 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 . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +#include "antares/solver/libObjectModel/library.h" +#include "antares/solver/modelConverter/modelConverter.h" +#include "antares/solver/modelParser/Library.h" + +using namespace Antares::Solver; + +namespace Antares::Solver::ObjectModel +{ +inline std::ostream& operator<<(std::ostream& os, const ValueType& value_type) +{ + using namespace std::string_literals; + switch (value_type) + { + case ValueType::FLOAT: + os << "FLOAT"s; + break; + case ValueType::INTEGER: + os << "INTEGER"s; + break; + case ValueType::BOOL: + os << "BOOL"s; + break; + default: + os << "UNKNOWN"s; + break; + } + return os; +} +} // namespace Antares::Solver::ObjectModel + +// Test empty library +BOOST_AUTO_TEST_CASE(Empty_library_is_valid) +{ + ModelParser::Library library; + ObjectModel::Library lib = ModelConverter::convert(library); + BOOST_CHECK(lib.Id().empty()); + BOOST_CHECK(lib.Description().empty()); + BOOST_CHECK(lib.PortTypes().empty()); + BOOST_CHECK(lib.Models().empty()); +} + +// Test library with id and description +BOOST_AUTO_TEST_CASE(library_id_description_properly_translated) +{ + ModelParser::Library library; + library.id = "test_id"; + library.description = "test_description"; + ObjectModel::Library lib = ModelConverter::convert(library); + BOOST_CHECK_EQUAL(lib.Id(), "test_id"); + BOOST_CHECK_EQUAL(lib.Description(), "test_description"); +} + +// Test library with port types +BOOST_AUTO_TEST_CASE(port_type_with_empty_fileds_properly_translated) +{ + ModelParser::Library library; + ModelParser::PortType portType1{"port1", "flow port", {}}; + ModelParser::PortType portType2{"port2", "impedance port", {}}; + library.port_types = {portType1, portType2}; + ObjectModel::Library lib = ModelConverter::convert(library); + BOOST_REQUIRE_EQUAL(lib.PortTypes().size(), 2); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port1").Id(), "port1"); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port1").Description(), "flow port"); + BOOST_CHECK(lib.PortTypes().at("port1").Fields().empty()); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port2").Id(), "port2"); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port2").Description(), "impedance port"); + BOOST_CHECK(lib.PortTypes().at("port2").Fields().empty()); +} + +// Test library with port types and fields +BOOST_AUTO_TEST_CASE(portType_with_fields_properly_translated) +{ + ModelParser::Library library; + ModelParser::PortType portType1{"port1", "flow port", {"field1", "field2"}}; + ModelParser::PortType portType2{"port2", "impedance port", {"field3", "field4"}}; + library.port_types = {portType1, portType2}; + ObjectModel::Library lib = ModelConverter::convert(library); + BOOST_REQUIRE_EQUAL(lib.PortTypes().at("port1").Fields().size(), 2); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port1").Fields()[0].Id(), "field1"); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port1").Fields()[1].Id(), "field2"); + BOOST_REQUIRE_EQUAL(lib.PortTypes().at("port2").Fields().size(), 2); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port2").Fields()[0].Id(), "field3"); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port2").Fields()[1].Id(), "field4"); +} + +// Test library with models +BOOST_AUTO_TEST_CASE(empty_model_properly_translated) +{ + ModelParser::Library library; + ModelParser::Model model1{.id = "model1", + .description = "description", + .parameters = {}, + .variables = {}, + .ports = {}, + .port_field_definitions = {}, + .constraints = {}, + .objective = "objectives"}; + library.models = {model1}; + ObjectModel::Library lib = ModelConverter::convert(library); + BOOST_REQUIRE_EQUAL(lib.Models().size(), 1); + BOOST_CHECK_EQUAL(lib.Models().at("model1").Id(), "model1"); + BOOST_CHECK_EQUAL(lib.Models().at("model1").Objective().Value(), "objectives"); +} + +// Test library with models and parameters +BOOST_AUTO_TEST_CASE(model_parameters_properly_translated) +{ + ModelParser::Library library; + ModelParser::Model model1{.id = "model1", + .description = "description", + .parameters = {{"param1", true, false}, {"param2", false, false}}, + .variables = {}, + .ports = {}, + .port_field_definitions{}, + .constraints{}, + .objective = "objectives"}; + library.models = {model1}; + ObjectModel::Library lib = ModelConverter::convert(library); + auto& model = lib.Models().at("model1"); + BOOST_REQUIRE_EQUAL(model.Parameters().size(), 2); + auto& parameter1 = model.Parameters().at("param1"); + auto& parameter2 = model.Parameters().at("param2"); + BOOST_CHECK_EQUAL(parameter1.Id(), "param1"); + BOOST_CHECK(parameter1.isTimeDependent()); + BOOST_CHECK(!parameter1.isScenarioDependent()); + BOOST_CHECK_EQUAL(parameter1.Type(), ObjectModel::ValueType::FLOAT); + BOOST_CHECK_EQUAL(parameter2.Id(), "param2"); + BOOST_CHECK(!parameter2.isTimeDependent()); + BOOST_CHECK(!parameter2.isScenarioDependent()); + BOOST_CHECK_EQUAL(parameter2.Type(), ObjectModel::ValueType::FLOAT); +} + +// Test library with models and variables +BOOST_AUTO_TEST_CASE(model_variables_properly_translated) +{ + ModelParser::Library library; + ModelParser::Model model1{ + .id = "model1", + .description = "description", + .parameters = {}, + .variables = {{"var1", "7", "pmax", ModelParser::ValueType::BOOL}, + {"var2", "99999999.9999999", "vcost", ModelParser::ValueType::INTEGER}}, + .ports = {}, + .port_field_definitions = {}, + .constraints = {}, + .objective = "objectives"}; + library.models = {model1}; + ObjectModel::Library lib = ModelConverter::convert(library); + auto& model = lib.Models().at("model1"); + BOOST_REQUIRE_EQUAL(model.Variables().size(), 2); + auto& variable1 = model.Variables().at("var1"); + auto& variable2 = model.Variables().at("var2"); + BOOST_CHECK_EQUAL(variable1.Id(), "var1"); + BOOST_CHECK_EQUAL(variable1.LowerBound().Value(), "7"); + BOOST_CHECK_EQUAL(variable1.UpperBound().Value(), "pmax"); + BOOST_CHECK_EQUAL(variable1.Type(), ObjectModel::ValueType::BOOL); + BOOST_CHECK_EQUAL(variable2.Id(), "var2"); + BOOST_CHECK_EQUAL(variable2.LowerBound().Value(), "99999999.9999999"); + BOOST_CHECK_EQUAL(variable2.UpperBound().Value(), "vcost"); + BOOST_CHECK_EQUAL(variable2.Type(), ObjectModel::ValueType::INTEGER); +} + +// Test library with models and ports +BOOST_AUTO_TEST_CASE(model_ports_properly_translated, *boost::unit_test::disabled()) +{ + ModelParser::Library library; + ModelParser::Model model1{.id = "model1", + .description = "description", + .parameters = {}, + .variables = {}, + .ports = {{"port1", "flow"}, {"port2", "impedance"}}, + .port_field_definitions = {}, + .constraints = {}, + .objective = "objectives"}; + library.models = {model1}; + ObjectModel::Library lib = ModelConverter::convert(library); + auto& model = lib.Models().at("model1"); + // BOOST_REQUIRE_EQUAL(model.Ports().size(), 2); + // auto& port1 = model.Ports().at("port1"); + // auto& port2 = model.Ports().at("port2"); + // BOOST_CHECK_EQUAL(port1.Name(), "port1"); + // BOOST_CHECK_EQUALS port1.Type() + // BOOST_CHECK_EQUAL(port2.Name(), "port2"); + // BOOST_CHECK_EQUALS port2.Type() +} + +// Test library with models and constraints +BOOST_AUTO_TEST_CASE(model_constraints_properly_translated) +{ + ModelParser::Library library; + ModelParser::Model model1{.id = "model1", + .description = "description", + .parameters = {}, + .variables = {}, + .ports = {}, + .port_field_definitions = {}, + .constraints = {{"constraint1", "expression1"}, + {"constraint2", "expression2"}}, + .objective = "objectives"}; + library.models = {model1}; + ObjectModel::Library lib = ModelConverter::convert(library); + auto& model = lib.Models().at("model1"); + BOOST_REQUIRE_EQUAL(model.getConstraints().size(), 2); + auto& constraint1 = model.getConstraints().at("constraint1"); + auto& constraint2 = model.getConstraints().at("constraint2"); + BOOST_CHECK_EQUAL(constraint1.Id(), "constraint1"); + BOOST_CHECK_EQUAL(constraint1.expression().Value(), "expression1"); + BOOST_CHECK_EQUAL(constraint2.Id(), "constraint2"); + BOOST_CHECK_EQUAL(constraint2.expression().Value(), "expression2"); +} + +// Test with 2 models +BOOST_AUTO_TEST_CASE(multiple_models_properly_translated) +{ + ModelParser::Library library; + ModelParser::Model model1{.id = "model1", + .description = "description", + .parameters = {{"param1", true, false}, {"param2", false, false}}, + .variables = {{"varP", "7", "pmin", ModelParser::ValueType::FLOAT}}, + .ports = {}, + .port_field_definitions = {}, + .constraints = {}, + .objective = "objectives"}; + ModelParser::Model model2{ + .id = "model2", + .description = "description", + .parameters = {}, + .variables = {{"var1", "7", "pmax", ModelParser::ValueType::BOOL}, + {"var2", "99999999.9999999", "vcost", ModelParser::ValueType::INTEGER}}, + .ports = {}, + .port_field_definitions = {}, + .constraints = {}, + .objective = "objectives"}; + library.models = {model1, model2}; + ObjectModel::Library lib = ModelConverter::convert(library); + BOOST_REQUIRE_EQUAL(lib.Models().size(), 2); + auto& modelo1 = lib.Models().at("model1"); + BOOST_REQUIRE_EQUAL(modelo1.Parameters().size(), 2); + BOOST_REQUIRE_EQUAL(modelo1.Variables().size(), 1); + auto& modelo2 = lib.Models().at("model2"); + BOOST_REQUIRE_EQUAL(modelo2.Parameters().size(), 0); + BOOST_REQUIRE_EQUAL(modelo2.Variables().size(), 2); +} From 6324724d404c146cc3c1adb13da5095fd8e8c06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20Mar=C3=A9chal?= <45510813+JasonMarechal25@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:37:30 +0200 Subject: [PATCH 031/103] [ANT-2206] default value for time/scenario dependant (#2447) Co-authored-by: Vincent Payet Co-authored-by: payetvin <113102157+payetvin@users.noreply.github.com> Co-authored-by: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Co-authored-by: Florian OMNES --- .../antares/solver/libObjectModel/valueType.h | 2 ++ src/solver/modelConverter/modelConverter.cpp | 2 +- src/solver/modelParser/encoders.hxx | 8 ++--- .../antares/solver/modelParser/Library.h | 10 +++--- .../solver/modelParser/testModelParser.cpp | 34 +++++++++++++++++-- .../modelParser/testModelTranslator.cpp | 24 ++++++++----- 6 files changed, 59 insertions(+), 21 deletions(-) diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/valueType.h b/src/solver/libModelObject/include/antares/solver/libObjectModel/valueType.h index feeac17b1e..d8921fb7dc 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/valueType.h +++ b/src/solver/libModelObject/include/antares/solver/libObjectModel/valueType.h @@ -19,6 +19,8 @@ ** along with Antares_Simulator. If not, see . */ #pragma once +#include +#include namespace Antares::Solver::ObjectModel { diff --git a/src/solver/modelConverter/modelConverter.cpp b/src/solver/modelConverter/modelConverter.cpp index 82cab77b92..a103c8fcd2 100644 --- a/src/solver/modelConverter/modelConverter.cpp +++ b/src/solver/modelConverter/modelConverter.cpp @@ -96,7 +96,7 @@ Antares::Solver::ObjectModel::ValueType convertType(Antares::Solver::ModelParser using namespace std::string_literals; switch (type) { - case Antares::Solver::ModelParser::ValueType::FLOAT: + case Antares::Solver::ModelParser::ValueType::CONTINUOUS: return Antares::Solver::ObjectModel::ValueType::FLOAT; case Antares::Solver::ModelParser::ValueType::INTEGER: return Antares::Solver::ObjectModel::ValueType::INTEGER; diff --git a/src/solver/modelParser/encoders.hxx b/src/solver/modelParser/encoders.hxx index 940cc9ac88..9d913b860a 100644 --- a/src/solver/modelParser/encoders.hxx +++ b/src/solver/modelParser/encoders.hxx @@ -39,8 +39,8 @@ struct convert return false; } rhs.id = node["id"].as(); - rhs.time_dependent = node["time-dependent"].as(); - rhs.scenario_dependent = node["scenario-dependent"].as(); + rhs.time_dependent = node["time-dependent"].as(true); + rhs.scenario_dependent = node["scenario-dependent"].as(true); return true; } }; @@ -56,7 +56,7 @@ struct convert } if (node.as() == "FLOAT") { - rhs = Antares::Solver::ModelParser::ValueType::FLOAT; + rhs = Antares::Solver::ModelParser::ValueType::CONTINUOUS; } else if (node.as() == "INTEGER") { @@ -87,7 +87,7 @@ struct convert rhs.lower_bound = node["lower-bound"].as(); rhs.upper_bound = node["upper-bound"].as(); rhs.variable_type = node["variable-type"].as( - Antares::Solver::ModelParser::ValueType::FLOAT); + Antares::Solver::ModelParser::ValueType::CONTINUOUS); return true; } }; diff --git a/src/solver/modelParser/include/antares/solver/modelParser/Library.h b/src/solver/modelParser/include/antares/solver/modelParser/Library.h index d806cb1c3f..77233a4a50 100644 --- a/src/solver/modelParser/include/antares/solver/modelParser/Library.h +++ b/src/solver/modelParser/include/antares/solver/modelParser/Library.h @@ -37,7 +37,7 @@ struct Parameter enum class ValueType { - FLOAT, + CONTINUOUS, INTEGER, BOOL }; @@ -47,8 +47,8 @@ inline std::string toString(const ValueType& value_type) using namespace std::string_literals; switch (value_type) { - case ValueType::FLOAT: - return "FLOAT"s; + case ValueType::CONTINUOUS: + return "CONTINUOUS"s; case ValueType::INTEGER: return "INTEGER"s; case ValueType::BOOL: @@ -63,8 +63,8 @@ inline std::ostream& operator<<(std::ostream& os, const ValueType& value_type) using namespace std::string_literals; switch (value_type) { - case ValueType::FLOAT: - os << "FLOAT"s; + case ValueType::CONTINUOUS: + os << "CONTINUOUS"s; break; case ValueType::INTEGER: os << "INTEGER"s; diff --git a/src/tests/src/solver/modelParser/testModelParser.cpp b/src/tests/src/solver/modelParser/testModelParser.cpp index 9e94dd2d52..ea59c9bbfa 100644 --- a/src/tests/src/solver/modelParser/testModelParser.cpp +++ b/src/tests/src/solver/modelParser/testModelParser.cpp @@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE(parameters_properly_parsed) description: "model_description" parameters: - id: "param_name" - time-dependent: false + time-dependent: FALSE scenario-dependent: false variables: [] ports: [] @@ -252,6 +252,34 @@ BOOST_AUTO_TEST_CASE(model_can_contain_multiple_parameters) BOOST_CHECK_EQUAL(libraryObj.models[0].parameters[1].scenario_dependent, true); } +// Time dependent and scenario dependant default value are true +BOOST_AUTO_TEST_CASE(test_library_model_parameters_default_values) +{ + Antares::Solver::ModelParser::Parser parser; + auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + description: "model_description" + parameters: + - id: "param_name" + variables: [] + ports: [] + port-field-definitions: [] + constraints: [] + objective: "objective" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_CHECK(libraryObj.models.size() == 1); + BOOST_CHECK(libraryObj.models[0].parameters.size() == 1); + BOOST_CHECK(libraryObj.models[0].parameters[0].id == "param_name"); + BOOST_CHECK(libraryObj.models[0].parameters[0].time_dependent == true); + BOOST_CHECK(libraryObj.models[0].parameters[0].scenario_dependent == true); +} + // Test library with one model containing variables BOOST_AUTO_TEST_CASE(variables_properly_parsed) { @@ -388,8 +416,8 @@ BOOST_AUTO_TEST_CASE(variable_types_can_be_integer_bool_float_default_to_float) auto& var4 = model.variables[3]; BOOST_CHECK_EQUAL(var1.variable_type, Antares::Solver::ModelParser::ValueType::BOOL); BOOST_CHECK_EQUAL(var2.variable_type, Antares::Solver::ModelParser::ValueType::INTEGER); - BOOST_CHECK_EQUAL(var3.variable_type, Antares::Solver::ModelParser::ValueType::FLOAT); - BOOST_CHECK_EQUAL(var4.variable_type, Antares::Solver::ModelParser::ValueType::FLOAT); + BOOST_CHECK_EQUAL(var3.variable_type, Antares::Solver::ModelParser::ValueType::CONTINUOUS); + BOOST_CHECK_EQUAL(var4.variable_type, Antares::Solver::ModelParser::ValueType::CONTINUOUS); } // Test library with one model containing ports diff --git a/src/tests/src/solver/modelParser/testModelTranslator.cpp b/src/tests/src/solver/modelParser/testModelTranslator.cpp index b8a3149997..bf203ae8ed 100644 --- a/src/tests/src/solver/modelParser/testModelTranslator.cpp +++ b/src/tests/src/solver/modelParser/testModelTranslator.cpp @@ -92,6 +92,13 @@ BOOST_AUTO_TEST_CASE(port_type_with_empty_fileds_properly_translated) BOOST_CHECK_EQUAL(lib.PortTypes().at("port2").Id(), "port2"); BOOST_CHECK_EQUAL(lib.PortTypes().at("port2").Description(), "impedance port"); BOOST_CHECK(lib.PortTypes().at("port2").Fields().empty()); + BOOST_REQUIRE_EQUAL(lib.PortTypes().size(), 2); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port1").Id(), "port1"); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port1").Description(), "flow port"); + BOOST_CHECK(lib.PortTypes().at("port1").Fields().empty()); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port2").Id(), "port2"); + BOOST_CHECK_EQUAL(lib.PortTypes().at("port2").Description(), "impedance port"); + BOOST_CHECK(lib.PortTypes().at("port2").Fields().empty()); } // Test library with port types and fields @@ -240,14 +247,15 @@ BOOST_AUTO_TEST_CASE(model_constraints_properly_translated) BOOST_AUTO_TEST_CASE(multiple_models_properly_translated) { ModelParser::Library library; - ModelParser::Model model1{.id = "model1", - .description = "description", - .parameters = {{"param1", true, false}, {"param2", false, false}}, - .variables = {{"varP", "7", "pmin", ModelParser::ValueType::FLOAT}}, - .ports = {}, - .port_field_definitions = {}, - .constraints = {}, - .objective = "objectives"}; + ModelParser::Model model1{ + .id = "model1", + .description = "description", + .parameters = {{"param1", true, false}, {"param2", false, false}}, + .variables = {{"varP", "7", "pmin", ModelParser::ValueType::CONTINUOUS}}, + .ports = {}, + .port_field_definitions = {}, + .constraints = {}, + .objective = "objectives"}; ModelParser::Model model2{ .id = "model2", .description = "description", From f21b708f300afc309a16ce6d5a0b90bde4ac0249 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:47:21 +0200 Subject: [PATCH 032/103] Modeler 1.1c: Scenarize problem filler [ANT-2003] (#2445) --- .../solver/modeler/api/linearProblemBuilder.h | 2 +- .../solver/modeler/api/linearProblemFiller.h | 31 ++++++++++-- .../modeler/api/linearProblemBuilder.cpp | 32 +++++++++++-- .../modeler/api/mock-fillers/FillerContext.h | 48 +++++++++++++++++++ .../api/mock-fillers/OneConstraintFiller.h | 18 ++++--- .../modeler/api/mock-fillers/OneVarFiller.h | 18 ++++--- .../TwoVarsTwoConstraintsFiller.h | 18 ++++--- .../modeler/api/testModelerLPbuilder.cpp | 34 +++++++++++-- 8 files changed, 170 insertions(+), 31 deletions(-) create mode 100644 src/tests/src/solver/modeler/api/mock-fillers/FillerContext.h diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemBuilder.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemBuilder.h index c5b4419113..d5d7fd43e1 100644 --- a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemBuilder.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemBuilder.h @@ -32,7 +32,7 @@ class LinearProblemBuilder { public: explicit LinearProblemBuilder(const std::vector& fillers); - void build(ILinearProblem& pb, LinearProblemData& data); + void build(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx); private: const std::vector& fillers_; diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemFiller.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemFiller.h index aad1fa3ce6..fb5bd230ae 100644 --- a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemFiller.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemFiller.h @@ -29,12 +29,37 @@ namespace Antares::Solver::Modeler::Api { +struct FillContext +{ + FillContext(unsigned first, unsigned last): + firstTimeStep(first), + lastTimeStep(last) + { + } + + unsigned getFirstTimeStep() const + { + return firstTimeStep; + } + + unsigned getLastTimeStep() const + { + return lastTimeStep; + } + + std::vector scenariosSelected; + +private: + unsigned firstTimeStep; + unsigned lastTimeStep; +}; + class LinearProblemFiller { public: - virtual void addVariables(ILinearProblem& pb, LinearProblemData& data) = 0; - virtual void addConstraints(ILinearProblem& pb, LinearProblemData& data) = 0; - virtual void addObjective(ILinearProblem& pb, LinearProblemData& data) = 0; + virtual void addVariables(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) = 0; + virtual void addConstraints(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) = 0; + virtual void addObjective(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) = 0; virtual ~LinearProblemFiller() = default; }; diff --git a/src/solver/modeler/api/linearProblemBuilder.cpp b/src/solver/modeler/api/linearProblemBuilder.cpp index f9d6103152..5363647c3f 100644 --- a/src/solver/modeler/api/linearProblemBuilder.cpp +++ b/src/solver/modeler/api/linearProblemBuilder.cpp @@ -1,3 +1,24 @@ +/* + * 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 #include @@ -11,11 +32,14 @@ LinearProblemBuilder::LinearProblemBuilder(const std::vectoraddVariables(pb, data); }); - std::ranges::for_each(fillers_, [&](const auto& filler) { filler->addConstraints(pb, data); }); - std::ranges::for_each(fillers_, [&](const auto& filler) { filler->addObjective(pb, data); }); + std::ranges::for_each(fillers_, + [&](const auto& filler) { filler->addVariables(pb, data, ctx); }); + std::ranges::for_each(fillers_, + [&](const auto& filler) { filler->addConstraints(pb, data, ctx); }); + std::ranges::for_each(fillers_, + [&](const auto& filler) { filler->addObjective(pb, data, ctx); }); } } // namespace Antares::Solver::Modeler::Api diff --git a/src/tests/src/solver/modeler/api/mock-fillers/FillerContext.h b/src/tests/src/solver/modeler/api/mock-fillers/FillerContext.h new file mode 100644 index 0000000000..f24c931e88 --- /dev/null +++ b/src/tests/src/solver/modeler/api/mock-fillers/FillerContext.h @@ -0,0 +1,48 @@ +#pragma once + +#include "antares/solver/modeler/api/linearProblemFiller.h" + +namespace Antares::Solver::Modeler::Api +{ + +class VarFillerContext: public LinearProblemFiller +{ +public: + explicit VarFillerContext() = default; + void addVariables(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; + void addConstraints(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; + void addObjective(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; + + std::array, 5> timeseries = { + {{1, 3, 5}, {2, 4, 6}, {7, 9, 11}, {8, 10, 12}, {13, 15, 17}}}; +}; + +void VarFillerContext::addVariables(ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) +{ + for (unsigned timestep = ctx.getFirstTimeStep(); timestep < ctx.getLastTimeStep(); timestep++) + { + for (unsigned scenario: ctx.scenariosSelected) + { + pb.addNumVariable(timeseries[timestep][scenario], + timeseries[timestep][scenario], + "variable-ts" + std::to_string(timestep) + "-sc" + + std::to_string(scenario)); + } + } +} + +void VarFillerContext::addConstraints([[maybe_unused]] ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) +{ +} + +void VarFillerContext::addObjective([[maybe_unused]] ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) +{ +} + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/tests/src/solver/modeler/api/mock-fillers/OneConstraintFiller.h b/src/tests/src/solver/modeler/api/mock-fillers/OneConstraintFiller.h index cb1f9db3e9..5ec2662b2a 100644 --- a/src/tests/src/solver/modeler/api/mock-fillers/OneConstraintFiller.h +++ b/src/tests/src/solver/modeler/api/mock-fillers/OneConstraintFiller.h @@ -9,21 +9,27 @@ class OneConstraintFiller: public LinearProblemFiller { public: explicit OneConstraintFiller() = default; - void addVariables(ILinearProblem& pb, LinearProblemData& data) override; - void addConstraints(ILinearProblem& pb, LinearProblemData& data) override; - void addObjective(ILinearProblem& pb, LinearProblemData& data) override; + void addVariables(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; + void addConstraints(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; + void addObjective(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; }; -void OneConstraintFiller::addVariables(ILinearProblem& pb, LinearProblemData& data) +void OneConstraintFiller::addVariables([[maybe_unused]] ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) { } -void OneConstraintFiller::addConstraints(ILinearProblem& pb, LinearProblemData& data) +void OneConstraintFiller::addConstraints(ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) { pb.addConstraint(1, 2, "constraint-by-OneConstraintFiller"); } -void OneConstraintFiller::addObjective(ILinearProblem& pb, LinearProblemData& data) +void OneConstraintFiller::addObjective([[maybe_unused]] ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) { } diff --git a/src/tests/src/solver/modeler/api/mock-fillers/OneVarFiller.h b/src/tests/src/solver/modeler/api/mock-fillers/OneVarFiller.h index 5d2ba08b55..a828056b63 100644 --- a/src/tests/src/solver/modeler/api/mock-fillers/OneVarFiller.h +++ b/src/tests/src/solver/modeler/api/mock-fillers/OneVarFiller.h @@ -9,24 +9,30 @@ class OneVarFiller: public LinearProblemFiller { public: explicit OneVarFiller() = default; - void addVariables(ILinearProblem& pb, LinearProblemData& data) override; - void addConstraints(ILinearProblem& pb, LinearProblemData& data) override; - void addObjective(ILinearProblem& pb, LinearProblemData& data) override; + void addVariables(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; + void addConstraints(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; + void addObjective(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; private: std::string added_var_name_ = "var-by-OneVarFiller"; }; -void OneVarFiller::addVariables(ILinearProblem& pb, LinearProblemData& data) +void OneVarFiller::addVariables(ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) { pb.addNumVariable(0, 1, added_var_name_); } -void OneVarFiller::addConstraints(ILinearProblem& pb, LinearProblemData& data) +void OneVarFiller::addConstraints([[maybe_unused]] ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) { } -void OneVarFiller::addObjective(ILinearProblem& pb, LinearProblemData& data) +void OneVarFiller::addObjective(ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) { auto* var = pb.getVariable(added_var_name_); pb.setObjectiveCoefficient(var, 1); diff --git a/src/tests/src/solver/modeler/api/mock-fillers/TwoVarsTwoConstraintsFiller.h b/src/tests/src/solver/modeler/api/mock-fillers/TwoVarsTwoConstraintsFiller.h index e8671644df..832ba3954f 100644 --- a/src/tests/src/solver/modeler/api/mock-fillers/TwoVarsTwoConstraintsFiller.h +++ b/src/tests/src/solver/modeler/api/mock-fillers/TwoVarsTwoConstraintsFiller.h @@ -9,24 +9,30 @@ class TwoVarsTwoConstraintsFiller: public LinearProblemFiller { public: explicit TwoVarsTwoConstraintsFiller() = default; - void addVariables(ILinearProblem& pb, LinearProblemData& data) override; - void addConstraints(ILinearProblem& pb, LinearProblemData& data) override; - void addObjective(ILinearProblem& pb, LinearProblemData& data) override; + void addVariables(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; + void addConstraints(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; + void addObjective(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) override; }; -void TwoVarsTwoConstraintsFiller::addVariables(ILinearProblem& pb, LinearProblemData& data) +void TwoVarsTwoConstraintsFiller::addVariables(ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) { pb.addNumVariable(0, 1, "var-1-by-TwoVarsTwoConstraintsFiller"); pb.addNumVariable(0, 3, "var-2-by-TwoVarsTwoConstraintsFiller"); } -void TwoVarsTwoConstraintsFiller::addConstraints(ILinearProblem& pb, LinearProblemData& data) +void TwoVarsTwoConstraintsFiller::addConstraints(ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) { pb.addConstraint(1, 2, "constr-1-by-TwoVarsTwoConstraintsFiller"); pb.addConstraint(1, 3, "constr-2-by-TwoVarsTwoConstraintsFiller"); } -void TwoVarsTwoConstraintsFiller::addObjective(ILinearProblem& pb, LinearProblemData& data) +void TwoVarsTwoConstraintsFiller::addObjective([[maybe_unused]] ILinearProblem& pb, + [[maybe_unused]] LinearProblemData& data, + [[maybe_unused]] FillContext& ctx) { } diff --git a/src/tests/src/solver/modeler/api/testModelerLPbuilder.cpp b/src/tests/src/solver/modeler/api/testModelerLPbuilder.cpp index ccdccf251a..6a423e2b37 100644 --- a/src/tests/src/solver/modeler/api/testModelerLPbuilder.cpp +++ b/src/tests/src/solver/modeler/api/testModelerLPbuilder.cpp @@ -25,6 +25,7 @@ #include #include +#include "mock-fillers/FillerContext.h" #include "mock-fillers/OneConstraintFiller.h" #include "mock-fillers/OneVarFiller.h" #include "mock-fillers/TwoVarsTwoConstraintsFiller.h" @@ -41,6 +42,7 @@ struct Fixture std::vector fillers; LinearProblemData LP_Data; + FillContext ctx = {0, 0}; // dummy value for other tests than context std::unique_ptr pb; }; @@ -49,7 +51,7 @@ BOOST_AUTO_TEST_SUITE(tests_on_linear_problem_builder) BOOST_FIXTURE_TEST_CASE(no_filler_given_to_builder___nothing_built, Fixture) { LinearProblemBuilder lpBuilder(fillers); - lpBuilder.build(*pb, LP_Data); + lpBuilder.build(*pb, LP_Data, ctx); BOOST_CHECK_EQUAL(pb->variableCount(), 0); BOOST_CHECK_EQUAL(pb->constraintCount(), 0); @@ -61,7 +63,7 @@ BOOST_FIXTURE_TEST_CASE(one_var_filler___the_var_is_built, Fixture) fillers = {oneVarFiller.get()}; LinearProblemBuilder lpBuilder(fillers); - lpBuilder.build(*pb, LP_Data); + lpBuilder.build(*pb, LP_Data, ctx); BOOST_CHECK_EQUAL(pb->variableCount(), 1); BOOST_CHECK_EQUAL(pb->constraintCount(), 0); @@ -76,7 +78,7 @@ BOOST_FIXTURE_TEST_CASE(one_constraint_filler___the_constraint_is_built, Fixture fillers = {oneConstrFiller.get()}; LinearProblemBuilder lpBuilder(fillers); - lpBuilder.build(*pb, LP_Data); + lpBuilder.build(*pb, LP_Data, ctx); BOOST_CHECK_EQUAL(pb->variableCount(), 0); BOOST_CHECK_EQUAL(pb->constraintCount(), 1); @@ -91,7 +93,7 @@ BOOST_FIXTURE_TEST_CASE(two_fillers_given_to_builder___all_is_built, Fixture) fillers = {oneVarFiller.get(), oneConstrFiller.get()}; LinearProblemBuilder lpBuilder(fillers); - lpBuilder.build(*pb, LP_Data); + lpBuilder.build(*pb, LP_Data, ctx); BOOST_CHECK_EQUAL(pb->constraintCount(), 1); BOOST_CHECK(pb->getConstraint("constraint-by-OneConstraintFiller")); @@ -106,10 +108,32 @@ BOOST_FIXTURE_TEST_CASE(three_fillers_given_to_builder___3_vars_3_constr_are_bui fillers = {oneVarFiller.get(), oneConstrFiller.get(), twoVarsTwoConstrFiller.get()}; LinearProblemBuilder lpBuilder(fillers); - lpBuilder.build(*pb, LP_Data); + lpBuilder.build(*pb, LP_Data, ctx); BOOST_CHECK_EQUAL(pb->variableCount(), 3); BOOST_CHECK_EQUAL(pb->constraintCount(), 3); } +BOOST_FIXTURE_TEST_CASE(FillerWithContext, Fixture) +{ + auto varFiller = std::make_unique(); + fillers = {varFiller.get()}; + + ctx = FillContext(0, 5); + + ctx.scenariosSelected.push_back(0); + ctx.scenariosSelected.push_back(2); + + LinearProblemBuilder lpBuilder(fillers); + lpBuilder.build(*pb, LP_Data, ctx); + + BOOST_CHECK_EQUAL(pb->variableCount(), 10); // 5 timestep * 2 scenario + + auto var1 = pb->getVariable("variable-ts0-sc0"); + BOOST_CHECK_EQUAL(var1->getLb(), varFiller->timeseries[0][0]); + + auto var2 = pb->getVariable("variable-ts3-sc2"); + BOOST_CHECK_EQUAL(var2->getLb(), varFiller->timeseries[3][2]); +} + BOOST_AUTO_TEST_SUITE_END() From c84c84380fe71df47fe47d31d8d79a3581e80681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20Mar=C3=A9chal?= <45510813+JasonMarechal25@users.noreply.github.com> Date: Fri, 11 Oct 2024 12:03:56 +0200 Subject: [PATCH 033/103] [ANT-2206] Full exemple (#2448) Ful exemple of the parsing + conversion to model of a library --------- Co-authored-by: Vincent Payet Co-authored-by: payetvin <113102157+payetvin@users.noreply.github.com> Co-authored-by: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Co-authored-by: Florian OMNES --- src/solver/modelParser/encoders.hxx | 54 +- .../antares/solver/modelParser/Library.h | 21 - .../src/solver/modelParser/CMakeLists.txt | 2 + .../src/solver/modelParser/enum_operators.h | 76 +++ .../solver/modelParser/testModelParser.cpp | 33 +- .../modelParser/testModelTranslator.cpp | 26 +- .../src/solver/modelParser/test_full.cpp | 510 ++++++++++++++++++ 7 files changed, 656 insertions(+), 66 deletions(-) create mode 100644 src/tests/src/solver/modelParser/enum_operators.h create mode 100644 src/tests/src/solver/modelParser/test_full.cpp diff --git a/src/solver/modelParser/encoders.hxx b/src/solver/modelParser/encoders.hxx index 9d913b860a..09287c06b5 100644 --- a/src/solver/modelParser/encoders.hxx +++ b/src/solver/modelParser/encoders.hxx @@ -29,6 +29,23 @@ // Implement convert specializations namespace YAML { + +/** + * @brief shortend to default construct a value when node is null + * @tparam T Type to convert the node to + * @param n node + * @return Object of type T + * It's just to simplify repertitve and verbose lines + * as_fallback_default>( +node["parameters"]) is equivalent to + node["parameters"].as>(std::vector()) + */ +template +inline T as_fallback_default(const Node& n) +{ + return n.as(T()); +} + template<> struct convert { @@ -54,15 +71,16 @@ struct convert { return false; } - if (node.as() == "FLOAT") + const auto value = node.as(); + if (value == "continuous") { rhs = Antares::Solver::ModelParser::ValueType::CONTINUOUS; } - else if (node.as() == "INTEGER") + else if (value == "integer") { rhs = Antares::Solver::ModelParser::ValueType::INTEGER; } - else if (node.as() == "BOOL") + else if (value == "boolean") { rhs = Antares::Solver::ModelParser::ValueType::BOOL; } @@ -84,8 +102,8 @@ struct convert return false; } rhs.id = node["id"].as(); - rhs.lower_bound = node["lower-bound"].as(); - rhs.upper_bound = node["upper-bound"].as(); + rhs.lower_bound = node["lower-bound"].as(""); + rhs.upper_bound = node["upper-bound"].as(""); rhs.variable_type = node["variable-type"].as( Antares::Solver::ModelParser::ValueType::CONTINUOUS); return true; @@ -149,16 +167,18 @@ struct convert } rhs.id = node["id"].as(); rhs.description = node["description"].as(""); - rhs.parameters = node["parameters"] - .as>(); - rhs.variables = node["variables"].as>(); - rhs.ports = node["ports"].as>(); - rhs.port_field_definitions = node["port-field-definitions"] - .as>(); - rhs.constraints = node["constraints"] - .as>(); - rhs.objective = node["objective"].as(); + rhs.parameters = as_fallback_default>( + node["parameters"]); + rhs.variables = as_fallback_default>( + node["variables"]); + rhs.ports = as_fallback_default>( + node["ports"]); + rhs.port_field_definitions = as_fallback_default< + std::vector>( + node["port-field-definitions"]); + rhs.constraints = as_fallback_default< + std::vector>(node["constraints"]); + rhs.objective = node["objective"].as(""); return true; } }; @@ -189,8 +209,8 @@ struct convert { rhs.id = node["id"].as(); rhs.description = node["description"].as(""); - rhs.port_types = node["port-types"] - .as>(); + rhs.port_types = as_fallback_default>( + node["port-types"]); rhs.models = node["models"].as>(); return true; } diff --git a/src/solver/modelParser/include/antares/solver/modelParser/Library.h b/src/solver/modelParser/include/antares/solver/modelParser/Library.h index 77233a4a50..c2a881b561 100644 --- a/src/solver/modelParser/include/antares/solver/modelParser/Library.h +++ b/src/solver/modelParser/include/antares/solver/modelParser/Library.h @@ -58,27 +58,6 @@ inline std::string toString(const ValueType& value_type) } } -inline std::ostream& operator<<(std::ostream& os, const ValueType& value_type) -{ - using namespace std::string_literals; - switch (value_type) - { - case ValueType::CONTINUOUS: - os << "CONTINUOUS"s; - break; - case ValueType::INTEGER: - os << "INTEGER"s; - break; - case ValueType::BOOL: - os << "BOOL"s; - break; - default: - os << "UNKNOWN"s; - break; - } - return os; -} - struct Variable { std::string id; diff --git a/src/tests/src/solver/modelParser/CMakeLists.txt b/src/tests/src/solver/modelParser/CMakeLists.txt index fc65d70e93..e694d66126 100644 --- a/src/tests/src/solver/modelParser/CMakeLists.txt +++ b/src/tests/src/solver/modelParser/CMakeLists.txt @@ -2,6 +2,8 @@ set(SOURCE_FILES testModelParser.cpp testModelTranslator.cpp + test_full.cpp + enum_operators.h ) # Add executable diff --git a/src/tests/src/solver/modelParser/enum_operators.h b/src/tests/src/solver/modelParser/enum_operators.h new file mode 100644 index 0000000000..eaf55c5543 --- /dev/null +++ b/src/tests/src/solver/modelParser/enum_operators.h @@ -0,0 +1,76 @@ + +/* + * 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 + +#include "antares/solver/libObjectModel/valueType.h" +#include "antares/solver/modelParser/Library.h" + +namespace Antares::Solver::ObjectModel +{ +inline std::ostream& operator<<(std::ostream& os, const ValueType& value_type) +{ + using namespace std::string_literals; + switch (value_type) + { + case ValueType::FLOAT: + os << "float"s; + break; + case ValueType::INTEGER: + os << "integer"s; + break; + case ValueType::BOOL: + os << "boolean"s; + break; + default: + os << "UNKNOWN"s; + break; + } + return os; +} +} // namespace Antares::Solver::ObjectModel + +namespace Antares::Solver::ModelParser +{ +inline std::ostream& operator<<(std::ostream& os, const ValueType& value_type) +{ + using namespace std::string_literals; + switch (value_type) + { + case ValueType::CONTINUOUS: + os << "CONTINUOUS"s; + break; + case ValueType::INTEGER: + os << "INTEGER"s; + break; + case ValueType::BOOL: + os << "BOOL"s; + break; + default: + os << "UNKNOWN"s; + break; + } + return os; +} +} // namespace Antares::Solver::ModelParser diff --git a/src/tests/src/solver/modelParser/testModelParser.cpp b/src/tests/src/solver/modelParser/testModelParser.cpp index ea59c9bbfa..23f237f862 100644 --- a/src/tests/src/solver/modelParser/testModelParser.cpp +++ b/src/tests/src/solver/modelParser/testModelParser.cpp @@ -27,6 +27,8 @@ #include "antares/solver/modelParser/parser.h" +#include "enum_operators.h" + using namespace std::string_literals; // Test empty library @@ -230,7 +232,7 @@ BOOST_AUTO_TEST_CASE(model_can_contain_multiple_parameters) description: "model_description" parameters: - id: "param_name1" - time-dependent: false + time-dependent: FALSE scenario-dependent: false - id: "param_name2" time-dependent: true @@ -391,15 +393,15 @@ BOOST_AUTO_TEST_CASE(variable_types_can_be_integer_bool_float_default_to_float) - id: "var1" lower-bound: 0 upper-bound: 1 - variable-type: "BOOL" + variable-type: "boolean" - id: "var2" lower-bound: 0 upper-bound: 1 - variable-type: "INTEGER" + variable-type: "integer" - id: "var3" lower-bound: 0 upper-bound: 1 - variable-type: "FLOAT" + variable-type: "continuous" - id: "var4" lower-bound: 0 upper-bound: 1 @@ -619,3 +621,26 @@ BOOST_AUTO_TEST_CASE(model_is_not_scalar) )"s; BOOST_CHECK_THROW(parser.parse(library), std::runtime_error); } + +BOOST_AUTO_TEST_CASE(model_attributs_can_be_ommited) +{ + Antares::Solver::ModelParser::Parser parser; + const auto library = R"( + library: + id: "lib_id" + description: "lib_description" + port-types: [] + models: + - id: "model_id" + )"s; + Antares::Solver::ModelParser::Library libraryObj = parser.parse(library); + BOOST_REQUIRE_EQUAL(libraryObj.models.size(), 1); + BOOST_CHECK_EQUAL(libraryObj.models[0].id, "model_id"); + BOOST_CHECK_EQUAL(libraryObj.models[0].description, ""); + BOOST_CHECK(libraryObj.models[0].parameters.empty()); + BOOST_CHECK(libraryObj.models[0].variables.empty()); + BOOST_CHECK(libraryObj.models[0].ports.empty()); + BOOST_CHECK(libraryObj.models[0].port_field_definitions.empty()); + BOOST_CHECK(libraryObj.models[0].constraints.empty()); + BOOST_CHECK_EQUAL(libraryObj.models[0].objective, ""); +} diff --git a/src/tests/src/solver/modelParser/testModelTranslator.cpp b/src/tests/src/solver/modelParser/testModelTranslator.cpp index bf203ae8ed..8f0e5aff19 100644 --- a/src/tests/src/solver/modelParser/testModelTranslator.cpp +++ b/src/tests/src/solver/modelParser/testModelTranslator.cpp @@ -29,31 +29,9 @@ #include "antares/solver/modelConverter/modelConverter.h" #include "antares/solver/modelParser/Library.h" -using namespace Antares::Solver; +#include "enum_operators.h" -namespace Antares::Solver::ObjectModel -{ -inline std::ostream& operator<<(std::ostream& os, const ValueType& value_type) -{ - using namespace std::string_literals; - switch (value_type) - { - case ValueType::FLOAT: - os << "FLOAT"s; - break; - case ValueType::INTEGER: - os << "INTEGER"s; - break; - case ValueType::BOOL: - os << "BOOL"s; - break; - default: - os << "UNKNOWN"s; - break; - } - return os; -} -} // namespace Antares::Solver::ObjectModel +using namespace Antares::Solver; // Test empty library BOOST_AUTO_TEST_CASE(Empty_library_is_valid) diff --git a/src/tests/src/solver/modelParser/test_full.cpp b/src/tests/src/solver/modelParser/test_full.cpp new file mode 100644 index 0000000000..a2a7316192 --- /dev/null +++ b/src/tests/src/solver/modelParser/test_full.cpp @@ -0,0 +1,510 @@ + +/* + * 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 . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +#include "antares/solver/libObjectModel/library.h" +#include "antares/solver/modelConverter/modelConverter.h" +#include "antares/solver/modelParser/Library.h" +#include "antares/solver/modelParser/parser.h" + +#include "enum_operators.h" + +using namespace std::string_literals; +using namespace Antares::Solver; + +void checkParameter(const ObjectModel::Parameter& parameter, + const std::string& name, + bool timeDependent, + bool scenarioDependent, + ObjectModel::ValueType type) +{ + std::cout << "Parameter: " << parameter.Id() << std::endl; + BOOST_CHECK_EQUAL(parameter.Id(), name); + BOOST_CHECK_EQUAL(parameter.isTimeDependent(), timeDependent); + BOOST_CHECK_EQUAL(parameter.isScenarioDependent(), scenarioDependent); + BOOST_CHECK_EQUAL(parameter.Type(), type); +} + +void checkVariable(const ObjectModel::Variable& variable, + const std::string& name, + const std::string& lowerBound, + const std::string& upperBound, + ObjectModel::ValueType type) +{ + std::cout << "Variable: " << variable.Id() << std::endl; + BOOST_CHECK_EQUAL(variable.Id(), name); + BOOST_CHECK_EQUAL(variable.LowerBound().Value(), lowerBound); + BOOST_CHECK_EQUAL(variable.UpperBound().Value(), upperBound); + BOOST_CHECK_EQUAL(variable.Type(), type); +} + +void checkConstraint(const ObjectModel::Constraint& constraint, + const std::string& name, + const std::string& expression) +{ + std::cout << "Constraint: " << constraint.Id() << std::endl; + BOOST_CHECK_EQUAL(constraint.Id(), name); + BOOST_CHECK_EQUAL(constraint.expression().Value(), expression); +} + +BOOST_AUTO_TEST_CASE(test_full) +{ + auto library = R"( +# Copyright (c) 2024, RTE (https://www.rte-france.com) +# +# See AUTHORS.txt +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# SPDX-License-Identifier: MPL-2.0 +# +# This file is part of the Antares project. +library: + id: basic + description: Basic library + + port-types: + - id: flow + description: A port which transfers power flow + fields: + - id: flow + + models: + - id: generator + description: A basic generator model + parameters: + - id: cost + time-dependent: false + scenario-dependent: false + - id: p_max + time-dependent: false + scenario-dependent: false + variables: + - id: generation + lower-bound: 0 + upper-bound: p_max + ports: + - id: injection_port + type: flow + port-field-definitions: + - port: injection_port + field: flow + definition: generation + objective: expec(sum(cost * generation)) + + - id: node + description: A basic balancing node model + ports: + - id: injection_port + type: flow + binding-constraints: + - id: balance + expression: sum_connections(injection_port.flow) = 0 + + - id: spillage + description: A basic spillage model + parameters: + - id: cost + time-dependent: false + scenario-dependent: false + variables: + - id: spillage + lower-bound: 0 + ports: + - id: injection_port + type: flow + port-field-definitions: + - port: injection_port + field: flow + definition: -spillage + + - id: unsupplied + description: A basic unsupplied model + parameters: + - id: cost + time-dependent: false + scenario-dependent: false + variables: + - id: unsupplied_energy + lower-bound: 0 + ports: + - id: injection_port + type: flow + port-field-definitions: + - port: injection_port + field: flow + definition: unsupplied_energy + + - id: demand + description: A basic fixed demand model + parameters: + - id: demand + time-dependent: true + scenario-dependent: true + ports: + - id: injection_port + type: flow + port-field-definitions: + - port: injection_port + field: flow + definition: -demand + + - id: short-term-storage + description: A short term storage + parameters: + - id: efficiency + - id: level_min + - id: level_max + - id: p_max_withdrawal + - id: p_max_injection + - id: inflows + variables: + - id: injection + lower-bound: 0 + upper-bound: p_max_injection + - id: withdrawal + lower-bound: 0 + upper-bound: p_max_withdrawal + - id: level + lower-bound: level_min + upper-bound: level_max + ports: + - id: injection_port + type: flow + port-field-definitions: + - port: injection_port + field: flow + definition: injection - withdrawal + constraints: + - id: Level equation + expression: level[t] - level[t-1] - efficiency * injection + withdrawal = inflows + + - id: thermal-cluster-dhd + description: DHD model for thermal cluster + parameters: + - id: cost + - id: p_min + - id: p_max + - id: d_min_up + - id: d_min_down + - id: nb_units_max + - id: nb_failures + time-dependent: true + scenario-dependent: true + variables: + - id: generation + lower-bound: 0 + upper-bound: nb_units_max * p_max + time-dependent: true + scenario-dependent: true + - id: nb_on + lower-bound: 0 + upper-bound: nb_units_max + time-dependent: true + scenario-dependent: false + - id: nb_stop + lower-bound: 0 + upper-bound: nb_units_max + time-dependent: true + scenario-dependent: false + - id: nb_start + lower-bound: 0 + upper-bound: nb_units_max + time-dependent: true + scenario-dependent: false + ports: + - id: injection_port + type: flow + port-field-definitions: + - port: injection_port + field: flow + definition: generation + constraints: + - id: Max generation + expression: generation <= nb_on * p_max + - id: Min generation + expression: generation >= nb_on * p_min + - id: Number of units variation + expression: nb_on = nb_on[t-1] + nb_start - nb_stop + - id: Min up time + expression: sum(t-d_min_up + 1 .. t, nb_start) <= nb_on + - id: Min down time + expression: sum(t-d_min_down + 1 .. t, nb_stop) <= nb_units_max[t-d_min_down] - nb_on + objective: expec(sum(cost * generation)) + )"s; + + try + { + ModelParser::Parser parser; + ModelParser::Library libraryObj = parser.parse(library); + ObjectModel::Library lib = ModelConverter::convert(libraryObj); + BOOST_CHECK_EQUAL(lib.Id(), "basic"); + BOOST_CHECK_EQUAL(lib.Description(), "Basic library"); + + BOOST_REQUIRE_EQUAL(lib.PortTypes().size(), 1); + auto& portType = lib.PortTypes().at("flow"); + BOOST_CHECK_EQUAL(portType.Id(), "flow"); + BOOST_CHECK_EQUAL(portType.Description(), "A port which transfers power flow"); + + BOOST_REQUIRE_EQUAL(portType.Fields().size(), 1); + auto& portTypeField = portType.Fields().at(0); + BOOST_CHECK_EQUAL(portTypeField.Id(), "flow"); + + BOOST_REQUIRE_EQUAL(lib.Models().size(), 7); + auto& model0 = lib.Models().at("generator"); + BOOST_CHECK_EQUAL(model0.Id(), "generator"); + BOOST_CHECK_EQUAL(model0.Objective().Value(), "expec(sum(cost * generation))"); + + BOOST_REQUIRE_EQUAL(model0.getConstraints().size(), 0); + BOOST_REQUIRE_EQUAL(model0.Parameters().size(), 2); + BOOST_REQUIRE_EQUAL(model0.Variables().size(), 1); + // BOOST_REQUIRE_EQUAL(model0.Ports().size(), 1); Unsuported + // BOOST_REQUIRE_EQUAL(model0.PortFieldDefinitions().size(), 1); Unsuported + + checkParameter(model0.Parameters().at("cost"), + "cost", + false, + false, + ObjectModel::ValueType::FLOAT); + checkParameter(model0.Parameters().at("p_max"), + "p_max", + false, + false, + ObjectModel::ValueType::FLOAT); + + checkVariable(model0.Variables().at("generation"), + "generation", + "0", + "p_max", + ObjectModel::ValueType::FLOAT); + + // auto& port = model0.Ports().at("injection_port"); + // BOOST_CHECK_EQUAL(port.Id(), "injection_port"); + // other properties + + auto& model1 = lib.Models().at("node"); + BOOST_CHECK_EQUAL(model1.Id(), "node"); + // BOOST_REQUIRE_EQUAL(model1.getConstraints().size(), 1); + BOOST_REQUIRE_EQUAL(model1.Parameters().size(), 0); + BOOST_REQUIRE_EQUAL(model1.Variables().size(), 0); + // BOOST_REQUIRE_EQUAL(model1.Ports().size(), 1); Unsuported + // BOOST_REQUIRE_EQUAL(model1.PortFieldDefinitions().size(), 0); Unsuported + + auto& model2 = lib.Models().at("spillage"); + BOOST_CHECK_EQUAL(model2.Id(), "spillage"); + BOOST_REQUIRE_EQUAL(model2.getConstraints().size(), 0); + BOOST_REQUIRE_EQUAL(model2.Parameters().size(), 1); + BOOST_REQUIRE_EQUAL(model2.Variables().size(), 1); + // BOOST_REQUIRE_EQUAL(model2.Ports().size(), 1); Unsuported + // BOOST_REQUIRE_EQUAL(model2.PortFieldDefinitions().size(), 1); Unsuported + + checkParameter(model2.Parameters().at("cost"), + "cost", + false, + false, + ObjectModel::ValueType::FLOAT); + checkVariable(model2.Variables().at("spillage"), + "spillage", + "0", + "", + ObjectModel::ValueType::FLOAT); + + auto& model3 = lib.Models().at("unsupplied"); + BOOST_CHECK_EQUAL(model3.Id(), "unsupplied"); + BOOST_REQUIRE_EQUAL(model3.getConstraints().size(), 0); + BOOST_REQUIRE_EQUAL(model3.Parameters().size(), 1); + BOOST_REQUIRE_EQUAL(model3.Variables().size(), 1); + // BOOST_REQUIRE_EQUAL(model3.Ports().size(), 1); Unsuported + // BOOST_REQUIRE_EQUAL(model3.PortFieldDefinitions().size(), 1); Unsuported + checkParameter(model3.Parameters().at("cost"), + "cost", + false, + false, + ObjectModel::ValueType::FLOAT); + checkVariable(model3.Variables().at("unsupplied_energy"), + "unsupplied_energy", + "0", + "", + ObjectModel::ValueType::FLOAT); + + auto& model4 = lib.Models().at("demand"); + BOOST_CHECK_EQUAL(model4.Id(), "demand"); + BOOST_REQUIRE_EQUAL(model4.getConstraints().size(), 0); + BOOST_REQUIRE_EQUAL(model4.Parameters().size(), 1); + BOOST_REQUIRE_EQUAL(model4.Variables().size(), 0); + // BOOST_REQUIRE_EQUAL(model4.Ports().size(), 1); Unsuported + // BOOST_REQUIRE_EQUAL(model4.PortFieldDefinitions().size(), 1); Unsuported + checkParameter(model4.Parameters().at("demand"), + "demand", + true, + true, + ObjectModel::ValueType::FLOAT); + + auto& model5 = lib.Models().at("short-term-storage"); + BOOST_CHECK_EQUAL(model5.Id(), "short-term-storage"); + BOOST_REQUIRE_EQUAL(model5.getConstraints().size(), 1); + BOOST_REQUIRE_EQUAL(model5.Parameters().size(), 6); + BOOST_REQUIRE_EQUAL(model5.Variables().size(), 3); + // BOOST_REQUIRE_EQUAL(model5.Ports().size(), 1); Unsuported + // BOOST_REQUIRE_EQUAL(model5.PortFieldDefinitions().size(), 1); Unsuported + checkParameter(model5.Parameters().at("efficiency"), + "efficiency", + true, + true, + ObjectModel::ValueType::FLOAT); + checkParameter(model5.Parameters().at("level_min"), + "level_min", + true, + true, + ObjectModel::ValueType::FLOAT); + checkParameter(model5.Parameters().at("level_max"), + "level_max", + true, + true, + ObjectModel::ValueType::FLOAT); + checkParameter(model5.Parameters().at("p_max_withdrawal"), + "p_max_withdrawal", + true, + true, + ObjectModel::ValueType::FLOAT); + checkParameter(model5.Parameters().at("p_max_injection"), + "p_max_injection", + true, + true, + ObjectModel::ValueType::FLOAT); + checkParameter(model5.Parameters().at("inflows"), + "inflows", + true, + true, + ObjectModel::ValueType::FLOAT); + checkVariable(model5.Variables().at("injection"), + "injection", + "0", + "p_max_injection", + ObjectModel::ValueType::FLOAT); + checkVariable(model5.Variables().at("withdrawal"), + "withdrawal", + "0", + "p_max_withdrawal", + ObjectModel::ValueType::FLOAT); + checkVariable(model5.Variables().at("level"), + "level", + "level_min", + "level_max", + ObjectModel::ValueType::FLOAT); + checkConstraint(model5.getConstraints().at("Level equation"), + "Level equation", + "level[t] - level[t-1] - efficiency * injection + withdrawal = inflows"); + + auto& model6 = lib.Models().at("thermal-cluster-dhd"); + BOOST_CHECK_EQUAL(model6.Id(), "thermal-cluster-dhd"); + BOOST_REQUIRE_EQUAL(model6.getConstraints().size(), 5); + BOOST_REQUIRE_EQUAL(model6.Parameters().size(), 7); + BOOST_REQUIRE_EQUAL(model6.Variables().size(), 4); + // BOOST_REQUIRE_EQUAL(model6.Ports().size(), 1); Unsuported + // BOOST_REQUIRE_EQUAL(model6.PortFieldDefinitions().size(), 1); Unsuported + checkParameter(model6.Parameters().at("cost"), + "cost", + true, + true, + ObjectModel::ValueType::FLOAT); + checkParameter(model6.Parameters().at("p_min"), + "p_min", + true, + true, + ObjectModel::ValueType::FLOAT); + checkParameter(model6.Parameters().at("p_max"), + "p_max", + true, + true, + ObjectModel::ValueType::FLOAT); + checkParameter(model6.Parameters().at("d_min_up"), + "d_min_up", + true, + true, + ObjectModel::ValueType::FLOAT); + checkParameter(model6.Parameters().at("d_min_down"), + "d_min_down", + true, + true, + ObjectModel::ValueType::FLOAT); + checkParameter(model6.Parameters().at("nb_units_max"), + "nb_units_max", + true, + true, + ObjectModel::ValueType::FLOAT); + checkParameter(model6.Parameters().at("nb_failures"), + "nb_failures", + true, + true, + ObjectModel::ValueType::FLOAT); + checkVariable(model6.Variables().at("generation"), + "generation", + "0", + "nb_units_max * p_max", + ObjectModel::ValueType::FLOAT); + checkVariable(model6.Variables().at("nb_on"), + "nb_on", + "0", + "nb_units_max", + ObjectModel::ValueType::FLOAT); + checkVariable(model6.Variables().at("nb_stop"), + "nb_stop", + "0", + "nb_units_max", + ObjectModel::ValueType::FLOAT); + checkVariable(model6.Variables().at("nb_start"), + "nb_start", + "0", + "nb_units_max", + ObjectModel::ValueType::FLOAT); + checkConstraint(model6.getConstraints().at("Max generation"), + "Max generation", + "generation <= nb_on * p_max"); + checkConstraint(model6.getConstraints().at("Min generation"), + "Min generation", + "generation >= nb_on * p_min"); + checkConstraint(model6.getConstraints().at("Number of units variation"), + "Number of units variation", + "nb_on = nb_on[t-1] + nb_start - nb_stop"); + checkConstraint(model6.getConstraints().at("Min up time"), + "Min up time", + "sum(t-d_min_up + 1 .. t, nb_start) <= nb_on"); + checkConstraint( + model6.getConstraints().at("Min down time"), + "Min down time", + "sum(t-d_min_down + 1 .. t, nb_stop) <= nb_units_max[t-d_min_down] - nb_on"); + BOOST_CHECK_EQUAL(model6.Objective().Value(), "expec(sum(cost * generation))"); + } + catch (const YAML::Exception& e) + { + std::cout << e.what() << std::endl; + BOOST_FAIL(e.what()); + } +} From 7805562558386ef1dcc9eaddcf61143d5eeeeeec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Fri, 11 Oct 2024 13:25:52 +0200 Subject: [PATCH 034/103] Remove function `memoryUsage` and affiliates (#2456) ### Remove - all instances of `memoryUsage` - all instances of `valuesMemoryUsage` - Function `memoryUsageAveragePerArea` - Function `PreproHydroMemoryUsage` - xcast.hxx (becomes unused) ### Consequences Remove two lines of logs - General memory usage (see src/libs/antares/study/runtime/runtime.cpp) - Memory usage for variables (see src/solver/simulation/include/antares/solver/simulation/solver.hxx) --- .../array/include/antares/array/matrix.h | 7 --- .../array/include/antares/array/matrix.hxx | 13 ------ src/libs/antares/correlation/correlation.cpp | 17 ------- .../include/antares/correlation/correlation.h | 5 -- .../antares/jit/include/antares/jit/jit.h | 3 -- .../antares/jit/include/antares/jit/jit.hxx | 5 -- .../memory/include/antares/memory/memory.h | 5 -- .../series/include/antares/series/series.h | 1 - src/libs/antares/series/series.cpp | 4 -- src/libs/antares/study/CMakeLists.txt | 1 - src/libs/antares/study/area/area.cpp | 46 ------------------- src/libs/antares/study/area/links.cpp | 10 ---- src/libs/antares/study/area/list.cpp | 7 --- src/libs/antares/study/area/ui.cpp | 5 -- .../binding_constraint/BindingConstraint.cpp | 17 ------- .../BindingConstraintsRepository.cpp | 10 ---- .../study/include/antares/study/area/area.h | 27 ----------- .../study/include/antares/study/area/links.h | 7 --- .../study/include/antares/study/area/ui.h | 5 -- .../binding_constraint/BindingConstraint.h | 8 ---- .../BindingConstraintsRepository.h | 5 -- .../study/include/antares/study/parameters.h | 5 -- .../antares/study/parts/common/cluster.h | 6 --- .../antares/study/parts/common/cluster_list.h | 6 --- .../antares/study/parts/hydro/prepro.h | 6 --- .../antares/study/parts/hydro/series.h | 12 ----- .../antares/study/parts/load/container.h | 5 -- .../include/antares/study/parts/load/prepro.h | 5 -- .../antares/study/parts/load/prepro.hxx | 5 -- .../antares/study/parts/renewable/cluster.h | 6 --- .../study/parts/renewable/cluster_list.h | 1 - .../antares/study/parts/solar/container.h | 5 -- .../antares/study/parts/solar/prepro.h | 5 -- .../antares/study/parts/solar/prepro.hxx | 5 -- .../antares/study/parts/thermal/cluster.h | 6 --- .../study/parts/thermal/cluster_list.h | 1 - .../antares/study/parts/thermal/ecoInput.h | 5 -- .../antares/study/parts/wind/container.h | 5 -- .../include/antares/study/parts/wind/prepro.h | 5 -- .../antares/study/parts/wind/prepro.hxx | 5 -- .../study/include/antares/study/simulation.h | 3 -- .../study/include/antares/study/study.h | 5 -- .../include/antares/study/ui-runtimeinfos.h | 2 - .../study/include/antares/study/xcast/xcast.h | 13 ------ .../include/antares/study/xcast/xcast.hxx | 39 ---------------- src/libs/antares/study/parameters.cpp | 6 --- src/libs/antares/study/parts/hydro/prepro.cpp | 5 -- src/libs/antares/study/parts/hydro/series.cpp | 6 --- .../antares/study/parts/load/container.cpp | 5 -- .../antares/study/parts/renewable/cluster.cpp | 7 --- .../study/parts/renewable/cluster_list.cpp | 7 --- .../antares/study/parts/solar/container.cpp | 5 -- .../antares/study/parts/thermal/cluster.cpp | 12 ----- .../study/parts/thermal/cluster_list.cpp | 8 ---- .../antares/study/parts/thermal/ecoInput.cpp | 5 -- .../antares/study/parts/wind/container.cpp | 5 -- src/libs/antares/study/runtime/runtime.cpp | 1 - src/libs/antares/study/simulation.cpp | 5 -- src/libs/antares/study/study.cpp | 20 -------- src/libs/antares/study/ui-runtimeinfos.cpp | 5 -- .../antares/solver/simulation/solver.hxx | 2 - .../antares/solver/ts-generator/prepro.h | 5 -- src/solver/ts-generator/prepro.cpp | 5 -- .../include/antares/solver/variable/area.h | 2 - .../include/antares/solver/variable/area.hxx | 13 ------ .../antares/solver/variable/bindConstraints.h | 2 - .../solver/variable/bindConstraints.hxx | 12 ----- .../antares/solver/variable/commons/join.h | 5 -- .../solver/variable/commons/links/links.h | 2 - .../solver/variable/commons/links/links.hxx | 12 ----- .../antares/solver/variable/container.h | 6 --- .../antares/solver/variable/container.hxx | 6 --- .../solver/variable/economy/STSbyGroup.h | 9 ---- .../economy/STStorageCashFlowByCluster.h | 9 ---- .../economy/STStorageInjectionByCluster.h | 9 ---- .../economy/STStorageLevelsByCluster.h | 9 ---- .../economy/STStorageWithdrawalByCluster.h | 9 ---- .../economy/productionByDispatchablePlant.h | 9 ---- .../economy/productionByRenewablePlant.h | 9 ---- .../antares/solver/variable/endoflist.h | 5 -- .../include/antares/solver/variable/info.h | 26 ----------- .../antares/solver/variable/setofareas.h | 2 - .../antares/solver/variable/setofareas.hxx | 11 ----- .../antares/solver/variable/storage/average.h | 5 -- .../solver/variable/storage/averagedata.h | 5 -- .../antares/solver/variable/storage/empty.h | 5 -- .../solver/variable/storage/intermediate.h | 5 -- .../solver/variable/storage/intermediate.hxx | 5 -- .../antares/solver/variable/storage/minmax.h | 5 -- .../antares/solver/variable/storage/raw.h | 5 -- .../antares/solver/variable/storage/results.h | 5 -- .../solver/variable/storage/stdDeviation.h | 5 -- .../antares/solver/variable/variable.h | 7 --- .../antares/solver/variable/variable.hxx | 19 -------- 94 files changed, 721 deletions(-) delete mode 100644 src/libs/antares/study/include/antares/study/xcast/xcast.hxx diff --git a/src/libs/antares/array/include/antares/array/matrix.h b/src/libs/antares/array/include/antares/array/matrix.h index 42432a0ae1..64d65b0e18 100644 --- a/src/libs/antares/array/include/antares/array/matrix.h +++ b/src/libs/antares/array/include/antares/array/matrix.h @@ -415,13 +415,6 @@ class Matrix */ bool empty() const; - //! Get the amount of memory used by the matrix - uint64_t memoryUsage() const; - - //! Get the amount of memory used by the matrix - uint64_t valuesMemoryUsage() const; - //@} - /*! ** \brief Print the matrix to std::cout (debug) */ diff --git a/src/libs/antares/array/include/antares/array/matrix.hxx b/src/libs/antares/array/include/antares/array/matrix.hxx index c95db1bd93..6e1fb3b9a0 100644 --- a/src/libs/antares/array/include/antares/array/matrix.hxx +++ b/src/libs/antares/array/include/antares/array/matrix.hxx @@ -528,19 +528,6 @@ inline bool Matrix::empty() const return (!width) or (!height); } -template -inline uint64_t Matrix::memoryUsage() const -{ - return sizeof(Matrix) + (sizeof(T) * (width * height)) - + ((jit) ? jit->memoryUsage() : 0); -} - -template -inline uint64_t Matrix::valuesMemoryUsage() const -{ - return (sizeof(T) * (width * height)); -} - template void Matrix::clear() { diff --git a/src/libs/antares/correlation/correlation.cpp b/src/libs/antares/correlation/correlation.cpp index efdf3b3769..a294d2cb5c 100644 --- a/src/libs/antares/correlation/correlation.cpp +++ b/src/libs/antares/correlation/correlation.cpp @@ -557,23 +557,6 @@ void Correlation::set(Matrix<>& m, const Area& from, const Area& to, double v) m[to.index][from.index] = v; } -uint64_t Correlation::memoryUsage() const -{ - uint64_t r = sizeof(Correlation); - if (!annual.empty()) - { - r += annual.memoryUsage(); - } - if (!monthly.empty()) - { - for (uint i = 0; i != 12; ++i) - { - r += monthly[i].memoryUsage(); - } - } - return r; -} - bool Correlation::forceReload(bool reload) const { bool ret = true; diff --git a/src/libs/antares/correlation/include/antares/correlation/correlation.h b/src/libs/antares/correlation/include/antares/correlation/correlation.h index c0ffebe4a0..c5770021b5 100644 --- a/src/libs/antares/correlation/include/antares/correlation/correlation.h +++ b/src/libs/antares/correlation/include/antares/correlation/correlation.h @@ -123,11 +123,6 @@ class Correlation final const AreaNameMapping& mapping, const Study& study); - /*! - ** \brief Get the amount of memory used the correlation matrices - */ - uint64_t memoryUsage() const; - /*! ** \brief Invalidate all matrices */ diff --git a/src/libs/antares/jit/include/antares/jit/jit.h b/src/libs/antares/jit/include/antares/jit/jit.h index 9354a792d4..b54aed0e4d 100644 --- a/src/libs/antares/jit/include/antares/jit/jit.h +++ b/src/libs/antares/jit/include/antares/jit/jit.h @@ -134,9 +134,6 @@ class JIT final */ void markAsModified(); - //! Get the amount of memory currently used - uint64_t memoryUsage() const; - public: //! Filename/folder to consider if some data should be loaded YString sourceFilename; diff --git a/src/libs/antares/jit/include/antares/jit/jit.hxx b/src/libs/antares/jit/include/antares/jit/jit.hxx index a19342e7e4..62c9c6a1c4 100644 --- a/src/libs/antares/jit/include/antares/jit/jit.hxx +++ b/src/libs/antares/jit/include/antares/jit/jit.hxx @@ -30,11 +30,6 @@ inline bool JIT::IsReady(JIT::Informations* j) return (!j or j->alreadyLoaded); } -inline uint64_t JIT::Informations::memoryUsage() const -{ - return sizeof(JIT::Informations) + sourceFilename.capacity(); -} - inline void JIT::Informations::markAsModified() { modified = true; diff --git a/src/libs/antares/memory/include/antares/memory/memory.h b/src/libs/antares/memory/include/antares/memory/memory.h index 42515c5fce..67cd52bfc4 100644 --- a/src/libs/antares/memory/include/antares/memory/memory.h +++ b/src/libs/antares/memory/include/antares/memory/memory.h @@ -91,11 +91,6 @@ class Memory final: public Yuni::Policy::ObjectLevelLockable void cacheFolder(const AnyString& folder); //@} - /*! - ** \brief Get the amount of memory currently used - */ - uint64_t memoryUsage() const; - /*! ** \brief Get the process ID of the application ** diff --git a/src/libs/antares/series/include/antares/series/series.h b/src/libs/antares/series/include/antares/series/series.h index f762e710fa..48dd0dfd07 100644 --- a/src/libs/antares/series/include/antares/series/series.h +++ b/src/libs/antares/series/include/antares/series/series.h @@ -108,7 +108,6 @@ class TimeSeries bool forceReload(bool reload = false) const; void markAsModified() const; - uint64_t memoryUsage() const; TS timeSeries; TimeSeriesNumbers& timeseriesNumbers; diff --git a/src/libs/antares/series/series.cpp b/src/libs/antares/series/series.cpp index 4c0cca690e..c92f7812cc 100644 --- a/src/libs/antares/series/series.cpp +++ b/src/libs/antares/series/series.cpp @@ -225,8 +225,4 @@ void TimeSeries::markAsModified() const timeSeries.markAsModified(); } -uint64_t TimeSeries::memoryUsage() const -{ - return timeSeries.memoryUsage(); -} } // namespace Antares::Data diff --git a/src/libs/antares/study/CMakeLists.txt b/src/libs/antares/study/CMakeLists.txt index a3524a4b96..a354de3058 100644 --- a/src/libs/antares/study/CMakeLists.txt +++ b/src/libs/antares/study/CMakeLists.txt @@ -179,7 +179,6 @@ source_group("study\\constraint" FILES ${SRC_STUDY_BINDING_CONSTRAINT}) set(SRC_XCAST include/antares/study/xcast.h include/antares/study/xcast/xcast.h - include/antares/study/xcast/xcast.hxx xcast/xcast.cpp ) source_group("study\\xcast" FILES ${SRC_XCAST}) diff --git a/src/libs/antares/study/area/area.cpp b/src/libs/antares/study/area/area.cpp index 3bd4b91222..6573a23e14 100644 --- a/src/libs/antares/study/area/area.cpp +++ b/src/libs/antares/study/area/area.cpp @@ -167,52 +167,6 @@ const AreaLink* Area::findExistingLinkWith(const Area& with) const return nullptr; } -uint64_t Area::memoryUsage() const -{ - uint64_t ret = 0; - - // Misc gen. (previously called Fatal hors hydro) - ret += miscGen.valuesMemoryUsage(); - // Reserves - ret += reserves.valuesMemoryUsage(); - - ret += sizeof(Area); - // Load - ret += load.memoryUsage(); - // Solar - ret += solar.memoryUsage(); - // Wind - ret += wind.memoryUsage(); - - // Hydro - ret += PreproHydroMemoryUsage(hydro.prepro.get()); - if (hydro.series) - { - ret += hydro.series->memoryUsage(); - } - - // Thermal - ret += thermal.list.memoryUsage(); - - // Renewable - ret += renewable.list.memoryUsage(); - - // UI - if (ui) - { - ret += ui->memoryUsage(); - } - - // links - auto end = links.end(); - for (auto i = links.begin(); i != end; ++i) - { - ret += (i->second)->memoryUsage(); - } - - return ret; -} - void Area::createMissingData() { createMissingTimeSeries(); diff --git a/src/libs/antares/study/area/links.cpp b/src/libs/antares/study/area/links.cpp index 97668638e0..3c2059b3f6 100644 --- a/src/libs/antares/study/area/links.cpp +++ b/src/libs/antares/study/area/links.cpp @@ -769,16 +769,6 @@ void AreaLinkRemove(AreaLink* link) delete link; } -uint64_t AreaLink::memoryUsage() const -{ - uint64_t to_return = sizeof(AreaLink); - to_return += parameters.valuesMemoryUsage(); - to_return += directCapacities.memoryUsage(); - to_return += indirectCapacities.memoryUsage(); - - return to_return; -} - bool AreaLink::forceReload(bool reload) const { return parameters.forceReload(reload) && directCapacities.forceReload(reload) diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index 0f95023f33..ec7bcd3ef2 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -1394,13 +1394,6 @@ void AreaListEnsureDataThermalPrepro(AreaList* l) l->each([](Data::Area& area) { area.thermal.list.ensureDataPrepro(); }); } -uint64_t AreaList::memoryUsage() const -{ - uint64_t ret = sizeof(AreaList) + sizeof(Area**) * areas.size(); - each([&ret](const Data::Area& area) { ret += area.memoryUsage(); }); - return ret; -} - uint AreaList::areaLinkCount() const { uint ret = 0; diff --git a/src/libs/antares/study/area/ui.cpp b/src/libs/antares/study/area/ui.cpp index cd3f0bb5fd..39cb998bf4 100644 --- a/src/libs/antares/study/area/ui.cpp +++ b/src/libs/antares/study/area/ui.cpp @@ -363,11 +363,6 @@ bool AreaUI::saveToFile(const AnyString& filename, bool force) const return true; } -uint64_t AreaUI::memoryUsage() const -{ - return sizeof(AreaUI); -} - bool AreaUI::modified() const { return pModified; diff --git a/src/libs/antares/study/binding_constraint/BindingConstraint.cpp b/src/libs/antares/study/binding_constraint/BindingConstraint.cpp index abdce0befb..b950773dd4 100644 --- a/src/libs/antares/study/binding_constraint/BindingConstraint.cpp +++ b/src/libs/antares/study/binding_constraint/BindingConstraint.cpp @@ -506,23 +506,6 @@ void BindingConstraint::buildFormula(Yuni::String& s) const } } -uint64_t BindingConstraint::memoryUsage() const -{ - return sizeof(BindingConstraint) - // comments - + pComments.capacity() - // Values - + RHSTimeSeries().memoryUsage() - // Estimation - + pLinkWeights.size() * (sizeof(double) + 3 * sizeof(void*)) - // Estimation - + pLinkOffsets.size() * (sizeof(int) + 3 * sizeof(void*)) - // Estimation - + pClusterWeights.size() * (sizeof(double) + 3 * sizeof(void*)) - // Estimation - + pClusterOffsets.size() * (sizeof(int) + 3 * sizeof(void*)); -} - bool BindingConstraint::contains(const BindingConstraint* bc) const { return (this == bc); diff --git a/src/libs/antares/study/binding_constraint/BindingConstraintsRepository.cpp b/src/libs/antares/study/binding_constraint/BindingConstraintsRepository.cpp index e68c97d15c..7ed09d8e09 100644 --- a/src/libs/antares/study/binding_constraint/BindingConstraintsRepository.cpp +++ b/src/libs/antares/study/binding_constraint/BindingConstraintsRepository.cpp @@ -315,16 +315,6 @@ void BindingConstraintsRepository::reverseWeightSign(const AreaLink* lnk) each([&lnk](BindingConstraint& constraint) { constraint.reverseWeightSign(lnk); }); } -uint64_t BindingConstraintsRepository::memoryUsage() const -{ - uint64_t m = sizeof(BindingConstraintsRepository); - for (const auto& i: constraints_) - { - m += i->memoryUsage(); - } - return m; -} - namespace // anonymous { template diff --git a/src/libs/antares/study/include/antares/study/area/area.h b/src/libs/antares/study/include/antares/study/area/area.h index fea12cea10..7567bb25ca 100644 --- a/src/libs/antares/study/include/antares/study/area/area.h +++ b/src/libs/antares/study/include/antares/study/area/area.h @@ -188,17 +188,6 @@ class Area final: private Yuni::NonCopyable */ void markAsModified() const; - /*! - ** \brief Get the amount of memory currently used by the area - */ - uint64_t memoryUsage() const; - - /*! - ** \brief Try to estimate the amount of memory required by the area for a simulation - */ - - //@} - //! \name Thermal clusters min stable power validity checking //@{ /*! @@ -656,22 +645,6 @@ class AreaList final: public Yuni::NonCopyable /// create a map with the corresponding scratchpad for each area link to this numspace Area::ScratchMap buildScratchMap(uint numspace); - //! \name Memory management - //@{ - /*! - ** \brief Try to estimate the amount of memory required by the class for a simulation - */ - - /*! - ** \brief Get the average amount of memory currently used by each area - */ - double memoryUsageAveragePerArea() const; - - /*! - ** \brief Get the amount of memory currently used by the class - */ - uint64_t memoryUsage() const; - /*! ** \brief Update the name id set */ diff --git a/src/libs/antares/study/include/antares/study/area/links.h b/src/libs/antares/study/include/antares/study/area/links.h index fd4b8e69d8..960f3c36ec 100644 --- a/src/libs/antares/study/include/antares/study/area/links.h +++ b/src/libs/antares/study/include/antares/study/area/links.h @@ -106,13 +106,6 @@ class AreaLink final: public Yuni::NonCopyable void markAsModified() const; //@} - //! \name Memory management - //@{ - /*! - ** \brief Get the size (bytes) in memory occupied by a `AreaLink` structure - */ - uint64_t memoryUsage() const; - bool isVisibleOnLayer(const size_t& layerID) const; Yuni::String getName() const; diff --git a/src/libs/antares/study/include/antares/study/area/ui.h b/src/libs/antares/study/include/antares/study/area/ui.h index 9ab5f39c8b..ddc03e7c4e 100644 --- a/src/libs/antares/study/include/antares/study/area/ui.h +++ b/src/libs/antares/study/include/antares/study/area/ui.h @@ -63,11 +63,6 @@ class AreaUI final */ bool saveToFile(const AnyString& filename, bool force = false) const; - /*! - ** \brief Amount of memory consummed by the instance - */ - uint64_t memoryUsage() const; - /*! ** \brief Get if the structure has been modified */ diff --git a/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraint.h b/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraint.h index e88c7b1bb6..1643c317bf 100644 --- a/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraint.h +++ b/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraint.h @@ -338,14 +338,6 @@ class BindingConstraint final: public Yuni::NonCopyable */ void markAsModified() const; - //! \name Memory Usage - //@{ - /*! - ** \brief Get the memory usage - */ - uint64_t memoryUsage() const; - //@} - /*! ** \brief Reverse the sign of the weight for a given interconnection or thermal cluster ** diff --git a/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraintsRepository.h b/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraintsRepository.h index 25809de754..ea3f8bbb5b 100644 --- a/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraintsRepository.h +++ b/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraintsRepository.h @@ -157,11 +157,6 @@ class BindingConstraintsRepository final: public Yuni::NonCopyable */ void markAsModified() const; - /*! - ** \brief Get the amount of memory currently used by the class - */ - uint64_t memoryUsage() const; - //! Data for the pre-processor std::unique_ptr prepro; diff --git a/src/libs/antares/study/include/antares/study/parts/load/prepro.h b/src/libs/antares/study/include/antares/study/parts/load/prepro.h index bbe3c7a008..e434fe1c01 100644 --- a/src/libs/antares/study/include/antares/study/parts/load/prepro.h +++ b/src/libs/antares/study/include/antares/study/parts/load/prepro.h @@ -59,11 +59,6 @@ class Prepro */ bool saveToFolder(const AnyString& folder) const; - /*! - ** \brief Get the amount of memory currently used - */ - uint64_t memoryUsage() const; - /*! ** \brief Make sure that all data are loaded in memory */ diff --git a/src/libs/antares/study/include/antares/study/parts/load/prepro.hxx b/src/libs/antares/study/include/antares/study/parts/load/prepro.hxx index c0bb3b6f6d..7c39772bbf 100644 --- a/src/libs/antares/study/include/antares/study/parts/load/prepro.hxx +++ b/src/libs/antares/study/include/antares/study/parts/load/prepro.hxx @@ -24,11 +24,6 @@ namespace Antares::Data::Load { -inline uint64_t Prepro::memoryUsage() const -{ - return xcast.memoryUsage(); -} - inline bool Prepro::forceReload(bool reload) const { return xcast.forceReload(reload); diff --git a/src/libs/antares/study/include/antares/study/parts/renewable/cluster.h b/src/libs/antares/study/include/antares/study/parts/renewable/cluster.h index 3651706149..2a47b54bfe 100644 --- a/src/libs/antares/study/include/antares/study/parts/renewable/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/renewable/cluster.h @@ -128,12 +128,6 @@ class RenewableCluster final: public Cluster */ uint groupId() const override; - /*! - ** \brief Get the memory consummed by the renewable cluster (in bytes) - */ - uint64_t memoryUsage() const override; - //@} - bool setTimeSeriesModeFromString(const YString& value); YString getTimeSeriesModeAsString() const; diff --git a/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h index 275d495020..f8798845dc 100644 --- a/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h @@ -36,7 +36,6 @@ class RenewableClusterList: public ClusterList { public: std::string typeID() const override; - uint64_t memoryUsage() const override; bool loadFromFolder(const AnyString& folder, Area* area); bool validateClusters() const; diff --git a/src/libs/antares/study/include/antares/study/parts/solar/container.h b/src/libs/antares/study/include/antares/study/parts/solar/container.h index 390b72cd90..1fcbcda9e5 100644 --- a/src/libs/antares/study/include/antares/study/parts/solar/container.h +++ b/src/libs/antares/study/include/antares/study/parts/solar/container.h @@ -59,11 +59,6 @@ class Container */ void markAsModified() const; - /*! - ** \brief Get the amount of memory currently used by the class - */ - uint64_t memoryUsage() const; - //! Data for the pre-processor std::unique_ptr prepro; diff --git a/src/libs/antares/study/include/antares/study/parts/solar/prepro.h b/src/libs/antares/study/include/antares/study/parts/solar/prepro.h index 4365c0c6cf..da559acd99 100644 --- a/src/libs/antares/study/include/antares/study/parts/solar/prepro.h +++ b/src/libs/antares/study/include/antares/study/parts/solar/prepro.h @@ -59,11 +59,6 @@ class Prepro */ bool saveToFolder(const AnyString& folder) const; - /*! - ** \brief Get the amount of memory currently used - */ - uint64_t memoryUsage() const; - /*! ** \brief Make sure that all data are loaded in memory */ diff --git a/src/libs/antares/study/include/antares/study/parts/solar/prepro.hxx b/src/libs/antares/study/include/antares/study/parts/solar/prepro.hxx index 5bf5a90d98..b32aec13be 100644 --- a/src/libs/antares/study/include/antares/study/parts/solar/prepro.hxx +++ b/src/libs/antares/study/include/antares/study/parts/solar/prepro.hxx @@ -23,11 +23,6 @@ namespace Antares::Data::Solar { -inline uint64_t Prepro::memoryUsage() const -{ - return xcast.memoryUsage(); -} - inline bool Prepro::forceReload(bool reload) const { return xcast.forceReload(reload); diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h b/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h index 9216ac88aa..09ada6b8c1 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h @@ -185,12 +185,6 @@ class ThermalCluster final: public Cluster, public std::enable_shared_from_this< */ uint groupId() const override; - /*! - ** \brief Get the memory consummed by the thermal cluster (in bytes) - */ - uint64_t memoryUsage() const override; - //@} - //! \name validity of Min Stable Power //@{ // bool minStablePowerValidity() const; diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h index af3e096225..1aab721b56 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h @@ -38,7 +38,6 @@ class ThermalClusterList: public ClusterList { public: std::string typeID() const override; - uint64_t memoryUsage() const override; /*! ** \brief Get the size (bytes) occupied in memory by a `ThermalClusterList` structure diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/ecoInput.h b/src/libs/antares/study/include/antares/study/parts/thermal/ecoInput.h index c0456b8653..f538aa41cf 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/ecoInput.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/ecoInput.h @@ -73,11 +73,6 @@ class EconomicInputData */ bool saveToFolder(const AnyString& folder) const; - /*! - ** \brief Get the amount of memory used by the class - */ - uint64_t memoryUsage() const; - //! All {FO,PO}{Duration,Rate} annual values // max x DAYS_PER_YEAR TimeSeries::TS fuelcost; diff --git a/src/libs/antares/study/include/antares/study/parts/wind/container.h b/src/libs/antares/study/include/antares/study/parts/wind/container.h index ba149068f5..21d46d3a83 100644 --- a/src/libs/antares/study/include/antares/study/parts/wind/container.h +++ b/src/libs/antares/study/include/antares/study/parts/wind/container.h @@ -59,11 +59,6 @@ class Container */ void markAsModified() const; - /*! - ** \brief Get the amount of memory currently used by the class - */ - uint64_t memoryUsage() const; - //! Data for the pre-processor std::unique_ptr prepro; diff --git a/src/libs/antares/study/include/antares/study/parts/wind/prepro.h b/src/libs/antares/study/include/antares/study/parts/wind/prepro.h index 1d0ed8722e..2e75729b26 100644 --- a/src/libs/antares/study/include/antares/study/parts/wind/prepro.h +++ b/src/libs/antares/study/include/antares/study/parts/wind/prepro.h @@ -56,11 +56,6 @@ class Prepro */ bool saveToFolder(const AnyString& folder) const; - /*! - ** \brief Get the amount of memory currently used - */ - uint64_t memoryUsage() const; - /*! ** \brief Make sure that all data are loaded in memory */ diff --git a/src/libs/antares/study/include/antares/study/parts/wind/prepro.hxx b/src/libs/antares/study/include/antares/study/parts/wind/prepro.hxx index 5013c89f8c..a52b568902 100644 --- a/src/libs/antares/study/include/antares/study/parts/wind/prepro.hxx +++ b/src/libs/antares/study/include/antares/study/parts/wind/prepro.hxx @@ -24,11 +24,6 @@ namespace Antares::Data::Wind { -inline uint64_t Prepro::memoryUsage() const -{ - return xcast.memoryUsage(); -} - inline bool Prepro::forceReload(bool reload) const { return xcast.forceReload(reload); diff --git a/src/libs/antares/study/include/antares/study/simulation.h b/src/libs/antares/study/include/antares/study/simulation.h index b3ca6addd8..14d93d2568 100644 --- a/src/libs/antares/study/include/antares/study/simulation.h +++ b/src/libs/antares/study/include/antares/study/simulation.h @@ -65,9 +65,6 @@ class SimulationComments final void saveUsingWriter(Solver::IResultWriter& writer, const AnyString& folder) const; - //! Get (in bytes) the amount of memory used by the class - uint64_t memoryUsage() const; - public: //! Comments YString comments; diff --git a/src/libs/antares/study/include/antares/study/study.h b/src/libs/antares/study/include/antares/study/study.h index 9b348a28f5..7172948641 100644 --- a/src/libs/antares/study/include/antares/study/study.h +++ b/src/libs/antares/study/include/antares/study/study.h @@ -428,11 +428,6 @@ class Study: public Yuni::NonCopyable, public LayerData */ void ensureDataAreLoadedForAllBindingConstraints(); - /*! - ** \brief Get the amound of memory consummed by the study (in bytes) - */ - uint64_t memoryUsage() const; - //! \name Logs //@{ /*! diff --git a/src/libs/antares/study/include/antares/study/ui-runtimeinfos.h b/src/libs/antares/study/include/antares/study/ui-runtimeinfos.h index 61409977b3..0417cdaddb 100644 --- a/src/libs/antares/study/include/antares/study/ui-runtimeinfos.h +++ b/src/libs/antares/study/include/antares/study/ui-runtimeinfos.h @@ -137,8 +137,6 @@ class UIRuntimeInfo final uint visibleLinksCount(uint layerID); - uint64_t memoryUsage() const; - public: //! Areas ordered by their name + links ordered by their name Area::LinkMap orderedAreasAndLinks; diff --git a/src/libs/antares/study/include/antares/study/xcast/xcast.h b/src/libs/antares/study/include/antares/study/xcast/xcast.h index cc7e281763..a029eeaef7 100644 --- a/src/libs/antares/study/include/antares/study/xcast/xcast.h +++ b/src/libs/antares/study/include/antares/study/xcast/xcast.h @@ -159,17 +159,6 @@ class XCast final: private Yuni::NonCopyable */ void markAsModified() const; - /*! - ** \brief Get the amount of memory currently used by the XCast data - */ - uint64_t memoryUsage() const; - - /*! - ** \brief Estimate the amount of memory required by this class for a simulation - */ - - //@} - public: /*! ** \brief Data required for XCast: coefficients (coeffMax x 12) @@ -214,6 +203,4 @@ class XCast final: private Yuni::NonCopyable } // namespace Antares::Data -#include "xcast.hxx" - #endif // __ANTARES_LIBS_STUDY_XCAST_XCAST_H__ diff --git a/src/libs/antares/study/include/antares/study/xcast/xcast.hxx b/src/libs/antares/study/include/antares/study/xcast/xcast.hxx deleted file mode 100644 index e5072fb81e..0000000000 --- a/src/libs/antares/study/include/antares/study/xcast/xcast.hxx +++ /dev/null @@ -1,39 +0,0 @@ -/* -** 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 . -*/ -#ifndef __ANTARES_LIBS_STUDY_XCAST_XCAST_HXX__ -#define __ANTARES_LIBS_STUDY_XCAST_XCAST_HXX__ - -#include - -namespace Antares -{ -namespace Data -{ -inline uint64_t XCast::memoryUsage() const -{ - return sizeof(XCast) + data.memoryUsage() + K.memoryUsage() + translation.memoryUsage() - + conversion.memoryUsage(); -} - -} // namespace Data -} // namespace Antares - -#endif // __ANTARES_LIBS_STUDY_XCAST_XCAST_HXX__ diff --git a/src/libs/antares/study/parameters.cpp b/src/libs/antares/study/parameters.cpp index 72be2dd7b4..3772c4dd19 100644 --- a/src/libs/antares/study/parameters.cpp +++ b/src/libs/antares/study/parameters.cpp @@ -1376,12 +1376,6 @@ void Parameters::validateOptions(const StudyLoadOptions& options) handleOptimizationOptions(options); } -uint64_t Parameters::memoryUsage() const -{ - return sizeof(Parameters) + yearsWeight.size() * sizeof(double) - + yearsFilter.size(); // vector of bools, 1 bit per coefficient -} - void Parameters::resetYearsWeigth() { yearsWeight.clear(); diff --git a/src/libs/antares/study/parts/hydro/prepro.cpp b/src/libs/antares/study/parts/hydro/prepro.cpp index 13711759f4..772655567a 100644 --- a/src/libs/antares/study/parts/hydro/prepro.cpp +++ b/src/libs/antares/study/parts/hydro/prepro.cpp @@ -92,11 +92,6 @@ PreproHydro::PreproHydro() { } -uint64_t PreproHydroMemoryUsage(PreproHydro* h) -{ - return (h) ? sizeof(double) : 0; -} - void PreproHydro::reset() { intermonthlyCorrelation = 0.5; diff --git a/src/libs/antares/study/parts/hydro/series.cpp b/src/libs/antares/study/parts/hydro/series.cpp index 52a087b975..c816be84a0 100644 --- a/src/libs/antares/study/parts/hydro/series.cpp +++ b/src/libs/antares/study/parts/hydro/series.cpp @@ -213,12 +213,6 @@ bool DataSeriesHydro::saveToFolder(const AreaName& areaID, const AnyString& fold return false; } -uint64_t DataSeriesHydro::memoryUsage() const -{ - return sizeof(double) + ror.memoryUsage() + storage.memoryUsage() + mingen.memoryUsage() - + maxHourlyGenPower.memoryUsage() + maxHourlyPumpPower.memoryUsage(); -} - uint DataSeriesHydro::TScount() const { const std::vector nbColumns({storage.numberOfColumns(), diff --git a/src/libs/antares/study/parts/load/container.cpp b/src/libs/antares/study/parts/load/container.cpp index 364b761985..3866deee9f 100644 --- a/src/libs/antares/study/parts/load/container.cpp +++ b/src/libs/antares/study/parts/load/container.cpp @@ -55,11 +55,6 @@ void Container::markAsModified() const } } -uint64_t Container::memoryUsage() const -{ - return sizeof(Container) + series.memoryUsage() + ((!prepro) ? 0 : prepro->memoryUsage()); -} - void Container::resetToDefault() { series.reset(); diff --git a/src/libs/antares/study/parts/renewable/cluster.cpp b/src/libs/antares/study/parts/renewable/cluster.cpp index 749ed53a57..a89872d4f9 100644 --- a/src/libs/antares/study/parts/renewable/cluster.cpp +++ b/src/libs/antares/study/parts/renewable/cluster.cpp @@ -201,13 +201,6 @@ double RenewableCluster::valueAtTimeStep(uint year, uint hourInYear) const return 0.; } -uint64_t RenewableCluster::memoryUsage() const -{ - uint64_t amount = sizeof(RenewableCluster); - amount += series.memoryUsage(); - return amount; -} - unsigned int RenewableCluster::precision() const { return 4; diff --git a/src/libs/antares/study/parts/renewable/cluster_list.cpp b/src/libs/antares/study/parts/renewable/cluster_list.cpp index aa1c915a75..2b1ac3d3b6 100644 --- a/src/libs/antares/study/parts/renewable/cluster_list.cpp +++ b/src/libs/antares/study/parts/renewable/cluster_list.cpp @@ -38,13 +38,6 @@ std::string RenewableClusterList::typeID() const return "renewables"; } -uint64_t RenewableClusterList::memoryUsage() const -{ - uint64_t ret = sizeof(RenewableClusterList) + (2 * sizeof(void*)) * enabledCount(); - std::ranges::for_each(each_enabled(), [&ret](const auto c) { ret += c->memoryUsage(); }); - return ret; -} - bool RenewableClusterList::saveToFolder(const AnyString& folder) const { // Make sure the folder is created diff --git a/src/libs/antares/study/parts/solar/container.cpp b/src/libs/antares/study/parts/solar/container.cpp index 08c85a0cc0..19275684e4 100644 --- a/src/libs/antares/study/parts/solar/container.cpp +++ b/src/libs/antares/study/parts/solar/container.cpp @@ -55,11 +55,6 @@ void Container::markAsModified() const } } -uint64_t Container::memoryUsage() const -{ - return sizeof(Container) + series.memoryUsage() + ((!prepro) ? 0 : prepro->memoryUsage()); -} - void Container::resetToDefault() { series.reset(); diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index 9198bc1ec6..f85fae235e 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -616,18 +616,6 @@ const char* Data::ThermalCluster::GroupName(enum ThermalDispatchableGroup grp) return ""; } -uint64_t ThermalCluster::memoryUsage() const -{ - uint64_t amount = sizeof(ThermalCluster) + modulation.memoryUsage(); - if (prepro) - { - amount += prepro->memoryUsage(); - } - amount += series.memoryUsage(); - amount += ecoInput.memoryUsage(); - return amount; -} - void ThermalCluster::calculatMinDivModulation() { minDivModulation.value = (modulation[thermalModulationCapacity][0] diff --git a/src/libs/antares/study/parts/thermal/cluster_list.cpp b/src/libs/antares/study/parts/thermal/cluster_list.cpp index 05dec064cc..99d7fc21ac 100644 --- a/src/libs/antares/study/parts/thermal/cluster_list.cpp +++ b/src/libs/antares/study/parts/thermal/cluster_list.cpp @@ -63,14 +63,6 @@ std::string ThermalClusterList::typeID() const return "thermal"; } -uint64_t ThermalClusterList::memoryUsage() const -{ - uint64_t ret = sizeof(ThermalClusterList) + (2 * sizeof(void*)) * enabledAndMustRunCount(); - std::ranges::for_each(each_enabled_and_not_mustrun(), - [&ret](const auto c) { ret += c->memoryUsage(); }); - return ret; -} - static bool ThermalClusterLoadFromSection(const AnyString& filename, ThermalCluster& cluster, const IniFile::Section& section); diff --git a/src/libs/antares/study/parts/thermal/ecoInput.cpp b/src/libs/antares/study/parts/thermal/ecoInput.cpp index c64b65a33d..a25c666f33 100644 --- a/src/libs/antares/study/parts/thermal/ecoInput.cpp +++ b/src/libs/antares/study/parts/thermal/ecoInput.cpp @@ -123,9 +123,4 @@ void EconomicInputData::reset() co2cost.reset(1, HOURS_PER_YEAR, true); } -uint64_t EconomicInputData::memoryUsage() const -{ - return sizeof(EconomicInputData); -} - } // namespace Antares::Data diff --git a/src/libs/antares/study/parts/wind/container.cpp b/src/libs/antares/study/parts/wind/container.cpp index 64575b73ab..bf90f779b8 100644 --- a/src/libs/antares/study/parts/wind/container.cpp +++ b/src/libs/antares/study/parts/wind/container.cpp @@ -54,11 +54,6 @@ void Container::markAsModified() const } } -uint64_t Container::memoryUsage() const -{ - return sizeof(Container) + series.memoryUsage() + ((!prepro) ? 0 : prepro->memoryUsage()); -} - void Container::resetToDefault() { series.reset(); diff --git a/src/libs/antares/study/runtime/runtime.cpp b/src/libs/antares/study/runtime/runtime.cpp index bef958919d..3bca4404a5 100644 --- a/src/libs/antares/study/runtime/runtime.cpp +++ b/src/libs/antares/study/runtime/runtime.cpp @@ -366,7 +366,6 @@ bool StudyRuntimeInfos::loadFromStudy(Study& study) logs.info() << " binding constraints: " << study.bindingConstraints.activeConstraints().size(); logs.info() << " geographic trimming:" << (gd.geographicTrimming ? "true" : "false"); - logs.info() << " memory : " << ((study.memoryUsage()) / 1024 / 1024) << "Mo"; logs.info(); return true; diff --git a/src/libs/antares/study/simulation.cpp b/src/libs/antares/study/simulation.cpp index cb4465130a..12db9184ca 100644 --- a/src/libs/antares/study/simulation.cpp +++ b/src/libs/antares/study/simulation.cpp @@ -90,10 +90,5 @@ bool SimulationComments::loadFromFolder(const StudyLoadOptions& options) return true; } -uint64_t SimulationComments::memoryUsage() const -{ - return name.capacity() + comments.capacity(); -} - } // namespace Data } // namespace Antares diff --git a/src/libs/antares/study/study.cpp b/src/libs/antares/study/study.cpp index 1b5493e750..39130a968e 100644 --- a/src/libs/antares/study/study.cpp +++ b/src/libs/antares/study/study.cpp @@ -187,26 +187,6 @@ void Study::reduceMemoryUsage() ClearAndShrink(bufferLoadingTS); } -// TODO remove with GUI -uint64_t Study::memoryUsage() const -{ - return buffer.capacity() // Folders paths - + dataBuffer.capacity() - + bufferLoadingTS.capacity() - // Simulation - + simulationComments.memoryUsage() - // parameters - + parameters.memoryUsage() - // Areas - + areas.memoryUsage() - // Binding constraints - + bindingConstraints.memoryUsage() - // Correlations matrices - + preproLoadCorrelation.memoryUsage() + preproSolarCorrelation.memoryUsage() - + preproHydroCorrelation.memoryUsage() + preproWindCorrelation.memoryUsage() - + (uiinfo ? uiinfo->memoryUsage() : 0); -} - unsigned Study::getNumberOfCoresPerMode(unsigned nbLogicalCores, int ncMode) { if (!nbLogicalCores) diff --git a/src/libs/antares/study/ui-runtimeinfos.cpp b/src/libs/antares/study/ui-runtimeinfos.cpp index 5140656226..de042cc785 100644 --- a/src/libs/antares/study/ui-runtimeinfos.cpp +++ b/src/libs/antares/study/ui-runtimeinfos.cpp @@ -143,11 +143,6 @@ void UIRuntimeInfo::reloadBindingConstraints() } } -uint64_t UIRuntimeInfo::memoryUsage() const -{ - return sizeof(UIRuntimeInfo) + sizeof(AreaLink*) * pLink.size(); -} - uint UIRuntimeInfo::countItems(BindingConstraint::Operator op, BindingConstraint::Type type) { ByOperatorAndType::const_iterator i = byOperator.find(op); diff --git a/src/solver/simulation/include/antares/solver/simulation/solver.hxx b/src/solver/simulation/include/antares/solver/simulation/solver.hxx index 7f4a63ab82..7a47a75e69 100644 --- a/src/solver/simulation/include/antares/solver/simulation/solver.hxx +++ b/src/solver/simulation/include/antares/solver/simulation/solver.hxx @@ -280,8 +280,6 @@ void ISimulation::run() // Memory usage { - logs.info() << " Variables: (" - << (uint)(ImplementationType::variables.memoryUsage() / 1024 / 1024) << "Mo)"; Variable::PrintInfosStdCout c; ImplementationType::variables.template provideInformations(c); } diff --git a/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h b/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h index 850463b580..ff3416bb67 100644 --- a/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h +++ b/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h @@ -95,11 +95,6 @@ class PreproAvailability */ bool saveToFolder(const AnyString& folder) const; - /*! - ** \brief Get the amount of memory used by the class - */ - uint64_t memoryUsage() const; - /*! ** \brief Normalize NPO max and check for consistency ** diff --git a/src/solver/ts-generator/prepro.cpp b/src/solver/ts-generator/prepro.cpp index b26faefb50..943527c8e7 100644 --- a/src/solver/ts-generator/prepro.cpp +++ b/src/solver/ts-generator/prepro.cpp @@ -155,11 +155,6 @@ void PreproAvailability::markAsModified() const data.markAsModified(); } -uint64_t PreproAvailability::memoryUsage() const -{ - return sizeof(PreproAvailability); -} - void PreproAvailability::reset() { data.reset(preproAvailabilityMax, DAYS_PER_YEAR, true); diff --git a/src/solver/variable/include/antares/solver/variable/area.h b/src/solver/variable/include/antares/solver/variable/area.h index 9328c27ba8..3f380a0941 100644 --- a/src/solver/variable/include/antares/solver/variable/area.h +++ b/src/solver/variable/include/antares/solver/variable/area.h @@ -163,8 +163,6 @@ class Areas //: public Variable::IVariable, NextT, VCardAllAreas> void beforeYearByYearExport(uint year, uint numSpace); - uint64_t memoryUsage() const; - template static void provideInformations(I& infos); diff --git a/src/solver/variable/include/antares/solver/variable/area.hxx b/src/solver/variable/include/antares/solver/variable/area.hxx index d3b34bb973..60028d1a85 100644 --- a/src/solver/variable/include/antares/solver/variable/area.hxx +++ b/src/solver/variable/include/antares/solver/variable/area.hxx @@ -538,19 +538,6 @@ void Areas::beforeYearByYearExport(uint year, uint numSpace) pAreas[i].beforeYearByYearExport(year, numSpace); } } - -template -uint64_t Areas::memoryUsage() const -{ - uint64_t result = 0; - for (unsigned int i = 0; i != pAreaCount; ++i) - { - result += sizeof(NextType) + sizeof(void*); // overhead vector - result += pAreas[i].memoryUsage(); - } - return result; -} - } // namespace Variable } // namespace Solver } // namespace Antares diff --git a/src/solver/variable/include/antares/solver/variable/bindConstraints.h b/src/solver/variable/include/antares/solver/variable/bindConstraints.h index b10d7e9186..9bf44dd85e 100644 --- a/src/solver/variable/include/antares/solver/variable/bindConstraints.h +++ b/src/solver/variable/include/antares/solver/variable/bindConstraints.h @@ -152,8 +152,6 @@ class BindingConstraints int precision, uint numSpace) const; - uint64_t memoryUsage() const; - template void yearEndSpatialAggregates(V&, uint, uint) { diff --git a/src/solver/variable/include/antares/solver/variable/bindConstraints.hxx b/src/solver/variable/include/antares/solver/variable/bindConstraints.hxx index 63738c4f5c..f1824c67da 100644 --- a/src/solver/variable/include/antares/solver/variable/bindConstraints.hxx +++ b/src/solver/variable/include/antares/solver/variable/bindConstraints.hxx @@ -234,18 +234,6 @@ void BindingConstraints::hourEnd(State& state, uint hourInTheYear) } } -template -uint64_t BindingConstraints::memoryUsage() const -{ - uint64_t result = 0; - for (unsigned int i = 0; i != pBCcount; ++i) - { - result += sizeof(NextType) + sizeof(void*); // overhead vector - result += pBindConstraints[i].memoryUsage(); - } - return result; -} - template void BindingConstraints::weekForEachArea(State& state, unsigned int numSpace) { diff --git a/src/solver/variable/include/antares/solver/variable/commons/join.h b/src/solver/variable/include/antares/solver/variable/commons/join.h index 37f048ec83..09d067a97a 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/join.h +++ b/src/solver/variable/include/antares/solver/variable/commons/join.h @@ -326,11 +326,6 @@ class Join: public Variable::IVariable, Yuni::Default, VCard RightType::template simulationEndSpatialAggregates(allVars); } - uint64_t memoryUsage() const - { - return LeftType::memoryUsage() + RightType::memoryUsage(); - } - template static void provideInformations(I& infos) { diff --git a/src/solver/variable/include/antares/solver/variable/commons/links/links.h b/src/solver/variable/include/antares/solver/variable/commons/links/links.h index eff3b7d09d..f7b29c6fd0 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/links/links.h +++ b/src/solver/variable/include/antares/solver/variable/commons/links/links.h @@ -174,8 +174,6 @@ class Links void beforeYearByYearExport(uint year, uint numSpace); - uint64_t memoryUsage() const; - void buildDigest(SurveyResults& results, int digestLevel, int dataLevel) const; template diff --git a/src/solver/variable/include/antares/solver/variable/commons/links/links.hxx b/src/solver/variable/include/antares/solver/variable/commons/links/links.hxx index d56090f7d3..00ba05bbe4 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/links/links.hxx +++ b/src/solver/variable/include/antares/solver/variable/commons/links/links.hxx @@ -348,18 +348,6 @@ void Links::RetrieveVariableList(PredicateT& predicate) NextType::RetrieveVariableList(predicate); } -template -inline uint64_t Links::memoryUsage() const -{ - uint64_t result = 0; - for (uint i = 0; i != pLinkCount; ++i) - { - result += sizeof(NextType) + sizeof(void*); - result += pLinks[i].memoryUsage(); - } - return result; -} - template Links::~Links() { diff --git a/src/solver/variable/include/antares/solver/variable/container.h b/src/solver/variable/include/antares/solver/variable/container.h index 94a3997b79..23938f71f1 100644 --- a/src/solver/variable/include/antares/solver/variable/container.h +++ b/src/solver/variable/include/antares/solver/variable/container.h @@ -220,12 +220,6 @@ class List: public NextT void buildDigest(SurveyResults& results, int digestLevel, int dataLevel) const; //@} - //! \name Memory management - //@{ - //! Get the amount of memory currently used by the class - uint64_t memoryUsage() const; - //@} - private: //! Pointer to the current study Data::Study* pStudy; diff --git a/src/solver/variable/include/antares/solver/variable/container.hxx b/src/solver/variable/include/antares/solver/variable/container.hxx index 0f9559b3a2..2435a2ef8d 100644 --- a/src/solver/variable/include/antares/solver/variable/container.hxx +++ b/src/solver/variable/include/antares/solver/variable/container.hxx @@ -237,12 +237,6 @@ inline void List::retrieveResultsForLink( NextType::template retrieveResultsForLink(result, link); } -template -inline uint64_t List::memoryUsage() const -{ - return sizeof(ListType) + NextType::memoryUsage(); -} - template void List::buildSurveyReport(SurveyResults& results, int dataLevel, diff --git a/src/solver/variable/include/antares/solver/variable/economy/STSbyGroup.h b/src/solver/variable/include/antares/solver/variable/economy/STSbyGroup.h index 4e3ad6ee7c..5ea9c01af4 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/STSbyGroup.h +++ b/src/solver/variable/include/antares/solver/variable/economy/STSbyGroup.h @@ -337,15 +337,6 @@ class STSbyGroup: public Variable::IVariable, NextT, VCardSTSb return pValuesForTheCurrentYear[numSpace][column].hour; } - inline uint64_t memoryUsage() const - { - uint64_t r = (sizeof(IntermediateValues) * nbColumns_ + IntermediateValues::MemoryUsage()) - * pNbYearsParallel; - r += sizeof(double) * nbColumns_ * HOURS_PER_YEAR * pNbYearsParallel; - r += AncestorType::memoryUsage(); - return r; - } - std::string caption(unsigned int column) const { static const std::vector VAR_POSSIBLE_KINDS = {"INJECTION", diff --git a/src/solver/variable/include/antares/solver/variable/economy/STStorageCashFlowByCluster.h b/src/solver/variable/include/antares/solver/variable/economy/STStorageCashFlowByCluster.h index eb2eaa48b9..9893049943 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/STStorageCashFlowByCluster.h +++ b/src/solver/variable/include/antares/solver/variable/economy/STStorageCashFlowByCluster.h @@ -259,15 +259,6 @@ class STstorageCashFlowByCluster: public Variable::IVariable static void provideInformations(I&) { diff --git a/src/solver/variable/include/antares/solver/variable/info.h b/src/solver/variable/include/antares/solver/variable/info.h index 39c6a43e42..2eaa3df68f 100644 --- a/src/solver/variable/include/antares/solver/variable/info.h +++ b/src/solver/variable/include/antares/solver/variable/info.h @@ -162,16 +162,6 @@ struct VariableAccessor } } - static uint64_t Value(const Type& container) - { - uint64_t result = 0; - for (uint i = 0; i != ColumnCountT; ++i) - { - result += container[i].memoryUsage(); - } - return result; - } - template static void BuildDigest(SurveyResults& results, const Type& container, @@ -383,17 +373,6 @@ struct VariableAccessor } } - static uint64_t Value(const Type& container) - { - uint64_t result = 0; - const typename Type::const_iterator end = container.end(); - for (typename Type::const_iterator i = container.begin(); i != end; ++i) - { - result += sizeof(ResultsT) + (*i).memoryUsage(); - } - return result; - } - template static void BuildDigest(SurveyResults& results, const Type& container, @@ -620,11 +599,6 @@ struct VariableAccessor container.merge(year, intermediateValues); } - static uint64_t Value(const Type& container) - { - return container.memoryUsage(); - } - template static void BuildDigest(SurveyResults& results, const Type& container, diff --git a/src/solver/variable/include/antares/solver/variable/setofareas.h b/src/solver/variable/include/antares/solver/variable/setofareas.h index 1263b986f3..74c68528ba 100644 --- a/src/solver/variable/include/antares/solver/variable/setofareas.h +++ b/src/solver/variable/include/antares/solver/variable/setofareas.h @@ -161,8 +161,6 @@ class SetsOfAreas void beforeYearByYearExport(uint year, uint numSpace); - uint64_t memoryUsage() const; - template static void provideInformations(I& infos); diff --git a/src/solver/variable/include/antares/solver/variable/setofareas.hxx b/src/solver/variable/include/antares/solver/variable/setofareas.hxx index 630ded8903..19e60f2997 100644 --- a/src/solver/variable/include/antares/solver/variable/setofareas.hxx +++ b/src/solver/variable/include/antares/solver/variable/setofareas.hxx @@ -266,17 +266,6 @@ void SetsOfAreas::buildDigest(SurveyResults& results, int digestLevel, in } } -template -inline uint64_t SetsOfAreas::memoryUsage() const -{ - uint64_t result = sizeof(NextType) * pSetsOfAreas.size(); - for (auto i = pBegin; i != pEnd; ++i) - { - result += (*i)->memoryUsage(); - } - return result; -} - template template inline void SetsOfAreas::provideInformations(I& infos) diff --git a/src/solver/variable/include/antares/solver/variable/storage/average.h b/src/solver/variable/include/antares/solver/variable/storage/average.h index fbeaf16a5b..43718fd4ca 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/average.h +++ b/src/solver/variable/include/antares/solver/variable/storage/average.h @@ -161,11 +161,6 @@ struct Average: public NextT NextType::template buildDigest(report, digestLevel, dataLevel); } - uint64_t memoryUsage() const - { - return avgdata.dynamicMemoryUsage() + NextType::memoryUsage(); - } - template class DecoratorT> Antares::Memory::Stored::ConstReturnType hourlyValuesForSpatialAggregate() const { diff --git a/src/solver/variable/include/antares/solver/variable/storage/averagedata.h b/src/solver/variable/include/antares/solver/variable/storage/averagedata.h index 132b70317d..57c03820b5 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/averagedata.h +++ b/src/solver/variable/include/antares/solver/variable/storage/averagedata.h @@ -52,11 +52,6 @@ class AverageData void merge(unsigned int year, const IntermediateValues& rhs); - uint64_t dynamicMemoryUsage() const - { - return sizeof(double) * HOURS_PER_YEAR + sizeof(double) * nbYearsCapacity; - } - public: double monthly[MONTHS_PER_YEAR]; double weekly[WEEKS_PER_YEAR]; diff --git a/src/solver/variable/include/antares/solver/variable/storage/empty.h b/src/solver/variable/include/antares/solver/variable/storage/empty.h index 354c0f4545..747f87ae2f 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/empty.h +++ b/src/solver/variable/include/antares/solver/variable/storage/empty.h @@ -71,11 +71,6 @@ struct Empty // Does nothing } - static uint64_t memoryUsage() - { - return 0; - } - template class DecoratorT> static Antares::Memory::Stored::ConstReturnType hourlyValuesForSpatialAggregate() { diff --git a/src/solver/variable/include/antares/solver/variable/storage/intermediate.h b/src/solver/variable/include/antares/solver/variable/storage/intermediate.h index e7c1757c62..661baf7eaa 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/intermediate.h +++ b/src/solver/variable/include/antares/solver/variable/storage/intermediate.h @@ -49,11 +49,6 @@ class IntermediateValues final typedef double Type; public: - //! Get the dynamic amount of memory consummed by a simulation - // \note This method assumes that you've already have gathered the size - // of this class - static uint64_t MemoryUsage(); - //! \name Constructor & Destructor //@{ /*! diff --git a/src/solver/variable/include/antares/solver/variable/storage/intermediate.hxx b/src/solver/variable/include/antares/solver/variable/storage/intermediate.hxx index 9dd74a235a..78a1806ede 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/intermediate.hxx +++ b/src/solver/variable/include/antares/solver/variable/storage/intermediate.hxx @@ -53,11 +53,6 @@ inline const IntermediateValues::Type& IntermediateValues::operator[]( return hour[index]; } -inline uint64_t IntermediateValues::MemoryUsage() -{ - return +sizeof(Type) * HOURS_PER_YEAR; -} - template inline void IntermediateValues::buildAnnualSurveyReport(SurveyResults& report, int fileLevel, diff --git a/src/solver/variable/include/antares/solver/variable/storage/minmax.h b/src/solver/variable/include/antares/solver/variable/storage/minmax.h index 6095863374..4d8c210435 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/minmax.h +++ b/src/solver/variable/include/antares/solver/variable/storage/minmax.h @@ -143,11 +143,6 @@ struct MinMaxBase: public NextT void merge(uint year, const IntermediateValues& rhs); - uint64_t memoryUsage() const - { - return sizeof(double) * HOURS_PER_YEAR + NextType::memoryUsage(); - } - template class DecoratorT> Antares::Memory::Stored::ConstReturnType hourlyValuesForSpatialAggregate() const { diff --git a/src/solver/variable/include/antares/solver/variable/storage/raw.h b/src/solver/variable/include/antares/solver/variable/storage/raw.h index fe6c444840..0d2cf279fc 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/raw.h +++ b/src/solver/variable/include/antares/solver/variable/storage/raw.h @@ -159,11 +159,6 @@ struct Raw: public NextT NextType::template buildDigest(report, digestLevel, dataLevel); } - uint64_t memoryUsage() const - { - return +sizeof(double) * HOURS_PER_YEAR + NextType::memoryUsage(); - } - template class DecoratorT> Antares::Memory::Stored::ConstReturnType hourlyValuesForSpatialAggregate() const { diff --git a/src/solver/variable/include/antares/solver/variable/storage/results.h b/src/solver/variable/include/antares/solver/variable/storage/results.h index e699d563e4..ddb809ce85 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/results.h +++ b/src/solver/variable/include/antares/solver/variable/storage/results.h @@ -91,11 +91,6 @@ class Results: public FirstDecoratorT DecoratorType::template buildDigest(results, digestLevel, dataLevel); } - uint64_t memoryUsage() const - { - return DecoratorType::memoryUsage(); - } - Antares::Memory::Stored::ConstReturnType hourlyValuesForSpatialAggregate() const { return DecoratorType::template hourlyValuesForSpatialAggregate< diff --git a/src/solver/variable/include/antares/solver/variable/storage/stdDeviation.h b/src/solver/variable/include/antares/solver/variable/storage/stdDeviation.h index 44159d9cba..ddda4cd3b5 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/stdDeviation.h +++ b/src/solver/variable/include/antares/solver/variable/storage/stdDeviation.h @@ -179,11 +179,6 @@ struct StdDeviation: public NextT precision); } - uint64_t memoryUsage() const - { - return sizeof(double) * HOURS_PER_YEAR + NextType::memoryUsage(); - } - template class DecoratorT> Antares::Memory::Stored::ConstReturnType hourlyValuesForSpatialAggregate() const { diff --git a/src/solver/variable/include/antares/solver/variable/variable.h b/src/solver/variable/include/antares/solver/variable/variable.h index 279ba9da3d..4e986607d8 100644 --- a/src/solver/variable/include/antares/solver/variable/variable.h +++ b/src/solver/variable/include/antares/solver/variable/variable.h @@ -273,13 +273,6 @@ class IVariable: protected NextT void beforeYearByYearExport(uint year, uint numSpace); //@} - //! \name Misc - //@{ - /*! - ** \brief Get the memory used by this variable and all other in the static list - */ - uint64_t memoryUsage() const; - /*! ** \brief "Print" informations about the variable tree */ diff --git a/src/solver/variable/include/antares/solver/variable/variable.hxx b/src/solver/variable/include/antares/solver/variable/variable.hxx index 6b2ba73a55..ee031633f8 100644 --- a/src/solver/variable/include/antares/solver/variable/variable.hxx +++ b/src/solver/variable/include/antares/solver/variable/variable.hxx @@ -356,25 +356,6 @@ inline void IVariable::beforeYearByYearExport(uint year, NextType::beforeYearByYearExport(year, numspace); } -template -inline uint64_t IVariable::memoryUsage() const -{ - uint64_t r = VariableAccessorType::Value(pResults); - if (VCardT::columnCount != (int)Category::dynamicColumns) - { - // Intermediate values - if (VCardT::hasIntermediateValues) - { - for (uint i = 0; i != (uint)VCardT::columnCount; ++i) - { - r += IntermediateValues::MemoryUsage(); - } - } - } - r += NextType::memoryUsage(); - return r; -} - template template inline void IVariable::provideInformations(I& infos) From b5618092a5ece25530138e57aacad963968e5d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Fri, 11 Oct 2024 14:00:29 +0200 Subject: [PATCH 035/103] Add a few const ref qualifiers to improve code readibility (#2459) --- src/solver/simulation/common-hydro-remix.cpp | 2 +- .../solver/simulation/sim_structure_probleme_economique.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/solver/simulation/common-hydro-remix.cpp b/src/solver/simulation/common-hydro-remix.cpp index de8e3f5328..be94eba549 100644 --- a/src/solver/simulation/common-hydro-remix.cpp +++ b/src/solver/simulation/common-hydro-remix.cpp @@ -59,7 +59,7 @@ static bool Remix(const Data::AreaList& areas, auto& D = weeklyResults.ValeursHorairesDeDefaillancePositive; - auto& S = weeklyResults.ValeursHorairesDeDefaillanceNegative; + const auto& S = weeklyResults.ValeursHorairesDeDefaillanceNegative; auto& H = weeklyResults.TurbinageHoraire; 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 aa46e5962d..29dd7c38f5 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 @@ -333,18 +333,18 @@ class computeTimeStepLevel double capacity; std::vector& inflows; std::vector& ovf; - std::vector& turb; + const std::vector& turb; double pumpRatio; - std::vector& pump; + const std::vector& pump; double excessDown; public: computeTimeStepLevel(const double& startLvl, std::vector& infl, std::vector& overfl, - std::vector& H, + const std::vector& H, double pumpEff, - std::vector& Pump, + const std::vector& Pump, double rc): step(0), level(startLvl), From 07b84b578f0231fd9cb8e389a67eed0b636f963e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 14 Oct 2024 13:49:06 +0200 Subject: [PATCH 036/103] Migration guide for version 9.2 (#2460) --- docs/user-guide/04-migration-guides.md | 41 +++++++++++++++++--------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/docs/user-guide/04-migration-guides.md b/docs/user-guide/04-migration-guides.md index eca0ef0fbe..51fc738920 100644 --- a/docs/user-guide/04-migration-guides.md +++ b/docs/user-guide/04-migration-guides.md @@ -2,32 +2,45 @@ This is a list of all recent changes that came with new Antares Simulator features. The main goal of this document is to lower the costs of changing existing interfaces, both GUI and scripts. ## v9.2.0 -### Adequacy Patch LMR -Removed following properties from **settings/generaldata.ini**. -- enable-first-step -- set-to-null-ntc-between-physical-out-for-first-step +### Input +#### Removed properties +The following properties were removed from **settings/generaldata.ini**. +- `adequacy patch/enable-first-step` +- `adequacy patch/set-to-null-ntc-between-physical-out-for-first-step` +- `other preferences/initial-reservoir-levels` +#### Short-term storages +- Added property `efficiencywithdrawal` (double in [0, 1], default 1) short-term storages (file input/st-storage/clusters//list.ini) +- Added timeseries cost-injection.txt, cost-withdrawal.txt and cost-level.txt. These files are optional. If present, they must contain either no value (same behavior as no file), or HOURS_PER_YEAR = 8760 coefficients in one column. Each of these timeseries is located in directory input/st-storage/series///, along existing series (rule-curves.txt, etc.). + +#### Final levels / scenario-builder +- Added optional key type "hfl" (hydro final level) in the scenario builder. The syntax is equivalent to existing prefix "hl" (hydro initial level), that is +``` +hl,area, = +``` + +By convention, `year` start at 0 and `value` must be in interval [0, 1]. + +#### Compatibility flag for hydro pmax coefficients +In file settings/generaldata.ini, in section `other preferences`, add property `hydro-pmax-format` with possible values `daily` (default, legacy) and `hourly` (new). + +Note: This flag allows to bypass the breaking change that took place in version 9.1 for hydro max powers. It is possible to support only the `legacy` file format. + ### (TS-generator only) TS generation for link capacities In files input/links//properties.ini, add the following properties -- tsgen_direct_XXX, -- tsgen_indirect_XXX -with XXX in - unitcount (unsigned int, default 1) -- nominalcapacity (float) -- law.planned (string "uniform"/"geometric") +- nominalcapacity (float, default 0) +- law.planned (string "uniform"/"geometric", default "uniform") - law.forced (same) -- volatility.planned (double in [0,1]) +- volatility.planned (double in [0,1], default 0) - volatility.forced (same) +- force-no-generation (true/false, default true) - "prepro" timeseries => input/links//prepro/_{direct, indirect}.txt, 365x6 values, respectively "forced outage duration", "planned outage duration", "forced outage rate", "planned outage rate", "minimum of groups in maintenance", "maximum of groups in maintenance". - "modulation" timeseries => input/links//prepro/_mod_{direct, indirect}.txt, 8760x1 values each in [0, 1] - number of TS to generate => generaldata.ini/General/nbtimeserieslinks (unsigned int, default value 1) -### Input -#### Short term storage: efficiency for withdrawal -In input/st-storage/area/list.ini add property: `efficiencywithdrawal` [double] in range 0-1 - ### Output - Remove column SPIL ENRG CSR (adequacy patch) - Add DTG MRG CSR and UNSP ENRG CSR variables From 426984516e4d96d95c29a5f1f43aa60fdd771285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 14 Oct 2024 17:49:42 +0200 Subject: [PATCH 037/103] batchrun forwards options to antares-solver [ANT-2314] (#2463) So there's no need to batchrun when/if new options appear for antares-solver. --- src/tools/batchrun/main.cpp | 232 +++++------------------------------- 1 file changed, 30 insertions(+), 202 deletions(-) diff --git a/src/tools/batchrun/main.cpp b/src/tools/batchrun/main.cpp index e2fb2e2278..9a31f4ecdf 100644 --- a/src/tools/batchrun/main.cpp +++ b/src/tools/batchrun/main.cpp @@ -85,163 +85,32 @@ int main(int argc, const char* argv[]) // Initializing the toolbox Antares::Resources::Initialize(argc, argv, true); - // options - std::string optInput; - std::string ortoolsSolver; - bool optNoTSImport = false; - bool optIgnoreAllConstraints = false; - bool optForceExpansion = false; - bool optForceEconomy = false; - bool optForceAdequacy = false; - bool optForce = false; - bool optYearByYear = false; - bool optNoOutput = false; - bool optParallel = false; - bool optVerbose = false; - bool ortoolsUsed = false; - Nullable optYears; - Nullable optSolver; - Nullable optName; - Nullable optForceParallel; - - // Command Line options + if (argc < 2) { - // Parser - GetOpt::Parser options; - // - options.addParagraph(String() << "Antares Batch Simulation Launcher v" << VersionToCString() - << "\n"); - // Input - options.addParagraph("Studies"); - options.add(optInput, 'i', "input", "The input folder, where to find some studies"); - - // Simulation mode - options.addParagraph("\nSimulation mode"); - options.addFlag(optForceExpansion, - ' ', - "economy", - "Force the simulation(s) in expansion mode"); - options.addFlag(optForceEconomy, ' ', "economy", "Force the simulation(s) in economy mode"); - options.addFlag(optForceAdequacy, - ' ', - "adequacy", - "Force the simulation(s) in adequacy mode"); - - options.addParagraph("\nParameters"); - options.add(optName, 'n', "name", "Set the name of the new simulation outputs"); - options.add(optYears, 'y', "year", "Override the number of MC years"); - options.addFlag(optForce, 'f', "force", "Ignore all warnings at loading"); - options.addFlag(optNoOutput, - ' ', - "no-output", - "Do not write the results in the output folder"); - options.addFlag(optYearByYear, - ' ', - "year-by-year", - "Force the writing of the result output for each year"); - - options.addParagraph("\nOptimization"); - options.addFlag(optNoTSImport, - ' ', - "no-ts-import", - "Do not import timeseries into the input folder."); - options.addFlag(optIgnoreAllConstraints, ' ', "no-constraints", "Ignore all constraints"); - - options.addParagraph("\nExtras"); - options.add(optSolver, ' ', "solver", "Specify the antares-solver location"); - options.addFlag(optParallel, - 'p', - "parallel", - "Enable the parallel computation of MC years"); - options.add(optForceParallel, - ' ', - "force-parallel", - "Override the max number of years computed simultaneously"); - - // add option for ortools use - // --use-ortools - options.addFlag(ortoolsUsed, ' ', "use-ortools", "Use ortools library to launch solver"); - - //--ortools-solver - options.add(ortoolsSolver, - ' ', - "ortools-solver", - "Ortools solver used for simulation (only available with use-ortools " - "option)\nAvailable solver list : " - + availableOrToolsSolversString()); - - options.remainingArguments(optInput); - // Version - options.addParagraph("\nMisc."); - bool optVersion = false; - options.addFlag(optVersion, 'v', "version", "Print the version and exit"); - options.addFlag(optVerbose, ' ', "verbose", "Displays study runs outputs"); - - if (options(argc, argv) == GetOpt::ReturnCode::error) - { - return options.errors() ? 1 : 0; - } + logs.error() << "Usage " << argv[0] << " optInput [other options]"; + return EXIT_FAILURE; + } - if (optVersion) - { - PrintVersionToStdCout(); - return 0; - } + const bool optVerbose = false; + // Command Line options + { + const std::string optInput(argv[1]); if (optInput.empty()) { logs.error() << "A folder input is required."; return EXIT_FAILURE; } - if (optForceExpansion and optForceAdequacy) - { - logs.error() << "contradictory options: --expansion and --adequacy"; - return EXIT_FAILURE; - } - - if (optForceEconomy and optForceAdequacy) - { - logs.error() << "contradictory options: --economy and --adequacy"; - return EXIT_FAILURE; - } - - if (ortoolsUsed) - { - const auto availableSolvers = getAvailableOrtoolsSolverName(); - if (auto it = std::find(availableSolvers.begin(), - availableSolvers.end(), - ortoolsSolver); - it == availableSolvers.end()) - { - logs.error() << "Please specify a solver using --ortools-solver. Available solvers " - << availableOrToolsSolversString() << ""; - return EXIT_FAILURE; - } - } - // Source Folder logs.debug() << "Folder : `" << optInput << '`'; String solver; - if (optSolver.empty()) + Solver::FindLocation(solver); + if (solver.empty()) { - Solver::FindLocation(solver); - if (solver.empty()) - { - logs.fatal() << "The solver has not been found"; - return EXIT_FAILURE; - } - } - else - { - std::string tmp = *optSolver; - fs::path solverPath = fs::absolute(tmp).lexically_normal(); - if (!fs::exists(solverPath)) - { - logs.fatal() << "The solver has not been found. specify --solver=" << solver; - return EXIT_FAILURE; - } + logs.fatal() << "The solver has not been found"; + return EXIT_FAILURE; } logs.info() << " Solver: '" << solver << "'"; @@ -257,7 +126,7 @@ int main(int argc, const char* argv[]) { if (finder.list.size() > 1) { - logs.info() << "Found " << finder.list.size() << " studyies"; + logs.info() << "Found " << finder.list.size() << " studies"; } else { @@ -265,14 +134,6 @@ int main(int argc, const char* argv[]) } logs.info() << "Starting..."; - if (!(!optName)) - { - String name; - name = *optName; - name.replace("\"", "\\\""); - *optName = name; - } - // The folder that contains the solver String dirname; IO::parent_path(dirname, solver); @@ -307,57 +168,24 @@ int main(int argc, const char* argv[]) cmd << "call "; // why is it required for working ??? } cmd << "\"" << solver << "\""; - if (optForce) - { - cmd << " --force"; - } - if (optForceExpansion) - { - cmd << " --economy"; - } - if (optForceEconomy) - { - cmd << " --economy"; - } - if (optForceAdequacy) - { - cmd << " --adequacy"; - } - if (!(!optName)) - { - cmd << " --name=\"" << *optName << "\""; - } - if (!(!optYears)) - { - cmd << " --year=" << *optYears; - } - if (optNoOutput) - { - cmd << " --no-output"; - } - if (optYearByYear) - { - cmd << " --year-by-year"; - } - if (optNoTSImport) - { - cmd << " --no-ts-import"; - } - if (optIgnoreAllConstraints) - { - cmd << " --no-constraints"; - } - if (optParallel) - { - cmd << " --parallel"; - } - if (optForceParallel) - { - cmd << " --force-parallel=" << *optForceParallel; - } - if (ortoolsUsed) + + // argv[0] => executable name + // argv[1] => directory name + for (int ii = 2; ii < argc; ii++) { - cmd << " --use-ortools --ortools-solver=" << ortoolsSolver; + const std::string arg(argv[ii]); + if (arg.find(" ") == std::string::npos) + { + cmd << " " << arg; + } + else + { + // Wrap spaces around quotes, if any + // example + // antares-batchrun directory --use-ortools --ortools-solver xpress + // --solver-parameters "PRESOLVE 1" + cmd << " \"" << arg << "\""; + } } cmd << " \"" << studypath << "\""; From 6f0499e3dbec79ecbe7d58d6cc079215b5172fac Mon Sep 17 00:00:00 2001 From: thibaulttoujouse <119934984+thibaulttoujouse@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:06:44 +0200 Subject: [PATCH 038/103] [doc] Small update for ST storages (#2464) --- docs/user-guide/solver/02-inputs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user-guide/solver/02-inputs.md b/docs/user-guide/solver/02-inputs.md index 8f497e8b34..659208d135 100644 --- a/docs/user-guide/solver/02-inputs.md +++ b/docs/user-guide/solver/02-inputs.md @@ -266,7 +266,7 @@ a choice can be made between different tabs: _where Efficiency[%], CO2_emission_factor[tons/MWh] and Variable_O&M_cost[€/MWh] are specified in the `Common` tab under operating costs and parameters, while Fuel_Cost[€/GJ] and C02_cost[€/tons] are provided as time-series in separate tabs._ -## Storages +## Short-term storages _[Documentation of the AntaresWeb interface for this section](https://antares-web.readthedocs.io/en/latest/user-guide/study/areas/08-st-storages/)_ From 0bb9b9a9c2dda6b69ff328ac22fdd34c3c5bcc82 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:48:28 +0200 Subject: [PATCH 039/103] Using filesystem path 2 [ANT-1999] (#2454) following #2435 --- src/analyzer/atsp/cache.cpp | 4 - src/libs/antares/memory/memory.cpp | 2 - .../paths/include/antares/paths/list.h | 11 --- src/libs/antares/paths/list.cpp | 18 +--- src/libs/antares/series/series.cpp | 8 +- src/libs/antares/study/area/links.cpp | 50 +++++----- src/libs/antares/study/area/list.cpp | 92 +++++++++-------- .../study/area/store-timeseries-numbers.cpp | 14 ++- .../binding_constraint/BindingConstraint.cpp | 2 - .../BindingConstraintsRepository.cpp | 4 +- .../study/include/antares/study/area/links.h | 6 +- .../BindingConstraintsRepository.h | 2 +- .../study/binding_constraint/EnvForLoading.h | 2 +- .../study/include/antares/study/layerdata.h | 3 +- .../study/include/antares/study/output.h | 2 + .../study/include/antares/study/parameters.h | 2 +- .../antares/study/parts/hydro/container.h | 4 +- .../antares/study/parts/hydro/prepro.h | 2 +- .../antares/study/parts/hydro/series.h | 2 +- .../include/antares/study/parts/load/prepro.h | 2 +- .../study/parts/renewable/cluster_list.h | 4 +- .../antares/study/parts/solar/prepro.h | 2 +- .../include/antares/study/parts/wind/prepro.h | 2 +- .../study/include/antares/study/simulation.h | 2 + .../study/include/antares/study/study.h | 1 + .../study/include/antares/study/xcast/xcast.h | 2 +- src/libs/antares/study/layerdata.cpp | 2 +- src/libs/antares/study/load.cpp | 74 ++++++-------- src/libs/antares/study/output.cpp | 3 + src/libs/antares/study/parameters.cpp | 2 +- .../study/parts/common/cluster_list.cpp | 13 ++- .../antares/study/parts/hydro/container.cpp | 98 ++++++++----------- src/libs/antares/study/parts/hydro/prepro.cpp | 20 ++-- src/libs/antares/study/parts/hydro/series.cpp | 24 +++-- src/libs/antares/study/parts/load/prepro.cpp | 2 +- .../antares/study/parts/renewable/cluster.cpp | 2 - .../study/parts/renewable/cluster_list.cpp | 13 +-- .../parts/short-term-storage/properties.cpp | 2 - src/libs/antares/study/parts/solar/prepro.cpp | 2 +- .../antares/study/parts/thermal/cluster.cpp | 2 - src/libs/antares/study/parts/wind/prepro.cpp | 10 +- .../antares/study/scenario-builder/sets.cpp | 2 - src/libs/antares/study/study.cpp | 5 + src/libs/antares/study/study.importprepro.cpp | 2 + src/libs/antares/study/xcast/xcast.cpp | 41 ++++---- .../antares/writer/immediate_file_writer.cpp | 4 +- src/libs/antares/writer/in_memory_writer.cpp | 4 +- .../writer/include/antares/writer/i_writer.h | 6 +- .../include/antares/writer/in_memory_writer.h | 3 +- .../writer/private/immediate_file_writer.h | 3 +- src/libs/antares/writer/private/zip_writer.h | 6 +- .../antares/writer/private/zip_writer.hxx | 5 +- src/libs/antares/writer/zip_writer.cpp | 2 +- src/solver/constraints-builder/load.cpp | 7 -- src/solver/hydro/management/daily.cpp | 4 +- src/solver/hydro/management/monthly.cpp | 2 +- src/solver/main.cpp | 3 - .../simulation/TimeSeriesNumbersWriter.cpp | 2 +- src/solver/simulation/opt_time_writer.cpp | 2 +- src/solver/simulation/solver_utils.cpp | 11 +-- src/solver/ts-generator/hydro.cpp | 34 +++---- src/solver/ts-generator/prepro.cpp | 13 +-- src/solver/ts-generator/xcast/xcast.cpp | 20 ++-- .../antares/solver/variable/container.hxx | 9 +- .../variable/surveyresults/reportbuilder.hxx | 52 ++++++---- .../variable/surveyresults/surveyresults.cpp | 24 +++-- .../short-term-storage-input-output.cpp | 88 ++++++++--------- 67 files changed, 392 insertions(+), 476 deletions(-) diff --git a/src/analyzer/atsp/cache.cpp b/src/analyzer/atsp/cache.cpp index 07ecd37803..dbc4d1132c 100644 --- a/src/analyzer/atsp/cache.cpp +++ b/src/analyzer/atsp/cache.cpp @@ -21,10 +21,6 @@ #include "atsp.h" -using namespace Yuni; - -#define SEP Yuni::Core::IO::Separator - namespace Antares { void ATSP::cacheCreate() diff --git a/src/libs/antares/memory/memory.cpp b/src/libs/antares/memory/memory.cpp index 3819cc8036..5d368137bc 100644 --- a/src/libs/antares/memory/memory.cpp +++ b/src/libs/antares/memory/memory.cpp @@ -47,8 +47,6 @@ using namespace Yuni; -#define SEP Yuni::IO::Separator - namespace Antares { /*extern*/ diff --git a/src/libs/antares/paths/include/antares/paths/list.h b/src/libs/antares/paths/include/antares/paths/list.h index 135a18ff95..4aa03124f7 100644 --- a/src/libs/antares/paths/include/antares/paths/list.h +++ b/src/libs/antares/paths/include/antares/paths/list.h @@ -178,17 +178,6 @@ class PathList return item.empty(); } - template - size_t sizeOnDisk(const StringT& sourceFolder) const - { - if (item.empty()) - { - return 0; - } - pTmp = sourceFolder; - return (!pTmp) ? 0 : internalSizeOnDisk(); - } - size_t totalSizeInBytes() const; template diff --git a/src/libs/antares/paths/list.cpp b/src/libs/antares/paths/list.cpp index 5369e24513..ad5efa1a33 100644 --- a/src/libs/antares/paths/list.cpp +++ b/src/libs/antares/paths/list.cpp @@ -41,23 +41,6 @@ void PathList::clear() item.clear(); } -size_t PathList::internalSizeOnDisk() const -{ - size_t size = 0; - Clob buffer; - - const ItemList::const_iterator end = item.end(); - for (ItemList::const_iterator i = item.begin(); i != end; ++i) - { - if (!(i->second.options & pathListOptFolder)) - { - buffer.clear() << pTmp << SEP << i->first; - size += (size_t)IO::File::Size(pTmp); - } - } - return size; -} - size_t PathList::totalSizeInBytes() const { size_t size = 0; @@ -70,6 +53,7 @@ size_t PathList::totalSizeInBytes() const return size; } +// TODO VP: remove with tools uint PathList::internalDeleteAllEmptyFolders() { if (!pTmp || item.empty()) diff --git a/src/libs/antares/series/series.cpp b/src/libs/antares/series/series.cpp index c92f7812cc..5b43f7b2fc 100644 --- a/src/libs/antares/series/series.cpp +++ b/src/libs/antares/series/series.cpp @@ -31,10 +31,6 @@ #include -using namespace Yuni; - -#define SEP IO::Separator - namespace Antares::Data { void TimeSeriesNumbers::registerSeries(const TimeSeries* s, std::string label) @@ -135,8 +131,8 @@ int TimeSeries::saveToFolder(const std::string& areaID, const std::string& folder, const std::string& prefix) const { - Clob buffer; - buffer.clear() << folder << SEP << prefix << areaID << ".txt"; + Yuni::Clob buffer; + buffer.clear() << folder << Yuni::IO::Separator << prefix << areaID << ".txt"; return timeSeries.saveToCSVFile(buffer, 0); } diff --git a/src/libs/antares/study/area/links.cpp b/src/libs/antares/study/area/links.cpp index 3c2059b3f6..851d93ff26 100644 --- a/src/libs/antares/study/area/links.cpp +++ b/src/libs/antares/study/area/links.cpp @@ -38,11 +38,6 @@ namespace fs = std::filesystem; #define SEP (IO::Separator) -namespace -{ -const YString DIRECTORY_NAME_FOR_TRANSMISSION_CAPACITIES = "ntc"; -} - namespace Antares { namespace Data @@ -78,15 +73,14 @@ AreaLink::~AreaLink() { } -bool AreaLink::linkLoadTimeSeries_for_version_below_810(const AnyString& folder) +bool AreaLink::linkLoadTimeSeries_for_version_below_810(const fs::path& folder) { - String buffer; - buffer.clear() << folder << SEP << with->id << ".txt"; + fs::path path = folder / static_cast(with->id + ".txt"); // Load link's data Matrix<> tmpMatrix; const uint matrixWidth = 8; - if (!tmpMatrix.loadFromCSVFile(buffer, + if (!tmpMatrix.loadFromCSVFile(path.string(), matrixWidth, HOURS_PER_YEAR, Matrix<>::optFixedSize | Matrix<>::optImmediate)) @@ -110,26 +104,28 @@ bool AreaLink::linkLoadTimeSeries_for_version_below_810(const AnyString& folder) return true; } -bool AreaLink::linkLoadTimeSeries_for_version_820_and_later(const AnyString& folder) +bool AreaLink::linkLoadTimeSeries_for_version_820_and_later(const fs::path& folder) { - String capacitiesFolder; - capacitiesFolder << folder << SEP << "capacities"; - - String filename; bool success = true; // Read link's parameters times series - filename.clear() << folder << SEP << with->id << "_parameters.txt"; - success = parameters.loadFromCSVFile(filename, fhlMax, HOURS_PER_YEAR, Matrix<>::optFixedSize) + std::string paramId = with->id + "_parameters.txt"; + fs::path path = folder / paramId; + success = parameters.loadFromCSVFile(path.string(), + fhlMax, + HOURS_PER_YEAR, + Matrix<>::optFixedSize) && success; + fs::path capacitiesFolder = folder / "capacities"; + // Read link's direct capacities time series - filename.clear() << capacitiesFolder << SEP << with->id << "_direct.txt"; - success = directCapacities.loadFromFile(filename.c_str(), false) && success; + path = capacitiesFolder / static_cast(with->id + "_direct.txt"); + success = directCapacities.loadFromFile(path, false) && success; // Read link's indirect capacities time series - filename.clear() << capacitiesFolder << SEP << with->id << "_indirect.txt"; - success = indirectCapacities.loadFromFile(filename.c_str(), false) && success; + path = capacitiesFolder / static_cast(with->id + "_indirect.txt"); + success = indirectCapacities.loadFromFile(path, false) && success; return success; } @@ -173,7 +169,7 @@ void AreaLink::overrideTransmissionCapacityAccordingToGlobalParameter( } } -bool AreaLink::loadTimeSeries(const StudyVersion& version, const AnyString& folder) +bool AreaLink::loadTimeSeries(const StudyVersion& version, const fs::path& folder) { if (version < StudyVersion(8, 2)) { @@ -187,14 +183,12 @@ bool AreaLink::loadTimeSeries(const StudyVersion& version, const AnyString& fold void AreaLink::storeTimeseriesNumbers(Solver::IResultWriter& writer) const { - Clob path; - std::string buffer; - - path << "ts-numbers" << SEP << DIRECTORY_NAME_FOR_TRANSMISSION_CAPACITIES << SEP << from->id - << SEP << with->id << ".txt"; + std::string filename = with->id + ".txt"; + fs::path path = fs::path("ts-numbers") / "ntc" / from->id.to() / filename; + std::string buffer; timeseriesNumbers.saveToBuffer(buffer); - writer.addEntryFromBuffer(path.c_str(), buffer); + writer.addEntryFromBuffer(path, buffer); } void AreaLink::detach() @@ -527,7 +521,7 @@ bool AreaLinksLoadFromFolder(Study& study, AreaList* areaList, Area* area, const link.comments.clear(); link.displayComments = true; - ret = link.loadTimeSeries(study.header.version, folder.string()) && ret; + ret = link.loadTimeSeries(study.header.version, folder) && ret; // Checks on loaded link's data if (study.usedByTheSolver) diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index ec7bcd3ef2..b9353937d9 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -44,7 +44,7 @@ namespace Antares::Data { namespace // anonymous { -static bool AreaListLoadThermalDataFromFile(AreaList& list, const Clob& filename) +static bool AreaListLoadThermalDataFromFile(AreaList& list, const fs::path& filename) { // Reset to 0 list.each( @@ -776,38 +776,39 @@ bool AreaList::saveToFolder(const AnyString& folder) const return ret; } -template -static void readAdqPatchMode(Study& study, Area& area, StringT& buffer) +static void readAdqPatchMode(Study& study, Area& area) { - if (study.header.version >= StudyVersion(8, 3)) + if (study.header.version < StudyVersion(8, 3)) + { + return; + } + + fs::path adqPath = study.folderInput / "areas" / area.id.to() + / "adequacy_patch.ini"; + IniFile ini; + if (ini.open(adqPath)) { - buffer.clear() << study.folderInput << SEP << "areas" << SEP << area.id << SEP - << "adequacy_patch.ini"; - IniFile ini; - if (ini.open(buffer)) + auto* section = ini.find("adequacy-patch"); + for (auto* p = section->firstProperty; p; p = p->next) { - auto* section = ini.find("adequacy-patch"); - for (auto* p = section->firstProperty; p; p = p->next) + CString<30, false> tmp; + tmp = p->key; + tmp.toLower(); + if (tmp == "adequacy-patch-mode") { - CString<30, false> tmp; - tmp = p->key; - tmp.toLower(); - if (tmp == "adequacy-patch-mode") - { - auto value = (p->value).toLower(); + auto value = (p->value).toLower(); - if (value == "virtual") - { - area.adequacyPatchMode = Data::AdequacyPatch::virtualArea; - } - else if (value == "inside") - { - area.adequacyPatchMode = Data::AdequacyPatch::physicalAreaInsideAdqPatch; - } - else - { - area.adequacyPatchMode = Data::AdequacyPatch::physicalAreaOutsideAdqPatch; - } + if (value == "virtual") + { + area.adequacyPatchMode = Data::AdequacyPatch::virtualArea; + } + else if (value == "inside") + { + area.adequacyPatchMode = Data::AdequacyPatch::physicalAreaInsideAdqPatch; + } + else + { + area.adequacyPatchMode = Data::AdequacyPatch::physicalAreaOutsideAdqPatch; } } } @@ -899,7 +900,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, { // if changes are required, please update reloadXCastData() fs::path loadPath = study.folderInput / "load" / "prepro" / area.id.to(); - ret = area.load.prepro->loadFromFolder(loadPath.string()) && ret; + ret = area.load.prepro->loadFromFolder(loadPath) && ret; } if (!options.loadOnlyNeeded || !area.load.prepro) // Series { @@ -916,7 +917,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, { // if changes are required, please update reloadXCastData() fs::path solarPath = study.folderInput / "solar" / "prepro" / area.id.to(); - ret = area.solar.prepro->loadFromFolder(solarPath.string()) && ret; + ret = area.solar.prepro->loadFromFolder(solarPath) && ret; } if (!options.loadOnlyNeeded || !area.solar.prepro) // Series { @@ -940,7 +941,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, { // if changes are required, please update reloadXCastData() fs::path hydroPrepro = pathHydro / "prepro"; - ret = area.hydro.prepro->loadFromFolder(study, area.id, hydroPrepro.string()) && ret; + ret = area.hydro.prepro->loadFromFolder(study, area.id, hydroPrepro) && ret; ret = area.hydro.prepro->validate(area.id) && ret; } @@ -972,7 +973,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, { // if changes are required, please update reloadXCastData() fs::path windPath = study.folderInput / "wind" / "prepro" / area.id.to(); - ret = area.wind.prepro->loadFromFolder(windPath.string()) && ret; + ret = area.wind.prepro->loadFromFolder(windPath) && ret; } if (!options.loadOnlyNeeded || !area.wind.prepro) // Series { @@ -1016,7 +1017,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, } // Adequacy patch - readAdqPatchMode(study, area, buffer); + readAdqPatchMode(study, area); // Nodal Optimization fs::path nodalPath = study.folderInput / "areas" / area.id.to() @@ -1160,21 +1161,18 @@ bool AreaList::loadFromFolder(const StudyLoadOptions& options) // Thermal data, specific to areas { logs.info() << "Loading thermal clusters..."; - buffer.clear() << pStudy.folderInput << SEP << "thermal" << SEP << "areas.ini"; - ret = AreaListLoadThermalDataFromFile(*this, buffer) && ret; + fs::path thermalPath = pStudy.folderInput / "thermal"; + fs::path areaIniPath = thermalPath / "areas.ini"; + ret = AreaListLoadThermalDataFromFile(*this, areaIniPath) && ret; - // The cluster list must be loaded before the method - // ensureDataIsInitialized is called + // The cluster list must be loaded before the method ensureDataIsInitialized is called // in order to allocate data with all thermal clusters. - CString<30, false> thermalPlant; - thermalPlant << SEP << "thermal" << SEP << "clusters" << SEP; - auto end = areas.end(); for (auto i = areas.begin(); i != end; ++i) { Area& area = *(i->second); - buffer.clear() << pStudy.folderInput << thermalPlant << area.id; - ret = area.thermal.list.loadFromFolder(pStudy, buffer.c_str(), &area) && ret; + fs::path areaPath = thermalPath / "clusters" / area.id.to(); + ret = area.thermal.list.loadFromFolder(pStudy, areaPath, &area) && ret; ret = area.thermal.list.validateClusters(pStudy.parameters) && ret; } } @@ -1203,18 +1201,16 @@ bool AreaList::loadFromFolder(const StudyLoadOptions& options) // Renewable data, specific to areas if (studyVersion >= StudyVersion(8, 1)) { - // The cluster list must be loaded before the method - // ensureDataIsInitialized is called + // The cluster list must be loaded before the method ensureDataIsInitialized is called // in order to allocate data with all renewable clusters. - CString<30, false> renewablePlant; - renewablePlant << SEP << "renewables" << SEP << "clusters" << SEP; + fs::path renewClusterPath = pStudy.folderInput / "renewables" / "clusters"; auto end = areas.end(); for (auto i = areas.begin(); i != end; ++i) { Area& area = *(i->second); - buffer.clear() << pStudy.folderInput << renewablePlant << area.id; - ret = area.renewable.list.loadFromFolder(buffer.c_str(), &area) && ret; + fs::path areaPath = renewClusterPath / area.id.to(); + ret = area.renewable.list.loadFromFolder(areaPath, &area) && ret; ret = area.renewable.list.validateClusters() && ret; } } diff --git a/src/libs/antares/study/area/store-timeseries-numbers.cpp b/src/libs/antares/study/area/store-timeseries-numbers.cpp index 9619206239..daa3a250c8 100644 --- a/src/libs/antares/study/area/store-timeseries-numbers.cpp +++ b/src/libs/antares/study/area/store-timeseries-numbers.cpp @@ -25,24 +25,22 @@ #include #include -using namespace Yuni; - -#define SEP IO::Separator +namespace fs = std::filesystem; namespace Antares::Data { static void storeTSnumbers(Solver::IResultWriter& writer, const TimeSeriesNumbers& timeseriesNumbers, - const String& id, - const String& directory) + const std::string& id, + const fs::path& directory) { - Clob path; - path << "ts-numbers" << SEP << directory << SEP << id << ".txt"; + std::string fullId = id + ".txt"; + fs::path path = "ts-numbers" / directory / fullId; std::string buffer; timeseriesNumbers.saveToBuffer(buffer); - writer.addEntryFromBuffer(path.c_str(), buffer); + writer.addEntryFromBuffer(path, buffer); } void storeTimeseriesNumbersForLoad(Solver::IResultWriter& writer, const Area& area) diff --git a/src/libs/antares/study/binding_constraint/BindingConstraint.cpp b/src/libs/antares/study/binding_constraint/BindingConstraint.cpp index b950773dd4..1114e25d72 100644 --- a/src/libs/antares/study/binding_constraint/BindingConstraint.cpp +++ b/src/libs/antares/study/binding_constraint/BindingConstraint.cpp @@ -34,8 +34,6 @@ using namespace Antares; -#define SEP IO::Separator - #ifdef _MSC_VER #define SNPRINTF sprintf_s #else diff --git a/src/libs/antares/study/binding_constraint/BindingConstraintsRepository.cpp b/src/libs/antares/study/binding_constraint/BindingConstraintsRepository.cpp index 7ed09d8e09..14687e4e6f 100644 --- a/src/libs/antares/study/binding_constraint/BindingConstraintsRepository.cpp +++ b/src/libs/antares/study/binding_constraint/BindingConstraintsRepository.cpp @@ -177,7 +177,7 @@ bool BindingConstraintsRepository::rename(BindingConstraint* bc, const AnyString bool BindingConstraintsRepository::loadFromFolder(Study& study, const StudyLoadOptions& options, - const AnyString& folder) + const std::filesystem::path& folder) { // Log entries logs.info(); // space for beauty @@ -203,7 +203,7 @@ bool BindingConstraintsRepository::loadFromFolder(Study& study, EnvForLoading env(study.areas, study.header.version); env.folder = folder; - env.iniFilename << env.folder << Yuni::IO::Separator << "bindingconstraints.ini"; + env.iniFilename = folder / "bindingconstraints.ini"; IniFile ini; if (!ini.open(env.iniFilename)) { diff --git a/src/libs/antares/study/include/antares/study/area/links.h b/src/libs/antares/study/include/antares/study/area/links.h index 960f3c36ec..fed36eb033 100644 --- a/src/libs/antares/study/include/antares/study/area/links.h +++ b/src/libs/antares/study/include/antares/study/area/links.h @@ -69,7 +69,7 @@ class AreaLink final: public Yuni::NonCopyable ~AreaLink(); //@} - bool loadTimeSeries(const StudyVersion& version, const AnyString& folder); + bool loadTimeSeries(const StudyVersion& version, const std::filesystem::path& folder); void storeTimeseriesNumbers(Solver::IResultWriter& writer) const; @@ -114,8 +114,8 @@ class AreaLink final: public Yuni::NonCopyable void overrideTransmissionCapacityAccordingToGlobalParameter(GlobalTransmissionCapacities tc); private: - bool linkLoadTimeSeries_for_version_below_810(const AnyString& folder); - bool linkLoadTimeSeries_for_version_820_and_later(const AnyString& folder); + bool linkLoadTimeSeries_for_version_below_810(const std::filesystem::path& folder); + bool linkLoadTimeSeries_for_version_820_and_later(const std::filesystem::path& folder); NamePair getNamePair() const; public: diff --git a/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraintsRepository.h b/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraintsRepository.h index ea3f8bbb5b..2eff230ac5 100644 --- a/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraintsRepository.h +++ b/src/libs/antares/study/include/antares/study/binding_constraint/BindingConstraintsRepository.h @@ -112,7 +112,7 @@ class BindingConstraintsRepository final: public Yuni::NonCopyable #include #include @@ -51,7 +52,7 @@ class LayerData protected: bool saveLayers(const AnyString& filename); - void loadLayers(const AnyString& filename); + void loadLayers(const std::filesystem::path& filename); }; } // namespace Antares::Data diff --git a/src/libs/antares/study/include/antares/study/output.h b/src/libs/antares/study/include/antares/study/output.h index 38846330bd..ffebc06d90 100644 --- a/src/libs/antares/study/include/antares/study/output.h +++ b/src/libs/antares/study/include/antares/study/output.h @@ -34,6 +34,8 @@ namespace Antares { namespace Data { + +// TODO VP: remove with GUI class Output final { public: diff --git a/src/libs/antares/study/include/antares/study/parameters.h b/src/libs/antares/study/include/antares/study/parameters.h index 56451e67a4..0df3a8b157 100644 --- a/src/libs/antares/study/include/antares/study/parameters.h +++ b/src/libs/antares/study/include/antares/study/parameters.h @@ -75,7 +75,7 @@ class Parameters final ** \param version Current study version ** \return True if the settings have been loaded, false if at least one error has occured */ - bool loadFromFile(const AnyString& filename, const StudyVersion& version); + bool loadFromFile(const std::filesystem::path& filename, const StudyVersion& version); /*! ** \brief Prepare all settings for a simulation diff --git a/src/libs/antares/study/include/antares/study/parts/hydro/container.h b/src/libs/antares/study/include/antares/study/parts/hydro/container.h index 1da5ab6023..91b668ba6a 100644 --- a/src/libs/antares/study/include/antares/study/parts/hydro/container.h +++ b/src/libs/antares/study/include/antares/study/parts/hydro/container.h @@ -114,7 +114,7 @@ class PartHydro ** \param folder The targer folder ** \return A non-zero value if the operation succeeded, 0 otherwise */ - static bool LoadFromFolder(Study& study, const AnyString& folder); + static bool LoadFromFolder(Study& study, const std::filesystem::path& folder); /*! ** \brief Check and validate the loaded datas @@ -157,7 +157,7 @@ class PartHydro /*! ** \brief Load daily max energy */ - bool LoadDailyMaxEnergy(const AnyString& folder, const AnyString& areaid); + bool LoadDailyMaxEnergy(const std::filesystem::path& folder, const std::string& areaid); bool CheckDailyMaxEnergy(const AnyString& areaName); diff --git a/src/libs/antares/study/include/antares/study/parts/hydro/prepro.h b/src/libs/antares/study/include/antares/study/parts/hydro/prepro.h index e1eaaa9862..b7aa6d46bb 100644 --- a/src/libs/antares/study/include/antares/study/parts/hydro/prepro.h +++ b/src/libs/antares/study/include/antares/study/parts/hydro/prepro.h @@ -95,7 +95,7 @@ class PreproHydro ** \param folder The source folder (ex: `input/hydro/prepro`) ** \return A non-zero value if the operation succeeded, 0 otherwise */ - bool loadFromFolder(Study& s, const AreaName& areaID, const std::string& folder); + bool loadFromFolder(Study& s, const std::string& areaID, const std::filesystem::path& folder); bool validate(const std::string& areaID); /*! diff --git a/src/libs/antares/study/include/antares/study/parts/hydro/series.h b/src/libs/antares/study/include/antares/study/parts/hydro/series.h index 2db6868d44..4bb8367ac3 100644 --- a/src/libs/antares/study/include/antares/study/parts/hydro/series.h +++ b/src/libs/antares/study/include/antares/study/parts/hydro/series.h @@ -76,7 +76,7 @@ class DataSeriesHydro StudyVersion version); // Loading hydro max generation and mqx pumping TS's - bool LoadMaxPower(const AreaName& areaID, const std::filesystem::path& folder); + bool LoadMaxPower(const std::string& areaID, const std::filesystem::path& folder); void buildHourlyMaxPowerFromDailyTS(const Matrix::ColumnType& DailyMaxGenPower, const Matrix::ColumnType& DailyMaxPumpPower); diff --git a/src/libs/antares/study/include/antares/study/parts/load/prepro.h b/src/libs/antares/study/include/antares/study/parts/load/prepro.h index e434fe1c01..24582a572b 100644 --- a/src/libs/antares/study/include/antares/study/parts/load/prepro.h +++ b/src/libs/antares/study/include/antares/study/parts/load/prepro.h @@ -52,7 +52,7 @@ class Prepro /*! ** \brief Load data from a folder */ - bool loadFromFolder(const AnyString& folder); + bool loadFromFolder(const std::filesystem::path& folder); /*! ** \brief Save data to a folder diff --git a/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h index f8798845dc..8dfb3ac65c 100644 --- a/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h @@ -22,6 +22,8 @@ #ifndef __ANTARES_LIBS_STUDY_PARTS_RENEWABLE_CLUSTER_LIST_H__ #define __ANTARES_LIBS_STUDY_PARTS_RENEWABLE_CLUSTER_LIST_H__ +#include + #include "../../fwd.h" #include "../common/cluster_list.h" #include "cluster.h" @@ -37,7 +39,7 @@ class RenewableClusterList: public ClusterList public: std::string typeID() const override; - bool loadFromFolder(const AnyString& folder, Area* area); + bool loadFromFolder(const std::filesystem::path& folder, Area* area); bool validateClusters() const; bool saveToFolder(const AnyString& folder) const override; diff --git a/src/libs/antares/study/include/antares/study/parts/solar/prepro.h b/src/libs/antares/study/include/antares/study/parts/solar/prepro.h index da559acd99..006e0813b5 100644 --- a/src/libs/antares/study/include/antares/study/parts/solar/prepro.h +++ b/src/libs/antares/study/include/antares/study/parts/solar/prepro.h @@ -52,7 +52,7 @@ class Prepro /*! ** \brief Solar data from a folder */ - bool loadFromFolder(const AnyString& folder); + bool loadFromFolder(const std::filesystem::path& folder); /*! ** \brief Save data to a folder diff --git a/src/libs/antares/study/include/antares/study/parts/wind/prepro.h b/src/libs/antares/study/include/antares/study/parts/wind/prepro.h index 2e75729b26..ea9227daa9 100644 --- a/src/libs/antares/study/include/antares/study/parts/wind/prepro.h +++ b/src/libs/antares/study/include/antares/study/parts/wind/prepro.h @@ -49,7 +49,7 @@ class Prepro /*! ** \brief Load data from a folder */ - bool loadFromFolder(const AnyString& folder); + bool loadFromFolder(const std::filesystem::path& folder); /*! ** \brief Save data to a folder diff --git a/src/libs/antares/study/include/antares/study/simulation.h b/src/libs/antares/study/include/antares/study/simulation.h index 14d93d2568..b46f29f532 100644 --- a/src/libs/antares/study/include/antares/study/simulation.h +++ b/src/libs/antares/study/include/antares/study/simulation.h @@ -34,6 +34,8 @@ namespace Data /*! ** \brief Set of settings for a simulation */ + +// TODO VP: remove with GUI class SimulationComments final { public: diff --git a/src/libs/antares/study/include/antares/study/study.h b/src/libs/antares/study/include/antares/study/study.h index 7172948641..164a0b935c 100644 --- a/src/libs/antares/study/include/antares/study/study.h +++ b/src/libs/antares/study/include/antares/study/study.h @@ -462,6 +462,7 @@ class Study: public Yuni::NonCopyable, public LayerData //! \name Simulation //@{ //! The current Simulation + // TODO VP: remove with GUI SimulationComments simulationComments; int64_t pStartTime; diff --git a/src/libs/antares/study/include/antares/study/xcast/xcast.h b/src/libs/antares/study/include/antares/study/xcast/xcast.h index a029eeaef7..bffccb8c1f 100644 --- a/src/libs/antares/study/include/antares/study/xcast/xcast.h +++ b/src/libs/antares/study/include/antares/study/xcast/xcast.h @@ -140,7 +140,7 @@ class XCast final: private Yuni::NonCopyable /*! ** \brief Load data from a folder */ - bool loadFromFolder(const AnyString& folder); + bool loadFromFolder(const std::filesystem::path& folder); /*! ** \brief Save data to a folder diff --git a/src/libs/antares/study/layerdata.cpp b/src/libs/antares/study/layerdata.cpp index 781a807037..cd8606dbaf 100644 --- a/src/libs/antares/study/layerdata.cpp +++ b/src/libs/antares/study/layerdata.cpp @@ -33,7 +33,7 @@ using namespace Yuni; namespace Antares::Data { -void LayerData::loadLayers(const AnyString& filename) +void LayerData::loadLayers(const std::filesystem::path& filename) { IniFile ini; if (std::ifstream(filename.c_str()).good() && ini.open(filename)) // check if file exists diff --git a/src/libs/antares/study/load.cpp b/src/libs/antares/study/load.cpp index c6b61a6e61..3a756333f3 100644 --- a/src/libs/antares/study/load.cpp +++ b/src/libs/antares/study/load.cpp @@ -26,16 +26,9 @@ #include "antares/study/ui-runtimeinfos.h" #include "antares/study/version.h" -using namespace Yuni; -using Antares::Constants::nbHoursInAWeek; - namespace fs = std::filesystem; -#define SEP IO::Separator - -namespace Antares -{ -namespace Data +namespace Antares::Data { bool Study::internalLoadHeader(const fs::path& path) { @@ -82,8 +75,8 @@ bool Study::internalLoadIni(const fs::path& path, const StudyLoadOptions& option } } // Load the general data - buffer.clear() << folderSettings << SEP << "generaldata.ini"; - bool errorWhileLoading = !parameters.loadFromFile(buffer, header.version); + fs::path generalDataPath = folderSettings / "generaldata.ini"; + bool errorWhileLoading = !parameters.loadFromFile(generalDataPath, header.version); parameters.validateOptions(options); @@ -98,8 +91,8 @@ bool Study::internalLoadIni(const fs::path& path, const StudyLoadOptions& option } // Load the layer data - buffer.clear() << path << SEP << "layers" << SEP << "layers.ini"; - loadLayers(buffer); + fs::path layersPath = path / "layers" / "layers.ini"; + loadLayers(layersPath); return true; } @@ -238,40 +231,32 @@ bool Study::internalLoadCorrelationMatrices(const StudyLoadOptions& options) if (!options.loadOnlyNeeded || timeSeriesLoad & parameters.timeSeriesToRefresh || timeSeriesLoad & parameters.timeSeriesToGenerate) { - buffer.clear() << folderInput << SEP << "load" << SEP << "prepro" << SEP - << "correlation.ini"; - preproLoadCorrelation.loadFromFile(*this, buffer); + fs::path loadPath = folderInput / "load" / "prepro" / "correlation.ini"; + preproLoadCorrelation.loadFromFile(*this, loadPath.string()); } // Solar if (!options.loadOnlyNeeded || timeSeriesSolar & parameters.timeSeriesToRefresh || timeSeriesSolar & parameters.timeSeriesToGenerate) { - buffer.clear() << folderInput << SEP << "solar" << SEP << "prepro" << SEP - << "correlation.ini"; - preproSolarCorrelation.loadFromFile(*this, buffer); + fs::path solarPath = folderInput / "solar" / "prepro" / "correlation.ini"; + preproSolarCorrelation.loadFromFile(*this, solarPath.string()); } // Wind + if (!options.loadOnlyNeeded || timeSeriesWind & parameters.timeSeriesToRefresh + || timeSeriesWind & parameters.timeSeriesToGenerate) { - if (!options.loadOnlyNeeded || timeSeriesWind & parameters.timeSeriesToRefresh - || timeSeriesWind & parameters.timeSeriesToGenerate) - { - buffer.clear() << folderInput << SEP << "wind" << SEP << "prepro" << SEP - << "correlation.ini"; - preproWindCorrelation.loadFromFile(*this, buffer); - } + fs::path windPath = folderInput / "wind" / "prepro" / "correlation.ini"; + preproWindCorrelation.loadFromFile(*this, windPath.string()); } // Hydro + if (!options.loadOnlyNeeded || (timeSeriesHydro & parameters.timeSeriesToRefresh) + || (timeSeriesHydro & parameters.timeSeriesToGenerate)) { - if (!options.loadOnlyNeeded || (timeSeriesHydro & parameters.timeSeriesToRefresh) - || (timeSeriesHydro & parameters.timeSeriesToGenerate)) - { - buffer.clear() << folderInput << SEP << "hydro" << SEP << "prepro" << SEP - << "correlation.ini"; - preproHydroCorrelation.loadFromFile(*this, buffer); - } + fs::path hydroPath = folderInput / "hydro" / "prepro" / "correlation.ini"; + preproHydroCorrelation.loadFromFile(*this, hydroPath.string()); } return true; } @@ -280,8 +265,8 @@ bool Study::internalLoadBindingConstraints(const StudyLoadOptions& options) { // All checks are performed in 'loadFromFolder' // (actually internalLoadFromFolder) - buffer.clear() << folderInput << SEP << "bindingconstraints"; - bool r = bindingConstraints.loadFromFolder(*this, options, buffer); + fs::path constraintPath = folderInput / "bindingconstraints"; + bool r = bindingConstraints.loadFromFolder(*this, options, constraintPath); if (r) { r &= bindingConstraintsGroups.buildFrom(bindingConstraints); @@ -291,16 +276,15 @@ bool Study::internalLoadBindingConstraints(const StudyLoadOptions& options) bool Study::internalLoadSets() { - const fs::path path = fs::path(folderInput.c_str()) / "areas" / "sets.ini"; // Set of areas logs.info(); logs.info() << "Loading sets of areas..."; // filename - buffer.clear() << folderInput << SEP << "areas" << SEP << "sets.ini"; + const fs::path setPath = folderInput / "areas" / "sets.ini"; // Load the rules - if (setsOfAreas.loadFromFile(path)) + if (setsOfAreas.loadFromFile(setPath)) { // Apply the rules SetHandlerAreas handler(areas); @@ -321,6 +305,7 @@ void Study::reloadCorrelation() internalLoadCorrelationMatrices(options); } +// TODO remove with GUI bool Study::reloadXCastData() { // if changes are required, please update AreaListLoadFromFolderSingleArea() @@ -333,17 +318,16 @@ bool Study::reloadXCastData() assert(area.wind.prepro); // Load - buffer.clear() << folderInput << SEP << "load" << SEP << "prepro" << SEP << area.id; - ret = area.load.prepro->loadFromFolder(buffer) && ret; + fs::path loadPath = folderInput / "load" / "prepro" / area.id.to(); + ret = area.load.prepro->loadFromFolder(loadPath.string()) && ret; // Solar - buffer.clear() << folderInput << SEP << "solar" << SEP << "prepro" << SEP << area.id; - ret = area.solar.prepro->loadFromFolder(buffer) && ret; + fs::path solarPath = folderInput / "solar" / "prepro" / area.id.to(); + ret = area.solar.prepro->loadFromFolder(solarPath.string()) && ret; // Wind - buffer.clear() << folderInput << SEP << "wind" << SEP << "prepro" << SEP << area.id; - ret = area.wind.prepro->loadFromFolder(buffer) && ret; + fs::path windPath = folderInput / "wind" / "prepro" / area.id.to(); + ret = area.wind.prepro->loadFromFolder(windPath.string()) && ret; }); return ret; } -} // namespace Data -} // namespace Antares +} // namespace Antares::Data diff --git a/src/libs/antares/study/output.cpp b/src/libs/antares/study/output.cpp index 0409f2bb6e..c28a1c95a2 100644 --- a/src/libs/antares/study/output.cpp +++ b/src/libs/antares/study/output.cpp @@ -35,6 +35,8 @@ namespace Antares::Data { namespace // anonymous { + +// TODO VP: remove with GUI class OutputFolderIterator: public IO::Directory::IIterator { public: @@ -189,6 +191,7 @@ bool Output::loadFromFolder(const AnyString& folder) return true; } +// TODO VP: remove with GUI void Output::RetrieveListFromStudy(List& out, const Study& study) { out.clear(); diff --git a/src/libs/antares/study/parameters.cpp b/src/libs/antares/study/parameters.cpp index 3772c4dd19..8beca3503a 100644 --- a/src/libs/antares/study/parameters.cpp +++ b/src/libs/antares/study/parameters.cpp @@ -1974,7 +1974,7 @@ void Parameters::saveToINI(IniFile& ini) const } } -bool Parameters::loadFromFile(const AnyString& filename, const StudyVersion& version) +bool Parameters::loadFromFile(const std::filesystem::path& filename, const StudyVersion& version) { // Loading the INI file IniFile ini; diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index b8e16c5081..0feee3a77f 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -28,7 +28,7 @@ #include #include "antares/study/study.h" -using namespace Yuni; +namespace fs = std::filesystem; namespace Antares::Data { @@ -88,21 +88,20 @@ void ClusterList::resizeAllTimeseriesNumbers(uint n) const } } -#define SEP IO::Separator - template void ClusterList::storeTimeseriesNumbers(Solver::IResultWriter& writer) const { - Clob path; std::string ts_content; + fs::path basePath = fs::path("ts-numbers") / typeID(); for (auto& cluster: each_enabled()) { - path.clear() << "ts-numbers" << SEP << typeID() << SEP << cluster->parentArea->id << SEP - << cluster->id() << ".txt"; + fs::path path = fs::path(cluster->parentArea->id.c_str()) + / std::string(cluster->id() + ".txt"); + ts_content.clear(); // We must clear ts_content here, since saveToBuffer does not do it. cluster->series.timeseriesNumbers.saveToBuffer(ts_content); - writer.addEntryFromBuffer(path.c_str(), ts_content); + writer.addEntryFromBuffer(path, ts_content); } } diff --git a/src/libs/antares/study/parts/hydro/container.cpp b/src/libs/antares/study/parts/hydro/container.cpp index 336595b95b..6ee131b4f3 100644 --- a/src/libs/antares/study/parts/hydro/container.cpp +++ b/src/libs/antares/study/parts/hydro/container.cpp @@ -25,10 +25,9 @@ #include "antares/study/parts/hydro/hydromaxtimeseriesreader.h" #include "antares/study/study.h" -using namespace Antares; -using namespace Yuni; +namespace fs = std::filesystem; -#define SEP IO::Separator +#define SEP Yuni::IO::Separator namespace Antares::Data { @@ -102,7 +101,7 @@ void PartHydro::reset() template static bool loadProperties(Study& study, IniFile::Property* property, - const std::string& filename, + const fs::path& filename, T PartHydro::*ptr) { if (!property) @@ -132,14 +131,13 @@ static bool loadProperties(Study& study, return ret; } -bool PartHydro::LoadFromFolder(Study& study, const AnyString& folder) +bool PartHydro::LoadFromFolder(Study& study, const fs::path& folder) { - auto& buffer = study.bufferLoadingTS; bool ret = true; // Initialize all alpha values to 0 study.areas.each( - [&ret, &buffer, &study, &folder](Data::Area& area) + [&ret, &study, &folder](Data::Area& area) { area.hydro.interDailyBreakdown = 1.; area.hydro.intraDailyModulation = 24.; @@ -174,7 +172,7 @@ bool PartHydro::LoadFromFolder(Study& study, const AnyString& folder) enabledModeIsChanged = true; } - ret = area.hydro.LoadDailyMaxEnergy(folder, area.id) && ret; + ret = area.hydro.LoadDailyMaxEnergy(folder.string(), area.id) && ret; if (enabledModeIsChanged) { @@ -183,7 +181,7 @@ bool PartHydro::LoadFromFolder(Study& study, const AnyString& folder) } else { - ret = area.hydro.LoadDailyMaxEnergy(folder, area.id) && ret; + ret = area.hydro.LoadDailyMaxEnergy(folder.string(), area.id) && ret; // Check is moved here, because in case of old study // dailyNbHoursAtGenPmax and dailyNbHoursAtPumpPmax are not yet initialized. @@ -192,36 +190,38 @@ bool PartHydro::LoadFromFolder(Study& study, const AnyString& folder) } } - buffer.clear() << folder << SEP << "common" << SEP << "capacity" << SEP - << "creditmodulations_" << area.id << '.' << study.inputExtension; - ret = area.hydro.creditModulation.loadFromCSVFile(buffer, + fs::path capacityPath = folder / "common" / "capacity"; + + std::string creditId = "creditmodulations_" + area.id + ".txt"; + fs::path creditPath = capacityPath / creditId; + ret = area.hydro.creditModulation.loadFromCSVFile(creditPath.string(), 101, 2, Matrix<>::optFixedSize, &study.dataBuffer) && ret; - buffer.clear() << folder << SEP << "common" << SEP << "capacity" << SEP << "reservoir_" - << area.id << '.' << study.inputExtension; - ret = area.hydro.reservoirLevel.loadFromCSVFile(buffer, + std::string reservoirId = "reservoir_" + area.id + ".txt"; + fs::path reservoirPath = capacityPath / reservoirId; + ret = area.hydro.reservoirLevel.loadFromCSVFile(reservoirPath.string(), 3, DAYS_PER_YEAR, Matrix<>::optFixedSize, &study.dataBuffer) && ret; - buffer.clear() << folder << SEP << "common" << SEP << "capacity" << SEP << "waterValues_" - << area.id << '.' << study.inputExtension; - ret = area.hydro.waterValues.loadFromCSVFile(buffer, + std::string waterValueId = "waterValues_" + area.id + ".txt"; + fs::path waterValuePath = capacityPath / waterValueId; + ret = area.hydro.waterValues.loadFromCSVFile(waterValuePath.string(), 101, DAYS_PER_YEAR, Matrix<>::optFixedSize, &study.dataBuffer) && ret; - buffer.clear() << folder << SEP << "common" << SEP << "capacity" << SEP - << "inflowPattern_" << area.id << '.' << study.inputExtension; - ret = area.hydro.inflowPattern.loadFromCSVFile(buffer, + std::string inflowId = "inflowPattern_" + area.id + ".txt"; + fs::path inflowPath = capacityPath / inflowId; + ret = area.hydro.inflowPattern.loadFromCSVFile(inflowPath.string(), 1, DAYS_PER_YEAR, Matrix<>::optFixedSize, @@ -230,103 +230,96 @@ bool PartHydro::LoadFromFolder(Study& study, const AnyString& folder) }); IniFile ini; - if (not ini.open(buffer.clear() << folder << SEP << "hydro.ini")) + auto path = folder / "hydro.ini"; + if (not ini.open(path)) { return false; } if (IniFile::Section* section = ini.find("inter-daily-breakdown")) { - ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::interDailyBreakdown) + ret = loadProperties(study, section->firstProperty, path, &PartHydro::interDailyBreakdown) && ret; } if (IniFile::Section* section = ini.find("intra-daily-modulation")) { - ret = loadProperties(study, - section->firstProperty, - buffer, - &PartHydro::intraDailyModulation) + ret = loadProperties(study, section->firstProperty, path, &PartHydro::intraDailyModulation) && ret; } if (IniFile::Section* section = ini.find("reservoir")) { - ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::reservoirManagement) + ret = loadProperties(study, section->firstProperty, path, &PartHydro::reservoirManagement) && ret; } if (IniFile::Section* section = ini.find("reservoir capacity")) { - ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::reservoirCapacity) + ret = loadProperties(study, section->firstProperty, path, &PartHydro::reservoirCapacity) && ret; } if (IniFile::Section* section = ini.find("follow load")) { - ret = loadProperties(study, - section->firstProperty, - buffer, - &PartHydro::followLoadModulations) + ret = loadProperties(study, section->firstProperty, path, &PartHydro::followLoadModulations) && ret; } if (IniFile::Section* section = ini.find("use water")) { - ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::useWaterValue) - && ret; + ret = loadProperties(study, section->firstProperty, path, &PartHydro::useWaterValue) && ret; } if (IniFile::Section* section = ini.find("hard bounds")) { ret = loadProperties(study, section->firstProperty, - buffer, + path, &PartHydro::hardBoundsOnRuleCurves) && ret; } if (IniFile::Section* section = ini.find("use heuristic")) { - ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::useHeuristicTarget) + ret = loadProperties(study, section->firstProperty, path, &PartHydro::useHeuristicTarget) && ret; } if (IniFile::Section* section = ini.find("power to level")) { - ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::powerToLevel) - && ret; + ret = loadProperties(study, section->firstProperty, path, &PartHydro::powerToLevel) && ret; } if (IniFile::Section* section = ini.find("initialize reservoir date")) { ret = loadProperties(study, section->firstProperty, - buffer, + path, &PartHydro::initializeReservoirLevelDate) && ret; } if (IniFile::Section* section = ini.find("use leeway")) { - ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::useLeeway) && ret; + ret = loadProperties(study, section->firstProperty, path, &PartHydro::useLeeway) && ret; } if (IniFile::Section* section = ini.find("leeway low")) { - ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::leewayLowerBound) + ret = loadProperties(study, section->firstProperty, path, &PartHydro::leewayLowerBound) && ret; } if (IniFile::Section* section = ini.find("leeway up")) { - ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::leewayUpperBound) + ret = loadProperties(study, section->firstProperty, path, &PartHydro::leewayUpperBound) && ret; } if (IniFile::Section* section = ini.find("pumping efficiency")) { - ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::pumpingEfficiency) + ret = loadProperties(study, section->firstProperty, path, &PartHydro::pumpingEfficiency) && ret; } @@ -480,7 +473,7 @@ bool PartHydro::SaveToFolder(const AreaList& areas, const AnyString& folder) return false; } - String buffer; + Yuni::String buffer; buffer.clear() << folder << SEP << "common" << SEP << "capacity"; struct AllSections @@ -704,26 +697,21 @@ void PartHydro::copyFrom(const PartHydro& rhs) } } -bool PartHydro::LoadDailyMaxEnergy(const AnyString& folder, const AnyString& areaid) +bool PartHydro::LoadDailyMaxEnergy(const fs::path& folder, const std::string& areaid) { - YString filePath; Matrix<>::BufferType fileContent; bool ret = true; - filePath.clear() << folder << SEP << "common" << SEP << "capacity" << SEP - << "maxDailyGenEnergy_" << areaid << ".txt"; - - ret = dailyNbHoursAtGenPmax.loadFromCSVFile(filePath, + fs::path genPath = folder / "common" / "capacity" / ("maxDailyGenEnergy_" + areaid + ".txt"); + ret = dailyNbHoursAtGenPmax.loadFromCSVFile(genPath.string(), 1, DAYS_PER_YEAR, Matrix<>::optFixedSize, &fileContent) && ret; - filePath.clear() << folder << SEP << "common" << SEP << "capacity" << SEP - << "maxDailyPumpEnergy_" << areaid << ".txt"; - - ret = dailyNbHoursAtPumpPmax.loadFromCSVFile(filePath, + fs::path pumpPath = folder / "common" / "capacity" / ("maxDailyPumpEnergy_" + areaid + ".txt"); + ret = dailyNbHoursAtPumpPmax.loadFromCSVFile(pumpPath.string(), 1, DAYS_PER_YEAR, Matrix<>::optFixedSize, diff --git a/src/libs/antares/study/parts/hydro/prepro.cpp b/src/libs/antares/study/parts/hydro/prepro.cpp index 772655567a..d4e803ea87 100644 --- a/src/libs/antares/study/parts/hydro/prepro.cpp +++ b/src/libs/antares/study/parts/hydro/prepro.cpp @@ -32,6 +32,8 @@ using namespace Antares; using namespace Yuni; +namespace fs = std::filesystem; + #define SEP IO::Separator namespace Antares @@ -46,7 +48,7 @@ static bool PreproHydroSaveSettings(PreproHydro* h, const char* filename) return ini.save(filename); } -static bool PreproHydroLoadSettings(PreproHydro* h, const std::string& filename) +static bool PreproHydroLoadSettings(PreproHydro* h, const fs::path& filename) { IniFile ini; IniFile::Section* s; @@ -140,7 +142,7 @@ bool PreproHydro::saveToFolder(const AreaName& areaID, const char* folder) return false; } -bool PreproHydro::loadFromFolder(Study& s, const AreaName& areaID, const std::string& folder) +bool PreproHydro::loadFromFolder(Study& s, const std::string& areaID, const fs::path& folder) { enum { @@ -148,15 +150,17 @@ bool PreproHydro::loadFromFolder(Study& s, const AreaName& areaID, const std::st }; constexpr int maxNbOfLineToLoad = 12; - data.resize(hydroPreproMax, 12, true); - String& buffer = s.bufferLoadingTS; - buffer.clear() << folder << SEP << areaID << SEP << "prepro.ini"; - bool ret = PreproHydroLoadSettings(this, buffer); + fs::path preproPath = folder / areaID / "prepro.ini"; + bool ret = PreproHydroLoadSettings(this, preproPath); - buffer.clear() << folder << SEP << areaID << SEP << "energy.txt"; - ret = data.loadFromCSVFile(buffer, hydroPreproMax, maxNbOfLineToLoad, mtrxOption, &s.dataBuffer) + fs::path energyPath = folder / areaID / "energy.txt"; + ret = data.loadFromCSVFile(energyPath.string(), + hydroPreproMax, + maxNbOfLineToLoad, + mtrxOption, + &s.dataBuffer) && ret; return ret; diff --git a/src/libs/antares/study/parts/hydro/series.cpp b/src/libs/antares/study/parts/hydro/series.cpp index c816be84a0..a9f62664c8 100644 --- a/src/libs/antares/study/parts/hydro/series.cpp +++ b/src/libs/antares/study/parts/hydro/series.cpp @@ -40,15 +40,14 @@ namespace Antares::Data { static bool loadTSfromFile(Matrix& ts, - const AreaName& areaID, + const std::string& areaID, const fs::path& folder, const std::string& filename, unsigned int height) { - YString filePath; + fs::path filePath = folder / areaID / filename; Matrix<>::BufferType fileContent; - filePath.clear() << folder << SEP << areaID << SEP << filename; - return ts.loadFromCSVFile(filePath, 1, height, &fileContent); + return ts.loadFromCSVFile(filePath.string(), 1, height, &fileContent); } static void ConvertDailyTSintoHourlyTS(const Matrix::ColumnType& dailyColumn, @@ -157,18 +156,23 @@ bool DataSeriesHydro::loadGenerationTS(const AreaName& areaID, return ret; } -bool DataSeriesHydro::LoadMaxPower(const AreaName& areaID, const fs::path& folder) +bool DataSeriesHydro::LoadMaxPower(const std::string& areaID, const fs::path& folder) { bool ret = true; - YString filepath; Matrix<>::BufferType fileContent; - filepath.clear() << folder << SEP << areaID << SEP << "maxHourlyGenPower.txt"; - ret = maxHourlyGenPower.timeSeries.loadFromCSVFile(filepath, 1, HOURS_PER_YEAR, &fileContent) + fs::path filePath = folder / areaID / "maxHourlyGenPower.txt"; + ret = maxHourlyGenPower.timeSeries.loadFromCSVFile(filePath.string(), + 1, + HOURS_PER_YEAR, + &fileContent) && ret; - filepath.clear() << folder << SEP << areaID << SEP << "maxHourlyPumpPower.txt"; - ret = maxHourlyPumpPower.timeSeries.loadFromCSVFile(filepath, 1, HOURS_PER_YEAR, &fileContent) + filePath = folder / areaID / "maxHourlyPumpPower.txt"; + ret = maxHourlyPumpPower.timeSeries.loadFromCSVFile(filePath.string(), + 1, + HOURS_PER_YEAR, + &fileContent) && ret; return ret; diff --git a/src/libs/antares/study/parts/load/prepro.cpp b/src/libs/antares/study/parts/load/prepro.cpp index 68ae63a322..b5a5342c82 100644 --- a/src/libs/antares/study/parts/load/prepro.cpp +++ b/src/libs/antares/study/parts/load/prepro.cpp @@ -38,7 +38,7 @@ Prepro::~Prepro() { } -bool Prepro::loadFromFolder(const AnyString& folder) +bool Prepro::loadFromFolder(const std::filesystem::path& folder) { return xcast.loadFromFolder(folder); } diff --git a/src/libs/antares/study/parts/renewable/cluster.cpp b/src/libs/antares/study/parts/renewable/cluster.cpp index a89872d4f9..8c92daec6f 100644 --- a/src/libs/antares/study/parts/renewable/cluster.cpp +++ b/src/libs/antares/study/parts/renewable/cluster.cpp @@ -38,8 +38,6 @@ using namespace Yuni; using namespace Antares; -#define SEP IO::Separator - namespace Antares::Data { Data::RenewableCluster::RenewableCluster(Area* parent): diff --git a/src/libs/antares/study/parts/renewable/cluster_list.cpp b/src/libs/antares/study/parts/renewable/cluster_list.cpp index 2b1ac3d3b6..68e0d80698 100644 --- a/src/libs/antares/study/parts/renewable/cluster_list.cpp +++ b/src/libs/antares/study/parts/renewable/cluster_list.cpp @@ -28,6 +28,8 @@ using namespace Yuni; +namespace fs = std::filesystem; + namespace Antares::Data { @@ -136,7 +138,7 @@ static bool ClusterLoadFromProperty(RenewableCluster& cluster, const IniFile::Pr return false; } -static bool ClusterLoadFromSection(const AnyString& filename, +static bool clusterLoadFromSection(const fs::path& filename, RenewableCluster& cluster, const IniFile::Section& section) { @@ -169,7 +171,7 @@ static bool ClusterLoadFromSection(const AnyString& filename, return true; } -bool RenewableClusterList::loadFromFolder(const AnyString& folder, Area* area) +bool RenewableClusterList::loadFromFolder(const fs::path& folder, Area* area) { assert(area and "A parent area is required"); @@ -177,11 +179,10 @@ bool RenewableClusterList::loadFromFolder(const AnyString& folder, Area* area) logs.info() << "Loading renewable configuration for the area " << area->name; // Open the ini file - YString buffer; - buffer << folder << SEP << "list.ini"; + fs::path filename = folder / "list.ini"; IniFile ini; - if (ini.open(buffer, false)) + if (ini.open(filename, false)) { bool ret = true; @@ -197,7 +198,7 @@ bool RenewableClusterList::loadFromFolder(const AnyString& folder, Area* area) auto cluster = std::make_shared(area); // Load data of a renewable cluster from a ini file section - if (!ClusterLoadFromSection(buffer, *cluster, *section)) + if (!clusterLoadFromSection(filename, *cluster, *section)) { continue; } diff --git a/src/libs/antares/study/parts/short-term-storage/properties.cpp b/src/libs/antares/study/parts/short-term-storage/properties.cpp index b4592105fe..28d6afe9a8 100644 --- a/src/libs/antares/study/parts/short-term-storage/properties.cpp +++ b/src/libs/antares/study/parts/short-term-storage/properties.cpp @@ -27,8 +27,6 @@ #include -#define SEP Yuni::IO::Separator - namespace Antares::Data::ShortTermStorage { diff --git a/src/libs/antares/study/parts/solar/prepro.cpp b/src/libs/antares/study/parts/solar/prepro.cpp index e11b4e00ea..0e3af8f016 100644 --- a/src/libs/antares/study/parts/solar/prepro.cpp +++ b/src/libs/antares/study/parts/solar/prepro.cpp @@ -43,7 +43,7 @@ Prepro::~Prepro() { } -bool Prepro::loadFromFolder(const AnyString& folder) +bool Prepro::loadFromFolder(const std::filesystem::path& folder) { return xcast.loadFromFolder(folder); } diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index f85fae235e..7467238a7e 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -42,8 +42,6 @@ using namespace Antares; #define THERMALAGGREGATELIST_INITIAL_CAPACITY 10 -#define SEP IO::Separator - namespace Yuni::Extension::CString { bool Into::Perform(AnyString string, TargetType& out) diff --git a/src/libs/antares/study/parts/wind/prepro.cpp b/src/libs/antares/study/parts/wind/prepro.cpp index f631a5db81..fd449e61a1 100644 --- a/src/libs/antares/study/parts/wind/prepro.cpp +++ b/src/libs/antares/study/parts/wind/prepro.cpp @@ -21,17 +21,9 @@ #include "antares/study/parts/wind/prepro.h" -#include -#include - #include #include "antares/study/study.h" -using namespace Yuni; -using namespace Antares; - -#define SEP IO::Separator - namespace Antares::Data::Wind { Prepro::Prepro(): @@ -43,7 +35,7 @@ Prepro::~Prepro() { } -bool Prepro::loadFromFolder(const AnyString& folder) +bool Prepro::loadFromFolder(const std::filesystem::path& folder) { return xcast.loadFromFolder(folder); } diff --git a/src/libs/antares/study/scenario-builder/sets.cpp b/src/libs/antares/study/scenario-builder/sets.cpp index 76dbcb9166..78cdffb3d9 100644 --- a/src/libs/antares/study/scenario-builder/sets.cpp +++ b/src/libs/antares/study/scenario-builder/sets.cpp @@ -26,8 +26,6 @@ using namespace Yuni; -#define SEP IO::Separator - namespace Antares::Data::ScenarioBuilder { Sets::Sets(): diff --git a/src/libs/antares/study/study.cpp b/src/libs/antares/study/study.cpp index 39130a968e..9db4360b03 100644 --- a/src/libs/antares/study/study.cpp +++ b/src/libs/antares/study/study.cpp @@ -635,6 +635,7 @@ Area* Study::areaAdd(const AreaName& name, bool updateMode) return area; } +// TODO VP: delete with GUI bool Study::areaDelete(Area* area) { if (not area) @@ -682,6 +683,7 @@ bool Study::areaDelete(Area* area) return true; } +// TODO VP: delete with GUI void Study::areaDelete(Area::Vector& arealist) { if (arealist.empty()) @@ -744,6 +746,7 @@ void Study::areaDelete(Area::Vector& arealist) } } +// TODO VP: delete with GUI bool Study::linkDelete(AreaLink* lnk) { // Impossible to find the attached area @@ -769,6 +772,7 @@ bool Study::linkDelete(AreaLink* lnk) return true; } +// TODO VP: delete with GUI bool Study::areaRename(Area* area, AreaName newName) { // A name must not be empty @@ -851,6 +855,7 @@ bool Study::areaRename(Area* area, AreaName newName) return ret; } +// TODO VP: delete with GUI bool Study::clusterRename(Cluster* cluster, ClusterName newName) { // A name must not be empty diff --git a/src/libs/antares/study/study.importprepro.cpp b/src/libs/antares/study/study.importprepro.cpp index 69a0fe058b..3cf520c5eb 100644 --- a/src/libs/antares/study/study.importprepro.cpp +++ b/src/libs/antares/study/study.importprepro.cpp @@ -29,6 +29,8 @@ using namespace Yuni; namespace Antares::Data { + +// TODO VP: remove with time series TS generation before solver execution bool Study::importTimeseriesIntoInput() { // Special case: some thermal clusters may force TS generation diff --git a/src/libs/antares/study/xcast/xcast.cpp b/src/libs/antares/study/xcast/xcast.cpp index 0f2e05956b..d8f055775a 100644 --- a/src/libs/antares/study/xcast/xcast.cpp +++ b/src/libs/antares/study/xcast/xcast.cpp @@ -30,6 +30,8 @@ using namespace Yuni; +namespace fs = std::filesystem; + #define SEP IO::Separator namespace Antares::Data @@ -181,7 +183,7 @@ void XCast::resetToDefaultValues() useTranslation = tsTranslationNone; } -bool XCast::loadFromFolder(const AnyString& folder) +bool XCast::loadFromFolder(const fs::path& folder) { // reset distribution = dtBeta; @@ -196,13 +198,13 @@ bool XCast::loadFromFolder(const AnyString& folder) // Return value bool ret = true; // Settings - buffer.clear() << folder << SEP << "settings.ini"; + fs::path settingsPath = folder / "settings.ini"; IniFile ini; - if (ini.open(buffer)) + if (ini.open(settingsPath)) { ini.each( - [this, &buffer](const IniFile::Section& section) + [this, &settingsPath](const IniFile::Section& section) { // For each property if (section.name == "general") @@ -217,7 +219,7 @@ bool XCast::loadFromFolder(const AnyString& folder) distribution = StringToDistribution(p->value); if (distribution == dtNone) { - logs.warning() << buffer + logs.warning() << settingsPath << ": Invalid probability distribution. The beta " "distribution will be used"; distribution = dtBeta; @@ -230,7 +232,7 @@ bool XCast::loadFromFolder(const AnyString& folder) if (capacity < 0.) { logs.warning() - << buffer << ": The capacity can not be a negative value"; + << settingsPath << ": The capacity can not be a negative value"; capacity = 0.; } continue; @@ -246,18 +248,18 @@ bool XCast::loadFromFolder(const AnyString& folder) continue; } - logs.warning() << buffer << ": Unknown property '" << p->key << "'"; + logs.warning() << settingsPath << ": Unknown property '" << p->key << "'"; } } else { - logs.warning() << buffer << ": unknown section '" << section.name << "'"; + logs.warning() << settingsPath << ": unknown section '" << section.name << "'"; } }); } else { - logs.error() << "I/O Error: unable to open '" << buffer << "'"; + logs.error() << "I/O Error: unable to open '" << settingsPath << "'"; ret = false; } @@ -265,22 +267,22 @@ bool XCast::loadFromFolder(const AnyString& folder) // fix invalid data // Coefficients - buffer.clear() << folder << SEP << "data.txt"; + fs::path p = folder / "data.txt"; // Performing normal loading - ret = data.loadFromCSVFile(buffer, (uint)dataMax, 12, Matrix<>::optFixedSize, &readBuffer) + ret = data.loadFromCSVFile(p.string(), (uint)dataMax, 12, Matrix<>::optFixedSize, &readBuffer) && ret; // K - buffer.clear() << folder << SEP << "k.txt"; - ret = K.loadFromCSVFile(buffer, 12, 24, Matrix<>::optFixedSize, &readBuffer) && ret; + p = folder / "k.txt"; + ret = K.loadFromCSVFile(p.string(), 12, 24, Matrix<>::optFixedSize, &readBuffer) && ret; uint opts = Matrix<>::optNone; // Time-series translation - buffer.clear() << folder << SEP << "translation.txt"; + p = folder / "translation.txt"; - ret = translation.loadFromCSVFile(buffer, 1, HOURS_PER_YEAR, opts, &readBuffer) && ret; + ret = translation.loadFromCSVFile(p.string(), 1, HOURS_PER_YEAR, opts, &readBuffer) && ret; if (!JIT::usedFromGUI) { if (translation.empty()) @@ -303,8 +305,9 @@ bool XCast::loadFromFolder(const AnyString& folder) opts = Matrix<>::optNone; // Transfer function - buffer.clear() << folder << SEP << "conversion.txt"; - ret = conversion.loadFromCSVFile(buffer, 3, 2, opts, &readBuffer) && ret; + p = folder / "conversion.txt"; + + ret = conversion.loadFromCSVFile(p.string(), 3, 2, opts, &readBuffer) && ret; if (not JIT::enabled) { if (conversion.width >= 3 && conversion.width <= conversionMaxPoints) @@ -318,7 +321,7 @@ bool XCast::loadFromFolder(const AnyString& folder) { if (conversion[x][0] <= -1.0e+19 || conversion[x][0] >= +1.0e+19) { - logs.error() << "TS-Generator: Conversion: Invalid range: " << buffer; + logs.error() << "TS-Generator: Conversion: Invalid range: " << p; } } conversion[conversion.width - 1][0] @@ -327,7 +330,7 @@ bool XCast::loadFromFolder(const AnyString& folder) } else { - logs.warning() << "Invalid transfer function: '" << buffer << "'"; + logs.warning() << "Invalid transfer function: '" << p << "'"; resetTransferFunction(); useConversion = false; } diff --git a/src/libs/antares/writer/immediate_file_writer.cpp b/src/libs/antares/writer/immediate_file_writer.cpp index 3554598de3..40a90ec067 100644 --- a/src/libs/antares/writer/immediate_file_writer.cpp +++ b/src/libs/antares/writer/immediate_file_writer.cpp @@ -68,7 +68,7 @@ void ImmediateFileResultWriter::addEntryFromBuffer(const std::string& entryPath, } // Write to file immediately, creating directories if needed -void ImmediateFileResultWriter::addEntryFromBuffer(const std::string& entryPath, +void ImmediateFileResultWriter::addEntryFromBuffer(const fs::path& entryPath, std::string& entryContent) { fs::path output; @@ -121,7 +121,7 @@ void NullResultWriter::addEntryFromBuffer(const std::string&, Yuni::Clob&) { } -void NullResultWriter::addEntryFromBuffer(const std::string&, std::string&) +void NullResultWriter::addEntryFromBuffer(const fs::path&, std::string&) { } diff --git a/src/libs/antares/writer/in_memory_writer.cpp b/src/libs/antares/writer/in_memory_writer.cpp index 182fee1927..2c5e282fcb 100644 --- a/src/libs/antares/writer/in_memory_writer.cpp +++ b/src/libs/antares/writer/in_memory_writer.cpp @@ -75,9 +75,9 @@ void InMemoryWriter::addEntryFromBuffer(const std::string& entryPath, Yuni::Clob addToMap(pEntries, entryPath, entryContent, pMapMutex, pDurationCollector); } -void InMemoryWriter::addEntryFromBuffer(const std::string& entryPath, std::string& entryContent) +void InMemoryWriter::addEntryFromBuffer(const fs::path& entryPath, std::string& entryContent) { - addToMap(pEntries, entryPath, entryContent, pMapMutex, pDurationCollector); + addToMap(pEntries, entryPath.string(), entryContent, pMapMutex, pDurationCollector); } void InMemoryWriter::addEntryFromFile(const fs::path& entryPath, const fs::path& filePath) diff --git a/src/libs/antares/writer/include/antares/writer/i_writer.h b/src/libs/antares/writer/include/antares/writer/i_writer.h index 40fd3799ee..473ae6daa4 100644 --- a/src/libs/antares/writer/include/antares/writer/i_writer.h +++ b/src/libs/antares/writer/include/antares/writer/i_writer.h @@ -35,7 +35,9 @@ class IResultWriter public: using Ptr = std::shared_ptr; virtual void addEntryFromBuffer(const std::string& entryPath, Yuni::Clob& entryContent) = 0; - virtual void addEntryFromBuffer(const std::string& entryPath, std::string& entryContent) = 0; + virtual void addEntryFromBuffer(const std::filesystem::path& entryPath, + std::string& entryContent) + = 0; virtual void addEntryFromFile(const std::filesystem::path& entryPath, const std::filesystem::path& filePath) = 0; @@ -52,7 +54,7 @@ class IResultWriter class NullResultWriter: public Solver::IResultWriter { void addEntryFromBuffer(const std::string&, Yuni::Clob&) override; - void addEntryFromBuffer(const std::string&, std::string&) override; + void addEntryFromBuffer(const std::filesystem::path&, std::string&) override; void addEntryFromFile(const std::filesystem::path&, const std::filesystem::path&) override; void flush() override; bool needsTheJobQueue() const override; diff --git a/src/libs/antares/writer/include/antares/writer/in_memory_writer.h b/src/libs/antares/writer/include/antares/writer/in_memory_writer.h index 9fc465a83f..e5be52be24 100644 --- a/src/libs/antares/writer/include/antares/writer/in_memory_writer.h +++ b/src/libs/antares/writer/include/antares/writer/in_memory_writer.h @@ -38,7 +38,8 @@ class InMemoryWriter: public IResultWriter explicit InMemoryWriter(Benchmarking::DurationCollector& duration_collector); virtual ~InMemoryWriter(); void addEntryFromBuffer(const std::string& entryPath, Yuni::Clob& entryContent) override; - void addEntryFromBuffer(const std::string& entryPath, std::string& entryContent) override; + void addEntryFromBuffer(const std::filesystem::path& entryPath, + std::string& entryContent) override; void addEntryFromFile(const std::filesystem::path& entryPath, const std::filesystem::path& filePath) override; void flush() override; diff --git a/src/libs/antares/writer/private/immediate_file_writer.h b/src/libs/antares/writer/private/immediate_file_writer.h index 1711bbfe96..1c340ee066 100644 --- a/src/libs/antares/writer/private/immediate_file_writer.h +++ b/src/libs/antares/writer/private/immediate_file_writer.h @@ -36,7 +36,8 @@ class ImmediateFileResultWriter: public IResultWriter virtual ~ImmediateFileResultWriter(); // Write to file immediately, creating directories if needed void addEntryFromBuffer(const std::string& entryPath, Yuni::Clob& entryContent) override; - void addEntryFromBuffer(const std::string& entryPath, std::string& entryContent) override; + void addEntryFromBuffer(const std::filesystem::path& entryPath, + std::string& entryContent) override; void addEntryFromFile(const std::filesystem::path& entryPath, const std::filesystem::path& filePath) override; void flush() override; diff --git a/src/libs/antares/writer/private/zip_writer.h b/src/libs/antares/writer/private/zip_writer.h index f24c353018..948c3aaa04 100644 --- a/src/libs/antares/writer/private/zip_writer.h +++ b/src/libs/antares/writer/private/zip_writer.h @@ -82,7 +82,8 @@ class ZipWriter: public IResultWriter Benchmarking::DurationCollector& duration_collector); virtual ~ZipWriter(); void addEntryFromBuffer(const std::string& entryPath, Yuni::Clob& entryContent) override; - void addEntryFromBuffer(const std::string& entryPath, std::string& entryContent) override; + void addEntryFromBuffer(const std::filesystem::path& entryPath, + std::string& entryContent) override; void addEntryFromFile(const std::filesystem::path& entryPath, const std::filesystem::path& filePath) override; void flush() override; @@ -109,7 +110,8 @@ class ZipWriter: public IResultWriter private: template - void addEntryFromBufferHelper(const std::string& entryPath, ContentType& entryContent); + void addEntryFromBufferHelper(const std::filesystem::path& entryPath, + ContentType& entryContent); }; } // namespace Antares::Solver diff --git a/src/libs/antares/writer/private/zip_writer.hxx b/src/libs/antares/writer/private/zip_writer.hxx index a435768b5a..2bc13ff316 100644 --- a/src/libs/antares/writer/private/zip_writer.hxx +++ b/src/libs/antares/writer/private/zip_writer.hxx @@ -27,7 +27,8 @@ namespace Antares::Solver { template -void ZipWriter::addEntryFromBufferHelper(const std::string& entryPath, ContentType& entryContent) +void ZipWriter::addEntryFromBufferHelper(const std::filesystem::path& entryPath, + ContentType& entryContent) { if (pState != ZipState::can_receive_data) { @@ -37,7 +38,7 @@ void ZipWriter::addEntryFromBufferHelper(const std::string& entryPath, ContentTy EnsureQueueStartedIfNeeded ensureQueue(this, pQueueService); pendingTasks_.add(Concurrency::AddTask( *pQueueService, - ZipWriteJob(*this, entryPath, entryContent, pDurationCollector), + ZipWriteJob(*this, entryPath.string(), entryContent, pDurationCollector), Yuni::Job::priorityLow)); } diff --git a/src/libs/antares/writer/zip_writer.cpp b/src/libs/antares/writer/zip_writer.cpp index 007524377a..008f7fdd9c 100644 --- a/src/libs/antares/writer/zip_writer.cpp +++ b/src/libs/antares/writer/zip_writer.cpp @@ -157,7 +157,7 @@ void ZipWriter::addEntryFromBuffer(const std::string& entryPath, Yuni::Clob& ent addEntryFromBufferHelper(entryPath, entryContent); } -void ZipWriter::addEntryFromBuffer(const std::string& entryPath, std::string& entryContent) +void ZipWriter::addEntryFromBuffer(const fs::path& entryPath, std::string& entryContent) { addEntryFromBufferHelper(entryPath, entryContent); } diff --git a/src/solver/constraints-builder/load.cpp b/src/solver/constraints-builder/load.cpp index 73beec49c1..36868da082 100644 --- a/src/solver/constraints-builder/load.cpp +++ b/src/solver/constraints-builder/load.cpp @@ -18,17 +18,10 @@ * You should have received a copy of the Mozilla Public Licence 2.0 * along with Antares_Simulator. If not, see . */ -#include - -#include #include "antares/config/config.h" #include "antares/solver/constraints-builder/cbuilder.h" #include "antares/study/area/constants.h" -using namespace Yuni; - -#define SEP Yuni::IO::Separator - namespace Antares { bool CBuilder::completeFromStudy() diff --git a/src/solver/hydro/management/daily.cpp b/src/solver/hydro/management/daily.cpp index 8bf59df763..ee11407f1f 100644 --- a/src/solver/hydro/management/daily.cpp +++ b/src/solver/hydro/management/daily.cpp @@ -141,7 +141,7 @@ struct DebugData buffer << '\n'; } auto buffer_str = buffer.str(); - pWriter.addEntryFromBuffer(path.string(), buffer_str); + pWriter.addEntryFromBuffer(path, buffer_str); } void writeDailyDebugData(const Date::Calendar& calendar, @@ -210,7 +210,7 @@ struct DebugData } } auto buffer_str = buffer.str(); - pWriter.addEntryFromBuffer(path.string(), buffer_str); + pWriter.addEntryFromBuffer(path, buffer_str); } }; diff --git a/src/solver/hydro/management/monthly.cpp b/src/solver/hydro/management/monthly.cpp index 62658e277d..0b004a11ef 100644 --- a/src/solver/hydro/management/monthly.cpp +++ b/src/solver/hydro/management/monthly.cpp @@ -304,7 +304,7 @@ void HydroManagement::prepareMonthlyOptimalGenerations(const double* random_rese buffer << '\n'; } auto content = buffer.str(); - resultWriter_.addEntryFromBuffer(path.string(), content); + resultWriter_.addEntryFromBuffer(path, content); } indexArea++; }); diff --git a/src/solver/main.cpp b/src/solver/main.cpp index a0f012a9ef..3840446c73 100644 --- a/src/solver/main.cpp +++ b/src/solver/main.cpp @@ -28,9 +28,6 @@ #include "antares/application/application.h" using namespace Antares; -using namespace Yuni; - -#define SEP Yuni::IO::Separator namespace { diff --git a/src/solver/simulation/TimeSeriesNumbersWriter.cpp b/src/solver/simulation/TimeSeriesNumbersWriter.cpp index 09122c32e0..d35dd5fdc5 100644 --- a/src/solver/simulation/TimeSeriesNumbersWriter.cpp +++ b/src/solver/simulation/TimeSeriesNumbersWriter.cpp @@ -48,7 +48,7 @@ static void genericStoreTimeseriesNumbers(Solver::IResultWriter& writer, std::string buffer; timeseriesNumbers.saveToBuffer(buffer); - writer.addEntryFromBuffer(path.string(), buffer); + writer.addEntryFromBuffer(path, buffer); } void BindingConstraintsTimeSeriesNumbersWriter::write( diff --git a/src/solver/simulation/opt_time_writer.cpp b/src/solver/simulation/opt_time_writer.cpp index a09f3feaa8..8ea4091a26 100644 --- a/src/solver/simulation/opt_time_writer.cpp +++ b/src/solver/simulation/opt_time_writer.cpp @@ -47,5 +47,5 @@ void OptimizationStatisticsWriter::finalize() const path filename = path("optimization") / "week-by-week" / ("year_" + std::to_string(pYear) + ".txt"); std::string s = pBuffer.str(); - pWriter.addEntryFromBuffer(filename.string(), s); + pWriter.addEntryFromBuffer(filename, s); } diff --git a/src/solver/simulation/solver_utils.cpp b/src/solver/simulation/solver_utils.cpp index 76f5fc0ce3..401aa3db68 100644 --- a/src/solver/simulation/solver_utils.cpp +++ b/src/solver/simulation/solver_utils.cpp @@ -22,21 +22,18 @@ #include "antares/solver/simulation/solver_utils.h" #include +#include #include #include #include #include -#include - -#define SEP Yuni::IO::Separator +namespace fs = std::filesystem; static const std::string systemCostFilename = "annualSystemCost.txt"; static const std::string criterionsCostsFilename = "checkIntegrity.txt"; -static const std::string optimizationTimeFilename = std::string("optimization") + SEP - + "solve-durations.txt"; -static const std::string updateTimeFilename = std::string("optimization") + SEP - + "update-durations.txt"; +static const fs::path optimizationTimeFilename = fs::path("optimization") / "solve-durations.txt"; +static const fs::path updateTimeFilename = fs::path("optimization") / "update-durations.txt"; static std::ostream& toScientific(std::ostream& os) { diff --git a/src/solver/ts-generator/hydro.cpp b/src/solver/ts-generator/hydro.cpp index dd5af1a25e..966625aa81 100644 --- a/src/solver/ts-generator/hydro.cpp +++ b/src/solver/ts-generator/hydro.cpp @@ -30,7 +30,7 @@ using namespace Antares; -#define SEP Yuni::IO::Separator +namespace fs = std::filesystem; #define EPSILON ((double)1.0e-9) @@ -281,26 +281,22 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, Solver::IResu { logs.info() << "Archiving the hydro time-series"; study.areas.each( - [&study, ¤tYear, &writer, &progression](const Data::Area& area) + [¤tYear, &writer, &progression](const Data::Area& area) { const int precision = 0; - Yuni::String output; - study.buffer.clear() << "ts-generator" << SEP << "hydro" << SEP << "mc-" - << currentYear << SEP << area.id; - - { - std::string buffer; - area.hydro.series->ror.timeSeries.saveToBuffer(buffer, precision); - output.clear() << study.buffer << SEP << "ror.txt"; - writer.addEntryFromBuffer(output.c_str(), buffer); - } - - { - std::string buffer; - area.hydro.series->storage.timeSeries.saveToBuffer(buffer, precision); - output.clear() << study.buffer << SEP << "storage.txt"; - writer.addEntryFromBuffer(output.c_str(), buffer); - } + std::string mcYear = "mc-" + currentYear; + fs::path outputFolder = fs::path("ts-generator") / "hydro" / mcYear + / area.id.to(); + + std::string buffer; + area.hydro.series->ror.timeSeries.saveToBuffer(buffer, precision); + fs::path outputFile = outputFolder / "ror.txt"; + writer.addEntryFromBuffer(outputFile, buffer); + + area.hydro.series->storage.timeSeries.saveToBuffer(buffer, precision); + outputFile = outputFolder / "storage.txt"; + writer.addEntryFromBuffer(outputFile, buffer); + ++progression; }); } diff --git a/src/solver/ts-generator/prepro.cpp b/src/solver/ts-generator/prepro.cpp index 943527c8e7..d7addc9c46 100644 --- a/src/solver/ts-generator/prepro.cpp +++ b/src/solver/ts-generator/prepro.cpp @@ -20,18 +20,11 @@ */ #include -#include -#include -#include #include #include #include "antares/study/study.h" -using namespace Yuni; - -#define SEP IO::Separator - namespace Antares::Data { PreproAvailability::PreproAvailability(const YString& id, unsigned int unitCount): @@ -50,10 +43,10 @@ void PreproAvailability::copyFrom(const PreproAvailability& rhs) bool PreproAvailability::saveToFolder(const AnyString& folder) const { - if (IO::Directory::Create(folder)) + if (Yuni::IO::Directory::Create(folder)) { - String buffer; - buffer.clear() << folder << SEP << "data.txt"; + Yuni::String buffer; + buffer.clear() << folder << Yuni::IO::Separator << "data.txt"; return data.saveToCSVFile(buffer, /*decimal*/ 6); } return false; diff --git a/src/solver/ts-generator/xcast/xcast.cpp b/src/solver/ts-generator/xcast/xcast.cpp index 3f42862cb5..7af0d35da5 100644 --- a/src/solver/ts-generator/xcast/xcast.cpp +++ b/src/solver/ts-generator/xcast/xcast.cpp @@ -25,16 +25,12 @@ #include #include -#include - #include #include #include #include "antares/solver/ts-generator/xcast/predicate.hxx" -using namespace Yuni; - -#define SEP (IO::Separator) +namespace fs = std::filesystem; namespace Antares::TSGenerator::XCast { @@ -71,20 +67,18 @@ void XCast::exportTimeSeriesToTheOutput(Progression::Task& progression, Predicat logs.info() << "Exporting " << predicate.timeSeriesName() << " time-series into the output (year:" << year << ')'; - String output; - String filename; - - output << "ts-generator" << SEP << predicate.timeSeriesName() << SEP << "mc-" << year; - filename.reserve(output.size() + 80); + fs::path output = "ts-generator"; + output /= fs::path(predicate.timeSeriesName()) / std::string("mc-" + year); study.areas.each( - [this, &filename, &progression, &predicate, &output](Data::Area& area) + [this, &progression, &predicate, &output](Data::Area& area) { - filename.clear() << output << SEP << area.id << ".txt"; + std::string areaId = area.id + "txt"; + fs::path filename = output / areaId; std::string buffer; predicate.matrix(area).saveToBuffer(buffer); - pWriter.addEntryFromBuffer(filename.c_str(), buffer); + pWriter.addEntryFromBuffer(filename, buffer); ++progression; }); diff --git a/src/solver/variable/include/antares/solver/variable/container.hxx b/src/solver/variable/include/antares/solver/variable/container.hxx index 2435a2ef8d..dd76f9b523 100644 --- a/src/solver/variable/include/antares/solver/variable/container.hxx +++ b/src/solver/variable/include/antares/solver/variable/container.hxx @@ -23,13 +23,10 @@ #include -#include #include #include "antares/solver/variable/surveyresults/reportbuilder.hxx" -#define SEP Yuni::IO::Separator - namespace Antares { namespace Solver @@ -248,7 +245,8 @@ void List::buildSurveyReport(SurveyResults& results, // The new filename results.data.filename.clear(); - results.data.filename << results.data.output << SEP; + results.data.filename << std::filesystem::path(static_cast(results.data.output)) + / ""; Category::FileLevelToStream(results.data.filename, fileLevel); results.data.filename << '-'; Category::PrecisionLevelToStream(results.data.filename, precision); @@ -277,7 +275,8 @@ void List::buildAnnualSurveyReport(SurveyResults& results, // The new filename results.data.filename.clear(); - results.data.filename << results.data.output << SEP; + results.data.filename << std::filesystem::path(static_cast(results.data.output)) + / ""; Category::FileLevelToStream(results.data.filename, fileLevel); results.data.filename << '-'; Category::PrecisionLevelToStream(results.data.filename, precision); diff --git a/src/solver/variable/include/antares/solver/variable/surveyresults/reportbuilder.hxx b/src/solver/variable/include/antares/solver/variable/surveyresults/reportbuilder.hxx index 6354169b96..11a9277dab 100644 --- a/src/solver/variable/include/antares/solver/variable/surveyresults/reportbuilder.hxx +++ b/src/solver/variable/include/antares/solver/variable/surveyresults/reportbuilder.hxx @@ -36,8 +36,6 @@ #include "../info.h" #include "../surveyresults.h" -#define SEP Yuni::IO::Separator - namespace Antares { namespace Solver @@ -272,8 +270,10 @@ public: } // THIS FILE IS DEPRECATED !!! YString digestFileName; - digestFileName << results.data.originalOutput << SEP << "grid" << SEP << "digest.txt"; - writer.addEntryFromBuffer(digestFileName.c_str(), digestBuffer); + std::filesystem::path path = static_cast(results.data.originalOutput); + path /= "grid"; + path /= "digest.txt"; + writer.addEntryFromBuffer(path, digestBuffer); } private: @@ -320,9 +320,11 @@ private: { logs.info() << "Exporting results : " << area.name; // The new output - results.data.output.clear(); - results.data.output << results.data.originalOutput << SEP << "areas" << SEP - << area.id; + std::filesystem::path path = static_cast(results.data.originalOutput); + path /= "areas"; + path /= area.id.to(); + + results.data.output = path.string(); SurveyReportBuilderFile::Run(list, results, numSpace); } @@ -354,9 +356,11 @@ private: logs.info() << "Exporting results : " << area.name << " :: " << cluster->name(); // The new output - results.data.output.clear(); - results.data.output << results.data.originalOutput << SEP << "areas" << SEP - << area.id << SEP << "thermal" << SEP << cluster->id(); + std::filesystem::path path = static_cast(results.data.originalOutput); + path /= std::filesystem::path("areas") / area.id.to() / "thermal" + / cluster->id(); + + results.data.output = path.string(); SurveyReportBuilderFile::Run(list, results, numSpace); } @@ -405,9 +409,14 @@ private: Antares::logs.info() << "Exporting results : " << area.name << " - " << results.data.link->with->name; // The new output - results.data.output.clear(); - results.data.output << results.data.originalOutput << SEP << "links" << SEP - << area.id << " - " << results.data.link->with->id; + std::filesystem::path path = static_cast( + results.data.originalOutput); + std::string areaId = static_cast(area.id) + " - " + + results.data.link->with->id; + path /= std::filesystem::path("links") / areaId; + + results.data.output = path.string(); + SurveyReportBuilderFile::Run(list, results, numSpace); @@ -449,11 +458,13 @@ private: logs.info() << "Exporting results : " << sets.caption(i); // The new output - results.data.output.clear(); - results.data.output << results.data.originalOutput << SEP << "areas" << SEP << "@ " - << sets.nameByIndex(i); + std::filesystem::path path = static_cast(results.data.originalOutput); + std::string setId = "@ " + sets.nameByIndex(i); + path /= std::filesystem::path("areas") / setId; + results.data.output = path.string(); results.data.setOfAreasIndex = indx++; + SurveyReportBuilderFile::Run(list, results, numSpace); } } @@ -469,8 +480,10 @@ private: { logs.info() << "Exporting results : binding constraints"; // The new output - results.data.output.clear(); - results.data.output << results.data.originalOutput << SEP << "binding_constraints"; + std::filesystem::path path = static_cast(results.data.originalOutput); + path /= "binding_constraints"; + + results.data.output = path.string(); SurveyReportBuilderFile::Run(list, results, numSpace); } } @@ -496,7 +509,4 @@ public: } // namespace Solver } // namespace Antares -// cleanup -#undef SEP - #endif // __SOLVER_VARIABLE_SURVEYRESULTS_REPORT_BUILDER_HXX__ diff --git a/src/solver/variable/surveyresults/surveyresults.cpp b/src/solver/variable/surveyresults/surveyresults.cpp index 8df87678e4..6a89d2cb14 100644 --- a/src/solver/variable/surveyresults/surveyresults.cpp +++ b/src/solver/variable/surveyresults/surveyresults.cpp @@ -31,11 +31,8 @@ #include #include -using namespace Yuni; using namespace Antares; -#define SEP IO::Separator - namespace Antares::Solver::Variable::Private { void InternalExportDigestLinksMatrix(const Data::Study& study, @@ -114,12 +111,12 @@ void InternalExportDigestLinksMatrix(const Data::Study& study, } static void ExportGridInfosAreas(const Data::Study& study, - const Yuni::String& originalOutput, + const std::string& originalOutput, IResultWriter& writer) { - Clob out; - Clob outLinks; - Clob outThermal; + Yuni::Clob out; + Yuni::Clob outLinks; + Yuni::Clob outThermal; out << "id\tname\n"; outLinks << "upstream\tdownstream\n"; @@ -164,11 +161,12 @@ static void ExportGridInfosAreas(const Data::Study& study, } // each thermal cluster }); // each area - auto add = [&writer, &originalOutput](const YString& filename, Clob&& buffer) + auto add = [&writer, &originalOutput](const std::string& filename, Yuni::Clob&& buffer) { - YString path; - path << originalOutput << SEP << "grid" << SEP << filename; - writer.addEntryFromBuffer(path.c_str(), buffer); + std::filesystem::path path = originalOutput; + path /= "grid"; + path /= filename; + writer.addEntryFromBuffer(path.string(), buffer); }; add("areas.txt", std::move(out)); @@ -176,7 +174,7 @@ static void ExportGridInfosAreas(const Data::Study& study, add("thermal.txt", std::move(outThermal)); } -SurveyResultsData::SurveyResultsData(const Data::Study& s, const String& o): +SurveyResultsData::SurveyResultsData(const Data::Study& s, const Yuni::String& o): columnIndex((uint)-1), thermalCluster(nullptr), area(nullptr), @@ -511,7 +509,7 @@ static inline void WriteIndexHeaderToFileDescriptor(int precisionLevel, s += '\n'; } -SurveyResults::SurveyResults(const Data::Study& s, const String& o, IResultWriter& writer): +SurveyResults::SurveyResults(const Data::Study& s, const Yuni::String& o, IResultWriter& writer): data(s, o), yearByYearResults(false), isCurrentVarNA(nullptr), diff --git a/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp b/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp index d7de940912..427eeadb73 100644 --- a/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp +++ b/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp @@ -31,17 +31,16 @@ #include "antares/study/parts/short-term-storage/container.h" -#define SEP Yuni::IO::Separator - using namespace std; using namespace Antares::Data; +namespace fs = std::filesystem; + namespace { -std::string getFolder() +fs::path getFolder() { - std::filesystem::path tmpDir = std::filesystem::temp_directory_path(); - return tmpDir.string(); + return fs::temp_directory_path(); } void resizeFillVectors(ShortTermStorage::Series& series, double value, unsigned int size) @@ -57,7 +56,7 @@ void resizeFillVectors(ShortTermStorage::Series& series, double value, unsigned series.costLevel.resize(size, value); } -void createIndividualFileSeries(const std::string& path, double value, unsigned int size) +void createIndividualFileSeries(const fs::path& path, double value, unsigned int size) { std::ofstream outfile(path); @@ -69,7 +68,7 @@ void createIndividualFileSeries(const std::string& path, double value, unsigned outfile.close(); } -void createIndividualFileSeries(const std::string& path, unsigned int size) +void createIndividualFileSeries(const fs::path& path, unsigned int size) { std::ofstream outfile; outfile.open(path, std::ofstream::out | std::ofstream::trunc); @@ -85,40 +84,40 @@ void createIndividualFileSeries(const std::string& path, unsigned int size) void createFileSeries(double value, unsigned int size) { - std::string folder = getFolder(); + fs::path folder = getFolder(); - createIndividualFileSeries(folder + SEP + "PMAX-injection.txt", value, size); - createIndividualFileSeries(folder + SEP + "PMAX-withdrawal.txt", value, size); - createIndividualFileSeries(folder + SEP + "inflows.txt", value, size); - createIndividualFileSeries(folder + SEP + "lower-rule-curve.txt", value, size); - createIndividualFileSeries(folder + SEP + "upper-rule-curve.txt", value, size); + createIndividualFileSeries(folder / "PMAX-injection.txt", value, size); + createIndividualFileSeries(folder / "PMAX-withdrawal.txt", value, size); + createIndividualFileSeries(folder / "inflows.txt", value, size); + createIndividualFileSeries(folder / "lower-rule-curve.txt", value, size); + createIndividualFileSeries(folder / "upper-rule-curve.txt", value, size); - createIndividualFileSeries(folder + SEP + "cost-injection.txt", value, size); - createIndividualFileSeries(folder + SEP + "cost-withdrawal.txt", value, size); - createIndividualFileSeries(folder + SEP + "cost-level.txt", value, size); + createIndividualFileSeries(folder / "cost-injection.txt", value, size); + createIndividualFileSeries(folder / "cost-withdrawal.txt", value, size); + createIndividualFileSeries(folder / "cost-level.txt", value, size); } void createFileSeries(unsigned int size) { - std::string folder = getFolder(); + fs::path folder = getFolder(); - createIndividualFileSeries(folder + SEP + "PMAX-injection.txt", size); - createIndividualFileSeries(folder + SEP + "PMAX-withdrawal.txt", size); - createIndividualFileSeries(folder + SEP + "inflows.txt", size); - createIndividualFileSeries(folder + SEP + "lower-rule-curve.txt", size); - createIndividualFileSeries(folder + SEP + "upper-rule-curve.txt", size); + createIndividualFileSeries(folder / "PMAX-injection.txt", size); + createIndividualFileSeries(folder / "PMAX-withdrawal.txt", size); + createIndividualFileSeries(folder / "inflows.txt", size); + createIndividualFileSeries(folder / "lower-rule-curve.txt", size); + createIndividualFileSeries(folder / "upper-rule-curve.txt", size); - createIndividualFileSeries(folder + SEP + "cost-injection.txt", size); - createIndividualFileSeries(folder + SEP + "cost-withdrawal.txt", size); - createIndividualFileSeries(folder + SEP + "cost-level.txt", size); + createIndividualFileSeries(folder / "cost-injection.txt", size); + createIndividualFileSeries(folder / "cost-withdrawal.txt", size); + createIndividualFileSeries(folder / "cost-level.txt", size); } void createIniFile(bool enabled) { - std::string folder = getFolder(); + fs::path folder = getFolder(); std::ofstream outfile; - outfile.open(folder + SEP + "list.ini", std::ofstream::out | std::ofstream::trunc); + outfile.open(folder / "list.ini", std::ofstream::out | std::ofstream::trunc); outfile << "[area]" << std::endl; outfile << "name = area" << std::endl; @@ -135,10 +134,10 @@ void createIniFile(bool enabled) void createIniFileWrongValue() { - std::string folder = getFolder(); + fs::path folder = getFolder(); std::ofstream outfile; - outfile.open(folder + SEP + "list.ini", std::ofstream::out | std::ofstream::trunc); + outfile.open(folder / "list.ini", std::ofstream::out | std::ofstream::trunc); outfile << "[area]" << std::endl; outfile << "name = area" << std::endl; @@ -155,18 +154,17 @@ void createIniFileWrongValue() void createEmptyIniFile() { - std::string folder = getFolder(); + fs::path folder = getFolder(); std::ofstream outfile; - outfile.open(folder + SEP + "list.ini", std::ofstream::out | std::ofstream::trunc); + outfile.open(folder / "list.ini", std::ofstream::out | std::ofstream::trunc); outfile.close(); } void removeIniFile() { - std::string folder = getFolder(); - std::filesystem::remove(folder + SEP + "list.ini"); + fs::remove(getFolder() / "list.ini"); } } // namespace @@ -183,18 +181,18 @@ struct Fixture ~Fixture() { - std::filesystem::remove(folder + SEP + "PMAX-injection.txt"); - std::filesystem::remove(folder + SEP + "PMAX-withdrawal.txt"); - std::filesystem::remove(folder + SEP + "inflows.txt"); - std::filesystem::remove(folder + SEP + "lower-rule-curve.txt"); - std::filesystem::remove(folder + SEP + "upper-rule-curve.txt"); - - std::filesystem::remove(folder + SEP + "cost-injection.txt"); - std::filesystem::remove(folder + SEP + "cost-withdrawal.txt"); - std::filesystem::remove(folder + SEP + "cost-level.txt"); + fs::remove(folder / "PMAX-injection.txt"); + fs::remove(folder / "PMAX-withdrawal.txt"); + fs::remove(folder / "inflows.txt"); + fs::remove(folder / "lower-rule-curve.txt"); + fs::remove(folder / "upper-rule-curve.txt"); + + fs::remove(folder / "cost-injection.txt"); + fs::remove(folder / "cost-withdrawal.txt"); + fs::remove(folder / "cost-level.txt"); } - std::string folder = getFolder(); + fs::path folder = getFolder(); ShortTermStorage::Series series; ShortTermStorage::Properties properties; @@ -345,7 +343,7 @@ BOOST_FIXTURE_TEST_CASE(check_file_save, Fixture) removeIniFile(); - BOOST_CHECK(container.saveToFolder(folder)); + BOOST_CHECK(container.saveToFolder(folder.string())); BOOST_CHECK(container.createSTStorageClustersFromIniFile(folder)); @@ -356,7 +354,7 @@ BOOST_FIXTURE_TEST_CASE(check_series_save, Fixture) { resizeFillVectors(series, 0.123456789, 8760); - BOOST_CHECK(series.saveToFolder(folder)); + BOOST_CHECK(series.saveToFolder(folder.string())); resizeFillVectors(series, 0, 0); BOOST_CHECK(series.loadFromFolder(folder)); From b94e65ec4e561fa5ada602adf1c1cb5b5e021d7b Mon Sep 17 00:00:00 2001 From: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Date: Wed, 23 Oct 2024 11:09:20 +0200 Subject: [PATCH 040/103] Legacy ortools behind API - user story 3.1 & 3.2 (#2455) --- src/packaging/CMakeLists.txt | 43 +-- .../solver/modeler/api/linearProblem.h | 6 + .../modeler/api/linearProblemBuilder.cpp | 1 - .../modeler/ortoolsImpl/linearProblem.h | 15 +- .../solver/modeler/ortoolsImpl/mipSolution.h | 4 +- .../modeler/ortoolsImpl/linearProblem.cpp | 22 +- .../modeler/ortoolsImpl/mipSolution.cpp | 2 +- src/solver/optimisation/CMakeLists.txt | 249 +++++++++--------- src/solver/optimisation/LegacyFiller.cpp | 110 ++++++++ .../solver/optimisation/LegacyFiller.h | 33 +++ .../optimisation/LegacyOrtoolsLinearProblem.h | 45 ++++ .../opt_appel_solveur_lineaire.cpp | 30 ++- .../antares/solver/utils/ortools_utils.h | 61 +---- .../antares/solver/utils/ortools_wrapper.h | 4 - src/solver/utils/ortools_utils.cpp | 125 +-------- .../check_on_results/compare_mps_files.py | 4 +- 16 files changed, 400 insertions(+), 354 deletions(-) create mode 100644 src/solver/optimisation/LegacyFiller.cpp create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/LegacyFiller.h create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/LegacyOrtoolsLinearProblem.h diff --git a/src/packaging/CMakeLists.txt b/src/packaging/CMakeLists.txt index 868cd7a8ec..ea0e5c1836 100644 --- a/src/packaging/CMakeLists.txt +++ b/src/packaging/CMakeLists.txt @@ -6,18 +6,18 @@ include(GNUInstallDirs) # generate and install export file set(TARGET_LIBS #No alias - #each "block" of dependency describe the dependency for a target - #not dependency is present since once a dependency is in the export set - #it is available for everything + # each "block" of dependency describe the dependency for a target + # not dependency is present since once a dependency is in the export set + # it is available for everything - solver_api #What we want to export + solver_api # What we want to export - #solver_api + # solver_api study study-loader file-tree-study-loader antares-solver-simulation - #study + # study yuni-static-core array date @@ -37,39 +37,37 @@ set(TARGET_LIBS #No alias antares-solver-variable lps - #study-loader - #nothing + # study-loader : nothing - #file-tree-study-loader + # file-tree-study-loader application - #run-mode + # run-mode infoCollection - #antares-solver-simulation + # antares-solver-simulation concurrency misc model_antares antares-solver-ts-generator - #lps - #nothing + # lps : nothing - #array + # array io jit AntaresMemory - #date + # date logs - #correlation + # correlation locator - #antares-core + # antares-core antares-config-lib - #application + # application solver-lib sys signal-handling @@ -77,16 +75,19 @@ set(TARGET_LIBS #No alias optimization-options resources - #model_antares + # model_antares infeasible_problem_analysis + modeler_api + modeler-ortools-impl - #solver-lib + # solver-lib args_helper checks locale yuni-static-uuid - antares-solver #executable + # executable + antares-solver ) install(TARGETS ${TARGET_LIBS} diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h index 38006291e0..94c95e4e31 100644 --- a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h @@ -46,6 +46,9 @@ class ILinearProblem virtual IMipVariable* addNumVariable(double lb, double ub, const std::string& name) = 0; /// Create a integer variable virtual IMipVariable* addIntVariable(double lb, double ub, const std::string& name) = 0; + /// Create a continuous or integer variable + virtual IMipVariable* addVariable(double lb, double ub, bool integer, const std::string& name) + = 0; virtual IMipVariable* getVariable(const std::string& name) const = 0; virtual int variableCount() const = 0; @@ -68,6 +71,9 @@ class ILinearProblem /// Solve the problem, returns a IMipSolution virtual IMipSolution* solve(bool verboseSolver) = 0; + + // Definition of infinity + virtual double infinity() const = 0; }; } // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/api/linearProblemBuilder.cpp b/src/solver/modeler/api/linearProblemBuilder.cpp index 5363647c3f..ca93744cc6 100644 --- a/src/solver/modeler/api/linearProblemBuilder.cpp +++ b/src/solver/modeler/api/linearProblemBuilder.cpp @@ -20,7 +20,6 @@ */ #include -#include #include diff --git a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h index d4e6e52c02..3d69ee98e9 100644 --- a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h +++ b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h @@ -36,7 +36,7 @@ class MPObjective; namespace Antares::Solver::Modeler::OrtoolsImpl { -class OrtoolsLinearProblem final: public Api::ILinearProblem +class OrtoolsLinearProblem: public Api::ILinearProblem { public: OrtoolsLinearProblem(bool isMip, const std::string& solverName); @@ -44,6 +44,10 @@ class OrtoolsLinearProblem final: public Api::ILinearProblem OrtoolsMipVariable* addNumVariable(double lb, double ub, const std::string& name) override; OrtoolsMipVariable* addIntVariable(double lb, double ub, const std::string& name) override; + OrtoolsMipVariable* addVariable(double lb, + double ub, + bool integer, + const std::string& name) override; OrtoolsMipVariable* getVariable(const std::string& name) const override; int variableCount() const override; @@ -62,10 +66,13 @@ class OrtoolsLinearProblem final: public Api::ILinearProblem OrtoolsMipSolution* solve(bool verboseSolver) override; -private: - OrtoolsMipVariable* addVariable(double lb, double ub, bool integer, const std::string& name); + double infinity() const override; + +protected: + operations_research::MPSolver* MpSolver() const; - std::shared_ptr mpSolver_; +private: + operations_research::MPSolver* mpSolver_; operations_research::MPObjective* objective_; operations_research::MPSolverParameters params_; diff --git a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipSolution.h b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipSolution.h index c046c49ef6..0cf452c11b 100644 --- a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipSolution.h +++ b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipSolution.h @@ -35,7 +35,7 @@ class OrtoolsMipSolution final: public Api::IMipSolution { public: OrtoolsMipSolution(operations_research::MPSolver::ResultStatus& responseStatus, - std::shared_ptr solver); + operations_research::MPSolver* solver); ~OrtoolsMipSolution() override = default; @@ -47,7 +47,7 @@ class OrtoolsMipSolution final: public Api::IMipSolution private: operations_research::MPSolver::ResultStatus status_; - std::shared_ptr mpSolver_; + operations_research::MPSolver* mpSolver_; std::map solution_; }; diff --git a/src/solver/modeler/ortoolsImpl/linearProblem.cpp b/src/solver/modeler/ortoolsImpl/linearProblem.cpp index 1d8bf981bc..6e8b942945 100644 --- a/src/solver/modeler/ortoolsImpl/linearProblem.cpp +++ b/src/solver/modeler/ortoolsImpl/linearProblem.cpp @@ -31,16 +31,8 @@ namespace Antares::Solver::Modeler::OrtoolsImpl OrtoolsLinearProblem::OrtoolsLinearProblem(bool isMip, const std::string& solverName) { - auto* mpSolver = isMip ? MPSolver::CreateSolver( - (OrtoolsUtils::solverMap.at(solverName)).MIPSolverName) - : MPSolver::CreateSolver( - (OrtoolsUtils::solverMap.at(solverName)).LPSolverName); - - mpSolver_ = std::unique_ptr(mpSolver); - objective_ = mpSolver->MutableObjective(); - - params_.SetIntegerParam(MPSolverParameters::SCALING, 0); - params_.SetIntegerParam(MPSolverParameters::PRESOLVE, 0); + mpSolver_ = MPSolverFactory(isMip, solverName); + objective_ = mpSolver_->MutableObjective(); } class ElemAlreadyExists: public std::exception @@ -172,6 +164,11 @@ bool OrtoolsLinearProblem::isMaximization() const return objective_->maximization(); } +MPSolver* OrtoolsLinearProblem::MpSolver() const +{ + return mpSolver_; +} + OrtoolsMipSolution* OrtoolsLinearProblem::solve(bool verboseSolver) { if (verboseSolver) @@ -185,4 +182,9 @@ OrtoolsMipSolution* OrtoolsLinearProblem::solve(bool verboseSolver) return solution_.get(); } +double OrtoolsLinearProblem::infinity() const +{ + return MPSolver::infinity(); +} + } // namespace Antares::Solver::Modeler::OrtoolsImpl diff --git a/src/solver/modeler/ortoolsImpl/mipSolution.cpp b/src/solver/modeler/ortoolsImpl/mipSolution.cpp index 8a04484522..8239f9893a 100644 --- a/src/solver/modeler/ortoolsImpl/mipSolution.cpp +++ b/src/solver/modeler/ortoolsImpl/mipSolution.cpp @@ -26,7 +26,7 @@ namespace Antares::Solver::Modeler::OrtoolsImpl { OrtoolsMipSolution::OrtoolsMipSolution(operations_research::MPSolver::ResultStatus& status, - std::shared_ptr solver): + operations_research::MPSolver* solver): status_(status), mpSolver_(solver) { diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index a0d74288e7..e2472febd1 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -4,11 +4,11 @@ set(RTESOLVER_OPT opt_gestion_second_membre_cas_lineaire.cpp opt_optimisation_lineaire.cpp opt_chainage_intercos.cpp - include/antares/solver/optimisation/opt_fonctions.h + include/antares/solver/optimisation/opt_fonctions.h opt_pilotage_optimisation_lineaire.cpp opt_pilotage_optimisation_quadratique.cpp - include/antares/solver/optimisation/opt_structure_probleme_a_resoudre.h - include/antares/solver/optimisation/opt_constants.h + include/antares/solver/optimisation/opt_structure_probleme_a_resoudre.h + include/antares/solver/optimisation/opt_constants.h opt_alloc_probleme_a_optimiser.cpp opt_gestion_des_bornes_cas_quadratique.cpp opt_construction_variables_optimisees_lineaire.cpp @@ -19,7 +19,7 @@ set(RTESOLVER_OPT opt_numero_de_jour_du_pas_de_temps.cpp opt_construction_variables_optimisees_quadratique.cpp opt_decompte_variables_et_contraintes.cpp - opt_decompte_variables_et_contraintes.cpp + opt_decompte_variables_et_contraintes.cpp opt_gestion_des_bornes_cas_lineaire.cpp opt_verification_presence_reserve_jmoins1.cpp opt_init_contraintes_hydrauliques.cpp @@ -27,7 +27,7 @@ set(RTESOLVER_OPT opt_liberation_problemes_simplexe.cpp opt_restaurer_les_donnees.cpp opt_gestion_des_couts_cas_quadratique.cpp - opt_gestion_des_couts_cas_quadratique.cpp + opt_gestion_des_couts_cas_quadratique.cpp opt_construction_variables_couts_demarrages.cpp opt_gestion_des_bornes_couts_demarrage.cpp opt_gestion_des_couts_couts_demarrage.cpp @@ -36,140 +36,143 @@ 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 - include/antares/solver/optimisation/opt_export_structure.h + include/antares/solver/optimisation/opt_export_structure.h opt_export_structure.cpp - include/antares/solver/optimisation/weekly_optimization.h + include/antares/solver/optimisation/weekly_optimization.h weekly_optimization.cpp - include/antares/solver/optimisation/optim_post_process_list.h + include/antares/solver/optimisation/optim_post_process_list.h optim_post_process_list.cpp - include/antares/solver/optimisation/post_process_commands.h + include/antares/solver/optimisation/post_process_commands.h post_process_commands.cpp - include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h - include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.h - include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h + include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h + include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.h + include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h adequacy_patch_csr/adq_patch_post_process_list.cpp adequacy_patch_csr/post_processing.cpp - include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.h + include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.h adequacy_patch_csr/adq_patch_curtailment_sharing.cpp adequacy_patch_csr/solve_problem.cpp adequacy_patch_csr/set_variable_boundaries.cpp adequacy_patch_csr/set_problem_cost_function.cpp adequacy_patch_csr/construct_problem_variables.cpp adequacy_patch_csr/construct_problem_constraints_RHS.cpp - include/antares/solver/optimisation/adequacy_patch_csr/csr_quadratic_problem.h + include/antares/solver/optimisation/adequacy_patch_csr/csr_quadratic_problem.h adequacy_patch_csr/csr_quadratic_problem.cpp - include/antares/solver/optimisation/adequacy_patch_csr/count_constraints_variables.h + include/antares/solver/optimisation/adequacy_patch_csr/count_constraints_variables.h adequacy_patch_csr/count_constraints_variables.cpp include/antares/solver/optimisation/adequacy_patch_csr/constraints/CsrFlowDissociation.h - adequacy_patch_csr/constraints/CsrFlowDissociation.cpp + adequacy_patch_csr/constraints/CsrFlowDissociation.cpp include/antares/solver/optimisation/adequacy_patch_csr/constraints/CsrAreaBalance.h - adequacy_patch_csr/constraints/CsrAreaBalance.cpp + adequacy_patch_csr/constraints/CsrAreaBalance.cpp include/antares/solver/optimisation/adequacy_patch_csr/constraints/CsrBindingConstraintHour.h - adequacy_patch_csr/constraints/CsrBindingConstraintHour.cpp + adequacy_patch_csr/constraints/CsrBindingConstraintHour.cpp - include/antares/solver/optimisation/opt_rename_problem.h + include/antares/solver/optimisation/opt_rename_problem.h opt_rename_problem.cpp constraints/ConstraintBuilder.cpp - include/antares/solver/optimisation/constraints/ConstraintBuilder.h + include/antares/solver/optimisation/constraints/ConstraintBuilder.h constraints/constraint_builder_utils.cpp include/antares/solver/optimisation/constraints/constraint_builder_utils.h include/antares/solver/optimisation/constraints/AreaBalance.h - constraints/AreaBalance.cpp - include/antares/solver/optimisation/constraints/FictitiousLoad.h - constraints/FictitiousLoad.cpp - include/antares/solver/optimisation/constraints/ShortTermStorageLevel.h - constraints/ShortTermStorageLevel.cpp - include/antares/solver/optimisation/constraints/FlowDissociation.h - constraints/FlowDissociation.cpp - include/antares/solver/optimisation/constraints/BindingConstraintHour.h - constraints/BindingConstraintHour.cpp - include/antares/solver/optimisation/constraints/BindingConstraintDay.h - constraints/BindingConstraintDay.cpp - include/antares/solver/optimisation/constraints/BindingConstraintWeek.h - constraints/BindingConstraintWeek.cpp - include/antares/solver/optimisation/constraints/HydroPower.h - constraints/HydroPower.cpp - include/antares/solver/optimisation/constraints/HydroPowerSmoothingUsingVariationSum.h - constraints/HydroPowerSmoothingUsingVariationSum.cpp - include/antares/solver/optimisation/constraints/HydroPowerSmoothingUsingVariationMaxDown.h - constraints/HydroPowerSmoothingUsingVariationMaxDown.cpp - include/antares/solver/optimisation/constraints/HydroPowerSmoothingUsingVariationMaxUp.h - constraints/HydroPowerSmoothingUsingVariationMaxUp.cpp - include/antares/solver/optimisation/constraints/MinHydroPower.h - constraints/MinHydroPower.cpp - include/antares/solver/optimisation/constraints/MaxHydroPower.h - constraints/MaxHydroPower.cpp - include/antares/solver/optimisation/constraints/MaxPumping.h - constraints/MaxPumping.cpp - include/antares/solver/optimisation/constraints/AreaHydroLevel.h - constraints/AreaHydroLevel.cpp - include/antares/solver/optimisation/constraints/FinalStockEquivalent.h - constraints/FinalStockEquivalent.cpp - include/antares/solver/optimisation/constraints/FinalStockExpression.h - constraints/FinalStockExpression.cpp - include/antares/solver/optimisation/constraints/PMaxDispatchableGeneration.h - constraints/PMaxDispatchableGeneration.cpp - include/antares/solver/optimisation/constraints/PMinDispatchableGeneration.h - constraints/PMinDispatchableGeneration.cpp - include/antares/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.h - constraints/ConsistenceNumberOfDispatchableUnits.cpp - include/antares/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.h - constraints/NbUnitsOutageLessThanNbUnitsStop.cpp - include/antares/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.h - constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp - include/antares/solver/optimisation/constraints/MinDownTime.h - constraints/MinDownTime.cpp + constraints/AreaBalance.cpp + include/antares/solver/optimisation/constraints/FictitiousLoad.h + constraints/FictitiousLoad.cpp + include/antares/solver/optimisation/constraints/ShortTermStorageLevel.h + constraints/ShortTermStorageLevel.cpp + include/antares/solver/optimisation/constraints/FlowDissociation.h + constraints/FlowDissociation.cpp + include/antares/solver/optimisation/constraints/BindingConstraintHour.h + constraints/BindingConstraintHour.cpp + include/antares/solver/optimisation/constraints/BindingConstraintDay.h + constraints/BindingConstraintDay.cpp + include/antares/solver/optimisation/constraints/BindingConstraintWeek.h + constraints/BindingConstraintWeek.cpp + include/antares/solver/optimisation/constraints/HydroPower.h + constraints/HydroPower.cpp + include/antares/solver/optimisation/constraints/HydroPowerSmoothingUsingVariationSum.h + constraints/HydroPowerSmoothingUsingVariationSum.cpp + include/antares/solver/optimisation/constraints/HydroPowerSmoothingUsingVariationMaxDown.h + constraints/HydroPowerSmoothingUsingVariationMaxDown.cpp + include/antares/solver/optimisation/constraints/HydroPowerSmoothingUsingVariationMaxUp.h + constraints/HydroPowerSmoothingUsingVariationMaxUp.cpp + include/antares/solver/optimisation/constraints/MinHydroPower.h + constraints/MinHydroPower.cpp + include/antares/solver/optimisation/constraints/MaxHydroPower.h + constraints/MaxHydroPower.cpp + include/antares/solver/optimisation/constraints/MaxPumping.h + constraints/MaxPumping.cpp + include/antares/solver/optimisation/constraints/AreaHydroLevel.h + constraints/AreaHydroLevel.cpp + include/antares/solver/optimisation/constraints/FinalStockEquivalent.h + constraints/FinalStockEquivalent.cpp + include/antares/solver/optimisation/constraints/FinalStockExpression.h + constraints/FinalStockExpression.cpp + include/antares/solver/optimisation/constraints/PMaxDispatchableGeneration.h + constraints/PMaxDispatchableGeneration.cpp + include/antares/solver/optimisation/constraints/PMinDispatchableGeneration.h + constraints/PMinDispatchableGeneration.cpp + include/antares/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.h + constraints/ConsistenceNumberOfDispatchableUnits.cpp + include/antares/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.h + constraints/NbUnitsOutageLessThanNbUnitsStop.cpp + include/antares/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.h + constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp + include/antares/solver/optimisation/constraints/MinDownTime.h + constraints/MinDownTime.cpp - include/antares/solver/optimisation/ProblemMatrixEssential.h - ProblemMatrixEssential.cpp - include/antares/solver/optimisation/LinearProblemMatrixStartUpCosts.h - LinearProblemMatrixStartUpCosts.cpp - include/antares/solver/optimisation/LinearProblemMatrix.h - LinearProblemMatrix.cpp - include/antares/solver/optimisation/QuadraticProblemMatrix.h - QuadraticProblemMatrix.cpp - include/antares/solver/optimisation/constraints/ConstraintGroup.h - include/antares/solver/optimisation/constraints/Group1.h - constraints/Group1.cpp - include/antares/solver/optimisation/constraints/BindingConstraintDayGroup.h - constraints/BindingConstraintDayGroup.cpp - include/antares/solver/optimisation/constraints/BindingConstraintWeekGroup.h - constraints/BindingConstraintWeekGroup.cpp - include/antares/solver/optimisation/constraints/HydroPowerGroup.h - constraints/HydroPowerGroup.cpp - include/antares/solver/optimisation/constraints/HydraulicSmoothingGroup.h - constraints/HydraulicSmoothingGroup.cpp - include/antares/solver/optimisation/constraints/MinMaxHydroPowerGroup.h - constraints/MinMaxHydroPowerGroup.cpp - include/antares/solver/optimisation/constraints/MaxPumpingGroup.h - constraints/MaxPumpingGroup.cpp - include/antares/solver/optimisation/constraints/AreaHydroLevelGroup.h - constraints/AreaHydroLevelGroup.cpp - include/antares/solver/optimisation/constraints/FinalStockGroup.h - constraints/FinalStockGroup.cpp - include/antares/solver/optimisation/constraints/AbstractStartUpCostsGroup.h - constraints/AbstractStartUpCostsGroup.cpp - include/antares/solver/optimisation/constraints/PMinMaxDispatchableGenerationGroup.h - constraints/PMinMaxDispatchableGenerationGroup.cpp - include/antares/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnitsGroup.h - constraints/ConsistenceNumberOfDispatchableUnitsGroup.cpp - include/antares/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStopGroup.h - constraints/NbUnitsOutageLessThanNbUnitsStopGroup.cpp - include/antares/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTimeGroup.h - constraints/NbDispUnitsMinBoundSinceMinUpTimeGroup.cpp - include/antares/solver/optimisation/constraints/MinDownTimeGroup.h - constraints/MinDownTimeGroup.cpp - include/antares/solver/optimisation/constraints/ExchangeBalance.h - constraints/ExchangeBalance.cpp - include/antares/solver/optimisation/constraints/ExchangeBalanceGroup.h - constraints/ExchangeBalanceGroup.cpp - variables/VariableManagement.h - variables/VariableManagement.cpp - variables/VariableManagerUtils.h - variables/VariableManagerUtils.cpp - include/antares/solver/optimisation/HebdoProblemToLpsTranslator.h - HebdoProblemToLpsTranslator.cpp + include/antares/solver/optimisation/ProblemMatrixEssential.h + ProblemMatrixEssential.cpp + include/antares/solver/optimisation/LinearProblemMatrixStartUpCosts.h + LinearProblemMatrixStartUpCosts.cpp + include/antares/solver/optimisation/LinearProblemMatrix.h + LinearProblemMatrix.cpp + include/antares/solver/optimisation/QuadraticProblemMatrix.h + QuadraticProblemMatrix.cpp + include/antares/solver/optimisation/constraints/ConstraintGroup.h + include/antares/solver/optimisation/constraints/Group1.h + constraints/Group1.cpp + include/antares/solver/optimisation/constraints/BindingConstraintDayGroup.h + constraints/BindingConstraintDayGroup.cpp + include/antares/solver/optimisation/constraints/BindingConstraintWeekGroup.h + constraints/BindingConstraintWeekGroup.cpp + include/antares/solver/optimisation/constraints/HydroPowerGroup.h + constraints/HydroPowerGroup.cpp + include/antares/solver/optimisation/constraints/HydraulicSmoothingGroup.h + constraints/HydraulicSmoothingGroup.cpp + include/antares/solver/optimisation/constraints/MinMaxHydroPowerGroup.h + constraints/MinMaxHydroPowerGroup.cpp + include/antares/solver/optimisation/constraints/MaxPumpingGroup.h + constraints/MaxPumpingGroup.cpp + include/antares/solver/optimisation/constraints/AreaHydroLevelGroup.h + constraints/AreaHydroLevelGroup.cpp + include/antares/solver/optimisation/constraints/FinalStockGroup.h + constraints/FinalStockGroup.cpp + include/antares/solver/optimisation/constraints/AbstractStartUpCostsGroup.h + constraints/AbstractStartUpCostsGroup.cpp + include/antares/solver/optimisation/constraints/PMinMaxDispatchableGenerationGroup.h + constraints/PMinMaxDispatchableGenerationGroup.cpp + include/antares/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnitsGroup.h + constraints/ConsistenceNumberOfDispatchableUnitsGroup.cpp + include/antares/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStopGroup.h + constraints/NbUnitsOutageLessThanNbUnitsStopGroup.cpp + include/antares/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTimeGroup.h + constraints/NbDispUnitsMinBoundSinceMinUpTimeGroup.cpp + include/antares/solver/optimisation/constraints/MinDownTimeGroup.h + constraints/MinDownTimeGroup.cpp + include/antares/solver/optimisation/constraints/ExchangeBalance.h + constraints/ExchangeBalance.cpp + include/antares/solver/optimisation/constraints/ExchangeBalanceGroup.h + constraints/ExchangeBalanceGroup.cpp + variables/VariableManagement.h + variables/VariableManagement.cpp + variables/VariableManagerUtils.h + variables/VariableManagerUtils.cpp + include/antares/solver/optimisation/HebdoProblemToLpsTranslator.h + HebdoProblemToLpsTranslator.cpp + include/antares/solver/optimisation/LegacyOrtoolsLinearProblem.h + include/antares/solver/optimisation/LegacyFiller.h + LegacyFiller.cpp ) @@ -187,15 +190,17 @@ else () #set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} /wd 4101") # unused local variable endif () target_link_libraries(model_antares - PUBLIC - Antares::solverUtils - sirius_solver - antares-solver-simulation - Antares::benchmarking + PUBLIC + Antares::solverUtils + sirius_solver + antares-solver-simulation + Antares::benchmarking Antares::optimization-options - Antares::lps - PRIVATE - infeasible_problem_analysis + Antares::lps + PRIVATE + infeasible_problem_analysis + Antares::modeler_api + Antares::modeler-ortools-impl ) target_include_directories(model_antares diff --git a/src/solver/optimisation/LegacyFiller.cpp b/src/solver/optimisation/LegacyFiller.cpp new file mode 100644 index 0000000000..7cbcaff820 --- /dev/null +++ b/src/solver/optimisation/LegacyFiller.cpp @@ -0,0 +1,110 @@ +#include "antares/solver/optimisation/LegacyFiller.h" + +using namespace Antares::Solver::Modeler::Api; + +namespace Antares::Optimization +{ + +LegacyFiller::LegacyFiller(const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe): + problemeSimplexe_(problemeSimplexe) +{ +} + +void LegacyFiller::addVariables(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) +{ + // Create the variables and set objective cost. + CopyVariables(pb); +} + +void LegacyFiller::addConstraints(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) +{ + // Create constraints and set coefs + CopyRows(pb); + CopyMatrix(pb); +} + +void LegacyFiller::addObjective(ILinearProblem& pb, LinearProblemData& data, FillContext& ctx) +{ + // nothing to do: objective coefficients are set along with variables definition +} + +void LegacyFiller::CopyMatrix(ILinearProblem& pb) const +{ + for (int idxRow = 0; idxRow < problemeSimplexe_->NombreDeContraintes; ++idxRow) + { + auto* ct = pb.getConstraint(GetConstraintName(idxRow)); + int debutLigne = problemeSimplexe_->IndicesDebutDeLigne[idxRow]; + for (int idxCoef = 0; idxCoef < problemeSimplexe_->NombreDeTermesDesLignes[idxRow]; + ++idxCoef) + { + int pos = debutLigne + idxCoef; + auto* var = pb.getVariable(GetVariableName(problemeSimplexe_->IndicesColonnes[pos])); + ct->setCoefficient(var, problemeSimplexe_->CoefficientsDeLaMatriceDesContraintes[pos]); + } + } +} + +void LegacyFiller::CreateVariable(unsigned idxVar, ILinearProblem& pb) const +{ + double min_l = problemeSimplexe_->Xmin[idxVar]; + double max_l = problemeSimplexe_->Xmax[idxVar]; + bool isIntegerVariable = problemeSimplexe_->IntegerVariable(idxVar); + auto* var = pb.addVariable(min_l, max_l, isIntegerVariable, GetVariableName(idxVar)); + pb.setObjectiveCoefficient(var, problemeSimplexe_->CoutLineaire[idxVar]); +} + +void LegacyFiller::CopyVariables(ILinearProblem& pb) const +{ + for (int idxVar = 0; idxVar < problemeSimplexe_->NombreDeVariables; ++idxVar) + { + CreateVariable(idxVar, pb); + } +} + +void LegacyFiller::UpdateContraints(unsigned idxRow, ILinearProblem& pb) const +{ + double bMin = -pb.infinity(), bMax = pb.infinity(); + switch (problemeSimplexe_->Sens[idxRow]) + { + case '=': + bMin = bMax = problemeSimplexe_->SecondMembre[idxRow]; + break; + case '<': + bMax = problemeSimplexe_->SecondMembre[idxRow]; + break; + case '>': + bMin = problemeSimplexe_->SecondMembre[idxRow]; + break; + } + + pb.addConstraint(bMin, bMax, GetConstraintName(idxRow)); +} + +void LegacyFiller::CopyRows(ILinearProblem& pb) const +{ + for (int idxRow = 0; idxRow < problemeSimplexe_->NombreDeContraintes; ++idxRow) + { + UpdateContraints(idxRow, pb); + } +} + +std::string LegacyFiller::GetVariableName(unsigned int index) const +{ + if (!problemeSimplexe_->UseNamedProblems() + || problemeSimplexe_->VariableNames().at(index).empty()) + { + return 'x' + std::to_string(index); + } + return problemeSimplexe_->VariableNames().at(index); +} + +std::string LegacyFiller::GetConstraintName(unsigned int index) const +{ + if (!problemeSimplexe_->UseNamedProblems() + || problemeSimplexe_->ConstraintNames().at(index).empty()) + { + return 'c' + std::to_string(index); + } + return problemeSimplexe_->ConstraintNames().at(index); +} +} // namespace Antares::Optimization diff --git a/src/solver/optimisation/include/antares/solver/optimisation/LegacyFiller.h b/src/solver/optimisation/include/antares/solver/optimisation/LegacyFiller.h new file mode 100644 index 0000000000..f682b3c16b --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/LegacyFiller.h @@ -0,0 +1,33 @@ +#pragma once + +#include "antares/solver/modeler/api/linearProblemFiller.h" +#include "antares/solver/utils/named_problem.h" + +namespace Antares::Optimization +{ +class LegacyFiller: public Antares::Solver::Modeler::Api::LinearProblemFiller +{ +public: + explicit LegacyFiller(const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe); + void addVariables(Antares::Solver::Modeler::Api::ILinearProblem& pb, + Antares::Solver::Modeler::Api::LinearProblemData& data, + Antares::Solver::Modeler::Api::FillContext& ctx) override; + void addConstraints(Antares::Solver::Modeler::Api::ILinearProblem& pb, + Antares::Solver::Modeler::Api::LinearProblemData& data, + Antares::Solver::Modeler::Api::FillContext& ctx) override; + void addObjective(Antares::Solver::Modeler::Api::ILinearProblem& pb, + Antares::Solver::Modeler::Api::LinearProblemData& data, + Antares::Solver::Modeler::Api::FillContext& ctx) override; + +private: + const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe_; + + void CreateVariable(unsigned idxVar, Antares::Solver::Modeler::Api::ILinearProblem& pb) const; + void CopyVariables(Antares::Solver::Modeler::Api::ILinearProblem& pb) const; + void UpdateContraints(unsigned idxRow, Antares::Solver::Modeler::Api::ILinearProblem& pb) const; + void CopyRows(Antares::Solver::Modeler::Api::ILinearProblem& pb) const; + void CopyMatrix(Antares::Solver::Modeler::Api::ILinearProblem& pb) const; + std::string GetVariableName(unsigned index) const; + std::string GetConstraintName(unsigned index) const; +}; +} // namespace Antares::Optimization diff --git a/src/solver/optimisation/include/antares/solver/optimisation/LegacyOrtoolsLinearProblem.h b/src/solver/optimisation/include/antares/solver/optimisation/LegacyOrtoolsLinearProblem.h new file mode 100644 index 0000000000..dfeda76bd9 --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/LegacyOrtoolsLinearProblem.h @@ -0,0 +1,45 @@ +/* + * 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 + +namespace Antares::Optimization +{ + +class LegacyOrtoolsLinearProblem final + : public Antares::Solver::Modeler::OrtoolsImpl::OrtoolsLinearProblem +{ +public: + LegacyOrtoolsLinearProblem(bool isMip, const std::string& solverName): + OrtoolsLinearProblem(isMip, solverName) + { + // nothing else to do + } + + operations_research::MPSolver* getMpSolver() + { + return MpSolver(); + } +}; + +} // namespace Antares::Optimization diff --git a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp index 94eae39fc8..4aee790ea9 100644 --- a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp +++ b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp @@ -27,12 +27,17 @@ #include #include "antares/optimization-options/options.h" #include "antares/solver/infeasible-problem-analysis/unfeasible-pb-analyzer.h" +#include "antares/solver/modeler/api/linearProblemBuilder.h" +#include "antares/solver/optimisation/LegacyFiller.h" +#include "antares/solver/optimisation/LegacyOrtoolsLinearProblem.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "antares/solver/utils/filename.h" #include "antares/solver/utils/mps_utils.h" using namespace operations_research; +using namespace Antares::Solver::Modeler::Api; +using namespace Antares::Solver::Modeler::OrtoolsImpl; using Antares::Solver::IResultWriter; using Antares::Solver::Optimization::OptimizationOptions; @@ -201,9 +206,18 @@ static SimplexResult OPT_TryToCallSimplex(const OptimizationOptions& options, Probleme.NombreDeContraintesCoupes = 0; - if (options.ortoolsUsed) + auto ortoolsProblem = std::make_unique(Probleme.isMIP(), + options.ortoolsSolver); + auto legacyOrtoolsFiller = std::make_unique(&Probleme); + std::vector fillersCollection = {legacyOrtoolsFiller.get()}; + LinearProblemData LP_Data; + FillContext fillCtx(0, 167); + LinearProblemBuilder linearProblemBuilder(fillersCollection); + + if (options.ortoolsUsed && solver == nullptr) { - solver = ORTOOLS_ConvertIfNeeded(options.ortoolsSolver, &Probleme, solver); + linearProblemBuilder.build(*ortoolsProblem, LP_Data, fillCtx); + solver = ortoolsProblem->getMpSolver(); } const std::string filename = createMPSfilename(optPeriodStringGenerator, optimizationNumber); @@ -370,8 +384,16 @@ bool OPT_AppelDuSimplexe(const OptimizationOptions& options, Probleme.SetUseNamedProblems(true); - auto MPproblem = std::shared_ptr( - ProblemSimplexeNommeConverter(options.ortoolsSolver, &Probleme).Convert()); + auto ortoolsProblem = std::make_unique(Probleme.isMIP(), + options.ortoolsSolver); + auto legacyOrtoolsFiller = std::make_unique(&Probleme); + std::vector fillersCollection = {legacyOrtoolsFiller.get()}; + LinearProblemData LP_Data; + FillContext fillCtx(0, 167); + LinearProblemBuilder linearProblemBuilder(fillersCollection); + + linearProblemBuilder.build(*ortoolsProblem, LP_Data, fillCtx); + auto MPproblem = std::shared_ptr(ortoolsProblem->getMpSolver()); auto analyzer = makeUnfeasiblePbAnalyzer(); analyzer->run(MPproblem.get()); diff --git a/src/solver/utils/include/antares/solver/utils/ortools_utils.h b/src/solver/utils/include/antares/solver/utils/ortools_utils.h index 3dd0970ecc..e5fae32c9d 100644 --- a/src/solver/utils/include/antares/solver/utils/ortools_utils.h +++ b/src/solver/utils/include/antares/solver/utils/ortools_utils.h @@ -58,8 +58,7 @@ std::string availableOrToolsSolversString(); * * \return MPSolver */ -MPSolver* MPSolverFactory(const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* probleme, - const std::string& solverName); +MPSolver* MPSolverFactory(const bool isMip, const std::string& solverName); std::string generateTempPath(const std::string& filename); void removeTemporaryFile(const std::string& tmpPath); @@ -73,61 +72,3 @@ class OrtoolsUtils }; static const std::map solverMap; }; - -namespace Antares -{ -namespace Optimization -{ - -class Nomenclature -{ -public: - Nomenclature() = delete; - - explicit Nomenclature(char prefix): - prefix_(prefix) - { - } - - void SetTarget(const std::vector& target) - { - target_ = ⌖ - } - - std::string GetName(unsigned index) const - { - if (target_ == nullptr || target_->at(index).empty()) - { - return prefix_ + std::to_string(index); - } - return target_->at(index); - } - -private: - const std::vector* target_ = nullptr; - char prefix_; -}; - -class ProblemSimplexeNommeConverter -{ -public: - explicit ProblemSimplexeNommeConverter( - const std::string& solverName, - const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe); - - MPSolver* Convert(); - -private: - const std::string& solverName_; - const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe_; - Nomenclature variableNameManager_ = Nomenclature('x'); - Nomenclature constraintNameManager_ = Nomenclature('c'); - - void CreateVariable(unsigned idxVar, MPSolver* solver, MPObjective* const objective) const; - void CopyVariables(MPSolver* solver) const; - void UpdateContraints(unsigned idxRow, MPSolver* solver) const; - void CopyRows(MPSolver* solver) const; - void CopyMatrix(const MPSolver* solver) const; -}; -} // namespace Optimization -} // namespace Antares diff --git a/src/solver/utils/include/antares/solver/utils/ortools_wrapper.h b/src/solver/utils/include/antares/solver/utils/ortools_wrapper.h index 4f688dda4a..886bd16950 100644 --- a/src/solver/utils/include/antares/solver/utils/ortools_wrapper.h +++ b/src/solver/utils/include/antares/solver/utils/ortools_wrapper.h @@ -34,10 +34,6 @@ MPSolver* ORTOOLS_Simplexe(Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* Probl bool keepBasis, const Antares::Solver::Optimization::OptimizationOptions& options); -MPSolver* ORTOOLS_ConvertIfNeeded(const std::string& solverName, - const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* Probleme, - MPSolver* solver); - void ORTOOLS_ModifierLeVecteurCouts(MPSolver* ProbSpx, const double* costs, int nbVar); void ORTOOLS_ModifierLeVecteurSecondMembre(MPSolver* ProbSpx, const double* rhs, diff --git a/src/solver/utils/ortools_utils.cpp b/src/solver/utils/ortools_utils.cpp index 2cc81b80fa..d45357f382 100644 --- a/src/solver/utils/ortools_utils.cpp +++ b/src/solver/utils/ortools_utils.cpp @@ -102,111 +102,6 @@ static bool solverSupportsWarmStart(const MPSolver::OptimizationProblemType solv } } -namespace Antares -{ -namespace Optimization -{ -ProblemSimplexeNommeConverter::ProblemSimplexeNommeConverter( - const std::string& solverName, - const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe): - solverName_(solverName), - problemeSimplexe_(problemeSimplexe) -{ - if (problemeSimplexe_->UseNamedProblems()) - { - variableNameManager_.SetTarget(problemeSimplexe_->VariableNames()); - constraintNameManager_.SetTarget(problemeSimplexe_->ConstraintNames()); - } -} - -MPSolver* ProblemSimplexeNommeConverter::Convert() -{ - MPSolver* solver = MPSolverFactory(problemeSimplexe_, solverName_); - - // Create the variables and set objective cost. - CopyVariables(solver); - - // Create constraints and set coefs - CopyRows(solver); - - CopyMatrix(solver); - - return solver; -} - -void ProblemSimplexeNommeConverter::CopyMatrix(const MPSolver* solver) const -{ - auto variables = solver->variables(); - auto constraints = solver->constraints(); - - for (int idxRow = 0; idxRow < problemeSimplexe_->NombreDeContraintes; ++idxRow) - { - MPConstraint* const ct = constraints[idxRow]; - int debutLigne = problemeSimplexe_->IndicesDebutDeLigne[idxRow]; - for (int idxCoef = 0; idxCoef < problemeSimplexe_->NombreDeTermesDesLignes[idxRow]; - ++idxCoef) - { - int pos = debutLigne + idxCoef; - ct->SetCoefficient(variables[problemeSimplexe_->IndicesColonnes[pos]], - problemeSimplexe_->CoefficientsDeLaMatriceDesContraintes[pos]); - } - } -} - -void ProblemSimplexeNommeConverter::CreateVariable(unsigned idxVar, - MPSolver* solver, - MPObjective* const objective) const -{ - double min_l = problemeSimplexe_->Xmin[idxVar]; - double max_l = problemeSimplexe_->Xmax[idxVar]; - bool isIntegerVariable = problemeSimplexe_->IntegerVariable(idxVar); - const MPVariable* var = solver->MakeVar(min_l, - max_l, - isIntegerVariable, - variableNameManager_.GetName(idxVar)); - objective->SetCoefficient(var, problemeSimplexe_->CoutLineaire[idxVar]); -} - -void ProblemSimplexeNommeConverter::CopyVariables(MPSolver* solver) const - -{ - MPObjective* const objective = solver->MutableObjective(); - for (int idxVar = 0; idxVar < problemeSimplexe_->NombreDeVariables; ++idxVar) - { - CreateVariable(idxVar, solver, objective); - } -} - -void ProblemSimplexeNommeConverter::UpdateContraints(unsigned idxRow, MPSolver* solver) const -{ - double bMin = -MPSolver::infinity(), bMax = MPSolver::infinity(); - if (problemeSimplexe_->Sens[idxRow] == '=') - { - bMin = bMax = problemeSimplexe_->SecondMembre[idxRow]; - } - else if (problemeSimplexe_->Sens[idxRow] == '<') - { - bMax = problemeSimplexe_->SecondMembre[idxRow]; - } - else if (problemeSimplexe_->Sens[idxRow] == '>') - { - bMin = problemeSimplexe_->SecondMembre[idxRow]; - } - - solver->MakeRowConstraint(bMin, bMax, constraintNameManager_.GetName(idxRow)); -} - -void ProblemSimplexeNommeConverter::CopyRows(MPSolver* solver) const -{ - for (int idxRow = 0; idxRow < problemeSimplexe_->NombreDeContraintes; ++idxRow) - { - UpdateContraints(idxRow, solver); - } -} - -} // namespace Optimization -} // namespace Antares - static void extractSolutionValues(const std::vector& variables, Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe) { @@ -329,21 +224,6 @@ bool solveAndManageStatus(MPSolver* solver, int& resultStatus, const MPSolverPar return resultStatus == OUI_SPX; } -MPSolver* ORTOOLS_ConvertIfNeeded(const std::string& solverName, - const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* Probleme, - MPSolver* solver) -{ - if (solver == nullptr) - { - Antares::Optimization::ProblemSimplexeNommeConverter converter(solverName, Probleme); - return converter.Convert(); - } - else - { - return solver; - } -} - MPSolver* ORTOOLS_Simplexe(Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* Probleme, MPSolver* solver, bool keepBasis, @@ -474,13 +354,12 @@ std::string availableOrToolsSolversString() return solvers.str(); } -MPSolver* MPSolverFactory(const Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* probleme, - const std::string& solverName) +MPSolver* MPSolverFactory(const bool isMip, const std::string& solverName) { MPSolver* solver; try { - if (probleme->isMIP()) + if (isMip) { solver = MPSolver::CreateSolver((OrtoolsUtils::solverMap.at(solverName)).MIPSolverName); } diff --git a/src/tests/run-study-tests/check_on_results/compare_mps_files.py b/src/tests/run-study-tests/check_on_results/compare_mps_files.py index 152aaa7a80..76cf96c333 100644 --- a/src/tests/run-study-tests/check_on_results/compare_mps_files.py +++ b/src/tests/run-study-tests/check_on_results/compare_mps_files.py @@ -26,10 +26,10 @@ def run(self): self.find_folders_to_compare() ref_mps_files = list(self.ref_folder.glob('*.mps')) - assert ref_mps_files + assert ref_mps_files, "Couldn't find reference MPS files" mps_files = list(self.dated_output_folder.glob('**/*.mps')) - assert mps_files + assert mps_files, "Couldn't find actual output MPS files" list_of_pairs = [(mps_ref, mps) for mps_ref in ref_mps_files for mps in mps_files if mps_ref.name == mps.name] for pair in list_of_pairs: From 97e7b5d3eb95cdf48e20ef31d647e8457bdf471b Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Tue, 29 Oct 2024 11:10:05 +0100 Subject: [PATCH 041/103] Allow extension of cucumber features and steps (#2467) --- .github/workflows/cucumber-tests/action.yml | 2 +- src/tests/cucumber/CMakeLists.txt | 7 ++++- src/tests/cucumber/features/environment.py | 10 +++++++ src/tests/cucumber/features/steps/__init__.py | 8 +++++ .../steps/{ => common_steps}/assertions.py | 0 .../{ => common_steps}/simulator_utils.py | 24 ++++++--------- .../steps/{ => common_steps}/steps.py | 8 ++--- .../{ => common_steps}/study_input_handler.py | 0 .../study_output_handler.py | 0 .../cucumber/features/steps/import_helper.py | 30 +++++++++++++++++++ 10 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 src/tests/cucumber/features/environment.py create mode 100644 src/tests/cucumber/features/steps/__init__.py rename src/tests/cucumber/features/steps/{ => common_steps}/assertions.py (100%) rename src/tests/cucumber/features/steps/{ => common_steps}/simulator_utils.py (73%) rename src/tests/cucumber/features/steps/{ => common_steps}/steps.py (95%) rename src/tests/cucumber/features/steps/{ => common_steps}/study_input_handler.py (100%) rename src/tests/cucumber/features/steps/{ => common_steps}/study_output_handler.py (100%) create mode 100644 src/tests/cucumber/features/steps/import_helper.py diff --git a/.github/workflows/cucumber-tests/action.yml b/.github/workflows/cucumber-tests/action.yml index 475d3310b3..f927c9456a 100644 --- a/.github/workflows/cucumber-tests/action.yml +++ b/.github/workflows/cucumber-tests/action.yml @@ -20,4 +20,4 @@ runs: shell: bash run: | cd src/tests/cucumber - behave --tags ${{ inputs.tags }} ${{ inputs.feature }} + behave --tags ${{ inputs.tags }} ${{ inputs.feature }} --define use-ortools=false diff --git a/src/tests/cucumber/CMakeLists.txt b/src/tests/cucumber/CMakeLists.txt index cf22c8415b..ed6aabe4f6 100644 --- a/src/tests/cucumber/CMakeLists.txt +++ b/src/tests/cucumber/CMakeLists.txt @@ -1,2 +1,7 @@ -file(GENERATE OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/conf.yaml CONTENT "antares-solver : $" +file(GENERATE OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/behave.ini CONTENT + "[behave.userdata]\ +\n\ +antares-solver = $\ +\n\ +resources-path = ${CMAKE_SOURCE_DIR}/tests/resources/Antares_Simulator_Tests_NR" CONDITION $,${CMAKE_BUILD_TYPE}>) \ No newline at end of file diff --git a/src/tests/cucumber/features/environment.py b/src/tests/cucumber/features/environment.py new file mode 100644 index 0000000000..ea12cf495e --- /dev/null +++ b/src/tests/cucumber/features/environment.py @@ -0,0 +1,10 @@ +# This file defines behave hooks to run before all tests + +def before_all(context): + check_userdata_exists(context, "antares-solver") + check_userdata_exists(context, "resources-path") + +def check_userdata_exists(context, data_name: str): + if data_name not in context.config.userdata: + raise Exception( + f"The following parameter should be defined in 'behave.ini' or in the command line when calling behave: {data_name}") diff --git a/src/tests/cucumber/features/steps/__init__.py b/src/tests/cucumber/features/steps/__init__.py new file mode 100644 index 0000000000..ed21b90fea --- /dev/null +++ b/src/tests/cucumber/features/steps/__init__.py @@ -0,0 +1,8 @@ +from import_helper import import_steps +from pathlib import Path + +STEPS_DIR_NAME = "steps" +STEPS_DIR = Path(__file__).parent +assert STEPS_DIR.name == STEPS_DIR_NAME + +import_steps(STEPS_DIR) diff --git a/src/tests/cucumber/features/steps/assertions.py b/src/tests/cucumber/features/steps/common_steps/assertions.py similarity index 100% rename from src/tests/cucumber/features/steps/assertions.py rename to src/tests/cucumber/features/steps/common_steps/assertions.py diff --git a/src/tests/cucumber/features/steps/simulator_utils.py b/src/tests/cucumber/features/steps/common_steps/simulator_utils.py similarity index 73% rename from src/tests/cucumber/features/steps/simulator_utils.py rename to src/tests/cucumber/features/steps/common_steps/simulator_utils.py index 68f48df180..6f6349f773 100644 --- a/src/tests/cucumber/features/steps/simulator_utils.py +++ b/src/tests/cucumber/features/steps/common_steps/simulator_utils.py @@ -1,19 +1,9 @@ # Methods to run Antares simulator import subprocess -import yaml from pathlib import Path -from study_input_handler import study_input_handler -from study_output_handler import study_output_handler - - -def get_solver_path(): - with open("conf.yaml") as file: - content = yaml.full_load(file) - return content.get("antares-solver") - - -SOLVER_PATH = get_solver_path() # we only need to run this once +from common_steps.study_input_handler import study_input_handler +from common_steps.study_output_handler import study_output_handler def run_simulation(context): @@ -37,10 +27,14 @@ def init_simu(context): def build_antares_solver_command(context): - command = [SOLVER_PATH, "-i", str(context.study_path)] - if context.use_ortools: + command = [context.config.userdata["antares-solver"], "-i", str(context.study_path)] + if "use-ortools" in context.config.userdata and context.config.userdata["use-ortools"].lower() == 'true': command.append('--use-ortools') - command.append('--ortools-solver=' + context.ortools_solver) + if "ortools-solver" in context.config.userdata: + solver = context.config.userdata["ortools-solver"] + else: + solver = "sirius" + command.append('--ortools-solver=' + solver) if context.named_mps_problems: command.append('--named-mps-problems') if context.parallel: diff --git a/src/tests/cucumber/features/steps/steps.py b/src/tests/cucumber/features/steps/common_steps/steps.py similarity index 95% rename from src/tests/cucumber/features/steps/steps.py rename to src/tests/cucumber/features/steps/common_steps/steps.py index ef9ede4c2b..d3d44d0471 100644 --- a/src/tests/cucumber/features/steps/steps.py +++ b/src/tests/cucumber/features/steps/common_steps/steps.py @@ -5,19 +5,17 @@ from behave import * -from assertions import * -from simulator_utils import * +from common_steps.assertions import * +from common_steps.simulator_utils import * @given('the study path is "{string}"') def study_path_is(context, string): - context.study_path = os.path.join("..", "resources", "Antares_Simulator_Tests_NR", string.replace("/", os.sep)) + context.study_path = os.path.join(context.config.userdata["resources-path"], string.replace("/", os.sep)) @when('I run antares simulator') def run_antares(context): - context.use_ortools = True - context.ortools_solver = "sirius" context.named_mps_problems = False context.parallel = False run_simulation(context) diff --git a/src/tests/cucumber/features/steps/study_input_handler.py b/src/tests/cucumber/features/steps/common_steps/study_input_handler.py similarity index 100% rename from src/tests/cucumber/features/steps/study_input_handler.py rename to src/tests/cucumber/features/steps/common_steps/study_input_handler.py diff --git a/src/tests/cucumber/features/steps/study_output_handler.py b/src/tests/cucumber/features/steps/common_steps/study_output_handler.py similarity index 100% rename from src/tests/cucumber/features/steps/study_output_handler.py rename to src/tests/cucumber/features/steps/common_steps/study_output_handler.py diff --git a/src/tests/cucumber/features/steps/import_helper.py b/src/tests/cucumber/features/steps/import_helper.py new file mode 100644 index 0000000000..454b50f979 --- /dev/null +++ b/src/tests/cucumber/features/steps/import_helper.py @@ -0,0 +1,30 @@ +from importlib import import_module +from pkgutil import iter_modules +from os import walk +from pathlib import Path + +import os + + +def import_steps(steps_dir: Path): + assert steps_dir.exists() + + for (directory, _, _) in walk(steps_dir, followlinks=True): + if "__pycache__" in directory: + continue + + if directory == str(steps_dir): + continue + + current_directory = directory + os.sep + print(f"Importing Additional Steps: {current_directory}") + + all_modules = [ + module_info[1] + for module_info in iter_modules(path=[str(current_directory)]) + ] + current_directory = current_directory.replace(str(steps_dir) + os.sep, "") + + for module in all_modules: + module_path = current_directory.replace(os.sep, ".") + module + import_module(module_path) From 4128112e13488ef3d2121a1270700ed4fd648870 Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Wed, 30 Oct 2024 13:44:53 +0100 Subject: [PATCH 042/103] Fix User guide PDF generation (#2476) Make PR action fail if PDF generation fails --- docs/pdf-doc-generation-with-sphinx/create_pdf_doc.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pdf-doc-generation-with-sphinx/create_pdf_doc.sh b/docs/pdf-doc-generation-with-sphinx/create_pdf_doc.sh index a3f8a51f10..95af78b054 100644 --- a/docs/pdf-doc-generation-with-sphinx/create_pdf_doc.sh +++ b/docs/pdf-doc-generation-with-sphinx/create_pdf_doc.sh @@ -1,4 +1,6 @@ #!/bin/bash +# exit script if any subcommand fails +set -e # copy reference guide md files and assets cp -r ../user-guide source/ cp -r ../assets/ source/ From 94703f4e7d0355ccaecc6f2053a94062439f7ebd Mon Sep 17 00:00:00 2001 From: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:24:32 +0100 Subject: [PATCH 043/103] Fix study not found on windows when using simulator API (#2481) Fix an issue when using simulator API on windows where windows path with drive letter were unsuported --- .../antares/file-tree-study-loader/FileTreeStudyLoader.cpp | 7 ++----- .../antares/file-tree-study-loader/FileTreeStudyLoader.h | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libs/antares/file-tree-study-loader/FileTreeStudyLoader.cpp b/src/libs/antares/file-tree-study-loader/FileTreeStudyLoader.cpp index 92b8691d83..9dd0b722cb 100644 --- a/src/libs/antares/file-tree-study-loader/FileTreeStudyLoader.cpp +++ b/src/libs/antares/file-tree-study-loader/FileTreeStudyLoader.cpp @@ -29,7 +29,7 @@ namespace Antares { FileTreeStudyLoader::FileTreeStudyLoader(std::filesystem::path study_path): - study_path_{std::move(study_path)} + study_path_{std::move(study_path.string())} { } @@ -38,10 +38,7 @@ std::unique_ptr FileTreeStudyLoader::load() const using namespace std::literals::string_literals; Antares::Solver::Application application; constexpr unsigned int argc = 3; - // On Windows, std::filesystem::path::value_type is wchar_t - std::array argv{"", - reinterpret_cast(study_path_.c_str()), - "--parallel"}; + std::array argv{"", study_path_.c_str(), "--parallel"}; application.prepare(argc, argv.data()); return application.acquireStudy(); diff --git a/src/libs/antares/file-tree-study-loader/include/antares/file-tree-study-loader/FileTreeStudyLoader.h b/src/libs/antares/file-tree-study-loader/include/antares/file-tree-study-loader/FileTreeStudyLoader.h index 7b46a95c3a..fc207c1a4c 100644 --- a/src/libs/antares/file-tree-study-loader/include/antares/file-tree-study-loader/FileTreeStudyLoader.h +++ b/src/libs/antares/file-tree-study-loader/include/antares/file-tree-study-loader/FileTreeStudyLoader.h @@ -58,6 +58,6 @@ class FileTreeStudyLoader: public IStudyLoader [[nodiscard]] std::unique_ptr load() const override; private: - std::filesystem::path study_path_; + std::string study_path_; }; } // namespace Antares From 39708a6fca34bd4137344d98a56daf1d123ba34e Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:38:43 +0100 Subject: [PATCH 044/103] Don't apply reverse spinning if the cluster is no force gen [ANT-2293] (#2469) #2468 --- .../antares/study/parts/thermal/cluster.cpp | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index 7467238a7e..85abd8090a 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -403,22 +403,29 @@ void Data::ThermalCluster::reverseCalculationOfSpinning() { // Nothing to do if the spinning is equal to zero // because it will the same multiply all entries of the matrix by 1. - if (!Utils::isZero(spinning)) + if (Utils::isZero(spinning)) { - logs.debug() << " Calculation of spinning (reverse)... " << parentArea->name - << "::" << pName; - - auto& ts = series.timeSeries; - // The formula - // const double s = 1. - cluster.spinning / 100.; + return; + } - // All values in the matrix will be multiply by this coeff - // It is no really useful to test if the result of the formula - // is equal to zero, since the method `Matrix::multiplyAllValuesBy()` - // already does this test. - ts.multiplyAllEntriesBy(1. / (1. - (spinning / 100.))); - ts.roundAllEntries(); + // No ts have been generated, no need to save them into input or it will apply spinning twice + if (tsGenBehavior == LocalTSGenerationBehavior::forceNoGen) + { + return; } + + logs.debug() << " Calculation of spinning (reverse)... " << parentArea->name << "::" << pName; + + auto& ts = series.timeSeries; + // The formula + // const double s = 1. - cluster.spinning / 100.; + + // All values in the matrix will be multiply by this coeff + // It is no really useful to test if the result of the formula + // is equal to zero, since the method `Matrix::multiplyAllValuesBy()` + // already does this test. + ts.multiplyAllEntriesBy(1. / (1. - (spinning / 100.))); + ts.roundAllEntries(); } void Data::ThermalCluster::reset() From 2f4896e5016e70120adba1f6594fcc2b5ca71022 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Mon, 4 Nov 2024 17:15:26 +0100 Subject: [PATCH 045/103] Fix path for ts-numbers in output dir (#2484) --- src/libs/antares/study/parts/common/cluster_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index 0feee3a77f..b9afbaff2f 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -96,7 +96,7 @@ void ClusterList::storeTimeseriesNumbers(Solver::IResultWriter& writer for (auto& cluster: each_enabled()) { - fs::path path = fs::path(cluster->parentArea->id.c_str()) + fs::path path = basePath / cluster->parentArea->id.c_str() / std::string(cluster->id() + ".txt"); ts_content.clear(); // We must clear ts_content here, since saveToBuffer does not do it. From dd894c9023b489e3e284078174db524147f7ba25 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Thu, 7 Nov 2024 11:40:25 +0100 Subject: [PATCH 046/103] Remove unused function in opt (#2485) --- .../antares/solver/optimisation/opt_fonctions.h | 1 - .../opt_alloc_probleme_a_optimiser.cpp | 17 ----------------- 2 files changed, 18 deletions(-) diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h index f215ae5dd1..18551a08b5 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h @@ -99,7 +99,6 @@ void OPT_AllocateFromNumberOfVariableConstraints(PROBLEME_ANTARES_A_RESOUDRE* Pr int); void OPT_AllocDuProblemeAOptimiser(PROBLEME_HEBDO*); int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO*); -void OPT_AugmenterLaTailleDeLaMatriceDesContraintes(PROBLEME_ANTARES_A_RESOUDRE*); /*------------------------------*/ diff --git a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp index 20b448bde7..a9906ff21f 100644 --- a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp +++ b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp @@ -144,20 +144,3 @@ void OPT_AllocDuProblemeAOptimiser(PROBLEME_HEBDO* problemeHebdo) optimisationAllocateProblem(problemeHebdo, mxPaliers); } - -void OPT_AugmenterLaTailleDeLaMatriceDesContraintes(PROBLEME_ANTARES_A_RESOUDRE* ProblemeAResoudre) -{ - int NbTermes = ProblemeAResoudre->NombreDeTermesAllouesDansLaMatriceDesContraintes; - NbTermes += ProblemeAResoudre->IncrementDAllocationMatriceDesContraintes; - - logs.info(); - logs.info() << " Expected Number of Non-zero terms in Problem Matrix : increased to : " - << NbTermes; - logs.info(); - - ProblemeAResoudre->CoefficientsDeLaMatriceDesContraintes.resize(NbTermes); - - ProblemeAResoudre->IndicesColonnes.resize(NbTermes); - - ProblemeAResoudre->NombreDeTermesAllouesDansLaMatriceDesContraintes = NbTermes; -} From 3336eaf13ae2a92e84cf9755e44cb823ba9f0023 Mon Sep 17 00:00:00 2001 From: Juliette-Gerbaux <130555142+Juliette-Gerbaux@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:09:19 +0100 Subject: [PATCH 047/103] Fix documentation for hydro heuristic (#2488) Co-authored-by: Juliette-Gerbaux --- docs/user-guide/solver/06-hydro-heuristics.md | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/docs/user-guide/solver/06-hydro-heuristics.md b/docs/user-guide/solver/06-hydro-heuristics.md index 78ff065933..9a684926d9 100644 --- a/docs/user-guide/solver/06-hydro-heuristics.md +++ b/docs/user-guide/solver/06-hydro-heuristics.md @@ -33,7 +33,7 @@ not be confused with those of the document "optimization problem formulation" The hydro storage energy monthly and weekly profiles of each zone $z$ do not depend at all on the local demand and must-run generation in $z$ - $L_{z.}^+$ Time-series of "net" load for zone $z$, defined as: $L{z.}^+ = L{z.} - M{z.}$ -- $L_{z.}$ Time-series of "weighted" load for zone $z$, defined as:_ $L_{z.} = A^t L_{z.}^+$ +- $L_{z.}$ Time-series of "weighted" load for zone $z$, defined as: $L_{z.} = A^t L_{z.}^+$ All following parameters are related to the generic zone $z$: @@ -47,9 +47,9 @@ not be confused with those of the document "optimization problem formulation" - $S$ Reservoir size -- $\overline{S_d}$ Reservoir maximum level at the end of day d, expressed as a fraction of $S$ (rule curve) +- $\overline{S_d}$ Reservoir maximum level at the end of day d (rule curve) -- $\underline{S_d}$ Reservoir minimum level at the end of day d, expressed as a fraction of $S$ (rule curve) +- $\underline{S_d}$ Reservoir minimum level at the end of day d (rule curve) - $S_0$ Reservoir initial level at the beginning of the first day of the "hydro-year" @@ -72,18 +72,18 @@ not be confused with those of the document "optimization problem formulation" - $W_m^k$ Energy to generate on month m, at the end of stage k of pre-allocation -Following variables and parameters are local to linear optimization problems $M$ & $D(Tm)$ +Following variables and parameters are local to linear optimization problems $M$ & $D(m)$ solved within the heuristic. For the sake of clarity, the same generic index is used for all time steps, -knowing that in $M$ there are 12 monthly time-steps, while in $D(m)t$ there are from 28 to 31 daily +knowing that in $M$ there are 12 monthly time-steps, while in $D(m)$ there are from 28 to 31 daily time-steps. Costs $\gamma_{Var}$ given to these variables are chosen to enforce a logical hierarchy of penalties (letting the reservoir overflow is worse than violating rule curves, which is worse than deviating from the generation objective assessed in stage 1, etc.) -- $Y$ Generation deficit at the end of the period, as compared to the objective aimed at +- $W$ Generation deficit at the end of the period, as compared to the objective aimed at (positive variable) -- $O_t$ Overflow from the reservoir on time step $t$ +- $O_t$ Overflow from the reservoir on time step $t$ (positive variable) -- $G_t, \overline{G_t}$ Optimal generation and maximum generation on time step $t$ +- $G_t, \overline{G_t}, \underline{G_t}$ Optimal generation, maximum and minimum generation on time step $t$ - $T_t$ Generation objective assessed in the first stage, for time step t ( $W_m^1$ or $W_d^1$) @@ -95,9 +95,9 @@ from the generation objective assessed in stage 1, etc.) - $\Delta$ Maximum deviation throughout the period -- $V_t^+$ Amplitude of the violation of the upper rule curve at time step $t$ +- $V_t^+$ Amplitude of the violation of the upper rule curve at time step $t$ (positive variable) -- $V_t^-$ Amplitude of the violation of the lower rule curve at time step $t$ +- $V_t^-$ Amplitude of the violation of the lower rule curve at time step $t$ (positive variable) - $Y$ Maximum violation of lower rule curve throughout the period @@ -117,17 +117,20 @@ $$else: \text{for } m\in [1, 12]: \{W_m^1 \leftarrow I_m\}$$ _M2:_ -$$\text{for } m\in [1, 12]: W_m^2 \leftarrow \text{Solution of linear problem M}$$ +$$if (\mu) : \text{for } m\in [1, 12]: W_m^2 \leftarrow \text{Solution of linear problem M}$$ + +$$else : W_m^2 \leftarrow W_m^1$$ _D1:_ $$if (j): \text{for } d\in [1, 31]: W_d^1 \leftarrow \frac{L_d^{\beta}. (W_m^2)}{(\sum_{d\in m}{L_d^{\beta}})}$$ -$$else: \text{for } d\in [1, 31]: W_d^1 \leftarrow \frac{I_d . (W_m^2)} {(\sum_{d\in m}{I_d})}$$ +$$else: \text{for } d\in [1, 31]: W_d^1 \leftarrow I_d $$ _D2:_ -$$\text{for } m \in [1, 12]: W_{d\in m}^2 \leftarrow \text{Solution of linear problem D(m)}$$ +$$if(\mu) : \text{for } m \in [1, 12]: W_{d\in m}^2 \leftarrow \text{Solution of linear problem D(m)}$$ +$ else : \text{for } m \in [1, 12]: W_{d\in m}^2 \leftarrow$ Solution of a simplified version of linear problem $D(m)$ without reservoir levels _End_ @@ -146,9 +149,9 @@ $$S_t \geq 0$$ $$S_t \leq S$$ -$S_t + G_t - S_{t-1} = I_t$ (see note [^monthly_allocation]) +$G_t \geq \underline{G_t} $ and $G_t \leq \overline{G_t} $ -$$\sum_{t}{G_t} = \sum_{t}{T_t}$$ +For $t\in [1,12], S_{t} + G_{t} - S_{t-1} = I_{t}$ (see note [^monthly_allocation]) and $S_{12} = S_{0}.$ $$G_t - D_t \leq T_t$$ @@ -160,27 +163,28 @@ $$V_t^+ - S_t \geq -\overline{S_t}$$ $$Y - V_t^- \geq 0$$ +$$\Delta - D_t \geq 0$$ **Optimization problems $D(m)$** -$$\min_{G_t, S_t, ...}{\gamma_{\Delta}\Delta + \gamma_Y Y + \sum_{t}{(\gamma_D D_t + \gamma_{V-} V_t^- + \gamma_{O} O_t + \gamma_S S_t)}}$$ +$$\min_{G_t, S_t, ...}{\gamma_{\Delta}\Delta + \gamma_Y Y + \gamma_{W}W+ \sum_{t}{(\gamma_D D_t + \gamma_{V-} V_t^- + \gamma_{O} O_t + \gamma_S S_t)}}$$ s.t $$S_t \geq 0$$ $$S_t \leq S$$ -$$G_t \geq 0$$ +$$G_t \geq \underline{G_t}$$ $$G_t \leq \overline{G_t}$$ -$S_t + G_t + O_t - S_{t-1} = I_t$ (see note [^daily_allocation]) +$S_t + G_t + O_t - S_{t-1} = I_t$ (see note [^daily_allocation]) (initial level of the period is either $S_0$ if $m=1$ or the final level found in solving $D(m-1)$) -$\sum_{t}{G_t + Y} = \sum_{t}{T_t} + Y_{m-1}$ (value of Y previously found in solving **$D(m-1)$**) +$\sum_{t}{G_t + W} = \sum_{t}{T_t} + W_{m-1}$ (0 if $m=1$ else value of $W$ previously found in solving **$D(m-1)$**) -$$G_t - D_t \leq T_t$$ +$$G_t - D_t \leq T_t + \frac{W_{m-1}}{|d \in m|}$$ -$$G_t + D_t \geq T_t$$ +$$G_t + D_t \geq T_t + \frac{W_{m-1}}{|d \in m|}$$ $$\Delta - D_t \geq 0$$ From 5e170656b567bf6acb575c7abeaa882b344d7134 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Tue, 12 Nov 2024 15:18:00 +0100 Subject: [PATCH 048/103] Few improvements to solver specific options handling (#2487) Following comments left here #2466 --- src/libs/antares/checks/checkLoadedInputData.cpp | 6 +++--- .../include/antares/checks/checkLoadedInputData.h | 6 +++--- src/libs/antares/exception/CMakeLists.txt | 2 +- src/libs/antares/exception/LoadingError.cpp | 13 ++++++------- src/solver/application/application.cpp | 6 +++--- src/solver/misc/options.cpp | 2 +- src/tools/batchrun/main.cpp | 9 +-------- 7 files changed, 18 insertions(+), 26 deletions(-) diff --git a/src/libs/antares/checks/checkLoadedInputData.cpp b/src/libs/antares/checks/checkLoadedInputData.cpp index b62408b050..e7ae0d1238 100644 --- a/src/libs/antares/checks/checkLoadedInputData.cpp +++ b/src/libs/antares/checks/checkLoadedInputData.cpp @@ -29,9 +29,9 @@ namespace Antares::Check { -void checkOrtoolsUsage(Antares::Data::UnitCommitmentMode ucMode, - bool ortoolsUsed, - const std::string& solverName) +void checkSolverMILPincompatibility(Antares::Data::UnitCommitmentMode ucMode, + bool ortoolsUsed, + const std::string& solverName) { using namespace Antares::Data; if (ucMode == UnitCommitmentMode::ucMILP) diff --git a/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h b/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h index 62352390bc..6a82fb4986 100644 --- a/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h +++ b/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h @@ -24,9 +24,9 @@ namespace Antares::Check { -void checkOrtoolsUsage(Antares::Data::UnitCommitmentMode ucMode, - bool ortoolsUsed, - const std::string& solverName); +void checkSolverMILPincompatibility(Antares::Data::UnitCommitmentMode ucMode, + bool ortoolsUsed, + const std::string& solverName); void checkStudyVersion(const AnyString& optStudyFolder); diff --git a/src/libs/antares/exception/CMakeLists.txt b/src/libs/antares/exception/CMakeLists.txt index 691967b267..41bf90c93f 100644 --- a/src/libs/antares/exception/CMakeLists.txt +++ b/src/libs/antares/exception/CMakeLists.txt @@ -28,4 +28,4 @@ target_include_directories(${PROJ} install(DIRECTORY include/antares DESTINATION "include" -) \ No newline at end of file +) diff --git a/src/libs/antares/exception/LoadingError.cpp b/src/libs/antares/exception/LoadingError.cpp index 4a80591bef..cea447153e 100644 --- a/src/libs/antares/exception/LoadingError.cpp +++ b/src/libs/antares/exception/LoadingError.cpp @@ -81,19 +81,18 @@ InvalidSolver::InvalidSolver(const std::string& solver, const std::string& avail { } -static std::string InvalidSolverSpecificParametersHelper(const std::string& solver, - const std::string& specificParameters) +static std::string InvalidSolverParameterMessage(const std::string& solver, + const std::string& parameters) { std::ostringstream message; - message << "Specific parameters '" << specificParameters + message << "Specific parameters '" << parameters << "' are not valid or not supported for solver " << solver; return message.str(); } -InvalidSolverSpecificParameters::InvalidSolverSpecificParameters( - const std::string& solver, - const std::string& specificParameters): - LoadingError(InvalidSolverSpecificParametersHelper(solver, specificParameters)) +InvalidSolverSpecificParameters::InvalidSolverSpecificParameters(const std::string& solver, + const std::string& parameters): + LoadingError(InvalidSolverParameterMessage(solver, parameters)) { } diff --git a/src/solver/application/application.cpp b/src/solver/application/application.cpp index 335a6a2c98..6a51546304 100644 --- a/src/solver/application/application.cpp +++ b/src/solver/application/application.cpp @@ -277,9 +277,9 @@ void Application::startSimulation(Data::StudyLoadOptions& options) void Application::postParametersChecks() const { // Some more checks require the existence of pParameters, hence of a study. // Their execution is delayed up to this point. - checkOrtoolsUsage(pParameters->unitCommitment.ucMode, - pParameters->optOptions.ortoolsUsed, - pParameters->optOptions.ortoolsSolver); + checkSolverMILPincompatibility(pParameters->unitCommitment.ucMode, + pParameters->optOptions.ortoolsUsed, + pParameters->optOptions.ortoolsSolver); checkSimplexRangeHydroPricing(pParameters->simplexOptimizationRange, pParameters->hydroPricing.hpMode); diff --git a/src/solver/misc/options.cpp b/src/solver/misc/options.cpp index 960b0dda6c..dba4f2230a 100644 --- a/src/solver/misc/options.cpp +++ b/src/solver/misc/options.cpp @@ -272,7 +272,7 @@ void checkOrtoolsSolver(const Antares::Solver::Optimization::OptimizationOptions const std::list availableSolverList = getAvailableOrtoolsSolverName(); // Check if solver is available - bool found = (std::find(availableSolverList.begin(), availableSolverList.end(), solverName) + bool found = (std::ranges::find(availableSolverList, solverName) != availableSolverList.end()); if (!found) { diff --git a/src/tools/batchrun/main.cpp b/src/tools/batchrun/main.cpp index 9a31f4ecdf..420dc060dd 100644 --- a/src/tools/batchrun/main.cpp +++ b/src/tools/batchrun/main.cpp @@ -124,14 +124,7 @@ int main(int argc, const char* argv[]) if (not finder.list.empty()) { - if (finder.list.size() > 1) - { - logs.info() << "Found " << finder.list.size() << " studies"; - } - else - { - logs.info() << "Found 1 study"; - } + logs.info() << "Number of studies found : " << finder.list.size(); logs.info() << "Starting..."; // The folder that contains the solver From 44228f5133be5c5f47662f98e61e483f7a3ae244 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:47:30 +0100 Subject: [PATCH 049/103] Changelog 9.2 (#2465) - [x] Add * for each line --------- Co-authored-by: Florian OMNES --- docs/developer-guide/CHANGELOG.md | 113 ++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/docs/developer-guide/CHANGELOG.md b/docs/developer-guide/CHANGELOG.md index 6430d1b2e5..0496e11d9c 100644 --- a/docs/developer-guide/CHANGELOG.md +++ b/docs/developer-guide/CHANGELOG.md @@ -6,8 +6,121 @@ toc_depth: 2 ## Branch 9.2.x ### 9.2.0 +#### New features +* Short term storage withdrawal efficiency [ANT-1862] (#2223) +* Short term storage costs [ANT-1854] (#2302) +* Add ts-generation for links [ANT-1084] (#1986) + +#### Removed features +* Remove hydro hotstart (#2131) +* Remove adequacy patch lmr [ANT-1933] (#2341) +#### Improvements * Changed the formula for the number of cores [details](../user-guide/solver/optional-features/multi-threading.md) +* Expose API [ANT-1158] (#1993) +* Hydro final lvl (CR 25) [ANT-1084] (#1521) +* Adequacy patch CSR - revamp output variables [ANT-1932] (#2306) +* batchrun forwards options to antares-solver [ANT-2314] (#2463) +* Infeasibility analyzer [ANT-1825] (#2232) (#2227) +* Collect hydro validation errors (#2204) +* Perform hydro checks prior to the simulation [ANT-1720] (#2132) +* BC marginal cost : remove "return"s that break the static chain (#2121) + +#### Bugfixes +* Adequacy Patch regression [ANT-1845] (#2235) +* Fix condition for disabling "store in input" (#2180) +* Fix/rhs hydro power constraint (#2034) +* Fix Windows Debug version crash (#2322) +* Reset adequacy patch enabled (#2420) +* Fix reset order (#2304) +* Restore correct behavior when options -h/--list-solvers are provided (#2138) +* Fix missing synthesis results for links (#2115) + +#### Modeler +* 1.1: Modeler API [ANT-1876] (#2286) (#2391) +* 1.1c: Scenarize problem filler (#2445) + +* 2.1: Lib for modeling objects (#2383) +* 2.4: Expression visitors : first implementation (#2290) +* 2.4a: Replace AddNode with SumNode (#2396) +* 2.4c: portfield substitution (#2406) +* 2.4c: PortFieldSum and substitution [ANT-2005] (#2415) +* 2.4e: visualize ast with graphviz [ANT-2036] (#2399) (#2426) (#2429) + +* 4.5 Parse yaml [ANT-2206] (#2433) (#2431) (#2447) +* 4.5 Full exemple of parsing (#2448) + +* Add SumNode "wide" test (#2403) +* Add iterators on ASTs, allowing for loops (#2387) + +#### CI +* SonarCloud job, improvements, bugfixes (#2315) (#2281) (#2246) +* Run all tests even if one of them fails (#2265) +* install gh from rpm (#2216) +* Centos mirror list (#2372) +* Add tests in CI for version 9.2 (#2241) +* Use devtoolset-11 on CentOS7 to fix build (#2282) +* Keep using node js 16 on centos CI (#2248) +* Remove actions dependencies using node js 16 (#2215) +* Update deprecated actions (#2381) +* Add short test to coverage analysis (#2280) (#2267) +* Check formatting as part of the CI (workflow only) (#2198) +* Always run clang-format on PR (#2230) + +#### Build +* vcpkg (linux, sirius) (#2078) (#2090) (#2145) +* Remove src/antares-deps (#2182) +* Use OR-Tools v9.11-rte1.1 (#2437) +* Fix or-tools integration (#2402) +* Better dependencies with cmake, antares matrix (#2369) + +#### Doc +* CHANGELOG improvements (#2287) (#2229) (#2125) +* Fix PDF generation for useguide (#2134) +* Add contribution guidelines (#2380) +* update AUTHORS.txt (#2312) +* Fix links in README (#2310) +* Document clang-format (#2243) +* Add help button to website (#2368) + +#### Code quality +* Using filesystem path instead of Yuni [ANT-1999] (#2435) (#2454) (#2123) (#2066) +* Compilation warnings (#2237) (#2199) (#2183) (#2144) (#2119) (#2340) +* Separation of loading and validation [ANT-1213] (#2173) (#2175) (#2177) (#2179) +* Remove manually allocated memory (#2254) (#2270) (#2273) (#2363) +* Mark overriden functions as such in hydroLevelsData (#2389) +* Districts : simplifying the code (#2279) +* Remove duplication in simulation run (#2274) +* Fix various compilation warnings (#2346) +* Remove useless ;, macro definition (#2348) +* Use const char** for argv, remove function prepareArgs (#2338) +* Move TS number print (#2228) +* Link TS generation : splitting into multiple files (#2171) +* Infeasibility more cleaning (#2231) +* Harmonize time constants (#2203) +* Replace NULL -> nullptr in .cpp (#2209) +* Resize data collections in PROBLEME_A_RESOUDRE (#2189) +* Remove TS links from solver (#2155) +* Simplify functions prepareClustersInMustRunMode (#2168) +* Add a few const ref qualifiers to improve code readibility (#2459) +* Parallel years cleaning : few removal of "numspace" (#2128) +* Capture explicit var for lambdas (#2170) +* Fix circular dependencies on CMake targets (#2140) +* Fix Variable::Join (#2116) + +#### Technical cleaning +* Remove last global variable (#2410) +* Local matching removal : remove unused thread number / numSpace (#2404) +* Remove Antares::Memory::Array (#2187) +* Remove function memoryUsage and affiliates (#2456) +* Remove multiple definitions for Antares::Statistics::HasWrittenToDisk (#2136) +* Headers files : remove useless inclusions in OPT (#2411) +* Remove unused code & #defines (#2412) +* Remove unused CoutDeDefaillanceEnReserve (#2392) +* Remove unused adqPatchParams argument, class member (#2390) +* Remove unused headers in src/solver (yuni, cstdint, sim.h) (#2371) +* Remove unused CMake option BUILD MINIZIP (#2210) +* Remove useless forward declaration (#2268) ## Branch 9.1.x From cf653e70f7f8b88e7ae147622a5ad205a11f4c5e Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:58:57 +0100 Subject: [PATCH 050/103] Unit test for reverse calculation (#2483) Add new test checks the behavior of the `thermal_cluster` when the generation behavior is forced to no generation. Verify the `thermal_cluster` behavior when `tsGenBehavior` is set to `LocalTSGenerationBehavior::forceNoGen` and the time series is filled with a constant value. --------- Co-authored-by: Jason Marechal Co-authored-by: Florian OMNES --- .../src/libs/antares/study/test_study.cpp | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/tests/src/libs/antares/study/test_study.cpp b/src/tests/src/libs/antares/study/test_study.cpp index fa0348467d..4a1d8ec303 100644 --- a/src/tests/src/libs/antares/study/test_study.cpp +++ b/src/tests/src/libs/antares/study/test_study.cpp @@ -186,19 +186,51 @@ struct ThermalClusterStudy: public OneAreaStudy BOOST_FIXTURE_TEST_CASE(thermal_cluster_rename, ThermalClusterStudy) { BOOST_CHECK(study->clusterRename(cluster, "Renamed")); - BOOST_CHECK(cluster->name() == "Renamed"); - BOOST_CHECK(cluster->id() == "renamed"); + BOOST_CHECK_EQUAL(cluster->name(), "Renamed"); + BOOST_CHECK_EQUAL(cluster->id(), "renamed"); } BOOST_FIXTURE_TEST_CASE(thermal_cluster_delete, ThermalClusterStudy) { // gp : remove() only used in GUI (will go away when removing the GUI) - BOOST_CHECK(areaA->thermal.list.findInAll("cluster") == cluster); + BOOST_CHECK_EQUAL(areaA->thermal.list.findInAll("cluster"), cluster); areaA->thermal.list.remove("cluster"); - BOOST_CHECK(areaA->thermal.list.findInAll("cluster") == nullptr); + BOOST_CHECK_EQUAL(areaA->thermal.list.findInAll("cluster"), nullptr); BOOST_CHECK(areaA->thermal.list.empty()); } +// Custom macro +#define BOOST_CHECK_EQUAL_MESSAGE(L, R, M) \ + { \ + BOOST_TEST_INFO(M); \ + BOOST_CHECK_EQUAL(L, R); \ + } + +BOOST_FIXTURE_TEST_CASE(WithForceNoGenOptionTimeSeriesNotGeneratedForReverseSpinning, + ThermalClusterStudy) +{ + cluster->tsGenBehavior = LocalTSGenerationBehavior::forceNoGen; + cluster->spinning = 0.9; // An arbitrary value != 1.0 is chosen here, otherwise the reverse + // calculation of spinning does nothing + auto& ts = cluster->series.timeSeries; + + ts.resize(1, 8760); + ts.fill(100); + cluster->reverseCalculationOfSpinning(); + + for (unsigned i = 0; i < ts.width; ++i) + { + for (unsigned j = 0; j < ts.height; ++j) + { + BOOST_CHECK_EQUAL_MESSAGE(ts[i][j], + 100, + "Error at " + std::to_string(i) + ", " + std::to_string(j)); + } + } +} + +#undef BOOST_CHECK_EQUAL_MESSAGE + BOOST_AUTO_TEST_SUITE_END() // thermal clusters BOOST_AUTO_TEST_SUITE(renewable_clusters_operations) From efedb155307d15fa65d234eea34b70d2684f2d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20Mar=C3=A9chal?= <45510813+JasonMarechal25@users.noreply.github.com> Date: Fri, 15 Nov 2024 17:08:37 +0100 Subject: [PATCH 051/103] [skip ci] Migration doc : move hydro level from v8.7.0 to v9.2.0 (#2482) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Guillaume PIERRE Co-authored-by: Florian Omnès --- docs/user-guide/04-migration-guides.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/user-guide/04-migration-guides.md b/docs/user-guide/04-migration-guides.md index 51fc738920..2bdc0beb21 100644 --- a/docs/user-guide/04-migration-guides.md +++ b/docs/user-guide/04-migration-guides.md @@ -41,6 +41,11 @@ In files input/links//properties.ini, add the following properties - number of TS to generate => generaldata.ini/General/nbtimeserieslinks (unsigned int, default value 1) +### Input +#### Hydro Final Reservoir Level +In the existing file **settings/scenariobuilder.dat**, under **<ruleset>** section following properties added (if final reservoir level specified, different from `init`): +* **hfl,<area>,<year> = <hfl-value>** + ### Output - Remove column SPIL ENRG CSR (adequacy patch) - Add DTG MRG CSR and UNSP ENRG CSR variables @@ -154,10 +159,6 @@ For each thermal cluster, in existing file **input/thermal/clusters/<area> For each thermal cluster, new files added **input/thermal/series/<area>/<cluster>/CO2Cost.txt** and **input/thermal/series/<area>/<cluster>/fuelCost.txt**. **fuelCost.txt** and **CO2Cost.txt** must either have one column, or the same number of columns as existing file **series.txt** (availability). The number of rows for these new matrices is 8760. -#### Hydro Final Reservoir Level -In the existing file **settings/scenariobuilder.dat**, under **<ruleset>** section following properties added (if final reservoir level specified, different from `init`): -* **hfl,<area>,<year> = <hfl-value>** - ### Output #### Scenarized RHS for binding constraints Add directory **bindingconstraints** to output directory **ts-numbers**. For every binding constraint group, add a file **ts-numbers/bindingconstraints/<group>.txt** containing the TS numbers used for that group. From d1ca9a1f6808c89f10486490316fa47ed683e902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Tue, 19 Nov 2024 16:30:22 +0100 Subject: [PATCH 052/103] Polish changelog for v9.2 (#2494) --- docs/developer-guide/CHANGELOG.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/developer-guide/CHANGELOG.md b/docs/developer-guide/CHANGELOG.md index 0496e11d9c..017a22a11d 100644 --- a/docs/developer-guide/CHANGELOG.md +++ b/docs/developer-guide/CHANGELOG.md @@ -10,6 +10,7 @@ toc_depth: 2 * Short term storage withdrawal efficiency [ANT-1862] (#2223) * Short term storage costs [ANT-1854] (#2302) * Add ts-generation for links [ANT-1084] (#1986) +* Make it possible to specify the final hydro reservoir level [ANT-1084] (#1521) #### Removed features * Remove hydro hotstart (#2131) @@ -18,16 +19,15 @@ toc_depth: 2 #### Improvements * Changed the formula for the number of cores [details](../user-guide/solver/optional-features/multi-threading.md) * Expose API [ANT-1158] (#1993) -* Hydro final lvl (CR 25) [ANT-1084] (#1521) * Adequacy patch CSR - revamp output variables [ANT-1932] (#2306) * batchrun forwards options to antares-solver [ANT-2314] (#2463) * Infeasibility analyzer [ANT-1825] (#2232) (#2227) * Collect hydro validation errors (#2204) * Perform hydro checks prior to the simulation [ANT-1720] (#2132) -* BC marginal cost : remove "return"s that break the static chain (#2121) #### Bugfixes * Adequacy Patch regression [ANT-1845] (#2235) +* BC marginal cost : remove "return"s that break the static chain (#2121) * Fix condition for disabling "store in input" (#2180) * Fix/rhs hydro power constraint (#2034) * Fix Windows Debug version crash (#2322) @@ -39,17 +39,14 @@ toc_depth: 2 #### Modeler * 1.1: Modeler API [ANT-1876] (#2286) (#2391) * 1.1c: Scenarize problem filler (#2445) - * 2.1: Lib for modeling objects (#2383) * 2.4: Expression visitors : first implementation (#2290) * 2.4a: Replace AddNode with SumNode (#2396) * 2.4c: portfield substitution (#2406) * 2.4c: PortFieldSum and substitution [ANT-2005] (#2415) * 2.4e: visualize ast with graphviz [ANT-2036] (#2399) (#2426) (#2429) - * 4.5 Parse yaml [ANT-2206] (#2433) (#2431) (#2447) * 4.5 Full exemple of parsing (#2448) - * Add SumNode "wide" test (#2403) * Add iterators on ASTs, allowing for loops (#2387) From 883ed882ff0f931e52448b808a71866946cc7c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Tue, 19 Nov 2024 16:40:09 +0100 Subject: [PATCH 053/103] Remove computation for number of non-zero terms in the constraint matrix [ANT-2258] (#2496) The goal of this PR is to avoid having to compute the number of non-zero terms in the constraint matrix. Some C functions require a `T*` array. Previously, we used `std::vector::data` for `CoefficientsDeLaMatriceDesContraintes` and `IndicesColonnes`. Instead, we use a 2-step mechanism through templated class `VectorMap` 1. Fill a `std::vector>` (vector of pairs) 2. Extract the vector of pairs into an `std::vector`, use it's `data`. This `std::vector` is kept alive as long as it's `data` is used, preventing invalid memory reads. --- .../InfoCollection/StudyInfoCollector.cpp | 3 - .../infoCollection/StudyInfoCollector.h | 1 - src/solver/optimisation/CMakeLists.txt | 1 + .../HebdoProblemToLpsTranslator.cpp | 7 +++ .../adq_patch_curtailment_sharing.cpp | 8 +-- .../ConsistenceNumberOfDispatchableUnits.cpp | 1 - .../constraints/ConstraintBuilder.cpp | 22 ------- .../optimisation/constraints/MinDownTime.cpp | 2 - .../NbDispUnitsMinBoundSinceMinUpTime.cpp | 2 - .../NbUnitsOutageLessThanNbUnitsStop.cpp | 1 - .../PMaxDispatchableGeneration.cpp | 1 - .../PMinDispatchableGeneration.cpp | 1 - .../constraints/constraint_builder_utils.cpp | 4 +- .../solver/optimisation/SparseVector.hxx | 44 +++++++++++++ .../constraints/ConstraintBuilder.h | 8 +-- .../solver/optimisation/opt_fonctions.h | 3 +- .../opt_structure_probleme_a_resoudre.h | 6 +- .../opt_alloc_probleme_a_optimiser.cpp | 62 ++----------------- src/solver/simulation/adequacy.cpp | 1 - src/solver/simulation/economy.cpp | 1 - .../sim_structure_probleme_economique.h | 1 - .../translator/test_translator.cpp | 24 +++++-- 22 files changed, 85 insertions(+), 119 deletions(-) create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/SparseVector.hxx diff --git a/src/libs/antares/InfoCollection/StudyInfoCollector.cpp b/src/libs/antares/InfoCollection/StudyInfoCollector.cpp index fe72e57d10..33b59d915e 100644 --- a/src/libs/antares/InfoCollection/StudyInfoCollector.cpp +++ b/src/libs/antares/InfoCollection/StudyInfoCollector.cpp @@ -167,9 +167,6 @@ void SimulationInfoCollector::toFileContent(FileContent& file_content) { file_content.addItemToSection("optimization problem", "variables", opt_info_.nbVariables); file_content.addItemToSection("optimization problem", "constraints", opt_info_.nbConstraints); - file_content.addItemToSection("optimization problem", - "non-zero coefficients", - opt_info_.nbNonZeroCoeffs); } } // namespace Benchmarking diff --git a/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h b/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h index 96f83b38af..2ac5a06c12 100644 --- a/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h +++ b/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h @@ -62,7 +62,6 @@ struct OptimizationInfo { unsigned int nbVariables = 0; unsigned int nbConstraints = 0; - unsigned int nbNonZeroCoeffs = 0; }; class SimulationInfoCollector diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index e2472febd1..e8b46e6000 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -5,6 +5,7 @@ set(RTESOLVER_OPT opt_optimisation_lineaire.cpp opt_chainage_intercos.cpp include/antares/solver/optimisation/opt_fonctions.h + include/antares/solver/optimisation/SparseVector.hxx opt_pilotage_optimisation_lineaire.cpp opt_pilotage_optimisation_quadratique.cpp include/antares/solver/optimisation/opt_structure_probleme_a_resoudre.h diff --git a/src/solver/optimisation/HebdoProblemToLpsTranslator.cpp b/src/solver/optimisation/HebdoProblemToLpsTranslator.cpp index 9c67012c70..3e741652d8 100644 --- a/src/solver/optimisation/HebdoProblemToLpsTranslator.cpp +++ b/src/solver/optimisation/HebdoProblemToLpsTranslator.cpp @@ -43,6 +43,13 @@ void copy(const T& in, U& out) { std::ranges::copy(in, std::back_inserter(out)); } + +template +void copy(const SparseVector& in, U& out) +{ + copy(in.extract(), out); +} + } // namespace WeeklyDataFromAntares HebdoProblemToLpsTranslator::translate( diff --git a/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp b/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp index 0aa61a969d..b480108379 100644 --- a/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp +++ b/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp @@ -141,13 +141,9 @@ void HourlyCSRProblem::calculateCsrParameters() void HourlyCSRProblem::allocateProblem() { using namespace Antares::Data::AdequacyPatch; - int nbConst; - problemeAResoudre_.NombreDeVariables = countVariables(problemeHebdo_); - nbConst = problemeAResoudre_.NombreDeContraintes = countConstraints(problemeHebdo_); - int nbTerms = 3 * nbConst; // This is a rough estimate, reallocations may happen later if it's - // too low - OPT_AllocateFromNumberOfVariableConstraints(&problemeAResoudre_, nbTerms); + problemeAResoudre_.NombreDeContraintes = countConstraints(problemeHebdo_); + OPT_AllocateFromNumberOfVariableConstraints(&problemeAResoudre_); } void HourlyCSRProblem::buildProblemVariables() diff --git a/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.cpp b/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.cpp index 300cdbaef5..ab49f3e6d5 100644 --- a/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.cpp +++ b/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.cpp @@ -60,7 +60,6 @@ void ConsistenceNumberOfDispatchableUnits::add(int pays, int index, int pdt) } else { - builder.data.NbTermesContraintesPourLesCoutsDeDemarrage += 4; builder.data.nombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/ConstraintBuilder.cpp b/src/solver/optimisation/constraints/ConstraintBuilder.cpp index edac845526..ba4e70254a 100644 --- a/src/solver/optimisation/constraints/ConstraintBuilder.cpp +++ b/src/solver/optimisation/constraints/ConstraintBuilder.cpp @@ -188,11 +188,6 @@ void ConstraintBuilder::OPT_ChargerLaContrainteDansLaMatriceDesContraintes() = data.Pi[i]; data.IndicesColonnes[data.nombreDeTermesDansLaMatriceDeContrainte] = data.Colonne[i]; data.nombreDeTermesDansLaMatriceDeContrainte++; - if (data.nombreDeTermesDansLaMatriceDeContrainte - == data.NombreDeTermesAllouesDansLaMatriceDesContraintes) - { - OPT_AugmenterLaTailleDeLaMatriceDesContraintes(); - } } data.NombreDeTermesDesLignes[data.nombreDeContraintes] = nombreDeTermes_; @@ -201,20 +196,3 @@ void ConstraintBuilder::OPT_ChargerLaContrainteDansLaMatriceDesContraintes() return; } - -void ConstraintBuilder::OPT_AugmenterLaTailleDeLaMatriceDesContraintes() -{ - int NbTermes = data.NombreDeTermesAllouesDansLaMatriceDesContraintes; - NbTermes += data.IncrementDAllocationMatriceDesContraintes; - - logs.info(); - logs.info() << " Expected Number of Non-zero terms in Problem Matrix : increased to : " - << NbTermes; - logs.info(); - - data.CoefficientsDeLaMatriceDesContraintes.resize(NbTermes); - - data.IndicesColonnes.resize(NbTermes); - - data.NombreDeTermesAllouesDansLaMatriceDesContraintes = NbTermes; -} diff --git a/src/solver/optimisation/constraints/MinDownTime.cpp b/src/solver/optimisation/constraints/MinDownTime.cpp index a7467e742c..7d7505ee4d 100644 --- a/src/solver/optimisation/constraints/MinDownTime.cpp +++ b/src/solver/optimisation/constraints/MinDownTime.cpp @@ -66,8 +66,6 @@ void MinDownTime::add(int pays, int index, int pdt) } else { - builder.data.NbTermesContraintesPourLesCoutsDeDemarrage - += 1 + DureeMinimaleDArretDUnGroupeDuPalierThermique; builder.data.nombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp b/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp index 13f03df1c1..a1a73ef2fa 100644 --- a/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp +++ b/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp @@ -70,8 +70,6 @@ void NbDispUnitsMinBoundSinceMinUpTime::add(int pays, int index, int pdt) } else { - builder.data.NbTermesContraintesPourLesCoutsDeDemarrage - += 1 + 2 * DureeMinimaleDeMarcheDUnGroupeDuPalierThermique; builder.data.nombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.cpp b/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.cpp index 4d90766da3..bfa8fb52c2 100644 --- a/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.cpp +++ b/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.cpp @@ -50,7 +50,6 @@ void NbUnitsOutageLessThanNbUnitsStop::add(int pays, int index, int pdt) } else { - builder.data.NbTermesContraintesPourLesCoutsDeDemarrage += 2; builder.data.nombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/PMaxDispatchableGeneration.cpp b/src/solver/optimisation/constraints/PMaxDispatchableGeneration.cpp index a3d7fef5b8..466ebf81d2 100644 --- a/src/solver/optimisation/constraints/PMaxDispatchableGeneration.cpp +++ b/src/solver/optimisation/constraints/PMaxDispatchableGeneration.cpp @@ -48,7 +48,6 @@ void PMaxDispatchableGeneration::add(int pays, int index, int pdt) } else { - builder.data.NbTermesContraintesPourLesCoutsDeDemarrage += 2; builder.data.nombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/PMinDispatchableGeneration.cpp b/src/solver/optimisation/constraints/PMinDispatchableGeneration.cpp index df22497577..b6cf27fc8e 100644 --- a/src/solver/optimisation/constraints/PMinDispatchableGeneration.cpp +++ b/src/solver/optimisation/constraints/PMinDispatchableGeneration.cpp @@ -49,7 +49,6 @@ void PMinDispatchableGeneration::add(int pays, int index, int pdt) } else { - builder.data.NbTermesContraintesPourLesCoutsDeDemarrage += 2; builder.data.nombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/constraint_builder_utils.cpp b/src/solver/optimisation/constraints/constraint_builder_utils.cpp index 77a3228999..585d0b6d81 100644 --- a/src/solver/optimisation/constraints/constraint_builder_utils.cpp +++ b/src/solver/optimisation/constraints/constraint_builder_utils.cpp @@ -32,7 +32,6 @@ ConstraintBuilderData NewGetConstraintBuilderFromProblemHebdoAndProblemAResoudre ProblemeAResoudre.IndicesDebutDeLigne, ProblemeAResoudre.CoefficientsDeLaMatriceDesContraintes, ProblemeAResoudre.IndicesColonnes, - ProblemeAResoudre.NombreDeTermesAllouesDansLaMatriceDesContraintes, ProblemeAResoudre.NombreDeTermesDesLignes, ProblemeAResoudre.Sens, ProblemeAResoudre.IncrementDAllocationMatriceDesContraintes, @@ -44,6 +43,5 @@ ConstraintBuilderData NewGetConstraintBuilderFromProblemHebdoAndProblemAResoudre problemeHebdo->NamedProblems, problemeHebdo->NomsDesPays, problemeHebdo->weekInTheYear, - problemeHebdo->NombreDePasDeTemps, - problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage}; + problemeHebdo->NombreDePasDeTemps}; } diff --git a/src/solver/optimisation/include/antares/solver/optimisation/SparseVector.hxx b/src/solver/optimisation/include/antares/solver/optimisation/SparseVector.hxx new file mode 100644 index 0000000000..2b71ac4aec --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/SparseVector.hxx @@ -0,0 +1,44 @@ +#include + +template +class SparseVector +{ +public: + std::size_t size() const + { + return isExtracted ? v.size() : m.size(); + } + + T& operator[](std::size_t idx) + { + isExtracted = false; + m.push_back({idx, 0}); + return m.back().second; + } + + T* data() const + { + extract(); + return v.data(); + } + + std::vector& extract() const + { + if (!isExtracted) + { + isExtracted = true; + v.assign(m.size(), 0.); + for (auto [index, coeff]: m) + { + v[index] = coeff; + } + m.clear(); + } + return v; + } + +private: + mutable bool isExtracted = false; + mutable std::vector> m; + mutable std::vector v; +}; 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 2dfdec8000..dd0a1ab1b6 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h @@ -39,9 +39,8 @@ class ConstraintBuilderData int& nombreDeContraintes; int& nombreDeTermesDansLaMatriceDeContrainte; std::vector& IndicesDebutDeLigne; - std::vector& CoefficientsDeLaMatriceDesContraintes; - std::vector& IndicesColonnes; - int& NombreDeTermesAllouesDansLaMatriceDesContraintes; // TODO Check if ref is needed + SparseVector& CoefficientsDeLaMatriceDesContraintes; + SparseVector& IndicesColonnes; std::vector& NombreDeTermesDesLignes; std::string& Sens; int& IncrementDAllocationMatriceDesContraintes; @@ -54,7 +53,6 @@ class ConstraintBuilderData const std::vector& NomsDesPays; const uint32_t& weekInTheYear; const uint32_t& NombreDePasDeTemps; - uint32_t& NbTermesContraintesPourLesCoutsDeDemarrage; }; /*! \verbatim @@ -221,8 +219,6 @@ class ConstraintBuilder private: void OPT_ChargerLaContrainteDansLaMatriceDesContraintes(); - void OPT_AugmenterLaTailleDeLaMatriceDesContraintes(); - unsigned int hourInWeek_ = 0; char operator_ = '='; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h index 18551a08b5..bd27921f8f 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h @@ -95,8 +95,7 @@ double OPT_CalculerAireMaxPminJour(int, int, int, int, std::vector&, std::v void OPT_ChainagesDesIntercoPartantDUnNoeud(PROBLEME_HEBDO*); -void OPT_AllocateFromNumberOfVariableConstraints(PROBLEME_ANTARES_A_RESOUDRE* ProblemeAResoudre, - int); +void OPT_AllocateFromNumberOfVariableConstraints(PROBLEME_ANTARES_A_RESOUDRE* ProblemeAResoudre); void OPT_AllocDuProblemeAOptimiser(PROBLEME_HEBDO*); int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO*); diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_structure_probleme_a_resoudre.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_structure_probleme_a_resoudre.h index 7641c23d4e..1079a2f147 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_structure_probleme_a_resoudre.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_structure_probleme_a_resoudre.h @@ -27,6 +27,7 @@ #include +#include "SparseVector.hxx" #include "opt_constants.h" /*--------------------------------------------------------------------------------------*/ @@ -45,9 +46,8 @@ struct PROBLEME_ANTARES_A_RESOUDRE std::string Sens; std::vector IndicesDebutDeLigne; std::vector NombreDeTermesDesLignes; - std::vector CoefficientsDeLaMatriceDesContraintes; - std::vector IndicesColonnes; - int NombreDeTermesAllouesDansLaMatriceDesContraintes; + SparseVector CoefficientsDeLaMatriceDesContraintes; + SparseVector IndicesColonnes; int IncrementDAllocationMatriceDesContraintes; int NombreDeTermesDansLaMatriceDesContraintes; /* Donnees variables de la matrice des contraintes */ diff --git a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp index a9906ff21f..69e827fec5 100644 --- a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp +++ b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp @@ -20,13 +20,11 @@ */ #include +#include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" -int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO*); - -void OPT_AllocateFromNumberOfVariableConstraints(PROBLEME_ANTARES_A_RESOUDRE* ProblemeAResoudre, - int NbTermes) +void OPT_AllocateFromNumberOfVariableConstraints(PROBLEME_ANTARES_A_RESOUDRE* ProblemeAResoudre) { const size_t nbVariables = ProblemeAResoudre->NombreDeVariables; const size_t nbConstraints = ProblemeAResoudre->NombreDeContraintes; @@ -35,12 +33,6 @@ void OPT_AllocateFromNumberOfVariableConstraints(PROBLEME_ANTARES_A_RESOUDRE* Pr ProblemeAResoudre->IndicesDebutDeLigne.assign(nbConstraints, 0); ProblemeAResoudre->NombreDeTermesDesLignes.assign(nbConstraints, 0); - ProblemeAResoudre->CoefficientsDeLaMatriceDesContraintes.assign(NbTermes, 0.); - ProblemeAResoudre->IndicesColonnes.assign(NbTermes, 0); - - ProblemeAResoudre->NombreDeTermesAllouesDansLaMatriceDesContraintes = NbTermes; - ProblemeAResoudre->IncrementDAllocationMatriceDesContraintes = (int)(0.1 * NbTermes); - ProblemeAResoudre->CoutQuadratique.assign(nbVariables, 0.); ProblemeAResoudre->CoutLineaire.assign(nbVariables, 0.); ProblemeAResoudre->TypeDeVariable.assign(nbVariables, 0); @@ -70,62 +62,20 @@ void OPT_AllocateFromNumberOfVariableConstraints(PROBLEME_ANTARES_A_RESOUDRE* Pr ProblemeAResoudre->VariablesEntieres.resize(nbVariables); } -static void optimisationAllocateProblem(PROBLEME_HEBDO* problemeHebdo, const int mxPaliers) +static void optimisationAllocateProblem(PROBLEME_HEBDO* problemeHebdo) { const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; int NombreDePasDeTempsPourUneOptimisation = problemeHebdo ->NombreDePasDeTempsPourUneOptimisation; - int Sparsity = mxPaliers * problemeHebdo->NombreDePays; - Sparsity += problemeHebdo->NombreDInterconnexions; - if (Sparsity > 100) - { - Sparsity = 100; - } - - int NbTermes = 0; - NbTermes += ProblemeAResoudre->NombreDeContraintes; - - int Adder = mxPaliers; - Adder += 4; - Adder *= problemeHebdo->NombreDePays; - Adder += 2 * problemeHebdo->NombreDInterconnexions; - Adder *= NombreDePasDeTempsPourUneOptimisation; - - NbTermes += Adder; - - NbTermes += Adder; - - Adder = 3 * problemeHebdo->NombreDInterconnexions * NombreDePasDeTempsPourUneOptimisation; - NbTermes += Adder; - - Adder = Sparsity * problemeHebdo->NombreDeContraintesCouplantes; - Adder *= (NombreDePasDeTempsPourUneOptimisation); - Adder += Sparsity * (7 + 7) * problemeHebdo->NombreDeContraintesCouplantes; - - NbTermes += Adder; - - NbTermes += 3 * problemeHebdo->NombreDePays * NombreDePasDeTempsPourUneOptimisation; - NbTermes += problemeHebdo->NombreDePays * NombreDePasDeTempsPourUneOptimisation * 4; - NbTermes += problemeHebdo->NombreDePays * NombreDePasDeTempsPourUneOptimisation * 5; - - NbTermes += problemeHebdo->NombreDePays * NombreDePasDeTempsPourUneOptimisation - * 2; /*inequality constraint on final hydros level*/ - NbTermes += 1; /* constraint includes hydro generation, pumping and final level */ - NbTermes += 101; /* constraint expressing final level as a sum of stock layers */ - - NbTermes += problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage; - logs.info(); logs.info() << " Starting Memory Allocation for a Weekly Optimization problem in Canonical form "; logs.info() << " ( Problem Size :" << ProblemeAResoudre->NombreDeVariables << " variables " << ProblemeAResoudre->NombreDeContraintes << " Constraints) "; - logs.info() << " Expected Number of Non-zero terms in Problem Matrix : " << NbTermes; - logs.info(); - OPT_AllocateFromNumberOfVariableConstraints(problemeHebdo->ProblemeAResoudre.get(), NbTermes); + OPT_AllocateFromNumberOfVariableConstraints(problemeHebdo->ProblemeAResoudre.get()); int NbIntervalles = problemeHebdo->NombreDePasDeTemps / NombreDePasDeTempsPourUneOptimisation; @@ -140,7 +90,7 @@ void OPT_AllocDuProblemeAOptimiser(PROBLEME_HEBDO* problemeHebdo) { problemeHebdo->ProblemeAResoudre = std::make_unique(); - int mxPaliers = OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(problemeHebdo); + OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(problemeHebdo); - optimisationAllocateProblem(problemeHebdo, mxPaliers); + optimisationAllocateProblem(problemeHebdo); } diff --git a/src/solver/simulation/adequacy.cpp b/src/solver/simulation/adequacy.cpp index e0ef154020..d5eca92216 100644 --- a/src/solver/simulation/adequacy.cpp +++ b/src/solver/simulation/adequacy.cpp @@ -46,7 +46,6 @@ Benchmarking::OptimizationInfo Adequacy::getOptimizationInfo() const optInfo.nbVariables = Pb->NombreDeVariables; optInfo.nbConstraints = Pb->NombreDeContraintes; - optInfo.nbNonZeroCoeffs = Pb->NombreDeTermesAllouesDansLaMatriceDesContraintes; return optInfo; } diff --git a/src/solver/simulation/economy.cpp b/src/solver/simulation/economy.cpp index b6edbc4f6f..0b8b341148 100644 --- a/src/solver/simulation/economy.cpp +++ b/src/solver/simulation/economy.cpp @@ -51,7 +51,6 @@ Benchmarking::OptimizationInfo Economy::getOptimizationInfo() const optInfo.nbVariables = Pb->NombreDeVariables; optInfo.nbConstraints = Pb->NombreDeContraintes; - optInfo.nbNonZeroCoeffs = Pb->NombreDeTermesAllouesDansLaMatriceDesContraintes; return optInfo; } 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 29dd7c38f5..3a261bf40f 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 @@ -502,7 +502,6 @@ struct PROBLEME_HEBDO std::vector<::ShortTermStorage::AREA_INPUT> ShortTermStorage; /* Optimization problem */ - uint32_t NbTermesContraintesPourLesCoutsDeDemarrage = 0; std::vector DefaillanceNegativeUtiliserPMinThermique; std::vector DefaillanceNegativeUtiliserHydro; std::vector DefaillanceNegativeUtiliserConsoAbattue; diff --git a/src/tests/src/solver/optimisation/translator/test_translator.cpp b/src/tests/src/solver/optimisation/translator/test_translator.cpp index 2430c74cb0..77591180cb 100644 --- a/src/tests/src/solver/optimisation/translator/test_translator.cpp +++ b/src/tests/src/solver/optimisation/translator/test_translator.cpp @@ -112,6 +112,15 @@ BOOST_AUTO_TEST_CASE(empty_problem_empty_const_data) BOOST_CHECK(ret == ConstantDataFromAntares()); } +template +static void fillSparseVector(SparseVector& v, int idxMax) +{ + for (int idx = 0; idx < idxMax; idx++) + { + v[idx] = idx; + } +} + BOOST_AUTO_TEST_CASE(common_data_properly_copied) { HebdoProblemToLpsTranslator translator; @@ -121,15 +130,17 @@ BOOST_AUTO_TEST_CASE(common_data_properly_copied) problemHebdo.TypeDeVariable = {0, 1, 2}; problemHebdo.IndicesDebutDeLigne = {0, 3}; problemHebdo.NombreDeTermesDesLignes = {3, 3}; - problemHebdo.CoefficientsDeLaMatriceDesContraintes = {0, 1, 2, 3, 4, 5}; - problemHebdo.IndicesColonnes = {0, 1, 2, 3, 4, 5}; + fillSparseVector(problemHebdo.CoefficientsDeLaMatriceDesContraintes, 6); + fillSparseVector(problemHebdo.IndicesColonnes, 6); auto ret = translator.commonProblemData(&problemHebdo); + BOOST_CHECK_EQUAL(ret.VariablesCount, problemHebdo.NombreDeVariables); BOOST_CHECK_EQUAL(ret.ConstraintesCount, problemHebdo.NombreDeContraintes); BOOST_CHECK(std::ranges::equal(ret.VariablesType, problemHebdo.TypeDeVariable)); - BOOST_CHECK(ret.ConstraintsMatrixCoeff == problemHebdo.CoefficientsDeLaMatriceDesContraintes); - BOOST_CHECK(std::ranges::equal(ret.ColumnIndexes, problemHebdo.IndicesColonnes)); + BOOST_CHECK(ret.ConstraintsMatrixCoeff + == problemHebdo.CoefficientsDeLaMatriceDesContraintes.extract()); + BOOST_CHECK(std::ranges::equal(ret.ColumnIndexes, problemHebdo.IndicesColonnes.extract())); auto expectedMdeb = problemHebdo.IndicesDebutDeLigne; expectedMdeb.push_back(problemHebdo.CoefficientsDeLaMatriceDesContraintes.size()); BOOST_CHECK(std::ranges::equal(ret.Mdeb, expectedMdeb)); @@ -183,8 +194,9 @@ BOOST_AUTO_TEST_CASE(NombreDeCoefficients_is_properly_computed) problemHebdo.NombreDeContraintes = 3; problemHebdo.IndicesDebutDeLigne = {0, 3, 6}; problemHebdo.NombreDeTermesDesLignes = {3, 3, 3}; - problemHebdo.CoefficientsDeLaMatriceDesContraintes = {0, 1, 2, 3, 4, 5, 6, 7, 8}; - problemHebdo.IndicesColonnes = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + + fillSparseVector(problemHebdo.CoefficientsDeLaMatriceDesContraintes, 9); + fillSparseVector(problemHebdo.IndicesColonnes, 9); auto ret = translator.commonProblemData(&problemHebdo); BOOST_CHECK_EQUAL(ret.CoeffCount, 9); From c257cb90924e032be1a99b145b5d5de87a4c74bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Tue, 19 Nov 2024 16:56:13 +0100 Subject: [PATCH 054/103] Place CSR after hydro remix [ANT-2070] (#2438) --- .../adq_patch_post_process_list.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp b/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp index ca3a31ecb0..996ec70c6e 100644 --- a/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp +++ b/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp @@ -36,11 +36,7 @@ AdqPatchPostProcessList::AdqPatchPostProcessList(const AdqPatchParams& adqPatchP { post_process_list.push_back( std::make_unique(problemeHebdo_, thread_number_, areas)); - // Here a post process particular to adq patch - post_process_list.push_back(std::make_unique(adqPatchParams, - problemeHebdo_, - areas, - thread_number_)); + post_process_list.push_back( std::make_unique(problemeHebdo_, areas, false, false)); post_process_list.push_back(std::make_unique(problemeHebdo_, @@ -48,6 +44,12 @@ AdqPatchPostProcessList::AdqPatchPostProcessList(const AdqPatchParams& adqPatchP sheddingPolicy, splxOptimization, thread_number)); + + // Here a post process particular to adq patch + post_process_list.push_back(std::make_unique(adqPatchParams, + problemeHebdo_, + areas, + thread_number_)); // Here a post process particular to adq patch post_process_list.push_back( std::make_unique(problemeHebdo_, areas, thread_number)); From 5d5df42206d6716415289d322bfbc0d4521fd23d Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Wed, 20 Nov 2024 17:37:04 +0100 Subject: [PATCH 055/103] Move libObjectModel code (#2498) Move the code of the new dynamic modeler's system object model to study/system-model --------- Signed-off-by: Peter Mitri --- src/CMakeLists.txt | 1 + src/solver/CMakeLists.txt | 1 - src/solver/libModelObject/CMakeLists.txt | 34 ------ src/solver/modelConverter/CMakeLists.txt | 2 +- .../solver/modelConverter/modelConverter.h | 11 +- src/solver/modelConverter/modelConverter.cpp | 110 +++++++++--------- src/study/CMakeLists.txt | 3 + src/study/system-model/CMakeLists.txt | 33 ++++++ .../antares/study/system-model}/constraint.h | 4 +- .../antares/study/system-model}/expression.h | 4 +- .../antares/study/system-model}/library.h | 4 +- .../antares/study/system-model}/model.h | 4 +- .../antares/study/system-model}/parameter.h | 4 +- .../antares/study/system-model}/port.h | 4 +- .../antares/study/system-model}/portField.h | 4 +- .../study/system-model}/portFieldDefinition.h | 4 +- .../antares/study/system-model}/portType.h | 4 +- .../antares/study/system-model}/valueType.h | 4 +- .../antares/study/system-model}/variable.h | 5 +- .../system-model}/library.cpp | 6 +- .../system-model}/model.cpp | 6 +- .../src/solver/modelParser/CMakeLists.txt | 2 +- .../src/solver/modelParser/enum_operators.h | 7 +- .../modelParser/testModelTranslator.cpp | 31 ++--- .../src/solver/modelParser/test_full.cpp | 72 ++++++------ 25 files changed, 181 insertions(+), 183 deletions(-) delete mode 100644 src/solver/libModelObject/CMakeLists.txt create mode 100644 src/study/CMakeLists.txt create mode 100644 src/study/system-model/CMakeLists.txt rename src/{solver/libModelObject/include/antares/solver/libObjectModel => study/system-model/include/antares/study/system-model}/constraint.h (94%) rename src/{solver/libModelObject/include/antares/solver/libObjectModel => study/system-model/include/antares/study/system-model}/expression.h (93%) rename src/{solver/libModelObject/include/antares/solver/libObjectModel => study/system-model/include/antares/study/system-model}/library.h (96%) rename src/{solver/libModelObject/include/antares/solver/libObjectModel => study/system-model/include/antares/study/system-model}/model.h (96%) rename src/{solver/libModelObject/include/antares/solver/libObjectModel => study/system-model/include/antares/study/system-model}/parameter.h (96%) rename src/{solver/libModelObject/include/antares/solver/libObjectModel => study/system-model/include/antares/study/system-model}/port.h (93%) rename src/{solver/libModelObject/include/antares/solver/libObjectModel => study/system-model/include/antares/study/system-model}/portField.h (93%) rename src/{solver/libModelObject/include/antares/solver/libObjectModel => study/system-model/include/antares/study/system-model}/portFieldDefinition.h (93%) rename src/{solver/libModelObject/include/antares/solver/libObjectModel => study/system-model/include/antares/study/system-model}/portType.h (94%) rename src/{solver/libModelObject/include/antares/solver/libObjectModel => study/system-model/include/antares/study/system-model}/valueType.h (92%) rename src/{solver/libModelObject/include/antares/solver/libObjectModel => study/system-model/include/antares/study/system-model}/variable.h (94%) rename src/{solver/libModelObject => study/system-model}/library.cpp (95%) rename src/{solver/libModelObject => study/system-model}/model.cpp (96%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e93c5fcd58..e8b4d90a14 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -271,6 +271,7 @@ if(BUILD_UI) add_subdirectory(ui) #all antares ui libs + antares simulator endif() +add_subdirectory(study) #antares study model add_subdirectory(solver) #antares solver and all associated libs add_subdirectory(analyzer) #antares analyser diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index be643ebecb..adf9825864 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -12,7 +12,6 @@ add_subdirectory(constraints-builder) add_subdirectory(expressions) add_subdirectory(hydro) add_subdirectory(infeasible-problem-analysis) -add_subdirectory(libModelObject) add_subdirectory(lps) add_subdirectory(misc) add_subdirectory(modelConverter) diff --git a/src/solver/libModelObject/CMakeLists.txt b/src/solver/libModelObject/CMakeLists.txt deleted file mode 100644 index bb489afd7e..0000000000 --- a/src/solver/libModelObject/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -project(LibObjectModel) - -set(SRC_model - library.cpp - model.cpp - - include/antares/solver/libObjectModel/library.h - include/antares/solver/libObjectModel/model.h - include/antares/solver/libObjectModel/parameter.h - include/antares/solver/libObjectModel/valueType.h - include/antares/solver/libObjectModel/variable.h - include/antares/solver/libObjectModel/constraint.h - include/antares/solver/libObjectModel/expression.h - include/antares/solver/libObjectModel/port.h - include/antares/solver/libObjectModel/portField.h - include/antares/solver/libObjectModel/portFieldDefinition.h - include/antares/solver/libObjectModel/portType.h -) - -source_group("libObjectModel" FILES ${SRC_model}) -add_library(antares-solver-libObjectModel - ${SRC_model}) -add_library(Antares::antares-solver-libObjectModel ALIAS antares-solver-libObjectModel) - -target_include_directories(antares-solver-libObjectModel - PUBLIC - $ -) -target_link_libraries(antares-solver-libObjectModel - PUBLIC -) -install(DIRECTORY include/antares - DESTINATION "include" -) diff --git a/src/solver/modelConverter/CMakeLists.txt b/src/solver/modelConverter/CMakeLists.txt index d679c3f7ff..86c97eb569 100644 --- a/src/solver/modelConverter/CMakeLists.txt +++ b/src/solver/modelConverter/CMakeLists.txt @@ -16,7 +16,7 @@ target_include_directories(modelConverter # Link dependencies (if any) target_link_libraries(modelConverter PRIVATE - Antares::antares-solver-libObjectModel + Antares::antares-study-system-model Antares::modelParser ) diff --git a/src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h b/src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h index 4d2212b749..7ca778e10d 100644 --- a/src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h +++ b/src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h @@ -1,4 +1,3 @@ - /* * Copyright 2007-2024, RTE (https://www.rte-france.com) * See AUTHORS.txt @@ -22,20 +21,20 @@ #pragma once -namespace Antares::Solver +namespace Antares { -namespace ObjectModel +namespace Study::SystemModel { class Library; } -namespace ModelParser +namespace Solver::ModelParser { class Library; } -} // namespace Antares::Solver +} // namespace Antares namespace Antares::Solver::ModelConverter { -Antares::Solver::ObjectModel::Library convert(const Antares::Solver::ModelParser::Library& library); +Antares::Study::SystemModel::Library convert(const Antares::Solver::ModelParser::Library& library); } diff --git a/src/solver/modelConverter/modelConverter.cpp b/src/solver/modelConverter/modelConverter.cpp index a103c8fcd2..b585215195 100644 --- a/src/solver/modelConverter/modelConverter.cpp +++ b/src/solver/modelConverter/modelConverter.cpp @@ -23,39 +23,38 @@ #include -#include "antares/solver/libObjectModel/constraint.h" -#include "antares/solver/libObjectModel/library.h" -#include "antares/solver/libObjectModel/model.h" -#include "antares/solver/libObjectModel/parameter.h" -#include "antares/solver/libObjectModel/port.h" -#include "antares/solver/libObjectModel/portType.h" -#include "antares/solver/libObjectModel/variable.h" #include "antares/solver/modelParser/Library.h" +#include "antares/study/system-model/constraint.h" +#include "antares/study/system-model/library.h" +#include "antares/study/system-model/model.h" +#include "antares/study/system-model/parameter.h" +#include "antares/study/system-model/port.h" +#include "antares/study/system-model/portType.h" +#include "antares/study/system-model/variable.h" namespace Antares::Solver::ModelConverter { - /** * \brief Converts parameters from ModelParser::Model to ObjectModel::Parameter. * * \param model The ModelParser::Model object containing parameters. * \return A vector of ObjectModel::Parameter objects. */ -std::vector convertTypes( +std::vector convertTypes( const Antares::Solver::ModelParser::Library& library) { - // Convert portTypes to Antares::Solver::ObjectModel::PortType - std::vector out; + // Convert portTypes to Antares::Study::SystemModel::PortType + std::vector out; for (const auto& portType: library.port_types) { - std::vector fields; + std::vector fields; for (const auto& field: portType.fields) { - fields.emplace_back(Antares::Solver::ObjectModel::PortField{field}); + fields.emplace_back(Antares::Study::SystemModel::PortField{field}); } - Antares::Solver::ObjectModel::PortType portTypeModel(portType.id, - portType.description, - std::move(fields)); + Antares::Study::SystemModel::PortType portTypeModel(portType.id, + portType.description, + std::move(fields)); out.emplace_back(std::move(portTypeModel)); } return out; @@ -68,18 +67,18 @@ std::vector convertTypes( * \return The corresponding ObjectModel::ValueType. * \throws std::runtime_error if the type is unknown. */ -std::vector convertParameters( +std::vector convertParameters( const Antares::Solver::ModelParser::Model& model) { - std::vector parameters; + std::vector parameters; for (const auto& parameter: model.parameters) { - parameters.emplace_back(Antares::Solver::ObjectModel::Parameter{ + parameters.emplace_back(Antares::Study::SystemModel::Parameter{ parameter.id, - Antares::Solver::ObjectModel::ValueType::FLOAT, // TODO: change to correct type - static_cast( + Antares::Study::SystemModel::ValueType::FLOAT, // TODO: change to correct type + static_cast( parameter.time_dependent), - static_cast( + static_cast( parameter.scenario_dependent)}); } return parameters; @@ -91,17 +90,17 @@ std::vector convertParameters( * \param model The ModelParser::Model object containing variables. * \return A vector of ObjectModel::Variable objects. */ -Antares::Solver::ObjectModel::ValueType convertType(Antares::Solver::ModelParser::ValueType type) +Antares::Study::SystemModel::ValueType convertType(Antares::Solver::ModelParser::ValueType type) { using namespace std::string_literals; switch (type) { case Antares::Solver::ModelParser::ValueType::CONTINUOUS: - return Antares::Solver::ObjectModel::ValueType::FLOAT; + return Antares::Study::SystemModel::ValueType::FLOAT; case Antares::Solver::ModelParser::ValueType::INTEGER: - return Antares::Solver::ObjectModel::ValueType::INTEGER; + return Antares::Study::SystemModel::ValueType::INTEGER; case Antares::Solver::ModelParser::ValueType::BOOL: - return Antares::Solver::ObjectModel::ValueType::BOOL; + return Antares::Study::SystemModel::ValueType::BOOL; default: throw std::runtime_error("Unknown type: " + Antares::Solver::ModelParser::toString(type)); } @@ -113,16 +112,16 @@ Antares::Solver::ObjectModel::ValueType convertType(Antares::Solver::ModelParser * \param model The ModelParser::Model object containing ports. * \return A vector of ObjectModel::Port objects. */ -std::vector convertVariables( +std::vector convertVariables( const Antares::Solver::ModelParser::Model& model) { - std::vector variables; + std::vector variables; for (const auto& variable: model.variables) { - variables.emplace_back(Antares::Solver::ObjectModel::Variable{ + variables.emplace_back(Antares::Study::SystemModel::Variable{ variable.id, - Antares::Solver::ObjectModel::Expression{variable.lower_bound}, - Antares::Solver::ObjectModel::Expression{variable.upper_bound}, + Antares::Study::SystemModel::Expression{variable.lower_bound}, + Antares::Study::SystemModel::Expression{variable.upper_bound}, convertType(variable.variable_type)}); } return variables; @@ -134,26 +133,26 @@ std::vector convertVariables( * \param model The ModelParser::Model object containing constraints. * \return A vector of ObjectModel::Constraint objects. */ -std::vector convertPorts( +std::vector convertPorts( const Antares::Solver::ModelParser::Model& model) { - std::vector ports; + std::vector ports; for (const auto& port: model.ports) { - // ports.emplace_back(Antares::Solver::ObjectModel::Port{port.name, port.type}); + // ports.emplace_back(Antares::Study::SystemModel::Port{port.name, port.type}); } return ports; } -std::vector convertConstraints( +std::vector convertConstraints( const Antares::Solver::ModelParser::Model& model) { - std::vector constraints; + std::vector constraints; for (const auto& constraint: model.constraints) { - constraints.emplace_back(Antares::Solver::ObjectModel::Constraint{ + constraints.emplace_back(Antares::Study::SystemModel::Constraint{ constraint.id, - Antares::Solver::ObjectModel::Expression{constraint.expression}}); + Antares::Study::SystemModel::Expression{constraint.expression}}); } return constraints; } @@ -164,21 +163,21 @@ std::vector convertConstraints( * \param library The ModelParser::Library object containing models. * \return A vector of ObjectModel::Model objects. */ -std::vector convertModels( +std::vector convertModels( const Antares::Solver::ModelParser::Library& library) { - std::vector models; + std::vector models; for (const auto& model: library.models) { - Antares::Solver::ObjectModel::ModelBuilder modelBuilder; - std::vector parameters = convertParameters(model); - std::vector variables = convertVariables(model); - std::vector ports = convertPorts(model); - std::vector constraints = convertConstraints( + Antares::Study::SystemModel::ModelBuilder modelBuilder; + std::vector parameters = convertParameters(model); + std::vector variables = convertVariables(model); + std::vector ports = convertPorts(model); + std::vector constraints = convertConstraints( model); auto modelObj = modelBuilder.withId(model.id) - .withObjective(Antares::Solver::ObjectModel::Expression{model.objective}) + .withObjective(Antares::Study::SystemModel::Expression{model.objective}) .withParameters(std::move(parameters)) .withVariables(std::move(variables)) .withPorts(std::move(ports)) @@ -195,17 +194,16 @@ std::vector convertModels( * \param library The ModelParser::Library object to convert. * \return The corresponding ObjectModel::Library object. */ -Antares::Solver::ObjectModel::Library convert(const Antares::Solver::ModelParser::Library& library) +Antares::Study::SystemModel::Library convert(const Antares::Solver::ModelParser::Library& library) { - Antares::Solver::ObjectModel::LibraryBuilder builder; - std::vector portTypes = convertTypes(library); - std::vector models = convertModels(library); - Antares::Solver::ObjectModel::Library lib = builder.withId(library.id) - .withDescription(library.description) - .withPortTypes(std::move(portTypes)) - .withModels(std::move(models)) - .build(); + Antares::Study::SystemModel::LibraryBuilder builder; + std::vector portTypes = convertTypes(library); + std::vector models = convertModels(library); + Antares::Study::SystemModel::Library lib = builder.withId(library.id) + .withDescription(library.description) + .withPortTypes(std::move(portTypes)) + .withModels(std::move(models)) + .build(); return lib; } - } // namespace Antares::Solver::ModelConverter diff --git a/src/study/CMakeLists.txt b/src/study/CMakeLists.txt new file mode 100644 index 0000000000..9d14fd756e --- /dev/null +++ b/src/study/CMakeLists.txt @@ -0,0 +1,3 @@ +OMESSAGE("Antares Study") + +add_subdirectory(system-model) \ No newline at end of file diff --git a/src/study/system-model/CMakeLists.txt b/src/study/system-model/CMakeLists.txt new file mode 100644 index 0000000000..b497026127 --- /dev/null +++ b/src/study/system-model/CMakeLists.txt @@ -0,0 +1,33 @@ +project(SystemModel) + +set(SRC_model + library.cpp + model.cpp + include/antares/study/system-model/library.h + include/antares/study/system-model/model.h + include/antares/study/system-model/parameter.h + include/antares/study/system-model/valueType.h + include/antares/study/system-model/variable.h + include/antares/study/system-model/constraint.h + include/antares/study/system-model/expression.h + include/antares/study/system-model/port.h + include/antares/study/system-model/portField.h + include/antares/study/system-model/portFieldDefinition.h + include/antares/study/system-model/portType.h +) + +source_group("SystemModel" FILES ${SRC_model}) +add_library(antares-study-system-model + ${SRC_model}) +add_library(Antares::antares-study-system-model ALIAS antares-study-system-model) + +target_include_directories(antares-study-system-model + PUBLIC + $ +) +target_link_libraries(antares-study-system-model + PUBLIC +) +install(DIRECTORY include/antares + DESTINATION "include" +) diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/constraint.h b/src/study/system-model/include/antares/study/system-model/constraint.h similarity index 94% rename from src/solver/libModelObject/include/antares/solver/libObjectModel/constraint.h rename to src/study/system-model/include/antares/study/system-model/constraint.h index 5a66ee8571..eb7777f484 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/constraint.h +++ b/src/study/system-model/include/antares/study/system-model/constraint.h @@ -25,7 +25,7 @@ #include "expression.h" #include "parameter.h" -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { /// A constraint linking variables and parameters of a model together @@ -53,4 +53,4 @@ class Constraint Expression expression_; }; -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/expression.h b/src/study/system-model/include/antares/study/system-model/expression.h similarity index 93% rename from src/solver/libModelObject/include/antares/solver/libObjectModel/expression.h rename to src/study/system-model/include/antares/study/system-model/expression.h index 87fefbc8c5..6924401e68 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/expression.h +++ b/src/study/system-model/include/antares/study/system-model/expression.h @@ -22,7 +22,7 @@ #include -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { class Expression @@ -44,4 +44,4 @@ class Expression std::string value_; }; -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/library.h b/src/study/system-model/include/antares/study/system-model/library.h similarity index 96% rename from src/solver/libModelObject/include/antares/solver/libObjectModel/library.h rename to src/study/system-model/include/antares/study/system-model/library.h index 1be9d63815..a056731156 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/library.h +++ b/src/study/system-model/include/antares/study/system-model/library.h @@ -26,7 +26,7 @@ #include "model.h" #include "portType.h" -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { /// A library is a collection of models @@ -85,4 +85,4 @@ class LibraryBuilder Library library_; }; -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/model.h b/src/study/system-model/include/antares/study/system-model/model.h similarity index 96% rename from src/solver/libModelObject/include/antares/solver/libObjectModel/model.h rename to src/study/system-model/include/antares/study/system-model/model.h index c76b22cd35..8f19d424c1 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/model.h +++ b/src/study/system-model/include/antares/study/system-model/model.h @@ -29,7 +29,7 @@ #include "port.h" #include "variable.h" -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { /** @@ -96,4 +96,4 @@ class ModelBuilder Model model_; }; -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/parameter.h b/src/study/system-model/include/antares/study/system-model/parameter.h similarity index 96% rename from src/solver/libModelObject/include/antares/solver/libObjectModel/parameter.h rename to src/study/system-model/include/antares/study/system-model/parameter.h index ec25ff632e..4daa3d2b94 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/parameter.h +++ b/src/study/system-model/include/antares/study/system-model/parameter.h @@ -24,7 +24,7 @@ #include "valueType.h" -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { /** @@ -90,4 +90,4 @@ class Parameter ScenarioDependent scenarioDependent_ = ScenarioDependent::YES; // optional at construction }; -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/port.h b/src/study/system-model/include/antares/study/system-model/port.h similarity index 93% rename from src/solver/libModelObject/include/antares/solver/libObjectModel/port.h rename to src/study/system-model/include/antares/study/system-model/port.h index da8dc3d99f..a18f3711f9 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/port.h +++ b/src/study/system-model/include/antares/study/system-model/port.h @@ -24,7 +24,7 @@ #include "portType.h" -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { class Port @@ -45,4 +45,4 @@ class Port PortType type_; }; -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/portField.h b/src/study/system-model/include/antares/study/system-model/portField.h similarity index 93% rename from src/solver/libModelObject/include/antares/solver/libObjectModel/portField.h rename to src/study/system-model/include/antares/study/system-model/portField.h index 78325db1af..4da2af8bc0 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/portField.h +++ b/src/study/system-model/include/antares/study/system-model/portField.h @@ -22,7 +22,7 @@ #include -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { class PortField @@ -42,4 +42,4 @@ class PortField std::string id_; }; -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/portFieldDefinition.h b/src/study/system-model/include/antares/study/system-model/portFieldDefinition.h similarity index 93% rename from src/solver/libModelObject/include/antares/solver/libObjectModel/portFieldDefinition.h rename to src/study/system-model/include/antares/study/system-model/portFieldDefinition.h index 9e22622d89..80f4318780 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/portFieldDefinition.h +++ b/src/study/system-model/include/antares/study/system-model/portFieldDefinition.h @@ -23,7 +23,7 @@ #include "port.h" #include "portType.h" -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { class PortFieldDefinition @@ -37,4 +37,4 @@ class PortFieldDefinition Expression definition_; }; -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/portType.h b/src/study/system-model/include/antares/study/system-model/portType.h similarity index 94% rename from src/solver/libModelObject/include/antares/solver/libObjectModel/portType.h rename to src/study/system-model/include/antares/study/system-model/portType.h index 8fbfb15dca..907d5a33fd 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/portType.h +++ b/src/study/system-model/include/antares/study/system-model/portType.h @@ -25,7 +25,7 @@ #include "portField.h" -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { class PortType @@ -62,4 +62,4 @@ class PortType std::vector fields_; }; -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/valueType.h b/src/study/system-model/include/antares/study/system-model/valueType.h similarity index 92% rename from src/solver/libModelObject/include/antares/solver/libObjectModel/valueType.h rename to src/study/system-model/include/antares/study/system-model/valueType.h index d8921fb7dc..17d798d096 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/valueType.h +++ b/src/study/system-model/include/antares/study/system-model/valueType.h @@ -22,7 +22,7 @@ #include #include -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { /// Type of value held by variables or parameters @@ -33,4 +33,4 @@ enum class ValueType BOOL }; -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/include/antares/solver/libObjectModel/variable.h b/src/study/system-model/include/antares/study/system-model/variable.h similarity index 94% rename from src/solver/libModelObject/include/antares/solver/libObjectModel/variable.h rename to src/study/system-model/include/antares/study/system-model/variable.h index 44d5762b1d..ad9011df79 100644 --- a/src/solver/libModelObject/include/antares/solver/libObjectModel/variable.h +++ b/src/study/system-model/include/antares/study/system-model/variable.h @@ -23,10 +23,9 @@ #include #include "expression.h" -#include "parameter.h" #include "valueType.h" -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { /// A decision variable of the model @@ -68,4 +67,4 @@ class Variable Expression upperBound_; }; -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/library.cpp b/src/study/system-model/library.cpp similarity index 95% rename from src/solver/libModelObject/library.cpp rename to src/study/system-model/library.cpp index c531cd223d..e7026afd86 100644 --- a/src/solver/libModelObject/library.cpp +++ b/src/study/system-model/library.cpp @@ -19,14 +19,14 @@ * along with Antares_Simulator. If not, see . */ -#include "antares/solver/libObjectModel/library.h" +#include "antares/study/system-model/library.h" #include #include #include #include -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { /** @@ -98,4 +98,4 @@ Library LibraryBuilder::build() { return library_; } -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/solver/libModelObject/model.cpp b/src/study/system-model/model.cpp similarity index 96% rename from src/solver/libModelObject/model.cpp rename to src/study/system-model/model.cpp index bfb79e6882..5870840d73 100644 --- a/src/solver/libModelObject/model.cpp +++ b/src/study/system-model/model.cpp @@ -24,9 +24,9 @@ #include #include -#include +#include -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { /** @@ -135,4 +135,4 @@ ModelBuilder& ModelBuilder::withConstraints(std::vector&& constraint return *this; } -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel diff --git a/src/tests/src/solver/modelParser/CMakeLists.txt b/src/tests/src/solver/modelParser/CMakeLists.txt index e694d66126..57f733030c 100644 --- a/src/tests/src/solver/modelParser/CMakeLists.txt +++ b/src/tests/src/solver/modelParser/CMakeLists.txt @@ -15,7 +15,7 @@ target_link_libraries(TestModelParser Boost::unit_test_framework Antares::modelConverter Antares::modelParser - Antares::antares-solver-libObjectModel + Antares::antares-study-system-model ) # Storing test-toybox under the folder Unit-tests in the IDE diff --git a/src/tests/src/solver/modelParser/enum_operators.h b/src/tests/src/solver/modelParser/enum_operators.h index eaf55c5543..bceca0f519 100644 --- a/src/tests/src/solver/modelParser/enum_operators.h +++ b/src/tests/src/solver/modelParser/enum_operators.h @@ -1,4 +1,3 @@ - /* * Copyright 2007-2024, RTE (https://www.rte-france.com) * See AUTHORS.txt @@ -24,10 +23,10 @@ #include #include -#include "antares/solver/libObjectModel/valueType.h" #include "antares/solver/modelParser/Library.h" +#include "antares/study/system-model/valueType.h" -namespace Antares::Solver::ObjectModel +namespace Antares::Study::SystemModel { inline std::ostream& operator<<(std::ostream& os, const ValueType& value_type) { @@ -49,7 +48,7 @@ inline std::ostream& operator<<(std::ostream& os, const ValueType& value_type) } return os; } -} // namespace Antares::Solver::ObjectModel +} // namespace Antares::Study::SystemModel namespace Antares::Solver::ModelParser { diff --git a/src/tests/src/solver/modelParser/testModelTranslator.cpp b/src/tests/src/solver/modelParser/testModelTranslator.cpp index 8f0e5aff19..a22955b5db 100644 --- a/src/tests/src/solver/modelParser/testModelTranslator.cpp +++ b/src/tests/src/solver/modelParser/testModelTranslator.cpp @@ -25,19 +25,20 @@ #include -#include "antares/solver/libObjectModel/library.h" #include "antares/solver/modelConverter/modelConverter.h" #include "antares/solver/modelParser/Library.h" +#include "antares/study/system-model/library.h" #include "enum_operators.h" using namespace Antares::Solver; +using namespace Antares::Study; // Test empty library BOOST_AUTO_TEST_CASE(Empty_library_is_valid) { ModelParser::Library library; - ObjectModel::Library lib = ModelConverter::convert(library); + SystemModel::Library lib = ModelConverter::convert(library); BOOST_CHECK(lib.Id().empty()); BOOST_CHECK(lib.Description().empty()); BOOST_CHECK(lib.PortTypes().empty()); @@ -50,7 +51,7 @@ BOOST_AUTO_TEST_CASE(library_id_description_properly_translated) ModelParser::Library library; library.id = "test_id"; library.description = "test_description"; - ObjectModel::Library lib = ModelConverter::convert(library); + SystemModel::Library lib = ModelConverter::convert(library); BOOST_CHECK_EQUAL(lib.Id(), "test_id"); BOOST_CHECK_EQUAL(lib.Description(), "test_description"); } @@ -62,7 +63,7 @@ BOOST_AUTO_TEST_CASE(port_type_with_empty_fileds_properly_translated) ModelParser::PortType portType1{"port1", "flow port", {}}; ModelParser::PortType portType2{"port2", "impedance port", {}}; library.port_types = {portType1, portType2}; - ObjectModel::Library lib = ModelConverter::convert(library); + SystemModel::Library lib = ModelConverter::convert(library); BOOST_REQUIRE_EQUAL(lib.PortTypes().size(), 2); BOOST_CHECK_EQUAL(lib.PortTypes().at("port1").Id(), "port1"); BOOST_CHECK_EQUAL(lib.PortTypes().at("port1").Description(), "flow port"); @@ -86,7 +87,7 @@ BOOST_AUTO_TEST_CASE(portType_with_fields_properly_translated) ModelParser::PortType portType1{"port1", "flow port", {"field1", "field2"}}; ModelParser::PortType portType2{"port2", "impedance port", {"field3", "field4"}}; library.port_types = {portType1, portType2}; - ObjectModel::Library lib = ModelConverter::convert(library); + SystemModel::Library lib = ModelConverter::convert(library); BOOST_REQUIRE_EQUAL(lib.PortTypes().at("port1").Fields().size(), 2); BOOST_CHECK_EQUAL(lib.PortTypes().at("port1").Fields()[0].Id(), "field1"); BOOST_CHECK_EQUAL(lib.PortTypes().at("port1").Fields()[1].Id(), "field2"); @@ -108,7 +109,7 @@ BOOST_AUTO_TEST_CASE(empty_model_properly_translated) .constraints = {}, .objective = "objectives"}; library.models = {model1}; - ObjectModel::Library lib = ModelConverter::convert(library); + SystemModel::Library lib = ModelConverter::convert(library); BOOST_REQUIRE_EQUAL(lib.Models().size(), 1); BOOST_CHECK_EQUAL(lib.Models().at("model1").Id(), "model1"); BOOST_CHECK_EQUAL(lib.Models().at("model1").Objective().Value(), "objectives"); @@ -127,7 +128,7 @@ BOOST_AUTO_TEST_CASE(model_parameters_properly_translated) .constraints{}, .objective = "objectives"}; library.models = {model1}; - ObjectModel::Library lib = ModelConverter::convert(library); + SystemModel::Library lib = ModelConverter::convert(library); auto& model = lib.Models().at("model1"); BOOST_REQUIRE_EQUAL(model.Parameters().size(), 2); auto& parameter1 = model.Parameters().at("param1"); @@ -135,11 +136,11 @@ BOOST_AUTO_TEST_CASE(model_parameters_properly_translated) BOOST_CHECK_EQUAL(parameter1.Id(), "param1"); BOOST_CHECK(parameter1.isTimeDependent()); BOOST_CHECK(!parameter1.isScenarioDependent()); - BOOST_CHECK_EQUAL(parameter1.Type(), ObjectModel::ValueType::FLOAT); + BOOST_CHECK_EQUAL(parameter1.Type(), SystemModel::ValueType::FLOAT); BOOST_CHECK_EQUAL(parameter2.Id(), "param2"); BOOST_CHECK(!parameter2.isTimeDependent()); BOOST_CHECK(!parameter2.isScenarioDependent()); - BOOST_CHECK_EQUAL(parameter2.Type(), ObjectModel::ValueType::FLOAT); + BOOST_CHECK_EQUAL(parameter2.Type(), SystemModel::ValueType::FLOAT); } // Test library with models and variables @@ -157,7 +158,7 @@ BOOST_AUTO_TEST_CASE(model_variables_properly_translated) .constraints = {}, .objective = "objectives"}; library.models = {model1}; - ObjectModel::Library lib = ModelConverter::convert(library); + SystemModel::Library lib = ModelConverter::convert(library); auto& model = lib.Models().at("model1"); BOOST_REQUIRE_EQUAL(model.Variables().size(), 2); auto& variable1 = model.Variables().at("var1"); @@ -165,11 +166,11 @@ BOOST_AUTO_TEST_CASE(model_variables_properly_translated) BOOST_CHECK_EQUAL(variable1.Id(), "var1"); BOOST_CHECK_EQUAL(variable1.LowerBound().Value(), "7"); BOOST_CHECK_EQUAL(variable1.UpperBound().Value(), "pmax"); - BOOST_CHECK_EQUAL(variable1.Type(), ObjectModel::ValueType::BOOL); + BOOST_CHECK_EQUAL(variable1.Type(), SystemModel::ValueType::BOOL); BOOST_CHECK_EQUAL(variable2.Id(), "var2"); BOOST_CHECK_EQUAL(variable2.LowerBound().Value(), "99999999.9999999"); BOOST_CHECK_EQUAL(variable2.UpperBound().Value(), "vcost"); - BOOST_CHECK_EQUAL(variable2.Type(), ObjectModel::ValueType::INTEGER); + BOOST_CHECK_EQUAL(variable2.Type(), SystemModel::ValueType::INTEGER); } // Test library with models and ports @@ -185,7 +186,7 @@ BOOST_AUTO_TEST_CASE(model_ports_properly_translated, *boost::unit_test::disable .constraints = {}, .objective = "objectives"}; library.models = {model1}; - ObjectModel::Library lib = ModelConverter::convert(library); + SystemModel::Library lib = ModelConverter::convert(library); auto& model = lib.Models().at("model1"); // BOOST_REQUIRE_EQUAL(model.Ports().size(), 2); // auto& port1 = model.Ports().at("port1"); @@ -210,7 +211,7 @@ BOOST_AUTO_TEST_CASE(model_constraints_properly_translated) {"constraint2", "expression2"}}, .objective = "objectives"}; library.models = {model1}; - ObjectModel::Library lib = ModelConverter::convert(library); + SystemModel::Library lib = ModelConverter::convert(library); auto& model = lib.Models().at("model1"); BOOST_REQUIRE_EQUAL(model.getConstraints().size(), 2); auto& constraint1 = model.getConstraints().at("constraint1"); @@ -245,7 +246,7 @@ BOOST_AUTO_TEST_CASE(multiple_models_properly_translated) .constraints = {}, .objective = "objectives"}; library.models = {model1, model2}; - ObjectModel::Library lib = ModelConverter::convert(library); + SystemModel::Library lib = ModelConverter::convert(library); BOOST_REQUIRE_EQUAL(lib.Models().size(), 2); auto& modelo1 = lib.Models().at("model1"); BOOST_REQUIRE_EQUAL(modelo1.Parameters().size(), 2); diff --git a/src/tests/src/solver/modelParser/test_full.cpp b/src/tests/src/solver/modelParser/test_full.cpp index a2a7316192..71824c692d 100644 --- a/src/tests/src/solver/modelParser/test_full.cpp +++ b/src/tests/src/solver/modelParser/test_full.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2007-2024, RTE (https://www.rte-france.com) * See AUTHORS.txt @@ -26,21 +25,22 @@ #include -#include "antares/solver/libObjectModel/library.h" #include "antares/solver/modelConverter/modelConverter.h" #include "antares/solver/modelParser/Library.h" #include "antares/solver/modelParser/parser.h" +#include "antares/study/system-model/library.h" #include "enum_operators.h" using namespace std::string_literals; using namespace Antares::Solver; +using namespace Antares::Study; -void checkParameter(const ObjectModel::Parameter& parameter, +void checkParameter(const SystemModel::Parameter& parameter, const std::string& name, bool timeDependent, bool scenarioDependent, - ObjectModel::ValueType type) + SystemModel::ValueType type) { std::cout << "Parameter: " << parameter.Id() << std::endl; BOOST_CHECK_EQUAL(parameter.Id(), name); @@ -49,11 +49,11 @@ void checkParameter(const ObjectModel::Parameter& parameter, BOOST_CHECK_EQUAL(parameter.Type(), type); } -void checkVariable(const ObjectModel::Variable& variable, +void checkVariable(const SystemModel::Variable& variable, const std::string& name, const std::string& lowerBound, const std::string& upperBound, - ObjectModel::ValueType type) + SystemModel::ValueType type) { std::cout << "Variable: " << variable.Id() << std::endl; BOOST_CHECK_EQUAL(variable.Id(), name); @@ -62,7 +62,7 @@ void checkVariable(const ObjectModel::Variable& variable, BOOST_CHECK_EQUAL(variable.Type(), type); } -void checkConstraint(const ObjectModel::Constraint& constraint, +void checkConstraint(const SystemModel::Constraint& constraint, const std::string& name, const std::string& expression) { @@ -263,7 +263,7 @@ BOOST_AUTO_TEST_CASE(test_full) { ModelParser::Parser parser; ModelParser::Library libraryObj = parser.parse(library); - ObjectModel::Library lib = ModelConverter::convert(libraryObj); + SystemModel::Library lib = ModelConverter::convert(libraryObj); BOOST_CHECK_EQUAL(lib.Id(), "basic"); BOOST_CHECK_EQUAL(lib.Description(), "Basic library"); @@ -291,18 +291,18 @@ BOOST_AUTO_TEST_CASE(test_full) "cost", false, false, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model0.Parameters().at("p_max"), "p_max", false, false, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkVariable(model0.Variables().at("generation"), "generation", "0", "p_max", - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); // auto& port = model0.Ports().at("injection_port"); // BOOST_CHECK_EQUAL(port.Id(), "injection_port"); @@ -328,12 +328,12 @@ BOOST_AUTO_TEST_CASE(test_full) "cost", false, false, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkVariable(model2.Variables().at("spillage"), "spillage", "0", "", - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); auto& model3 = lib.Models().at("unsupplied"); BOOST_CHECK_EQUAL(model3.Id(), "unsupplied"); @@ -346,12 +346,12 @@ BOOST_AUTO_TEST_CASE(test_full) "cost", false, false, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkVariable(model3.Variables().at("unsupplied_energy"), "unsupplied_energy", "0", "", - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); auto& model4 = lib.Models().at("demand"); BOOST_CHECK_EQUAL(model4.Id(), "demand"); @@ -364,7 +364,7 @@ BOOST_AUTO_TEST_CASE(test_full) "demand", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); auto& model5 = lib.Models().at("short-term-storage"); BOOST_CHECK_EQUAL(model5.Id(), "short-term-storage"); @@ -377,47 +377,47 @@ BOOST_AUTO_TEST_CASE(test_full) "efficiency", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model5.Parameters().at("level_min"), "level_min", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model5.Parameters().at("level_max"), "level_max", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model5.Parameters().at("p_max_withdrawal"), "p_max_withdrawal", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model5.Parameters().at("p_max_injection"), "p_max_injection", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model5.Parameters().at("inflows"), "inflows", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkVariable(model5.Variables().at("injection"), "injection", "0", "p_max_injection", - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkVariable(model5.Variables().at("withdrawal"), "withdrawal", "0", "p_max_withdrawal", - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkVariable(model5.Variables().at("level"), "level", "level_min", "level_max", - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkConstraint(model5.getConstraints().at("Level equation"), "Level equation", "level[t] - level[t-1] - efficiency * injection + withdrawal = inflows"); @@ -433,57 +433,57 @@ BOOST_AUTO_TEST_CASE(test_full) "cost", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model6.Parameters().at("p_min"), "p_min", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model6.Parameters().at("p_max"), "p_max", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model6.Parameters().at("d_min_up"), "d_min_up", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model6.Parameters().at("d_min_down"), "d_min_down", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model6.Parameters().at("nb_units_max"), "nb_units_max", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkParameter(model6.Parameters().at("nb_failures"), "nb_failures", true, true, - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkVariable(model6.Variables().at("generation"), "generation", "0", "nb_units_max * p_max", - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkVariable(model6.Variables().at("nb_on"), "nb_on", "0", "nb_units_max", - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkVariable(model6.Variables().at("nb_stop"), "nb_stop", "0", "nb_units_max", - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkVariable(model6.Variables().at("nb_start"), "nb_start", "0", "nb_units_max", - ObjectModel::ValueType::FLOAT); + SystemModel::ValueType::FLOAT); checkConstraint(model6.getConstraints().at("Max generation"), "Max generation", "generation <= nb_on * p_max"); From 743e0793289002937012df6259360d8d5e9e2443 Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Fri, 22 Nov 2024 15:59:55 +0100 Subject: [PATCH 056/103] Add new solver documentation (#2473) Signed-off-by: Peter Mitri --- .github/workflows/build-userguide.yml | 1 - docs/README.md | 12 +- docs/developer-guide/6-Contributing.md | 8 +- .../Dynamic-modeler-architecture.md | 131 ++++++++ docs/stylesheets/extra.css | 18 +- docs/user-guide/01-overview.md | 8 +- docs/user-guide/02-install.md | 14 +- docs/user-guide/03-getting_started.md | 6 +- docs/user-guide/solver/00-index.md | 14 +- docs/user-guide/solver/01-overview-solver.md | 77 +---- ...{08-command-line.md => 02-command-line.md} | 44 +-- docs/user-guide/solver/03-appendix.md | 315 ++++++++++++++++++ docs/user-guide/solver/09-appendix.md | 217 ------------ .../solver/dynamic-modeler/00-index.md | 15 + .../01-overview-dynamic-modeler.md | 13 + .../solver/dynamic-modeler/02-inputs.md | 3 + .../solver/dynamic-modeler/03-outputs.md | 3 + .../solver/dynamic-modeler/04-parameters.md | 3 + .../solver/dynamic-modeler/05-model.md | 78 +++++ .../solver/dynamic-modeler/06-heuristics.md | 3 + .../dynamic-modeler/07-standard-library.md | 3 + .../dynamic-modeler/08-hybrid-studies.md | 3 + .../optional-features/multi-threading.md | 6 +- .../solver/static-modeler/00-index.md | 14 + .../01-overview-static-modeler.md | 64 ++++ .../solver/{ => static-modeler}/02-inputs.md | 20 +- .../solver/{ => static-modeler}/03-outputs.md | 4 +- .../{ => static-modeler}/04-parameters.md | 28 +- .../solver/{ => static-modeler}/05-model.md | 12 +- .../06-hydro-heuristics.md | 0 .../07-thermal-heuristic.md | 18 +- .../ts-generator/01-overview-tsgenerator.md | 4 +- docs/user-guide/ts-generator/04-parameters.md | 2 +- mkdocs.yml | 127 ++++--- requirements-doc.txt | 1 + 35 files changed, 851 insertions(+), 438 deletions(-) create mode 100644 docs/developer-guide/Architecture/Dynamic-modeler-architecture.md rename docs/user-guide/solver/{08-command-line.md => 02-command-line.md} (73%) create mode 100644 docs/user-guide/solver/03-appendix.md delete mode 100644 docs/user-guide/solver/09-appendix.md create mode 100644 docs/user-guide/solver/dynamic-modeler/00-index.md create mode 100644 docs/user-guide/solver/dynamic-modeler/01-overview-dynamic-modeler.md create mode 100644 docs/user-guide/solver/dynamic-modeler/02-inputs.md create mode 100644 docs/user-guide/solver/dynamic-modeler/03-outputs.md create mode 100644 docs/user-guide/solver/dynamic-modeler/04-parameters.md create mode 100644 docs/user-guide/solver/dynamic-modeler/05-model.md create mode 100644 docs/user-guide/solver/dynamic-modeler/06-heuristics.md create mode 100644 docs/user-guide/solver/dynamic-modeler/07-standard-library.md create mode 100644 docs/user-guide/solver/dynamic-modeler/08-hybrid-studies.md create mode 100644 docs/user-guide/solver/static-modeler/00-index.md create mode 100644 docs/user-guide/solver/static-modeler/01-overview-static-modeler.md rename docs/user-guide/solver/{ => static-modeler}/02-inputs.md (98%) rename docs/user-guide/solver/{ => static-modeler}/03-outputs.md (99%) rename docs/user-guide/solver/{ => static-modeler}/04-parameters.md (96%) rename docs/user-guide/solver/{ => static-modeler}/05-model.md (98%) rename docs/user-guide/solver/{ => static-modeler}/06-hydro-heuristics.md (100%) rename docs/user-guide/solver/{ => static-modeler}/07-thermal-heuristic.md (85%) diff --git a/.github/workflows/build-userguide.yml b/.github/workflows/build-userguide.yml index 599fdbd663..a12c034072 100644 --- a/.github/workflows/build-userguide.yml +++ b/.github/workflows/build-userguide.yml @@ -75,4 +75,3 @@ jobs: tag: ${{ github.event.inputs.release_tag }} run: | gh release upload "$tag" ${{ env.PDF_PATH }} - diff --git a/docs/README.md b/docs/README.md index 49c350d844..c2774db3c2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -60,19 +60,19 @@ In every *Antares Simulator* [release](https://github.com/AntaresSimulatorTeam/A the user guide is printed to a PDF file and published in the assets. This document can be downloaded by users who want to install *Antares Simulator* and be able to consult its documentation off-line. -In practice, the PDF is generated automatically from Markdown files under [reference-guide](./user-guide) by +In practice, the PDF is generated automatically from Markdown files under [user-guide](./user-guide) by [Sphinx](https://www.sphinx-doc.org/) (using LaTeX). The script for this generation is in [pdf-doc-generation-with-sphinx/create_pdf_doc.sh](./pdf-doc-generation-with-sphinx/create_pdf_doc.sh); it is automatically run by a GitHub [action](../.github/workflows/build-userguide.yml) during every release, and for each pull request (in order to verify that the PDF builds). While the source material used for the PDF user guide are the same as the ones used for the mkdocs website (i.e. -Markdown files under `reference-guide`), some extra source files are needed: +Markdown files under `user-guide`), some extra source files are needed: - As for all Sphinx projects, this one needs a configuration file: [conf.py](./pdf-doc-generation-with-sphinx/source/conf.py). This file allows you to customize the Sphinx build, in the same way mkdoks.yml allows you to customize mkdocs build. - Sphinx navigation is built iteratively, using "index" files that refer to each other. The top-most index file is [pdf-doc-generation-with-sphinx/source/index.rst](./pdf-doc-generation-with-sphinx/source/index.rst). It points to - [reference-guide/00-index.md](user-guide/00-index.md), which in turns points to other pages or indexes, - defining the whole navigation tree of the documentation. **This [reference-guide/00-index.md](user-guide/00-index.md) + [user-guide/00-index.md](user-guide/00-index.md), which in turns points to other pages or indexes, + defining the whole navigation tree of the documentation. **This [user-guide/00-index.md](user-guide/00-index.md) file should be updated** in the same way mkdocs.yml is, in order to keep the navigation tree of the PDF document synchronized with the navigation tree of the mkdocs website. @@ -80,9 +80,9 @@ When modifying the user guide content, you can easily preview the resulting PDF root of the project and running: ```bash cd docs/pdf-doc-generation-with-sphinx -bash create_pdf_doc.sh reference-guide.pdf +bash create_pdf_doc.sh user-guide.pdf ``` -Sphinx will create a `reference-guide.pdf` file in `docs/pdf-doc-generation-with-sphinx`. +Sphinx will create a `user-guide.pdf` file in `docs/pdf-doc-generation-with-sphinx`. ### Doxygen [//]: # (TODO) diff --git a/docs/developer-guide/6-Contributing.md b/docs/developer-guide/6-Contributing.md index 977a2860b8..cae411dbdb 100644 --- a/docs/developer-guide/6-Contributing.md +++ b/docs/developer-guide/6-Contributing.md @@ -2,7 +2,7 @@ In general, [Google's coding standard](https://google.github.io/styleguide/cppguide.html) is used, and we strongly encourage to read it. -You can find all the steps needed to build & install Antares Simulator in the [documentation website](https://antares-simulator.readthedocs.io/) or [its sources](docs/developer-guide/0-Introduction.md). +You can find all the steps needed to build & install Antares Simulator in the [documentation website](https://antares-simulator.readthedocs.io/) or [its sources](https://github.com/AntaresSimulatorTeam/Antares_Simulator). Below are our specific (but not all!) exceptions to the Google's coding standard: @@ -19,7 +19,7 @@ Below are our specific (but not all!) exceptions to the Google's coding standard Naming and formatting - We ALWAYS use 4 spaces indent and don't use tabs. -- We don't have strict limits on line width, but keep it reasonable to fit on the screen. The advised width is that written in the [src/.clang-format](src/.clang-format) file (currently 100). +- We don't have strict limits on line width, but keep it reasonable to fit on the screen. The advised width is that written in the [src/.clang-format](https://github.com/AntaresSimulatorTeam/Antares_Simulator/blob/develop/src/.clang-format) file (currently 100). - Doxygen-style comments can be used. - Use left-to-right order for variables/params: `const string& s` (reference to the const string). - In one line `if`, `for`, `while` we use brackets. @@ -74,7 +74,7 @@ The description should be short but proportional to the length or complexity of When a pull request is opened, please set it to draft if it is still being worked on or not ready for review. If your Pull Request changes a part of the code that is [documented](https://antares-simulator.readthedocs.io/), -please update the documentation also, in the ["docs"](docs) directory. +please update the documentation also, in the ["docs"](https://github.com/AntaresSimulatorTeam/Antares_Simulator/tree/develop/docs) directory. ## ClangFormat @@ -85,7 +85,7 @@ To automatically format a file, install `clang-format` and run: clang-format 18.1.3 is the reference version, but any 18.x version should work as well. We strongly advise that you configure your IDE / text editor to automatically format code according to the clang-format style. Non-conforming code can't be merged to the develop branch. -You may also use script [src/format-code.sh](src/format-code.sh) to format all the code. Generated code (ANTLR, etc.) won't be automatically formatted. +You may also use script [src/format-code.sh](https://github.com/AntaresSimulatorTeam/Antares_Simulator/blob/develop/src/format-code.sh) to format all the code. Generated code (ANTLR, etc.) won't be automatically formatted. ## Formatting Example/Guide/Reference diff --git a/docs/developer-guide/Architecture/Dynamic-modeler-architecture.md b/docs/developer-guide/Architecture/Dynamic-modeler-architecture.md new file mode 100644 index 0000000000..17ce09800e --- /dev/null +++ b/docs/developer-guide/Architecture/Dynamic-modeler-architecture.md @@ -0,0 +1,131 @@ +# Dynamic modeler architecture + +## Models +(for details about these concepts, see [this page](../../user-guide/solver/dynamic-modeler/05-model.md)) + +```plantuml +@startuml + +class Model { ++ string id ++ Expression objective ++ map parameters ++ map variables ++ map constraints ++ map ports +} +Model "1" *-- "0:N" Parameter +Model "1" *-- "0:N" Variable +Model "1" *-- "0:N" Constraint +Model "1" *-- "0:N" Port +Model --> Expression + +class Parameter { ++ string id ++ ValueType type ++ bool timeDependent ++ bool scenarioDependent +} +Parameter "N" *-- "1" ValueType + +enum ValueType { +FLOAT +INTEGER +BOOL +} + +class Variable { ++ string id ++ ValueType type ++ Expression lowerBound ++ Expression upperBound +} +Variable "N" *-- "1" ValueType +Variable --> Expression + +class Constraint { ++ string id ++ Expression expression +} +Constraint --> Expression + +class Port { ++ string id ++ PortType type +} +Port "N" *-- "1" PortType + +class PortType { ++ id ++ vector fields +} +PortType "1" *-- "1:N" PortField + +class PortField { ++ string id +} + +class Expression { ++ string textualRepresentation ++ Node nodeRepresentation +} + +class ModelLibrary { ++ string id ++ map models +} +ModelLibrary "1" *-- "1:N" Model + +class ModelLibraryRepository { ++ map modelLibraries +} +ModelLibraryRepository "1" *-- "0:N" ModelLibrary + +@enduml +``` + +## Components +(for details about these concepts, see [this page](../../user-guide/solver/dynamic-modeler/05-model.md)) + +```plantuml +@startuml + +class Model { ++ string id ++ Expression objective ++ map parameters ++ map variables ++ map constraints ++ map ports +} + +class Component { ++ string id ++ Model model ++ string scenarioGroup ++ map parameterValues +} +Component "0:N" *-- "1" Model +Component --> Expression + +class Expression { ++ string textualRepresentation ++ Node nodeRepresentation +} + +class PortConnection { ++ string component1Id ++ string port1Id ++ string component2Id ++ string port2Id +} + +class System { ++ map components ++ vector portConnections +} +System "1" *-- "1:N" Component +System "1" *-- "0:N" PortConnection + +@enduml +``` \ No newline at end of file diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index a4abde6c67..1b6449c19a 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -1,21 +1,29 @@ -[data-md-color-scheme="antares"] { - --md-primary-fg-color: #002a5e; +[data-md-color-scheme="default"] { + --md-primary-fg-color: #002a5e; --md-primary-fg-color--light: #00a3ca; - --md-primary-fg-color--dark: #112446; - --md-typeset-a-color: #00a3ca; /* text link color*/ + --md-primary-fg-color--dark: #112446; + --md-typeset-a-color: #00a3ca; /* text link color*/ --md-accent-fg-color: #ff9800; /* link color on hover*/ } + [data-md-color-scheme="slate"] { --md-hue: 213; /* [0, 360] */ - --md-accent-fg-color: #ff9800; + --md-primary-fg-color: #002a5e; + --md-primary-fg-color--light: #00a3ca; + --md-primary-fg-color--dark: #112446; + --md-typeset-a-color: #00a3ca; /* text link color*/ + --md-accent-fg-color: #ff9800; /* link color on hover*/ } + /* Use this class for images with transparent background, it will add padding and a white background in dark mode */ .add-padding-and-white-bg { padding: 20px; } + [data-md-color-scheme="slate"] .add-padding-and-white-bg { background-color: whitesmoke; } + /* De-activate mkdocs' default h5 styling, which puts the h5 header in upper case */ .md-typeset h5 { text-transform: none; diff --git a/docs/user-guide/01-overview.md b/docs/user-guide/01-overview.md index ddc3b03c60..6482a1df56 100644 --- a/docs/user-guide/01-overview.md +++ b/docs/user-guide/01-overview.md @@ -34,7 +34,7 @@ the random factors that may affect the balance between load and generation. Econ as much a critical role as they do in the other kinds of studies since the stakes are mainly to know if and when supply security is likely to be jeopardized (detailed costs incurred in more ordinary conditions are of comparatively lower importance). In these studies, the default *Antares* option to use is the -[`adequacy`](18-parameters.md#mode) simulation mode. +[`adequacy`](solver/static-modeler/04-parameters.md#mode) simulation mode. ### Transmission project profitability [//]: # (TODO: explain what "fair and perfect market" means) @@ -45,7 +45,7 @@ and/or improvement of the security of supply (reduction of the loss-of-load expe In these studies, economic parameters and the physical modeling of the dynamic constraints bearing on the generating units are of paramount importance. Though a thorough survey of many "Monte-Carlo years" is still required, the number of scenarios to simulate is not as large as in generation adequacy studies. -In these studies, the default *Antares* option to use is the [`economy`](18-parameters.md#mode) simulation mode. +In these studies, the default *Antares* option to use is the [`economy`](solver/static-modeler/04-parameters.md#mode) simulation mode. ## Performance considerations Typically, *Antares* has to solve a least-cost hydro-thermal power schedule and unit commitment problem, with an hourly @@ -54,7 +54,7 @@ The large number and the size of the individual problems to solve often make opt Depending on user-defined results accuracy requirements, various practical options[^2] allow to simplify either the formulation of the problems, or their resolution. -[^2]: See [hydro-pricing-mode](solver/04-parameters.md#hydro-pricing-mode), [unit-commitment-mode](solver/04-parameters.md#unit-commitment-mode) +[^2]: See [hydro-pricing-mode](solver/static-modeler/04-parameters.md#hydro-pricing-mode), [unit-commitment-mode](solver/static-modeler/04-parameters.md#unit-commitment-mode) [//]: # (TODO: list in [^2] the other parameters that have impact on performance) @@ -73,4 +73,4 @@ operation problems (one for each week of each Monte-Carlo year), assumed to be i Note that, however, dependency issues such as the management of hydro stock (or any other kind of energy storage facility) may bring a significant coupling between the successive problems, which needs to be addressed properly[^3]. -[^3]: See how *Antares* addresses stock dependency between successive problems [here](solver/06-hydro-heuristics.md#seasonal-hydro-pre-allocation). +[^3]: See how *Antares* addresses stock dependency between successive problems [here](solver/static-modeler/06-hydro-heuristics.md#seasonal-hydro-pre-allocation). \ No newline at end of file diff --git a/docs/user-guide/02-install.md b/docs/user-guide/02-install.md index ffa1c75c37..c72c3e8da0 100644 --- a/docs/user-guide/02-install.md +++ b/docs/user-guide/02-install.md @@ -20,12 +20,12 @@ Installed alone, the Antares simulator does not require a lot of HDD space (less - The size of the power system model (number of Areas, Links, Thermal clusters, etc.) - The number of ready-made Time-Series and the number of Time-Series to be generated at runtime and stored afterward - (see [these parameters](18-parameters.md#time-series-parameters)). + (see [these parameters](ts-generator/04-parameters.md#time-series-parameters)). - The activation of output filters - (see [thematic-trimming](18-parameters.md#thematic-trimming) and [geographic-trimming](18-parameters.md#geographic-trimming) parameters). + (see [thematic-trimming](solver/static-modeler/04-parameters.md#thematic-trimming) and [geographic-trimming](solver/static-modeler/04-parameters.md#geographic-trimming) parameters). - The number of Monte-Carlo years involved in the simulation session, if the storage of detailed - [year-by-year results](18-parameters.md#year-by-year) is activated -- Whether [MPS export](18-parameters.md#include-exportmps) is activated + [year-by-year results](solver/static-modeler/04-parameters.md#year-by-year) is activated +- Whether [MPS export](solver/static-modeler/04-parameters.md#include-exportmps) is activated If you encounter space issues, consider tweaking the aforementioned parameters or reducing your study size. @@ -35,8 +35,8 @@ The amount of RAM required for a simulation depends on: - The size of the power system model (number of Areas, Links, Thermal clusters, etc.) - The number of ready-made Time-Series and that of Time-Series to be generated at runtime -- The simulation [mode](18-parameters.md#mode) -- The [unit commitment resolution mode](18-parameters.md#unit-commitment-mode) +- The simulation [mode](solver/static-modeler/04-parameters.md#mode) +- The [unit commitment resolution mode](solver/static-modeler/04-parameters.md#unit-commitment-mode) - If the [multi-threading](solver/optional-features/multi-threading.md) option is used If you encounter memory issues, consider tweaking the aforementioned parameters or reducing your study size. @@ -50,4 +50,4 @@ If you encounter memory issues, consider tweaking the aforementioned parameters - **Ubuntu 20.04**: download & run executables, available on [GitHub](https://github.com/AntaresSimulatorTeam/Antares_Simulator/releases). - **OracleServer 8.9**: download & run installation packages, or executables, available on [GitHub](https://github.com/AntaresSimulatorTeam/Antares_Simulator/releases). - **OracleLinux 8**: download & run executables, available on [GitHub](https://github.com/AntaresSimulatorTeam/Antares_Simulator/releases). -- Any other Windows/Linux/Unix OS: refer to our website to see how to [build *Antares* from sources](../developer-guide/3-Build.md) \ No newline at end of file +- Any other Windows/Linux/Unix OS: refer to our website to see how to [build *Antares* from sources](../developer-guide/3-Build.md) diff --git a/docs/user-guide/03-getting_started.md b/docs/user-guide/03-getting_started.md index ba4ca923a8..6930298a40 100644 --- a/docs/user-guide/03-getting_started.md +++ b/docs/user-guide/03-getting_started.md @@ -56,16 +56,16 @@ These steps most often involve: 1. Initializing or updating the input data (time-series, grid topology, fleet description, etc.). *In this step, the user is expected to provide all the input data they have, except the time-series that are - supposed to be [automatically generated](18-parameters.md#generate) by *Antares* (see step (3)).* + supposed to be [automatically generated](solver/static-modeler/04-parameters.md#generate) by *Antares* (see step (3)).* *As stated above, it is highly recommended to use robust tools to produce input data, such as [Antares Web](https://antares-web.readthedocs.io) or [Antares Extensions](#using-extensions).* 2. Defining the simulation contexts (definition of the "Monte-Carlo years" to simulate) -3. *(Optional)* If some time-series are supposed to be [automatically generated](18-parameters.md#generate), +3. *(Optional)* If some time-series are supposed to be [automatically generated](solver/static-modeler/04-parameters.md#generate), running a simulation to produce actual numeric scenarios, following the directives defined in (2). *In this step, the [ts-generator](ts-generator/01-overview-tsgenerator.md) tool should be used.* 4. Running the optimization, to solve all the optimization problems associated with each of the scenarios produced in (3). *In this step, the main [solver](solver/01-overview-solver.md) tool should be used.* -5. Exploiting the detailed [results](solver/03-outputs.md) yielded by (4). +5. Exploiting the detailed [results](solver/static-modeler/03-outputs.md) yielded by (4). *In this step, we recommend using [Antares Web](https://antares-web.readthedocs.io) or [Antares Extensions](#using-extensions).* diff --git a/docs/user-guide/solver/00-index.md b/docs/user-guide/solver/00-index.md index 4ef21bd614..ad9273f951 100644 --- a/docs/user-guide/solver/00-index.md +++ b/docs/user-guide/solver/00-index.md @@ -1,17 +1,13 @@ [//]: # (Index used by Sphinx to generate correct PDF tree) + # Solver ```{toctree} :hidden: - 01-overview-solver.md -02-inputs.md -03-outputs.md -04-parameters.md -05-model.md -06-hydro-heuristics.md -07-thermal-heuristic.md -08-command-line.md +static-modeler/00-index.md +dynamic-modeler/00-index.md +02-command-line.md optional-features/00-index.md -09-appendix.md +03-appendix.md ``` diff --git a/docs/user-guide/solver/01-overview-solver.md b/docs/user-guide/solver/01-overview-solver.md index d620960a25..6457b65bcc 100644 --- a/docs/user-guide/solver/01-overview-solver.md +++ b/docs/user-guide/solver/01-overview-solver.md @@ -2,63 +2,20 @@ _**This section is under construction**_ -The *Solver* is *Antares Simulator*'s main feature. - -**Monte Carlo Simulation** Runs either an economy simulation or an adequacy simulation -depending on the values of the [parameters](04-parameters.md). -If hardware resources and simulation settings allow it, simulations can benefit from [multi-threading](optional-features/multi-threading.md). - - -## Antares at one glance - -This section gives a summary of the whole simulation process followed by Antares in Economy simulations (Adequacy being simplified variant of it): - -1. Load or Generate [stochastic generators] Time-series of every kind for all system areas - -2. For each Monte-Carlo year, pick up at random or not [scenario builder] one time-series of each kind for each area/link - -3. For each area and each reservoir: - - 1. Split up the annual overall hydro storage inflows into monthly hydro storage generation, taking into account reservoir constraints, hydro management policy and operation conditions (demand, must-run generation, etc.) [heuristic + optimizer] - - 2. For every day of each month, break down the monthly hydro energy into daily blocks, taking into account hydro management policy and operation conditions (demand, must-run generation, etc.) [heuristic + optimizer]. Aggregate daily blocks back into weekly hydro storage energy credits (used if the final optimization is run with full weekly 168-hour span) - - 3. For each week of the year (daily/weekly hydro energy credits are now known in every area), run a three-stage 168-hour optimization cycle (or seven 24-hour optimizations, if the optimization preference is set to "daily"). This aim of this cycle is to minimize the sum of all costs throughout the optimization period. This sum may include regular proportional fuel costs, start-up and no-load heat costs, unsupplied and spilled energy costs, and hurdle costs on interconnection. The solution has to respect minimum and maximum limits on the power output of each plant, minimum up and down durations, as well as interconnection capacity limits and "binding constraints" at large (which may be technical – e.g. DC flow rules – or commercial – e.g. contracts). Note that an accurate resolution of this problem requires mixed integer linear programming (because of dynamic constraints on thermal units). A simplified implementation of this approach is used when the advanced parameter "Unit commitment" is set on "accurate". This high quality option may imply long calculation times. This is why, when "Unit commitment" is set on "fast", Antares makes further simplifications that save a lot of time (starting costs are not taken into account within the optimization step but are simply added afterwards, units within a thermal cluster are subject to starting up/shutting down constraints more stringent than the minimum up/down durations). In both cases, the general optimization sequence is as follows: - - i. Minimization of the overall system cost throughout the week in a continuous relaxed linear optimization. Prior to the optimization, an 8760-hourly vector of operating reserve R3 (see next section) may be added to the load vector (this will lead in step (ii) to identify plants that would not be called if there were no reserve requirements. Their actual output will be that found in step (iii), wherein the load used in the computations takes back its original value) - - ii. So as to accommodate the schedule resulting from (i), search for integer values of the on/off variables that satisfy the dynamic constraints with the smallest possible cost increase. - - iii. Take into account the integer variables found in (ii) and solve again the optimal schedule problem for the week. - -## Operating reserves modeling - -Many definitions may be encountered regarding the different operating reserves (spinning / non-spinning, fast / delayed, primary-secondary-tertiary, frequency containment reserve – frequency restoration reserve – replacement reserve, etc.). - -Besides, all of them need not be modeled with the same level of accuracy in a simulator such as Antares. Furthermore, the best way to use the concept is not always quite the same in pure Adequacy studies and in Economy studies. - -Several classes of reserves may therefore be used in Antares; how to use them at best depend on the kind and quality of operational data at hand, and on the aim of the studies to carry out; though all kinds of reserves may always be defined in the INPUT dataset, the set of reserves that will effectively be used depends on the kind of simulations to run. Note that any or all classes of reserves may be ignored in a given simulation (without being removed from the INPUT dataset) by setting the matching "optimization preference" to "ignore reserve X": - -- **Pre-allocated reserve on dispatchable thermal plants (R0)**
- This reserve (which corresponds to the parameter "spinning" attached to the thermal plants) is expressed as a percentage of the nominal capacity of the plants. It is simply used as a derating parameter: for instance, a 1000 MW plant with a 2.5% spinning parameter will not be able to generate more than 975 MW. It is important to notice that, if the plant is not scheduled on, it will NOT contribute to the spinning reserve (to be effectively available, the 25 MW of reserve would need the plant to be started). This first class of reserve is available for **Adequacy** as well as for **Economy**. - -- **Day-ahead reserve (R3):**
- This reserve is available in **Adequacy** and **Economy** simulations, with the following meaning: - "For any day D, to be able to accommodate last-minute random variations of the expected demand and/or generation (as they were seen from day D -1), a certain amount of power (R3) should be ready to be available at short notice". -
- In actual operating terms, R3 is a complex (spinning/non-spinning) mix as well as (hydro/thermal) mix. It may involve or not part of the primary and secondary power/frequency regulation reserves. R3 may represent as much as the overall amount of frequency containment reserve, frequency restoration reserve and replacement reserve required for operation on day D, as seen from day D-1. -
- In the simulations, R3 is construed as a "virtual" increase of the load to serve, which influences the optimal unit commitment and dispatch (because of minimum stable power levels and minimum On / Down times). - -**IMPORTANT:** - -The optimization makes sure that, should the need arise, reserve R3 will actually be available where it is needed **BUT** there is no commitment regarding whether this service should be provided by an increase of local generation, a decrease of exports or even an increase of imports: the optimizer will choose the mix leading to the minimal cost for the system. - -Note that this "standard" feature of Antares makes it possible to assess the potential value of keeping some headroom in interconnections for the purpose of transferring operating reserves, when "remote" reserves are less expensive than domestic ones. - -The table below gives an overview of the different reserves available in Antares - -| | _Economy_ | _Adequacy_ | -|------|-----------|------------| -| _R0_ | _Yes_ | _Yes_ | -| _R3_ | _Yes_ | _Yes_ | \ No newline at end of file +The *Solver* is *Antares Simulator*'s main feature. +It covers modelling & solving the adequacy optimization problem. + +As of 2024, the modelling feature is being overhauled to allow more flexibility in the definition of physical models. + +- The existing modeler will still be maintained for a few years, you can find its + documentation under the ["static modeler" section](static-modeler/01-overview-static-modeler). +- The new modeler will be gradually enriched to cover all existing features, you can find its + documentation under the ["dynamic modeler" section](dynamic-modeler/01-overview-dynamic-modeler). +- It will be possible, for a few transitional years, to define "hybrid" studies, + mixing [static models](static-modeler/05-model.md) with [dynamic models](dynamic-modeler/05-model.md). This is + documented [here](dynamic-modeler/08-hybrid-studies.md). + +As a consequence, you will be able to use the solver with three types of studies: legacy studies, new studies, and +hybrid studies. +All these possibilities are offered by the same "antares-solver" executable ; it is able to adapt to the different input +files. Its usage is documented [here](02-command-line.md). diff --git a/docs/user-guide/solver/08-command-line.md b/docs/user-guide/solver/02-command-line.md similarity index 73% rename from docs/user-guide/solver/08-command-line.md rename to docs/user-guide/solver/02-command-line.md index 8ef88dfd23..346e9cfdfc 100644 --- a/docs/user-guide/solver/08-command-line.md +++ b/docs/user-guide/solver/02-command-line.md @@ -9,36 +9,36 @@ hide: ## Simulation -| command | usage | -|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------------| -| -i, --input | Study folder | -| --expansion | Force the simulation in [expansion](04-parameters.md#mode) mode | -| --economy | Force the simulation in [economy](04-parameters.md#mode) mode | -| --adequacy | Force the simulation in [adequacy](04-parameters.md#mode) mode | -| --parallel | Enable [parallel](optional-features/multi-threading.md) computation of MC years | -| --force-parallel=VALUE | Override the max number of years computed [simultaneously](optional-features/multi-threading.md) | -| --use-ortools | Use the [OR-Tools](https://developers.google.com/optimization) modelling library (under the hood) | -| --ortools-solver=VALUE | The solver to use (only available if use-ortools is activated). Possible values are: `sirius` (default), `coin`, `xpress`, `scip` | +| command | usage | +|:-----------------------|:----------------------------------------------------------------------------------------------------------------------------------| +| -i, --input | Study folder | +| --expansion | Force the simulation in [expansion](static-modeler/04-parameters.md#mode) mode | +| --economy | Force the simulation in [economy](static-modeler/04-parameters.md#mode) mode | +| --adequacy | Force the simulation in [adequacy](static-modeler/04-parameters.md#mode) mode | +| --parallel | Enable [parallel](optional-features/multi-threading.md) computation of MC years | +| --force-parallel=VALUE | Override the max number of years computed [simultaneously](optional-features/multi-threading.md) | +| --use-ortools | Use the [OR-Tools](https://developers.google.com/optimization) modelling library (under the hood) | +| --ortools-solver=VALUE | The solver to use (only available if use-ortools is activated). Possible values are: `sirius` (default), `coin`, `xpress`, `scip` | ## Parameters -| command | usage | -|:-------------------------|:--------------------------------------------------------------------------------------------------| -| -n, --name=VALUE | Set the name of the new simulation | -| -g, --generators-only | Run the time-series generators only | -| -c, --comment-file=VALUE | Specify the file to copy as comments of the simulation | -| -f, --force | Ignore all warnings at loading | -| --no-output | Do not write the results in the output folder | -| -y, --year=VALUE | Override the [number of MC years](04-parameters.md#nbyears) | -| --year-by-year | Force the [writing the result output for each year](04-parameters.md#year-by-year) (economy only) | -| --derated | Force the [derated](04-parameters.md#derated) mode | -| -z, --zip-output | Write the results into a single zip archive | +| command | usage | +|:-------------------------|:----------------------------------------------------------------------------------------------------------------| +| -n, --name=VALUE | Set the name of the new simulation | +| -g, --generators-only | Run the time-series generators only | +| -c, --comment-file=VALUE | Specify the file to copy as comments of the simulation | +| -f, --force | Ignore all warnings at loading | +| --no-output | Do not write the results in the output folder | +| -y, --year=VALUE | Override the [number of MC years](static-modeler/04-parameters.md#nbyears) | +| --year-by-year | Force the [writing the result output for each year](static-modeler/04-parameters.md#year-by-year) (economy only) | +| --derated | Force the [derated](static-modeler/04-parameters.md#derated) mode | +| -z, --zip-output | Write the results into a single zip archive | ## Optimization | command | usage | |:-------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| --optimization-range | Force the [simplex optimization range](04-parameters.md#simplex-range) ('day' or 'week') | +| --optimization-range | Force the [simplex optimization range](static-modeler/04-parameters.md#simplex-range) ('day' or 'week') | | --no-constraints | Ignore all binding constraints | | --no-ts-import | Do not import timeseries into the input folder (this option may be useful for running old studies without upgrade) | | -m, --mps-export | Export anonymous MPS, weekly or daily optimal UC+dispatch linear (MPS will be named if the problem is infeasible) | diff --git a/docs/user-guide/solver/03-appendix.md b/docs/user-guide/solver/03-appendix.md new file mode 100644 index 0000000000..90dc6ca020 --- /dev/null +++ b/docs/user-guide/solver/03-appendix.md @@ -0,0 +1,315 @@ +# Appendix + +[//]: # (TODO: the contents of this page may be dispatched in opther pages) + +## Details on the "include-exportmps" parameter + +[//]: # (TODO: specify where the MPS files are written) + +This [parameter](static-modeler/04-parameters.md#include-exportmps) does not influence the way calculations are carried +out, +nor does it change their results. +The effect of this preference is that, if the parameter is activated, *Antares* will produce and store in the +simulation output folder two files for every linear problem solved in the whole simulation. + +- The first file ("problem" file) contains a standardized description of the mathematical problem solved by *Antares'* + built-in linear solver. The format standard used in this file is known as "MPS". +- The second file ("criterion" file) contains the value of the optimal (minimum) value found for the objective function + of the optimization problem (overall system cost throughout a day or a week). + +All commercial as well as open-source linear solvers are able to process MPS files. As a consequence, tests aiming at +comparing *Antares* solver with other commercial solutions can be easily carried out: all that has to be done is to +submit the MPS problem to the solver at hand and measure its performances (calculation time, criterion value) +with those of *Antares*. + +Note that this kind of comparison brings no information regarding the quality of the physical modelling on which the +simulation is based. It is useful, however, to gather evidence on mathematical grounds. + +File names are structured as follows: + +- When the optimization parameter [simplex-range](static-modeler/04-parameters.md#simplex-range) is set on `week`: + Problem-MC year-week number-date-time.mps + Criterion-MC year-week number-date-time.txt +- When the optimization parameter [simplex-range](static-modeler/04-parameters.md#simplex-range) is set on `day`: + Problem-MC year-week number-date-time-day number.mps + Criterion-MC year-week number-date-time-day number.txt + +[//]: # (TODO: add link to "two successive optimization problems" doc) +Besides, each economic problem generally needs to be solved through two successive optimization problems. +Files related to these two problems will bear almost the same name, the only difference being the "time" suffix. +The files related to the second optimization (final *Antares* results) are those that bear the latest tag. + +Finally, in some rare cases where the problems to solve are small and fast, the files attached to the two optimization +rounds may begin to be printed within the same second. In these cases, an additional suffix is added before the mps or +txt extension. + +> _**Note:**_ The extra runtime and disk space resulting from the activation of the "mps" option may be quite +> significant. +> This option should therefore be used only when a comparison of results with those of other solvers is actually +> intended. + +## Details on the "include-unfeasible-problem-behavior" parameter + +This [parameter](static-modeler/04-parameters.md#include-unfeasible-problem-behavior) can take one of the four values: +`ERROR_DRY`, `ERROR_MPS`, `WARNING_DRY`, `WARNING_MPS` + +If `ERROR_DRY` or `ERROR_MPS` is selected, the simulation will stop right after encountering the first mathematically +unfeasible optimization (daily or weekly) problem. No output will be produced beyond this point. +Should the dataset contain several unfeasible problems (i.e. regarding different weeks of different MC years), +it is possible that successive runs of the same simulation stop at different points (if parallel computation is used, +the triggering problem may differ from one run to the other). + +If `WARNING_DRY` or `WARNING_MPS` is selected, the simulation will skip all mathematically unfeasible optimization +(daily or weekly) problems encountered, fill out all results regarding these problems with zeroes and then resume the +simulation. The hydro reservoir levels used for resuming the simulation are those reached at the end of the last +successful week. + +With `..._DRY` options, no specific data is printed regarding the faulty problem(s). +With `..._MPS` options, the full expression of the faulty problem(s) is printed in the standard "MPS" format, +thus allowing further analysis of the infeasibility issue. + +## Details on the "initial-reservoir-levels" parameter + +**(DEPRECATED since 9.2)** + +### version 9.2: The reservoir level is now always determined with cold start behavior. + +This parameter can take the two values "cold start" or "hot start". [default: cold start]. Simulations results may in +some circumstances be heavily impacted by this setting, hence proper attention should be paid to its meaning before +considering changing the default value. + +**General:** + +This parameter is meant to define the initial reservoir levels that should be used, in each system area, when processing +data related to the hydropower storage resources to consider in each specific Monte-Carlo year. + +As a consequence, Areas which fall in either of the two following categories are not impacted by the value of the +parameter: + +- No hydro-storage capability installed +- Hydro-storage capability installed, but the "reservoir management" option is set to "False" + +Areas that have some hydro-storage capability installed and for which explicit reservoir management is required are +concerned by the parameter. The developments that follow concern only this category of Areas. + +**Cold Start:** + +On starting the simulation of a new Monte-Carlo year, the reservoir level to consider in each Area on the first day of +the initialization month is randomly drawn between the extreme levels defined for the Area on that day. + +More precisely: + +- The value is drawn according to the probability distribution function of a "Beta" random variable, whose four internal + parameters are set so as to adopt the following behavior: + Lower bound: Minimum reservoir level. + Upper bound: Maximum reservoir level + Expectation: Average reservoir level + Standard Deviation: (1/3) (Upper bound-Lower bound) + +- The random number generator used for that purpose works with a dedicated seed that ensures that results can be + reproduced + [^17] from one run to another, regardless of the simulation runtime mode (sequential or parallel) + and regardless of the number of Monte-Carlo years to be simulated [^18]. + +**Hot Start:** + +On starting the simulation of a new Monte-Carlo year, the reservoir level to consider in each Area on the first day of +the initialization month is set to the value reached at the end of the previous simulated year, if three conditions are +met: + +- The simulation calendar is defined throughout the whole year, and the simulation starts on the day chosen for + initializing the reservoir levels of all Areas. + +- The Monte-Carlo year considered is not the first to simulate, or does not belong to the first batch of years to be + simulated in parallel. In sequential runtime mode, that means that year #N may start with the level reached at the end + of year #(N-1). In parallel runtime mode, if the simulation is carried out with batches of B years over as many CPU + cores, years of the k-th batch + [^19] may start with the ending levels of the years processed in the (k-1)-th batch. + +- The parallelization context (see [Multi-threading](optional-features/multi-threading.md)) must be set to ensure that + the M Monte-Carlo years to simulate will be processed in a round number of K consecutive batches of B years in + parallel (i.e. M = K\*B and all time-series refresh intervals are exact multiple of B). + +The first year of the simulation, and more generally years belonging to the first simulation batch in parallel mode, are +initialized as they would be in the cold start option. + +**Note that:** + +- _Depending on the hydro management options used, the amount of hydro-storage energy generated throughout the year may + either match closely the overall amount of natural inflows of the same year, or differ to a lesser or greater extent. + In the case of a close match, the ending reservoir level will be similar to the starting level. If the energy + generated exceeds the inflows (either natural or pumped), the ending level will be lower than the starting level (and + conversely, be higher if generation does not reach the inflow credit). Using the "hot start" option allows to take + this phenomenon into account in a very realistic fashion, since the consequences of hydro decisions taken at any time + have a decisive influence on the system's long term future._ + +- _When using the reservoir level "hot start" option, comparisons between different simulations make sense only if they + rely on the exact same options, i.e. either sequential mode or parallel mode over the same number of CPU cores._ + +- _More generally, it has to be pointed out that the "hydro-storage" model implemented in Antares can be used to model " + storable" resources quite different from actual hydro reserves: batteries, gas subterraneous stocks, etc._ + +## Details on the "hydro-heuristic-policy" parameter + +[//]: # (TODO: update this paragraph) +_**This section is under construction**_ + +This parameter can take the two values "Accommodate rule curves" or "Maximize +generation". [default: Accommodate rule curves]. + +**General:** + +This parameter is meant to define how the reservoir level should be managed throughout the year, either with emphasis +put on the respect of rule curves or on the maximization of the use of natural inflows. + +**Accommodate rule curves:** + +Upper and lower rule curves are accommodated in both monthly and daily heuristic stages (described page 58). In the +second stage, violations of the lower rule curve are avoided as much as possible (penalty cost on $\Psi$. higher than +penalty cost on Y). This policy may result in a restriction of the overall yearly energy generated from the natural +inflows. + +**Maximize generation:** + +Upper and lower rule curves are accommodated in both monthly and daily heuristic stages (described page 58). In the +second stage, incomplete use of natural inflows is avoided as much as possible (penalty cost on Y higher than penalty +cost on $\Psi$). This policy may result in violations of the lower rule curve. + +## Details on the "hydro-pricing-mode" parameter + +[//]: # (TODO: update this paragraph) +_**This section is under construction**_ + +This parameter can take the two values "fast" or "accurate". [default: fast]. + +Simulations carried out in "accurate" mode yield results that are theoretically optimal as far as the techno-economic +modelling of hydro (or equivalent) energy reserves is concerned. It may, however, require noticeably longer computation +time than the simpler "fast" mode. + +Simulations carried out in "fast" mode are less demanding in computer resources. From a qualitative standpoint, they are +expected to lead to somewhat more intensive (less cautious) use of stored energy. + +**General:** + +This parameter is meant to define how the reservoir level difference between the beginning and the end of an +optimization week should be reflected in the hydro economic signal (water value) used in the computation of optimal +hourly generated /pumped power during this week. + +**Fast:** + +The water value is taken to remain about the same throughout the week, and a constant value equal to that found at the +date and for the level at which the week_ **begins** _is used in the course of the optimization. A value interpolated +from the reference table for the exact level reached at each time step within the week is used ex-post in the assessment +of the variable "H.COST" (positive for generation, negative for pumping) defined +in [Output Files](static-modeler/03-outputs.md). This +option should be reserved to simulations in which computation resources are an issue or to simulations in which +level-dependent water value variations throughout a week are known to be small. + +**Accurate:** + +The water value is considered as variable throughout the week. As a consequence, a different cost is used for each " +layer" of the stock from/to which energy can be withdrawn/injected, in an internal hydro merit-order involving the 100 +tabulated water-values found at the date at which the week **ends**. A value interpolated from the reference table for +the exact level reached at each time step within the week is used ex-post in the assessment of the variable "H.COST" ( +positive for generation, negative for pumping) defined in [Output Files](static-modeler/03-outputs.md). This option +should be used if +computation resources are not an issue and if level-dependent water value variations throughout a week must be accounted +for. + +## Details on the "unit-commitment-mode" parameter + +[//]: # (TODO: update this paragraph) +_**This section is under construction**_ + +This parameter can take the two values "fast" or "accurate". [default: fast]. + +Simulations carried out in "accurate" mode yield results that are expected to be close to the theoretical optimum as far +as the techno-economic modelling of thermal units is concerned. They may, however, require much longer computation time +than the simpler "fast" mode. + +Simulations carried out in "fast" mode are less demanding in computer resources. From a qualitative standpoint, they are +expected to lead to a more costly use of thermal energy. This potential bias is partly due to the fact that in this +mode, start-up costs do not participate as such to the optimization process but are simply added ex post. + +**General:** + +In its native form [^20], the weekly optimization problem belongs to the MILP (Mixed Integer Linear Program) class. The +Integer variables reflect, for each time step, the operational status (running or not) of each thermal unit. Besides, +the amount of power generated from each unit can be described as a so-called semi-continuous variable (its value is +either 0 or some point within the interval [Pmin , Pmax]). Finally, the periods during which each unit is either +generating or not cannot be shorter than minimal (on- and off-) thresholds depending on its technology. + +The Unit Commitment mode parameter defines two different ways to address the issue of the mathematical resolution of +this problem. In both cases, two successive so-called "relaxed" LP global optimizations are carried out. In-between +those two LPs, a number of local IP (unit commitment of each thermal cluster) are carried out. + +Besides, dynamic thermal constraints (minimum on- and off- time durations) are formulated on time-indices rolling over +the week; this simplification brings the ability to run a simulation over a short period of time, such as one single +week extracted from a whole year, while avoiding the downside (data management complexity, increased runtime) of a +standard implementation based on longer simulations tiled over each other (illustration below). + +![Standard_Implementation](img/Standard_Implementation.png) + +![Antares_Implementation](img/Antares_Implementation.png) + +**Fast:** + +In the first optimization stage, integrity constraints are removed from the problem and replaced by simpler continuous +constraints. + +For each thermal cluster, the intermediate IP looks simply for an efficient unit-commitment compatible with the +operational status obtained in the first stage, with the additional condition (more stringent than what is actually +required) that on- and off- periods should be exact multiple of the higher of the two thresholds specified in the +dataset. + +In the second optimization stage, the unit commitment set by the intermediate IPs is considered as a context to use in a +new comprehensive optimal hydro-thermal schedule assessment. The amount of day-ahead (spinning) reserve, if any, is +added to the demand considered in the first stage and subtracted in the second stage. Start-up costs as well as No-Load +Heat costs are assessed in accordance with the unit-commitment determined in the first stage and are added ex post. + +**Accurate:** + +In the first optimization stage, integrity constraints are properly relaxed. Integer variables describing the start-up +process of each unit are given relevant start-up costs, and variables attached to running units are given No-Load Heat +costs (if any), regardless of their generation output level. Fuel costs / Market bids are attached to variables +representing the generation output levels. + +For each thermal cluster, the intermediate IP looks for a unit-commitment compatible with the integrity constraints in +the immediate neighborhood of the relaxed solution obtained in the first stage. In this process, the dynamic +thresholds (min on-time, min off-time) are set to their exact values, without any additional constraint. + +In the second optimization stage, the unit commitment set by the intermediate IP is considered as a context to use in a +new comprehensive optimal hydro-thermal schedule assessment. The amount of day-ahead (spinning) reserve, if any, is +added to the demand considered in the first stage and subtracted in the second stage. + +## Details on the "renewable-generation-modelling" parameter + +[//]: # (TODO: update this paragraph) +_**This section is under construction**_ + +This parameter can take the two values “aggregated” or “cluster”. For a new study, it will default to cluster. For a +legacy (Antares version <8.1.0) study it will default to aggregated. + +If the parameter is set to “aggregated”, the user will have access to the Wind & Solar windows, but not the Renewable +window. When the parameter is set to “cluster”, the Renewable window will be available, but not the Wind nor the Solar +windows. The data stored in the windows that are not available will always be conserved. However, only Renewable data ( +and not the wind and solar data) will be considered for the calculations when the parameter is set to “cluster”. And +only the wind and solar data (and not the renewable data) will be considered for the calculations when the parameter is +set to “aggregated”. + +The Renewable window can be filled out with the different renewable clusters inside each node. Each renewable cluster +needs to have a group specified or will default to the «Other RES 1» group. Production Timeseries can be filled out much +like the Thermal production ones. Note that unlike thermal clusters, negative production values are allowed. The +Renewable window is described in more details in the “4. Active Windows” section. In the Simulation window, only +“Ready-made” timeseries can be selected for renewables for now. This should be modified in a future release. The MC +scenario builder for Renewables works the same way as for Thermal Clusters. + +[^17]: As long as the System's list of Areas does not change + +[^18]:E.g. : if three playlists A,B,C are defined over 1000 years (A: years 1 to 1000, B: years 1 to 100, C: Years +13,42,57,112), initial reservoir levels in each Area are identical in the playlists' intersection (years 13,42,57) + +[^19]: If the playlist is full, these years have numbers # (k-1)B+1 ,…., #kB + +[^20]: Described in the note "Optimization Problems Formulation" + diff --git a/docs/user-guide/solver/09-appendix.md b/docs/user-guide/solver/09-appendix.md deleted file mode 100644 index 1f8e24673d..0000000000 --- a/docs/user-guide/solver/09-appendix.md +++ /dev/null @@ -1,217 +0,0 @@ -# Appendix - -[//]: # (TODO: the contents of this page may be dispatched in opther pages) - -## Details on the "include-exportmps" parameter -[//]: # (TODO: specify where the MPS files are written) - -This [parameter](04-parameters.md#include-exportmps) does not influence the way calculations are carried out, -nor does it change their results. -The effect of this preference is that, if the parameter is activated, *Antares* will produce and store in the -simulation output folder two files for every linear problem solved in the whole simulation. - -- The first file ("problem" file) contains a standardized description of the mathematical problem solved by *Antares'* - built-in linear solver. The format standard used in this file is known as "MPS". -- The second file ("criterion" file) contains the value of the optimal (minimum) value found for the objective function - of the optimization problem (overall system cost throughout a day or a week). - -All commercial as well as open-source linear solvers are able to process MPS files. As a consequence, tests aiming at -comparing *Antares* solver with other commercial solutions can be easily carried out: all that has to be done is to -submit the MPS problem to the solver at hand and measure its performances (calculation time, criterion value) -with those of *Antares*. - -Note that this kind of comparison brings no information regarding the quality of the physical modelling on which the -simulation is based. It is useful, however, to gather evidence on mathematical grounds. - -File names are structured as follows: -- When the optimization parameter [simplex-range](04-parameters.md#simplex-range) is set on `week`: - Problem-MC year-week number-date-time.mps - Criterion-MC year-week number-date-time.txt -- When the optimization parameter [simplex-range](04-parameters.md#simplex-range) is set on `day`: - Problem-MC year-week number-date-time-day number.mps - Criterion-MC year-week number-date-time-day number.txt - - -[//]: # (TODO: add link to "two successive optimization problems" doc) -Besides, each economic problem generally needs to be solved through two successive optimization problems. -Files related to these two problems will bear almost the same name, the only difference being the "time" suffix. -The files related to the second optimization (final *Antares* results) are those that bear the latest tag. - -Finally, in some rare cases where the problems to solve are small and fast, the files attached to the two optimization -rounds may begin to be printed within the same second. In these cases, an additional suffix is added before the mps or -txt extension. - -> _**Note:**_ The extra runtime and disk space resulting from the activation of the "mps" option may be quite significant. -> This option should therefore be used only when a comparison of results with those of other solvers is actually intended. - -## Details on the "include-unfeasible-problem-behavior" parameter - -This [parameter](04-parameters.md#include-unfeasible-problem-behavior) can take one of the four values: -`ERROR_DRY`, `ERROR_MPS`, `WARNING_DRY`, `WARNING_MPS` - -If `ERROR_DRY` or `ERROR_MPS` is selected, the simulation will stop right after encountering the first mathematically -unfeasible optimization (daily or weekly) problem. No output will be produced beyond this point. -Should the dataset contain several unfeasible problems (i.e. regarding different weeks of different MC years), -it is possible that successive runs of the same simulation stop at different points (if parallel computation is used, -the triggering problem may differ from one run to the other). - -If `WARNING_DRY` or `WARNING_MPS` is selected, the simulation will skip all mathematically unfeasible optimization -(daily or weekly) problems encountered, fill out all results regarding these problems with zeroes and then resume the -simulation. The hydro reservoir levels used for resuming the simulation are those reached at the end of the last successful week. - -With `..._DRY` options, no specific data is printed regarding the faulty problem(s). -With `..._MPS` options, the full expression of the faulty problem(s) is printed in the standard "MPS" format, -thus allowing further analysis of the infeasibility issue. - - -## Details on the "initial-reservoir-levels" parameter (DEPRECATED since 9.2) - -### version 9.2: The reservoir level is now always determined with cold start behavior. - -This parameter can take the two values "cold start" or "hot start". [default: cold start]. Simulations results may in some circumstances be heavily impacted by this setting, hence proper attention should be paid to its meaning before considering changing the default value. - -**General:** - -This parameter is meant to define the initial reservoir levels that should be used, in each system area, when processing -data related to the hydropower storage resources to consider in each specific Monte-Carlo year. - -As a consequence, Areas which fall in either of the two following categories are not impacted by the value of the parameter: -- No hydro-storage capability installed -- Hydro-storage capability installed, but the "reservoir management" option is set to "False" - -Areas that have some hydro-storage capability installed and for which explicit reservoir management is required are concerned by the parameter. The developments that follow concern only this category of Areas. - -**Cold Start:** - -On starting the simulation of a new Monte-Carlo year, the reservoir level to consider in each Area on the first day of -the initialization month is randomly drawn between the extreme levels defined for the Area on that day. - -More precisely: - -- The value is drawn according to the probability distribution function of a "Beta" random variable, whose four internal parameters are set so as to adopt the following behavior: - Lower bound: Minimum reservoir level. - Upper bound: Maximum reservoir level - Expectation: Average reservoir level - Standard Deviation: (1/3) (Upper bound-Lower bound) - -- The random number generator used for that purpose works with a dedicated seed that ensures that results can be reproduced - [^17] from one run to another, regardless of the simulation runtime mode (sequential or parallel) - and regardless of the number of Monte-Carlo years to be simulated [^18]. - -**Hot Start:** - -On starting the simulation of a new Monte-Carlo year, the reservoir level to consider in each Area on the first day of the initialization month is set to the value reached at the end of the previous simulated year, if three conditions are met: - -- The simulation calendar is defined throughout the whole year, and the simulation starts on the day chosen for initializing the reservoir levels of all Areas. - -- The Monte-Carlo year considered is not the first to simulate, or does not belong to the first batch of years to be simulated in parallel. In sequential runtime mode, that means that year #N may start with the level reached at the end of year #(N-1). In parallel runtime mode, if the simulation is carried out with batches of B years over as many CPU cores, years of the k-th batch - [^19] may start with the ending levels of the years processed in the (k-1)-th batch. - -- The parallelization context (see [Multi-threading](optional-features/multi-threading.md)) must be set to ensure that the M Monte-Carlo years to simulate will be processed in a round number of K consecutive batches of B years in parallel (i.e. M = K\*B and all time-series refresh intervals are exact multiple of B). - -The first year of the simulation, and more generally years belonging to the first simulation batch in parallel mode, are initialized as they would be in the cold start option. - -**Note that:** - -- _Depending on the hydro management options used, the amount of hydro-storage energy generated throughout the year may either match closely the overall amount of natural inflows of the same year, or differ to a lesser or greater extent. In the case of a close match, the ending reservoir level will be similar to the starting level. If the energy generated exceeds the inflows (either natural or pumped), the ending level will be lower than the starting level (and conversely, be higher if generation does not reach the inflow credit). Using the "hot start" option allows to take this phenomenon into account in a very realistic fashion, since the consequences of hydro decisions taken at any time have a decisive influence on the system's long term future._ - -- _When using the reservoir level "hot start" option, comparisons between different simulations make sense only if they rely on the exact same options, i.e. either sequential mode or parallel mode over the same number of CPU cores._ - -- _More generally, it has to be pointed out that the "hydro-storage" model implemented in Antares can be used to model "storable" resources quite different from actual hydro reserves: batteries, gas subterraneous stocks, etc._ - -## Details on the "hydro-heuristic-policy" parameter -[//]: # (TODO: update this paragraph) -_**This section is under construction**_ - -This parameter can take the two values "Accommodate rule curves" or "Maximize generation". [default: Accommodate rule curves]. - -**General:** - -This parameter is meant to define how the reservoir level should be managed throughout the year, either with emphasis put on the respect of rule curves or on the maximization of the use of natural inflows. - -**Accommodate rule curves:** - -Upper and lower rule curves are accommodated in both monthly and daily heuristic stages (described page 58). In the second stage, violations of the lower rule curve are avoided as much as possible (penalty cost on $\Psi$. higher than penalty cost on Y). This policy may result in a restriction of the overall yearly energy generated from the natural inflows. - -**Maximize generation:** - -Upper and lower rule curves are accommodated in both monthly and daily heuristic stages (described page 58). In the second stage, incomplete use of natural inflows is avoided as much as possible (penalty cost on Y higher than penalty cost on $\Psi$). This policy may result in violations of the lower rule curve. - -## Details on the "hydro-pricing-mode" parameter -[//]: # (TODO: update this paragraph) -_**This section is under construction**_ - -This parameter can take the two values "fast" or "accurate". [default: fast]. - -Simulations carried out in "accurate" mode yield results that are theoretically optimal as far as the techno-economic modelling of hydro (or equivalent) energy reserves is concerned. It may, however, require noticeably longer computation time than the simpler "fast" mode. - -Simulations carried out in "fast" mode are less demanding in computer resources. From a qualitative standpoint, they are expected to lead to somewhat more intensive (less cautious) use of stored energy. - -**General:** - -This parameter is meant to define how the reservoir level difference between the beginning and the end of an optimization week should be reflected in the hydro economic signal (water value) used in the computation of optimal hourly generated /pumped power during this week. - -**Fast:** - -The water value is taken to remain about the same throughout the week, and a constant value equal to that found at the date and for the level at which the week_ **begins** _is used in the course of the optimization. A value interpolated from the reference table for the exact level reached at each time step within the week is used ex-post in the assessment of the variable "H.COST" (positive for generation, negative for pumping) defined in [Output Files](03-outputs.md). This option should be reserved to simulations in which computation resources are an issue or to simulations in which level-dependent water value variations throughout a week are known to be small. - -**Accurate:** - -The water value is considered as variable throughout the week. As a consequence, a different cost is used for each "layer" of the stock from/to which energy can be withdrawn/injected, in an internal hydro merit-order involving the 100 tabulated water-values found at the date at which the week **ends**. A value interpolated from the reference table for the exact level reached at each time step within the week is used ex-post in the assessment of the variable "H.COST" (positive for generation, negative for pumping) defined in [Output Files](03-outputs.md). This option should be used if computation resources are not an issue and if level-dependent water value variations throughout a week must be accounted for. - -## Details on the "unit-commitment-mode" parameter -[//]: # (TODO: update this paragraph) -_**This section is under construction**_ - -This parameter can take the two values "fast" or "accurate". [default: fast]. - -Simulations carried out in "accurate" mode yield results that are expected to be close to the theoretical optimum as far as the techno-economic modelling of thermal units is concerned. They may, however, require much longer computation time than the simpler "fast" mode. - -Simulations carried out in "fast" mode are less demanding in computer resources. From a qualitative standpoint, they are expected to lead to a more costly use of thermal energy. This potential bias is partly due to the fact that in this mode, start-up costs do not participate as such to the optimization process but are simply added ex post. - -**General:** - -In its native form [^20], the weekly optimization problem belongs to the MILP (Mixed Integer Linear Program) class. The Integer variables reflect, for each time step, the operational status (running or not) of each thermal unit. Besides, the amount of power generated from each unit can be described as a so-called semi-continuous variable (its value is either 0 or some point within the interval [Pmin , Pmax]). Finally, the periods during which each unit is either generating or not cannot be shorter than minimal (on- and off-) thresholds depending on its technology. - -The Unit Commitment mode parameter defines two different ways to address the issue of the mathematical resolution of this problem. In both cases, two successive so-called "relaxed" LP global optimizations are carried out. In-between those two LPs, a number of local IP (unit commitment of each thermal cluster) are carried out. - -Besides, dynamic thermal constraints (minimum on- and off- time durations) are formulated on time-indices rolling over the week; this simplification brings the ability to run a simulation over a short period of time, such as one single week extracted from a whole year, while avoiding the downside (data management complexity, increased runtime) of a standard implementation based on longer simulations tiled over each other (illustration below). - -![Standard_Implementation](img/Standard_Implementation.png) - -![Antares_Implementation](img/Antares_Implementation.png) - -**Fast:** - -In the first optimization stage, integrity constraints are removed from the problem and replaced by simpler continuous constraints. - -For each thermal cluster, the intermediate IP looks simply for an efficient unit-commitment compatible with the operational status obtained in the first stage, with the additional condition (more stringent than what is actually required) that on- and off- periods should be exact multiple of the higher of the two thresholds specified in the dataset. - -In the second optimization stage, the unit commitment set by the intermediate IPs is considered as a context to use in a new comprehensive optimal hydro-thermal schedule assessment. The amount of day-ahead (spinning) reserve, if any, is added to the demand considered in the first stage and subtracted in the second stage. Start-up costs as well as No-Load Heat costs are assessed in accordance with the unit-commitment determined in the first stage and are added ex post. - -**Accurate:** - -In the first optimization stage, integrity constraints are properly relaxed. Integer variables describing the start-up process of each unit are given relevant start-up costs, and variables attached to running units are given No-Load Heat costs (if any), regardless of their generation output level. Fuel costs / Market bids are attached to variables representing the generation output levels. - -For each thermal cluster, the intermediate IP looks for a unit-commitment compatible with the integrity constraints in the immediate neighborhood of the relaxed solution obtained in the first stage. In this process, the dynamic thresholds (min on-time, min off-time) are set to their exact values, without any additional constraint. - -In the second optimization stage, the unit commitment set by the intermediate IP is considered as a context to use in a new comprehensive optimal hydro-thermal schedule assessment. The amount of day-ahead (spinning) reserve, if any, is added to the demand considered in the first stage and subtracted in the second stage. - -## Details on the "renewable-generation-modelling" parameter -[//]: # (TODO: update this paragraph) -_**This section is under construction**_ - -This parameter can take the two values “aggregated” or “cluster”. For a new study, it will default to cluster. For a legacy (Antares version <8.1.0) study it will default to aggregated. - -If the parameter is set to “aggregated”, the user will have access to the Wind & Solar windows, but not the Renewable window. When the parameter is set to “cluster”, the Renewable window will be available, but not the Wind nor the Solar windows. The data stored in the windows that are not available will always be conserved. However, only Renewable data (and not the wind and solar data) will be considered for the calculations when the parameter is set to “cluster”. And only the wind and solar data (and not the renewable data) will be considered for the calculations when the parameter is set to “aggregated”. - -The Renewable window can be filled out with the different renewable clusters inside each node. Each renewable cluster needs to have a group specified or will default to the «Other RES 1» group. Production Timeseries can be filled out much like the Thermal production ones. Note that unlike thermal clusters, negative production values are allowed. The Renewable window is described in more details in the “4. Active Windows” section. In the Simulation window, only “Ready-made” timeseries can be selected for renewables for now. This should be modified in a future release. The MC scenario builder for Renewables works the same way as for Thermal Clusters. - -[^17]: As long as the System's list of Areas does not change - -[^18]:E.g. : if three playlists A,B,C are defined over 1000 years (A: years 1 to 1000, B: years 1 to 100, C: Years 13,42,57,112), initial reservoir levels in each Area are identical in the playlists' intersection (years 13,42,57) - -[^19]: If the playlist is full, these years have numbers # (k-1)B+1 ,…., #kB - -[^20]: Described in the note "Optimization Problems Formulation" - diff --git a/docs/user-guide/solver/dynamic-modeler/00-index.md b/docs/user-guide/solver/dynamic-modeler/00-index.md new file mode 100644 index 0000000000..e49906698f --- /dev/null +++ b/docs/user-guide/solver/dynamic-modeler/00-index.md @@ -0,0 +1,15 @@ +[//]: # (Index used by Sphinx to generate correct PDF tree) + +# Dynamic Modeler + +```{toctree} +:hidden: +01-overview-new-solver.md +02-inputs.md +03-outputs.md +04-parameters.md +05-model.md +06-heuristics.md +07-standard-library.md +08-hybrid-studies.md +``` \ No newline at end of file diff --git a/docs/user-guide/solver/dynamic-modeler/01-overview-dynamic-modeler.md b/docs/user-guide/solver/dynamic-modeler/01-overview-dynamic-modeler.md new file mode 100644 index 0000000000..095c0a9711 --- /dev/null +++ b/docs/user-guide/solver/dynamic-modeler/01-overview-dynamic-modeler.md @@ -0,0 +1,13 @@ +# Overview + +_**Disclaimer: please note that the new Antares dynamic modeler is still under development, and that some of the +features described in this section may still be unavailable**_ + +The new Antares dynamic modeler allows more flexibility in the definition of physical models used in the simulation. +By doing so, it allows the users to conduct complex studies leveraging advanced physical models with highly +customizable behavior. + +All this is achieved by allowing the user to define the MIP variables and constraints behind every physical model +instantiated in their energy system. +Of course, Antares is also delivered with a riche set of [standard models]() that can be used out-of-the-box, and that +can cover a large scope of everyday studies. \ No newline at end of file diff --git a/docs/user-guide/solver/dynamic-modeler/02-inputs.md b/docs/user-guide/solver/dynamic-modeler/02-inputs.md new file mode 100644 index 0000000000..f0eff54ca7 --- /dev/null +++ b/docs/user-guide/solver/dynamic-modeler/02-inputs.md @@ -0,0 +1,3 @@ +# Input files + +_**This section is under construction**_ \ No newline at end of file diff --git a/docs/user-guide/solver/dynamic-modeler/03-outputs.md b/docs/user-guide/solver/dynamic-modeler/03-outputs.md new file mode 100644 index 0000000000..447b91809d --- /dev/null +++ b/docs/user-guide/solver/dynamic-modeler/03-outputs.md @@ -0,0 +1,3 @@ +# Output files + +_**This feature is under development**_ \ No newline at end of file diff --git a/docs/user-guide/solver/dynamic-modeler/04-parameters.md b/docs/user-guide/solver/dynamic-modeler/04-parameters.md new file mode 100644 index 0000000000..ce619350b6 --- /dev/null +++ b/docs/user-guide/solver/dynamic-modeler/04-parameters.md @@ -0,0 +1,3 @@ +# Parameters + +_**This feature is under development**_ diff --git a/docs/user-guide/solver/dynamic-modeler/05-model.md b/docs/user-guide/solver/dynamic-modeler/05-model.md new file mode 100644 index 0000000000..4e0d037286 --- /dev/null +++ b/docs/user-guide/solver/dynamic-modeler/05-model.md @@ -0,0 +1,78 @@ +# Optimization model + +_**This section is under construction**_ + +The new Antares dynamic modeler is all about giving the user the power to define the mathematical model of every +physical element in the system. Elements of this model are described in this section. + +## Models + +A model defines the behavior of an element in the simulated system. Several elements can have the same behavior, and +therefore the same model. +For example, a "FlexibleLoad" model can define the behavior of a flexible demand. + +The basic attributes of a model are: + +- a list of parameters: these are the input data required by the model. + For example: the nominal power of the groups in a thermal cluster, the value of a load, etc. + A parameter can be time-step-dependent or not, and scenario-dependent or not. +- a list of potentially bounded variables: these are the quantities whose values the simulation will have to define. + For example: the power produced by a thermal cluster, or the level of a stock. +- a list of constraints: these are equations that link parameters and model variables. + For example, for a battery, we might have an equation of the following type: + **level[t] - level[t-1] - efficiency * injection + withdrawal = inflows** +- a contribution to system cost, defined on the basis of model parameters and variables. + For example, for a thermal cluster, the contribution might look like this: + **time_sum(cost * generation)** +- a list of [ports](#ports-and-connections) + +## Components +A “component” is a model instance: it is an object in the simulated system whose behavior is defined by a model as +described above. +It is therefore defined by: +- a unique identifier in the study +- a model that defines its behavior +- a set of values for the parameters of the model + +## Ports and connections +So far, we haven't defined any possibilities for interaction between models, or between components of a study. However, +we will need to connect these objects to each other: connect a power demand, a production cluster, or a link to a node, typically. + +- a [model](#models) defines a list of its ports, which enable components implementing this model to be connected to other components +- a port, in a model, is defined by a name and its “type”. +- a port type defines the quantities that are exposed: typically a power flow, but also, for example, a gas flow, a voltage phase, etc. + A port type can expose several quantities; these quantities are called “fields”. +- In a system, two components may be linked together by a connection between two ports of identical type (and only in this way). + +The introduction of the port concept allows the user to: +1. expose the internal quantities of a model in a standard way to the outside: for example, the object to which a + generator is connected doesn't need to know the name of the variable internal to the power flow model, it just needs + to know its name on the port type common to all the models. +2. assemble several quantities on the same interface: for example, an electrical power flow and the voltage phase, + for an AC electrical network. + + +Each model can: +1. define, with an [expression](#expressions), the value of a field exposed on one of its ports. +2. use, in any [expression](#expressions), the value of a field of one of its ports, potentially defined by another model. + +In order to obtain a mathematically solvable problems, in a system, each connection between two ports must have a +single definition for each field. + +## Expressions +The [models](#models) allow certain elements to be defined by the user, using “free” mathematical expressions: +- constraints +- variable bounds +- contribution to system cost +- definition of the value of a field exposed on a port + +Expressions can be used to reference: +- model parameters +- model variables +- model port fields + +They also enable a number of antares-specific operations using: +- temporal operators: + - shift: for example, to reference the value of a parameter or variable at the previous time step + - evaluation: reference the value of a parameter or variable at a specific time step, e.g. time step 0 +- time aggregations: for example summing a variable on an interval of time diff --git a/docs/user-guide/solver/dynamic-modeler/06-heuristics.md b/docs/user-guide/solver/dynamic-modeler/06-heuristics.md new file mode 100644 index 0000000000..d175817fc0 --- /dev/null +++ b/docs/user-guide/solver/dynamic-modeler/06-heuristics.md @@ -0,0 +1,3 @@ +# Heuristics + +_**This feature is under development**_ diff --git a/docs/user-guide/solver/dynamic-modeler/07-standard-library.md b/docs/user-guide/solver/dynamic-modeler/07-standard-library.md new file mode 100644 index 0000000000..312e587ce5 --- /dev/null +++ b/docs/user-guide/solver/dynamic-modeler/07-standard-library.md @@ -0,0 +1,3 @@ +# Standard library + +_**This feature is under development**_ diff --git a/docs/user-guide/solver/dynamic-modeler/08-hybrid-studies.md b/docs/user-guide/solver/dynamic-modeler/08-hybrid-studies.md new file mode 100644 index 0000000000..4129576d42 --- /dev/null +++ b/docs/user-guide/solver/dynamic-modeler/08-hybrid-studies.md @@ -0,0 +1,3 @@ +# Hybrid studies + +_**This feature is under development**_ diff --git a/docs/user-guide/solver/optional-features/multi-threading.md b/docs/user-guide/solver/optional-features/multi-threading.md index 5d126a6672..c48bc80a11 100644 --- a/docs/user-guide/solver/optional-features/multi-threading.md +++ b/docs/user-guide/solver/optional-features/multi-threading.md @@ -14,12 +14,12 @@ Provided that hardware resources are large enough, this mode may reduce signific To benefit from multi-threading, the simulation must be run in the following context: -- The [parallel](../08-command-line.md#simulation) option must be enabled (it is disabled by default) -- The simulation [mode](../04-parameters.md#mode) must be either `Adequacy` or `Economy` +- The [parallel](../02-command-line.md#simulation) option must be enabled (it is disabled by default) +- The simulation [mode](../static-modeler/04-parameters.md#mode) must be either `Adequacy` or `Economy` When the "parallel" solver option is used, each Monte-Carlo year is dispatched in an individual process on the available CPU cores. The number of such individual processes depends on the characteristics of the local hardware and on the value given to -the study-dependent [number-of-cores-mode](../04-parameters.md#number-of-cores-mode) advanced parameter. +the study-dependent [number-of-cores-mode](../static-modeler/04-parameters.md#number-of-cores-mode) advanced parameter. This parameter can take five different values (Minimum, Low, Medium, High, Maximum). The number of independent processes resulting from the combination (local hardware + study settings) is given in the following table, which shows the CPU allowances granted in the different configurations. diff --git a/docs/user-guide/solver/static-modeler/00-index.md b/docs/user-guide/solver/static-modeler/00-index.md new file mode 100644 index 0000000000..1b8d1f07e3 --- /dev/null +++ b/docs/user-guide/solver/static-modeler/00-index.md @@ -0,0 +1,14 @@ +[//]: # (Index used by Sphinx to generate correct PDF tree) + +# Legacy Solver + +```{toctree} +:hidden: +01-overview-legacy-solver.md +02-inputs.md +03-outputs.md +04-parameters.md +05-model.md +06-hydro-heuristics.md +07-thermal-heuristic.md +``` \ No newline at end of file diff --git a/docs/user-guide/solver/static-modeler/01-overview-static-modeler.md b/docs/user-guide/solver/static-modeler/01-overview-static-modeler.md new file mode 100644 index 0000000000..728296c45e --- /dev/null +++ b/docs/user-guide/solver/static-modeler/01-overview-static-modeler.md @@ -0,0 +1,64 @@ +# Overview + +_**This section is under construction**_ + +The *Solver* is *Antares Simulator*'s main feature. + +**Monte Carlo Simulation** Runs either an economy simulation or an adequacy simulation +depending on the values of the [parameters](04-parameters.md). +If hardware resources and simulation settings allow it, simulations can benefit from [multi-threading](../optional-features/multi-threading.md). + + +## Antares at one glance + +This section gives a summary of the whole simulation process followed by Antares in Economy simulations (Adequacy being simplified variant of it): + +1. Load or Generate [stochastic generators] Time-series of every kind for all system areas + +2. For each Monte-Carlo year, pick up at random or not [scenario builder] one time-series of each kind for each area/link + +3. For each area and each reservoir: + + 1. Split up the annual overall hydro storage inflows into monthly hydro storage generation, taking into account reservoir constraints, hydro management policy and operation conditions (demand, must-run generation, etc.) [heuristic + optimizer] + + 2. For every day of each month, break down the monthly hydro energy into daily blocks, taking into account hydro management policy and operation conditions (demand, must-run generation, etc.) [heuristic + optimizer]. Aggregate daily blocks back into weekly hydro storage energy credits (used if the final optimization is run with full weekly 168-hour span) + + 3. For each week of the year (daily/weekly hydro energy credits are now known in every area), run a three-stage 168-hour optimization cycle (or seven 24-hour optimizations, if the optimization preference is set to "daily"). This aim of this cycle is to minimize the sum of all costs throughout the optimization period. This sum may include regular proportional fuel costs, start-up and no-load heat costs, unsupplied and spilled energy costs, and hurdle costs on interconnection. The solution has to respect minimum and maximum limits on the power output of each plant, minimum up and down durations, as well as interconnection capacity limits and "binding constraints" at large (which may be technical – e.g. DC flow rules – or commercial – e.g. contracts). Note that an accurate resolution of this problem requires mixed integer linear programming (because of dynamic constraints on thermal units). A simplified implementation of this approach is used when the advanced parameter "Unit commitment" is set on "accurate". This high quality option may imply long calculation times. This is why, when "Unit commitment" is set on "fast", Antares makes further simplifications that save a lot of time (starting costs are not taken into account within the optimization step but are simply added afterwards, units within a thermal cluster are subject to starting up/shutting down constraints more stringent than the minimum up/down durations). In both cases, the general optimization sequence is as follows: + + i. Minimization of the overall system cost throughout the week in a continuous relaxed linear optimization. Prior to the optimization, an 8760-hourly vector of operating reserve R3 (see next section) may be added to the load vector (this will lead in step (ii) to identify plants that would not be called if there were no reserve requirements. Their actual output will be that found in step (iii), wherein the load used in the computations takes back its original value) + + ii. So as to accommodate the schedule resulting from (i), search for integer values of the on/off variables that satisfy the dynamic constraints with the smallest possible cost increase. + + iii. Take into account the integer variables found in (ii) and solve again the optimal schedule problem for the week. + +## Operating reserves modeling + +Many definitions may be encountered regarding the different operating reserves (spinning / non-spinning, fast / delayed, primary-secondary-tertiary, frequency containment reserve – frequency restoration reserve – replacement reserve, etc.). + +Besides, all of them need not be modeled with the same level of accuracy in a simulator such as Antares. Furthermore, the best way to use the concept is not always quite the same in pure Adequacy studies and in Economy studies. + +Several classes of reserves may therefore be used in Antares; how to use them at best depend on the kind and quality of operational data at hand, and on the aim of the studies to carry out; though all kinds of reserves may always be defined in the INPUT dataset, the set of reserves that will effectively be used depends on the kind of simulations to run. Note that any or all classes of reserves may be ignored in a given simulation (without being removed from the INPUT dataset) by setting the matching "optimization preference" to "ignore reserve X": + +- **Pre-allocated reserve on dispatchable thermal plants (R0)**
+ This reserve (which corresponds to the parameter "spinning" attached to the thermal plants) is expressed as a percentage of the nominal capacity of the plants. It is simply used as a derating parameter: for instance, a 1000 MW plant with a 2.5% spinning parameter will not be able to generate more than 975 MW. It is important to notice that, if the plant is not scheduled on, it will NOT contribute to the spinning reserve (to be effectively available, the 25 MW of reserve would need the plant to be started). This first class of reserve is available for **Adequacy** as well as for **Economy**. + +- **Day-ahead reserve (R3):**
+ This reserve is available in **Adequacy** and **Economy** simulations, with the following meaning: + "For any day D, to be able to accommodate last-minute random variations of the expected demand and/or generation (as they were seen from day D -1), a certain amount of power (R3) should be ready to be available at short notice". +
+ In actual operating terms, R3 is a complex (spinning/non-spinning) mix as well as (hydro/thermal) mix. It may involve or not part of the primary and secondary power/frequency regulation reserves. R3 may represent as much as the overall amount of frequency containment reserve, frequency restoration reserve and replacement reserve required for operation on day D, as seen from day D-1. +
+ In the simulations, R3 is construed as a "virtual" increase of the load to serve, which influences the optimal unit commitment and dispatch (because of minimum stable power levels and minimum On / Down times). + +**IMPORTANT:** + +The optimization makes sure that, should the need arise, reserve R3 will actually be available where it is needed **BUT** there is no commitment regarding whether this service should be provided by an increase of local generation, a decrease of exports or even an increase of imports: the optimizer will choose the mix leading to the minimal cost for the system. + +Note that this "standard" feature of Antares makes it possible to assess the potential value of keeping some headroom in interconnections for the purpose of transferring operating reserves, when "remote" reserves are less expensive than domestic ones. + +The table below gives an overview of the different reserves available in Antares + +| | _Economy_ | _Adequacy_ | +|------|-----------|------------| +| _R0_ | _Yes_ | _Yes_ | +| _R3_ | _Yes_ | _Yes_ | \ No newline at end of file diff --git a/docs/user-guide/solver/02-inputs.md b/docs/user-guide/solver/static-modeler/02-inputs.md similarity index 98% rename from docs/user-guide/solver/02-inputs.md rename to docs/user-guide/solver/static-modeler/02-inputs.md index 659208d135..a2f6c5f003 100644 --- a/docs/user-guide/solver/02-inputs.md +++ b/docs/user-guide/solver/static-modeler/02-inputs.md @@ -49,7 +49,7 @@ It is based on the edition of a special "sets.ini" file. - Make sure that the sets.ini file is ready for use before opening the Antares study. Attempts to update the sets.ini file while the study is opened will not be effective. - Definition of meaningless districts (references to nodes that do not exist,…) will generate warnings in the GUI log files. -**HOW TO UPDATE / CREATE the file** : using any text editor, or, better yet, [using Antares extensions](../03-getting_started.md#using-extensions). +**HOW TO UPDATE / CREATE the file** : using any text editor, or, better yet, [using Antares extensions](../../03-getting_started.md#using-extensions). **WHERE TO FIND / STORE THE FILE** : INPUT/areas/sets.ini @@ -157,7 +157,7 @@ The user may pick any area appearing in the list and is then given access to dif - The "local data" tab is used to set the parameters of the stochastic generator. These parameters are presented in four sub-tabs whose content is presented in - [Time-series analysis and generation](../ts-generator/01-overview-tsgenerator.md). + [Time-series analysis and generation](../../ts-generator/01-overview-tsgenerator.md). - The "digest" tab displays for all areas a short account of the local data @@ -233,8 +233,8 @@ a choice can be made between different tabs: - Fuel efficiency (%) - Cost generation [Set manually / Use cost timeseries] - Marginal operating cost (€/MWh) - - Volatility (forced): a parameter between 0 and 1, see section [Time-series generation (thermal)](../ts-generator/05-algorithm.md#time-series-generation-thermal) - - Volatility (planned): a parameter between 0 and 1, see section [Time-series generation (thermal)](../ts-generator/05-algorithm.md#time-series-generation-thermal) + - Volatility (forced): a parameter between 0 and 1, see section [Time-series generation (thermal)](../../ts-generator/05-algorithm.md#time-series-generation-thermal) + - Volatility (planned): a parameter between 0 and 1, see section [Time-series generation (thermal)](../../ts-generator/05-algorithm.md#time-series-generation-thermal) - Law (forced): Probabilistic law used for the generation of the forced outage time-series, can be set to either uniform or geometric - Law (planned): Probabilistic law used for the generation of the planned outage time-series, can be set to either uniform or geometric - Generate TS: Parameter to specify the behavior of this cluster for TS generation. **This cluster-wise parameter takes priority over the study-wide one.** It can hold three values: @@ -499,7 +499,7 @@ The user may pick any area appearing in the list and is then given access to dif When given invalid matrices, the TS generator emits an infeasibility diagnosis -- The "local data" tab is used to set the parameters of the stochastic generator. These parameters are presented in four subtabs whose content is presented in [Time-series analysis and generation](../ts-generator/04-parameters.md). +- The "local data" tab is used to set the parameters of the stochastic generator. These parameters are presented in four subtabs whose content is presented in [Time-series analysis and generation](../../ts-generator/04-parameters.md). - The "digest" tab displays for all areas a short account of the local data @@ -542,7 +542,7 @@ The user may pick any area appearing in the list and is then given access to dif When given invalid matrices, the TS generator emits an infeasibility diagnosis -- The "local data" tab is used to set the parameters of the stochastic generator. These parameters are presented in four subtabs whose content is presented in [Time-series analysis and generation](../ts-generator/04-parameters.md). +- The "local data" tab is used to set the parameters of the stochastic generator. These parameters are presented in four subtabs whose content is presented in [Time-series analysis and generation](../../ts-generator/04-parameters.md). - The "digest" tab displays for all areas a short account of the local data @@ -663,9 +663,9 @@ This window is used to handle all input data regarding the interconnections. On - Loop flow: amount of power flowing circularly though the grid when all "nodes" are perfectly balanced (no import and no export). Such loop flows may be expected on any "simplified" grid in which large regions (or even countries) are modeled by a small number of "macro" nodes, and should accordingly be accounted for. - - PST min (denoted $Y^-$ in [Kirchhoff Constraints Generator](../other-features/kirchhoff-constraints-builder.md)): lower bound of phase-shifting that can be reached by a PST installed on the link, if any (note : the effect of the active loop flow generated by the PST may be superimposed to that of the passive loop flow) + - PST min (denoted $Y^-$ in [Kirchhoff Constraints Generator](../../other-features/kirchhoff-constraints-builder.md)): lower bound of phase-shifting that can be reached by a PST installed on the link, if any (note : the effect of the active loop flow generated by the PST may be superimposed to that of the passive loop flow) - - PST max (denoted $Y^+$ in [Kirchhoff Constraints Generator](../other-features/kirchhoff-constraints-builder.md)): upper bound of phase-shifting that can be reached by a PST installed on the link, if any (note : the effect of the active loop flow generated by the PST may be superimposed to that of the passive loop flow) + - PST max (denoted $Y^+$ in [Kirchhoff Constraints Generator](../../other-features/kirchhoff-constraints-builder.md)): upper bound of phase-shifting that can be reached by a PST installed on the link, if any (note : the effect of the active loop flow generated by the PST may be superimposed to that of the passive loop flow) For the sake of simplicity and homogeneity with the convention used for impedance, PST settings are assumed to be expressed in $ rad/U^2_{ref} $ @@ -712,7 +712,7 @@ Then the DC flow approximation may be implemented, for each time-step of the sim $$ c= 1, ..., C : \sum_{i \in C}{sign(l,c)F_lZ_l = 0}$$ -_Note that such specific binding constraints can be automatically generated within Antares by using the auxiliary module "Kirchhoff's Constraints Generator" further described in [Kirchhoff Constraints Generator](../other-features/kirchhoff-constraints-builder.md)._ +_Note that such specific binding constraints can be automatically generated within Antares by using the auxiliary module "Kirchhoff's Constraints Generator" further described in [Kirchhoff Constraints Generator](../../other-features/kirchhoff-constraints-builder.md)._ Aside from such sets of constraints, which may help to give realistic geographic patterns to the flows, completely different sets of constraints may be also defined, such as those set up by the market organization, which may define precise perimeters for valid commercial flows [^10]. @@ -827,4 +827,4 @@ links and binding constraints. Status can be changed by toggling the icons. Defa other purely graphic icons/buttons (no action on data) allow respectively to center the map on a given set of (x , y) coordinates, and to prune the "empty" space around the current map. Multiple additional maps may be defined by using the cross-shaped button located top right. A detailed presentation of all system map editor features can be found in -the document "System Map Editor User guide". +the document "System Map Editor User guide". \ No newline at end of file diff --git a/docs/user-guide/solver/03-outputs.md b/docs/user-guide/solver/static-modeler/03-outputs.md similarity index 99% rename from docs/user-guide/solver/03-outputs.md rename to docs/user-guide/solver/static-modeler/03-outputs.md index 367340cc3e..e6ec1f0222 100644 --- a/docs/user-guide/solver/03-outputs.md +++ b/docs/user-guide/solver/static-modeler/03-outputs.md @@ -205,7 +205,7 @@ Alike Input data, output results can be filtered so as to include only items tha [^13]: NODU and NP Cost do not appear in "Adequacy" results since these variables are irrelevant in that context -[^adqp]: Please note that this output variable is only available in the economy mode, when the adequacy patch is activated (see [Adequacy Patch](optional-features/adequacy-patch.md)) +[^adqp]: Please note that this output variable is only available in the economy mode, when the adequacy patch is activated (see [Adequacy Patch](../optional-features/adequacy-patch.md)) [^14]: This description applies to both « MC synthesis » files and "Year-by-Year" files, with some simplifications in the latter case @@ -254,4 +254,4 @@ Here is a list of new output variables in recent versions: | 8.5 | LMR VIOL., SPIL. ENRG. CSR, DTG MRG CSR | values-*.txt | no | | 8.6 | PSP_open_injection, PSP_open_withdrawal, PSP_open_level, PSP_closed_injection, PSP_closed_withdrawal, PSP_closed_level, Pondage_injection, Pondage_withdrawal, Pondage_level, Battery_injection, Battery_withdrawal, Battery_level, Other1_injection, Other1_withdrawal, Other1_level, Other2_injection, Other2_withdrawal, Other2_level, Other3_injection, Other3_withdrawal, Other3_level, Other4_injection, Other4_withdrawal, Other4_level, Other5_injection, Other5_withdrawal, Other5_level | values-*.txt | yes | | 8.6 | STS inj by plant, STS withdrawal by plant, STS lvl by plant | details-STstorage-*.txt | yes | -| 8.6 | CO2 EMIS., NH3 EMIS., SO2 EMIS., NOX EMIS., PM2_5 EMIS., PM5 EMIS., PM10 EMIS., NMVOC EMIS., OP1 EMIS., OP2 EMIS., OP3 EMIS., OP4 EMIS., OP5 EMIS. | values-*.txt | yes | +| 8.6 | CO2 EMIS., NH3 EMIS., SO2 EMIS., NOX EMIS., PM2_5 EMIS., PM5 EMIS., PM10 EMIS., NMVOC EMIS., OP1 EMIS., OP2 EMIS., OP3 EMIS., OP4 EMIS., OP5 EMIS. | values-*.txt | yes | \ No newline at end of file diff --git a/docs/user-guide/solver/04-parameters.md b/docs/user-guide/solver/static-modeler/04-parameters.md similarity index 96% rename from docs/user-guide/solver/04-parameters.md rename to docs/user-guide/solver/static-modeler/04-parameters.md index 5ca79193a0..aad7e09794 100644 --- a/docs/user-guide/solver/04-parameters.md +++ b/docs/user-guide/solver/static-modeler/04-parameters.md @@ -24,11 +24,11 @@ These parameters are listed under the `[general]` section in the `.ini` file. - **Default value:** `economy` - **Usage:** this parameter sets the study mode for Antares - `economy/economic`: Antares simulator will try to ensure balance between load and generation, while minimizing the - economical cost of the grid's operation (more on this [here](../01-overview.md#transmission-project-profitability)). "Economy" simulations make a full use of + economical cost of the grid's operation (more on this [here](../../01-overview.md#transmission-project-profitability)). "Economy" simulations make a full use of *Antares* optimization capabilities. They require economic as well as technical input data and may demand a lot of computer resources. - `adequacy`: in this mode, all power plants' operational cost is considered zero. Antares' only objective is to ensure - balance between load and generation (more on this [here](../01-overview.md#generation-adequacy-problems)). "Adequacy" simulations are faster and require only + balance between load and generation (more on this [here](../../01-overview.md#generation-adequacy-problems)). "Adequacy" simulations are faster and require only technical input data. Their results are limited to adequacy indicators. - `expansion`: Antares simulator will optimize the investments on the grid, minimizing both investments and operational costs. @@ -173,7 +173,7 @@ These parameters are listed under the `[general]` section in the `.ini` file. whose detailed analysis may have shown that they were not physically realistic. A different typical use case consists in replaying only a small number of years of specific interest (for instance, years in the course of which Min or Max values of a given variable were encountered in a previous simulation). - In addition, each MC year i=1, …, N can be given a relative [weight](#playlistyearweight) + In addition, each MC year i=1, …, N can be given a relative [weight](#playlist_year_weight) > _**WARNING:**_ this parameter cannot be used with parameter [derated](#derated) @@ -431,7 +431,7 @@ _**This section is under construction**_ - `optim-2`: export MPS for second step of the optimization - `both-optims` or `true`: export MPS for both steps of the optimization -> _**Note:**_ You can find more information on this parameter [here](09-appendix.md#details-on-the-include-exportmps-parameter). +> _**Note:**_ You can find more information on this parameter [here](../03-appendix.md#details-on-the-include-exportmps-parameter). --- #### include-split-exported-mps @@ -468,7 +468,7 @@ _**This section is under construction**_ - `ERROR_DRY`: stop simulation - `ERROR_MPS`: stop simulation, and export the MPS of the unfeasible problem -> _**Note:**_ You can find more information on this parameter [here](09-appendix.md#details-on-the-include-unfeasible-problem-behavior-parameter). +> _**Note:**_ You can find more information on this parameter [here](../03-appendix.md#details-on-the-include-unfeasible-problem-behavior-parameter). --- #### solver-parameters @@ -482,7 +482,7 @@ _**This section is under construction**_ --- ## Adequacy-patch parameters -Defines a set of options related to the [adequacy patch](optional-features/adequacy-patch.md). +Defines a set of options related to the [adequacy patch](../optional-features/adequacy-patch.md). The set of preferences is study-specific; it can be changed at any time and saved along with study data. These parameters are listed under the `[adequacy patch]` section in the `.ini` file. @@ -491,7 +491,7 @@ These parameters are listed under the `[adequacy patch]` section in the `.ini` f - **Expected value:** `true` or `false` - **Required:** no - **Default value:** `false` -- **Usage:** set this parameter to `true` if you want to enable the [Adequacy Patch](optional-features/adequacy-patch.md) algorithm. +- **Usage:** set this parameter to `true` if you want to enable the [Adequacy Patch](../optional-features/adequacy-patch.md) algorithm. --- #### set-to-null-ntc-from-physical-out-to-physical-in-for-first-step @@ -578,7 +578,7 @@ These parameters are listed under the `[other preferences]` section in the `.ini - `cold start` - `hot start` -> _**Note:**_ You can find more information on this parameter [here](09-appendix.md#details-on-the-initial-reservoir-levels-parameter). +> _**Note:**_ You can find more information on this parameter [here](../03-appendix.md#details-on-the-initial-reservoir-levels-parameter). --- #### hydro-heuristic-policy @@ -592,7 +592,7 @@ These parameters are listed under the `[other preferences]` section in the `.ini - `accommodate rule curves` - `maximize generation` -> _**Note:**_ You can find more information on this parameter [here](09-appendix.md#details-on-the-hydro-heuristic-policy-parameter). +> _**Note:**_ You can find more information on this parameter [here](../03-appendix.md#details-on-the-hydro-heuristic-policy-parameter). --- #### hydro-pricing-mode @@ -606,7 +606,7 @@ These parameters are listed under the `[other preferences]` section in the `.ini - `fast` - `accurate`: Note that this mode is significantly slower than the `fast` mode. -> _**Note:**_ You can find more information on this parameter [here](09-appendix.md#details-on-the-hydro-pricing-mode-parameter). +> _**Note:**_ You can find more information on this parameter [here](../03-appendix.md#details-on-the-hydro-pricing-mode-parameter). --- #### power-fluctuations @@ -648,7 +648,7 @@ These parameters are listed under the `[other preferences]` section in the `.ini - `accurate`: Heuristic in which 2 LP problems are solved. Explicit modelling for the number of ON/OFF units. Slower than `fast`. - `milp`: A single MILP problem is solved, with explicit modelling for the number of ON/OFF units. Slower than `accurate`. -> _**Note:**_ You can find more information on this parameter [here](09-appendix.md#details-on-the-unit-commitment-mode-parameter). +> _**Note:**_ You can find more information on this parameter [here](../03-appendix.md#details-on-the-unit-commitment-mode-parameter). --- #### number-of-cores-mode @@ -660,7 +660,7 @@ These parameters are listed under the `[other preferences]` section in the `.ini - `maximum` - **Required:** no - **Default value:** `medium` -- **Usage:** use this parameter to configure [multi-threading](optional-features/multi-threading.md). +- **Usage:** use this parameter to configure [multi-threading](../optional-features/multi-threading.md). --- #### renewable-generation-modelling @@ -674,7 +674,7 @@ These parameters are listed under the `[other preferences]` section in the `.ini - `aggregated` - `clusters` -> _**Note:**_ You can find more information on this parameter [here](09-appendix.md#details-on-the-renewable-generation-modelling-parameter). +> _**Note:**_ You can find more information on this parameter [here](../03-appendix.md#details-on-the-renewable-generation-modelling-parameter). --- #### day-ahead-reserve-management @@ -822,4 +822,4 @@ They are **required** if [thematic-trimming](#thematic-trimming) is set to `true --- ## Model-wise parameters [//]: # (TODO: link to model-wise parameters documentation) -_**This section is under construction**_ +_**This section is under construction**_ \ No newline at end of file diff --git a/docs/user-guide/solver/05-model.md b/docs/user-guide/solver/static-modeler/05-model.md similarity index 98% rename from docs/user-guide/solver/05-model.md rename to docs/user-guide/solver/static-modeler/05-model.md index 9f37c2ac9a..b05bb39509 100644 --- a/docs/user-guide/solver/05-model.md +++ b/docs/user-guide/solver/static-modeler/05-model.md @@ -31,9 +31,13 @@ The scope of this document is exclusively devoted to step (4). Note that equival The following picture gives a functional view of all that is involved in steps (1) to (5). In this illustration, Step (4), whose goal is to solve the problems introduced in this document, is materialized by the red box. -![Antares_Process](../img/Antares_Process.jpg) +![Antares_Process](../img/Antares_Process.png) -The number and the size of the individual problems to solve (a least-cost hydro-thermal unit-commitment and power schedule, with an hourly resolution and throughout a week, over a large interconnected system) make optimization sessions often computer-intensive. Note that the content of the blue "hydro energy manager" box appearing on the previous figure, whose purpose is to deal with energy storage issues at the seasonal scale, is not detailed in the present document but in the ["Miscellaneous"](../reference-guide/08-miscellaneous.md#the-heuristic-for-seasonal-hydro-pre-allocation) section. +The number and the size of the individual problems to solve (a least-cost hydro-thermal unit-commitment and power +schedule, with an hourly resolution and throughout a week, over a large interconnected system) make optimization +sessions often computer-intensive. Note that the content of the blue "hydro energy manager" box appearing on the +previous figure, whose purpose is to deal with energy storage issues at the seasonal scale, is not detailed in the +present document but in [this section](06-hydro-heuristics.md#seasonal-hydro-pre-allocation). Depending on user-defined results accuracy requirements, various practical options allow to simplify either the formulation of the weekly UC & dispatch problems (e.g. do not account for constraints associated with operational reserves) or their resolution (i.e. find, for the native MILP, an approximate solution based on two successive LPs). For the sake of simplicity and clarity, the way these options are used to revise the primary problem formulation is not detailed hereafter. Likewise, many simplifications are introduced to keep notations as light as possible. This is why, for instance, the overall sum of load, wind power generation, solar power generation, run of the river generation, and all other kinds of so-called "must-run" generation is simply denoted "load" in the present document. @@ -560,7 +564,7 @@ Finally, upstream of the proper optimization, there is a last set of hydro-relat The following diagram summarizes the situation regarding both random and epsilon numbers defined and used within Antares. They are meant to build up, along with the regular description of the power system (physical limits and standard costs), an optimization framework that is up to the complex tasks at hand: balanced Monte- Carlo draws, reproducible simulations exploring the whole span of optimal operating configurations. -![Random_Parameters](img/Random_Parameters.png) +![Random_Parameters](../img/Random_Parameters.png) | Random Epsilons | Minimum absolute value | Maximum absolute value | |-----------------|-------------------------|--------------------------| @@ -604,4 +608,4 @@ Last Rev : M. Doquet - 25 JAN 2023 [^alike]: Consider for instance a case where a fleet of ten exactly identical plants, in a highly symmetric system, is expected to generate an overall amount of power roughly equivalent to the nominal capacity of two of them. Simulations results indicating that this power should exclusively be provided by a specific pair of units (the other eight remaining always idle, throughout all Monte Carlo scenarios), would appear heavily biased, though not mathematically wrong. -[^costs]: These random noises affect only cost-related parameters and not RHS parameters (such perturbations, which have not been implemented so far, might bring some benefits as regards degeneracy). It can also be noted that, in the special case of hydro, the random noise is present in the problem formulation given in this document, with notation $\epsilon_\lambda^0$. +[^costs]: These random noises affect only cost-related parameters and not RHS parameters (such perturbations, which have not been implemented so far, might bring some benefits as regards degeneracy). It can also be noted that, in the special case of hydro, the random noise is present in the problem formulation given in this document, with notation $\epsilon_\lambda^0$. \ No newline at end of file diff --git a/docs/user-guide/solver/06-hydro-heuristics.md b/docs/user-guide/solver/static-modeler/06-hydro-heuristics.md similarity index 100% rename from docs/user-guide/solver/06-hydro-heuristics.md rename to docs/user-guide/solver/static-modeler/06-hydro-heuristics.md diff --git a/docs/user-guide/solver/07-thermal-heuristic.md b/docs/user-guide/solver/static-modeler/07-thermal-heuristic.md similarity index 85% rename from docs/user-guide/solver/07-thermal-heuristic.md rename to docs/user-guide/solver/static-modeler/07-thermal-heuristic.md index 372ceb8bed..e43dbf0b77 100644 --- a/docs/user-guide/solver/07-thermal-heuristic.md +++ b/docs/user-guide/solver/static-modeler/07-thermal-heuristic.md @@ -12,7 +12,7 @@ Please note that this content is only relevant in case the user chooses a linear The linearised resolution of the weekly adequacy problem[^1] is summarized in the diagram below: -![Global diagram](img/global_diagram.png){ .add-padding-and-white-bg } +![Global diagram](../img/global_diagram.png){ .add-padding-and-white-bg } The general principle of the linear resolution is that two iterations of the weekly optimisation problem will be solved: - A first resolution in which integer variables are either linearised, or completely removed, depending on the "unit commitment mode" chosen (step 1). @@ -35,33 +35,33 @@ The way steps 1 and 2 are performed depends on a parameter set by the user in th ### Fast mode #### Step 1: first problem resolution -The general idea of the fast mode is to completely remove the constraints and costs involving integers (the $M_\theta$, $M_\theta^+$ and $M_\theta^-$ variables) in step 1. This means that the first resolution of the weekly problem does not consider constraints (17) to (23) in the [optimisation problem formulation](01-modeling.md). Constraint (16) related to the minimum/maximum output of the thermal cluster is kept. In addition, costs related to integer variables (start-up and hourly fixed costs) are not included in the objective function. +The general idea of the fast mode is to completely remove the constraints and costs involving integers (the $M_\theta$, $M_\theta^+$ and $M_\theta^-$ variables) in step 1. This means that the first resolution of the weekly problem does not consider constraints (17) to (23) in the [optimisation problem formulation](05-model.md). Constraint (16) related to the minimum/maximum output of the thermal cluster is kept. In addition, costs related to integer variables (start-up and hourly fixed costs) are not included in the objective function. The first resolution of the problem is then run, and provides hourly power outputs for each thermal cluster $P_{\theta,t}^{optim1}$. At each hour, an initial value of the NODU of each cluster in then calculated: $M_{\theta,t}^{guide}$ = $ceil(\frac{P_{\theta,t}^{optim1}}{\overline{P_{\theta} } }) $. #### Step 2: fast mode heuristic In step 2, for each cluster, a parameter $\Delta_{adjust,\theta} = max(\Delta_\theta^+, \Delta_\theta^-)$ is then calculated, which is the maximum of the minimum on and off durations. Hence, they are approximated to be of the same duration. For each week and each thermal cluster, the week is then divided in intervals of length $\Delta_{adjust,\theta}$. The week is supposed to be cyclic (hour 1 is the timestep followin hour 168), just like in the weekly optimization problem solved by Antares. Within each interval, the NODU of the cluster is increased to the maximum value of $M_{\theta, t}^{guide}$ during this period. This process is run several time by shifting the intervals timestep by timestep until all the possible week splits have been performed. Finally, the solution which minimizes the number of adjustments of the NODU is used as the solution of step 2 $M_{\theta,t}^{heuristic}$. -![Step 2 of the "fast" thermal mode](img/thermal_heuristic_fast_step_2.png){ .add-padding-and-white-bg } +![Step 2 of the "fast" thermal mode](../img/thermal_heuristic_fast_step_2.png){ .add-padding-and-white-bg }

Illustration of step 2 of the fast mode, with $\Delta_{adjust,\theta}$ equal to 2. Here, both solutions are acceptable as they involve 3 NODU adjustments.

#### Step 3: second resolution -Finally, the result of the heuristic $M_{\theta,t}^{heuristic}$ is converted into a lower bound of the power output of each thermal cluster in step 3: $P_{\theta,t}^{min}=\underline{P_\theta}*M_{\theta,t}^{heuristic}$. The second resolution of the problem is then run considering this lower bound, and still excluding integer variables and constraints (17) to (23) of the [optimisation problem formulation](01-modeling.md). In particular, this means that startup and fixed costs are not considered in the formulation of the optimisation problem in any of the two resolutions. However, they are added ex-post and visible in the output variables. +Finally, the result of the heuristic $M_{\theta,t}^{heuristic}$ is converted into a lower bound of the power output of each thermal cluster in step 3: $P_{\theta,t}^{min}=\underline{P_\theta}*M_{\theta,t}^{heuristic}$. The second resolution of the problem is then run considering this lower bound, and still excluding integer variables and constraints (17) to (23) of the [optimisation problem formulation](05-model.md). In particular, this means that startup and fixed costs are not considered in the formulation of the optimisation problem in any of the two resolutions. However, they are added ex-post and visible in the output variables. ### Accurate mode #### Step 1: first problem resolution -The accurate mode aims at taking into account integer variables in both resolutions of the optimisation problem (steps 1 and 3), but considering them as continuous variables in step 1, and fixing them as parameters in step 3. Contrary to the fast mode, constraints (17) to (23) of the [optimisation problem formulation](01-modeling.md) are taken into account in both resolutions, as well as the start-up and fixed costs in the objective function, but the integer variables $M_\theta$ are considered continuous. +The accurate mode aims at taking into account integer variables in both resolutions of the optimisation problem (steps 1 and 3), but considering them as continuous variables in step 1, and fixing them as parameters in step 3. Contrary to the fast mode, constraints (17) to (23) of the [optimisation problem formulation](05-model.md) are taken into account in both resolutions, as well as the start-up and fixed costs in the objective function, but the integer variables $M_\theta$ are considered continuous. The first resolution of the problem is then run. As an output, the integer NODU for each thermal cluster is calculed by rounding up the continuous NODUs which are the output of this resolution: $M_{\theta,t}^{guide}=ceil(M_{\theta,t}^{optim1})$. The variables counting the number of units being started-up or shut-down at any time step $M_{\theta,t}^{+}$ and $M_{\theta,t}^{-}$ are also calculated at that stage. #### Step 2: accurate mode heuristic -Step 2 of the accurate mode starts by checking for each cluster and for each week whether any constraint of minimum time up or down (constraints (22) and (23) of the [weekly optimisation problem](01-modeling.md)) is violated. If no constraint is violated for a given thermal cluster at a given week, no further action is performed and the output variable of this step $M_{\theta,t}^{heuristic}=M_{\theta,t}^{guide}$. +Step 2 of the accurate mode starts by checking for each cluster and for each week whether any constraint of minimum time up or down (constraints (22) and (23) of the [weekly optimisation problem](05-model.md)) is violated. If no constraint is violated for a given thermal cluster at a given week, no further action is performed and the output variable of this step $M_{\theta,t}^{heuristic}=M_{\theta,t}^{guide}$. For a given cluster and a given week, if any of these constraints is violated, a small optimisation problem is run, which aims at minimizing the changes to the NODU of the cluster while respecting constraints (22) and (23). The output of this optimisation problem is then $M_{\theta,t}^{heuristic}$. #### Step 3: second resolution -Finally, the output of step 2 $M_{\theta,t}^{heuristic}$ is converted into a lower bound of the NODU of each thermal cluster for the second resolution: $M_{\theta,t} \geq M_{\theta,t}^{heuristic}$. The second resolution of the problem is then run considering this lower bound, and still including integer variables (as continuous variables) and constraints (17) to (23) of the [optimisation problem formulation](01-modeling.md), and start-up and fixed costs in the objective function. +Finally, the output of step 2 $M_{\theta,t}^{heuristic}$ is converted into a lower bound of the NODU of each thermal cluster for the second resolution: $M_{\theta,t} \geq M_{\theta,t}^{heuristic}$. The second resolution of the problem is then run considering this lower bound, and still including integer variables (as continuous variables) and constraints (17) to (23) of the [optimisation problem formulation](05-model.md), and start-up and fixed costs in the objective function. ## Annual smoothing heuristic (step 4) @@ -77,7 +77,7 @@ with $\sigma_\theta^+$ the startup cost of a unit of cluster $\theta$, and ${\ta The smoothing heuristic may then choose to increase the NODU in certain clusters when it identifies that a shut-down/start-up sequence lasted shorter than duration d. The new NODU cannot exceed the maximum accepted NODU to respect the production plan, which is equal to $floor(\frac{P_\theta}{\underline{P_\theta}})$. -![Step 4: smoothing heuristic](img/thermal_smoothing_heuristic.png). +![Step 4: smoothing heuristic](../img/thermal_smoothing_heuristic.png). -[^1]: The formulation of the weekly optimization problem is described in the ["Formulation of the optimisation problems"](01-modeling.md) section. \ No newline at end of file +[^1]: The formulation of the weekly optimization problem is described in the ["Formulation of the optimisation problems"](05-model.md) section. \ No newline at end of file diff --git a/docs/user-guide/ts-generator/01-overview-tsgenerator.md b/docs/user-guide/ts-generator/01-overview-tsgenerator.md index e77bab6872..67349f7654 100644 --- a/docs/user-guide/ts-generator/01-overview-tsgenerator.md +++ b/docs/user-guide/ts-generator/01-overview-tsgenerator.md @@ -4,6 +4,6 @@ _**This section is under construction**_ The Time-Series Generator tool is intended to be used before running an *Antares* simulation if you do not dispose of all the needed input data. -This tool can be used to generate automatically [any or all](04-parameters.md) stochastic input data +This tool can be used to generate automatically [any or all](../solver/static-modeler/04-parameters.md) stochastic input data (such as renewable energy production time-series) -and put them automatically inside the *Antares* [solver](../solver/02-inputs.md)'s input directory. +and put them automatically inside the *Antares* [solver](../solver/static-modeler/02-inputs.md)'s input directory. diff --git a/docs/user-guide/ts-generator/04-parameters.md b/docs/user-guide/ts-generator/04-parameters.md index debe1465cc..6da36c8ece 100644 --- a/docs/user-guide/ts-generator/04-parameters.md +++ b/docs/user-guide/ts-generator/04-parameters.md @@ -167,7 +167,7 @@ These parameters are listed under the `[input]` section in the `.ini` file. should be exported into the input files (in replacement of the original ones). > _**Note:**_ -> you can also use [archives](../solver/04-parameters.md#archives) to store the time-series in the output folder. +> you can also use [archives](../solver/static-modeler/04-parameters.md#archives) to store the time-series in the output folder. --- ## Seeds - Mersenne Twister parameters diff --git a/mkdocs.yml b/mkdocs.yml index 129404222e..14b203357d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -19,77 +19,94 @@ theme: # - toc.separate palette: - media: "(prefers-color-scheme: light)" - scheme: antares + scheme: default toggle: - icon: material/toggle-switch-off-outline + icon: material/toggle-switch name: Switch to dark mode + - media: "(prefers-color-scheme: dark)" scheme: slate toggle: - icon: material/toggle-switch + icon: material/toggle-switch-off-outline name: Switch to light mode nav: - 'Home': 'index.md' - 'User guide': - - 'Overview': 'user-guide/01-overview.md' - - 'Installation': 'user-guide/02-install.md' - - 'Getting started': 'user-guide/03-getting_started.md' - - 'Solver': - - 'Overview': 'user-guide/solver/01-overview.md' - - 'Input files': 'user-guide/solver/02-inputs.md' - - 'Output files': 'user-guide/solver/03-outputs.md' - - 'Parameters': 'user-guide/solver/04-parameters.md' - - 'Optimization model': 'user-guide/solver/05-model.md' - - 'Hydro heuristics': 'user-guide/solver/06-hydro-heuristics.md' - - 'Thermal heuristics': 'user-guide/solver/07-thermal-heuristic.md' - - 'Command-line instructions': 'user-guide/solver/08-command-line.md' - - 'Optional features': - - 'Multi-threading': 'user-guide/solver/optional-features/multi-threading.md' - - 'Adequacy patch': 'user-guide/solver/optional-features/adequacy-patch.md' - - 'Usage with FICO® Xpress Optimizer': 'user-guide/solver/optional-features/xpress.md' - - 'Appendix': 'user-guide/solver/09-appendix.md' - - 'Time-series generation': - - 'Overview': 'user-guide/ts-generator/01-overview.md' - - 'Input files': 'user-guide/ts-generator/02-inputs.md' - - 'Output files': 'user-guide/ts-generator/03-outputs.md' - - 'Parameters': 'user-guide/ts-generator/04-parameters.md' - - 'Algorithm': 'user-guide/ts-generator/05-algorithm.md' - - 'Command-line instructions': 'user-guide/ts-generator/06-command-line.md' - - 'Other features': - - 'Batch Runner': 'user-guide/other-features/batchrun.md' - - 'Config Checker': 'user-guide/other-features/config.md' - - 'GUI': 'user-guide/other-features/ui-simulator.md' - - 'Kirchhoff''s constraint generator': 'user-guide/other-features/kirchhoff-constraints-builder.md' - - 'Study Cleaner': 'user-guide/other-features/study-cleaner.md' - - 'Study Finder': 'user-guide/other-features/study-finder.md' - - 'Study Updater': 'user-guide/other-features/study-updater.md' - - 'Time-Series Analyzer': 'user-guide/other-features/analyzer.md' - - 'Vacuum': 'user-guide/other-features/vacuum.md' - - 'Year-by-Year Aggregator': 'user-guide/other-features/ybyaggregator.md' - - 'Migration guides': 'user-guide/04-migration-guides.md' - - 'Attribution notices': 'user-guide/05-attribution_notices.md' + - 'Overview': 'user-guide/01-overview.md' + - 'Installation': 'user-guide/02-install.md' + - 'Getting started': 'user-guide/03-getting_started.md' + - 'Solver': + - 'Overview': 'user-guide/solver/01-overview-solver.md' + - 'Static Modeler': + - 'Overview': 'user-guide/solver/static-modeler/01-overview-static-modeler.md' + - 'Input files': 'user-guide/solver/static-modeler/02-inputs.md' + - 'Output files': 'user-guide/solver/static-modeler/03-outputs.md' + - 'Parameters': 'user-guide/solver/static-modeler/04-parameters.md' + - 'Optimization model': 'user-guide/solver/static-modeler/05-model.md' + - 'Hydro heuristics': 'user-guide/solver/static-modeler/06-hydro-heuristics.md' + - 'Thermal heuristics': 'user-guide/solver/static-modeler/07-thermal-heuristic.md' + - 'Dynamic Modeler': + - 'Overview': 'user-guide/solver/dynamic-modeler/01-overview-dynamic-modeler.md' + - 'Input files': 'user-guide/solver/dynamic-modeler/02-inputs.md' + - 'Output files': 'user-guide/solver/dynamic-modeler/03-outputs.md' + - 'Parameters': 'user-guide/solver/dynamic-modeler/04-parameters.md' + - 'Optimization model': 'user-guide/solver/dynamic-modeler/05-model.md' + - 'Heuristics': 'user-guide/solver/dynamic-modeler/06-heuristics.md' + - 'Standard library': 'user-guide/solver/dynamic-modeler/07-standard-library.md' + - 'Hybrid studies': 'user-guide/solver/dynamic-modeler/08-hybrid-studies.md' + - 'Command-line instructions': 'user-guide/solver/02-command-line.md' + - 'Optional features': + - 'Multi-threading': 'user-guide/solver/optional-features/multi-threading.md' + - 'Adequacy patch': 'user-guide/solver/optional-features/adequacy-patch.md' + - 'Usage with FICO® Xpress Optimizer': 'user-guide/solver/optional-features/xpress.md' + - 'Appendix': 'user-guide/solver/03-appendix.md' + - 'Time-series generation': + - 'Overview': 'user-guide/ts-generator/01-overview-tsgenerator.md' + - 'Input files': 'user-guide/ts-generator/02-inputs.md' + - 'Output files': 'user-guide/ts-generator/03-outputs.md' + - 'Parameters': 'user-guide/ts-generator/04-parameters.md' + - 'Algorithm': 'user-guide/ts-generator/05-algorithm.md' + - 'Command-line instructions': 'user-guide/ts-generator/06-command-line.md' + - 'Other features': + - 'Batch Runner': 'user-guide/other-features/batchrun.md' + - 'Config Checker': 'user-guide/other-features/config.md' + - 'GUI': 'user-guide/other-features/ui-simulator.md' + - 'Kirchhoff''s constraint generator': 'user-guide/other-features/kirchhoff-constraints-builder.md' + - 'Study Cleaner': 'user-guide/other-features/study-cleaner.md' + - 'Study Finder': 'user-guide/other-features/study-finder.md' + - 'Study Updater': 'user-guide/other-features/study-updater.md' + - 'Time-Series Analyzer': 'user-guide/other-features/analyzer.md' + - 'Vacuum': 'user-guide/other-features/vacuum.md' + - 'Year-by-Year Aggregator': 'user-guide/other-features/ybyaggregator.md' + - 'Migration guides': 'user-guide/04-migration-guides.md' + - 'Attribution notices': 'user-guide/05-attribution_notices.md' - 'Developer guide': - - 'Overview': 'developer-guide/0-Overview.md' - - 'Development requirements': 'developer-guide/1-Development-requirements.md' - - 'Dependencies install': 'developer-guide/2-Dependencies-install.md' - - 'Build': 'developer-guide/3-Build.md' - - 'Tests (user)': 'developer-guide/4-Tests-user.md' - - 'Tests (developer)': 'developer-guide/4-Tests-dev.md' - - 'Installer creation': 'developer-guide/5-Installer-creation.md' - - 'Contributing': 'developer-guide/6-Contributing.md' - - 'Continuous Integration': 'developer-guide/continuous-integration.md' - - 'OR-tools integration': 'developer-guide/ortools-integration.md' - - 'Changelog': 'developer-guide/CHANGELOG.md' + - 'Overview': 'developer-guide/0-Overview.md' + - 'Development requirements': 'developer-guide/1-Development-requirements.md' + - 'Dependencies install': 'developer-guide/2-Dependencies-install.md' + - 'Build': 'developer-guide/3-Build.md' + - 'Tests (user)': 'developer-guide/4-Tests-user.md' + - 'Tests (developer)': 'developer-guide/4-Tests-dev.md' + - 'Installer creation': 'developer-guide/5-Installer-creation.md' + - 'Contributing': 'developer-guide/6-Contributing.md' + - 'Continuous Integration': 'developer-guide/continuous-integration.md' + - 'OR-tools integration': 'developer-guide/ortools-integration.md' + - 'Changelog': 'developer-guide/CHANGELOG.md' + - 'Software architecture': + - 'Dynamic modeler architecture' : 'developer-guide/Architecture/Dynamic-modeler-architecture.md' - 'External links': - - 'Antares ecosystem': 'https://antares-doc.readthedocs.io' - - 'Antares website': 'https://antares-simulator.org' - - 'RTE website': 'http://www.rte-france.com/' + - 'Antares ecosystem': 'https://antares-doc.readthedocs.io' + - 'Antares website': 'https://antares-simulator.org' + - 'RTE website': 'http://www.rte-france.com/' - 'Contact': 'https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues/new?template=support_request.md' plugins: - search + - plantuml: + puml_url: https://www.plantuml.com/plantuml/ + puml_keyword: plantuml extra_css: - stylesheets/extra.css @@ -107,7 +124,7 @@ markdown_extensions: permalink: true toc_depth: 3 - pymdownx.emoji: - emoji_index: !!python/name:materialx.emoji.twemoji + emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:materialx.emoji.to_svg - admonition - pymdownx.details diff --git a/requirements-doc.txt b/requirements-doc.txt index 80491f6f5b..0ceaecb6b0 100644 --- a/requirements-doc.txt +++ b/requirements-doc.txt @@ -2,3 +2,4 @@ mkdocs mkdocs-material sphinx myst-parser +mkdocs_puml \ No newline at end of file From 427c3959f528da0decf2aecda78e4486d095942c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20Mar=C3=A9chal?= <45510813+JasonMarechal25@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:28:07 +0100 Subject: [PATCH 057/103] 9.2.0-rc5 (#2486) --- docs/developer-guide/CHANGELOG.md | 377 +++++++++++++++++++----------- sonar-project.properties | 6 +- src/CMakeLists.txt | 2 +- src/vcpkg.json | 2 +- 4 files changed, 250 insertions(+), 137 deletions(-) diff --git a/docs/developer-guide/CHANGELOG.md b/docs/developer-guide/CHANGELOG.md index 017a22a11d..ca785b77d5 100644 --- a/docs/developer-guide/CHANGELOG.md +++ b/docs/developer-guide/CHANGELOG.md @@ -5,6 +5,7 @@ toc_depth: 2 # Antares Changelog ## Branch 9.2.x + ### 9.2.0 #### New features * Short term storage withdrawal efficiency [ANT-1862] (#2223) @@ -119,25 +120,35 @@ toc_depth: 2 * Remove unused CMake option BUILD MINIZIP (#2210) * Remove useless forward declaration (#2268) +#### For developers + +* Update ortools to 9.11-rte1.1 +* Various improvement to code quality + ## Branch 9.1.x ### 9.1.0 (06/2024) + #### New features + * Scenarized & hourly values for hydro pumping and hydro generation. Previously this data was not scenarized and daily. * STS groups are now "dynamic" : group names are no longer fixed by code, user is free to define these groups. * Add optimization options from command line in OR-Tools / XPRESS (#1837) #### Improvements + * Rationalize consistency checks on the number of columns (#2073) * Documentation reorganization and improvement (#2024) (#2023) (#2022) * Add doc for thermal heuristic (#2048) #### Bugfixes + * Change the formula used in thermal clusters profits (#2097) [ANT-1719] * Bug on GUI: double-click on study.antares doesn't work anymore (#2047) [ANT-1634] * Fix build error related to Boost Test < 1.67 on OL8 (#2094) #### For developers + * Update format-code.sh (#2027) * Update clang-format options and apply them (#2067) * FileTreeStudyLoader [ANT-1213] (#2058) @@ -155,6 +166,7 @@ toc_depth: 2 * Create & forward declare BasisStatus struct, reduce build time (#2044) #### Code quality + * Simplify code for timer (#2032) * Refactor Application (#2056) * Remove some Yuni Strings in solver (#2061) @@ -167,6 +179,7 @@ toc_depth: 2 * Use std::clamp for sc-builder's hydro levels (#2074) #### Removed + * Remove study cleaner tool (#2059) * Remove export target (#2053) * Remove unique_ptr passed by ref (#2086) @@ -178,91 +191,126 @@ toc_depth: 2 ## Branch 9.0.x ### 9.0.0 + #### License + * Use licence MPL 2.0 instead of GPL3_WITH_RTE-Exceptions (#1812) #### Improvements + * Include overflow variable in HydroPower constraint (#1903) * Add total time logging at the end of the simulation (#1908) * Add STS level constraint to suspect list for infeasible problem analysis (#1891) #### For developers + * Use precompiled OR-Tools for Oracle Linux 8 CI (#1893) * Change version behavior to allow more flexibility (#1898) #### Code quality + * Use std::shared_ptr instead of indices for active binding constraints in results (#1887) * Fix a few compilation warnings (#1880) * Scratchpad numspace (#1749) #### Tests + * Fix invalid index causing segfault in `test-study` test (#1902) ## Branch 8.8.x (end of support 12/2025) + ### 8.8.10 (09/2024) + #### Bugfix (adequacy patch) + * Force enable-first-step=false [ANT-2218] (#2419) * Adequacy patch CSR - revamp output variables [ANT-1932] (#2421) * Place CSR after hydro remix [ANT-2070] (#2407) #### Bugfix (other) + * Use OR-Tools v9.11-rte1.1 [ANT-2069] (#2418) ### 8.8.9 (09/2024) + * Revert "Fix bug hydro heuristic with mingen (ANT-1825) (#2258)" ### 8.8.8 (09/2024) + #### Bugfix + * Timeseries generation stored in input (#2180) * Fix bug hydro heuristic with mingen (ANT-1825) (#2258) ### 8.8.7 (07/2024) + #### Improvements + - Add OR-Tools solver option for batchrun tool (#1981) #### Bugfix + - Adequacy Patch regression [ANT-1845] #2235 ### 8.8.6 (07/2024) + #### Bugfix + - Fix missing synthesis results for links (#2115) + #### Dependencies + - Update vcpkg (fix Boost) ### 8.8.5 (05/2024) + #### Bugfix + - [UI] Fix opening a study from the file browser - Fix crash occurring when duplicate thermal clusters are present in a study (same name) - Fix formula for "PROFIT BY PLANT" ### 8.8.4 (03/2024) + #### Bugfix + * Adequacy patch CSR - fix DTG MRG (#1982) * Fix ts numbers for no gen clusters (#1969) * Remove unitcount limit for time series generation (#1960) ### 8.8.3 (02/2024) + #### Bugfix -* Fix an issue where depending on the platform the output archive could contain several entries of the same area and interco files + +* Fix an issue where depending on the platform the output archive could contain several entries of the same area and + interco files ### 8.8.2 + #### Bugfix -* Fix segfault caused by uninitialized `cluster.series.timeseriesNumbers` (#1876). This bug was introduced in v8.8.1 by #1752 + +* Fix segfault caused by uninitialized `cluster.series.timeseriesNumbers` (#1876). This bug was introduced in v8.8.1 by + #1752 * Bump OR-Tools from 9.5 to 9.8 (fix crash with XPRESS) (#1873) ### 8.8.1 (01/2024) + /!\ This version has known bugs, please use 8.8.2 instead. #### Bugfix + * Simplify TS numbers drawings, fix bug related to refresh & local thermal generation (#1752) #### Improvements -* Take into account breaking change in OR-Tools's API, enable SCIP & GLPK solvers, bump OR-Tools (#1825). This should improve performances with FICO XPRESS + +* Take into account breaking change in OR-Tools's API, enable SCIP & GLPK solvers, bump OR-Tools (#1825). This should + improve performances with FICO XPRESS * Fail if OR-Tools solver is not found (#1851) * Normalize simulation mode Expansion, fix logs (#1771) * Add possibility to release without running any tests (#1852) #### Code quality + * Use `std::unordered_map` for tmpDataByArea_ (hydro ventilation) (#1855) * Remove `mutable` keyword from `PROBLEME_HEBDO` (#1846) * Remove `Study::gotFatalError`, throw exceptions instead (#1806) @@ -271,9 +319,11 @@ toc_depth: 2 * Remove `YUNI_STATIC_ASSERT` (#1863) #### Testing + * Add tests on short-term storage/thermal cluster/renewable cluster removal (#1841) #### Doc + * Add precision about `enabled` field in ST storage (#1850) * Use dedicated URL path for Doxygen, instead of root (#1865) * Fix HTML generation for readthedocs (#1867) @@ -283,12 +333,14 @@ toc_depth: 2 -------------------- #### New features + * New "cash-flow" variable for ST storage (#1633) * Experimental optimization with discrete variables (MILP unit-commitment mode #670) * Add `enabled` property for ST storage objects, fix bug related to saving ST objects (#1807) * Solver logs can be enabled either by the command-line option (--solver-logs) or in the generaldata.ini #### Improvements + * Add shortcut -s for names MPS problems in CLI options (#1613) * Use 50% as a default value for ST-storage property initiallevel (#1632) * Add warning logs for non-existent output variable (#1638) @@ -298,13 +350,16 @@ toc_depth: 2 * New log msg when solver not found in or-tools (#1687) #### For developers + * Fix annoying error log about correlation matrices in tests (#1573) #### Bugfixes (reported by users) + * Fix output variable PROFIT for thermal clusters (#1767) * Bug on renewable cluster (wrong group) (#1631) #### Bugfixes (reported internally) + * Fix oracle-linux8 binaries missing compression feature (#1741) * Named MPS - fix duplicated "ranged" binding constraints (#1569) * Fix save for short term storage objects (#1807) @@ -317,21 +372,25 @@ toc_depth: 2 * Fix writer causing a segfault with OR-Tools (#1584) #### Documentation + * Create Doxygen documentation (#1650) * Update README.md (#1654) * Add advice for developers (#1639) * Document the usage of XPRESS (#1596) #### GUI + * Fix regression on cluster renaming, add unit tests (#1699) #### Dependencies + * Use minizip-ng 4.0.1 (from 3.0.7) (#1696) * Bump vcpkg to latest tag (2023.07.21) (#1532) * Remove dead code yuni-docmake (#1544) * Remove fixed-size ints from Yuni (#1622, #1629) #### Code cleaning / quality + * Architecture Decision Record for Study breakdown (#1600) * Remove dependency to UI, use RAII to handle resources (#1678) * De-templatize `HydroManagement::prepareNetDemand` (#1679) @@ -373,6 +432,7 @@ toc_depth: 2 * Remove tmpnam from tests (#1506) #### Build + * ACR CMake (#1551) * Add "Antares::action" CMake library, build only if BUILD_UI=ON (#1637) * Fix conflicting library name (#1590) @@ -385,55 +445,71 @@ toc_depth: 2 * Fix build for Oracle Linux 8 (#1542) #### Misc + * Schedule deps compile instead of develop merge (#1530) ## Branch 8.7.x ### 8.7.3 (02/2024) + #### Bugfix + * Use OR-Tools v9.8-rte1.0 (performance improvements with OR-Tools + XPRESS) ### 8.7.2 (11/2023) + #### Bugfix + * Named MPS - fix duplicated "ranged" binding constraints (#1569) ### 8.7.1 (11/2023) + #### Bugfix + * Fix output variable PROFIT for thermal clusters (#1767) ### 8.7.0 (08/2023) + #### New Features + * Binding constraint RHS scenarization (#1219) * Implement --mps-export command-line option (#1404) * Name constraints & variables in MPS files using --named-mps-problems command-lin e option (#1294) * Thermal price definition (contributed by RTE-i, #1272) #### Improvements + * Write full command-line instead of solver location in logs (#1518) #### Packages + * Give Oracle Linux 8 assets a proper name instead of "unknown" (#1438) * Don't build tools (study-updater, etc.) by default (#1442) #### Bugfixes + * Fix error when writing files over 80Mb into a zip (#1488) * Fix memory leaks (#1468) * Fix segfault, add !skipped to enabled constraints (#1441) * Backport [v8.4.3](#v843-082023) changes #### GUI + * Thermal price definition (RTEi's -> CR20) - UI (#1485) #### Docs + * Fix possible values for ST storage (#1455) #### Tests + * Add named MPS tests (#1408) * Enforce better unit test isolation (#1486) * Add tests for Windows CI when job is scheduled (#1483) * Tests for CR20: thermal price definition (#1364), improvements (#1422) #### For developers + * Remove platform-specific headers (#1523) * Remove one `goto` instruction in OPT (#1522) * Remove study singleton in application signal handlers (#1513) @@ -463,53 +539,76 @@ toc_depth: 2 * Array, logs jit and correlation in makefile (#1410) ## Branch 8.6.x (end of support 06/2025) + ### 8.6.8 (07/2024) + #### Bugfix + - [UI] Remove propery storagecycle for short term storage added when saving a study (#2037) + #### Dependencies + - Update vcpkg (fix Boost) ### 8.6.7 (05/2024) + #### Bugfixes -* Fix formula use in output var Profit by plant [ANT-1719] (https://github.com/AntaresSimulatorTeam/Antares_Simulator/pull/2097) + +* Fix formula use in output var Profit by + plant [ANT-1719] (https://github.com/AntaresSimulatorTeam/Antares_Simulator/pull/2097) ### 8.6.6 (03/2024) + #### Bugfixes + * Adequacy patch CSR - fix DTG MRG (#1982) * Fix ts numbers for no gen clusters (#1969) * Remove unitcount limit for time series generation (#1960) ### 8.6.5 (02/2024) + #### Bugfix + * Use OR-Tools v9.8-rte1.0 (performance improvements with OR-Tools + XPRESS) ### 8.6.4 (11/2023) + #### Bugfixes + * Fix Oracle Linux minizip build + actually run zip unit tests (#1744) * Fix output variable PROFIT for thermal clusters (#1767) ### 8.6.3 (10/2023) + #### Bugfixes + * Increase file size limit from 80Mo to 80Go when reading file. Fix issue on Windows ### 8.6.2 (08/2023) + #### Bugfixes + * Backport [v8.4.3](#v843-082023) changes ### 8.6.1 (06/2023) -------------------- + #### Bugfixes + * Fix major bug related to short-term storage & MRG. PRICE (#1377) ### 8.6.0 (06/2023) -------------------- + #### New features + * Short-term storage (#1163). * Add pollutant emissions (#1184, #1222) * Minimal generation for hydraulic (#1273, RTE/RTE-i/Redstork) * Make LMR optional for adequacy patch (#1247) #### Improvements + * Use ISO8601 for date format in the logs (#1303) * Publish installers for Oracle Linux 8 (#1341) * Remove doc from UI/package, publish it as a separate PDF (#1233) @@ -517,11 +616,13 @@ toc_depth: 2 * Performance metrics (produce a JSON file) (#1306) #### Bugfixes + * Fix a bug in adequacy study mode (#1314) * Fix memory errors detected by valgrind (#1302) * Fix empty ROR & STORAGE in output using the TS-Generator (#1293) #### Code quality + * Simplify if/else (#1309) * Max number of columns in an output file (#1159) * Fix a few compilation warnings (int -> uint) (#1301) @@ -535,69 +636,87 @@ toc_depth: 2 * Remove group{Min,Max}Count, annuityInvestment in thermal clusters (#1350) #### For developers -* Bumped OR-Tools 9.2 -> 9.5. CMake 3.18+ is required for build if building OR-Tools, and XPRESS 9.0 for execution (previously 8.13). + +* Bumped OR-Tools 9.2 -> 9.5. CMake 3.18+ is required for build if building OR-Tools, and XPRESS 9.0 for execution ( + previously 8.13). + ## Branch 8.5.x ### 8.5.1 (08/2023) -------------------- + #### Changes + * Backport [v8.4.3](#v843-082023) changes ### 8.5.0 (02/2022) -------------------- + #### New features -* Curtailment Sharing Rule for Adequacy Patch #1062, including a scaling coefficient in hurdle costs #1155. This feature was contributed by RTE-i with support from RTE, ELIA and APG. + +* Curtailment Sharing Rule for Adequacy Patch #1062, including a scaling coefficient in hurdle costs #1155. This feature + was contributed by RTE-i with support from RTE, ELIA and APG. #### Bugfix + * Hydraulic patch #697 * Fix link path error in Kirchhoff constraint builder #1157 #### For developers + * Fix build on Ubuntu 22.04 #1160 * Cleaning #1142, 1146, #1149 #### Examples & documentation + * Update docs to include CSR #1156 * Fix examples studies (invalid v8.3.0 -> v8.5.0) #1136 + ## Branch 8.4.x ### 8.4.3 (08/2023) -------------------- #### Features + * Increase file size limit from 80Mo to 80Go when reading file. #### Bugfix -* Fix "unhandled error" with big studies in zip mode. MPS files were too big and hit file size hard limit +* Fix "unhandled error" with big studies in zip mode. MPS files were too big and hit file size hard limit ### 8.4.2 (01/2022) -------------------- #### Improvements + * Generate a solver-only asset for every release #976, #1080 * Use MPS writer from solvers, instead of copy-pasted functions #1023 #### GUI + * Allow more than 100 thermal clusters #1011 * Remove status bar count. The sum was sometimes wrong #1029 * Remove unused "District marginal prices" button from Advanced Parameters #1067 #### Bugfix + * Fix overwritten MPS files when optimization/simplex-range=day #1041 * Restore warm start for OR-Tools+XPRESS #1079 * Fix output overwrite when using zip output by adding a -2, -3, etc. suffix #1044 * Fix crash when generaldata.ini is empty, using default values #892 - #### Testing + * Introduce missing MPS comparison tests #1035 #### For developers + * Fix empty CMAKE_BUILD_TYPE #1028 * Fix memory leaks #669 #### Code cleaning + * Clean up Yuni #1055 * Remove default implementation for hourEnd (see variable.hxx) #1020 * Remove free functions for areas' mem allocation #922 @@ -605,12 +724,13 @@ toc_depth: 2 * Remove unused `ContrainteDeReserveJMoins1ParZone`, `NumeroDeVariableDefaillanceEnReserve` #1047 * Extract code related to spilled energy bounds #1049 * Simplify code for adq patch (Local matching) #1054 -* Refactor naming for {MPS, criterion, etc.} files and exported structures (see parameter optimization/include-exportstructure) #1030 +* Refactor naming for {MPS, criterion, etc.} files and exported structures (see parameter + optimization/include-exportstructure) #1030 * Refactor: move current year and week from study to weekly optimization problem #1032 * Pass optimization number as an argument #1040 - #### New Contributors + * @JasonMarechal25 made their first contribution in #1055 **Full Changelog**: https://github.com/AntaresSimulatorTeam/Antares_Simulator/compare/v8.4.1...v8.4.2 @@ -619,12 +739,14 @@ toc_depth: 2 -------------------- #### Bugfix + * Fix formula for profit calculation #1022 ### 8.4.0 (12/2022) -------------------- #### Features + * Add option & command-line argument to write results into a single zip archive #794 * Add option to set link capacity to null/infinity for physical links only #792 * Speed up simulations by extracting simplex basis in XPRESS/OR-Tools #957 @@ -633,9 +755,11 @@ toc_depth: 2 * Enable MPS write with OR-Tools+Sirius #### GUI + * Make sure that RC/beta are displayed in version numbers #739 #### Bugfix + * Remove error message printed on -h/--help in antares-solver #895 * Use average for BC MARG PRICE (daily & weekly) #940 * Fix crash when exporting MPS with OR-Tools #923 @@ -648,6 +772,7 @@ toc_depth: 2 * Add condition to avoid null pointer by @payetvin in #989 #### For developers + * Case insensitive option for build type by @payetvin in #986 * [DEV] Refactored ortools_utils by @payetvin in #978 * [CI] Integrate ortools v9.2-rte2.0 by @payetvin in #1007 @@ -660,37 +785,47 @@ toc_depth: 2 * Use GIT_SHALLOW for OR-Tools's FetchContent #904 * Remove antares-solver swap variant & librairies, reduce build duration #906 - #### Documentation + * [DOC] OR-Tools build #880 * Document how to run JSON tests #902 * Document option --list-solvers #770 #### New Contributors + * @kathvargasr made their first contribution in #967 **Full Changelog**: https://github.com/AntaresSimulatorTeam/Antares_Simulator/compare/v8.3.2..v8.4.0 ## Older branches + ### 8.3.3 (12/2022) -------------------- + #### Bugfix + - Round renewable production (#985) ### 8.3.2 (09/2022) -------------------- + #### Output aggregation change -- Daily, weekly, monthtly & annual values for link variable "MARG. COST" (EUR/MWh) was previously obtained by a sum. It now computed by average (#881). + +- Daily, weekly, monthtly & annual values for link variable "MARG. COST" (EUR/MWh) was previously obtained by a sum. It + now computed by average (#881). #### New features + - Add new BC marginal price output variable (#801) - Add Antares logo in solver logs (#861) - Add XPRESS-compatible assets for Ubuntu. Windows coming soon. #### GUI + - In the "Links" panel, replace "Flat" view by "By area" view (#755) #### Bug fixes + - Fix segfault when more than 9 renewable clusters are present in an area (#869) - Fix segfault related to the digest occurring when many thermal clusters are present (#852) - Statistics: use std::mutex / std::atomic<> to prevent concurrent writes (#838) @@ -699,6 +834,7 @@ toc_depth: 2 - MPS for the 1st optimization were erased by the one related to the 2nd optimization. Fixed (#863). #### For developers + - Simplify day ahead reserve condition (#777) - Remove unused "shedding strategy" (#788) - Refactor Layers by adding a LayerData class (#866) @@ -710,29 +846,40 @@ toc_depth: 2 - Simplify tuneSolverSpecificOptions (#829) #### Documentation + - Input and output format due to addition of BC marginal prices (#836) - Fix e-mail address and website (#834) ### 8.3.1 (08/2022) -------------------- + #### New features + - Add execution-info.ini output file, containing execution durations and study info #740 #803 #816 - OR-Tools: set solver-specific options for XPRESS #796 #### Bug fixes + - Fix missing renewable columns in districts (sets of areas) #802 #### GUI + - Fix wrong number of cores in the "Run a simulation" window #793 #### For developers + - Bump C++11 to C++17 ### 8.3.0 (07/2022) -------------------- + #### New features -- Adequacy patch - share the unsupplied energy according to the "local matching rule". This feature was contributed by RTE-i with support from RTE, ELIA and APG #657 -- Add output variable "profit by cluster". This variable represents the difference between proportional costs and marginal costs in the area. It provides a partial answer to the question "what is the economic profit associated to a thermal cluster ?", excluding non-proportional (€/h) and startup costs (€/startup). #686 + +- Adequacy patch - share the unsupplied energy according to the "local matching rule". This feature was contributed by + RTE-i with support from RTE, ELIA and APG #657 +- Add output variable "profit by cluster". This variable represents the difference between proportional costs and + marginal costs in the area. It provides a partial answer to the question "what is the economic profit associated to a + thermal cluster ?", excluding non-proportional (€/h) and startup costs (€/startup). #686 - Allow +/- infinity in binding constraint RHS, allowing the user to enable BCs only for some timesteps #631(*) - Add option to enable the splitting of exported MPS files. This feature is intended to be used by Antares Xpansion. - Add --list-solvers command-line argument, to list linear solvers available through OR-Tools @@ -741,6 +888,7 @@ toc_depth: 2 (*) May not work with the Sirius solver. Consider using other solvers through OR-Tools #### Bug fixes + - Fix segfault occuring when inter/intramodal correlation is enabled and TS width are inconsistent #694 - Fix logging of performed MC years when running jobs in parallel #680 - Fix a crash occuring in studies where an area contains 100+ thermal clusters (#753) @@ -750,6 +898,7 @@ toc_depth: 2 - UI - Fix GUI freeze when using multiple map layers (#721) #### For developers + - Display the git commit-id in the logs for debugging & diagnosis purposes #698 - Code cleaning in hydro heuristic #671 - Use antares-deps 2.0.2, which now excludes OR-Tools #684 @@ -757,30 +906,40 @@ toc_depth: 2 - Code cleaning #663 #665 #666 #687 #725 #667 #668 #730 #### Misc. improvements + - Generate 2 assets in CentOS 7 : one that includes XPRESS, one that does not #689 - Upgrade examples 8.1 -> 8.3 (#733) ### 8.2.3 (11/2022) -------------------- + #### Bug fixes + - Round renewable production (#985) ### 8.2.2 (04/2022) -------------------- + #### Bug fixes + - Fix solver crash on parsing command-line parameters #624 + #### GUI + - Fix crash occuring when switching to the links panel #658 ### 8.2.1 (03/2022) -------------------- + #### Bug fixes + - Fix scenario builder data loss when renaming area #610 - Write 1 in the ts-numbers when series.width == 1 #609 - Add noise to the cost vector in the allocation problems to enforce uniqueness #622 - Linux only : fix segfault occurring when an INI file does not exist #606 #### GUI + - Place "Dataset > Resize columns to..." in first position #607 - Allow that all NTC be 0 in one direction #595 - Fix occasional crash when opening the links panel #594 @@ -790,24 +949,32 @@ toc_depth: 2 ### 8.2.0 (03/2022) -------------------- + #### New features -- Multiple timeseries for link capacities (NTC). It is now possible to establish different scenarios for the capacity of a link. Users can now take partial or total outages for links into account #520 -- Infeasible problem analyzer. When the underlying problem has no solution, list the most suspicious constraints in a report. This should help users identify faulty binding constraints #431 + +- Multiple timeseries for link capacities (NTC). It is now possible to establish different scenarios for the capacity of + a link. Users can now take partial or total outages for links into account #520 +- Infeasible problem analyzer. When the underlying problem has no solution, list the most suspicious constraints in a + report. This should help users identify faulty binding constraints #431 - Add a hydro-debug switch that allows the printing of some useful debug data in heuristic mode #254 #### GUI + - Add a "view results" button in the dialog that appears when a simulation has been completed #511 - Help menu : add an "online documentation" item #509 - Improve UI for new thermal parameter "tsGenBehavior" #534 - Improve cell styles when loop-flow is enabled for a link #571 #### Bug fixes + - Prevent an area from having a link to itself #531 - Fix crash when the study folder does not exist #521 - Fix crash when failing to load a study #502 #### For developers -- Remove calls to exit() #505. Provide consistent return values for antares-solver by fixing a segfault related to the log object #522 + +- Remove calls to exit() #505. Provide consistent return values for antares-solver by fixing a segfault related to the + log object #522 - Remove calls to setjmp, goto's big brother #527 - Large refactor of antares-solver's main function, hoping to make error management easier to understand #521 - Use std::shared_ptr instead of Yuni::SmartPtr in most cases #529 @@ -817,36 +984,51 @@ toc_depth: 2 -------------------- #### Bug fixes + - Fix segfault occurring randomly when thermal clusters are disabled (#472) -- Fix hydro level discontinuities (#491). Very rarely, hydro reservoirs would inexplicably be filled from 0% to 100% in 1h, this violating the modelling constraints. -- Execution times when the Sirius solver is used in conjunction with OR-Tools are now similar as with Sirius alone. This is a result of [this fix](https://github.com/AntaresSimulatorTeam/or-tools/pull/1), related to "hot-start". +- Fix hydro level discontinuities (#491). Very rarely, hydro reservoirs would inexplicably be filled from 0% to 100% in + 1h, this violating the modelling constraints. +- Execution times when the Sirius solver is used in conjunction with OR-Tools are now similar as with Sirius alone. This + is a result of [this fix](https://github.com/AntaresSimulatorTeam/or-tools/pull/1), related to "hot-start". #### GUI + - Speed up scrolling (#395) - Warn the user about disabled renewable clusters only when relevant (#386) #### Packages -Include antares-analyzer into .zip and .tar.gz archives (#470). This is especially useful if you use the portable version of Antares. + +Include antares-analyzer into .zip and .tar.gz archives (#470). This is especially useful if you use the portable +version of Antares. #### For developers -In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in particular gcc 9. This allows for C++17 features to be used without hassle. + +In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in particular gcc 9. This allows for C++17 +features to be used without hassle. ### 8.1.0 (09/2021) -------------------- #### New features -- Allow up to 9 RES groups (off-shore wind, on-shore wind, rooftop solar, PV solar, etc.) as opposed to wind and solar previously. This allows the user to distinguish between more renewable energy sources. When creating a new study, renewable generation modelling is set to "clusters" by default. This change does not affect opening an existing study. Note that TS generation is not available for these new RES groups. + +- Allow up to 9 RES groups (off-shore wind, on-shore wind, rooftop solar, PV solar, etc.) as opposed to wind and solar + previously. This allows the user to distinguish between more renewable energy sources. When creating a new study, + renewable generation modelling is set to "clusters" by default. This change does not affect opening an existing study. + Note that TS generation is not available for these new RES groups. - Add 3 thermal groups, named other, other 2, other 3 and other 4. #### Bug fixes + - When a binding constraint is marked as skipped in the GUI, disable it in the solver #366 #### GUI + - Keep selection on thermal/renewable cluster when its group changes #360 - Dialogs "Thematic trimming" and "User playlist" are now resizable #### For developers + - Add non-regression tests on each release - Fix vcpkg on Github Actions - Add build cache for Github Actions to speed up the build (Linux only) @@ -877,6 +1059,7 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti ### 8.0.1 (03/2021) -------------------- + #### Features - Add "Continue Offline" button at startup if antares metric server is unreachable @@ -886,7 +1069,8 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Error with hydro start when using scenario playlist and stochastic TS refresh span - Files needed for antares-xpansion not exported when using scenario playlist with first year disabled - Correction of crash if user define a stochastic TS refresh span of 0 : minimum value is now 0 -- Correction of MC years playlist weight write when sum of weight was equal to number oy years (no MC years playlist export in .ini) +- Correction of MC years playlist weight write when sum of weight was equal to number oy years (no MC years playlist + export in .ini) #### For developers @@ -899,10 +1083,12 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti #### Features - OR-Tools integration : - - add command line option in antares-solver to define OR-Tools use and OR-Tools solver (option --use-ortools and --ortools-solver='solver') + - add command line option in antares-solver to define OR-Tools use and OR-Tools solver (option --use-ortools and + --ortools-solver='solver') - add GUI option in run simulation to define antares-solver launch with OR-Tools option -- Add advanced hydro allocation feature. The default and existing behavior is to accomodate the guide curves, the new behavior is to maximize generation, even if it means that the reservoir level goes beyond the guide curves. +- Add advanced hydro allocation feature. The default and existing behavior is to accomodate the guide curves, the new + behavior is to maximize generation, even if it means that the reservoir level goes beyond the guide curves. - Add indication on how to disable anonymous metrics @@ -932,19 +1118,24 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti #### Bug fixes -- Selecting an area and then, from the inspector, trying to select a thermal cluster or a link of this area in the dependencies +- Selecting an area and then, from the inspector, trying to select a thermal cluster or a link of this area in the + dependencies section causes a crash. The inspector's cluster/link selection was removed. - Scenario builder : - - It makes no sense for the user to access the scenario builder Configure menu item whereas the Building mode parameter is set + - It makes no sense for the user to access the scenario builder Configure menu item whereas the Building mode + parameter is set to Automatic or Derated. In the previous cases, the Configute menu item is disabled. - - If a disabled thermal cluster is given a time series number in a non active rule of the scenario builder, a warning should not be - triggered. If the disabled cluster is given a number for many MC years in the active rule, a single summary warning should be raised, + - If a disabled thermal cluster is given a time series number in a non active rule of the scenario builder, a + warning should not be + triggered. If the disabled cluster is given a number for many MC years in the active rule, a single summary + warning should be raised, not a warning per year. #### For developers - External dependencies : - - use of new repository [antares-deps](https://github.com/AntaresSimulatorTeam/antares-deps) for external dependencies compilation + - use of new repository [antares-deps](https://github.com/AntaresSimulatorTeam/antares-deps) for external + dependencies compilation - Fix several compilation warnings - Remove unused `COUT_TRANSPORT` constant @@ -957,7 +1148,8 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - continuous integration : - use docker images in CI - use of antares-deps release artifact in CI - - push of docker image to dockerHub in [antaresrte/rte-antares repository](https://hub.docker.com/repository/docker/antaresrte/rte-antares) + - push of docker image to dockerHub + in [antaresrte/rte-antares repository](https://hub.docker.com/repository/docker/antaresrte/rte-antares) - add Centos7 support - Unit tests : @@ -975,7 +1167,7 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Simulation dashboard: A new "Geographic Trimming" option is now available in the "Configure" menu. This option makes - it possible to filter the simulation's output content so as + it possible to filter the simulation's output content so as to include only results regarding Areas and Links of interest - Optimization: a new parameter "Unfeasible Problems Behavior" @@ -1158,7 +1350,7 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti New link parameters (one value) Asset type (AC,DC,Gas,Virtual,Other) : KCG deals only with AC links "account for loop flow" toggle - "tune PST" toggle + "tune PST" toggle KCG generating directives: Working map to use for generation Calendar to use for constraints activation (relaxation outside) @@ -1192,18 +1384,18 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti Res.level initialization date: redefined at the monthly scale New hydro variables and parameters: Input : max daily hydro generating energy - max daily hydro pumping energy and power - monthly-to-daily inflow breakdown pattern + max daily hydro pumping energy and power + monthly-to-daily inflow breakdown pattern water value (time, level) modulation of max generating power (level) modulation of max pumping power (level) pumping efficiency +many "storage management options" parameters - Output: Reservoir level (H.LEV) - Water value (H.VAL) - Pumping power (H.PUMP) - Natural Inflow (H.INFL) - Forced Overflow (H.OVFL) + Output: Reservoir level (H.LEV) + Water value (H.VAL) + Pumping power (H.PUMP) + Natural Inflow (H.INFL) + Forced Overflow (H.OVFL) Cost of Gen+Pumping (H.COST) Optimization preferences: "Hot/Cold start" (year N may start or not at the final N-1 level) @@ -1233,7 +1425,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Output: the link-variable "MARG.COST" was rounded to an integer value (changed to 2 decimal accuracy) - ### 6.1.3 (06/2018) ---------------- @@ -1264,7 +1455,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Example library : upgraded to 6.1 and extended - ### 6.1.2 (11/2017) ---------------- @@ -1273,7 +1463,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Solver, Simplexe package: Improvement of the Scaling stage (Matrix, right hand side, costs) - ### 6.1.1 (11/2017) ---------------- @@ -1281,7 +1470,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Solver: Light changes in Presolve stage - ### 6.1.0 (09/2017) ---------------- @@ -1290,10 +1478,9 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - GUI and simulation: "binding constraints" objects may now involve not only flows on interconnections but also power generated from thermal clusters. Alike flows, generation from thermal clusters may - be handled either on an hourly, daily or weekly basis and may be + be handled either on an hourly, daily or weekly basis and may be associated with arbitrary offsets (time-lags expressed in hours). - ### 6.0.6 (07/2017) ---------------- @@ -1305,8 +1492,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Solver: strenghtening of the final admissibility check step in the "accurate" commitment mode - - ### 6.0.5 (07/2017) ---------------- @@ -1321,7 +1506,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Study Cleaner: Unwarranted removal of the graphic multi-map lay-out could occur when cleaning datasets (detected as of 6.0.0) - ### 6.0.4 (06/2017) ---------------- @@ -1333,7 +1517,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Simulation: Negative "ROW Balance" is properly included in unsupplied energy allowances - ### 6.0.3 (06/2017) ---------------- @@ -1348,12 +1531,11 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti current map was sometimes wrongly initialized (Area considered selected though not explicitly clicked on yet) -- GUI: The order in which binding constraint terms are shown in the - "summary" Window could depend on the execution platform used - -- GUI: The Antares study icon could not be properly copied in some - circumstances +- GUI: The order in which binding constraint terms are shown in the + "summary" Window could depend on the execution platform used +- GUI: The Antares study icon could not be properly copied in some + circumstances ### 6.0.2 (06/2017) ---------------- @@ -1371,7 +1553,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti reached could be ambiguous when identical results are found for two years ore more. - ### 6.0.1 (05/2017) ---------------- @@ -1381,7 +1562,7 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti are generated and stored in the same way, regardless of their activity status (unabled/disabled). This makes easier to check data consistency -- Simulation: Upper bounds for spilled power and unsupplied power are +- Simulation: Upper bounds for spilled power and unsupplied power are actually set to their maximum theoretical value(i.e. if economic conditions make it justified: spill all power or shed all demand) So far, spillage of power that could be absorbed by the local demand @@ -1399,7 +1580,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti automatic simulation sequences taking into account the simplifications listed above - ### 6.0.0 (04/2017) ---------------- @@ -1415,10 +1595,10 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti in multiple Antares sessions - Simulation: Introduction of a flexible multi-threaded mode for the processing - of heavy problems: Antares "Monte-Carlo years" can be be distributed on a + of heavy problems: Antares "Monte-Carlo years" can be be distributed on a number of CPU cores freely set by the user. This parameter appears as a new - tunable item of the "advanced parameters" list attached to any Antares Study. - Five values are available in the [1, N] interval, N being the number of CPU + tunable item of the "advanced parameters" list attached to any Antares Study. + Five values are available in the [1, N] interval, N being the number of CPU cores of the machine (virtual or physical) Antares is run on - License control through the internet: a new system has been developed for @@ -1436,7 +1616,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti such as study archiving/expansion (use of a specific compressed format), copy to backup folders, registering of studies and archives in catalogues. - ### 5.0.9-SE (04/2017) ---------------- @@ -1457,7 +1636,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - License control : management of SSL certificates encrypted through SHA-256 algorithm - ### 5.0.7 (12/2016) ---------------- @@ -1465,7 +1643,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Fixing a packaging error - ### 5.0.6 (12/2016) ---------------- @@ -1478,7 +1655,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti a thermal cluster could result in a partial dataset corruption (references to the deleted object were kept alive in the scenario builder context) - #### Features - Unsupplied energy control: if the actual economic optimization requires it, load @@ -1495,14 +1671,12 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti on the first hour of the year, were re-written to be compatible with the next versions of Antares, which will be fully multi-threaded - - ### 5.0.5 (08/2016) ---------------- #### Bug fixes -- No-Load Heat costs and Start-up costs: in the "fast" unit commitment options, +- No-Load Heat costs and Start-up costs: in the "fast" unit commitment options, the result was slightly below the actual optimal possible cost for some datasets (i.e. datasets in which the thermal cluster coming last in alphabetic order had a minimum stable power equal to zero). @@ -1511,7 +1685,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti be split between the different possible sources when there is a choice to make can work properly again (feature inhibited in previous 5.0.x versions) - #### Features - License control throughout the internet: all combinations of UTF8 characters can @@ -1521,7 +1694,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti exceeds that of load, the fact that the demand should necessarily be served is locally expressed as a constraint of the optimization problem (LOLE=0) - ### 5.0.4 (05/2016) ---------------- @@ -1537,7 +1709,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Binding constraints including offset parameters: unbounded positive or negative values can be used for all classes of constraints (hourly, daily, weekly) - ### 5.0.3 (05/2016) ---------------- @@ -1546,7 +1717,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Crashes occured when the "full must-run status" parameter was set on "true" for thermal clusters - ### 5.0.2 (04/2016) ---------------- @@ -1560,7 +1730,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti each month incorporates heavier penalization terms for the 12 deviations from the theoretical monthly targets (formerly, only the largest deviation was penalized). - ### 5.0.1 (04/2016) ---------------- @@ -1572,7 +1741,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - In the previous version, additional logs were added. That could lower the simulation performances in some cases. This problem is now solved. - ### 5.0.0 (03/2016) ---------------- @@ -1604,7 +1772,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Output, File comparison functions: "Max" operator has been added - #### Features - Optimization: introduction of a new unit-commitment mode based on a MILP approach slower but more @@ -1638,8 +1805,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Output: In synthetic Monte-Carlo results,year-by-year results and cluster-by-cluster results, Addition of a field "Number of dispatched units" (NODU) - - ### 4.5.4 (03/2015) ---------------- @@ -1667,7 +1832,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Control of license validity through the internet (setting up of a dedicated server) - #### Bug fixes - Scenario builder: indices not subject to random draws could be mixed up in areas @@ -1706,7 +1870,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Copy/paste of nodes : the field "spread on unsupplied energy cost" was not pasted - ### 4.5.0 (04/2014) ---------------- @@ -1720,7 +1883,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Identical upper and lower bounds have been set for the absolute values of all non-zero system costs ( max = 5 10^4 Euros/MWh ; min = 5 10^-3 Euros/MWh) - #### Bug fixes - Hydro Time-series generation : the GUI did not react properly when forbidden @@ -1730,7 +1892,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Unit commitment of thermal plants: the time of the first activation of a plant within a week was not fully optimized - ### 4.4.1 (05/2013) ---------------- @@ -1744,9 +1905,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti (perfectly identical sets of time-series in different locations) could sometimes be casted to 99%. Exact 100% correlations are now properly displayed. - - - ### 4.4.0 (04/2013) ---------------- @@ -1780,14 +1938,11 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti enough to allow the full use of the daily hydro storage energy credit, the energy in excess is levelled on the other days of the month with a flatter pattern. - #### Bug fixes - On creation of a new link, the transmission capacity status parameter is set to `Use transmission capacities` instead of `Set to null`. - - ### 4.3.7 (02/2013) ---------------- @@ -1795,14 +1950,11 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Performance improvements for graphical display of large tables - #### Bug fixes - The binding constraint data might not be written properly in some cases when the constraint was renamed. - - ### 4.3.6 (12/2012) ---------------- @@ -1814,7 +1966,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Windows only: improved free disk space assessment, which now takes into consideration user- and folder-related quotas - ### 4.3.5 (10/2012) ---------------- @@ -1835,7 +1986,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti Note that when a daily or weekly optimization has multiple equally optimal solutions, the ultimate choice may differ from that of the previous version - #### Bug fixes - Reference numbers of the time-series used in the course of a simulation: @@ -1852,8 +2002,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Districts: when the Monte-Carlo synthesis edition is skipped, the results regarding districts were not accessible via the output viewer. - - ### 4.2.6 (07/2012) ---------------- @@ -1863,7 +2011,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - The Monte-Carlo synthesis edition can be skipped when year-by-year results are asked for - #### Bug fixes - Binding constraints: in the filter available for the weight matrix, removal of @@ -1883,30 +2030,24 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti the unsupplied energy levelling process (corrected by a slight lessening of the authorized levelling) - - - ### 4.1.0 (06/2012) ---------------- #### Features - Hydro storage energy management : each nodal policy of use can be tuned so as to - accommodate simultaneously the net load of several nodes + accommodate simultaneously the net load of several nodes - Hydro storage energy modelling : monthly time-series of inflows and reference trajectories for reservoir levels can be used instead of monthly time-series of generated energies. -- Load shedding strategies : when unsupplied energy is unavoidable, a choice is now possible +- Load shedding strategies : when unsupplied energy is unavoidable, a choice is now possible between two policies : minimize the duration of sheddings or "shave" the load curve. - When multiple mathematically equivalent solutions exist a the first order for the economic optimization problem, a choice can be made at the second order between three ramping strategies - - - ### 3.8.0 (12/2011) ---------------- @@ -1927,8 +2068,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti noise around the reference values can be introduced to help discriminate between theoretically equivalent solutions - - ### 3.7.4 (08/2011) ---------------- @@ -1954,23 +2093,16 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - New variables are introduced in the economic output files : the overall available dispatchable thermal generation (AVL DTG) and the thermal margin (DTG MRG = AVL DTG - dispatched power) - - - ### 3.6.4 (04/2011) ---------------- #### Features -- The "scenario builder" is now available. With this builder it is possible to define +- The "scenario builder" is now available. With this builder it is possible to define precisely the simulation context (for any given year, random numbers drawn for each kind of time-series can be replaced by user-defined numbers). This feature allows simulations to be carried out in a versatile "What If" mode. - - - - ### 3.5.3 (03/2011) ---------------- @@ -1985,10 +2117,7 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Automatic processing of the inter-monthly & inter-regional hydro correlation hydro energy matrix to meet the feasibility constraints (the matrix has to be positive semi-definite). User should check in the simulation log file that no warning such as : - "info : hydro correlation not positive semi-definite : shrink by factor x " appears. - - - + "info : hydro correlation not positive semi-definite : shrink by factor x " appears. ### 3.4.4 (02/2011) ---------------- @@ -1998,9 +2127,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - The names of nodes, thermal clusters and binding constraints can be extended to 128 characters. Authorized characters are : `a-z, A-Z,0-9,-,_, space` - - - ### 3.4.3 (10/2010) ---------------- @@ -2029,10 +2155,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti description of the auto-correlation dynamic (two parameters) and a full spatial correlation matrix - - - - ### 3.3.2 (07/2010) ---------------- @@ -2043,7 +2165,7 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Introduction of new stochastic time-series generators for solar power and load -- Introduction of an explicit modelling of wind-to-power curves. +- Introduction of an explicit modelling of wind-to-power curves. As a consequence, wind power time-series can now be generated either through a direct approach (by analysis of historical time-series of power) or through an indirect (more physical) @@ -2057,9 +2179,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - Introduction of so-called hurdles costs on interconnection. - - - ### 3.1.0 (01/2010) ---------------- @@ -2075,8 +2194,6 @@ In the CI workflow, CentOS 7 now uses devtoolset-9 (previously 7), with in parti - New info is given for simulation context (available & required amounts of RAM & HDD space) - - ### From V1 to V2 (all versions) ---------------------------- diff --git a/sonar-project.properties b/sonar-project.properties index 2a76f458da..7a7aaca2e6 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,19 +1,15 @@ sonar.projectName=Antares_Simulator sonar.projectKey=AntaresSimulatorTeam_Antares_Simulator sonar.organization=antaressimulatorteam -sonar.projectVersion=9.1.0 - +sonar.projectVersion=9.2.0 # ===================================================== # Properties that will be shared amongst all modules # ===================================================== - # SQ standard properties sonar.sources=src sonar.tests=src/tests sonar.sourceEncoding=UTF-8 - sonar.exclusions=src/ext/**,src/tests/**,src/ui/** sonar.coverage.exclusions=src/ext/**,src/tests/**,src/analyzer/**,src/distrib/**,src/tools/**,src/ui/** - sonar.coverageReportPaths=coverage.xml sonar.cfamily.threads=4 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e8b4d90a14..56533d676a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,7 +8,7 @@ set(ANTARES_VERSION_REVISION 0) # Beta release set(ANTARES_BETA 0) -set(ANTARES_RC 4) +set(ANTARES_RC 5) set(ANTARES_VERSION_YEAR 2024) diff --git a/src/vcpkg.json b/src/vcpkg.json index b87c13d7b3..a4a3e12fcf 100644 --- a/src/vcpkg.json +++ b/src/vcpkg.json @@ -1,6 +1,6 @@ { "name": "antares-simulator", - "version-string": "9.1.0", + "version-string": "9.2.0", "builtin-baseline": "9484a57dd560b89f0a583be08af6753611c57fd5", "vcpkg-configuration": { "overlay-ports": [ From 0d9e6d4166aaee92db6403b1e84967bd13fcfd79 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Mon, 25 Nov 2024 11:01:41 +0100 Subject: [PATCH 058/103] Modeler 4.4: expression parsing [ANT-2313] (#2471) This pull request includes several updates and improvements to the ANTLR grammar and related files for the `Expr` language. The changes involve modifications to the grammar rules, updates to the CMake configuration, and synchronization with a newer version of ANTLR. ### Grammar and Parsing Improvements: * Refactored `Expr.g4` grammar to introduce new rules and improve parsing capabilities, including the addition of `atom`, `shift_expr`, and `right_expr` rules. [[1]](diffhunk://#diff-9904320a1807a7a3514cd161403920248cbde82e6c2dbc9cf855c5c134dd62dcL20-R68) [[2]](diffhunk://#diff-9904320a1807a7a3514cd161403920248cbde82e6c2dbc9cf855c5c134dd62dcL45-L48) * Updated `Expr.tokens` to reflect new token definitions and changes in the grammar. * Removed redundant rules and tokens from `Expr.g4` and `Expr.tokens`. [[1]](diffhunk://#diff-9904320a1807a7a3514cd161403920248cbde82e6c2dbc9cf855c5c134dd62dcL45-L48) [[2]](diffhunk://#diff-cb10c1b9428e9e48c48e524757dfc48dcc6ae8dd2ad921eff65851cbc3c2e5c1L10-R30) ### Build Configuration Updates: * Updated `sonar-project.properties` to exclude `src/libs/antares/antlr-interface` from Sonar analysis. antlr-interface contains generated code that trigger defect in analysis * Modified `CMakeLists.txt` to always include the `antlr-interface` directory and removed conditional logic for building with ANTLR4. [[1]](diffhunk://#diff-148715d6ea0c0ea0a346af3f6bd610d010d490eca35ac6a9b408748f7ca9e3f4L186-L188) [[2]](diffhunk://#diff-148715d6ea0c0ea0a346af3f6bd610d010d490eca35ac6a9b408748f7ca9e3f4R194-R195) [[3]](diffhunk://#diff-9e299f60c14464c86511d6c9a4e7c081765abb4840b57ea4dc25238311006ce9L31-L33) ### Synchronization with ANTLR 4.13.2: * Updated generated files to be compatible with ANTLR 4.13.2, including `ExprBaseVisitor.cpp`, `ExprBaseVisitor.h`, and `ExprLexer.cpp`. [[1]](diffhunk://#diff-bda2e00a884ff4b113d535c8239b493bfc88c5c4f1d38c4687c2f28e44cdfde8L2-R2) [[2]](diffhunk://#diff-abcc97c1794721be0f33a540339645ac1d5d9d3dd6cbe941235200bad3dcacb9L2-R2) [[3]](diffhunk://#diff-6adabe5fce15f2c6367db67aa33a2e02bb220796c9ff4e143160752a637ca3c0L2-R2) * Adjusted `ExprLexer.cpp` to use `std::unique_ptr` for static data initialization. [[1]](diffhunk://#diff-6adabe5fce15f2c6367db67aa33a2e02bb220796c9ff4e143160752a637ca3c0L48-R48) [[2]](diffhunk://#diff-6adabe5fce15f2c6367db67aa33a2e02bb220796c9ff4e143160752a637ca3c0L61-R62) ### Visitor Pattern Enhancements: * Updated `ExprBaseVisitor` to include new visit methods for the added grammar rules. [[1]](diffhunk://#diff-abcc97c1794721be0f33a540339645ac1d5d9d3dd6cbe941235200bad3dcacb9L22-R57) [[2]](diffhunk://#diff-abcc97c1794721be0f33a540339645ac1d5d9d3dd6cbe941235200bad3dcacb9L58-R106) These changes collectively enhance the flexibility and maintainability of the grammar and build configuration, while ensuring compatibility with the latest ANTLR version. --------- Co-authored-by: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> Co-authored-by: Florian OMNES <26088210+flomnes@users.noreply.github.com> Co-authored-by: Florian OMNES --- sonar-project.properties | 16 +- src/CMakeLists.txt | 5 +- src/libs/antares/CMakeLists.txt | 4 +- .../antares/antlr-interface/CMakeLists.txt | 1 - src/libs/antares/antlr-interface/Expr.g4 | 66 +- src/libs/antares/antlr-interface/Expr.interp | 31 +- src/libs/antares/antlr-interface/Expr.tokens | 38 +- .../antlr-interface/ExprBaseVisitor.cpp | 2 +- .../antares/antlr-interface/ExprBaseVisitor.h | 50 +- .../antares/antlr-interface/ExprLexer.cpp | 85 +- src/libs/antares/antlr-interface/ExprLexer.h | 6 +- .../antares/antlr-interface/ExprLexer.interp | 33 +- .../antares/antlr-interface/ExprLexer.tokens | 38 +- .../antares/antlr-interface/ExprParser.cpp | 1163 +++++++++++------ src/libs/antares/antlr-interface/ExprParser.h | 236 +++- .../antares/antlr-interface/ExprVisitor.cpp | 2 +- .../antares/antlr-interface/ExprVisitor.h | 34 +- src/solver/expressions/CMakeLists.txt | 5 +- src/solver/expressions/NodeRegistry.cpp | 14 + .../antares/solver/expressions/NodeRegistry.h | 22 + .../antares/solver/expressions/Registry.hxx | 7 +- .../expressions/visitors/AstDOTStyleVisitor.h | 3 +- .../solver/expressions/visitors/NodeVisitor.h | 23 +- .../visitors/AstDOTStyleVisitor.cpp | 2 +- .../expressions/visitors/EvalVisitor.cpp | 1 + .../expressions/visitors/NodeVisitor.cpp | 46 + src/solver/modelConverter/CMakeLists.txt | 6 +- .../modelConverter/convertorVisitor.cpp | 297 +++++ .../solver/modelConverter/convertorVisitor.h | 32 + .../solver/modelConverter/modelConverter.h | 16 +- src/solver/modelConverter/modelConverter.cpp | 88 +- src/study/system-model/CMakeLists.txt | 1 + .../antares/study/system-model/constraint.h | 2 +- .../antares/study/system-model/expression.h | 13 +- .../antares/study/system-model/library.h | 7 +- .../antares/study/system-model/model.h | 12 +- .../antares/study/system-model/parameter.h | 8 - .../antares/study/system-model/variable.h | 8 +- src/study/system-model/library.cpp | 4 +- src/study/system-model/model.cpp | 6 +- src/tests/src/libs/antares/CMakeLists.txt | 5 +- .../src/solver/modelParser/CMakeLists.txt | 5 +- .../modelParser/testConvertorVisitor.cpp | 228 ++++ .../modelParser/testModelTranslator.cpp | 75 +- .../src/solver/modelParser/test_full.cpp | 144 +- src/vcpkg.json | 3 + 46 files changed, 2068 insertions(+), 825 deletions(-) create mode 100644 src/solver/expressions/NodeRegistry.cpp create mode 100644 src/solver/expressions/include/antares/solver/expressions/NodeRegistry.h create mode 100644 src/solver/expressions/visitors/NodeVisitor.cpp create mode 100644 src/solver/modelConverter/convertorVisitor.cpp create mode 100644 src/solver/modelConverter/include/antares/solver/modelConverter/convertorVisitor.h create mode 100644 src/tests/src/solver/modelParser/testConvertorVisitor.cpp diff --git a/sonar-project.properties b/sonar-project.properties index 7a7aaca2e6..0c74bd252a 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -9,7 +9,19 @@ sonar.projectVersion=9.2.0 sonar.sources=src sonar.tests=src/tests sonar.sourceEncoding=UTF-8 -sonar.exclusions=src/ext/**,src/tests/**,src/ui/** -sonar.coverage.exclusions=src/ext/**,src/tests/**,src/analyzer/**,src/distrib/**,src/tools/**,src/ui/** + +sonar.exclusions=src/ext/**,\ + src/tests/**,\ + src/ui/**,\ + src/libs/antares/antlr-interface/** + +sonar.coverage.exclusions=src/ext/**,\ + src/tests/**,\ + src/analyzer/**,\ + src/distrib/**,\ + src/tools/**,\ + src/ui/**,\ + src/libs/antares/antlr-interface/** + sonar.coverageReportPaths=coverage.xml sonar.cfamily.threads=4 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 56533d676a..e1fca9a3d2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -183,9 +183,6 @@ message(STATUS "Build antares tools: ${BUILD_TOOLS}") option(BUILD_ORTOOLS "Build OR-Tools" OFF) message(STATUS "Build OR-Tools: ${BUILD_ORTOOLS}") -option(WITH_ANTLR4 "With antlr4" OFF) -message(STATUS "With antlr4: ${WITH_ANTLR4}") - option(BUILD_MERSENNE_TWISTER_PYBIND11 "Build pybind11 bindings for Mersenne-Twister" OFF) if (${BUILD_MERSENNE_TWISTER_PYBIND11}) find_package(pybind11 REQUIRED) @@ -194,6 +191,8 @@ endif() #Boost header libraries find_package(Boost REQUIRED) +find_package(antlr4-runtime REQUIRED) + #Sirius solver if(POLICY CMP0074) cmake_policy(SET CMP0074 NEW) diff --git a/src/libs/antares/CMakeLists.txt b/src/libs/antares/CMakeLists.txt index 5b4f253052..c06632cd29 100644 --- a/src/libs/antares/CMakeLists.txt +++ b/src/libs/antares/CMakeLists.txt @@ -28,9 +28,7 @@ add_subdirectory(study-loader) add_subdirectory(sys) add_subdirectory(utils) add_subdirectory(writer) -if(WITH_ANTLR4) - add_subdirectory(antlr-interface) -endif() +add_subdirectory(antlr-interface) add_subdirectory(optimization-options) diff --git a/src/libs/antares/antlr-interface/CMakeLists.txt b/src/libs/antares/antlr-interface/CMakeLists.txt index 4cd06fef3b..727ec96d0e 100644 --- a/src/libs/antares/antlr-interface/CMakeLists.txt +++ b/src/libs/antares/antlr-interface/CMakeLists.txt @@ -13,7 +13,6 @@ ExprLexer.cpp ExprParser.cpp ExprVisitor.cpp ) -find_package(antlr4-runtime CONFIG REQUIRED) add_library(${PROJ} ${SRCS}) add_library(Antares::${PROJ} ALIAS ${PROJ}) diff --git a/src/libs/antares/antlr-interface/Expr.g4 b/src/libs/antares/antlr-interface/Expr.g4 index d0d1642497..9b21de7bbd 100644 --- a/src/libs/antares/antlr-interface/Expr.g4 +++ b/src/libs/antares/antlr-interface/Expr.g4 @@ -17,23 +17,55 @@ grammar Expr; /* To match the whole input */ fullexpr: expr EOF; -shift: TIME (op=('+' | '-') expr)?; - -expr: '-' expr # negation - | expr op=('/' | '*') expr # muldiv - | expr op=('+' | '-') expr # addsub - | expr COMPARISON expr # comparison - | IDENTIFIER # identifier - | IDENTIFIER '.' IDENTIFIER # portField - | NUMBER # number - | '(' expr ')' # expression - | IDENTIFIER '(' expr ')' # function - | IDENTIFIER '[' shift (',' shift)* ']' # timeShift - | IDENTIFIER '[' expr (',' expr )* ']' # timeIndex - | IDENTIFIER '[' shift1=shift '..' shift2=shift ']' # timeShiftRange - | IDENTIFIER '[' expr '..' expr ']' # timeRange +expr + : atom # unsignedAtom + | IDENTIFIER '.' IDENTIFIER # portField + | '-' expr # negation + | '(' expr ')' # expression + | expr op=('/' | '*') expr # muldiv + | expr op=('+' | '-') expr # addsub + | expr COMPARISON expr # comparison + | 'sum' '(' expr ')' # allTimeSum + | 'sum' '(' from=shift '..' to=shift ',' expr ')' # timeSum + | IDENTIFIER '(' expr ')' # function + | IDENTIFIER '[' shift ']' # timeShift + | IDENTIFIER '[' expr ']' # timeIndex ; +atom + : NUMBER # number + | IDENTIFIER # identifier + ; + +// a shift is required to be either "t" or "t + ..." or "t - ..." +// Note: simply defining it as "shift: TIME ('+' | '-') expr" won't work +// because the minus sign will not have the expected precedence: +// "t - d + 1" would be equivalent to "t - (d + 1)" +shift: TIME shift_expr?; + +// Because the shift MUST start with + or -, we need +// to differentiate it from generic "expr". +// A shift expression can only be extended to the right by a +// "right_expr" which cannot start with a + or -, +// unlike shift_expr itself. +// TODO: the grammar is still a little weird, because we +// allow more things in the "expr" parts of those +// shift expressions than on their left-most part +// (port fields, nested time shifts and so on). +shift_expr + : shift_expr op=('*' | '/') right_expr # shiftMuldiv + | shift_expr op=('+' | '-') right_expr # shiftAddsub + | op=('+' | '-') atom # signedAtom + | op=('+' | '-') '(' expr ')' # signedExpression + ; + +right_expr + : right_expr op=('/' | '*') right_expr # rightMuldiv + | '(' expr ')' # rightExpression + | atom # rightAtom + ; + + fragment DIGIT : [0-9] ; fragment CHAR : [a-zA-Z_]; fragment CHAR_OR_DIGIT : (CHAR | DIGIT); @@ -42,9 +74,5 @@ NUMBER : DIGIT+ ('.' DIGIT+)?; TIME : 't'; IDENTIFIER : CHAR CHAR_OR_DIGIT*; COMPARISON : ( '=' | '>=' | '<=' ); -ADDSUB : ( '+' | '-' ); -MULDIV : ( '*' | '/' ); -LBRACKET: '['; -RBRACKET: ']'; WS: (' ' | '\t' | '\r'| '\n') -> skip; diff --git a/src/libs/antares/antlr-interface/Expr.interp b/src/libs/antares/antlr-interface/Expr.interp index bed351938d..d4189d97c1 100644 --- a/src/libs/antares/antlr-interface/Expr.interp +++ b/src/libs/antares/antlr-interface/Expr.interp @@ -1,23 +1,22 @@ token literal names: null -'+' -'-' -'/' -'*' '.' +'-' '(' ')' -',' +'/' +'*' +'+' +'sum' '..' +',' +'[' +']' null 't' null null null -null -'[' -']' -null token symbolic names: null @@ -30,21 +29,23 @@ null null null null +null +null +null NUMBER TIME IDENTIFIER COMPARISON -ADDSUB -MULDIV -LBRACKET -RBRACKET WS rule names: fullexpr -shift expr +atom +shift +shift_expr +right_expr atn: -[4, 1, 18, 86, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 3, 1, 13, 8, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 5, 2, 37, 8, 2, 10, 2, 12, 2, 40, 9, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 5, 2, 49, 8, 2, 10, 2, 12, 2, 52, 9, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 70, 8, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 5, 2, 81, 8, 2, 10, 2, 12, 2, 84, 9, 2, 1, 2, 0, 1, 4, 3, 0, 2, 4, 0, 2, 1, 0, 1, 2, 1, 0, 3, 4, 97, 0, 6, 1, 0, 0, 0, 2, 9, 1, 0, 0, 0, 4, 69, 1, 0, 0, 0, 6, 7, 3, 4, 2, 0, 7, 8, 5, 0, 0, 1, 8, 1, 1, 0, 0, 0, 9, 12, 5, 11, 0, 0, 10, 11, 7, 0, 0, 0, 11, 13, 3, 4, 2, 0, 12, 10, 1, 0, 0, 0, 12, 13, 1, 0, 0, 0, 13, 3, 1, 0, 0, 0, 14, 15, 6, 2, -1, 0, 15, 16, 5, 2, 0, 0, 16, 70, 3, 4, 2, 13, 17, 70, 5, 12, 0, 0, 18, 19, 5, 12, 0, 0, 19, 20, 5, 5, 0, 0, 20, 70, 5, 12, 0, 0, 21, 70, 5, 10, 0, 0, 22, 23, 5, 6, 0, 0, 23, 24, 3, 4, 2, 0, 24, 25, 5, 7, 0, 0, 25, 70, 1, 0, 0, 0, 26, 27, 5, 12, 0, 0, 27, 28, 5, 6, 0, 0, 28, 29, 3, 4, 2, 0, 29, 30, 5, 7, 0, 0, 30, 70, 1, 0, 0, 0, 31, 32, 5, 12, 0, 0, 32, 33, 5, 16, 0, 0, 33, 38, 3, 2, 1, 0, 34, 35, 5, 8, 0, 0, 35, 37, 3, 2, 1, 0, 36, 34, 1, 0, 0, 0, 37, 40, 1, 0, 0, 0, 38, 36, 1, 0, 0, 0, 38, 39, 1, 0, 0, 0, 39, 41, 1, 0, 0, 0, 40, 38, 1, 0, 0, 0, 41, 42, 5, 17, 0, 0, 42, 70, 1, 0, 0, 0, 43, 44, 5, 12, 0, 0, 44, 45, 5, 16, 0, 0, 45, 50, 3, 4, 2, 0, 46, 47, 5, 8, 0, 0, 47, 49, 3, 4, 2, 0, 48, 46, 1, 0, 0, 0, 49, 52, 1, 0, 0, 0, 50, 48, 1, 0, 0, 0, 50, 51, 1, 0, 0, 0, 51, 53, 1, 0, 0, 0, 52, 50, 1, 0, 0, 0, 53, 54, 5, 17, 0, 0, 54, 70, 1, 0, 0, 0, 55, 56, 5, 12, 0, 0, 56, 57, 5, 16, 0, 0, 57, 58, 3, 2, 1, 0, 58, 59, 5, 9, 0, 0, 59, 60, 3, 2, 1, 0, 60, 61, 5, 17, 0, 0, 61, 70, 1, 0, 0, 0, 62, 63, 5, 12, 0, 0, 63, 64, 5, 16, 0, 0, 64, 65, 3, 4, 2, 0, 65, 66, 5, 9, 0, 0, 66, 67, 3, 4, 2, 0, 67, 68, 5, 17, 0, 0, 68, 70, 1, 0, 0, 0, 69, 14, 1, 0, 0, 0, 69, 17, 1, 0, 0, 0, 69, 18, 1, 0, 0, 0, 69, 21, 1, 0, 0, 0, 69, 22, 1, 0, 0, 0, 69, 26, 1, 0, 0, 0, 69, 31, 1, 0, 0, 0, 69, 43, 1, 0, 0, 0, 69, 55, 1, 0, 0, 0, 69, 62, 1, 0, 0, 0, 70, 82, 1, 0, 0, 0, 71, 72, 10, 12, 0, 0, 72, 73, 7, 1, 0, 0, 73, 81, 3, 4, 2, 13, 74, 75, 10, 11, 0, 0, 75, 76, 7, 0, 0, 0, 76, 81, 3, 4, 2, 12, 77, 78, 10, 10, 0, 0, 78, 79, 5, 13, 0, 0, 79, 81, 3, 4, 2, 11, 80, 71, 1, 0, 0, 0, 80, 74, 1, 0, 0, 0, 80, 77, 1, 0, 0, 0, 81, 84, 1, 0, 0, 0, 82, 80, 1, 0, 0, 0, 82, 83, 1, 0, 0, 0, 83, 5, 1, 0, 0, 0, 84, 82, 1, 0, 0, 0, 6, 12, 38, 50, 69, 80, 82] \ No newline at end of file +[4, 1, 17, 117, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 56, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 67, 8, 1, 10, 1, 12, 1, 70, 9, 1, 1, 2, 1, 2, 3, 2, 74, 8, 2, 1, 3, 1, 3, 3, 3, 78, 8, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 88, 8, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 5, 4, 96, 8, 4, 10, 4, 12, 4, 99, 9, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 107, 8, 5, 1, 5, 1, 5, 1, 5, 5, 5, 112, 8, 5, 10, 5, 12, 5, 115, 9, 5, 1, 5, 0, 3, 2, 8, 10, 6, 0, 2, 4, 6, 8, 10, 0, 2, 1, 0, 5, 6, 2, 0, 2, 2, 7, 7, 128, 0, 12, 1, 0, 0, 0, 2, 55, 1, 0, 0, 0, 4, 73, 1, 0, 0, 0, 6, 75, 1, 0, 0, 0, 8, 87, 1, 0, 0, 0, 10, 106, 1, 0, 0, 0, 12, 13, 3, 2, 1, 0, 13, 14, 5, 0, 0, 1, 14, 1, 1, 0, 0, 0, 15, 16, 6, 1, -1, 0, 16, 56, 3, 4, 2, 0, 17, 18, 5, 15, 0, 0, 18, 19, 5, 1, 0, 0, 19, 56, 5, 15, 0, 0, 20, 21, 5, 2, 0, 0, 21, 56, 3, 2, 1, 10, 22, 23, 5, 3, 0, 0, 23, 24, 3, 2, 1, 0, 24, 25, 5, 4, 0, 0, 25, 56, 1, 0, 0, 0, 26, 27, 5, 8, 0, 0, 27, 28, 5, 3, 0, 0, 28, 29, 3, 2, 1, 0, 29, 30, 5, 4, 0, 0, 30, 56, 1, 0, 0, 0, 31, 32, 5, 8, 0, 0, 32, 33, 5, 3, 0, 0, 33, 34, 3, 6, 3, 0, 34, 35, 5, 9, 0, 0, 35, 36, 3, 6, 3, 0, 36, 37, 5, 10, 0, 0, 37, 38, 3, 2, 1, 0, 38, 39, 5, 4, 0, 0, 39, 56, 1, 0, 0, 0, 40, 41, 5, 15, 0, 0, 41, 42, 5, 3, 0, 0, 42, 43, 3, 2, 1, 0, 43, 44, 5, 4, 0, 0, 44, 56, 1, 0, 0, 0, 45, 46, 5, 15, 0, 0, 46, 47, 5, 11, 0, 0, 47, 48, 3, 6, 3, 0, 48, 49, 5, 12, 0, 0, 49, 56, 1, 0, 0, 0, 50, 51, 5, 15, 0, 0, 51, 52, 5, 11, 0, 0, 52, 53, 3, 2, 1, 0, 53, 54, 5, 12, 0, 0, 54, 56, 1, 0, 0, 0, 55, 15, 1, 0, 0, 0, 55, 17, 1, 0, 0, 0, 55, 20, 1, 0, 0, 0, 55, 22, 1, 0, 0, 0, 55, 26, 1, 0, 0, 0, 55, 31, 1, 0, 0, 0, 55, 40, 1, 0, 0, 0, 55, 45, 1, 0, 0, 0, 55, 50, 1, 0, 0, 0, 56, 68, 1, 0, 0, 0, 57, 58, 10, 8, 0, 0, 58, 59, 7, 0, 0, 0, 59, 67, 3, 2, 1, 9, 60, 61, 10, 7, 0, 0, 61, 62, 7, 1, 0, 0, 62, 67, 3, 2, 1, 8, 63, 64, 10, 6, 0, 0, 64, 65, 5, 16, 0, 0, 65, 67, 3, 2, 1, 7, 66, 57, 1, 0, 0, 0, 66, 60, 1, 0, 0, 0, 66, 63, 1, 0, 0, 0, 67, 70, 1, 0, 0, 0, 68, 66, 1, 0, 0, 0, 68, 69, 1, 0, 0, 0, 69, 3, 1, 0, 0, 0, 70, 68, 1, 0, 0, 0, 71, 74, 5, 13, 0, 0, 72, 74, 5, 15, 0, 0, 73, 71, 1, 0, 0, 0, 73, 72, 1, 0, 0, 0, 74, 5, 1, 0, 0, 0, 75, 77, 5, 14, 0, 0, 76, 78, 3, 8, 4, 0, 77, 76, 1, 0, 0, 0, 77, 78, 1, 0, 0, 0, 78, 7, 1, 0, 0, 0, 79, 80, 6, 4, -1, 0, 80, 81, 7, 1, 0, 0, 81, 88, 3, 4, 2, 0, 82, 83, 7, 1, 0, 0, 83, 84, 5, 3, 0, 0, 84, 85, 3, 2, 1, 0, 85, 86, 5, 4, 0, 0, 86, 88, 1, 0, 0, 0, 87, 79, 1, 0, 0, 0, 87, 82, 1, 0, 0, 0, 88, 97, 1, 0, 0, 0, 89, 90, 10, 4, 0, 0, 90, 91, 7, 0, 0, 0, 91, 96, 3, 10, 5, 0, 92, 93, 10, 3, 0, 0, 93, 94, 7, 1, 0, 0, 94, 96, 3, 10, 5, 0, 95, 89, 1, 0, 0, 0, 95, 92, 1, 0, 0, 0, 96, 99, 1, 0, 0, 0, 97, 95, 1, 0, 0, 0, 97, 98, 1, 0, 0, 0, 98, 9, 1, 0, 0, 0, 99, 97, 1, 0, 0, 0, 100, 101, 6, 5, -1, 0, 101, 102, 5, 3, 0, 0, 102, 103, 3, 2, 1, 0, 103, 104, 5, 4, 0, 0, 104, 107, 1, 0, 0, 0, 105, 107, 3, 4, 2, 0, 106, 100, 1, 0, 0, 0, 106, 105, 1, 0, 0, 0, 107, 113, 1, 0, 0, 0, 108, 109, 10, 3, 0, 0, 109, 110, 7, 0, 0, 0, 110, 112, 3, 10, 5, 4, 111, 108, 1, 0, 0, 0, 112, 115, 1, 0, 0, 0, 113, 111, 1, 0, 0, 0, 113, 114, 1, 0, 0, 0, 114, 11, 1, 0, 0, 0, 115, 113, 1, 0, 0, 0, 10, 55, 66, 68, 73, 77, 87, 95, 97, 106, 113] \ No newline at end of file diff --git a/src/libs/antares/antlr-interface/Expr.tokens b/src/libs/antares/antlr-interface/Expr.tokens index 29d96df5f3..868577445e 100644 --- a/src/libs/antares/antlr-interface/Expr.tokens +++ b/src/libs/antares/antlr-interface/Expr.tokens @@ -7,24 +7,24 @@ T__5=6 T__6=7 T__7=8 T__8=9 -NUMBER=10 -TIME=11 -IDENTIFIER=12 -COMPARISON=13 -ADDSUB=14 -MULDIV=15 -LBRACKET=16 -RBRACKET=17 -WS=18 -'+'=1 +T__9=10 +T__10=11 +T__11=12 +NUMBER=13 +TIME=14 +IDENTIFIER=15 +COMPARISON=16 +WS=17 +'.'=1 '-'=2 -'/'=3 -'*'=4 -'.'=5 -'('=6 -')'=7 -','=8 +'('=3 +')'=4 +'/'=5 +'*'=6 +'+'=7 +'sum'=8 '..'=9 -'t'=11 -'['=16 -']'=17 +','=10 +'['=11 +']'=12 +'t'=14 diff --git a/src/libs/antares/antlr-interface/ExprBaseVisitor.cpp b/src/libs/antares/antlr-interface/ExprBaseVisitor.cpp index 42d6fef5d3..864d91febf 100644 --- a/src/libs/antares/antlr-interface/ExprBaseVisitor.cpp +++ b/src/libs/antares/antlr-interface/ExprBaseVisitor.cpp @@ -1,5 +1,5 @@ -// Generated from Expr.g4 by ANTLR 4.13.1 +// Generated from Expr.g4 by ANTLR 4.13.2 #include "ExprBaseVisitor.h" diff --git a/src/libs/antares/antlr-interface/ExprBaseVisitor.h b/src/libs/antares/antlr-interface/ExprBaseVisitor.h index a8af3c573f..5df811ca64 100644 --- a/src/libs/antares/antlr-interface/ExprBaseVisitor.h +++ b/src/libs/antares/antlr-interface/ExprBaseVisitor.h @@ -1,5 +1,5 @@ -// Generated from Expr.g4 by ANTLR 4.13.1 +// Generated from Expr.g4 by ANTLR 4.13.2 #pragma once @@ -19,15 +19,15 @@ class ExprBaseVisitor : public ExprVisitor { return visitChildren(ctx); } - virtual std::any visitShift(ExprParser::ShiftContext *ctx) override { + virtual std::any visitTimeSum(ExprParser::TimeSumContext *ctx) override { return visitChildren(ctx); } - virtual std::any visitIdentifier(ExprParser::IdentifierContext *ctx) override { + virtual std::any visitNegation(ExprParser::NegationContext *ctx) override { return visitChildren(ctx); } - virtual std::any visitNegation(ExprParser::NegationContext *ctx) override { + virtual std::any visitUnsignedAtom(ExprParser::UnsignedAtomContext *ctx) override { return visitChildren(ctx); } @@ -35,10 +35,26 @@ class ExprBaseVisitor : public ExprVisitor { return visitChildren(ctx); } + virtual std::any visitTimeIndex(ExprParser::TimeIndexContext *ctx) override { + return visitChildren(ctx); + } + virtual std::any visitComparison(ExprParser::ComparisonContext *ctx) override { return visitChildren(ctx); } + virtual std::any visitAllTimeSum(ExprParser::AllTimeSumContext *ctx) override { + return visitChildren(ctx); + } + + virtual std::any visitTimeShift(ExprParser::TimeShiftContext *ctx) override { + return visitChildren(ctx); + } + + virtual std::any visitFunction(ExprParser::FunctionContext *ctx) override { + return visitChildren(ctx); + } + virtual std::any visitAddsub(ExprParser::AddsubContext *ctx) override { return visitChildren(ctx); } @@ -55,23 +71,39 @@ class ExprBaseVisitor : public ExprVisitor { return visitChildren(ctx); } - virtual std::any visitTimeIndex(ExprParser::TimeIndexContext *ctx) override { + virtual std::any visitIdentifier(ExprParser::IdentifierContext *ctx) override { return visitChildren(ctx); } - virtual std::any visitTimeShift(ExprParser::TimeShiftContext *ctx) override { + virtual std::any visitShift(ExprParser::ShiftContext *ctx) override { return visitChildren(ctx); } - virtual std::any visitFunction(ExprParser::FunctionContext *ctx) override { + virtual std::any visitSignedAtom(ExprParser::SignedAtomContext *ctx) override { + return visitChildren(ctx); + } + + virtual std::any visitSignedExpression(ExprParser::SignedExpressionContext *ctx) override { + return visitChildren(ctx); + } + + virtual std::any visitShiftMuldiv(ExprParser::ShiftMuldivContext *ctx) override { + return visitChildren(ctx); + } + + virtual std::any visitShiftAddsub(ExprParser::ShiftAddsubContext *ctx) override { + return visitChildren(ctx); + } + + virtual std::any visitRightExpression(ExprParser::RightExpressionContext *ctx) override { return visitChildren(ctx); } - virtual std::any visitTimeShiftRange(ExprParser::TimeShiftRangeContext *ctx) override { + virtual std::any visitRightMuldiv(ExprParser::RightMuldivContext *ctx) override { return visitChildren(ctx); } - virtual std::any visitTimeRange(ExprParser::TimeRangeContext *ctx) override { + virtual std::any visitRightAtom(ExprParser::RightAtomContext *ctx) override { return visitChildren(ctx); } diff --git a/src/libs/antares/antlr-interface/ExprLexer.cpp b/src/libs/antares/antlr-interface/ExprLexer.cpp index a645fcddd0..6cb4377101 100644 --- a/src/libs/antares/antlr-interface/ExprLexer.cpp +++ b/src/libs/antares/antlr-interface/ExprLexer.cpp @@ -1,5 +1,5 @@ -// Generated from Expr.g4 by ANTLR 4.13.1 +// Generated from Expr.g4 by ANTLR 4.13.2 #include "ExprLexer.h" @@ -45,7 +45,7 @@ ::antlr4::internal::OnceFlag exprlexerLexerOnceFlag; #if ANTLR4_USE_THREAD_LOCAL_CACHE static thread_local #endif -ExprLexerStaticData *exprlexerLexerStaticData = nullptr; +std::unique_ptr exprlexerLexerStaticData = nullptr; void exprlexerLexerInitialize() { #if ANTLR4_USE_THREAD_LOCAL_CACHE @@ -58,8 +58,8 @@ void exprlexerLexerInitialize() { auto staticData = std::make_unique( std::vector{ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "T__7", "T__8", - "DIGIT", "CHAR", "CHAR_OR_DIGIT", "NUMBER", "TIME", "IDENTIFIER", - "COMPARISON", "ADDSUB", "MULDIV", "LBRACKET", "RBRACKET", "WS" + "T__9", "T__10", "T__11", "DIGIT", "CHAR", "CHAR_OR_DIGIT", "NUMBER", + "TIME", "IDENTIFIER", "COMPARISON", "WS" }, std::vector{ "DEFAULT_TOKEN_CHANNEL", "HIDDEN" @@ -68,50 +68,49 @@ void exprlexerLexerInitialize() { "DEFAULT_MODE" }, std::vector{ - "", "'+'", "'-'", "'/'", "'*'", "'.'", "'('", "')'", "','", "'..'", - "", "'t'", "", "", "", "", "'['", "']'" + "", "'.'", "'-'", "'('", "')'", "'/'", "'*'", "'+'", "'sum'", "'..'", + "','", "'['", "']'", "", "'t'" }, std::vector{ - "", "", "", "", "", "", "", "", "", "", "NUMBER", "TIME", "IDENTIFIER", - "COMPARISON", "ADDSUB", "MULDIV", "LBRACKET", "RBRACKET", "WS" + "", "", "", "", "", "", "", "", "", "", "", "", "", "NUMBER", "TIME", + "IDENTIFIER", "COMPARISON", "WS" } ); static const int32_t serializedATNSegment[] = { - 4,0,18,111,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7, + 4,0,17,109,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7, 6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7,13,2,14, - 7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,2,20,7,20,1,0, - 1,0,1,1,1,1,1,2,1,2,1,3,1,3,1,4,1,4,1,5,1,5,1,6,1,6,1,7,1,7,1,8,1,8,1, - 8,1,9,1,9,1,10,1,10,1,11,1,11,3,11,69,8,11,1,12,4,12,72,8,12,11,12,12, - 12,73,1,12,1,12,4,12,78,8,12,11,12,12,12,79,3,12,82,8,12,1,13,1,13,1, - 14,1,14,5,14,88,8,14,10,14,12,14,91,9,14,1,15,1,15,1,15,1,15,1,15,3,15, - 98,8,15,1,16,1,16,1,17,1,17,1,18,1,18,1,19,1,19,1,20,1,20,1,20,1,20,0, - 0,21,1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,0,21,0,23,0,25,10,27, - 11,29,12,31,13,33,14,35,15,37,16,39,17,41,18,1,0,5,1,0,48,57,3,0,65,90, - 95,95,97,122,2,0,43,43,45,45,2,0,42,42,47,47,3,0,9,10,13,13,32,32,114, - 0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,0, - 0,0,0,13,1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0, - 0,29,1,0,0,0,0,31,1,0,0,0,0,33,1,0,0,0,0,35,1,0,0,0,0,37,1,0,0,0,0,39, - 1,0,0,0,0,41,1,0,0,0,1,43,1,0,0,0,3,45,1,0,0,0,5,47,1,0,0,0,7,49,1,0, - 0,0,9,51,1,0,0,0,11,53,1,0,0,0,13,55,1,0,0,0,15,57,1,0,0,0,17,59,1,0, - 0,0,19,62,1,0,0,0,21,64,1,0,0,0,23,68,1,0,0,0,25,71,1,0,0,0,27,83,1,0, - 0,0,29,85,1,0,0,0,31,97,1,0,0,0,33,99,1,0,0,0,35,101,1,0,0,0,37,103,1, - 0,0,0,39,105,1,0,0,0,41,107,1,0,0,0,43,44,5,43,0,0,44,2,1,0,0,0,45,46, - 5,45,0,0,46,4,1,0,0,0,47,48,5,47,0,0,48,6,1,0,0,0,49,50,5,42,0,0,50,8, - 1,0,0,0,51,52,5,46,0,0,52,10,1,0,0,0,53,54,5,40,0,0,54,12,1,0,0,0,55, - 56,5,41,0,0,56,14,1,0,0,0,57,58,5,44,0,0,58,16,1,0,0,0,59,60,5,46,0,0, - 60,61,5,46,0,0,61,18,1,0,0,0,62,63,7,0,0,0,63,20,1,0,0,0,64,65,7,1,0, - 0,65,22,1,0,0,0,66,69,3,21,10,0,67,69,3,19,9,0,68,66,1,0,0,0,68,67,1, - 0,0,0,69,24,1,0,0,0,70,72,3,19,9,0,71,70,1,0,0,0,72,73,1,0,0,0,73,71, - 1,0,0,0,73,74,1,0,0,0,74,81,1,0,0,0,75,77,5,46,0,0,76,78,3,19,9,0,77, - 76,1,0,0,0,78,79,1,0,0,0,79,77,1,0,0,0,79,80,1,0,0,0,80,82,1,0,0,0,81, - 75,1,0,0,0,81,82,1,0,0,0,82,26,1,0,0,0,83,84,5,116,0,0,84,28,1,0,0,0, - 85,89,3,21,10,0,86,88,3,23,11,0,87,86,1,0,0,0,88,91,1,0,0,0,89,87,1,0, - 0,0,89,90,1,0,0,0,90,30,1,0,0,0,91,89,1,0,0,0,92,98,5,61,0,0,93,94,5, - 62,0,0,94,98,5,61,0,0,95,96,5,60,0,0,96,98,5,61,0,0,97,92,1,0,0,0,97, - 93,1,0,0,0,97,95,1,0,0,0,98,32,1,0,0,0,99,100,7,2,0,0,100,34,1,0,0,0, - 101,102,7,3,0,0,102,36,1,0,0,0,103,104,5,91,0,0,104,38,1,0,0,0,105,106, - 5,93,0,0,106,40,1,0,0,0,107,108,7,4,0,0,108,109,1,0,0,0,109,110,6,20, - 0,0,110,42,1,0,0,0,7,0,68,73,79,81,89,97,1,6,0,0 + 7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,1,0,1,0,1,1,1, + 1,1,2,1,2,1,3,1,3,1,4,1,4,1,5,1,5,1,6,1,6,1,7,1,7,1,7,1,7,1,8,1,8,1,8, + 1,9,1,9,1,10,1,10,1,11,1,11,1,12,1,12,1,13,1,13,1,14,1,14,3,14,75,8,14, + 1,15,4,15,78,8,15,11,15,12,15,79,1,15,1,15,4,15,84,8,15,11,15,12,15,85, + 3,15,88,8,15,1,16,1,16,1,17,1,17,5,17,94,8,17,10,17,12,17,97,9,17,1,18, + 1,18,1,18,1,18,1,18,3,18,104,8,18,1,19,1,19,1,19,1,19,0,0,20,1,1,3,2, + 5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10,21,11,23,12,25,0,27,0,29,0,31,13, + 33,14,35,15,37,16,39,17,1,0,3,1,0,48,57,3,0,65,90,95,95,97,122,3,0,9, + 10,13,13,32,32,112,0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0, + 9,1,0,0,0,0,11,1,0,0,0,0,13,1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1, + 0,0,0,0,21,1,0,0,0,0,23,1,0,0,0,0,31,1,0,0,0,0,33,1,0,0,0,0,35,1,0,0, + 0,0,37,1,0,0,0,0,39,1,0,0,0,1,41,1,0,0,0,3,43,1,0,0,0,5,45,1,0,0,0,7, + 47,1,0,0,0,9,49,1,0,0,0,11,51,1,0,0,0,13,53,1,0,0,0,15,55,1,0,0,0,17, + 59,1,0,0,0,19,62,1,0,0,0,21,64,1,0,0,0,23,66,1,0,0,0,25,68,1,0,0,0,27, + 70,1,0,0,0,29,74,1,0,0,0,31,77,1,0,0,0,33,89,1,0,0,0,35,91,1,0,0,0,37, + 103,1,0,0,0,39,105,1,0,0,0,41,42,5,46,0,0,42,2,1,0,0,0,43,44,5,45,0,0, + 44,4,1,0,0,0,45,46,5,40,0,0,46,6,1,0,0,0,47,48,5,41,0,0,48,8,1,0,0,0, + 49,50,5,47,0,0,50,10,1,0,0,0,51,52,5,42,0,0,52,12,1,0,0,0,53,54,5,43, + 0,0,54,14,1,0,0,0,55,56,5,115,0,0,56,57,5,117,0,0,57,58,5,109,0,0,58, + 16,1,0,0,0,59,60,5,46,0,0,60,61,5,46,0,0,61,18,1,0,0,0,62,63,5,44,0,0, + 63,20,1,0,0,0,64,65,5,91,0,0,65,22,1,0,0,0,66,67,5,93,0,0,67,24,1,0,0, + 0,68,69,7,0,0,0,69,26,1,0,0,0,70,71,7,1,0,0,71,28,1,0,0,0,72,75,3,27, + 13,0,73,75,3,25,12,0,74,72,1,0,0,0,74,73,1,0,0,0,75,30,1,0,0,0,76,78, + 3,25,12,0,77,76,1,0,0,0,78,79,1,0,0,0,79,77,1,0,0,0,79,80,1,0,0,0,80, + 87,1,0,0,0,81,83,5,46,0,0,82,84,3,25,12,0,83,82,1,0,0,0,84,85,1,0,0,0, + 85,83,1,0,0,0,85,86,1,0,0,0,86,88,1,0,0,0,87,81,1,0,0,0,87,88,1,0,0,0, + 88,32,1,0,0,0,89,90,5,116,0,0,90,34,1,0,0,0,91,95,3,27,13,0,92,94,3,29, + 14,0,93,92,1,0,0,0,94,97,1,0,0,0,95,93,1,0,0,0,95,96,1,0,0,0,96,36,1, + 0,0,0,97,95,1,0,0,0,98,104,5,61,0,0,99,100,5,62,0,0,100,104,5,61,0,0, + 101,102,5,60,0,0,102,104,5,61,0,0,103,98,1,0,0,0,103,99,1,0,0,0,103,101, + 1,0,0,0,104,38,1,0,0,0,105,106,7,2,0,0,106,107,1,0,0,0,107,108,6,19,0, + 0,108,40,1,0,0,0,7,0,74,79,85,87,95,103,1,6,0,0 }; staticData->serializedATN = antlr4::atn::SerializedATNView(serializedATNSegment, sizeof(serializedATNSegment) / sizeof(serializedATNSegment[0])); @@ -123,7 +122,7 @@ void exprlexerLexerInitialize() { for (size_t i = 0; i < count; i++) { staticData->decisionToDFA.emplace_back(staticData->atn->getDecisionState(i), i); } - exprlexerLexerStaticData = staticData.release(); + exprlexerLexerStaticData = std::move(staticData); } } diff --git a/src/libs/antares/antlr-interface/ExprLexer.h b/src/libs/antares/antlr-interface/ExprLexer.h index c7db2c5f77..3d6d36bd29 100644 --- a/src/libs/antares/antlr-interface/ExprLexer.h +++ b/src/libs/antares/antlr-interface/ExprLexer.h @@ -1,5 +1,5 @@ -// Generated from Expr.g4 by ANTLR 4.13.1 +// Generated from Expr.g4 by ANTLR 4.13.2 #pragma once @@ -13,8 +13,8 @@ class ExprLexer : public antlr4::Lexer { public: enum { T__0 = 1, T__1 = 2, T__2 = 3, T__3 = 4, T__4 = 5, T__5 = 6, T__6 = 7, - T__7 = 8, T__8 = 9, NUMBER = 10, TIME = 11, IDENTIFIER = 12, COMPARISON = 13, - ADDSUB = 14, MULDIV = 15, LBRACKET = 16, RBRACKET = 17, WS = 18 + T__7 = 8, T__8 = 9, T__9 = 10, T__10 = 11, T__11 = 12, NUMBER = 13, + TIME = 14, IDENTIFIER = 15, COMPARISON = 16, WS = 17 }; explicit ExprLexer(antlr4::CharStream *input); diff --git a/src/libs/antares/antlr-interface/ExprLexer.interp b/src/libs/antares/antlr-interface/ExprLexer.interp index e98cab1e7c..43521ebb69 100644 --- a/src/libs/antares/antlr-interface/ExprLexer.interp +++ b/src/libs/antares/antlr-interface/ExprLexer.interp @@ -1,23 +1,22 @@ token literal names: null -'+' -'-' -'/' -'*' '.' +'-' '(' ')' -',' +'/' +'*' +'+' +'sum' '..' +',' +'[' +']' null 't' null null null -null -'[' -']' -null token symbolic names: null @@ -30,14 +29,13 @@ null null null null +null +null +null NUMBER TIME IDENTIFIER COMPARISON -ADDSUB -MULDIV -LBRACKET -RBRACKET WS rule names: @@ -50,6 +48,9 @@ T__5 T__6 T__7 T__8 +T__9 +T__10 +T__11 DIGIT CHAR CHAR_OR_DIGIT @@ -57,10 +58,6 @@ NUMBER TIME IDENTIFIER COMPARISON -ADDSUB -MULDIV -LBRACKET -RBRACKET WS channel names: @@ -71,4 +68,4 @@ mode names: DEFAULT_MODE atn: -[4, 0, 18, 111, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 3, 11, 69, 8, 11, 1, 12, 4, 12, 72, 8, 12, 11, 12, 12, 12, 73, 1, 12, 1, 12, 4, 12, 78, 8, 12, 11, 12, 12, 12, 79, 3, 12, 82, 8, 12, 1, 13, 1, 13, 1, 14, 1, 14, 5, 14, 88, 8, 14, 10, 14, 12, 14, 91, 9, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 98, 8, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 0, 0, 21, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 0, 21, 0, 23, 0, 25, 10, 27, 11, 29, 12, 31, 13, 33, 14, 35, 15, 37, 16, 39, 17, 41, 18, 1, 0, 5, 1, 0, 48, 57, 3, 0, 65, 90, 95, 95, 97, 122, 2, 0, 43, 43, 45, 45, 2, 0, 42, 42, 47, 47, 3, 0, 9, 10, 13, 13, 32, 32, 114, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 1, 43, 1, 0, 0, 0, 3, 45, 1, 0, 0, 0, 5, 47, 1, 0, 0, 0, 7, 49, 1, 0, 0, 0, 9, 51, 1, 0, 0, 0, 11, 53, 1, 0, 0, 0, 13, 55, 1, 0, 0, 0, 15, 57, 1, 0, 0, 0, 17, 59, 1, 0, 0, 0, 19, 62, 1, 0, 0, 0, 21, 64, 1, 0, 0, 0, 23, 68, 1, 0, 0, 0, 25, 71, 1, 0, 0, 0, 27, 83, 1, 0, 0, 0, 29, 85, 1, 0, 0, 0, 31, 97, 1, 0, 0, 0, 33, 99, 1, 0, 0, 0, 35, 101, 1, 0, 0, 0, 37, 103, 1, 0, 0, 0, 39, 105, 1, 0, 0, 0, 41, 107, 1, 0, 0, 0, 43, 44, 5, 43, 0, 0, 44, 2, 1, 0, 0, 0, 45, 46, 5, 45, 0, 0, 46, 4, 1, 0, 0, 0, 47, 48, 5, 47, 0, 0, 48, 6, 1, 0, 0, 0, 49, 50, 5, 42, 0, 0, 50, 8, 1, 0, 0, 0, 51, 52, 5, 46, 0, 0, 52, 10, 1, 0, 0, 0, 53, 54, 5, 40, 0, 0, 54, 12, 1, 0, 0, 0, 55, 56, 5, 41, 0, 0, 56, 14, 1, 0, 0, 0, 57, 58, 5, 44, 0, 0, 58, 16, 1, 0, 0, 0, 59, 60, 5, 46, 0, 0, 60, 61, 5, 46, 0, 0, 61, 18, 1, 0, 0, 0, 62, 63, 7, 0, 0, 0, 63, 20, 1, 0, 0, 0, 64, 65, 7, 1, 0, 0, 65, 22, 1, 0, 0, 0, 66, 69, 3, 21, 10, 0, 67, 69, 3, 19, 9, 0, 68, 66, 1, 0, 0, 0, 68, 67, 1, 0, 0, 0, 69, 24, 1, 0, 0, 0, 70, 72, 3, 19, 9, 0, 71, 70, 1, 0, 0, 0, 72, 73, 1, 0, 0, 0, 73, 71, 1, 0, 0, 0, 73, 74, 1, 0, 0, 0, 74, 81, 1, 0, 0, 0, 75, 77, 5, 46, 0, 0, 76, 78, 3, 19, 9, 0, 77, 76, 1, 0, 0, 0, 78, 79, 1, 0, 0, 0, 79, 77, 1, 0, 0, 0, 79, 80, 1, 0, 0, 0, 80, 82, 1, 0, 0, 0, 81, 75, 1, 0, 0, 0, 81, 82, 1, 0, 0, 0, 82, 26, 1, 0, 0, 0, 83, 84, 5, 116, 0, 0, 84, 28, 1, 0, 0, 0, 85, 89, 3, 21, 10, 0, 86, 88, 3, 23, 11, 0, 87, 86, 1, 0, 0, 0, 88, 91, 1, 0, 0, 0, 89, 87, 1, 0, 0, 0, 89, 90, 1, 0, 0, 0, 90, 30, 1, 0, 0, 0, 91, 89, 1, 0, 0, 0, 92, 98, 5, 61, 0, 0, 93, 94, 5, 62, 0, 0, 94, 98, 5, 61, 0, 0, 95, 96, 5, 60, 0, 0, 96, 98, 5, 61, 0, 0, 97, 92, 1, 0, 0, 0, 97, 93, 1, 0, 0, 0, 97, 95, 1, 0, 0, 0, 98, 32, 1, 0, 0, 0, 99, 100, 7, 2, 0, 0, 100, 34, 1, 0, 0, 0, 101, 102, 7, 3, 0, 0, 102, 36, 1, 0, 0, 0, 103, 104, 5, 91, 0, 0, 104, 38, 1, 0, 0, 0, 105, 106, 5, 93, 0, 0, 106, 40, 1, 0, 0, 0, 107, 108, 7, 4, 0, 0, 108, 109, 1, 0, 0, 0, 109, 110, 6, 20, 0, 0, 110, 42, 1, 0, 0, 0, 7, 0, 68, 73, 79, 81, 89, 97, 1, 6, 0, 0] \ No newline at end of file +[4, 0, 17, 109, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 3, 14, 75, 8, 14, 1, 15, 4, 15, 78, 8, 15, 11, 15, 12, 15, 79, 1, 15, 1, 15, 4, 15, 84, 8, 15, 11, 15, 12, 15, 85, 3, 15, 88, 8, 15, 1, 16, 1, 16, 1, 17, 1, 17, 5, 17, 94, 8, 17, 10, 17, 12, 17, 97, 9, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 3, 18, 104, 8, 18, 1, 19, 1, 19, 1, 19, 1, 19, 0, 0, 20, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 0, 27, 0, 29, 0, 31, 13, 33, 14, 35, 15, 37, 16, 39, 17, 1, 0, 3, 1, 0, 48, 57, 3, 0, 65, 90, 95, 95, 97, 122, 3, 0, 9, 10, 13, 13, 32, 32, 112, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 1, 41, 1, 0, 0, 0, 3, 43, 1, 0, 0, 0, 5, 45, 1, 0, 0, 0, 7, 47, 1, 0, 0, 0, 9, 49, 1, 0, 0, 0, 11, 51, 1, 0, 0, 0, 13, 53, 1, 0, 0, 0, 15, 55, 1, 0, 0, 0, 17, 59, 1, 0, 0, 0, 19, 62, 1, 0, 0, 0, 21, 64, 1, 0, 0, 0, 23, 66, 1, 0, 0, 0, 25, 68, 1, 0, 0, 0, 27, 70, 1, 0, 0, 0, 29, 74, 1, 0, 0, 0, 31, 77, 1, 0, 0, 0, 33, 89, 1, 0, 0, 0, 35, 91, 1, 0, 0, 0, 37, 103, 1, 0, 0, 0, 39, 105, 1, 0, 0, 0, 41, 42, 5, 46, 0, 0, 42, 2, 1, 0, 0, 0, 43, 44, 5, 45, 0, 0, 44, 4, 1, 0, 0, 0, 45, 46, 5, 40, 0, 0, 46, 6, 1, 0, 0, 0, 47, 48, 5, 41, 0, 0, 48, 8, 1, 0, 0, 0, 49, 50, 5, 47, 0, 0, 50, 10, 1, 0, 0, 0, 51, 52, 5, 42, 0, 0, 52, 12, 1, 0, 0, 0, 53, 54, 5, 43, 0, 0, 54, 14, 1, 0, 0, 0, 55, 56, 5, 115, 0, 0, 56, 57, 5, 117, 0, 0, 57, 58, 5, 109, 0, 0, 58, 16, 1, 0, 0, 0, 59, 60, 5, 46, 0, 0, 60, 61, 5, 46, 0, 0, 61, 18, 1, 0, 0, 0, 62, 63, 5, 44, 0, 0, 63, 20, 1, 0, 0, 0, 64, 65, 5, 91, 0, 0, 65, 22, 1, 0, 0, 0, 66, 67, 5, 93, 0, 0, 67, 24, 1, 0, 0, 0, 68, 69, 7, 0, 0, 0, 69, 26, 1, 0, 0, 0, 70, 71, 7, 1, 0, 0, 71, 28, 1, 0, 0, 0, 72, 75, 3, 27, 13, 0, 73, 75, 3, 25, 12, 0, 74, 72, 1, 0, 0, 0, 74, 73, 1, 0, 0, 0, 75, 30, 1, 0, 0, 0, 76, 78, 3, 25, 12, 0, 77, 76, 1, 0, 0, 0, 78, 79, 1, 0, 0, 0, 79, 77, 1, 0, 0, 0, 79, 80, 1, 0, 0, 0, 80, 87, 1, 0, 0, 0, 81, 83, 5, 46, 0, 0, 82, 84, 3, 25, 12, 0, 83, 82, 1, 0, 0, 0, 84, 85, 1, 0, 0, 0, 85, 83, 1, 0, 0, 0, 85, 86, 1, 0, 0, 0, 86, 88, 1, 0, 0, 0, 87, 81, 1, 0, 0, 0, 87, 88, 1, 0, 0, 0, 88, 32, 1, 0, 0, 0, 89, 90, 5, 116, 0, 0, 90, 34, 1, 0, 0, 0, 91, 95, 3, 27, 13, 0, 92, 94, 3, 29, 14, 0, 93, 92, 1, 0, 0, 0, 94, 97, 1, 0, 0, 0, 95, 93, 1, 0, 0, 0, 95, 96, 1, 0, 0, 0, 96, 36, 1, 0, 0, 0, 97, 95, 1, 0, 0, 0, 98, 104, 5, 61, 0, 0, 99, 100, 5, 62, 0, 0, 100, 104, 5, 61, 0, 0, 101, 102, 5, 60, 0, 0, 102, 104, 5, 61, 0, 0, 103, 98, 1, 0, 0, 0, 103, 99, 1, 0, 0, 0, 103, 101, 1, 0, 0, 0, 104, 38, 1, 0, 0, 0, 105, 106, 7, 2, 0, 0, 106, 107, 1, 0, 0, 0, 107, 108, 6, 19, 0, 0, 108, 40, 1, 0, 0, 0, 7, 0, 74, 79, 85, 87, 95, 103, 1, 6, 0, 0] \ No newline at end of file diff --git a/src/libs/antares/antlr-interface/ExprLexer.tokens b/src/libs/antares/antlr-interface/ExprLexer.tokens index 29d96df5f3..868577445e 100644 --- a/src/libs/antares/antlr-interface/ExprLexer.tokens +++ b/src/libs/antares/antlr-interface/ExprLexer.tokens @@ -7,24 +7,24 @@ T__5=6 T__6=7 T__7=8 T__8=9 -NUMBER=10 -TIME=11 -IDENTIFIER=12 -COMPARISON=13 -ADDSUB=14 -MULDIV=15 -LBRACKET=16 -RBRACKET=17 -WS=18 -'+'=1 +T__9=10 +T__10=11 +T__11=12 +NUMBER=13 +TIME=14 +IDENTIFIER=15 +COMPARISON=16 +WS=17 +'.'=1 '-'=2 -'/'=3 -'*'=4 -'.'=5 -'('=6 -')'=7 -','=8 +'('=3 +')'=4 +'/'=5 +'*'=6 +'+'=7 +'sum'=8 '..'=9 -'t'=11 -'['=16 -']'=17 +','=10 +'['=11 +']'=12 +'t'=14 diff --git a/src/libs/antares/antlr-interface/ExprParser.cpp b/src/libs/antares/antlr-interface/ExprParser.cpp index 3c688d96d3..3572cd6863 100644 --- a/src/libs/antares/antlr-interface/ExprParser.cpp +++ b/src/libs/antares/antlr-interface/ExprParser.cpp @@ -1,5 +1,5 @@ -// Generated from Expr.g4 by ANTLR 4.13.1 +// Generated from Expr.g4 by ANTLR 4.13.2 #include "ExprVisitor.h" @@ -40,7 +40,7 @@ ::antlr4::internal::OnceFlag exprParserOnceFlag; #if ANTLR4_USE_THREAD_LOCAL_CACHE static thread_local #endif -ExprParserStaticData *exprParserStaticData = nullptr; +std::unique_ptr exprParserStaticData = nullptr; void exprParserInitialize() { #if ANTLR4_USE_THREAD_LOCAL_CACHE @@ -52,44 +52,54 @@ void exprParserInitialize() { #endif auto staticData = std::make_unique( std::vector{ - "fullexpr", "shift", "expr" + "fullexpr", "expr", "atom", "shift", "shift_expr", "right_expr" }, std::vector{ - "", "'+'", "'-'", "'/'", "'*'", "'.'", "'('", "')'", "','", "'..'", - "", "'t'", "", "", "", "", "'['", "']'" + "", "'.'", "'-'", "'('", "')'", "'/'", "'*'", "'+'", "'sum'", "'..'", + "','", "'['", "']'", "", "'t'" }, std::vector{ - "", "", "", "", "", "", "", "", "", "", "NUMBER", "TIME", "IDENTIFIER", - "COMPARISON", "ADDSUB", "MULDIV", "LBRACKET", "RBRACKET", "WS" + "", "", "", "", "", "", "", "", "", "", "", "", "", "NUMBER", "TIME", + "IDENTIFIER", "COMPARISON", "WS" } ); static const int32_t serializedATNSegment[] = { - 4,1,18,86,2,0,7,0,2,1,7,1,2,2,7,2,1,0,1,0,1,0,1,1,1,1,1,1,3,1,13,8,1, - 1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,5,2,37,8,2,10,2,12,2,40,9,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,5,2,49,8,2,10,2,12,2,52,9,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, - 2,1,2,1,2,1,2,1,2,1,2,1,2,3,2,70,8,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, - 1,2,5,2,81,8,2,10,2,12,2,84,9,2,1,2,0,1,4,3,0,2,4,0,2,1,0,1,2,1,0,3,4, - 97,0,6,1,0,0,0,2,9,1,0,0,0,4,69,1,0,0,0,6,7,3,4,2,0,7,8,5,0,0,1,8,1,1, - 0,0,0,9,12,5,11,0,0,10,11,7,0,0,0,11,13,3,4,2,0,12,10,1,0,0,0,12,13,1, - 0,0,0,13,3,1,0,0,0,14,15,6,2,-1,0,15,16,5,2,0,0,16,70,3,4,2,13,17,70, - 5,12,0,0,18,19,5,12,0,0,19,20,5,5,0,0,20,70,5,12,0,0,21,70,5,10,0,0,22, - 23,5,6,0,0,23,24,3,4,2,0,24,25,5,7,0,0,25,70,1,0,0,0,26,27,5,12,0,0,27, - 28,5,6,0,0,28,29,3,4,2,0,29,30,5,7,0,0,30,70,1,0,0,0,31,32,5,12,0,0,32, - 33,5,16,0,0,33,38,3,2,1,0,34,35,5,8,0,0,35,37,3,2,1,0,36,34,1,0,0,0,37, - 40,1,0,0,0,38,36,1,0,0,0,38,39,1,0,0,0,39,41,1,0,0,0,40,38,1,0,0,0,41, - 42,5,17,0,0,42,70,1,0,0,0,43,44,5,12,0,0,44,45,5,16,0,0,45,50,3,4,2,0, - 46,47,5,8,0,0,47,49,3,4,2,0,48,46,1,0,0,0,49,52,1,0,0,0,50,48,1,0,0,0, - 50,51,1,0,0,0,51,53,1,0,0,0,52,50,1,0,0,0,53,54,5,17,0,0,54,70,1,0,0, - 0,55,56,5,12,0,0,56,57,5,16,0,0,57,58,3,2,1,0,58,59,5,9,0,0,59,60,3,2, - 1,0,60,61,5,17,0,0,61,70,1,0,0,0,62,63,5,12,0,0,63,64,5,16,0,0,64,65, - 3,4,2,0,65,66,5,9,0,0,66,67,3,4,2,0,67,68,5,17,0,0,68,70,1,0,0,0,69,14, - 1,0,0,0,69,17,1,0,0,0,69,18,1,0,0,0,69,21,1,0,0,0,69,22,1,0,0,0,69,26, - 1,0,0,0,69,31,1,0,0,0,69,43,1,0,0,0,69,55,1,0,0,0,69,62,1,0,0,0,70,82, - 1,0,0,0,71,72,10,12,0,0,72,73,7,1,0,0,73,81,3,4,2,13,74,75,10,11,0,0, - 75,76,7,0,0,0,76,81,3,4,2,12,77,78,10,10,0,0,78,79,5,13,0,0,79,81,3,4, - 2,11,80,71,1,0,0,0,80,74,1,0,0,0,80,77,1,0,0,0,81,84,1,0,0,0,82,80,1, - 0,0,0,82,83,1,0,0,0,83,5,1,0,0,0,84,82,1,0,0,0,6,12,38,50,69,80,82 + 4,1,17,117,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,1,0,1,0,1, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,3,1,56,8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 5,1,67,8,1,10,1,12,1,70,9,1,1,2,1,2,3,2,74,8,2,1,3,1,3,3,3,78,8,3,1,4, + 1,4,1,4,1,4,1,4,1,4,1,4,1,4,3,4,88,8,4,1,4,1,4,1,4,1,4,1,4,1,4,5,4,96, + 8,4,10,4,12,4,99,9,4,1,5,1,5,1,5,1,5,1,5,1,5,3,5,107,8,5,1,5,1,5,1,5, + 5,5,112,8,5,10,5,12,5,115,9,5,1,5,0,3,2,8,10,6,0,2,4,6,8,10,0,2,1,0,5, + 6,2,0,2,2,7,7,128,0,12,1,0,0,0,2,55,1,0,0,0,4,73,1,0,0,0,6,75,1,0,0,0, + 8,87,1,0,0,0,10,106,1,0,0,0,12,13,3,2,1,0,13,14,5,0,0,1,14,1,1,0,0,0, + 15,16,6,1,-1,0,16,56,3,4,2,0,17,18,5,15,0,0,18,19,5,1,0,0,19,56,5,15, + 0,0,20,21,5,2,0,0,21,56,3,2,1,10,22,23,5,3,0,0,23,24,3,2,1,0,24,25,5, + 4,0,0,25,56,1,0,0,0,26,27,5,8,0,0,27,28,5,3,0,0,28,29,3,2,1,0,29,30,5, + 4,0,0,30,56,1,0,0,0,31,32,5,8,0,0,32,33,5,3,0,0,33,34,3,6,3,0,34,35,5, + 9,0,0,35,36,3,6,3,0,36,37,5,10,0,0,37,38,3,2,1,0,38,39,5,4,0,0,39,56, + 1,0,0,0,40,41,5,15,0,0,41,42,5,3,0,0,42,43,3,2,1,0,43,44,5,4,0,0,44,56, + 1,0,0,0,45,46,5,15,0,0,46,47,5,11,0,0,47,48,3,6,3,0,48,49,5,12,0,0,49, + 56,1,0,0,0,50,51,5,15,0,0,51,52,5,11,0,0,52,53,3,2,1,0,53,54,5,12,0,0, + 54,56,1,0,0,0,55,15,1,0,0,0,55,17,1,0,0,0,55,20,1,0,0,0,55,22,1,0,0,0, + 55,26,1,0,0,0,55,31,1,0,0,0,55,40,1,0,0,0,55,45,1,0,0,0,55,50,1,0,0,0, + 56,68,1,0,0,0,57,58,10,8,0,0,58,59,7,0,0,0,59,67,3,2,1,9,60,61,10,7,0, + 0,61,62,7,1,0,0,62,67,3,2,1,8,63,64,10,6,0,0,64,65,5,16,0,0,65,67,3,2, + 1,7,66,57,1,0,0,0,66,60,1,0,0,0,66,63,1,0,0,0,67,70,1,0,0,0,68,66,1,0, + 0,0,68,69,1,0,0,0,69,3,1,0,0,0,70,68,1,0,0,0,71,74,5,13,0,0,72,74,5,15, + 0,0,73,71,1,0,0,0,73,72,1,0,0,0,74,5,1,0,0,0,75,77,5,14,0,0,76,78,3,8, + 4,0,77,76,1,0,0,0,77,78,1,0,0,0,78,7,1,0,0,0,79,80,6,4,-1,0,80,81,7,1, + 0,0,81,88,3,4,2,0,82,83,7,1,0,0,83,84,5,3,0,0,84,85,3,2,1,0,85,86,5,4, + 0,0,86,88,1,0,0,0,87,79,1,0,0,0,87,82,1,0,0,0,88,97,1,0,0,0,89,90,10, + 4,0,0,90,91,7,0,0,0,91,96,3,10,5,0,92,93,10,3,0,0,93,94,7,1,0,0,94,96, + 3,10,5,0,95,89,1,0,0,0,95,92,1,0,0,0,96,99,1,0,0,0,97,95,1,0,0,0,97,98, + 1,0,0,0,98,9,1,0,0,0,99,97,1,0,0,0,100,101,6,5,-1,0,101,102,5,3,0,0,102, + 103,3,2,1,0,103,104,5,4,0,0,104,107,1,0,0,0,105,107,3,4,2,0,106,100,1, + 0,0,0,106,105,1,0,0,0,107,113,1,0,0,0,108,109,10,3,0,0,109,110,7,0,0, + 0,110,112,3,10,5,4,111,108,1,0,0,0,112,115,1,0,0,0,113,111,1,0,0,0,113, + 114,1,0,0,0,114,11,1,0,0,0,115,113,1,0,0,0,10,55,66,68,73,77,87,95,97, + 106,113 }; staticData->serializedATN = antlr4::atn::SerializedATNView(serializedATNSegment, sizeof(serializedATNSegment) / sizeof(serializedATNSegment[0])); @@ -101,7 +111,7 @@ void exprParserInitialize() { for (size_t i = 0; i < count; i++) { staticData->decisionToDFA.emplace_back(staticData->atn->getDecisionState(i), i); } - exprParserStaticData = staticData.release(); + exprParserStaticData = std::move(staticData); } } @@ -178,9 +188,9 @@ ExprParser::FullexprContext* ExprParser::fullexpr() { }); try { enterOuterAlt(_localctx, 1); - setState(6); + setState(12); expr(0); - setState(7); + setState(13); match(ExprParser::EOF); } @@ -193,82 +203,6 @@ ExprParser::FullexprContext* ExprParser::fullexpr() { return _localctx; } -//----------------- ShiftContext ------------------------------------------------------------------ - -ExprParser::ShiftContext::ShiftContext(ParserRuleContext *parent, size_t invokingState) - : ParserRuleContext(parent, invokingState) { -} - -tree::TerminalNode* ExprParser::ShiftContext::TIME() { - return getToken(ExprParser::TIME, 0); -} - -ExprParser::ExprContext* ExprParser::ShiftContext::expr() { - return getRuleContext(0); -} - - -size_t ExprParser::ShiftContext::getRuleIndex() const { - return ExprParser::RuleShift; -} - - -std::any ExprParser::ShiftContext::accept(tree::ParseTreeVisitor *visitor) { - if (auto parserVisitor = dynamic_cast(visitor)) - return parserVisitor->visitShift(this); - else - return visitor->visitChildren(this); -} - -ExprParser::ShiftContext* ExprParser::shift() { - ShiftContext *_localctx = _tracker.createInstance(_ctx, getState()); - enterRule(_localctx, 2, ExprParser::RuleShift); - size_t _la = 0; - -#if __cplusplus > 201703L - auto onExit = finally([=, this] { -#else - auto onExit = finally([=] { -#endif - exitRule(); - }); - try { - enterOuterAlt(_localctx, 1); - setState(9); - match(ExprParser::TIME); - setState(12); - _errHandler->sync(this); - - _la = _input->LA(1); - if (_la == ExprParser::T__0 - - || _la == ExprParser::T__1) { - setState(10); - antlrcpp::downCast(_localctx)->op = _input->LT(1); - _la = _input->LA(1); - if (!(_la == ExprParser::T__0 - - || _la == ExprParser::T__1)) { - antlrcpp::downCast(_localctx)->op = _errHandler->recoverInline(this); - } - else { - _errHandler->reportMatch(this); - consume(); - } - setState(11); - expr(0); - } - - } - catch (RecognitionException &e) { - _errHandler->reportError(this, e); - _localctx->exception = std::current_exception(); - _errHandler->recover(this, _localctx->exception); - } - - return _localctx; -} - //----------------- ExprContext ------------------------------------------------------------------ ExprParser::ExprContext::ExprContext(ParserRuleContext *parent, size_t invokingState) @@ -284,18 +218,26 @@ void ExprParser::ExprContext::copyFrom(ExprContext *ctx) { ParserRuleContext::copyFrom(ctx); } -//----------------- IdentifierContext ------------------------------------------------------------------ +//----------------- TimeSumContext ------------------------------------------------------------------ -tree::TerminalNode* ExprParser::IdentifierContext::IDENTIFIER() { - return getToken(ExprParser::IDENTIFIER, 0); +ExprParser::ExprContext* ExprParser::TimeSumContext::expr() { + return getRuleContext(0); +} + +std::vector ExprParser::TimeSumContext::shift() { + return getRuleContexts(); } -ExprParser::IdentifierContext::IdentifierContext(ExprContext *ctx) { copyFrom(ctx); } +ExprParser::ShiftContext* ExprParser::TimeSumContext::shift(size_t i) { + return getRuleContext(i); +} +ExprParser::TimeSumContext::TimeSumContext(ExprContext *ctx) { copyFrom(ctx); } -std::any ExprParser::IdentifierContext::accept(tree::ParseTreeVisitor *visitor) { + +std::any ExprParser::TimeSumContext::accept(tree::ParseTreeVisitor *visitor) { if (auto parserVisitor = dynamic_cast(visitor)) - return parserVisitor->visitIdentifier(this); + return parserVisitor->visitTimeSum(this); else return visitor->visitChildren(this); } @@ -314,144 +256,90 @@ std::any ExprParser::NegationContext::accept(tree::ParseTreeVisitor *visitor) { else return visitor->visitChildren(this); } -//----------------- ExpressionContext ------------------------------------------------------------------ - -ExprParser::ExprContext* ExprParser::ExpressionContext::expr() { - return getRuleContext(0); -} - -ExprParser::ExpressionContext::ExpressionContext(ExprContext *ctx) { copyFrom(ctx); } - - -std::any ExprParser::ExpressionContext::accept(tree::ParseTreeVisitor *visitor) { - if (auto parserVisitor = dynamic_cast(visitor)) - return parserVisitor->visitExpression(this); - else - return visitor->visitChildren(this); -} -//----------------- ComparisonContext ------------------------------------------------------------------ - -std::vector ExprParser::ComparisonContext::expr() { - return getRuleContexts(); -} - -ExprParser::ExprContext* ExprParser::ComparisonContext::expr(size_t i) { - return getRuleContext(i); -} +//----------------- UnsignedAtomContext ------------------------------------------------------------------ -tree::TerminalNode* ExprParser::ComparisonContext::COMPARISON() { - return getToken(ExprParser::COMPARISON, 0); +ExprParser::AtomContext* ExprParser::UnsignedAtomContext::atom() { + return getRuleContext(0); } -ExprParser::ComparisonContext::ComparisonContext(ExprContext *ctx) { copyFrom(ctx); } +ExprParser::UnsignedAtomContext::UnsignedAtomContext(ExprContext *ctx) { copyFrom(ctx); } -std::any ExprParser::ComparisonContext::accept(tree::ParseTreeVisitor *visitor) { +std::any ExprParser::UnsignedAtomContext::accept(tree::ParseTreeVisitor *visitor) { if (auto parserVisitor = dynamic_cast(visitor)) - return parserVisitor->visitComparison(this); + return parserVisitor->visitUnsignedAtom(this); else return visitor->visitChildren(this); } -//----------------- AddsubContext ------------------------------------------------------------------ - -std::vector ExprParser::AddsubContext::expr() { - return getRuleContexts(); -} +//----------------- ExpressionContext ------------------------------------------------------------------ -ExprParser::ExprContext* ExprParser::AddsubContext::expr(size_t i) { - return getRuleContext(i); +ExprParser::ExprContext* ExprParser::ExpressionContext::expr() { + return getRuleContext(0); } -ExprParser::AddsubContext::AddsubContext(ExprContext *ctx) { copyFrom(ctx); } +ExprParser::ExpressionContext::ExpressionContext(ExprContext *ctx) { copyFrom(ctx); } -std::any ExprParser::AddsubContext::accept(tree::ParseTreeVisitor *visitor) { +std::any ExprParser::ExpressionContext::accept(tree::ParseTreeVisitor *visitor) { if (auto parserVisitor = dynamic_cast(visitor)) - return parserVisitor->visitAddsub(this); + return parserVisitor->visitExpression(this); else return visitor->visitChildren(this); } -//----------------- PortFieldContext ------------------------------------------------------------------ +//----------------- TimeIndexContext ------------------------------------------------------------------ -std::vector ExprParser::PortFieldContext::IDENTIFIER() { - return getTokens(ExprParser::IDENTIFIER); +tree::TerminalNode* ExprParser::TimeIndexContext::IDENTIFIER() { + return getToken(ExprParser::IDENTIFIER, 0); } -tree::TerminalNode* ExprParser::PortFieldContext::IDENTIFIER(size_t i) { - return getToken(ExprParser::IDENTIFIER, i); +ExprParser::ExprContext* ExprParser::TimeIndexContext::expr() { + return getRuleContext(0); } -ExprParser::PortFieldContext::PortFieldContext(ExprContext *ctx) { copyFrom(ctx); } +ExprParser::TimeIndexContext::TimeIndexContext(ExprContext *ctx) { copyFrom(ctx); } -std::any ExprParser::PortFieldContext::accept(tree::ParseTreeVisitor *visitor) { +std::any ExprParser::TimeIndexContext::accept(tree::ParseTreeVisitor *visitor) { if (auto parserVisitor = dynamic_cast(visitor)) - return parserVisitor->visitPortField(this); + return parserVisitor->visitTimeIndex(this); else return visitor->visitChildren(this); } -//----------------- MuldivContext ------------------------------------------------------------------ +//----------------- ComparisonContext ------------------------------------------------------------------ -std::vector ExprParser::MuldivContext::expr() { +std::vector ExprParser::ComparisonContext::expr() { return getRuleContexts(); } -ExprParser::ExprContext* ExprParser::MuldivContext::expr(size_t i) { +ExprParser::ExprContext* ExprParser::ComparisonContext::expr(size_t i) { return getRuleContext(i); } -ExprParser::MuldivContext::MuldivContext(ExprContext *ctx) { copyFrom(ctx); } - - -std::any ExprParser::MuldivContext::accept(tree::ParseTreeVisitor *visitor) { - if (auto parserVisitor = dynamic_cast(visitor)) - return parserVisitor->visitMuldiv(this); - else - return visitor->visitChildren(this); -} -//----------------- NumberContext ------------------------------------------------------------------ - -tree::TerminalNode* ExprParser::NumberContext::NUMBER() { - return getToken(ExprParser::NUMBER, 0); +tree::TerminalNode* ExprParser::ComparisonContext::COMPARISON() { + return getToken(ExprParser::COMPARISON, 0); } -ExprParser::NumberContext::NumberContext(ExprContext *ctx) { copyFrom(ctx); } +ExprParser::ComparisonContext::ComparisonContext(ExprContext *ctx) { copyFrom(ctx); } -std::any ExprParser::NumberContext::accept(tree::ParseTreeVisitor *visitor) { +std::any ExprParser::ComparisonContext::accept(tree::ParseTreeVisitor *visitor) { if (auto parserVisitor = dynamic_cast(visitor)) - return parserVisitor->visitNumber(this); + return parserVisitor->visitComparison(this); else return visitor->visitChildren(this); } -//----------------- TimeIndexContext ------------------------------------------------------------------ - -tree::TerminalNode* ExprParser::TimeIndexContext::IDENTIFIER() { - return getToken(ExprParser::IDENTIFIER, 0); -} - -tree::TerminalNode* ExprParser::TimeIndexContext::LBRACKET() { - return getToken(ExprParser::LBRACKET, 0); -} - -std::vector ExprParser::TimeIndexContext::expr() { - return getRuleContexts(); -} - -ExprParser::ExprContext* ExprParser::TimeIndexContext::expr(size_t i) { - return getRuleContext(i); -} +//----------------- AllTimeSumContext ------------------------------------------------------------------ -tree::TerminalNode* ExprParser::TimeIndexContext::RBRACKET() { - return getToken(ExprParser::RBRACKET, 0); +ExprParser::ExprContext* ExprParser::AllTimeSumContext::expr() { + return getRuleContext(0); } -ExprParser::TimeIndexContext::TimeIndexContext(ExprContext *ctx) { copyFrom(ctx); } +ExprParser::AllTimeSumContext::AllTimeSumContext(ExprContext *ctx) { copyFrom(ctx); } -std::any ExprParser::TimeIndexContext::accept(tree::ParseTreeVisitor *visitor) { +std::any ExprParser::AllTimeSumContext::accept(tree::ParseTreeVisitor *visitor) { if (auto parserVisitor = dynamic_cast(visitor)) - return parserVisitor->visitTimeIndex(this); + return parserVisitor->visitAllTimeSum(this); else return visitor->visitChildren(this); } @@ -461,20 +349,8 @@ tree::TerminalNode* ExprParser::TimeShiftContext::IDENTIFIER() { return getToken(ExprParser::IDENTIFIER, 0); } -tree::TerminalNode* ExprParser::TimeShiftContext::LBRACKET() { - return getToken(ExprParser::LBRACKET, 0); -} - -std::vector ExprParser::TimeShiftContext::shift() { - return getRuleContexts(); -} - -ExprParser::ShiftContext* ExprParser::TimeShiftContext::shift(size_t i) { - return getRuleContext(i); -} - -tree::TerminalNode* ExprParser::TimeShiftContext::RBRACKET() { - return getToken(ExprParser::RBRACKET, 0); +ExprParser::ShiftContext* ExprParser::TimeShiftContext::shift() { + return getRuleContext(0); } ExprParser::TimeShiftContext::TimeShiftContext(ExprContext *ctx) { copyFrom(ctx); } @@ -505,65 +381,60 @@ std::any ExprParser::FunctionContext::accept(tree::ParseTreeVisitor *visitor) { else return visitor->visitChildren(this); } -//----------------- TimeShiftRangeContext ------------------------------------------------------------------ +//----------------- AddsubContext ------------------------------------------------------------------ -tree::TerminalNode* ExprParser::TimeShiftRangeContext::IDENTIFIER() { - return getToken(ExprParser::IDENTIFIER, 0); +std::vector ExprParser::AddsubContext::expr() { + return getRuleContexts(); } -tree::TerminalNode* ExprParser::TimeShiftRangeContext::LBRACKET() { - return getToken(ExprParser::LBRACKET, 0); +ExprParser::ExprContext* ExprParser::AddsubContext::expr(size_t i) { + return getRuleContext(i); } -tree::TerminalNode* ExprParser::TimeShiftRangeContext::RBRACKET() { - return getToken(ExprParser::RBRACKET, 0); +ExprParser::AddsubContext::AddsubContext(ExprContext *ctx) { copyFrom(ctx); } + + +std::any ExprParser::AddsubContext::accept(tree::ParseTreeVisitor *visitor) { + if (auto parserVisitor = dynamic_cast(visitor)) + return parserVisitor->visitAddsub(this); + else + return visitor->visitChildren(this); } +//----------------- PortFieldContext ------------------------------------------------------------------ -std::vector ExprParser::TimeShiftRangeContext::shift() { - return getRuleContexts(); +std::vector ExprParser::PortFieldContext::IDENTIFIER() { + return getTokens(ExprParser::IDENTIFIER); } -ExprParser::ShiftContext* ExprParser::TimeShiftRangeContext::shift(size_t i) { - return getRuleContext(i); +tree::TerminalNode* ExprParser::PortFieldContext::IDENTIFIER(size_t i) { + return getToken(ExprParser::IDENTIFIER, i); } -ExprParser::TimeShiftRangeContext::TimeShiftRangeContext(ExprContext *ctx) { copyFrom(ctx); } +ExprParser::PortFieldContext::PortFieldContext(ExprContext *ctx) { copyFrom(ctx); } -std::any ExprParser::TimeShiftRangeContext::accept(tree::ParseTreeVisitor *visitor) { +std::any ExprParser::PortFieldContext::accept(tree::ParseTreeVisitor *visitor) { if (auto parserVisitor = dynamic_cast(visitor)) - return parserVisitor->visitTimeShiftRange(this); + return parserVisitor->visitPortField(this); else return visitor->visitChildren(this); } -//----------------- TimeRangeContext ------------------------------------------------------------------ - -tree::TerminalNode* ExprParser::TimeRangeContext::IDENTIFIER() { - return getToken(ExprParser::IDENTIFIER, 0); -} - -tree::TerminalNode* ExprParser::TimeRangeContext::LBRACKET() { - return getToken(ExprParser::LBRACKET, 0); -} +//----------------- MuldivContext ------------------------------------------------------------------ -std::vector ExprParser::TimeRangeContext::expr() { +std::vector ExprParser::MuldivContext::expr() { return getRuleContexts(); } -ExprParser::ExprContext* ExprParser::TimeRangeContext::expr(size_t i) { +ExprParser::ExprContext* ExprParser::MuldivContext::expr(size_t i) { return getRuleContext(i); } -tree::TerminalNode* ExprParser::TimeRangeContext::RBRACKET() { - return getToken(ExprParser::RBRACKET, 0); -} - -ExprParser::TimeRangeContext::TimeRangeContext(ExprContext *ctx) { copyFrom(ctx); } +ExprParser::MuldivContext::MuldivContext(ExprContext *ctx) { copyFrom(ctx); } -std::any ExprParser::TimeRangeContext::accept(tree::ParseTreeVisitor *visitor) { +std::any ExprParser::MuldivContext::accept(tree::ParseTreeVisitor *visitor) { if (auto parserVisitor = dynamic_cast(visitor)) - return parserVisitor->visitTimeRange(this); + return parserVisitor->visitMuldiv(this); else return visitor->visitChildren(this); } @@ -578,8 +449,8 @@ ExprParser::ExprContext* ExprParser::expr(int precedence) { ExprParser::ExprContext *_localctx = _tracker.createInstance(_ctx, parentState); ExprParser::ExprContext *previousContext = _localctx; (void)previousContext; // Silence compiler, in case the context is not used by generated code. - size_t startState = 4; - enterRecursionRule(_localctx, 4, ExprParser::RuleExpr, precedence); + size_t startState = 2; + enterRecursionRule(_localctx, 2, ExprParser::RuleExpr, precedence); size_t _la = 0; @@ -593,169 +464,136 @@ ExprParser::ExprContext* ExprParser::expr(int precedence) { try { size_t alt; enterOuterAlt(_localctx, 1); - setState(69); + setState(55); _errHandler->sync(this); - switch (getInterpreter()->adaptivePredict(_input, 3, _ctx)) { + switch (getInterpreter()->adaptivePredict(_input, 0, _ctx)) { case 1: { - _localctx = _tracker.createInstance(_localctx); + _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; - setState(15); - match(ExprParser::T__1); setState(16); - expr(13); + atom(); break; } case 2: { - _localctx = _tracker.createInstance(_localctx); + _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; setState(17); match(ExprParser::IDENTIFIER); - break; - } - - case 3: { - _localctx = _tracker.createInstance(_localctx); - _ctx = _localctx; - previousContext = _localctx; setState(18); - match(ExprParser::IDENTIFIER); + match(ExprParser::T__0); setState(19); - match(ExprParser::T__4); - setState(20); match(ExprParser::IDENTIFIER); break; } - case 4: { - _localctx = _tracker.createInstance(_localctx); + case 3: { + _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; + setState(20); + match(ExprParser::T__1); setState(21); - match(ExprParser::NUMBER); + expr(10); break; } - case 5: { + case 4: { _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; setState(22); - match(ExprParser::T__5); + match(ExprParser::T__2); setState(23); expr(0); setState(24); - match(ExprParser::T__6); + match(ExprParser::T__3); break; } - case 6: { - _localctx = _tracker.createInstance(_localctx); + case 5: { + _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; setState(26); - match(ExprParser::IDENTIFIER); + match(ExprParser::T__7); setState(27); - match(ExprParser::T__5); + match(ExprParser::T__2); setState(28); expr(0); setState(29); - match(ExprParser::T__6); + match(ExprParser::T__3); break; } - case 7: { - _localctx = _tracker.createInstance(_localctx); + case 6: { + _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; setState(31); - match(ExprParser::IDENTIFIER); + match(ExprParser::T__7); setState(32); - match(ExprParser::LBRACKET); + match(ExprParser::T__2); setState(33); - shift(); + antlrcpp::downCast(_localctx)->from = shift(); + setState(34); + match(ExprParser::T__8); + setState(35); + antlrcpp::downCast(_localctx)->to = shift(); + setState(36); + match(ExprParser::T__9); + setState(37); + expr(0); setState(38); - _errHandler->sync(this); - _la = _input->LA(1); - while (_la == ExprParser::T__7) { - setState(34); - match(ExprParser::T__7); - setState(35); - shift(); - setState(40); - _errHandler->sync(this); - _la = _input->LA(1); - } - setState(41); - match(ExprParser::RBRACKET); + match(ExprParser::T__3); break; } - case 8: { - _localctx = _tracker.createInstance(_localctx); + case 7: { + _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; - setState(43); + setState(40); match(ExprParser::IDENTIFIER); - setState(44); - match(ExprParser::LBRACKET); - setState(45); + setState(41); + match(ExprParser::T__2); + setState(42); expr(0); - setState(50); - _errHandler->sync(this); - _la = _input->LA(1); - while (_la == ExprParser::T__7) { - setState(46); - match(ExprParser::T__7); - setState(47); - expr(0); - setState(52); - _errHandler->sync(this); - _la = _input->LA(1); - } - setState(53); - match(ExprParser::RBRACKET); + setState(43); + match(ExprParser::T__3); break; } - case 9: { - _localctx = _tracker.createInstance(_localctx); + case 8: { + _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; - setState(55); + setState(45); match(ExprParser::IDENTIFIER); - setState(56); - match(ExprParser::LBRACKET); - setState(57); - antlrcpp::downCast(_localctx)->shift1 = shift(); - setState(58); - match(ExprParser::T__8); - setState(59); - antlrcpp::downCast(_localctx)->shift2 = shift(); - setState(60); - match(ExprParser::RBRACKET); + setState(46); + match(ExprParser::T__10); + setState(47); + shift(); + setState(48); + match(ExprParser::T__11); break; } - case 10: { - _localctx = _tracker.createInstance(_localctx); + case 9: { + _localctx = _tracker.createInstance(_localctx); _ctx = _localctx; previousContext = _localctx; - setState(62); + setState(50); match(ExprParser::IDENTIFIER); - setState(63); - match(ExprParser::LBRACKET); - setState(64); - expr(0); - setState(65); - match(ExprParser::T__8); - setState(66); + setState(51); + match(ExprParser::T__10); + setState(52); expr(0); - setState(67); - match(ExprParser::RBRACKET); + setState(53); + match(ExprParser::T__11); break; } @@ -763,38 +601,38 @@ ExprParser::ExprContext* ExprParser::expr(int precedence) { break; } _ctx->stop = _input->LT(-1); - setState(82); + setState(68); _errHandler->sync(this); - alt = getInterpreter()->adaptivePredict(_input, 5, _ctx); + alt = getInterpreter()->adaptivePredict(_input, 2, _ctx); while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) { if (alt == 1) { if (!_parseListeners.empty()) triggerExitRuleEvent(); previousContext = _localctx; - setState(80); + setState(66); _errHandler->sync(this); - switch (getInterpreter()->adaptivePredict(_input, 4, _ctx)) { + switch (getInterpreter()->adaptivePredict(_input, 1, _ctx)) { case 1: { auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState)); _localctx = newContext; pushNewRecursionContext(newContext, startState, RuleExpr); - setState(71); + setState(57); - if (!(precpred(_ctx, 12))) throw FailedPredicateException(this, "precpred(_ctx, 12)"); - setState(72); + if (!(precpred(_ctx, 8))) throw FailedPredicateException(this, "precpred(_ctx, 8)"); + setState(58); antlrcpp::downCast(_localctx)->op = _input->LT(1); _la = _input->LA(1); - if (!(_la == ExprParser::T__2 + if (!(_la == ExprParser::T__4 - || _la == ExprParser::T__3)) { + || _la == ExprParser::T__5)) { antlrcpp::downCast(_localctx)->op = _errHandler->recoverInline(this); } else { _errHandler->reportMatch(this); consume(); } - setState(73); - expr(13); + setState(59); + expr(9); break; } @@ -802,23 +640,23 @@ ExprParser::ExprContext* ExprParser::expr(int precedence) { auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState)); _localctx = newContext; pushNewRecursionContext(newContext, startState, RuleExpr); - setState(74); + setState(60); - if (!(precpred(_ctx, 11))) throw FailedPredicateException(this, "precpred(_ctx, 11)"); - setState(75); + if (!(precpred(_ctx, 7))) throw FailedPredicateException(this, "precpred(_ctx, 7)"); + setState(61); antlrcpp::downCast(_localctx)->op = _input->LT(1); _la = _input->LA(1); - if (!(_la == ExprParser::T__0 + if (!(_la == ExprParser::T__1 - || _la == ExprParser::T__1)) { + || _la == ExprParser::T__6)) { antlrcpp::downCast(_localctx)->op = _errHandler->recoverInline(this); } else { _errHandler->reportMatch(this); consume(); } - setState(76); - expr(12); + setState(62); + expr(8); break; } @@ -826,13 +664,13 @@ ExprParser::ExprContext* ExprParser::expr(int precedence) { auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState)); _localctx = newContext; pushNewRecursionContext(newContext, startState, RuleExpr); - setState(77); + setState(63); - if (!(precpred(_ctx, 10))) throw FailedPredicateException(this, "precpred(_ctx, 10)"); - setState(78); + if (!(precpred(_ctx, 6))) throw FailedPredicateException(this, "precpred(_ctx, 6)"); + setState(64); match(ExprParser::COMPARISON); - setState(79); - expr(11); + setState(65); + expr(7); break; } @@ -840,9 +678,565 @@ ExprParser::ExprContext* ExprParser::expr(int precedence) { break; } } + setState(70); + _errHandler->sync(this); + alt = getInterpreter()->adaptivePredict(_input, 2, _ctx); + } + } + catch (RecognitionException &e) { + _errHandler->reportError(this, e); + _localctx->exception = std::current_exception(); + _errHandler->recover(this, _localctx->exception); + } + return _localctx; +} + +//----------------- AtomContext ------------------------------------------------------------------ + +ExprParser::AtomContext::AtomContext(ParserRuleContext *parent, size_t invokingState) + : ParserRuleContext(parent, invokingState) { +} + + +size_t ExprParser::AtomContext::getRuleIndex() const { + return ExprParser::RuleAtom; +} + +void ExprParser::AtomContext::copyFrom(AtomContext *ctx) { + ParserRuleContext::copyFrom(ctx); +} + +//----------------- NumberContext ------------------------------------------------------------------ + +tree::TerminalNode* ExprParser::NumberContext::NUMBER() { + return getToken(ExprParser::NUMBER, 0); +} + +ExprParser::NumberContext::NumberContext(AtomContext *ctx) { copyFrom(ctx); } + + +std::any ExprParser::NumberContext::accept(tree::ParseTreeVisitor *visitor) { + if (auto parserVisitor = dynamic_cast(visitor)) + return parserVisitor->visitNumber(this); + else + return visitor->visitChildren(this); +} +//----------------- IdentifierContext ------------------------------------------------------------------ + +tree::TerminalNode* ExprParser::IdentifierContext::IDENTIFIER() { + return getToken(ExprParser::IDENTIFIER, 0); +} + +ExprParser::IdentifierContext::IdentifierContext(AtomContext *ctx) { copyFrom(ctx); } + + +std::any ExprParser::IdentifierContext::accept(tree::ParseTreeVisitor *visitor) { + if (auto parserVisitor = dynamic_cast(visitor)) + return parserVisitor->visitIdentifier(this); + else + return visitor->visitChildren(this); +} +ExprParser::AtomContext* ExprParser::atom() { + AtomContext *_localctx = _tracker.createInstance(_ctx, getState()); + enterRule(_localctx, 4, ExprParser::RuleAtom); + +#if __cplusplus > 201703L + auto onExit = finally([=, this] { +#else + auto onExit = finally([=] { +#endif + exitRule(); + }); + try { + setState(73); + _errHandler->sync(this); + switch (_input->LA(1)) { + case ExprParser::NUMBER: { + _localctx = _tracker.createInstance(_localctx); + enterOuterAlt(_localctx, 1); + setState(71); + match(ExprParser::NUMBER); + break; + } + + case ExprParser::IDENTIFIER: { + _localctx = _tracker.createInstance(_localctx); + enterOuterAlt(_localctx, 2); + setState(72); + match(ExprParser::IDENTIFIER); + break; + } + + default: + throw NoViableAltException(this); + } + + } + catch (RecognitionException &e) { + _errHandler->reportError(this, e); + _localctx->exception = std::current_exception(); + _errHandler->recover(this, _localctx->exception); + } + + return _localctx; +} + +//----------------- ShiftContext ------------------------------------------------------------------ + +ExprParser::ShiftContext::ShiftContext(ParserRuleContext *parent, size_t invokingState) + : ParserRuleContext(parent, invokingState) { +} + +tree::TerminalNode* ExprParser::ShiftContext::TIME() { + return getToken(ExprParser::TIME, 0); +} + +ExprParser::Shift_exprContext* ExprParser::ShiftContext::shift_expr() { + return getRuleContext(0); +} + + +size_t ExprParser::ShiftContext::getRuleIndex() const { + return ExprParser::RuleShift; +} + + +std::any ExprParser::ShiftContext::accept(tree::ParseTreeVisitor *visitor) { + if (auto parserVisitor = dynamic_cast(visitor)) + return parserVisitor->visitShift(this); + else + return visitor->visitChildren(this); +} + +ExprParser::ShiftContext* ExprParser::shift() { + ShiftContext *_localctx = _tracker.createInstance(_ctx, getState()); + enterRule(_localctx, 6, ExprParser::RuleShift); + size_t _la = 0; + +#if __cplusplus > 201703L + auto onExit = finally([=, this] { +#else + auto onExit = finally([=] { +#endif + exitRule(); + }); + try { + enterOuterAlt(_localctx, 1); + setState(75); + match(ExprParser::TIME); + setState(77); + _errHandler->sync(this); + + _la = _input->LA(1); + if (_la == ExprParser::T__1 + + || _la == ExprParser::T__6) { + setState(76); + shift_expr(0); + } + + } + catch (RecognitionException &e) { + _errHandler->reportError(this, e); + _localctx->exception = std::current_exception(); + _errHandler->recover(this, _localctx->exception); + } + + return _localctx; +} + +//----------------- Shift_exprContext ------------------------------------------------------------------ + +ExprParser::Shift_exprContext::Shift_exprContext(ParserRuleContext *parent, size_t invokingState) + : ParserRuleContext(parent, invokingState) { +} + + +size_t ExprParser::Shift_exprContext::getRuleIndex() const { + return ExprParser::RuleShift_expr; +} + +void ExprParser::Shift_exprContext::copyFrom(Shift_exprContext *ctx) { + ParserRuleContext::copyFrom(ctx); +} + +//----------------- SignedAtomContext ------------------------------------------------------------------ + +ExprParser::AtomContext* ExprParser::SignedAtomContext::atom() { + return getRuleContext(0); +} + +ExprParser::SignedAtomContext::SignedAtomContext(Shift_exprContext *ctx) { copyFrom(ctx); } + + +std::any ExprParser::SignedAtomContext::accept(tree::ParseTreeVisitor *visitor) { + if (auto parserVisitor = dynamic_cast(visitor)) + return parserVisitor->visitSignedAtom(this); + else + return visitor->visitChildren(this); +} +//----------------- SignedExpressionContext ------------------------------------------------------------------ + +ExprParser::ExprContext* ExprParser::SignedExpressionContext::expr() { + return getRuleContext(0); +} + +ExprParser::SignedExpressionContext::SignedExpressionContext(Shift_exprContext *ctx) { copyFrom(ctx); } + + +std::any ExprParser::SignedExpressionContext::accept(tree::ParseTreeVisitor *visitor) { + if (auto parserVisitor = dynamic_cast(visitor)) + return parserVisitor->visitSignedExpression(this); + else + return visitor->visitChildren(this); +} +//----------------- ShiftMuldivContext ------------------------------------------------------------------ + +ExprParser::Shift_exprContext* ExprParser::ShiftMuldivContext::shift_expr() { + return getRuleContext(0); +} + +ExprParser::Right_exprContext* ExprParser::ShiftMuldivContext::right_expr() { + return getRuleContext(0); +} + +ExprParser::ShiftMuldivContext::ShiftMuldivContext(Shift_exprContext *ctx) { copyFrom(ctx); } + + +std::any ExprParser::ShiftMuldivContext::accept(tree::ParseTreeVisitor *visitor) { + if (auto parserVisitor = dynamic_cast(visitor)) + return parserVisitor->visitShiftMuldiv(this); + else + return visitor->visitChildren(this); +} +//----------------- ShiftAddsubContext ------------------------------------------------------------------ + +ExprParser::Shift_exprContext* ExprParser::ShiftAddsubContext::shift_expr() { + return getRuleContext(0); +} + +ExprParser::Right_exprContext* ExprParser::ShiftAddsubContext::right_expr() { + return getRuleContext(0); +} + +ExprParser::ShiftAddsubContext::ShiftAddsubContext(Shift_exprContext *ctx) { copyFrom(ctx); } + + +std::any ExprParser::ShiftAddsubContext::accept(tree::ParseTreeVisitor *visitor) { + if (auto parserVisitor = dynamic_cast(visitor)) + return parserVisitor->visitShiftAddsub(this); + else + return visitor->visitChildren(this); +} + +ExprParser::Shift_exprContext* ExprParser::shift_expr() { + return shift_expr(0); +} + +ExprParser::Shift_exprContext* ExprParser::shift_expr(int precedence) { + ParserRuleContext *parentContext = _ctx; + size_t parentState = getState(); + ExprParser::Shift_exprContext *_localctx = _tracker.createInstance(_ctx, parentState); + ExprParser::Shift_exprContext *previousContext = _localctx; + (void)previousContext; // Silence compiler, in case the context is not used by generated code. + size_t startState = 8; + enterRecursionRule(_localctx, 8, ExprParser::RuleShift_expr, precedence); + + size_t _la = 0; + +#if __cplusplus > 201703L + auto onExit = finally([=, this] { +#else + auto onExit = finally([=] { +#endif + unrollRecursionContexts(parentContext); + }); + try { + size_t alt; + enterOuterAlt(_localctx, 1); + setState(87); + _errHandler->sync(this); + switch (getInterpreter()->adaptivePredict(_input, 5, _ctx)) { + case 1: { + _localctx = _tracker.createInstance(_localctx); + _ctx = _localctx; + previousContext = _localctx; + + setState(80); + antlrcpp::downCast(_localctx)->op = _input->LT(1); + _la = _input->LA(1); + if (!(_la == ExprParser::T__1 + + || _la == ExprParser::T__6)) { + antlrcpp::downCast(_localctx)->op = _errHandler->recoverInline(this); + } + else { + _errHandler->reportMatch(this); + consume(); + } + setState(81); + atom(); + break; + } + + case 2: { + _localctx = _tracker.createInstance(_localctx); + _ctx = _localctx; + previousContext = _localctx; + setState(82); + antlrcpp::downCast(_localctx)->op = _input->LT(1); + _la = _input->LA(1); + if (!(_la == ExprParser::T__1 + + || _la == ExprParser::T__6)) { + antlrcpp::downCast(_localctx)->op = _errHandler->recoverInline(this); + } + else { + _errHandler->reportMatch(this); + consume(); + } + setState(83); + match(ExprParser::T__2); setState(84); + expr(0); + setState(85); + match(ExprParser::T__3); + break; + } + + default: + break; + } + _ctx->stop = _input->LT(-1); + setState(97); + _errHandler->sync(this); + alt = getInterpreter()->adaptivePredict(_input, 7, _ctx); + while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) { + if (alt == 1) { + if (!_parseListeners.empty()) + triggerExitRuleEvent(); + previousContext = _localctx; + setState(95); + _errHandler->sync(this); + switch (getInterpreter()->adaptivePredict(_input, 6, _ctx)) { + case 1: { + auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState)); + _localctx = newContext; + pushNewRecursionContext(newContext, startState, RuleShift_expr); + setState(89); + + if (!(precpred(_ctx, 4))) throw FailedPredicateException(this, "precpred(_ctx, 4)"); + setState(90); + antlrcpp::downCast(_localctx)->op = _input->LT(1); + _la = _input->LA(1); + if (!(_la == ExprParser::T__4 + + || _la == ExprParser::T__5)) { + antlrcpp::downCast(_localctx)->op = _errHandler->recoverInline(this); + } + else { + _errHandler->reportMatch(this); + consume(); + } + setState(91); + right_expr(0); + break; + } + + case 2: { + auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState)); + _localctx = newContext; + pushNewRecursionContext(newContext, startState, RuleShift_expr); + setState(92); + + if (!(precpred(_ctx, 3))) throw FailedPredicateException(this, "precpred(_ctx, 3)"); + setState(93); + antlrcpp::downCast(_localctx)->op = _input->LT(1); + _la = _input->LA(1); + if (!(_la == ExprParser::T__1 + + || _la == ExprParser::T__6)) { + antlrcpp::downCast(_localctx)->op = _errHandler->recoverInline(this); + } + else { + _errHandler->reportMatch(this); + consume(); + } + setState(94); + right_expr(0); + break; + } + + default: + break; + } + } + setState(99); _errHandler->sync(this); - alt = getInterpreter()->adaptivePredict(_input, 5, _ctx); + alt = getInterpreter()->adaptivePredict(_input, 7, _ctx); + } + } + catch (RecognitionException &e) { + _errHandler->reportError(this, e); + _localctx->exception = std::current_exception(); + _errHandler->recover(this, _localctx->exception); + } + return _localctx; +} + +//----------------- Right_exprContext ------------------------------------------------------------------ + +ExprParser::Right_exprContext::Right_exprContext(ParserRuleContext *parent, size_t invokingState) + : ParserRuleContext(parent, invokingState) { +} + + +size_t ExprParser::Right_exprContext::getRuleIndex() const { + return ExprParser::RuleRight_expr; +} + +void ExprParser::Right_exprContext::copyFrom(Right_exprContext *ctx) { + ParserRuleContext::copyFrom(ctx); +} + +//----------------- RightExpressionContext ------------------------------------------------------------------ + +ExprParser::ExprContext* ExprParser::RightExpressionContext::expr() { + return getRuleContext(0); +} + +ExprParser::RightExpressionContext::RightExpressionContext(Right_exprContext *ctx) { copyFrom(ctx); } + + +std::any ExprParser::RightExpressionContext::accept(tree::ParseTreeVisitor *visitor) { + if (auto parserVisitor = dynamic_cast(visitor)) + return parserVisitor->visitRightExpression(this); + else + return visitor->visitChildren(this); +} +//----------------- RightMuldivContext ------------------------------------------------------------------ + +std::vector ExprParser::RightMuldivContext::right_expr() { + return getRuleContexts(); +} + +ExprParser::Right_exprContext* ExprParser::RightMuldivContext::right_expr(size_t i) { + return getRuleContext(i); +} + +ExprParser::RightMuldivContext::RightMuldivContext(Right_exprContext *ctx) { copyFrom(ctx); } + + +std::any ExprParser::RightMuldivContext::accept(tree::ParseTreeVisitor *visitor) { + if (auto parserVisitor = dynamic_cast(visitor)) + return parserVisitor->visitRightMuldiv(this); + else + return visitor->visitChildren(this); +} +//----------------- RightAtomContext ------------------------------------------------------------------ + +ExprParser::AtomContext* ExprParser::RightAtomContext::atom() { + return getRuleContext(0); +} + +ExprParser::RightAtomContext::RightAtomContext(Right_exprContext *ctx) { copyFrom(ctx); } + + +std::any ExprParser::RightAtomContext::accept(tree::ParseTreeVisitor *visitor) { + if (auto parserVisitor = dynamic_cast(visitor)) + return parserVisitor->visitRightAtom(this); + else + return visitor->visitChildren(this); +} + +ExprParser::Right_exprContext* ExprParser::right_expr() { + return right_expr(0); +} + +ExprParser::Right_exprContext* ExprParser::right_expr(int precedence) { + ParserRuleContext *parentContext = _ctx; + size_t parentState = getState(); + ExprParser::Right_exprContext *_localctx = _tracker.createInstance(_ctx, parentState); + ExprParser::Right_exprContext *previousContext = _localctx; + (void)previousContext; // Silence compiler, in case the context is not used by generated code. + size_t startState = 10; + enterRecursionRule(_localctx, 10, ExprParser::RuleRight_expr, precedence); + + size_t _la = 0; + +#if __cplusplus > 201703L + auto onExit = finally([=, this] { +#else + auto onExit = finally([=] { +#endif + unrollRecursionContexts(parentContext); + }); + try { + size_t alt; + enterOuterAlt(_localctx, 1); + setState(106); + _errHandler->sync(this); + switch (_input->LA(1)) { + case ExprParser::T__2: { + _localctx = _tracker.createInstance(_localctx); + _ctx = _localctx; + previousContext = _localctx; + + setState(101); + match(ExprParser::T__2); + setState(102); + expr(0); + setState(103); + match(ExprParser::T__3); + break; + } + + case ExprParser::NUMBER: + case ExprParser::IDENTIFIER: { + _localctx = _tracker.createInstance(_localctx); + _ctx = _localctx; + previousContext = _localctx; + setState(105); + atom(); + break; + } + + default: + throw NoViableAltException(this); + } + _ctx->stop = _input->LT(-1); + setState(113); + _errHandler->sync(this); + alt = getInterpreter()->adaptivePredict(_input, 9, _ctx); + while (alt != 2 && alt != atn::ATN::INVALID_ALT_NUMBER) { + if (alt == 1) { + if (!_parseListeners.empty()) + triggerExitRuleEvent(); + previousContext = _localctx; + auto newContext = _tracker.createInstance(_tracker.createInstance(parentContext, parentState)); + _localctx = newContext; + pushNewRecursionContext(newContext, startState, RuleRight_expr); + setState(108); + + if (!(precpred(_ctx, 3))) throw FailedPredicateException(this, "precpred(_ctx, 3)"); + setState(109); + antlrcpp::downCast(_localctx)->op = _input->LT(1); + _la = _input->LA(1); + if (!(_la == ExprParser::T__4 + + || _la == ExprParser::T__5)) { + antlrcpp::downCast(_localctx)->op = _errHandler->recoverInline(this); + } + else { + _errHandler->reportMatch(this); + consume(); + } + setState(110); + right_expr(4); + } + setState(115); + _errHandler->sync(this); + alt = getInterpreter()->adaptivePredict(_input, 9, _ctx); } } catch (RecognitionException &e) { @@ -855,7 +1249,9 @@ ExprParser::ExprContext* ExprParser::expr(int precedence) { bool ExprParser::sempred(RuleContext *context, size_t ruleIndex, size_t predicateIndex) { switch (ruleIndex) { - case 2: return exprSempred(antlrcpp::downCast(context), predicateIndex); + case 1: return exprSempred(antlrcpp::downCast(context), predicateIndex); + case 4: return shift_exprSempred(antlrcpp::downCast(context), predicateIndex); + case 5: return right_exprSempred(antlrcpp::downCast(context), predicateIndex); default: break; @@ -865,9 +1261,30 @@ bool ExprParser::sempred(RuleContext *context, size_t ruleIndex, size_t predicat bool ExprParser::exprSempred(ExprContext *_localctx, size_t predicateIndex) { switch (predicateIndex) { - case 0: return precpred(_ctx, 12); - case 1: return precpred(_ctx, 11); - case 2: return precpred(_ctx, 10); + case 0: return precpred(_ctx, 8); + case 1: return precpred(_ctx, 7); + case 2: return precpred(_ctx, 6); + + default: + break; + } + return true; +} + +bool ExprParser::shift_exprSempred(Shift_exprContext *_localctx, size_t predicateIndex) { + switch (predicateIndex) { + case 3: return precpred(_ctx, 4); + case 4: return precpred(_ctx, 3); + + default: + break; + } + return true; +} + +bool ExprParser::right_exprSempred(Right_exprContext *_localctx, size_t predicateIndex) { + switch (predicateIndex) { + case 5: return precpred(_ctx, 3); default: break; diff --git a/src/libs/antares/antlr-interface/ExprParser.h b/src/libs/antares/antlr-interface/ExprParser.h index aa1c8b6f09..4d7f02fd16 100644 --- a/src/libs/antares/antlr-interface/ExprParser.h +++ b/src/libs/antares/antlr-interface/ExprParser.h @@ -1,5 +1,5 @@ -// Generated from Expr.g4 by ANTLR 4.13.1 +// Generated from Expr.g4 by ANTLR 4.13.2 #pragma once @@ -13,12 +13,13 @@ class ExprParser : public antlr4::Parser { public: enum { T__0 = 1, T__1 = 2, T__2 = 3, T__3 = 4, T__4 = 5, T__5 = 6, T__6 = 7, - T__7 = 8, T__8 = 9, NUMBER = 10, TIME = 11, IDENTIFIER = 12, COMPARISON = 13, - ADDSUB = 14, MULDIV = 15, LBRACKET = 16, RBRACKET = 17, WS = 18 + T__7 = 8, T__8 = 9, T__9 = 10, T__10 = 11, T__11 = 12, NUMBER = 13, + TIME = 14, IDENTIFIER = 15, COMPARISON = 16, WS = 17 }; enum { - RuleFullexpr = 0, RuleShift = 1, RuleExpr = 2 + RuleFullexpr = 0, RuleExpr = 1, RuleAtom = 2, RuleShift = 3, RuleShift_expr = 4, + RuleRight_expr = 5 }; explicit ExprParser(antlr4::TokenStream *input); @@ -39,8 +40,11 @@ class ExprParser : public antlr4::Parser { class FullexprContext; + class ExprContext; + class AtomContext; class ShiftContext; - class ExprContext; + class Shift_exprContext; + class Right_exprContext; class FullexprContext : public antlr4::ParserRuleContext { public: @@ -56,21 +60,6 @@ class ExprParser : public antlr4::Parser { FullexprContext* fullexpr(); - class ShiftContext : public antlr4::ParserRuleContext { - public: - antlr4::Token *op = nullptr; - ShiftContext(antlr4::ParserRuleContext *parent, size_t invokingState); - virtual size_t getRuleIndex() const override; - antlr4::tree::TerminalNode *TIME(); - ExprContext *expr(); - - - virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; - - }; - - ShiftContext* shift(); - class ExprContext : public antlr4::ParserRuleContext { public: ExprContext(antlr4::ParserRuleContext *parent, size_t invokingState); @@ -84,11 +73,15 @@ class ExprParser : public antlr4::Parser { }; - class IdentifierContext : public ExprContext { + class TimeSumContext : public ExprContext { public: - IdentifierContext(ExprContext *ctx); + TimeSumContext(ExprContext *ctx); - antlr4::tree::TerminalNode *IDENTIFIER(); + ExprParser::ShiftContext *from = nullptr; + ExprParser::ShiftContext *to = nullptr; + ExprContext *expr(); + std::vector shift(); + ShiftContext* shift(size_t i); virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; }; @@ -102,6 +95,15 @@ class ExprParser : public antlr4::Parser { virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; }; + class UnsignedAtomContext : public ExprContext { + public: + UnsignedAtomContext(ExprContext *ctx); + + AtomContext *atom(); + + virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; + }; + class ExpressionContext : public ExprContext { public: ExpressionContext(ExprContext *ctx); @@ -111,6 +113,16 @@ class ExprParser : public antlr4::Parser { virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; }; + class TimeIndexContext : public ExprContext { + public: + TimeIndexContext(ExprContext *ctx); + + antlr4::tree::TerminalNode *IDENTIFIER(); + ExprContext *expr(); + + virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; + }; + class ComparisonContext : public ExprContext { public: ComparisonContext(ExprContext *ctx); @@ -122,6 +134,35 @@ class ExprParser : public antlr4::Parser { virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; }; + class AllTimeSumContext : public ExprContext { + public: + AllTimeSumContext(ExprContext *ctx); + + ExprContext *expr(); + + virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; + }; + + class TimeShiftContext : public ExprContext { + public: + TimeShiftContext(ExprContext *ctx); + + antlr4::tree::TerminalNode *IDENTIFIER(); + ShiftContext *shift(); + + virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; + }; + + class FunctionContext : public ExprContext { + public: + FunctionContext(ExprContext *ctx); + + antlr4::tree::TerminalNode *IDENTIFIER(); + ExprContext *expr(); + + virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; + }; + class AddsubContext : public ExprContext { public: AddsubContext(ExprContext *ctx); @@ -154,85 +195,162 @@ class ExprParser : public antlr4::Parser { virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; }; - class NumberContext : public ExprContext { + ExprContext* expr(); + ExprContext* expr(int precedence); + class AtomContext : public antlr4::ParserRuleContext { + public: + AtomContext(antlr4::ParserRuleContext *parent, size_t invokingState); + + AtomContext() = default; + void copyFrom(AtomContext *context); + using antlr4::ParserRuleContext::copyFrom; + + virtual size_t getRuleIndex() const override; + + + }; + + class NumberContext : public AtomContext { public: - NumberContext(ExprContext *ctx); + NumberContext(AtomContext *ctx); antlr4::tree::TerminalNode *NUMBER(); virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; }; - class TimeIndexContext : public ExprContext { + class IdentifierContext : public AtomContext { public: - TimeIndexContext(ExprContext *ctx); + IdentifierContext(AtomContext *ctx); antlr4::tree::TerminalNode *IDENTIFIER(); - antlr4::tree::TerminalNode *LBRACKET(); - std::vector expr(); - ExprContext* expr(size_t i); - antlr4::tree::TerminalNode *RBRACKET(); virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; }; - class TimeShiftContext : public ExprContext { + AtomContext* atom(); + + class ShiftContext : public antlr4::ParserRuleContext { public: - TimeShiftContext(ExprContext *ctx); + ShiftContext(antlr4::ParserRuleContext *parent, size_t invokingState); + virtual size_t getRuleIndex() const override; + antlr4::tree::TerminalNode *TIME(); + Shift_exprContext *shift_expr(); - antlr4::tree::TerminalNode *IDENTIFIER(); - antlr4::tree::TerminalNode *LBRACKET(); - std::vector shift(); - ShiftContext* shift(size_t i); - antlr4::tree::TerminalNode *RBRACKET(); virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; + }; - class FunctionContext : public ExprContext { + ShiftContext* shift(); + + class Shift_exprContext : public antlr4::ParserRuleContext { public: - FunctionContext(ExprContext *ctx); + Shift_exprContext(antlr4::ParserRuleContext *parent, size_t invokingState); + + Shift_exprContext() = default; + void copyFrom(Shift_exprContext *context); + using antlr4::ParserRuleContext::copyFrom; - antlr4::tree::TerminalNode *IDENTIFIER(); + virtual size_t getRuleIndex() const override; + + + }; + + class SignedAtomContext : public Shift_exprContext { + public: + SignedAtomContext(Shift_exprContext *ctx); + + antlr4::Token *op = nullptr; + AtomContext *atom(); + + virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; + }; + + class SignedExpressionContext : public Shift_exprContext { + public: + SignedExpressionContext(Shift_exprContext *ctx); + + antlr4::Token *op = nullptr; ExprContext *expr(); virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; }; - class TimeShiftRangeContext : public ExprContext { + class ShiftMuldivContext : public Shift_exprContext { public: - TimeShiftRangeContext(ExprContext *ctx); + ShiftMuldivContext(Shift_exprContext *ctx); - ExprParser::ShiftContext *shift1 = nullptr; - ExprParser::ShiftContext *shift2 = nullptr; - antlr4::tree::TerminalNode *IDENTIFIER(); - antlr4::tree::TerminalNode *LBRACKET(); - antlr4::tree::TerminalNode *RBRACKET(); - std::vector shift(); - ShiftContext* shift(size_t i); + antlr4::Token *op = nullptr; + Shift_exprContext *shift_expr(); + Right_exprContext *right_expr(); virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; }; - class TimeRangeContext : public ExprContext { + class ShiftAddsubContext : public Shift_exprContext { public: - TimeRangeContext(ExprContext *ctx); + ShiftAddsubContext(Shift_exprContext *ctx); - antlr4::tree::TerminalNode *IDENTIFIER(); - antlr4::tree::TerminalNode *LBRACKET(); - std::vector expr(); - ExprContext* expr(size_t i); - antlr4::tree::TerminalNode *RBRACKET(); + antlr4::Token *op = nullptr; + Shift_exprContext *shift_expr(); + Right_exprContext *right_expr(); virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; }; - ExprContext* expr(); - ExprContext* expr(int precedence); + Shift_exprContext* shift_expr(); + Shift_exprContext* shift_expr(int precedence); + class Right_exprContext : public antlr4::ParserRuleContext { + public: + Right_exprContext(antlr4::ParserRuleContext *parent, size_t invokingState); + + Right_exprContext() = default; + void copyFrom(Right_exprContext *context); + using antlr4::ParserRuleContext::copyFrom; + + virtual size_t getRuleIndex() const override; + + + }; + + class RightExpressionContext : public Right_exprContext { + public: + RightExpressionContext(Right_exprContext *ctx); + + ExprContext *expr(); + + virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; + }; + + class RightMuldivContext : public Right_exprContext { + public: + RightMuldivContext(Right_exprContext *ctx); + + antlr4::Token *op = nullptr; + std::vector right_expr(); + Right_exprContext* right_expr(size_t i); + + virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; + }; + + class RightAtomContext : public Right_exprContext { + public: + RightAtomContext(Right_exprContext *ctx); + + AtomContext *atom(); + + virtual std::any accept(antlr4::tree::ParseTreeVisitor *visitor) override; + }; + + Right_exprContext* right_expr(); + Right_exprContext* right_expr(int precedence); bool sempred(antlr4::RuleContext *_localctx, size_t ruleIndex, size_t predicateIndex) override; bool exprSempred(ExprContext *_localctx, size_t predicateIndex); + bool shift_exprSempred(Shift_exprContext *_localctx, size_t predicateIndex); + bool right_exprSempred(Right_exprContext *_localctx, size_t predicateIndex); // By default the static state used to implement the parser is lazily initialized during the first // call to the constructor. You can call this function if you wish to initialize the static state diff --git a/src/libs/antares/antlr-interface/ExprVisitor.cpp b/src/libs/antares/antlr-interface/ExprVisitor.cpp index c214f0f76f..0cdeed41d9 100644 --- a/src/libs/antares/antlr-interface/ExprVisitor.cpp +++ b/src/libs/antares/antlr-interface/ExprVisitor.cpp @@ -1,5 +1,5 @@ -// Generated from Expr.g4 by ANTLR 4.13.1 +// Generated from Expr.g4 by ANTLR 4.13.2 #include "ExprVisitor.h" diff --git a/src/libs/antares/antlr-interface/ExprVisitor.h b/src/libs/antares/antlr-interface/ExprVisitor.h index c064d6d54a..e92c3e3402 100644 --- a/src/libs/antares/antlr-interface/ExprVisitor.h +++ b/src/libs/antares/antlr-interface/ExprVisitor.h @@ -1,5 +1,5 @@ -// Generated from Expr.g4 by ANTLR 4.13.1 +// Generated from Expr.g4 by ANTLR 4.13.2 #pragma once @@ -21,16 +21,24 @@ class ExprVisitor : public antlr4::tree::AbstractParseTreeVisitor { */ virtual std::any visitFullexpr(ExprParser::FullexprContext *context) = 0; - virtual std::any visitShift(ExprParser::ShiftContext *context) = 0; - - virtual std::any visitIdentifier(ExprParser::IdentifierContext *context) = 0; + virtual std::any visitTimeSum(ExprParser::TimeSumContext *context) = 0; virtual std::any visitNegation(ExprParser::NegationContext *context) = 0; + virtual std::any visitUnsignedAtom(ExprParser::UnsignedAtomContext *context) = 0; + virtual std::any visitExpression(ExprParser::ExpressionContext *context) = 0; + virtual std::any visitTimeIndex(ExprParser::TimeIndexContext *context) = 0; + virtual std::any visitComparison(ExprParser::ComparisonContext *context) = 0; + virtual std::any visitAllTimeSum(ExprParser::AllTimeSumContext *context) = 0; + + virtual std::any visitTimeShift(ExprParser::TimeShiftContext *context) = 0; + + virtual std::any visitFunction(ExprParser::FunctionContext *context) = 0; + virtual std::any visitAddsub(ExprParser::AddsubContext *context) = 0; virtual std::any visitPortField(ExprParser::PortFieldContext *context) = 0; @@ -39,15 +47,23 @@ class ExprVisitor : public antlr4::tree::AbstractParseTreeVisitor { virtual std::any visitNumber(ExprParser::NumberContext *context) = 0; - virtual std::any visitTimeIndex(ExprParser::TimeIndexContext *context) = 0; + virtual std::any visitIdentifier(ExprParser::IdentifierContext *context) = 0; - virtual std::any visitTimeShift(ExprParser::TimeShiftContext *context) = 0; + virtual std::any visitShift(ExprParser::ShiftContext *context) = 0; - virtual std::any visitFunction(ExprParser::FunctionContext *context) = 0; + virtual std::any visitSignedAtom(ExprParser::SignedAtomContext *context) = 0; + + virtual std::any visitSignedExpression(ExprParser::SignedExpressionContext *context) = 0; + + virtual std::any visitShiftMuldiv(ExprParser::ShiftMuldivContext *context) = 0; + + virtual std::any visitShiftAddsub(ExprParser::ShiftAddsubContext *context) = 0; + + virtual std::any visitRightExpression(ExprParser::RightExpressionContext *context) = 0; - virtual std::any visitTimeShiftRange(ExprParser::TimeShiftRangeContext *context) = 0; + virtual std::any visitRightMuldiv(ExprParser::RightMuldivContext *context) = 0; - virtual std::any visitTimeRange(ExprParser::TimeRangeContext *context) = 0; + virtual std::any visitRightAtom(ExprParser::RightAtomContext *context) = 0; }; diff --git a/src/solver/expressions/CMakeLists.txt b/src/solver/expressions/CMakeLists.txt index 5f30a6779d..58643f6529 100644 --- a/src/solver/expressions/CMakeLists.txt +++ b/src/solver/expressions/CMakeLists.txt @@ -21,9 +21,12 @@ set(SRC_Expressions visitors/PortFieldSumSubstitutionVisitor.cpp visitors/AstDOTStyleVisitor.cpp visitors/InvalidNode.cpp + visitors/NodeVisitor.cpp hashable.cpp + NodeRegistry.cpp + include/antares/solver/expressions/NodeRegistry.h include/antares/solver/expressions/nodes/SumNode.h include/antares/solver/expressions/nodes/BinaryNode.h include/antares/solver/expressions/nodes/ComparisonNode.h @@ -78,8 +81,8 @@ target_include_directories(solver-expressions ) target_link_libraries(solver-expressions PUBLIC - Antares::logs Boost::headers + Antares::logs ) diff --git a/src/solver/expressions/NodeRegistry.cpp b/src/solver/expressions/NodeRegistry.cpp new file mode 100644 index 0000000000..0fdbdea819 --- /dev/null +++ b/src/solver/expressions/NodeRegistry.cpp @@ -0,0 +1,14 @@ +#include +#include +#include + +namespace Antares::Solver +{ +NodeRegistry::NodeRegistry(Antares::Solver::Nodes::Node* node, + Antares::Solver::Registry registry): + node(node), + registry(std::move(registry)) +{ +} + +} // namespace Antares::Solver diff --git a/src/solver/expressions/include/antares/solver/expressions/NodeRegistry.h b/src/solver/expressions/include/antares/solver/expressions/NodeRegistry.h new file mode 100644 index 0000000000..994b8f6886 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/NodeRegistry.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +namespace Antares::Solver +{ +class NodeRegistry +{ +public: + NodeRegistry() = default; + NodeRegistry(Antares::Solver::Nodes::Node* node, + Antares::Solver::Registry registry); + + // Shallow copy + NodeRegistry(NodeRegistry&&) = default; + NodeRegistry& operator=(NodeRegistry&&) = default; + + Antares::Solver::Nodes::Node* node; + Antares::Solver::Registry registry; +}; +} // namespace Antares::Solver diff --git a/src/solver/expressions/include/antares/solver/expressions/Registry.hxx b/src/solver/expressions/include/antares/solver/expressions/Registry.hxx index 2ccc9ff8fd..ba74974cb0 100644 --- a/src/solver/expressions/include/antares/solver/expressions/Registry.hxx +++ b/src/solver/expressions/include/antares/solver/expressions/Registry.hxx @@ -32,14 +32,16 @@ template class Registry { public: + Registry() = default; + Registry(Registry&&) = default; + Registry& operator=(Registry&&) = default; + // Method to create a new derived class object and add it to the registry template requires std::derived_from Derived* create(Args&&... args) { auto created = std::make_unique(std::forward(args)...); - - std::lock_guard lock(mutex_); registry_.push_back(std::move(created)); return dynamic_cast( registry_.back().get()); // Return the pointer to the newly created object @@ -48,6 +50,5 @@ public: private: std::vector> registry_; // Registry to manage dynamically allocated objects - std::mutex mutex_; }; } // namespace Antares::Solver diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h index a8e4e1ff43..f2a0240e69 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/AstDOTStyleVisitor.h @@ -20,6 +20,7 @@ */ #pragma once +#include #include #include @@ -116,7 +117,7 @@ class AstDOTStyleVisitor: public NodeVisitor * @param os The output stream to which the DOT representation is written. * @param root The root of the expression to be output. */ - void operator()(std::ostream& os, Nodes::Node* root); + void operator()(std::ostream& os, const Nodes::Node* root); private: void visit(const Nodes::SumNode* node, std::ostream& os) override; diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h index 9b88019376..3681224ee6 100644 --- a/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h @@ -19,11 +19,11 @@ ** along with Antares_Simulator. If not, see . */ #pragma once +#include #include #include #include -#include #include #include #include @@ -31,6 +31,19 @@ namespace Antares::Solver::Visitors { +// we use LogSink because the inclusion of somehow results in the +// inclusion of (very bad idea in a header!) which conflict with antlr4 headers (defines +// in the former become enums in the latter etc...) +struct LogSink +{ + using LogFunction = std::function; + + LogFunction info; + LogFunction warning; + LogFunction error; +}; + +LogSink RedirectToAntaresLogs(); template RetT tryVisit(const Nodes::Node* node, VisitorT& visitor, Args... args) @@ -119,7 +132,7 @@ class NodeVisitor: public IName } catch (std::exception&) { - logs.error() << "Antares::Solver::Visitor: could not visit the node!"; + log_.error("Antares::Solver::Visitor: could not visit the node!"); throw; } } @@ -269,5 +282,11 @@ class NodeVisitor: public IName * @return The result of processing the ComponentParameterNode. */ virtual R visit(const Nodes::ComponentParameterNode*, Args... args) = 0; + +private: + // we use LogSink because the inclusion of somehow results in the + // inclusion of (very bad idea in a header!) which conflict with antlr4 headers + // (defines in the former become enums in the latter etc...) + LogSink log_ = RedirectToAntaresLogs(); }; } // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp index fb74a129df..2538ec1360 100644 --- a/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp +++ b/src/solver/expressions/visitors/AstDOTStyleVisitor.cpp @@ -258,7 +258,7 @@ void AstDOTStyleVisitor::EndTreeGraph(std::ostream& os) nbNodesPerType_.clear(); } -void AstDOTStyleVisitor::operator()(std::ostream& os, Nodes::Node* root) +void AstDOTStyleVisitor::operator()(std::ostream& os, const Nodes::Node* root) { NewTreeGraph(os); dispatch(root, os); diff --git a/src/solver/expressions/visitors/EvalVisitor.cpp b/src/solver/expressions/visitors/EvalVisitor.cpp index 4d0b45e119..aa89bd5cc9 100644 --- a/src/solver/expressions/visitors/EvalVisitor.cpp +++ b/src/solver/expressions/visitors/EvalVisitor.cpp @@ -21,6 +21,7 @@ #include "antares/solver/expressions/visitors/EvalVisitor.h" +#include #include #include diff --git a/src/solver/expressions/visitors/NodeVisitor.cpp b/src/solver/expressions/visitors/NodeVisitor.cpp new file mode 100644 index 0000000000..6499f72328 --- /dev/null +++ b/src/solver/expressions/visitors/NodeVisitor.cpp @@ -0,0 +1,46 @@ +/* +** 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 +#include + +namespace Antares::Solver::Visitors +{ +static void ToYuniInfo(const std::string& msg) +{ + logs.info() << msg; +} + +static void ToYuniWarning(const std::string& msg) +{ + logs.warning() << msg; +} + +static void ToYuniError(const std::string& msg) +{ + logs.error() << msg; +} + +LogSink RedirectToAntaresLogs() +{ + return {.info = ToYuniInfo, .warning = ToYuniWarning, .error = ToYuniError}; +} +} // namespace Antares::Solver::Visitors diff --git a/src/solver/modelConverter/CMakeLists.txt b/src/solver/modelConverter/CMakeLists.txt index 86c97eb569..005a47e55d 100644 --- a/src/solver/modelConverter/CMakeLists.txt +++ b/src/solver/modelConverter/CMakeLists.txt @@ -1,6 +1,8 @@ set(SOURCES modelConverter.cpp + convertorVisitor.cpp include/antares/solver/modelConverter/modelConverter.h + include/antares/solver/modelConverter/convertorVisitor.h ) # Create the library @@ -18,8 +20,10 @@ target_link_libraries(modelConverter PRIVATE Antares::antares-study-system-model Antares::modelParser + Antares::antlr-interface + Antares::solver-expressions ) install(DIRECTORY include/antares DESTINATION "include" -) \ No newline at end of file +) diff --git a/src/solver/modelConverter/convertorVisitor.cpp b/src/solver/modelConverter/convertorVisitor.cpp new file mode 100644 index 0000000000..6a9267f142 --- /dev/null +++ b/src/solver/modelConverter/convertorVisitor.cpp @@ -0,0 +1,297 @@ +/* + * 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 +#include + +#include "ExprLexer.h" +#include "ExprParser.h" +#include "antlr4-runtime.h" + +namespace Antares::Solver::ModelConverter +{ + +using namespace Antares::Solver::Nodes; + +/// Visitor to convert ANTLR expressions to Antares::Solver::Nodes +class ConvertorVisitor: public ExprVisitor +{ +public: + ConvertorVisitor(Registry& registry, const ModelParser::Model& model); + + std::any visit(antlr4::tree::ParseTree* tree) override; + + std::any visitIdentifier(ExprParser::IdentifierContext* context) override; + std::any visitMuldiv(ExprParser::MuldivContext* context) override; + std::any visitFullexpr(ExprParser::FullexprContext* context) override; + std::any visitShift(ExprParser::ShiftContext* context) override; + std::any visitNegation(ExprParser::NegationContext* context) override; + std::any visitExpression(ExprParser::ExpressionContext* context) override; + std::any visitComparison(ExprParser::ComparisonContext* context) override; + std::any visitAddsub(ExprParser::AddsubContext* context) override; + std::any visitPortField(ExprParser::PortFieldContext* context) override; + std::any visitNumber(ExprParser::NumberContext* context) override; + std::any visitTimeIndex(ExprParser::TimeIndexContext* context) override; + std::any visitTimeShift(ExprParser::TimeShiftContext* context) override; + std::any visitFunction(ExprParser::FunctionContext* context) override; + + std::any visitTimeSum(ExprParser::TimeSumContext* context) override; + std::any visitAllTimeSum(ExprParser::AllTimeSumContext* context) override; + std::any visitSignedAtom(ExprParser::SignedAtomContext* context) override; + std::any visitUnsignedAtom(ExprParser::UnsignedAtomContext* context) override; + std::any visitRightAtom(ExprParser::RightAtomContext* context) override; + std::any visitSignedExpression(ExprParser::SignedExpressionContext* context) override; + std::any visitShiftAddsub(ExprParser::ShiftAddsubContext* context) override; + std::any visitShiftMuldiv(ExprParser::ShiftMuldivContext* context) override; + std::any visitRightMuldiv(ExprParser::RightMuldivContext* context) override; + std::any visitRightExpression(ExprParser::RightExpressionContext* context) override; + +private: + Registry& registry_; + const ModelParser::Model& model_; +}; + +NodeRegistry convertExpressionToNode(const std::string& exprStr, const ModelParser::Model& model) +{ + if (exprStr.empty()) + { + return {}; + } + antlr4::ANTLRInputStream input(exprStr); + ExprLexer lexer(&input); + antlr4::CommonTokenStream tokens(&lexer); + ExprParser parser(&tokens); + + ExprParser::ExprContext* tree = parser.expr(); + Antares::Solver::Registry registry; + ConvertorVisitor visitor(registry, model); + Node* root = std::any_cast(visitor.visit(tree)); + return NodeRegistry(root, std::move(registry)); +} + +ConvertorVisitor::ConvertorVisitor(Antares::Solver::Registry& registry, + const ModelParser::Model& model): + registry_(registry), + model_(model) +{ +} + +std::any ConvertorVisitor::visit(antlr4::tree::ParseTree* tree) +{ + return tree->accept(this); +} + +class NoParameterOrVariableWithThisName: public std::runtime_error +{ +public: + explicit NoParameterOrVariableWithThisName(const std::string& name): + runtime_error("No parameter or variable found for this identifier: " + name) + { + } +}; + +std::any ConvertorVisitor::visitIdentifier(ExprParser::IdentifierContext* context) +{ + for (const auto& param: model_.parameters) + { + if (param.id == context->IDENTIFIER()->getText()) + { + return static_cast(registry_.create(param.id)); + } + } + + for (const auto& var: model_.variables) + { + if (var.id == context->getText()) + { + return static_cast(registry_.create(var.id)); + } + } + + throw NoParameterOrVariableWithThisName(context->getText()); +} + +std::any ConvertorVisitor::visitMuldiv(ExprParser::MuldivContext* context) +{ + auto* left = std::any_cast(visit(context->expr(0))); + auto* right = std::any_cast(visit(context->expr(1))); + + std::string op = context->op->getText(); + return (op == "*") ? static_cast(registry_.create(left, right)) + : static_cast(registry_.create(left, right)); +} + +std::any ConvertorVisitor::visitFullexpr(ExprParser::FullexprContext* context) +{ + return context->expr()->accept(this); +} + +std::any ConvertorVisitor::visitNegation(ExprParser::NegationContext* context) +{ + Node* n = std::any_cast(context->expr()->accept(this)); + return static_cast(registry_.create(n)); +} + +std::any ConvertorVisitor::visitExpression(ExprParser::ExpressionContext* context) +{ + return context->expr()->accept(this); +} + +std::any ConvertorVisitor::visitComparison(ExprParser::ComparisonContext* context) +{ + Node* left = std::any_cast(visit(context->expr(0))); + Node* right = std::any_cast(visit(context->expr(1))); + + std::string op = context->COMPARISON()->getText(); + if (op == "=") + { + return static_cast(registry_.create(left, right)); + } + else if (op == "<=") + { + return static_cast(registry_.create(left, right)); + } + else + { + return static_cast(registry_.create(left, right)); + } +} + +std::any ConvertorVisitor::visitAddsub(ExprParser::AddsubContext* context) +{ + Node* left = std::any_cast(visit(context->expr(0))); + Node* right = std::any_cast(visit(context->expr(1))); + + std::string op = context->op->getText(); + return (op == "+") ? static_cast(registry_.create(left, right)) + : static_cast(registry_.create(left, right)); +} + +class NotImplemented: public std::runtime_error +{ +public: + using std::runtime_error::runtime_error; +}; + +// TODO implement this +std::any ConvertorVisitor::visitPortField([[maybe_unused]] ExprParser::PortFieldContext* context) +{ + throw NotImplemented("Node portfield not implemented yet"); +} + +std::any ConvertorVisitor::visitNumber(ExprParser::NumberContext* context) +{ + double d = stod(context->getText()); + return static_cast(registry_.create(d)); +} + +// TODO implement this +std::any ConvertorVisitor::visitTimeIndex([[maybe_unused]] ExprParser::TimeIndexContext* context) +{ + throw NotImplemented("Node time index not implemented yet"); +} + +// TODO implement this +std::any ConvertorVisitor::visitTimeShift([[maybe_unused]] ExprParser::TimeShiftContext* context) +{ + throw NotImplemented("Node time shift not implemented yet"); +} + +// TODO implement this +std::any ConvertorVisitor::visitFunction([[maybe_unused]] ExprParser::FunctionContext* context) +{ + throw NotImplemented("Node function not implemented yet"); +} + +// TODO implement this +std::any ConvertorVisitor::visitTimeSum([[maybe_unused]] ExprParser::TimeSumContext* context) +{ + throw NotImplemented("Node time sum not implemented yet"); +} + +// TODO implement this +std::any ConvertorVisitor::visitAllTimeSum([[maybe_unused]] ExprParser::AllTimeSumContext* context) +{ + throw NotImplemented("Node all time sum not implemented yet"); +} + +// shift related, not tested +std::any ConvertorVisitor::visitSignedAtom(ExprParser::SignedAtomContext* context) +{ + auto a = context->atom()->accept(this); + if (context->op->getText() == "-") + { + return static_cast(registry_.create(std::any_cast(a))); + } + return a; +} + +std::any ConvertorVisitor::visitUnsignedAtom(ExprParser::UnsignedAtomContext* context) +{ + return context->atom()->accept(this); +} + +// TODO implement this +std::any ConvertorVisitor::visitRightAtom([[maybe_unused]] ExprParser::RightAtomContext* context) +{ + throw NotImplemented("Node right atom not implemented yet"); +} + +// TODO implement this +std::any ConvertorVisitor::visitShift([[maybe_unused]] ExprParser::ShiftContext* context) +{ + throw NotImplemented("Node shift not implemented yet"); +} + +// TODO implement this +std::any ConvertorVisitor::visitShiftAddsub( + [[maybe_unused]] ExprParser::ShiftAddsubContext* context) +{ + throw NotImplemented("Node shift add sub not implemented yet"); +} + +// TODO implement this +std::any ConvertorVisitor::visitShiftMuldiv( + [[maybe_unused]] ExprParser::ShiftMuldivContext* context) +{ + throw NotImplemented("Node shift mul div not implemented yet"); +} + +// TODO implement this +std::any ConvertorVisitor::visitRightMuldiv( + [[maybe_unused]] ExprParser::RightMuldivContext* context) +{ + throw NotImplemented("Node right mul div not implemented yet"); +} + +// TODO implement this +std::any ConvertorVisitor::visitSignedExpression( + [[maybe_unused]] ExprParser::SignedExpressionContext* context) +{ + throw NotImplemented("Node signed expression not implemented yet"); +} + +std::any ConvertorVisitor::visitRightExpression(ExprParser::RightExpressionContext* context) +{ + return context->expr()->accept(this); +} + +} // namespace Antares::Solver::ModelConverter diff --git a/src/solver/modelConverter/include/antares/solver/modelConverter/convertorVisitor.h b/src/solver/modelConverter/include/antares/solver/modelConverter/convertorVisitor.h new file mode 100644 index 0000000000..1b8dd34643 --- /dev/null +++ b/src/solver/modelConverter/include/antares/solver/modelConverter/convertorVisitor.h @@ -0,0 +1,32 @@ +/* + * 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 +#include "antares/solver/modelParser/Library.h" + +namespace Antares::Solver::ModelConverter +{ +NodeRegistry convertExpressionToNode(const std::string& exprStr, const ModelParser::Model& model); +} // namespace Antares::Solver::ModelConverter diff --git a/src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h b/src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h index 7ca778e10d..ffa0b66a71 100644 --- a/src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h +++ b/src/solver/modelConverter/include/antares/solver/modelConverter/modelConverter.h @@ -20,6 +20,9 @@ */ #pragma once +#include + +#include "antares/solver/modelParser/Library.h" namespace Antares { @@ -34,7 +37,18 @@ class Library; } } // namespace Antares +namespace Antares::Solver::Nodes +{ +class Node; +} + namespace Antares::Solver::ModelConverter { +class UnknownTypeException: public std::runtime_error +{ +public: + explicit UnknownTypeException(ModelParser::ValueType type); +}; + Antares::Study::SystemModel::Library convert(const Antares::Solver::ModelParser::Library& library); -} +} // namespace Antares::Solver::ModelConverter diff --git a/src/solver/modelConverter/modelConverter.cpp b/src/solver/modelConverter/modelConverter.cpp index b585215195..c8b3d856c9 100644 --- a/src/solver/modelConverter/modelConverter.cpp +++ b/src/solver/modelConverter/modelConverter.cpp @@ -21,10 +21,9 @@ #include "antares/solver/modelConverter/modelConverter.h" -#include - -#include "antares/solver/modelParser/Library.h" +#include "antares/solver/modelConverter/convertorVisitor.h" #include "antares/study/system-model/constraint.h" +#include "antares/study/system-model/expression.h" #include "antares/study/system-model/library.h" #include "antares/study/system-model/model.h" #include "antares/study/system-model/parameter.h" @@ -34,11 +33,16 @@ namespace Antares::Solver::ModelConverter { +UnknownTypeException::UnknownTypeException(ModelParser::ValueType type): + std::runtime_error("Unknown type: " + ModelParser::toString(type)) +{ +} + /** - * \brief Converts parameters from ModelParser::Model to ObjectModel::Parameter. + * \brief Converts parameters from ModelParser::Model to SystemModel::Parameter. * * \param model The ModelParser::Model object containing parameters. - * \return A vector of ObjectModel::Parameter objects. + * \return A vector of SystemModel::Parameter objects. */ std::vector convertTypes( const Antares::Solver::ModelParser::Library& library) @@ -61,11 +65,11 @@ std::vector convertTypes( } /** - * \brief Converts a ModelParser::ValueType to an ObjectModel::ValueType. + * \brief Converts a ModelParser::ValueType to an SystemModel::ValueType. * * \param type The ModelParser::ValueType to convert. - * \return The corresponding ObjectModel::ValueType. - * \throws std::runtime_error if the type is unknown. + * \return The corresponding SystemModel::ValueType. + * \throws UnknownType if the type is unknown. */ std::vector convertParameters( const Antares::Solver::ModelParser::Model& model) @@ -73,22 +77,21 @@ std::vector convertParameters( std::vector parameters; for (const auto& parameter: model.parameters) { - parameters.emplace_back(Antares::Study::SystemModel::Parameter{ + parameters.emplace_back( parameter.id, - Antares::Study::SystemModel::ValueType::FLOAT, // TODO: change to correct type static_cast( parameter.time_dependent), static_cast( - parameter.scenario_dependent)}); + parameter.scenario_dependent)); } return parameters; } /** - * \brief Converts variables from ModelParser::Model to ObjectModel::Variable. + * \brief Converts variables from ModelParser::Model to SystemModel::Variable. * * \param model The ModelParser::Model object containing variables. - * \return A vector of ObjectModel::Variable objects. + * \return A vector of SystemModel::Variable objects. */ Antares::Study::SystemModel::ValueType convertType(Antares::Solver::ModelParser::ValueType type) { @@ -102,46 +105,46 @@ Antares::Study::SystemModel::ValueType convertType(Antares::Solver::ModelParser: case Antares::Solver::ModelParser::ValueType::BOOL: return Antares::Study::SystemModel::ValueType::BOOL; default: - throw std::runtime_error("Unknown type: " + Antares::Solver::ModelParser::toString(type)); + throw UnknownTypeException(type); } } /** - * \brief Converts ports from ModelParser::Model to ObjectModel::Port. + * \brief Converts ports from ModelParser::Model to SystemModel::Port. * * \param model The ModelParser::Model object containing ports. - * \return A vector of ObjectModel::Port objects. + * \return A vector of SystemModel::Port objects. */ -std::vector convertVariables( - const Antares::Solver::ModelParser::Model& model) +std::vector convertVariables(const ModelParser::Model& model) { std::vector variables; for (const auto& variable: model.variables) { - variables.emplace_back(Antares::Study::SystemModel::Variable{ - variable.id, - Antares::Study::SystemModel::Expression{variable.lower_bound}, - Antares::Study::SystemModel::Expression{variable.upper_bound}, - convertType(variable.variable_type)}); + Antares::Study::SystemModel::Expression lb(variable.lower_bound, + convertExpressionToNode(variable.lower_bound, + model)); + Antares::Study::SystemModel::Expression ub(variable.upper_bound, + convertExpressionToNode(variable.upper_bound, + model)); + variables.emplace_back(variable.id, + std::move(lb), + std::move(ub), + convertType(variable.variable_type)); } + return variables; } /** - * \brief Converts constraints from ModelParser::Model to ObjectModel::Constraint. + * \brief Converts constraints from ModelParser::Model to SystemModel::Constraint. * * \param model The ModelParser::Model object containing constraints. - * \return A vector of ObjectModel::Constraint objects. + * \return A vector of SystemModel::Constraint objects. */ std::vector convertPorts( - const Antares::Solver::ModelParser::Model& model) + [[maybe_unused]] const Antares::Solver::ModelParser::Model& model) { - std::vector ports; - for (const auto& port: model.ports) - { - // ports.emplace_back(Antares::Study::SystemModel::Port{port.name, port.type}); - } - return ports; + return {}; } std::vector convertConstraints( @@ -150,18 +153,19 @@ std::vector convertConstraints( std::vector constraints; for (const auto& constraint: model.constraints) { - constraints.emplace_back(Antares::Study::SystemModel::Constraint{ - constraint.id, - Antares::Study::SystemModel::Expression{constraint.expression}}); + auto expr = convertExpressionToNode(constraint.expression, model); + constraints.emplace_back(constraint.id, + Antares::Study::SystemModel::Expression{constraint.expression, + std::move(expr)}); } return constraints; } /** - * \brief Converts models from ModelParser::Library to ObjectModel::Model. + * \brief Converts models from ModelParser::Library to SystemModel::Model. * * \param library The ModelParser::Library object containing models. - * \return A vector of ObjectModel::Model objects. + * \return A vector of SystemModel::Model objects. */ std::vector convertModels( const Antares::Solver::ModelParser::Library& library) @@ -176,8 +180,12 @@ std::vector convertModels( std::vector constraints = convertConstraints( model); + auto nodeObjective = convertExpressionToNode(model.objective, model); + auto modelObj = modelBuilder.withId(model.id) - .withObjective(Antares::Study::SystemModel::Expression{model.objective}) + .withObjective( + Antares::Study::SystemModel::Expression{model.objective, + std::move(nodeObjective)}) .withParameters(std::move(parameters)) .withVariables(std::move(variables)) .withPorts(std::move(ports)) @@ -189,10 +197,10 @@ std::vector convertModels( } /** - * \brief Converts a ModelParser::Library object to an ObjectModel::Library object. + * \brief Converts a ModelParser::Library object to an SystemModel::Library object. * * \param library The ModelParser::Library object to convert. - * \return The corresponding ObjectModel::Library object. + * \return The corresponding SystemModel::Library object. */ Antares::Study::SystemModel::Library convert(const Antares::Solver::ModelParser::Library& library) { diff --git a/src/study/system-model/CMakeLists.txt b/src/study/system-model/CMakeLists.txt index b497026127..e9a7348534 100644 --- a/src/study/system-model/CMakeLists.txt +++ b/src/study/system-model/CMakeLists.txt @@ -27,6 +27,7 @@ target_include_directories(antares-study-system-model ) target_link_libraries(antares-study-system-model PUBLIC + Antares::solver-expressions ) install(DIRECTORY include/antares DESTINATION "include" diff --git a/src/study/system-model/include/antares/study/system-model/constraint.h b/src/study/system-model/include/antares/study/system-model/constraint.h index eb7777f484..b4afe5c0ef 100644 --- a/src/study/system-model/include/antares/study/system-model/constraint.h +++ b/src/study/system-model/include/antares/study/system-model/constraint.h @@ -43,7 +43,7 @@ class Constraint return id_; } - Expression expression() const + const Expression& expression() const { return expression_; } diff --git a/src/study/system-model/include/antares/study/system-model/expression.h b/src/study/system-model/include/antares/study/system-model/expression.h index 6924401e68..0b52d82f91 100644 --- a/src/study/system-model/include/antares/study/system-model/expression.h +++ b/src/study/system-model/include/antares/study/system-model/expression.h @@ -22,6 +22,13 @@ #include +#include + +namespace Antares::Solver::Nodes +{ +class Node; +} + namespace Antares::Study::SystemModel { @@ -30,8 +37,9 @@ class Expression public: Expression() = default; - explicit Expression(std::string value): - value_(std::move(value)) + explicit Expression(const std::string& value, Antares::Solver::NodeRegistry root): + value_(value), + root_(std::move(root)) { } @@ -42,6 +50,7 @@ class Expression private: std::string value_; + Antares::Solver::NodeRegistry root_; }; } // namespace Antares::Study::SystemModel diff --git a/src/study/system-model/include/antares/study/system-model/library.h b/src/study/system-model/include/antares/study/system-model/library.h index a056731156..8f5e3599f8 100644 --- a/src/study/system-model/include/antares/study/system-model/library.h +++ b/src/study/system-model/include/antares/study/system-model/library.h @@ -53,7 +53,7 @@ class Library const std::unordered_map& Models() const { - return models_; + return *models_; } private: @@ -63,7 +63,8 @@ class Library std::string description_; std::unordered_map portTypes_; - std::unordered_map models_; + std::shared_ptr> + models_ = std::make_shared>(); }; /** @@ -79,7 +80,7 @@ class LibraryBuilder LibraryBuilder& withPortTypes(std::vector&& portTypes); LibraryBuilder& withModels(std::vector&& models); - Library build(); + const Library& build() const; private: Library library_; diff --git a/src/study/system-model/include/antares/study/system-model/model.h b/src/study/system-model/include/antares/study/system-model/model.h index 8f19d424c1..a050424131 100644 --- a/src/study/system-model/include/antares/study/system-model/model.h +++ b/src/study/system-model/include/antares/study/system-model/model.h @@ -39,12 +39,20 @@ namespace Antares::Study::SystemModel class Model { public: + Model() = default; + Model(Model&&) = default; + Model(const Model&) = delete; + ~Model() = default; + + Model& operator=(Model&&) = default; + Model& operator=(const Model&) = delete; + const std::string& Id() const { return id_; } - Expression Objective() const + const Expression& Objective() const { return objective_; } @@ -84,7 +92,7 @@ class ModelBuilder { public: ModelBuilder& withId(std::string_view id); - ModelBuilder& withObjective(Expression objective); + ModelBuilder& withObjective(Expression&& objective); ModelBuilder& withParameters(std::vector&& parameters); ModelBuilder& withVariables(std::vector&& variables); ModelBuilder& withPorts(std::vector&& ports); diff --git a/src/study/system-model/include/antares/study/system-model/parameter.h b/src/study/system-model/include/antares/study/system-model/parameter.h index 4daa3d2b94..b2dad9b7d1 100644 --- a/src/study/system-model/include/antares/study/system-model/parameter.h +++ b/src/study/system-model/include/antares/study/system-model/parameter.h @@ -53,11 +53,9 @@ class Parameter }; explicit Parameter(std::string id, - ValueType type, TimeDependent timeDependent, ScenarioDependent scenarioDependent): id_(std::move(id)), - type_(type), timeDependent_(timeDependent), scenarioDependent_(scenarioDependent) { @@ -68,11 +66,6 @@ class Parameter return id_; } - ValueType Type() const - { - return type_; - } - bool isTimeDependent() const { return timeDependent_ == TimeDependent::YES; @@ -85,7 +78,6 @@ class Parameter private: std::string id_; - ValueType type_; TimeDependent timeDependent_ = TimeDependent::YES; // optional at construction ScenarioDependent scenarioDependent_ = ScenarioDependent::YES; // optional at construction }; diff --git a/src/study/system-model/include/antares/study/system-model/variable.h b/src/study/system-model/include/antares/study/system-model/variable.h index ad9011df79..451fbd2b90 100644 --- a/src/study/system-model/include/antares/study/system-model/variable.h +++ b/src/study/system-model/include/antares/study/system-model/variable.h @@ -35,8 +35,8 @@ class Variable Variable(std::string id, Expression lower_bound, Expression upper_bound, ValueType type): id_(std::move(id)), type_(type), - lowerBound_(lower_bound), - upperBound_(upper_bound) + lowerBound_(std::move(lower_bound)), + upperBound_(std::move(upper_bound)) { } @@ -50,12 +50,12 @@ class Variable return type_; } - Expression LowerBound() const + const Expression& LowerBound() const { return lowerBound_; } - Expression UpperBound() const + const Expression& UpperBound() const { return upperBound_; } diff --git a/src/study/system-model/library.cpp b/src/study/system-model/library.cpp index e7026afd86..ace09d45ae 100644 --- a/src/study/system-model/library.cpp +++ b/src/study/system-model/library.cpp @@ -83,7 +83,7 @@ LibraryBuilder& LibraryBuilder::withModels(std::vector&& models) { std::transform(models.begin(), models.end(), - std::inserter(library_.models_, library_.models_.end()), + std::inserter(*library_.models_, library_.models_->end()), [](/*Non const to prevent copy*/ Model& model) { return std::make_pair(model.Id(), std::move(model)); }); return *this; @@ -94,7 +94,7 @@ LibraryBuilder& LibraryBuilder::withModels(std::vector&& models) * * \return The constructed Library object. */ -Library LibraryBuilder::build() +const Library& LibraryBuilder::build() const { return library_; } diff --git a/src/study/system-model/model.cpp b/src/study/system-model/model.cpp index 5870840d73..fd77cb3cf2 100644 --- a/src/study/system-model/model.cpp +++ b/src/study/system-model/model.cpp @@ -36,7 +36,7 @@ namespace Antares::Study::SystemModel */ Model ModelBuilder::build() { - return model_; + return std::move(model_); } /** @@ -57,9 +57,9 @@ ModelBuilder& ModelBuilder::withId(std::string_view id) * \param objective The Expression object representing the objective. * \return Reference to the ModelBuilder object. */ -ModelBuilder& ModelBuilder::withObjective(Expression objective) +ModelBuilder& ModelBuilder::withObjective(Expression&& objective) { - model_.objective_ = objective; + model_.objective_ = std::move(objective); return *this; } diff --git a/src/tests/src/libs/antares/CMakeLists.txt b/src/tests/src/libs/antares/CMakeLists.txt index 654f897b0a..97ef92fd0e 100644 --- a/src/tests/src/libs/antares/CMakeLists.txt +++ b/src/tests/src/libs/antares/CMakeLists.txt @@ -5,10 +5,7 @@ add_subdirectory(benchmarking) add_subdirectory(inifile) add_subdirectory(yaml-parser) - -if(WITH_ANTLR4) - add_subdirectory(antlr4-interface) -endif() +add_subdirectory(antlr4-interface) set(src_libs_antares "${CMAKE_SOURCE_DIR}/libs/antares") diff --git a/src/tests/src/solver/modelParser/CMakeLists.txt b/src/tests/src/solver/modelParser/CMakeLists.txt index 57f733030c..9f884255d8 100644 --- a/src/tests/src/solver/modelParser/CMakeLists.txt +++ b/src/tests/src/solver/modelParser/CMakeLists.txt @@ -2,6 +2,7 @@ set(SOURCE_FILES testModelParser.cpp testModelTranslator.cpp + testConvertorVisitor.cpp test_full.cpp enum_operators.h ) @@ -13,9 +14,11 @@ add_executable(TestModelParser ${SOURCE_FILES}) target_link_libraries(TestModelParser PRIVATE Boost::unit_test_framework + Antares::solver-expressions Antares::modelConverter Antares::modelParser Antares::antares-study-system-model + Antares::antlr-interface ) # Storing test-toybox under the folder Unit-tests in the IDE @@ -25,4 +28,4 @@ set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) add_test(NAME TestModelParser COMMAND TestModelParser) # Set test properties -set_property(TEST TestModelParser PROPERTY LABELS unit) \ No newline at end of file +set_property(TEST TestModelParser PROPERTY LABELS unit) diff --git a/src/tests/src/solver/modelParser/testConvertorVisitor.cpp b/src/tests/src/solver/modelParser/testConvertorVisitor.cpp new file mode 100644 index 0000000000..8eddcda921 --- /dev/null +++ b/src/tests/src/solver/modelParser/testConvertorVisitor.cpp @@ -0,0 +1,228 @@ +/* + * 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 . + */ +#define WIN32_LEAN_AND_MEAN + +#include + +#include +#include "antares/solver/expressions/Registry.hxx" +#include "antares/solver/expressions/visitors/CompareVisitor.h" +#include "antares/solver/modelConverter/convertorVisitor.h" +#include "antares/solver/modelParser/Library.h" + +using namespace Antares::Solver; + +class ExpressionToNodeConvertorEmptyModel +{ +public: + ExpressionToNodeConvertorEmptyModel(ModelParser::Model&& model): + model_(std::move(model)) + { + } + + // Empty model + ExpressionToNodeConvertorEmptyModel() = default; + + NodeRegistry run(const std::string& input) + { + return ModelConverter::convertExpressionToNode(input, model_); + } + +private: + const ModelParser::Model model_; +}; + +static Nodes::LiteralNode* toLiteral(Nodes::Node* n) +{ + return dynamic_cast(n); +} + +BOOST_FIXTURE_TEST_CASE(empty_expression, ExpressionToNodeConvertorEmptyModel) +{ + BOOST_CHECK_EQUAL(run("").node, nullptr); +} + +BOOST_FIXTURE_TEST_CASE(negation, ExpressionToNodeConvertorEmptyModel) +{ + std::string expression = "-7"; + auto expr = run(expression); + BOOST_CHECK_EQUAL(expr.node->name(), "NegationNode"); + auto* nodeNeg = dynamic_cast(expr.node); + BOOST_REQUIRE(nodeNeg); + BOOST_CHECK_EQUAL(toLiteral(nodeNeg->child())->value(), 7); +} + +BOOST_AUTO_TEST_CASE(identifier) +{ + ModelParser::Model model{ + .id = "model0", + .description = "description", + .parameters = {{"param1", true, false}, {"param2", false, false}}, + .variables = {{"varP", "7", "pmin", ModelParser::ValueType::CONTINUOUS}}, + .ports = {}, + .port_field_definitions = {}, + .constraints = {}, + .objective = "objectives"}; + ExpressionToNodeConvertorEmptyModel converter(std::move(model)); + + { + std::string expression = "param1"; + auto expr = converter.run(expression); + BOOST_CHECK_EQUAL(expr.node->name(), "ParameterNode"); + } + + { + std::string expression = "varP"; + auto expr = converter.run(expression); + BOOST_CHECK_EQUAL(expr.node->name(), "VariableNode"); + } +} + +bool expectedMessage(const std::runtime_error& ex) +{ + BOOST_CHECK_EQUAL(ex.what(), + std::string("No parameter or variable found for this identifier: abc")); + return true; +} + +BOOST_AUTO_TEST_CASE(identifierNotFound) +{ + ModelParser::Model model{ + .id = "model0", + .description = "description", + .parameters = {{"param1", true, false}}, + .variables = {{"varP", "7", "pmin", ModelParser::ValueType::CONTINUOUS}}, + .ports = {}, + .port_field_definitions = {}, + .constraints = {}, + .objective = "objectives"}; + + std::string expression = "abc"; // not a param or var + BOOST_CHECK_EXCEPTION(ModelConverter::convertExpressionToNode(expression, model), + std::runtime_error, + expectedMessage); +} + +BOOST_FIXTURE_TEST_CASE(addTwoLiterals, ExpressionToNodeConvertorEmptyModel) +{ + const std::string expression = "1 + 2"; + auto expr = run(expression); + BOOST_CHECK_EQUAL(expr.node->name(), "SumNode"); + + auto* nodeSum = dynamic_cast(expr.node); + BOOST_REQUIRE(nodeSum); + auto operands = nodeSum->getOperands(); + BOOST_CHECK_EQUAL(toLiteral(operands[0])->value(), 1); + BOOST_CHECK_EQUAL(toLiteral(operands[1])->value(), 2); +} + +BOOST_FIXTURE_TEST_CASE(subtractTwoLiterals, ExpressionToNodeConvertorEmptyModel) +{ + const std::string expression = "6 - 3"; + auto expr = run(expression); + BOOST_CHECK_EQUAL(expr.node->name(), "SubtractionNode"); + + auto* nodeSub = dynamic_cast(expr.node); + BOOST_REQUIRE(nodeSub); + BOOST_CHECK_EQUAL(toLiteral(nodeSub->left())->value(), 6); + BOOST_CHECK_EQUAL(toLiteral(nodeSub->right())->value(), 3); +} + +BOOST_FIXTURE_TEST_CASE(multiplyTwoLiterals, ExpressionToNodeConvertorEmptyModel) +{ + std::string expression = "1 * 2"; + auto expr = run(expression); + BOOST_CHECK_EQUAL(expr.node->name(), "MultiplicationNode"); + + auto* nodeMult = dynamic_cast(expr.node); + BOOST_REQUIRE(nodeMult); + BOOST_CHECK_EQUAL(toLiteral(nodeMult->left())->value(), 1); + BOOST_CHECK_EQUAL(toLiteral(nodeMult->right())->value(), 2); +} + +BOOST_FIXTURE_TEST_CASE(divideTwoLiterals, ExpressionToNodeConvertorEmptyModel) +{ + const std::string expression = "6 / 3"; + auto expr = run(expression); + BOOST_CHECK_EQUAL(expr.node->name(), "DivisionNode"); + + auto* nodeDiv = dynamic_cast(expr.node); + BOOST_REQUIRE(nodeDiv); + BOOST_CHECK_EQUAL(toLiteral(nodeDiv->left())->value(), 6); + BOOST_CHECK_EQUAL(toLiteral(nodeDiv->right())->value(), 3); +} + +BOOST_FIXTURE_TEST_CASE(comparison, ExpressionToNodeConvertorEmptyModel) +{ + std::string expression = "1 = 2"; + auto expr = run(expression); + BOOST_CHECK_EQUAL(expr.node->name(), "EqualNode"); + + expression = "1 <= 5"; + expr = run(expression); + BOOST_CHECK_EQUAL(expr.node->name(), "LessThanOrEqualNode"); + + expression = "8364 >= 27"; + expr = run(expression); + BOOST_CHECK_EQUAL(expr.node->name(), "GreaterThanOrEqualNode"); + + auto* nodeGreater = dynamic_cast(expr.node); + BOOST_REQUIRE(nodeGreater); + BOOST_CHECK_EQUAL(toLiteral(nodeGreater->left())->value(), 8364); + BOOST_CHECK_EQUAL(toLiteral(nodeGreater->right())->value(), 27); +} + +BOOST_AUTO_TEST_CASE(medium_expression) +{ + ModelParser::Model model{ + .id = "model0", + .description = "description", + .parameters = {{"param1", true, false}, {"param2", false, false}}, + .variables = {{"varP", "7", "param1", ModelParser::ValueType::CONTINUOUS}}, + .ports = {}, + .port_field_definitions = {}, + .constraints = {}, + .objective = "objectives"}; + + ExpressionToNodeConvertorEmptyModel converter(std::move(model)); + std::string expression = "(12 * (4 - 1) + param1) / -(42 + 3 + varP)"; + auto expr = converter.run(expression); + + Registry registry; + + auto* param = registry.create("param1"); + auto* var = registry.create("varP"); + auto* l3 = registry.create(3); + auto* l42 = registry.create(42); + auto* l1 = registry.create(1); + auto* l4 = registry.create(4); + auto* l12 = registry.create(12); + auto* sub = registry.create(l4, l1); + auto* mult = registry.create(l12, sub); + auto* sum1 = registry.create(mult, param); + auto* sum2 = registry.create(l42, l3); + auto* sum3 = registry.create(sum2, var); + auto* neg = registry.create(sum3); + auto* div = registry.create(sum1, neg); + + Visitors::CompareVisitor cmp; + BOOST_CHECK(cmp.dispatch(expr.node, div)); +} diff --git a/src/tests/src/solver/modelParser/testModelTranslator.cpp b/src/tests/src/solver/modelParser/testModelTranslator.cpp index a22955b5db..9233b90767 100644 --- a/src/tests/src/solver/modelParser/testModelTranslator.cpp +++ b/src/tests/src/solver/modelParser/testModelTranslator.cpp @@ -1,5 +1,4 @@ -/* - * Copyright 2007-2024, RTE (https://www.rte-france.com) +/* * 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, @@ -25,6 +24,7 @@ #include +#include "antares/solver/expressions/nodes/Node.h" #include "antares/solver/modelConverter/modelConverter.h" #include "antares/solver/modelParser/Library.h" #include "antares/study/system-model/library.h" @@ -34,10 +34,14 @@ using namespace Antares::Solver; using namespace Antares::Study; -// Test empty library -BOOST_AUTO_TEST_CASE(Empty_library_is_valid) +struct Fixture { ModelParser::Library library; +}; + +// Test empty library +BOOST_FIXTURE_TEST_CASE(Empty_library_is_valid, Fixture) +{ SystemModel::Library lib = ModelConverter::convert(library); BOOST_CHECK(lib.Id().empty()); BOOST_CHECK(lib.Description().empty()); @@ -46,9 +50,9 @@ BOOST_AUTO_TEST_CASE(Empty_library_is_valid) } // Test library with id and description -BOOST_AUTO_TEST_CASE(library_id_description_properly_translated) +BOOST_FIXTURE_TEST_CASE(library_id_description_properly_translated, Fixture) + { - ModelParser::Library library; library.id = "test_id"; library.description = "test_description"; SystemModel::Library lib = ModelConverter::convert(library); @@ -57,9 +61,8 @@ BOOST_AUTO_TEST_CASE(library_id_description_properly_translated) } // Test library with port types -BOOST_AUTO_TEST_CASE(port_type_with_empty_fileds_properly_translated) +BOOST_FIXTURE_TEST_CASE(port_type_with_empty_fileds_properly_translated, Fixture) { - ModelParser::Library library; ModelParser::PortType portType1{"port1", "flow port", {}}; ModelParser::PortType portType2{"port2", "impedance port", {}}; library.port_types = {portType1, portType2}; @@ -81,9 +84,8 @@ BOOST_AUTO_TEST_CASE(port_type_with_empty_fileds_properly_translated) } // Test library with port types and fields -BOOST_AUTO_TEST_CASE(portType_with_fields_properly_translated) +BOOST_FIXTURE_TEST_CASE(portType_with_fields_properly_translated, Fixture) { - ModelParser::Library library; ModelParser::PortType portType1{"port1", "flow port", {"field1", "field2"}}; ModelParser::PortType portType2{"port2", "impedance port", {"field3", "field4"}}; library.port_types = {portType1, portType2}; @@ -97,28 +99,26 @@ BOOST_AUTO_TEST_CASE(portType_with_fields_properly_translated) } // Test library with models -BOOST_AUTO_TEST_CASE(empty_model_properly_translated) +BOOST_FIXTURE_TEST_CASE(empty_model_properly_translated, Fixture) { - ModelParser::Library library; ModelParser::Model model1{.id = "model1", .description = "description", - .parameters = {}, + .parameters = {{"param1", true, false}}, .variables = {}, .ports = {}, .port_field_definitions = {}, .constraints = {}, - .objective = "objectives"}; + .objective = "param1"}; library.models = {model1}; SystemModel::Library lib = ModelConverter::convert(library); BOOST_REQUIRE_EQUAL(lib.Models().size(), 1); BOOST_CHECK_EQUAL(lib.Models().at("model1").Id(), "model1"); - BOOST_CHECK_EQUAL(lib.Models().at("model1").Objective().Value(), "objectives"); + BOOST_CHECK_EQUAL(lib.Models().at("model1").Objective().Value(), "param1"); } // Test library with models and parameters -BOOST_AUTO_TEST_CASE(model_parameters_properly_translated) +BOOST_FIXTURE_TEST_CASE(model_parameters_properly_translated, Fixture) { - ModelParser::Library library; ModelParser::Model model1{.id = "model1", .description = "description", .parameters = {{"param1", true, false}, {"param2", false, false}}, @@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(model_parameters_properly_translated) .ports = {}, .port_field_definitions{}, .constraints{}, - .objective = "objectives"}; + .objective = ""}; library.models = {model1}; SystemModel::Library lib = ModelConverter::convert(library); auto& model = lib.Models().at("model1"); @@ -136,27 +136,24 @@ BOOST_AUTO_TEST_CASE(model_parameters_properly_translated) BOOST_CHECK_EQUAL(parameter1.Id(), "param1"); BOOST_CHECK(parameter1.isTimeDependent()); BOOST_CHECK(!parameter1.isScenarioDependent()); - BOOST_CHECK_EQUAL(parameter1.Type(), SystemModel::ValueType::FLOAT); BOOST_CHECK_EQUAL(parameter2.Id(), "param2"); BOOST_CHECK(!parameter2.isTimeDependent()); BOOST_CHECK(!parameter2.isScenarioDependent()); - BOOST_CHECK_EQUAL(parameter2.Type(), SystemModel::ValueType::FLOAT); } // Test library with models and variables -BOOST_AUTO_TEST_CASE(model_variables_properly_translated) +BOOST_FIXTURE_TEST_CASE(model_variables_properly_translated, Fixture) { - ModelParser::Library library; ModelParser::Model model1{ .id = "model1", .description = "description", - .parameters = {}, + .parameters = {{"pmax", true, false}}, .variables = {{"var1", "7", "pmax", ModelParser::ValueType::BOOL}, - {"var2", "99999999.9999999", "vcost", ModelParser::ValueType::INTEGER}}, + {"var2", "99999999.9999999", "var1", ModelParser::ValueType::INTEGER}}, .ports = {}, .port_field_definitions = {}, .constraints = {}, - .objective = "objectives"}; + .objective = "var1"}; library.models = {model1}; SystemModel::Library lib = ModelConverter::convert(library); auto& model = lib.Models().at("model1"); @@ -169,7 +166,7 @@ BOOST_AUTO_TEST_CASE(model_variables_properly_translated) BOOST_CHECK_EQUAL(variable1.Type(), SystemModel::ValueType::BOOL); BOOST_CHECK_EQUAL(variable2.Id(), "var2"); BOOST_CHECK_EQUAL(variable2.LowerBound().Value(), "99999999.9999999"); - BOOST_CHECK_EQUAL(variable2.UpperBound().Value(), "vcost"); + BOOST_CHECK_EQUAL(variable2.UpperBound().Value(), "var1"); BOOST_CHECK_EQUAL(variable2.Type(), SystemModel::ValueType::INTEGER); } @@ -177,6 +174,7 @@ BOOST_AUTO_TEST_CASE(model_variables_properly_translated) BOOST_AUTO_TEST_CASE(model_ports_properly_translated, *boost::unit_test::disabled()) { ModelParser::Library library; + Registry registry; ModelParser::Model model1{.id = "model1", .description = "description", .parameters = {}, @@ -184,10 +182,10 @@ BOOST_AUTO_TEST_CASE(model_ports_properly_translated, *boost::unit_test::disable .ports = {{"port1", "flow"}, {"port2", "impedance"}}, .port_field_definitions = {}, .constraints = {}, - .objective = "objectives"}; + .objective = ""}; library.models = {model1}; SystemModel::Library lib = ModelConverter::convert(library); - auto& model = lib.Models().at("model1"); + [[maybe_unused]] auto& model = lib.Models().at("model1"); // BOOST_REQUIRE_EQUAL(model.Ports().size(), 2); // auto& port1 = model.Ports().at("port1"); // auto& port2 = model.Ports().at("port2"); @@ -198,18 +196,18 @@ BOOST_AUTO_TEST_CASE(model_ports_properly_translated, *boost::unit_test::disable } // Test library with models and constraints -BOOST_AUTO_TEST_CASE(model_constraints_properly_translated) +BOOST_FIXTURE_TEST_CASE(model_constraints_properly_translated, Fixture) { - ModelParser::Library library; ModelParser::Model model1{.id = "model1", .description = "description", - .parameters = {}, + .parameters = {{"expression1", true, false}, + {"expression2", true, false}}, .variables = {}, .ports = {}, .port_field_definitions = {}, .constraints = {{"constraint1", "expression1"}, {"constraint2", "expression2"}}, - .objective = "objectives"}; + .objective = ""}; library.models = {model1}; SystemModel::Library lib = ModelConverter::convert(library); auto& model = lib.Models().at("model1"); @@ -223,28 +221,27 @@ BOOST_AUTO_TEST_CASE(model_constraints_properly_translated) } // Test with 2 models -BOOST_AUTO_TEST_CASE(multiple_models_properly_translated) +BOOST_FIXTURE_TEST_CASE(multiple_models_properly_translated, Fixture) { - ModelParser::Library library; ModelParser::Model model1{ .id = "model1", .description = "description", .parameters = {{"param1", true, false}, {"param2", false, false}}, - .variables = {{"varP", "7", "pmin", ModelParser::ValueType::CONTINUOUS}}, + .variables = {{"varP", "7", "param2", ModelParser::ValueType::CONTINUOUS}}, .ports = {}, .port_field_definitions = {}, .constraints = {}, - .objective = "objectives"}; + .objective = ""}; ModelParser::Model model2{ .id = "model2", .description = "description", .parameters = {}, - .variables = {{"var1", "7", "pmax", ModelParser::ValueType::BOOL}, - {"var2", "99999999.9999999", "vcost", ModelParser::ValueType::INTEGER}}, + .variables = {{"var1", "7", "8", ModelParser::ValueType::BOOL}, + {"var2", "99999999.9999999", "var1", ModelParser::ValueType::INTEGER}}, .ports = {}, .port_field_definitions = {}, .constraints = {}, - .objective = "objectives"}; + .objective = ""}; library.models = {model1, model2}; SystemModel::Library lib = ModelConverter::convert(library); BOOST_REQUIRE_EQUAL(lib.Models().size(), 2); diff --git a/src/tests/src/solver/modelParser/test_full.cpp b/src/tests/src/solver/modelParser/test_full.cpp index 71824c692d..4901fa610b 100644 --- a/src/tests/src/solver/modelParser/test_full.cpp +++ b/src/tests/src/solver/modelParser/test_full.cpp @@ -25,6 +25,7 @@ #include +#include "antares/solver/expressions/nodes/Node.h" #include "antares/solver/modelConverter/modelConverter.h" #include "antares/solver/modelParser/Library.h" #include "antares/solver/modelParser/parser.h" @@ -39,14 +40,12 @@ using namespace Antares::Study; void checkParameter(const SystemModel::Parameter& parameter, const std::string& name, bool timeDependent, - bool scenarioDependent, - SystemModel::ValueType type) + bool scenarioDependent) { std::cout << "Parameter: " << parameter.Id() << std::endl; BOOST_CHECK_EQUAL(parameter.Id(), name); BOOST_CHECK_EQUAL(parameter.isTimeDependent(), timeDependent); BOOST_CHECK_EQUAL(parameter.isScenarioDependent(), scenarioDependent); - BOOST_CHECK_EQUAL(parameter.Type(), type); } void checkVariable(const SystemModel::Variable& variable, @@ -116,7 +115,7 @@ BOOST_AUTO_TEST_CASE(test_full) - port: injection_port field: flow definition: generation - objective: expec(sum(cost * generation)) + objective: cost * generation - id: node description: A basic balancing node model @@ -125,7 +124,7 @@ BOOST_AUTO_TEST_CASE(test_full) type: flow binding-constraints: - id: balance - expression: sum_connections(injection_port.flow) = 0 + expression: injection_port = 0 - id: spillage description: A basic spillage model @@ -203,7 +202,7 @@ BOOST_AUTO_TEST_CASE(test_full) definition: injection - withdrawal constraints: - id: Level equation - expression: level[t] - level[t-1] - efficiency * injection + withdrawal = inflows + expression: level - level - efficiency * injection + withdrawal = inflows - id: thermal-cluster-dhd description: DHD model for thermal cluster @@ -251,12 +250,12 @@ BOOST_AUTO_TEST_CASE(test_full) - id: Min generation expression: generation >= nb_on * p_min - id: Number of units variation - expression: nb_on = nb_on[t-1] + nb_start - nb_stop + expression: nb_on = nb_on + nb_start - nb_stop - id: Min up time - expression: sum(t-d_min_up + 1 .. t, nb_start) <= nb_on + expression: t-d_min_up + 1 <= nb_on - id: Min down time - expression: sum(t-d_min_down + 1 .. t, nb_stop) <= nb_units_max[t-d_min_down] - nb_on - objective: expec(sum(cost * generation)) + expression: t-d_min_down + 1 <= nb_units_max - nb_on + objective: cost * generation )"s; try @@ -279,7 +278,7 @@ BOOST_AUTO_TEST_CASE(test_full) BOOST_REQUIRE_EQUAL(lib.Models().size(), 7); auto& model0 = lib.Models().at("generator"); BOOST_CHECK_EQUAL(model0.Id(), "generator"); - BOOST_CHECK_EQUAL(model0.Objective().Value(), "expec(sum(cost * generation))"); + BOOST_CHECK_EQUAL(model0.Objective().Value(), "cost * generation"); BOOST_REQUIRE_EQUAL(model0.getConstraints().size(), 0); BOOST_REQUIRE_EQUAL(model0.Parameters().size(), 2); @@ -287,16 +286,8 @@ BOOST_AUTO_TEST_CASE(test_full) // BOOST_REQUIRE_EQUAL(model0.Ports().size(), 1); Unsuported // BOOST_REQUIRE_EQUAL(model0.PortFieldDefinitions().size(), 1); Unsuported - checkParameter(model0.Parameters().at("cost"), - "cost", - false, - false, - SystemModel::ValueType::FLOAT); - checkParameter(model0.Parameters().at("p_max"), - "p_max", - false, - false, - SystemModel::ValueType::FLOAT); + checkParameter(model0.Parameters().at("cost"), "cost", false, false); + checkParameter(model0.Parameters().at("p_max"), "p_max", false, false); checkVariable(model0.Variables().at("generation"), "generation", @@ -324,11 +315,7 @@ BOOST_AUTO_TEST_CASE(test_full) // BOOST_REQUIRE_EQUAL(model2.Ports().size(), 1); Unsuported // BOOST_REQUIRE_EQUAL(model2.PortFieldDefinitions().size(), 1); Unsuported - checkParameter(model2.Parameters().at("cost"), - "cost", - false, - false, - SystemModel::ValueType::FLOAT); + checkParameter(model2.Parameters().at("cost"), "cost", false, false); checkVariable(model2.Variables().at("spillage"), "spillage", "0", @@ -342,11 +329,7 @@ BOOST_AUTO_TEST_CASE(test_full) BOOST_REQUIRE_EQUAL(model3.Variables().size(), 1); // BOOST_REQUIRE_EQUAL(model3.Ports().size(), 1); Unsuported // BOOST_REQUIRE_EQUAL(model3.PortFieldDefinitions().size(), 1); Unsuported - checkParameter(model3.Parameters().at("cost"), - "cost", - false, - false, - SystemModel::ValueType::FLOAT); + checkParameter(model3.Parameters().at("cost"), "cost", false, false); checkVariable(model3.Variables().at("unsupplied_energy"), "unsupplied_energy", "0", @@ -360,11 +343,7 @@ BOOST_AUTO_TEST_CASE(test_full) BOOST_REQUIRE_EQUAL(model4.Variables().size(), 0); // BOOST_REQUIRE_EQUAL(model4.Ports().size(), 1); Unsuported // BOOST_REQUIRE_EQUAL(model4.PortFieldDefinitions().size(), 1); Unsuported - checkParameter(model4.Parameters().at("demand"), - "demand", - true, - true, - SystemModel::ValueType::FLOAT); + checkParameter(model4.Parameters().at("demand"), "demand", true, true); auto& model5 = lib.Models().at("short-term-storage"); BOOST_CHECK_EQUAL(model5.Id(), "short-term-storage"); @@ -373,36 +352,12 @@ BOOST_AUTO_TEST_CASE(test_full) BOOST_REQUIRE_EQUAL(model5.Variables().size(), 3); // BOOST_REQUIRE_EQUAL(model5.Ports().size(), 1); Unsuported // BOOST_REQUIRE_EQUAL(model5.PortFieldDefinitions().size(), 1); Unsuported - checkParameter(model5.Parameters().at("efficiency"), - "efficiency", - true, - true, - SystemModel::ValueType::FLOAT); - checkParameter(model5.Parameters().at("level_min"), - "level_min", - true, - true, - SystemModel::ValueType::FLOAT); - checkParameter(model5.Parameters().at("level_max"), - "level_max", - true, - true, - SystemModel::ValueType::FLOAT); - checkParameter(model5.Parameters().at("p_max_withdrawal"), - "p_max_withdrawal", - true, - true, - SystemModel::ValueType::FLOAT); - checkParameter(model5.Parameters().at("p_max_injection"), - "p_max_injection", - true, - true, - SystemModel::ValueType::FLOAT); - checkParameter(model5.Parameters().at("inflows"), - "inflows", - true, - true, - SystemModel::ValueType::FLOAT); + checkParameter(model5.Parameters().at("efficiency"), "efficiency", true, true); + checkParameter(model5.Parameters().at("level_min"), "level_min", true, true); + checkParameter(model5.Parameters().at("level_max"), "level_max", true, true); + checkParameter(model5.Parameters().at("p_max_withdrawal"), "p_max_withdrawal", true, true); + checkParameter(model5.Parameters().at("p_max_injection"), "p_max_injection", true, true); + checkParameter(model5.Parameters().at("inflows"), "inflows", true, true); checkVariable(model5.Variables().at("injection"), "injection", "0", @@ -420,7 +375,7 @@ BOOST_AUTO_TEST_CASE(test_full) SystemModel::ValueType::FLOAT); checkConstraint(model5.getConstraints().at("Level equation"), "Level equation", - "level[t] - level[t-1] - efficiency * injection + withdrawal = inflows"); + "level - level - efficiency * injection + withdrawal = inflows"); auto& model6 = lib.Models().at("thermal-cluster-dhd"); BOOST_CHECK_EQUAL(model6.Id(), "thermal-cluster-dhd"); @@ -429,41 +384,13 @@ BOOST_AUTO_TEST_CASE(test_full) BOOST_REQUIRE_EQUAL(model6.Variables().size(), 4); // BOOST_REQUIRE_EQUAL(model6.Ports().size(), 1); Unsuported // BOOST_REQUIRE_EQUAL(model6.PortFieldDefinitions().size(), 1); Unsuported - checkParameter(model6.Parameters().at("cost"), - "cost", - true, - true, - SystemModel::ValueType::FLOAT); - checkParameter(model6.Parameters().at("p_min"), - "p_min", - true, - true, - SystemModel::ValueType::FLOAT); - checkParameter(model6.Parameters().at("p_max"), - "p_max", - true, - true, - SystemModel::ValueType::FLOAT); - checkParameter(model6.Parameters().at("d_min_up"), - "d_min_up", - true, - true, - SystemModel::ValueType::FLOAT); - checkParameter(model6.Parameters().at("d_min_down"), - "d_min_down", - true, - true, - SystemModel::ValueType::FLOAT); - checkParameter(model6.Parameters().at("nb_units_max"), - "nb_units_max", - true, - true, - SystemModel::ValueType::FLOAT); - checkParameter(model6.Parameters().at("nb_failures"), - "nb_failures", - true, - true, - SystemModel::ValueType::FLOAT); + checkParameter(model6.Parameters().at("cost"), "cost", true, true); + checkParameter(model6.Parameters().at("p_min"), "p_min", true, true); + checkParameter(model6.Parameters().at("p_max"), "p_max", true, true); + checkParameter(model6.Parameters().at("d_min_up"), "d_min_up", true, true); + checkParameter(model6.Parameters().at("d_min_down"), "d_min_down", true, true); + checkParameter(model6.Parameters().at("nb_units_max"), "nb_units_max", true, true); + checkParameter(model6.Parameters().at("nb_failures"), "nb_failures", true, true); checkVariable(model6.Variables().at("generation"), "generation", "0", @@ -492,15 +419,14 @@ BOOST_AUTO_TEST_CASE(test_full) "generation >= nb_on * p_min"); checkConstraint(model6.getConstraints().at("Number of units variation"), "Number of units variation", - "nb_on = nb_on[t-1] + nb_start - nb_stop"); + "nb_on = nb_on + nb_start - nb_stop"); checkConstraint(model6.getConstraints().at("Min up time"), "Min up time", - "sum(t-d_min_up + 1 .. t, nb_start) <= nb_on"); - checkConstraint( - model6.getConstraints().at("Min down time"), - "Min down time", - "sum(t-d_min_down + 1 .. t, nb_stop) <= nb_units_max[t-d_min_down] - nb_on"); - BOOST_CHECK_EQUAL(model6.Objective().Value(), "expec(sum(cost * generation))"); + "t-d_min_up + 1 <= nb_on"); + checkConstraint(model6.getConstraints().at("Min down time"), + "Min down time", + "t-d_min_down + 1 <= nb_units_max - nb_on"); + BOOST_CHECK_EQUAL(model6.Objective().Value(), "cost * generation"); } catch (const YAML::Exception& e) { diff --git a/src/vcpkg.json b/src/vcpkg.json index a4a3e12fcf..68a34fa53c 100644 --- a/src/vcpkg.json +++ b/src/vcpkg.json @@ -37,6 +37,9 @@ }, { "name": "yaml-cpp" + }, + { + "name": "antlr4" } ] } From 2f983591866f7116b5c3e12c8e4b8bdeb0efb1ce Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Tue, 26 Nov 2024 13:12:33 +0100 Subject: [PATCH 059/103] New System model (2.2) [ANT-2208] (#2500) --- src/study/system-model/CMakeLists.txt | 4 + src/study/system-model/component.cpp | 126 +++++++++++ .../antares/study/system-model/component.h | 96 +++++++++ .../antares/study/system-model/system.h | 79 +++++++ src/study/system-model/system.cpp | 89 ++++++++ src/tests/src/CMakeLists.txt | 2 + src/tests/src/study/CMakeLists.txt | 1 + .../src/study/system-model/CMakeLists.txt | 19 ++ .../src/study/system-model/test_component.cpp | 198 ++++++++++++++++++ .../src/study/system-model/test_main.cpp | 25 +++ .../src/study/system-model/test_system.cpp | 98 +++++++++ src/tests/src/utils/unit_test_utils.h | 38 ++++ 12 files changed, 775 insertions(+) create mode 100644 src/study/system-model/component.cpp create mode 100644 src/study/system-model/include/antares/study/system-model/component.h create mode 100644 src/study/system-model/include/antares/study/system-model/system.h create mode 100644 src/study/system-model/system.cpp create mode 100644 src/tests/src/study/CMakeLists.txt create mode 100644 src/tests/src/study/system-model/CMakeLists.txt create mode 100644 src/tests/src/study/system-model/test_component.cpp create mode 100644 src/tests/src/study/system-model/test_main.cpp create mode 100644 src/tests/src/study/system-model/test_system.cpp create mode 100644 src/tests/src/utils/unit_test_utils.h diff --git a/src/study/system-model/CMakeLists.txt b/src/study/system-model/CMakeLists.txt index e9a7348534..19cbfa7abb 100644 --- a/src/study/system-model/CMakeLists.txt +++ b/src/study/system-model/CMakeLists.txt @@ -3,6 +3,8 @@ project(SystemModel) set(SRC_model library.cpp model.cpp + component.cpp + system.cpp include/antares/study/system-model/library.h include/antares/study/system-model/model.h include/antares/study/system-model/parameter.h @@ -14,6 +16,8 @@ set(SRC_model include/antares/study/system-model/portField.h include/antares/study/system-model/portFieldDefinition.h include/antares/study/system-model/portType.h + include/antares/study/system-model/component.h + include/antares/study/system-model/system.h ) source_group("SystemModel" FILES ${SRC_model}) diff --git a/src/study/system-model/component.cpp b/src/study/system-model/component.cpp new file mode 100644 index 0000000000..b9b7c6a03b --- /dev/null +++ b/src/study/system-model/component.cpp @@ -0,0 +1,126 @@ +/* +** 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 + +#include + +namespace Antares::Study::SystemModel +{ + +static void checkComponentDataValidity(const ComponentData& data) +{ + // Check that mandatory attributes are not empty + if (data.id.empty()) + { + throw std::invalid_argument("A component can't have an empty id"); + } + if (data.model == nullptr) + { + throw std::invalid_argument("A component can't have an empty model"); + } + if (data.scenario_group_id.empty()) + { + throw std::invalid_argument("A component can't have an empty scenario_group_id"); + } + // Check that parameters values are coherent with the model + if (data.model->Parameters().size() != data.parameter_values.size()) + { + throw std::invalid_argument( + "The component has " + std::to_string(data.parameter_values.size()) + + " parameter(s), but its model has " + std::to_string(data.model->Parameters().size())); + } + for (const auto param: data.model->Parameters() | std::views::keys) + { + if (!data.parameter_values.contains(param)) + { + throw std::invalid_argument("The component has no value for parameter '" + param + "'"); + } + } +} + +Component::Component(const ComponentData& component_data) +{ + checkComponentDataValidity(component_data); + data_ = std::move(component_data); +} + +/** + * \brief Sets the ID of the component. + * + * \param id The ID to set. + * \return Reference to the ComponentBuilder object. + */ +ComponentBuilder& ComponentBuilder::withId(const std::string_view id) +{ + data_.id = id; + return *this; +} + +/** + * \brief Sets the model of the component. + * + * \param model The model to set. + * \return Reference to the ComponentBuilder object. + */ +ComponentBuilder& ComponentBuilder::withModel(Model* model) +{ + data_.model = model; + return *this; +} + +/** + * \brief Sets the parameter values of the component. The parameters included should be all of the + * model's parameters. + * + * \param parameter_values The map of parameter values to set. + * \return Reference to the ComponentBuilder object. + */ +ComponentBuilder& ComponentBuilder::withParameterValues( + std::map parameter_values) +{ + data_.parameter_values = std::move(parameter_values); + return *this; +} + +/** + * \brief Sets the ID of the scenario group to which the component belongs. + * + * \param scenario_group_id The scenario group ID to set. + * \return Reference to the ComponentBuilder object. + */ +ComponentBuilder& ComponentBuilder::withScenarioGroupId(const std::string& scenario_group_id) +{ + data_.scenario_group_id = scenario_group_id; + return *this; +} + +/** + * \brief Builds and returns the Component object. + * + * \return The constructed Component object. + */ +Component ComponentBuilder::build() const +{ + return Component(data_); +} + +} // namespace Antares::Study::SystemModel diff --git a/src/study/system-model/include/antares/study/system-model/component.h b/src/study/system-model/include/antares/study/system-model/component.h new file mode 100644 index 0000000000..d3be08ba80 --- /dev/null +++ b/src/study/system-model/include/antares/study/system-model/component.h @@ -0,0 +1,96 @@ +/* +** 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 "model.h" + +namespace Antares::Study::SystemModel +{ + +/** + * Defines the attributes of the Component class + * Made into a struct to avoid duplication in ComponentBuilder + */ +struct ComponentData +{ + std::string id; + Model* model = nullptr; + std::map parameter_values; + std::string scenario_group_id; +}; + +/** + * Defines an actual component of the simulated system. + */ +class Component +{ +public: + // Only allowing one private constructor (see below) to forbid empty Components + Component() = delete; + + const std::string& Id() const + { + return data_.id; + } + + Model* getModel() const + { + return data_.model; + } + + double getParameterValue(const std::string& parameter_id) const + { + if (!data_.parameter_values.contains(parameter_id)) + { + throw std::invalid_argument("Parameter '" + parameter_id + "' not found in component '" + + data_.id + "'"); + } + return data_.parameter_values.at(parameter_id); + } + + std::string getScenarioGroupId() const + { + return data_.scenario_group_id; + } + +private: + // Only ComponentBuilder is allowed to build Component instances + friend class ComponentBuilder; + explicit Component(const ComponentData& component_data); + ComponentData data_; +}; + +class ComponentBuilder +{ +public: + ComponentBuilder& withId(std::string_view id); + ComponentBuilder& withModel(Model* model); + ComponentBuilder& withParameterValues(std::map parameter_values); + ComponentBuilder& withScenarioGroupId(const std::string& scenario_group_id); + Component build() const; + +private: + ComponentData data_; +}; + +} // namespace Antares::Study::SystemModel diff --git a/src/study/system-model/include/antares/study/system-model/system.h b/src/study/system-model/include/antares/study/system-model/system.h new file mode 100644 index 0000000000..50fa196399 --- /dev/null +++ b/src/study/system-model/include/antares/study/system-model/system.h @@ -0,0 +1,79 @@ +/* +** 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 "component.h" + +namespace Antares::Study::SystemModel +{ + +/** + * Defines the attributes of the System class + * Made into a struct to avoid duplication in SystemBuilder + */ +struct SystemData +{ +}; + +/** + * Defines the simulated system. + */ +class System +{ +public: + // Only allowing one private constructor (see below) to forbid empty Systems + System() = delete; + System(System& other) = delete; + + const std::string& Id() const + { + return id_; + } + + const std::unordered_map& Components() const + { + return components_; + } + +private: + // Only SystemBuilder is allowed to build System instances + friend class SystemBuilder; + System(std::string_view id, std::vector components); + std::string id_; + std::unordered_map components_; + std::pair makeComponent(Component& component) const; +}; + +class SystemBuilder +{ +public: + SystemBuilder& withId(std::string_view id); + SystemBuilder& withComponents(std::vector&& components); + System build() const; + +private: + std::string id_; + std::vector components_; +}; + +} // namespace Antares::Study::SystemModel diff --git a/src/study/system-model/system.cpp b/src/study/system-model/system.cpp new file mode 100644 index 0000000000..20a26287e1 --- /dev/null +++ b/src/study/system-model/system.cpp @@ -0,0 +1,89 @@ +/* +** 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 + +#include + +namespace Antares::Study::SystemModel +{ +System::System(const std::string_view id, std::vector components): + id_(id) +{ + // Check that mandatory attributes are not empty + if (id.empty()) + { + throw std::invalid_argument("A system can't have an empty id"); + } + if (components.empty()) + { + throw std::invalid_argument("A system must contain at least one component"); + } + std::ranges::transform(components, + std::inserter(components_, components_.end()), + [this](/*Non const to prevent copy*/ Component& component) + { return makeComponent(component); }); +} + +std::pair System::makeComponent(Component& component) const +{ + if (components_.contains(component.Id())) + { + throw std::invalid_argument("System has at least two components with the same id ('" + + component.Id() + "'), this is not supported"); + } + return std::make_pair(component.Id(), std::move(component)); +} + +/** + * \brief Sets the ID of the system. + * + * \param id The ID to set. + * \return Reference to the SystemBuilder object. + */ +SystemBuilder& SystemBuilder::withId(std::string_view id) +{ + id_ = id; + return *this; +} + +/** + * \brief Sets the components of the system. + * + * \param components A vector of components to set. + * \return Reference to the SystemBuilder object. + */ +SystemBuilder& SystemBuilder::withComponents(std::vector&& components) +{ + components_ = std::move(components); + return *this; +} + +/** + * \brief Builds and returns the System object. + * + * \return The constructed System object. + */ +System SystemBuilder::build() const +{ + return System(id_, components_); +} +} // namespace Antares::Study::SystemModel diff --git a/src/tests/src/CMakeLists.txt b/src/tests/src/CMakeLists.txt index 14c9929f56..02418c5997 100644 --- a/src/tests/src/CMakeLists.txt +++ b/src/tests/src/CMakeLists.txt @@ -5,3 +5,5 @@ add_subdirectory(utils) add_subdirectory(libs) add_subdirectory(solver) + +add_subdirectory(study) diff --git a/src/tests/src/study/CMakeLists.txt b/src/tests/src/study/CMakeLists.txt new file mode 100644 index 0000000000..78be5cda71 --- /dev/null +++ b/src/tests/src/study/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(system-model) \ No newline at end of file diff --git a/src/tests/src/study/system-model/CMakeLists.txt b/src/tests/src/study/system-model/CMakeLists.txt new file mode 100644 index 0000000000..c24ea1e68d --- /dev/null +++ b/src/tests/src/study/system-model/CMakeLists.txt @@ -0,0 +1,19 @@ +set(EXECUTABLE_NAME test-system-model) +add_executable(${EXECUTABLE_NAME}) + +target_sources(${EXECUTABLE_NAME} + PRIVATE + test_main.cpp + test_component.cpp + test_system.cpp +) + +target_link_libraries(${EXECUTABLE_NAME} + PRIVATE + Boost::unit_test_framework + antares-study-system-model +) + +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) +add_test(NAME test-system-model COMMAND ${EXECUTABLE_NAME}) +set_property(TEST test-system-model PROPERTY LABELS unit) diff --git a/src/tests/src/study/system-model/test_component.cpp b/src/tests/src/study/system-model/test_component.cpp new file mode 100644 index 0000000000..e8c69007a9 --- /dev/null +++ b/src/tests/src/study/system-model/test_component.cpp @@ -0,0 +1,198 @@ +/* + * 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 . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include "antares/study/system-model/component.h" + +#include "../../utils/unit_test_utils.h" + +using namespace Antares::Study::SystemModel; + +struct ComponentBuilderCreationFixture +{ + ComponentBuilder component_builder; +}; + +static Model createModelWithParameters() +{ + ModelBuilder model_builder; + return model_builder.withId("model") + .withParameters( + {Parameter("param1", Parameter::TimeDependent::NO, Parameter::ScenarioDependent::NO), + Parameter("param2", Parameter::TimeDependent::NO, Parameter::ScenarioDependent::NO)}) + .build(); +} + +static Model createModelWithoutParameters() +{ + ModelBuilder model_builder; + return model_builder.withId("model").build(); +} + +BOOST_FIXTURE_TEST_SUITE(_Component_, ComponentBuilderCreationFixture) + +BOOST_AUTO_TEST_CASE(nominal_build_with_parameters) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({{"param1", 5}, {"param2", 3}}) + .withScenarioGroupId("scenario_group") + .build(); + BOOST_CHECK_EQUAL(component.Id(), "component"); + BOOST_CHECK_EQUAL(component.getModel(), &model); + BOOST_CHECK_EQUAL(component.getParameterValue("param1"), 5); + BOOST_CHECK_EQUAL(component.getParameterValue("param2"), 3); + BOOST_CHECK_EXCEPTION(component.getParameterValue("param3"), + std::invalid_argument, + checkMessage("Parameter 'param3' not found in component 'component'")); + BOOST_CHECK_EQUAL(component.getScenarioGroupId(), "scenario_group"); +} + +BOOST_AUTO_TEST_CASE(nominal_build_without_parameters1) +{ + Model model = createModelWithoutParameters(); + auto component = component_builder.withId("component2") + .withModel(&model) + .withParameterValues({}) + .withScenarioGroupId("scenario_group2") + .build(); + BOOST_CHECK_EQUAL(component.Id(), "component2"); + BOOST_CHECK_EQUAL(component.getModel(), &model); + BOOST_CHECK_EXCEPTION(component.getParameterValue("param1"), + std::invalid_argument, + checkMessage("Parameter 'param1' not found in component 'component2'")); + BOOST_CHECK_EQUAL(component.getScenarioGroupId(), "scenario_group2"); +} + +BOOST_AUTO_TEST_CASE(nominal_build_without_parameters2) +{ + Model model = createModelWithoutParameters(); + auto component = component_builder.withId("component3") + .withModel(&model) + .withScenarioGroupId("scenario_group3") + .build(); + BOOST_CHECK_EQUAL(component.Id(), "component3"); + BOOST_CHECK_EQUAL(component.getModel(), &model); + BOOST_CHECK_EQUAL(component.getScenarioGroupId(), "scenario_group3"); +} + +BOOST_AUTO_TEST_CASE(fail_on_no_id) +{ + Model model = createModelWithoutParameters(); + auto component = component_builder.withModel(&model).withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("A component can't have an empty id")); +} + +BOOST_AUTO_TEST_CASE(fail_on_no_model) +{ + auto component = component_builder.withId("component").withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("A component can't have an empty model")); +} + +BOOST_AUTO_TEST_CASE(fail_on_no_scenario_group_id) +{ + Model model = createModelWithoutParameters(); + auto component = component_builder.withId("component").withModel(&model); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("A component can't have an empty scenario_group_id")); +} + +BOOST_AUTO_TEST_CASE(fail_on_no_params1) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has 0 parameter(s), but its model has 2")); +} + +BOOST_AUTO_TEST_CASE(fail_on_no_params2) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({}) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has 0 parameter(s), but its model has 2")); +} + +BOOST_AUTO_TEST_CASE(fail_on_missing_param) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({{"param2", 3}}) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has 1 parameter(s), but its model has 2")); +} + +BOOST_AUTO_TEST_CASE(fail_on_missing_wrong_param) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({{"param_1", 3}, {"param2", 3}}) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has no value for parameter 'param1'")); +} + +BOOST_AUTO_TEST_CASE(fail_on_too_many_params1) +{ + Model model = createModelWithParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({{"param1", 3}, {"param2", 3}, {"param3", 3}}) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has 3 parameter(s), but its model has 2")); +} + +BOOST_AUTO_TEST_CASE(fail_on_too_many_params2) +{ + Model model = createModelWithoutParameters(); + auto component = component_builder.withId("component") + .withModel(&model) + .withParameterValues({{"param1", 3}}) + .withScenarioGroupId("scenario_group"); + BOOST_CHECK_EXCEPTION(component_builder.build(), + std::invalid_argument, + checkMessage("The component has 1 parameter(s), but its model has 0")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/study/system-model/test_main.cpp b/src/tests/src/study/system-model/test_main.cpp new file mode 100644 index 0000000000..85475f9418 --- /dev/null +++ b/src/tests/src/study/system-model/test_main.cpp @@ -0,0 +1,25 @@ +/* + * 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 . + */ + +#define BOOST_TEST_MODULE systemModel +#define WIN32_LEAN_AND_MEAN + +#include diff --git a/src/tests/src/study/system-model/test_system.cpp b/src/tests/src/study/system-model/test_system.cpp new file mode 100644 index 0000000000..9500b6118b --- /dev/null +++ b/src/tests/src/study/system-model/test_system.cpp @@ -0,0 +1,98 @@ +/* + * 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 . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include "antares/study/system-model/system.h" + +#include "../../utils/unit_test_utils.h" + +using namespace Antares::Study::SystemModel; + +struct SystemBuilderCreationFixture +{ + SystemBuilder system_builder; +}; + +static Component createComponent(std::string id) +{ + ModelBuilder model_builder; + auto model = model_builder.withId("model").build(); + ComponentBuilder component_builder; + auto component = component_builder.withId(id) + .withModel(&model) + .withScenarioGroupId("scenario_group") + .build(); + return component; +} + +BOOST_AUTO_TEST_SUITE(_System_) + +BOOST_FIXTURE_TEST_CASE(nominal_build, SystemBuilderCreationFixture) +{ + auto system = system_builder.withId("system") + .withComponents({createComponent("component1"), createComponent("component2")}) + .build(); + BOOST_CHECK_EQUAL(system.Id(), "system"); + BOOST_CHECK_EQUAL(system.Components().size(), 2); + BOOST_CHECK_EQUAL(system.Components().at("component1").Id(), "component1"); + BOOST_CHECK_EQUAL(system.Components().at("component2").Id(), "component2"); +} + +BOOST_FIXTURE_TEST_CASE(fail_on_no_id, SystemBuilderCreationFixture) +{ + system_builder.withComponents({createComponent("component1"), createComponent("component2")}); + BOOST_CHECK_EXCEPTION(system_builder.build(), + std::invalid_argument, + checkMessage("A system can't have an empty id")); +} + +BOOST_FIXTURE_TEST_CASE(fail_on_no_component1, SystemBuilderCreationFixture) +{ + system_builder.withId("system"); + BOOST_CHECK_EXCEPTION(system_builder.build(), + std::invalid_argument, + checkMessage("A system must contain at least one component")); +} + +BOOST_FIXTURE_TEST_CASE(fail_on_no_component2, SystemBuilderCreationFixture) +{ + system_builder.withId("system").withComponents({}); + BOOST_CHECK_EXCEPTION(system_builder.build(), + std::invalid_argument, + checkMessage("A system must contain at least one component")); +} + +BOOST_FIXTURE_TEST_CASE(fail_on_components_with_same_id, SystemBuilderCreationFixture) +{ + system_builder.withId("system").withComponents({}).withComponents( + {createComponent("component1"), + createComponent("component2"), + createComponent("component2")}); + BOOST_CHECK_EXCEPTION(system_builder.build(), + std::invalid_argument, + checkMessage("System has at least two components with the same id " + "('component2'), this is not supported")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/utils/unit_test_utils.h b/src/tests/src/utils/unit_test_utils.h new file mode 100644 index 0000000000..3fe0389f2e --- /dev/null +++ b/src/tests/src/utils/unit_test_utils.h @@ -0,0 +1,38 @@ +/* + * 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 + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +inline std::function checkMessage(std::string expected_message) +{ + auto predicate = [expected_message](const std::exception& e) + { + BOOST_CHECK_EQUAL(e.what(), expected_message); + return true; + }; + return predicate; +} From 7507ed8fe9f87dc9f5b4d53e39597f31163947a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Tue, 26 Nov 2024 15:05:11 +0100 Subject: [PATCH 060/103] Use thread-safe version of localtime (#2503) `std::localtime` isn't guaranteed to be thead-safe, since it relies on a globally defined buffer. We use variants based on local variables instead. --- src/libs/antares/utils/utils.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libs/antares/utils/utils.cpp b/src/libs/antares/utils/utils.cpp index fc8ef1d309..c2c1286021 100644 --- a/src/libs/antares/utils/utils.cpp +++ b/src/libs/antares/utils/utils.cpp @@ -99,8 +99,14 @@ void BeautifyName(std::string& out, const std::string& oldname) std::tm getCurrentTime() { using namespace std::chrono; - auto time = system_clock::to_time_t(system_clock::now()); - return *std::localtime(&time); + auto now = system_clock::to_time_t(system_clock::now()); + std::tm local_time; +#ifdef _WIN32 + localtime_s(&local_time, &now); // Windows +#else + localtime_r(&now, &local_time); // POSIX +#endif + return local_time; } std::string formatTime(const std::tm& localTime, const std::string& format) From 88c711a474baa2f807081a53a223904430f65da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Tue, 26 Nov 2024 15:44:51 +0100 Subject: [PATCH 061/103] Allow the passing of optimization options through the API (#2502) - Add an `OptimizationOptions` argument to public function `PerformSimulation` - Add an `OptimizationOptions` argument to private methods `API::run` and `API::execute` - In the existing tests, use the default instance for `OptimizationOptions`, that is ```cpp struct OptimizationOptions { //! Force ortools use bool ortoolsUsed = false; //! The solver name, sirius is the default std::string ortoolsSolver = "sirius"; bool solverLogs = false; std::string solverParameters; }; ``` - Add a test with COIN - Move headers around (remove unused logs.h causing issues, etc.) --------- Co-authored-by: Peter Mitri --- src/api/API.cpp | 16 ++++--- src/api/CMakeLists.txt | 3 +- src/api/include/antares/api/solver.h | 7 ++- src/api/private/API.h | 7 ++- src/api/solver.cpp | 6 ++- src/api_client_example/src/API_client.cpp | 7 ++- .../antares/exception/AssertionError.hpp | 2 - .../optimization-options/CMakeLists.txt | 3 ++ .../antares/optimization-options/options.h | 2 +- src/solver/misc/options.cpp | 1 - .../modeler/ortoolsImpl/linearProblem.cpp | 1 + src/solver/utils/ortools_utils.cpp | 37 ++++++++------- src/tests/src/api_internal/CMakeLists.txt | 1 + src/tests/src/api_internal/test_api.cpp | 45 +++++++++++++++++-- src/tests/src/api_lib/test_api.cpp | 2 +- .../src/study/system-model/CMakeLists.txt | 1 + src/tests/src/utils/CMakeLists.txt | 6 +++ src/tests/src/utils/unit_test_utils.cpp | 13 ++++++ src/tests/src/utils/unit_test_utils.h | 15 +------ 19 files changed, 121 insertions(+), 54 deletions(-) create mode 100644 src/tests/src/utils/unit_test_utils.cpp diff --git a/src/api/API.cpp b/src/api/API.cpp index c1ba723925..7bcda34502 100644 --- a/src/api/API.cpp +++ b/src/api/API.cpp @@ -32,7 +32,9 @@ namespace Antares::API { -SimulationResults APIInternal::run(const IStudyLoader& study_loader) +SimulationResults APIInternal::run( + const IStudyLoader& study_loader, + const Antares::Solver::Optimization::OptimizationOptions& optOptions) { try { @@ -43,7 +45,7 @@ SimulationResults APIInternal::run(const IStudyLoader& study_loader) Antares::API::Error err{.reason = e.what()}; return {.simulationPath = "", .antares_problems = {}, .error = err}; } - return execute(); + return execute(optOptions); } /** @@ -53,7 +55,8 @@ SimulationResults APIInternal::run(const IStudyLoader& study_loader) * This method is initialy a copy of Application::execute with some modifications hence the apparent * dupllication */ -SimulationResults APIInternal::execute() const +SimulationResults APIInternal::execute( + const Antares::Solver::Optimization::OptimizationOptions& optOptions) const { // study_ == nullptr e.g when the -h flag is given if (!study_) @@ -63,17 +66,16 @@ SimulationResults APIInternal::execute() const return {.simulationPath{}, .antares_problems{}, .error = err}; } - // Only those two fields are used un simulation Settings settings; - settings.tsGeneratorsOnly = false; - settings.noOutput = false; + auto& parameters = study_->parameters; + parameters.optOptions = optOptions; Benchmarking::DurationCollector durationCollector; Benchmarking::OptimizationInfo optimizationInfo; auto ioQueueService = std::make_shared(); ioQueueService->maximumThreadCount(1); ioQueueService->start(); - auto resultWriter = Solver::resultWriterFactory(study_->parameters.resultFormat, + auto resultWriter = Solver::resultWriterFactory(parameters.resultFormat, study_->folderOutput, ioQueueService, durationCollector); diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index 109c640578..aa542c3701 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -30,11 +30,12 @@ target_include_directories(solver_api target_link_libraries(solver_api PRIVATE + Antares::file-tree-study-loader Antares::study Antares::study-loader - Antares::file-tree-study-loader antares-solver-simulation PUBLIC + Antares::optimization-options Antares::lps ) install(DIRECTORY include/antares diff --git a/src/api/include/antares/api/solver.h b/src/api/include/antares/api/solver.h index d016a9a08a..a8279c00c8 100644 --- a/src/api/include/antares/api/solver.h +++ b/src/api/include/antares/api/solver.h @@ -21,6 +21,9 @@ */ #pragma once + +#include + #include "SimulationResults.h" namespace Antares::API @@ -31,5 +34,7 @@ namespace Antares::API * @return SimulationResults object which contains the results of the simulation. * @exception noexcept This function does not throw exceptions. */ -SimulationResults PerformSimulation(const std::filesystem::path& study_path) noexcept; +SimulationResults PerformSimulation( + const std::filesystem::path& study_path, + const Antares::Solver::Optimization::OptimizationOptions& optOptions) noexcept; } // namespace Antares::API diff --git a/src/api/private/API.h b/src/api/private/API.h index 91f8a4e2d3..3561f6d21b 100644 --- a/src/api/private/API.h +++ b/src/api/private/API.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include "antares/api/SimulationResults.h" @@ -46,11 +47,13 @@ class APIInternal * load the study that will be simulated. * @return SimulationResults object which contains the results of the simulation. */ - SimulationResults run(const IStudyLoader& study_loader); + SimulationResults run(const IStudyLoader& study_loader, + const Antares::Solver::Optimization::OptimizationOptions& optOptions); private: std::shared_ptr study_; - SimulationResults execute() const; + SimulationResults execute( + const Antares::Solver::Optimization::OptimizationOptions& optOptions) const; }; } // namespace Antares::API diff --git a/src/api/solver.cpp b/src/api/solver.cpp index 6e2f7068ea..4e65696f8a 100644 --- a/src/api/solver.cpp +++ b/src/api/solver.cpp @@ -28,13 +28,15 @@ namespace Antares::API { -SimulationResults PerformSimulation(const std::filesystem::path& study_path) noexcept +SimulationResults PerformSimulation( + const std::filesystem::path& study_path, + const Antares::Solver::Optimization::OptimizationOptions& optOptions) noexcept { try { APIInternal api; FileTreeStudyLoader study_loader(study_path); - return api.run(study_loader); + return api.run(study_loader, optOptions); } catch (const std::exception& e) { diff --git a/src/api_client_example/src/API_client.cpp b/src/api_client_example/src/API_client.cpp index 6489806c51..9cb19d8e59 100644 --- a/src/api_client_example/src/API_client.cpp +++ b/src/api_client_example/src/API_client.cpp @@ -19,12 +19,11 @@ * along with Antares_Simulator. If not, see . */ - #include "API_client.h" #include -Antares::API::SimulationResults solve(std::filesystem::path study_path) { - return Antares::API::PerformSimulation(std::move(study_path)); +Antares::API::SimulationResults solve(std::filesystem::path study_path) +{ + return Antares::API::PerformSimulation(std::move(study_path), {}); } - diff --git a/src/libs/antares/exception/include/antares/exception/AssertionError.hpp b/src/libs/antares/exception/include/antares/exception/AssertionError.hpp index 7fafaeffc3..e90cc23a7c 100644 --- a/src/libs/antares/exception/include/antares/exception/AssertionError.hpp +++ b/src/libs/antares/exception/include/antares/exception/AssertionError.hpp @@ -31,8 +31,6 @@ class AssertionError: public std::runtime_error { public: explicit AssertionError(const std::string& message); - - ~AssertionError() noexcept override = default; }; } // namespace Data diff --git a/src/libs/antares/optimization-options/CMakeLists.txt b/src/libs/antares/optimization-options/CMakeLists.txt index 3d507b7e5c..106fafdc9f 100644 --- a/src/libs/antares/optimization-options/CMakeLists.txt +++ b/src/libs/antares/optimization-options/CMakeLists.txt @@ -8,3 +8,6 @@ target_include_directories(${PROJ} ) add_library(Antares::${PROJ} ALIAS ${PROJ}) + +install(DIRECTORY include/antares + DESTINATION "include") diff --git a/src/libs/antares/optimization-options/include/antares/optimization-options/options.h b/src/libs/antares/optimization-options/include/antares/optimization-options/options.h index 893c1b1c21..d1e60353ab 100644 --- a/src/libs/antares/optimization-options/include/antares/optimization-options/options.h +++ b/src/libs/antares/optimization-options/include/antares/optimization-options/options.h @@ -20,7 +20,7 @@ */ #pragma once -#include +#include namespace Antares::Solver::Optimization { diff --git a/src/solver/misc/options.cpp b/src/solver/misc/options.cpp index dba4f2230a..8cf5d190e3 100644 --- a/src/solver/misc/options.cpp +++ b/src/solver/misc/options.cpp @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff --git a/src/solver/modeler/ortoolsImpl/linearProblem.cpp b/src/solver/modeler/ortoolsImpl/linearProblem.cpp index 6e8b942945..feba47dda8 100644 --- a/src/solver/modeler/ortoolsImpl/linearProblem.cpp +++ b/src/solver/modeler/ortoolsImpl/linearProblem.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include diff --git a/src/solver/utils/ortools_utils.cpp b/src/solver/utils/ortools_utils.cpp index d45357f382..c72fb67762 100644 --- a/src/solver/utils/ortools_utils.cpp +++ b/src/solver/utils/ortools_utils.cpp @@ -21,8 +21,8 @@ #include "antares/solver/utils/ortools_utils.h" #include +#include -#include #include #include #include "antares/antares/Enum.hpp" @@ -354,33 +354,40 @@ std::string availableOrToolsSolversString() return solvers.str(); } -MPSolver* MPSolverFactory(const bool isMip, const std::string& solverName) +static std::optional translateSolverName(const std::string& solverName, bool isMip) { - MPSolver* solver; try { if (isMip) { - solver = MPSolver::CreateSolver((OrtoolsUtils::solverMap.at(solverName)).MIPSolverName); + return OrtoolsUtils::solverMap.at(solverName).MIPSolverName; } else { - solver = MPSolver::CreateSolver((OrtoolsUtils::solverMap.at(solverName)).LPSolverName); + return OrtoolsUtils::solverMap.at(solverName).LPSolverName; } + } + catch (const std::out_of_range&) + { + return {}; + } +} - if (!solver) - { - std::string msg_to_throw = "Solver " + solverName + " not found. \n"; - msg_to_throw += "Please make sure that your OR-Tools install supports solver " - + solverName + "."; +MPSolver* MPSolverFactory(const bool isMip, const std::string& solverName) +{ + const std::string notFound = "Solver " + solverName + " not found"; + const std::invalid_argument except(notFound); - throw Antares::Data::AssertionError(msg_to_throw); - } + auto internalSolverName = translateSolverName(solverName, isMip); + if (!internalSolverName) + { + throw except; } - catch (...) + + MPSolver* solver = MPSolver::CreateSolver(*internalSolverName); + if (!solver) { - Antares::logs.error() << "Solver creation failed."; - throw; + throw except; } return solver; diff --git a/src/tests/src/api_internal/CMakeLists.txt b/src/tests/src/api_internal/CMakeLists.txt index 2186dc6f4b..1c972cd4c6 100644 --- a/src/tests/src/api_internal/CMakeLists.txt +++ b/src/tests/src/api_internal/CMakeLists.txt @@ -11,6 +11,7 @@ target_link_libraries(${EXECUTABLE_NAME} Boost::unit_test_framework Antares::solver_api Antares::tests::in-memory-study + test_utils_unit ) target_include_directories(${EXECUTABLE_NAME} diff --git a/src/tests/src/api_internal/test_api.cpp b/src/tests/src/api_internal/test_api.cpp index d8b52d3332..082972bcc3 100644 --- a/src/tests/src/api_internal/test_api.cpp +++ b/src/tests/src/api_internal/test_api.cpp @@ -26,6 +26,9 @@ #include +#include + +#include "../../src/utils/unit_test_utils.h" #include "API.h" #include "in-memory-study.h" @@ -60,7 +63,7 @@ BOOST_AUTO_TEST_CASE(simulation_path_points_to_results) { Antares::API::APIInternal api; auto study_loader = std::make_unique(); - auto results = api.run(*study_loader.get()); + auto results = api.run(*study_loader.get(), {}); BOOST_CHECK_EQUAL(results.simulationPath, std::filesystem::path{"no_output"}); // Testing for "no_output" is a bit weird, but it's the only way to test this without actually // running the simulation @@ -70,7 +73,7 @@ BOOST_AUTO_TEST_CASE(api_run_contains_antares_problem) { Antares::API::APIInternal api; auto study_loader = std::make_unique(); - auto results = api.run(*study_loader.get()); + auto results = api.run(*study_loader.get(), {}); BOOST_CHECK(!results.antares_problems.empty()); BOOST_CHECK(!results.error); @@ -80,7 +83,7 @@ BOOST_AUTO_TEST_CASE(result_failure_when_study_is_null) { Antares::API::APIInternal api; auto study_loader = std::make_unique(false); - auto results = api.run(*study_loader.get()); + auto results = api.run(*study_loader.get(), {}); BOOST_CHECK(results.error); } @@ -90,9 +93,43 @@ BOOST_AUTO_TEST_CASE(result_contains_problems) { Antares::API::APIInternal api; auto study_loader = std::make_unique(); - auto results = api.run(*study_loader.get()); + auto results = api.run(*study_loader.get(), {}); + + BOOST_CHECK(!results.antares_problems.empty()); + BOOST_CHECK(!results.error); + BOOST_CHECK_EQUAL(results.antares_problems.weeklyProblems.size(), 52); +} + +// Test where data in problems are consistant with data in study +BOOST_AUTO_TEST_CASE(result_with_ortools_coin) +{ + Antares::API::APIInternal api; + auto study_loader = std::make_unique(); + const Antares::Solver::Optimization::OptimizationOptions opt{.ortoolsUsed = true, + .ortoolsSolver = "coin", + .solverLogs = false, + .solverParameters = ""}; + + auto results = api.run(*study_loader.get(), opt); BOOST_CHECK(!results.antares_problems.empty()); BOOST_CHECK(!results.error); BOOST_CHECK_EQUAL(results.antares_problems.weeklyProblems.size(), 52); } + +// Test where we use an invalid OR-Tools solver +BOOST_AUTO_TEST_CASE(invalid_ortools_solver) +{ + Antares::API::APIInternal api; + auto study_loader = std::make_unique(); + const Antares::Solver::Optimization::OptimizationOptions opt{ + .ortoolsUsed = true, + .ortoolsSolver = "this-solver-does-not-exist", + .solverLogs = true, + .solverParameters = ""}; + + auto shouldThrow = [&api, &study_loader, &opt] { return api.run(*study_loader.get(), opt); }; + BOOST_CHECK_EXCEPTION(shouldThrow(), + std::invalid_argument, + checkMessage("Solver this-solver-does-not-exist not found")); +} diff --git a/src/tests/src/api_lib/test_api.cpp b/src/tests/src/api_lib/test_api.cpp index 0dbddfae7f..c1111b5c6a 100644 --- a/src/tests/src/api_lib/test_api.cpp +++ b/src/tests/src/api_lib/test_api.cpp @@ -29,7 +29,7 @@ BOOST_AUTO_TEST_CASE(result_failure_when_study_path_invalid) { using namespace std::string_literals; - auto results = Antares::API::PerformSimulation("dummy"s); + auto results = Antares::API::PerformSimulation("dummy"s, {}); BOOST_CHECK(results.error); BOOST_CHECK(!results.error->reason.empty()); } diff --git a/src/tests/src/study/system-model/CMakeLists.txt b/src/tests/src/study/system-model/CMakeLists.txt index c24ea1e68d..0f5f956ac8 100644 --- a/src/tests/src/study/system-model/CMakeLists.txt +++ b/src/tests/src/study/system-model/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries(${EXECUTABLE_NAME} PRIVATE Boost::unit_test_framework antares-study-system-model + test_utils_unit ) set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) diff --git a/src/tests/src/utils/CMakeLists.txt b/src/tests/src/utils/CMakeLists.txt index fe3f0a00df..56c38bdaff 100644 --- a/src/tests/src/utils/CMakeLists.txt +++ b/src/tests/src/utils/CMakeLists.txt @@ -1,8 +1,14 @@ add_library(test_utils_unit files-system.cpp files-system.h + unit_test_utils.h + unit_test_utils.cpp ) +target_link_libraries(test_utils_unit + PRIVATE + Boost::unit_test_framework) + target_include_directories( test_utils_unit PUBLIC diff --git a/src/tests/src/utils/unit_test_utils.cpp b/src/tests/src/utils/unit_test_utils.cpp new file mode 100644 index 0000000000..383d5687ad --- /dev/null +++ b/src/tests/src/utils/unit_test_utils.cpp @@ -0,0 +1,13 @@ +#include "unit_test_utils.h" + +#define WIN32_LEAN_AND_MEAN +#include + +std::function checkMessage(std::string expected_message) +{ + return [expected_message](const std::exception& e) + { + BOOST_CHECK_EQUAL(e.what(), expected_message); + return true; + }; +} diff --git a/src/tests/src/utils/unit_test_utils.h b/src/tests/src/utils/unit_test_utils.h index 3fe0389f2e..3cefa738e8 100644 --- a/src/tests/src/utils/unit_test_utils.h +++ b/src/tests/src/utils/unit_test_utils.h @@ -21,18 +21,7 @@ #pragma once -#define WIN32_LEAN_AND_MEAN - +#include #include -#include - -inline std::function checkMessage(std::string expected_message) -{ - auto predicate = [expected_message](const std::exception& e) - { - BOOST_CHECK_EQUAL(e.what(), expected_message); - return true; - }; - return predicate; -} +std::function checkMessage(std::string expected_message); From a7b07023fcd63181b2c1c462faeab00b6ee41e0b Mon Sep 17 00:00:00 2001 From: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:03:52 +0100 Subject: [PATCH 062/103] [ANT-2300] Short-term storage: penalty for storage control, injection and withdrawal flow gradient (#2491) Co-authored-by: Florian OMNES Co-authored-by: Florian OMNES <26088210+flomnes@users.noreply.github.com> --- docs/user-guide/04-migration-guides.md | 251 ++++++++++++++---- .../parts/short-term-storage/properties.h | 3 + .../study/parts/short-term-storage/series.h | 4 + .../parts/short-term-storage/properties.cpp | 12 + .../study/parts/short-term-storage/series.cpp | 15 +- src/solver/optimisation/CMakeLists.txt | 6 + .../constraints/ConstraintBuilder.cpp | 38 ++- .../optimisation/constraints/Group1.cpp | 26 +- .../ShortTermStorageCostVariation.cpp | 48 ++++ ...mStorageCostVariationInjectionBackward.cpp | 50 ++++ ...rmStorageCostVariationInjectionForward.cpp | 50 ++++ ...StorageCostVariationWithdrawalBackward.cpp | 49 ++++ ...mStorageCostVariationWithdrawalForward.cpp | 52 ++++ .../constraints/ConstraintBuilder.h | 25 +- .../solver/optimisation/constraints/Group1.h | 2 +- .../ShortTermStorageCostVariation.h | 102 +++++++ .../constraints/ShortTermStorageLevel.h | 11 +- .../solver/optimisation/opt_rename_problem.h | 8 + ...truction_variables_optimisees_lineaire.cpp | 23 ++ .../opt_decompte_variables_et_contraintes.cpp | 44 ++- .../opt_gestion_des_bornes_cas_lineaire.cpp | 21 ++ .../opt_gestion_des_couts_cas_lineaire.cpp | 17 ++ ...opt_gestion_second_membre_cas_lineaire.cpp | 4 +- .../optimisation/opt_rename_problem.cpp | 24 ++ .../variables/VariableManagement.cpp | 20 ++ .../variables/VariableManagement.h | 8 + .../sim_structure_probleme_economique.h | 8 + .../simulation/sim_alloc_probleme_hebdo.cpp | 14 + .../simulation/sim_calcul_economique.cpp | 2 + .../short-term-storage-input-output.cpp | 93 ++++++- 30 files changed, 944 insertions(+), 86 deletions(-) create mode 100644 src/solver/optimisation/constraints/ShortTermStorageCostVariation.cpp create mode 100644 src/solver/optimisation/constraints/ShortTermStorageCostVariationInjectionBackward.cpp create mode 100644 src/solver/optimisation/constraints/ShortTermStorageCostVariationInjectionForward.cpp create mode 100644 src/solver/optimisation/constraints/ShortTermStorageCostVariationWithdrawalBackward.cpp create mode 100644 src/solver/optimisation/constraints/ShortTermStorageCostVariationWithdrawalForward.cpp create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageCostVariation.h diff --git a/docs/user-guide/04-migration-guides.md b/docs/user-guide/04-migration-guides.md index 2bdc0beb21..23f10a2668 100644 --- a/docs/user-guide/04-migration-guides.md +++ b/docs/user-guide/04-migration-guides.md @@ -1,19 +1,40 @@ # Migration guides -This is a list of all recent changes that came with new Antares Simulator features. The main goal of this document is to lower the costs of changing existing interfaces, both GUI and scripts. + +This is a list of all recent changes that came with new Antares Simulator features. The main goal of this document is to +lower the costs of changing existing interfaces, both GUI and scripts. ## v9.2.0 + ### Input + #### Removed properties + The following properties were removed from **settings/generaldata.ini**. + - `adequacy patch/enable-first-step` - `adequacy patch/set-to-null-ntc-between-physical-out-for-first-step` - `other preferences/initial-reservoir-levels` + #### Short-term storages -- Added property `efficiencywithdrawal` (double in [0, 1], default 1) short-term storages (file input/st-storage/clusters//list.ini) -- Added timeseries cost-injection.txt, cost-withdrawal.txt and cost-level.txt. These files are optional. If present, they must contain either no value (same behavior as no file), or HOURS_PER_YEAR = 8760 coefficients in one column. Each of these timeseries is located in directory input/st-storage/series///, along existing series (rule-curves.txt, etc.). + +- Added properties: + - `efficiencywithdrawal` (double in [0, 1], default 1) short-term storages (file + input/st-storage/clusters//list.ini) + - `penalize-variation-injection` boolean, default false (file + input/st-storage/series//list.ini) + - `penalize-variation-withdrawal` boolean, default false (file + input/st-storage/series//list.ini) + +- Added timeseries cost-injection.txt, cost-withdrawal.txt, cost-level.txt, cost-variation-injection.txt and + cost-variation-withdrawal.txt. These files are optional. If present, they must contain either no value (same behavior + as no file), or HOURS_PER_YEAR = 8760 coefficients in one column. Each of these timeseries is located in directory + input/st-storage/series///, along existing series (rule-curves.txt, etc.). #### Final levels / scenario-builder -- Added optional key type "hfl" (hydro final level) in the scenario builder. The syntax is equivalent to existing prefix "hl" (hydro initial level), that is + +- Added optional key type "hfl" (hydro final level) in the scenario builder. The syntax is equivalent to existing + prefix "hl" (hydro initial level), that is + ``` hl,area, = ``` @@ -21,13 +42,17 @@ hl,area, = By convention, `year` start at 0 and `value` must be in interval [0, 1]. #### Compatibility flag for hydro pmax coefficients -In file settings/generaldata.ini, in section `other preferences`, add property `hydro-pmax-format` with possible values `daily` (default, legacy) and `hourly` (new). -Note: This flag allows to bypass the breaking change that took place in version 9.1 for hydro max powers. It is possible to support only the `legacy` file format. +In file settings/generaldata.ini, in section `other preferences`, add property `hydro-pmax-format` with possible values +`daily` (default, legacy) and `hourly` (new). +Note: This flag allows to bypass the breaking change that took place in version 9.1 for hydro max powers. It is possible +to support only the `legacy` file format. ### (TS-generator only) TS generation for link capacities + In files input/links//properties.ini, add the following properties + - unitcount (unsigned int, default 1) - nominalcapacity (float, default 0) - law.planned (string "uniform"/"geometric", default "uniform") @@ -36,36 +61,51 @@ In files input/links//properties.ini, add the following properties - volatility.forced (same) - force-no-generation (true/false, default true) -- "prepro" timeseries => input/links//prepro/_{direct, indirect}.txt, 365x6 values, respectively "forced outage duration", "planned outage duration", "forced outage rate", "planned outage rate", "minimum of groups in maintenance", "maximum of groups in maintenance". -- "modulation" timeseries => input/links//prepro/_mod_{direct, indirect}.txt, 8760x1 values each in [0, 1] +- "prepro" timeseries => input/links//prepro/_{direct, indirect}.txt, 365x6 values, respectively "forced + outage duration", "planned outage duration", "forced outage rate", "planned outage rate", "minimum of groups in + maintenance", "maximum of groups in maintenance". +- "modulation" timeseries => input/links//prepro/_mod_{direct, indirect}.txt, 8760x1 values each + in [0, 1] - number of TS to generate => generaldata.ini/General/nbtimeserieslinks (unsigned int, default value 1) - ### Input + #### Hydro Final Reservoir Level -In the existing file **settings/scenariobuilder.dat**, under **<ruleset>** section following properties added (if final reservoir level specified, different from `init`): + +In the existing file **settings/scenariobuilder.dat**, under **<ruleset>** section following properties added (if +final reservoir level specified, different from `init`): + * **hfl,<area>,<year> = <hfl-value>** ### Output + - Remove column SPIL ENRG CSR (adequacy patch) - Add DTG MRG CSR and UNSP ENRG CSR variables ## v9.1.0 -### Input + +### Input + #### Hydro Maximum Generation/Pumping Power -* For time series ![Migration diagram](img/migration.png "Migration diagram"), for more details, see [this Python script](img/migration.py) -Regarding Hydro time-series, the scenario builder allows the user to choose, for a given year and area, a different time series whether we consider : +* For time series ![Migration diagram](img/migration.png "Migration diagram"), for more details, + see [this Python script](img/migration.py) + +Regarding Hydro time-series, the scenario builder allows the user to choose, for a given year and area, a different time +series whether we consider : + - inflows, ROR and minimum generation, max pumping & generation (prefix "h") - initial level (prefix "hl") -This implies that, inside one of the previous categories, the number of available time series is the same + This implies that, inside one of the previous categories, the number of available time series is the same ![Logic changes](img/logic-hydro-maxP.png "Logic changes") #### Short term storage groups + STS groups in input are now "dynamic" : group names are no longer fixed by code, user is free to define these groups. -In the "thematic trimming" section, the new dynamic variable `STS by group` is now used to enable/disable all variables (level/injection/withdrawal) for all groups. The following variables are obsolete and must not be provided +In the "thematic trimming" section, the new dynamic variable `STS by group` is now used to enable/disable all +variables (level/injection/withdrawal) for all groups. The following variables are obsolete and must not be provided ``` PSP_open_injection @@ -81,42 +121,60 @@ Other5_injection Other5_withdral Other5_level ``` + (3*9=27 variables in total) The default value for group is "OTHER1". ### Output + #### ST Storage -- Output columns for ST storage are capitalized. For any STS group name my_group, 3 output columns are created : `MY_GROUP_INJECTION`, `MY_GROUP_WITHDRAWAL`, `MY_GROUP_LEVEL`. +- Output columns for ST storage are capitalized. For any STS group name my_group, 3 output columns are created : + `MY_GROUP_INJECTION`, `MY_GROUP_WITHDRAWAL`, `MY_GROUP_LEVEL`. - If a group is empty, no column is produced. -- There is now a variable number of columns in files values-XXX.txt, depending on the groups of ST storages provided by the user. Note that groups are case-insensitive, for example `battery`, `Battery` and `BATTERY` all represent the same group. If no ST storage exist for a given area, no variables associated to ST storages will be produced. +- There is now a variable number of columns in files values-XXX.txt, depending on the groups of ST storages provided by + the user. Note that groups are case-insensitive, for example `battery`, `Battery` and `BATTERY` all represent the same + group. If no ST storage exist for a given area, no variables associated to ST storages will be produced. ## v9.0.0 + ### Input + #### Study version + Breaking change in the study format, file **study.antares** + ``` version = 900 ``` + becomes + ``` version = 9.0 ``` -Compatibility is kept with versions up to 8.8.0. Starting from version 9.0.0, the new format must be used. +Compatibility is kept with versions up to 8.8.0. Starting from version 9.0.0, the new format must be used. ## v8.8.0 + ### Input + #### Short-term storage -If no value is specified for `initiallevel`, then a default value of 50% is used. Note that this value is used only if `initialleveloptim=false`, and that `false` is the default value for `initialleveloptim`. -Add property `enabled` (bool, default=`true`). If a ST storage object is not enabled, it is ignored by Antares Simulator. +If no value is specified for `initiallevel`, then a default value of 50% is used. Note that this value is used only if +`initialleveloptim=false`, and that `false` is the default value for `initialleveloptim`. + +Add property `enabled` (bool, default=`true`). If a ST storage object is not enabled, it is ignored by Antares +Simulator. #### Solver logs (expert option) + Save solver logs by setting `solver-logs = true` (default : `false`) under the `optimization` section. #### Experimental "MILP" mode + New value `milp` for existing property `other preferences/unit-commitment-mode` in file **settings/generaldata.ini**. Using this property requires OR-Tools and a MILP solver (XPRESS, COIN) @@ -126,51 +184,75 @@ antares-8.8-solver --use-ortools --ortools-solver coin|xpress ... ``` ### Output + ### Cashflow by short-term storage -In existing file **details-STstorage-<period>.txt** (mc-all & mc-ind), add a new column for each ST storage object, named "STS Cashflow By Cluster", in EURO. + +In existing file **details-STstorage-<period>.txt** (mc-all & mc-ind), add a new column for each ST storage +object, named "STS Cashflow By Cluster", in EURO. ## v8.7.0 + ### Input + #### Scenarized RHS for binding constraints + - For each binding constraint, file **input/bindingconstraints/<id>.txt** is split into 3 files: - **input/bindingconstraints/<id>_lt.txt** - **input/bindingconstraints/<id>_gt.txt** - **input/bindingconstraints/<id>_eq.txt** - Each of these files can be either empty or have N column of 8674 rows + Each of these files can be either empty or have N column of 8674 rows - In file **input/bindingconstraints/bindingconstraints.ini**, add property `group` to every section -- Binding constraints in the same group must have the same number of RHS columns (3 files described above for their respective types). Exception: a constraint in a group can have empty RHS or only one RHS column -- In file **settings/scenariobuilder.dat**, add prefix `bc` for every group of binding constraints. The syntax is the following +- Binding constraints in the same group must have the same number of RHS columns (3 files described above for their + respective types). Exception: a constraint in a group can have empty RHS or only one RHS column +- In file **settings/scenariobuilder.dat**, add prefix `bc` for every group of binding constraints. The syntax is the + following + ``` bc,, = ``` + This line is not mandatory for every group & MC year. If absent, the TS number will be drawn randomly (usual behavior). - 0 <= MC Year < generaldata.ini/general.nbyears - 1 <=TS number <= number of columns for the group #### Thermal cluster new properties -For each thermal cluster, in existing file **input/thermal/clusters/<area>/list.ini**, under existing sections **<cluster>**, following properties added: -* `costgeneration` [string] can take values `useCostTimeseries` or be excluded from the section if `SetManually` is selected (default behavior). +For each thermal cluster, in existing file **input/thermal/clusters/<area>/list.ini**, under existing sections * +*<cluster>**, following properties added: + +* `costgeneration` [string] can take values `useCostTimeseries` or be excluded from the section if `SetManually` is + selected (default behavior). * `efficiency` [float] between 0-100 (default = 100). Unit is "percentage". -* `variableomcost` [float] excluded from the section if default value 0 is selected (default behavior). Unit is Euro / MWh +* `variableomcost` [float] excluded from the section if default value 0 is selected (default behavior). Unit is Euro / + MWh -For each thermal cluster, new files added **input/thermal/series/<area>/<cluster>/CO2Cost.txt** and **input/thermal/series/<area>/<cluster>/fuelCost.txt**. **fuelCost.txt** and **CO2Cost.txt** must either have one column, or the same number of columns as existing file **series.txt** (availability). The number of rows for these new matrices is 8760. +For each thermal cluster, new files added **input/thermal/series/<area>/<cluster>/CO2Cost.txt** and * +*input/thermal/series/<area>/<cluster>/fuelCost.txt**. **fuelCost.txt** and **CO2Cost.txt** must either have +one column, or the same number of columns as existing file **series.txt** (availability). The number of rows for these +new matrices is 8760. ### Output + #### Scenarized RHS for binding constraints -Add directory **bindingconstraints** to output directory **ts-numbers**. For every binding constraint group, add a file **ts-numbers/bindingconstraints/<group>.txt** containing the TS numbers used for that group. + +Add directory **bindingconstraints** to output directory **ts-numbers**. For every binding constraint group, add a file +**ts-numbers/bindingconstraints/<group>.txt** containing the TS numbers used for that group. ## v8.6.0 + ### Input + #### Short-term storage + * Add directories **input/st-storage/clusters** and **input/st-storage/series** * For each area, add directory **input/st-storage/clusters/<area id>/list.ini** * This file contains the multiple sections whose name is ignored. Each section contains these properties: * `name` [str] - * `group` [str]. Possible values: "PSP_open", "PSP_closed", "Pondage", "Battery", "Other1", ... , "Other5". Default Other1 + * `group` [str]. Possible values: "PSP_open", "PSP_closed", "Pondage", "Battery", "Other1", ... , "Other5". Default + Other1 * `efficiency` [double] in range 0-1 * `reservoircapacity` [double] > 0 * `initiallevel` [double] in range 0-1 @@ -178,7 +260,8 @@ Add directory **bindingconstraints** to output directory **ts-numbers**. For eve * `injectionnominalcapacity` [double] > 0 * `initialleveloptim` [bool] -* For each short-term-storage object, add the corresponding time-series in directory **input/st-storage/series/<area id>/<STS id>**. All of these files contain 8760 rows and 1 column. +* For each short-term-storage object, add the corresponding time-series in directory **input/st-storage/series/<area + id>/<STS id>**. All of these files contain 8760 rows and 1 column. * **PMAX-injection.txt** All entries must be in range 0-1 * **PMAX-withdrawal.txt** All entries must be in range 0-1 * **inflows.txt** All entries must be > 0 @@ -186,31 +269,46 @@ Add directory **bindingconstraints** to output directory **ts-numbers**. For eve * **upper-rule-curve.txt** All entries must be in range 0-1 #### Pollutant emission factors -In files **input/thermal/cluster/area/list.ini** add properties `nh3`, `nox`, `pm2_5`, `pm5`, `pm10`, `nmvoc`, `so2`, `op1`, `op2`, `op3`, `op4`, `op5` [double]. These properties are emission factors similar to the existing one for CO2. + +In files **input/thermal/cluster/area/list.ini** add properties `nh3`, `nox`, `pm2_5`, `pm5`, `pm10`, `nmvoc`, `so2`, +`op1`, `op2`, `op3`, `op4`, `op5` [double]. These properties are emission factors similar to the existing one for CO2. #### Adequacy patch -In file **settings/generaldata.ini**, in section `adequacy patch` add property `enable-first-step` [bool]. Default value = `true` Enable or disable DENS column + +In file **settings/generaldata.ini**, in section `adequacy patch` add property `enable-first-step` [bool]. Default +value = `true` Enable or disable DENS column #### Hydro Pmin -For each area, new file added **input/hydro/series/<area>/mingen.txt**. This file has one or more columns, and 8760 rows. The number of columns may be 1, or identical to the number of columns in existing file **mod.txt**. + +For each area, new file added **input/hydro/series/<area>/mingen.txt**. This file has one or more columns, and +8760 rows. The number of columns may be 1, or identical to the number of columns in existing file **mod.txt**. ### Output + #### Short-term storage + * For every short-term storage group, add 3 columns in files **values-<period>.txt** (mc-all & mc-ind) * `ST--withdrawal` * `ST--injection` * `ST--level` -* For every area, add file **details-STstorage-<period>.txt** (mc-all & mc-ind) containing the same columns, but this time for every short-term storage object. +* For every area, add file **details-STstorage-<period>.txt** (mc-all & mc-ind) containing the same columns, but + this time for every short-term storage object. #### Pollutant emission factors -In files **economy/mc-all/areas/** add column: CO2 EMIS. One colum for every pollutant: CO2, NH3, NOX, PM2\_5, PM5, PM10, NMVOC, OP1, OP2, OP3, OP4, OP5 + +In files **economy/mc-all/areas/** add column: CO2 EMIS. One colum for every pollutant: CO2, NH3, NOX, PM2\_5, PM5, +PM10, NMVOC, OP1, OP2, OP3, OP4, OP5 ## v8.5.2 + ### Input + In file **settings/generaldata.ini**, in section `optimization`, link-type is now deprecated ## v8.5.0 + ### Input + In file **settings/generaldata.ini**, in section `adequacy patch`, add properties * `price-taking-order` [string] can take values `DENS` (default value) and `Load`. @@ -221,70 +319,103 @@ In file **settings/generaldata.ini**, in section `adequacy patch`, add propertie * `threshold-csr-variable-bounds-relaxation` [int]. Default value = `3` ### Output -* If `include-adq-patch` is set to `true`, add column `LMR VIOL.` in files **values-<period>.txt** (mc-all & mc-ind) -* If `include-adq-patch` is set to `true`, add column `SPIL. ENRG. CSR` in files **values-<period>.txt** (mc-all & mc-ind) -* If `include-adq-patch` is set to `true`, add column `DTG MRG CSR` in files **values-<period>.txt** (mc-all & mc-ind) + +* If `include-adq-patch` is set to `true`, add column `LMR VIOL.` in files **values-<period>.txt** (mc-all & + mc-ind) +* If `include-adq-patch` is set to `true`, add column `SPIL. ENRG. CSR` in files **values-<period>.txt** (mc-all & + mc-ind) +* If `include-adq-patch` is set to `true`, add column `DTG MRG CSR` in files **values-<period>.txt** (mc-all & + mc-ind) ## v8.4.0 + ### Input + #### Zero/infinite capacity for physical links only -In file **settings/generaldata.ini**, in section `optimization`, change admissible values for key `transmission-capacities` [str]: + +In file **settings/generaldata.ini**, in section `optimization`, change admissible values for key +`transmission-capacities` [str]: * `local-values` (formerly `true`, default) uses the local capacity of all links * `null-for-all-links` (formerly `false`) sets the capacity of all links to 0 * `infinite-for-all-links` (formerly `infinite`) sets the capacity of all links to +infinity * `null-for-physical-links` sets the capacity of physical links to 0, uses the local capacity for virtual links -* `infinite-for-physical-links` sets the capacity of physical links to +infinity, uses the local capacity for virtual links +* `infinite-for-physical-links` sets the capacity of physical links to +infinity, uses the local capacity for virtual + links Previous values (`true`, `false` and `infinite`) are still admissible for compatibility. ### Remove "Split MPS" -In existing section `optimization`, remove property `include-split-exported-mps` [bool]. This property will be ignored (no error) for compatibility. + +In existing section `optimization`, remove property `include-split-exported-mps` [bool]. This property will be ignored ( +no error) for compatibility. #### Result format -In file **settings/generaldata.ini**, in existing section `output`, add property `result-format` [str]. Default value = `txt-files`. If this property is set to `zip`, all results are written into a single zip archive, instead of multiple files. + +In file **settings/generaldata.ini**, in existing section `output`, add property `result-format` [str]. Default value = +`txt-files`. If this property is set to `zip`, all results are written into a single zip archive, instead of multiple +files. ### Output + #### Result format -If property `output/result-format` is set to `zip`, all results are stored in a single archive. The hierarchy within this archive remains identical, for example **economy/mc-all/areas/**. Otherwise, txt files are created like in previous versions. + +If property `output/result-format` is set to `zip`, all results are stored in a single archive. The hierarchy within +this archive remains identical, for example **economy/mc-all/areas/**. Otherwise, txt files are created like in previous +versions. ## v8.3.2 + ### Writing MPS files + MPS files of first optimization used to be overwritten by MPS files of second optimization. Not anymore. Now user can choose to print : + * no MPS file, * MPS files related to the first optimization (named **problem-<week>-<year>--optim-nb-1.txt**), * MPS files related to the second optimization (named **problem-<week>-<year>--optim-nb-2.txt**), * MPS files related to the both optimizations. -In the **generaldata.ini** input file, corresponding values for **include-exportmps** are : **none**, **optim-1**, **optim-2**, **both-optims**. +In the **generaldata.ini** input file, corresponding values for **include-exportmps** are : **none**, **optim-1**, * +*optim-2**, **both-optims**. Compatibility with existing values is maintained (**true** = **both-optims**, **false**=**none**). ### Marginal price of a binding constraint + #### Input -In the context of the addition of a new output variable (marginal price associated to a binding constraint), file **input/bindingconstraints/bindingconstraints.ini** get 2 new parameters for each binding constraint. + +In the context of the addition of a new output variable (marginal price associated to a binding constraint), file * +*input/bindingconstraints/bindingconstraints.ini** get 2 new parameters for each binding constraint. They control which marginal price time granularity is printed, either regarding year by year or synthesis results. * `filter-year-by-year`. Default value = hourly, daily, weekly, monthly, annual * `filter-synthesis`. Default value = hourly, daily, weekly, monthly, annual #### Marginal cost for binding constraints -Still on the binding constraints marginal price results, 2 new folders **binding_constraints** are created inside any simulation output folder, more precisely under **mc-ind** and **mc-all**. + +Still on the binding constraints marginal price results, 2 new folders **binding_constraints** are created inside any +simulation output folder, more precisely under **mc-ind** and **mc-all**. Examples : + * **output/yyyymmdd-hhmmeco/economy/mc-ind/00001/binding_constraints** * **output/yyyymmdd-hhmmeco/economy/mc-all/binding_constraints** -These folders are meant to contain results of any kind regarding binding constraints marginal price (year by year or synthesis). +These folders are meant to contain results of any kind regarding binding constraints marginal price (year by year or +synthesis). Examples of output files inside these folders : + * **binding-constraints-hourly.txt** * **binding-constraints-weekly.txt** ## v8.3.1 + ### Output -Add file **execution_info.ini**, containing information about the execution time for the various steps of a study, as well as study related information that affects performance. + +Add file **execution_info.ini**, containing information about the execution time for the various steps of a study, as +well as study related information that affects performance. ```ini [durations_ms] @@ -327,7 +458,9 @@ unit commitment = fast ``` ## v8.3.0 + ### Input + In file **settings/generaldata.ini**, add section `adequacy patch`, with properties * `include-adq-patch` [bool]. Default value = `false` @@ -336,21 +469,25 @@ In file **settings/generaldata.ini**, add section `adequacy patch`, with propert In existing section `optimization`, add property `include-split-exported-mps` [bool]. Default value = `false` -Add variables `DENS` and `Profit by plant`, which may be used for thematic trimming, see file **settings/generaldata.ini**, section `variables selection`. +Add variables `DENS` and `Profit by plant`, which may be used for thematic trimming, see file **settings/generaldata.ini +**, section `variables selection`. -For each area, add a new file **input/areas/<area>/adequacy_patch.ini** containing a single section `adequacy-patch`. This section contains a single property `adequacy-patch-mode`, that can take values +For each area, add a new file **input/areas/<area>/adequacy_patch.ini** containing a single section +`adequacy-patch`. This section contains a single property `adequacy-patch-mode`, that can take values * `outside` * `inside` * `virtual` Example + ``` [adequacy-patch] adequacy-patch-mode = outside ``` ### Output + * If `include-adq-patch` is set to `true`, add column `DENS` in files **values-<period>.txt** (mc-all & mc-ind) * Add `Profit by plant` column in files **details-<period>.txt** (mc-all & mc-ind) * If `include-split-exported-mps` is set to `true`, create split MPS files in the output folder @@ -365,10 +502,18 @@ NOTE: **period** can be any of the following * `annual` ## v8.2.0 + ### Input -* For each link, the first two columns of file **input/links/<area 1>/<area 2>.txt** have been moved to **input/links/<area 1>/capacities/<area 2>_direct.txt** and **input/links/<area 1>/capacities/<area 2>_indirect.txt** respectively. Note that these two files may contain more than one column, but must contain the same number of columns. The 6 remaining columns have been moved to area **input/links/<area 1>/<area 2>_parameters.txt**. -* In file **settings/generaldata.ini**, add `hydro-debug` [bool] key to existing section `output`. Default value is `false`. +* For each link, the first two columns of file **input/links/<area 1>/<area 2>.txt** have been moved to * + *input/links/<area 1>/capacities/<area 2>_direct.txt** and **input/links/<area + 1>/capacities/<area 2>_indirect.txt** respectively. Note that these two files may contain more than one + column, but must contain the same number of columns. The 6 remaining columns have been moved to area * + *input/links/<area 1>/<area 2>_parameters.txt**. + +* In file **settings/generaldata.ini**, add `hydro-debug` [bool] key to existing section `output`. Default value is + `false`. ### Output + If parameter `hydro-debug` is enabled, a **debug** directory is created in the output folder. diff --git a/src/libs/antares/study/include/antares/study/parts/short-term-storage/properties.h b/src/libs/antares/study/include/antares/study/parts/short-term-storage/properties.h index ac1d37e791..9ea294169e 100644 --- a/src/libs/antares/study/include/antares/study/parts/short-term-storage/properties.h +++ b/src/libs/antares/study/include/antares/study/parts/short-term-storage/properties.h @@ -57,6 +57,9 @@ class Properties /// cluster name std::string name; + bool penalizeVariationWithdrawal = false; + bool penalizeVariationInjection = false; + /// Enabled ? bool enabled = true; diff --git a/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h b/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h index 9e053b0054..80f90b94f2 100644 --- a/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h +++ b/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h @@ -26,9 +26,11 @@ namespace Antares::Data::ShortTermStorage { + class Series { public: + Series() = default; // check if series values are valid bool validate(const std::string& id = "") const; @@ -47,6 +49,8 @@ class Series std::vector costInjection; std::vector costWithdrawal; std::vector costLevel; + std::vector costVariationInjection; + std::vector costVariationWithdrawal; private: bool validateSizes(const std::string&) const; diff --git a/src/libs/antares/study/parts/short-term-storage/properties.cpp b/src/libs/antares/study/parts/short-term-storage/properties.cpp index 28d6afe9a8..3805b239a2 100644 --- a/src/libs/antares/study/parts/short-term-storage/properties.cpp +++ b/src/libs/antares/study/parts/short-term-storage/properties.cpp @@ -89,6 +89,16 @@ bool Properties::loadKey(const IniFile::Property* p) return true; } + if (p->key == "penalize-variation-withdrawal") + { + return p->value.to(this->penalizeVariationWithdrawal); + } + + if (p->key == "penalize-variation-injection") + { + return p->value.to(this->penalizeVariationInjection); + } + if (p->key == "enabled") { return p->value.to(this->enabled); @@ -111,6 +121,8 @@ void Properties::save(IniFile& ini) const s->add("efficiency", this->injectionEfficiency); s->add("efficiencyWithdrawal", this->withdrawalEfficiency); s->add("initialleveloptim", this->initialLevelOptim); + s->add("penalize-variation-injection", this->penalizeVariationInjection); + s->add("penalize-variation-withdrawal", this->penalizeVariationWithdrawal); s->add("enabled", this->enabled); } diff --git a/src/libs/antares/study/parts/short-term-storage/series.cpp b/src/libs/antares/study/parts/short-term-storage/series.cpp index ab58f29f9c..6c341c948d 100644 --- a/src/libs/antares/study/parts/short-term-storage/series.cpp +++ b/src/libs/antares/study/parts/short-term-storage/series.cpp @@ -49,6 +49,10 @@ bool Series::loadFromFolder(const fs::path& folder) ret = loadFile(folder / "cost-withdrawal.txt", costWithdrawal) && ret; ret = loadFile(folder / "cost-level.txt", costLevel) && ret; + ret = loadFile(folder / "cost-variation-injection.txt", costVariationInjection) && ret; + + ret = loadFile(folder / "cost-variation-withdrawal.txt", costVariationWithdrawal) && ret; + return ret; } @@ -122,6 +126,10 @@ void Series::fillDefaultSeriesIfEmpty() fillIfEmpty(costInjection, 0.0); fillIfEmpty(costWithdrawal, 0.0); fillIfEmpty(costLevel, 0.0); + + fillIfEmpty(costVariationInjection, 0.0); + + fillIfEmpty(costVariationWithdrawal, 0.0); } bool Series::saveToFolder(const std::string& folder) const @@ -148,6 +156,9 @@ bool Series::saveToFolder(const std::string& folder) const checkWrite("cost-withdrawal.txt", costWithdrawal); checkWrite("cost-level.txt", costLevel); + checkWrite("cost-variation-injection.txt", costVariationInjection); + checkWrite("cost-variation-withdrawal.txt", costVariationWithdrawal); + return ret; } @@ -215,7 +226,9 @@ bool Series::validateSizes(const std::string& id) const && checkSize("upper-rule-curve.txt", id, upperRuleCurve) && checkSize("cost-injection.txt", id, costInjection) && checkSize("cost-withdrawal.txt", id, costWithdrawal) - && checkSize("cost-level.txt", id, costLevel); + && checkSize("cost-level.txt", id, costLevel) + && checkSize("cost-variation-injection.txt", id, costVariationInjection) + && checkSize("cost-variation-withdrawal.txt", id, costVariationWithdrawal); } bool Series::validateMaxInjection(const std::string& id) const diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index e8b46e6000..57194b388a 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -81,6 +81,12 @@ set(RTESOLVER_OPT constraints/FictitiousLoad.cpp include/antares/solver/optimisation/constraints/ShortTermStorageLevel.h constraints/ShortTermStorageLevel.cpp + include/antares/solver/optimisation/constraints/ShortTermStorageCostVariation.h + constraints/ShortTermStorageCostVariation.cpp + constraints/ShortTermStorageCostVariationInjectionForward.cpp + constraints/ShortTermStorageCostVariationInjectionBackward.cpp + constraints/ShortTermStorageCostVariationWithdrawalForward.cpp + constraints/ShortTermStorageCostVariationWithdrawalBackward.cpp include/antares/solver/optimisation/constraints/FlowDissociation.h constraints/FlowDissociation.cpp include/antares/solver/optimisation/constraints/BindingConstraintHour.h diff --git a/src/solver/optimisation/constraints/ConstraintBuilder.cpp b/src/solver/optimisation/constraints/ConstraintBuilder.cpp index ba4e70254a..6d7662a605 100644 --- a/src/solver/optimisation/constraints/ConstraintBuilder.cpp +++ b/src/solver/optimisation/constraints/ConstraintBuilder.cpp @@ -97,15 +97,23 @@ ConstraintBuilder& ConstraintBuilder::IntercoIndirectCost(unsigned int index, do return *this; } -ConstraintBuilder& ConstraintBuilder::ShortTermStorageInjection(unsigned int index, double coeff) +ConstraintBuilder& ConstraintBuilder::ShortTermStorageInjection(unsigned int index, + double coeff, + int offset, + int delta) { - AddVariable(variableManager_.ShortTermStorageInjection(index, hourInWeek_), coeff); + AddVariable(variableManager_.ShortTermStorageInjection(index, hourInWeek_, offset, delta), + coeff); return *this; } -ConstraintBuilder& ConstraintBuilder::ShortTermStorageWithdrawal(unsigned int index, double coeff) +ConstraintBuilder& ConstraintBuilder::ShortTermStorageWithdrawal(unsigned int index, + double coeff, + int offset, + int delta) { - AddVariable(variableManager_.ShortTermStorageWithdrawal(index, hourInWeek_), coeff); + AddVariable(variableManager_.ShortTermStorageWithdrawal(index, hourInWeek_, offset, delta), + coeff); return *this; } @@ -118,6 +126,28 @@ ConstraintBuilder& ConstraintBuilder::ShortTermStorageLevel(unsigned int index, return *this; } +ConstraintBuilder& ConstraintBuilder::ShortTermCostVariationInjection(unsigned int index, + double coeff, + int offset, + int delta) +{ + AddVariable( + variableManager_.ShortTermStorageCostVariationInjection(index, hourInWeek_, offset, delta), + coeff); + return *this; +} + +ConstraintBuilder& ConstraintBuilder::ShortTermCostVariationWithdrawal(unsigned int index, + double coeff, + int offset, + int delta) +{ + AddVariable( + variableManager_.ShortTermStorageCostVariationWithdrawal(index, hourInWeek_, offset, delta), + coeff); + return *this; +} + ConstraintBuilder& ConstraintBuilder::HydProd(unsigned int index, double coeff) { AddVariable(variableManager_.HydProd(index, hourInWeek_), coeff); diff --git a/src/solver/optimisation/constraints/Group1.cpp b/src/solver/optimisation/constraints/Group1.cpp index 61e9c8a0fc..810b957aee 100644 --- a/src/solver/optimisation/constraints/Group1.cpp +++ b/src/solver/optimisation/constraints/Group1.cpp @@ -21,6 +21,8 @@ #include "antares/solver/optimisation/constraints/Group1.h" +#include "antares/solver/optimisation/constraints/ShortTermStorageCostVariation.h" + AreaBalanceData Group1::GetAreaBalanceData() { return {.CorrespondanceCntNativesCntOptim = problemeHebdo_->CorrespondanceCntNativesCntOptim, @@ -39,7 +41,7 @@ FictitiousLoadData Group1::GetFictitiousLoadData() .DefaillanceNegativeUtiliserHydro = problemeHebdo_->DefaillanceNegativeUtiliserHydro}; } -ShortTermStorageLevelData Group1::GetShortTermStorageLevelData() +ShortTermStorageData Group1::GetShortTermStorageData() { return { .CorrespondanceCntNativesCntOptim = problemeHebdo_->CorrespondanceCntNativesCntOptim, @@ -72,9 +74,21 @@ void Group1::BuildConstraints() auto fictitiousLoadData = GetFictitiousLoadData(); FictitiousLoad fictitiousLoad(builder_, fictitiousLoadData); - auto shortTermStorageLevelData = GetShortTermStorageLevelData(); - ShortTermStorageLevel shortTermStorageLevel(builder_, shortTermStorageLevelData); - + auto shortTermStorageData = GetShortTermStorageData(); + ShortTermStorageLevel shortTermStorageLevel(builder_, shortTermStorageData); + + ShortTermStorageCostVariationInjectionBackward shortTermStorageCostVariationInjectionBackward( + builder_, + shortTermStorageData); + ShortTermStorageCostVariationInjectionForward shortTermStorageCostVariationInjectionForward( + builder_, + shortTermStorageData); + ShortTermStorageCostVariationWithdrawalBackward shortTermStorageCostVariationWithdrawalBackward( + builder_, + shortTermStorageData); + ShortTermStorageCostVariationWithdrawalForward shortTermStorageCostVariationWithdrawalForward( + builder_, + shortTermStorageData); auto flowDissociationData = GetFlowDissociationData(); FlowDissociation flowDissociation(builder_, flowDissociationData); @@ -91,6 +105,10 @@ void Group1::BuildConstraints() areaBalance.add(pdt, pays); fictitiousLoad.add(pdt, pays); shortTermStorageLevel.add(pdt, pays); + shortTermStorageCostVariationInjectionBackward.add(pdt, pays); + shortTermStorageCostVariationInjectionForward.add(pdt, pays); + shortTermStorageCostVariationWithdrawalBackward.add(pdt, pays); + shortTermStorageCostVariationWithdrawalForward.add(pdt, pays); } for (uint32_t interco = 0; interco < problemeHebdo_->NombreDInterconnexions; interco++) diff --git a/src/solver/optimisation/constraints/ShortTermStorageCostVariation.cpp b/src/solver/optimisation/constraints/ShortTermStorageCostVariation.cpp new file mode 100644 index 0000000000..becf41b4ca --- /dev/null +++ b/src/solver/optimisation/constraints/ShortTermStorageCostVariation.cpp @@ -0,0 +1,48 @@ +/* + * 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/ShortTermStorageCostVariation.h" + +void ShortTermStorageCostVariation::addStorageConstraint(const std::string& constraintName, + int pdt, + int pays) +{ + ConstraintNamer namer(builder.data.NomDesContraintes); + const int hourInTheYear = builder.data.weekInTheYear * 168 + pdt; + namer.UpdateTimeStep(hourInTheYear); + namer.UpdateArea(builder.data.NomsDesPays[pays]); + + builder.updateHourWithinWeek(pdt); + for (const auto& storage: data.ShortTermStorage[pays]) + { + if (IsConstraintEnabled(storage)) + { + namer.ShortTermStorageCostVariation(constraintName, + builder.data.nombreDeContraintes, + storage.name); + const auto index = storage.clusterGlobalIndex; + + TargetConstraintIndex(pdt, index) = builder.data.nombreDeContraintes; + + buildConstraint(index); + } + } +} diff --git a/src/solver/optimisation/constraints/ShortTermStorageCostVariationInjectionBackward.cpp b/src/solver/optimisation/constraints/ShortTermStorageCostVariationInjectionBackward.cpp new file mode 100644 index 0000000000..4039af2735 --- /dev/null +++ b/src/solver/optimisation/constraints/ShortTermStorageCostVariationInjectionBackward.cpp @@ -0,0 +1,50 @@ +/* +** 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/ShortTermStorageCostVariation.h" + +// CostVariationInjection[h] + Injection[h+1] - Injection[h] >= 0 +void ShortTermStorageCostVariationInjectionBackward::buildConstraint(int index) +{ + builder.ShortTermCostVariationInjection(index, 1.0) + .ShortTermStorageInjection(index, -1.0) + .ShortTermStorageInjection(index, 1.0, 1, builder.data.NombreDePasDeTempsPourUneOptimisation) + .greaterThan() + .build(); +} + +void ShortTermStorageCostVariationInjectionBackward::add(unsigned int pdt, unsigned int pays) +{ + addStorageConstraint("ShortTermStorageCostVariationInjectionBackward", pdt, pays); +} + +int& ShortTermStorageCostVariationInjectionBackward:: + ShortTermStorageCostVariationInjectionBackward::TargetConstraintIndex(int pdt, int index) +{ + return data.CorrespondanceCntNativesCntOptim[pdt] + .ShortTermStorageCostVariationInjectionBackward[index]; +} + +bool ShortTermStorageCostVariationInjectionBackward::IsConstraintEnabled( + const ShortTermStorage::PROPERTIES& properties) +{ + return properties.penalizeVariationInjection; +} diff --git a/src/solver/optimisation/constraints/ShortTermStorageCostVariationInjectionForward.cpp b/src/solver/optimisation/constraints/ShortTermStorageCostVariationInjectionForward.cpp new file mode 100644 index 0000000000..33060439bd --- /dev/null +++ b/src/solver/optimisation/constraints/ShortTermStorageCostVariationInjectionForward.cpp @@ -0,0 +1,50 @@ +/* +** 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/ShortTermStorageCostVariation.h" + +// CostVariationInjection[h] - Injection[h+1] + Injection[h] >= 0 +void ShortTermStorageCostVariationInjectionForward::buildConstraint(int index) +{ + builder.ShortTermCostVariationInjection(index, 1.0) + .ShortTermStorageInjection(index, 1.0) + .ShortTermStorageInjection(index, -1.0, 1, builder.data.NombreDePasDeTempsPourUneOptimisation) + .greaterThan() + .build(); +} + +void ShortTermStorageCostVariationInjectionForward::add(unsigned int pdt, unsigned int pays) +{ + addStorageConstraint("ShortTermStorageCostVariationInjectionForward", pdt, pays); +} + +int& ShortTermStorageCostVariationInjectionForward::ShortTermStorageCostVariationInjectionForward:: + TargetConstraintIndex(int pdt, int index) +{ + return data.CorrespondanceCntNativesCntOptim[pdt] + .ShortTermStorageCostVariationInjectionForward[index]; +} + +bool ShortTermStorageCostVariationInjectionForward::IsConstraintEnabled( + const ShortTermStorage::PROPERTIES& properties) +{ + return properties.penalizeVariationInjection; +} diff --git a/src/solver/optimisation/constraints/ShortTermStorageCostVariationWithdrawalBackward.cpp b/src/solver/optimisation/constraints/ShortTermStorageCostVariationWithdrawalBackward.cpp new file mode 100644 index 0000000000..d63251b2df --- /dev/null +++ b/src/solver/optimisation/constraints/ShortTermStorageCostVariationWithdrawalBackward.cpp @@ -0,0 +1,49 @@ +/* +** 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/ShortTermStorageCostVariation.h" + +// CostVariationWithdrawal[h] + Withdrawal[h+1] - Withdrawal[h] >= 0 +void ShortTermStorageCostVariationWithdrawalBackward::buildConstraint(int index) +{ + builder.ShortTermCostVariationWithdrawal(index, 1.0) + .ShortTermStorageWithdrawal(index, -1.0) + .ShortTermStorageWithdrawal(index, 1.0, 1, builder.data.NombreDePasDeTempsPourUneOptimisation) + .greaterThan() + .build(); +} + +void ShortTermStorageCostVariationWithdrawalBackward::add(unsigned int pdt, unsigned int pays) +{ + addStorageConstraint("ShortTermStorageCostVariationWithdrawalBackward", pdt, pays); +} + +int& ShortTermStorageCostVariationWithdrawalBackward::TargetConstraintIndex(int pdt, int index) +{ + return data.CorrespondanceCntNativesCntOptim[pdt] + .ShortTermStorageCostVariationWithdrawalBackward[index]; +} + +bool ShortTermStorageCostVariationWithdrawalBackward::IsConstraintEnabled( + const ShortTermStorage::PROPERTIES& properties) +{ + return properties.penalizeVariationWithdrawal; +} diff --git a/src/solver/optimisation/constraints/ShortTermStorageCostVariationWithdrawalForward.cpp b/src/solver/optimisation/constraints/ShortTermStorageCostVariationWithdrawalForward.cpp new file mode 100644 index 0000000000..00b67babdd --- /dev/null +++ b/src/solver/optimisation/constraints/ShortTermStorageCostVariationWithdrawalForward.cpp @@ -0,0 +1,52 @@ +/* +** 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/ShortTermStorageCostVariation.h" + +// CostVariationWithdrawal[h] - Withdrawal[h+1] + Withdrawal[h] >= 0 +void ShortTermStorageCostVariationWithdrawalForward::buildConstraint(int index) +{ + builder.ShortTermCostVariationWithdrawal(index, 1.0) + .ShortTermStorageWithdrawal(index, 1.0) + .ShortTermStorageWithdrawal(index, + -1.0, + 1, + builder.data.NombreDePasDeTempsPourUneOptimisation) + .greaterThan() + .build(); +} + +void ShortTermStorageCostVariationWithdrawalForward::add(unsigned int pdt, unsigned int pays) +{ + addStorageConstraint("ShortTermStorageCostVariationWithdrawalForward", pdt, pays); +} + +bool ShortTermStorageCostVariationWithdrawalForward::IsConstraintEnabled( + const ShortTermStorage::PROPERTIES& properties) +{ + return properties.penalizeVariationWithdrawal; +} + +int& ShortTermStorageCostVariationWithdrawalForward::TargetConstraintIndex(int pdt, int index) +{ + return data.CorrespondanceCntNativesCntOptim[pdt] + .ShortTermStorageCostVariationWithdrawalForward[index]; +} 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 dd0a1ab1b6..b06af4614d 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ConstraintBuilder.h @@ -114,14 +114,28 @@ class ConstraintBuilder ConstraintBuilder& IntercoIndirectCost(unsigned int index, double coeff); - ConstraintBuilder& ShortTermStorageInjection(unsigned int index, double coeff); + ConstraintBuilder& ShortTermStorageInjection(unsigned int index, + double coeff, + int offset = 0, + int delta = 0); - ConstraintBuilder& ShortTermStorageWithdrawal(unsigned int index, double coeff); + ConstraintBuilder& ShortTermStorageWithdrawal(unsigned int index, + double coeff, + int offset = 0, + int delta = 0); ConstraintBuilder& ShortTermStorageLevel(unsigned int index, double coeff, int offset = 0, int delta = 0); + ConstraintBuilder& ShortTermCostVariationInjection(unsigned int index, + double coeff, + int offset = 0, + int delta = 0); + ConstraintBuilder& ShortTermCostVariationWithdrawal(unsigned int index, + double coeff, + int offset = 0, + int delta = 0); ConstraintBuilder& HydProd(unsigned int index, double coeff); @@ -284,3 +298,10 @@ struct StartUpCostsData const std::vector& PaliersThermiquesDuPays; bool Simulation; }; + +struct ShortTermStorageData +{ + std::vector& CorrespondanceCntNativesCntOptim; + + const std::vector<::ShortTermStorage::AREA_INPUT>& ShortTermStorage; +}; 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 2428ccaa44..e5134edb6e 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/Group1.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/Group1.h @@ -37,7 +37,7 @@ class Group1: public ConstraintGroup private: AreaBalanceData GetAreaBalanceData(); FictitiousLoadData GetFictitiousLoadData(); - ShortTermStorageLevelData GetShortTermStorageLevelData(); + ShortTermStorageData GetShortTermStorageData(); FlowDissociationData GetFlowDissociationData(); BindingConstraintHourData GetBindingConstraintHourData(); }; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageCostVariation.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageCostVariation.h new file mode 100644 index 0000000000..b2ecaa072b --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageCostVariation.h @@ -0,0 +1,102 @@ +/* + * 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 ShortTermStorageCostVariation: public ConstraintFactory +{ +public: + ShortTermStorageCostVariation(ConstraintBuilder& builder, ShortTermStorageData& data): + ConstraintFactory(builder), + data(data) + { + } + + virtual void add(unsigned int pdt, unsigned int pays) = 0; + + ShortTermStorageData& data; + +protected: + virtual void buildConstraint(int index) = 0; + + virtual bool IsConstraintEnabled(const ShortTermStorage::PROPERTIES& properties) = 0; + + virtual int& TargetConstraintIndex(int pdt, int index) = 0; + + void addStorageConstraint(const std::string& constraintName, int pdt, int pays); +}; + +class ShortTermStorageCostVariationInjectionBackward: ShortTermStorageCostVariation +{ +public: + using ShortTermStorageCostVariation::ShortTermStorageCostVariation; + + void add(unsigned int pdt, unsigned int pays) override; + + bool IsConstraintEnabled(const ShortTermStorage::PROPERTIES& properties) override; + + int& TargetConstraintIndex(int pdt, int index) override; + + void buildConstraint(int index) override; +}; + +class ShortTermStorageCostVariationInjectionForward: ShortTermStorageCostVariation +{ +public: + using ShortTermStorageCostVariation::ShortTermStorageCostVariation; + + void add(unsigned int pdt, unsigned int pays) override; + + bool IsConstraintEnabled(const ShortTermStorage::PROPERTIES& properties) override; + + int& TargetConstraintIndex(int pdt, int index) override; + + void buildConstraint(int index) override; +}; + +class ShortTermStorageCostVariationWithdrawalBackward: ShortTermStorageCostVariation +{ +public: + using ShortTermStorageCostVariation::ShortTermStorageCostVariation; + + void add(unsigned int pdt, unsigned int pays) override; + + bool IsConstraintEnabled(const ShortTermStorage::PROPERTIES& properties) override; + + int& TargetConstraintIndex(int pdt, int index) override; + + void buildConstraint(int index) override; +}; + +class ShortTermStorageCostVariationWithdrawalForward: ShortTermStorageCostVariation +{ +public: + using ShortTermStorageCostVariation::ShortTermStorageCostVariation; + + void add(unsigned int pdt, unsigned int pays) override; + + bool IsConstraintEnabled(const ShortTermStorage::PROPERTIES& properties) override; + + int& TargetConstraintIndex(int pdt, int index) override; + + void buildConstraint(int index) override; +}; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageLevel.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageLevel.h index 5571e4636c..7df31f85af 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageLevel.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageLevel.h @@ -22,17 +22,10 @@ #pragma once #include "ConstraintBuilder.h" -struct ShortTermStorageLevelData -{ - std::vector& CorrespondanceCntNativesCntOptim; - - const std::vector<::ShortTermStorage::AREA_INPUT>& ShortTermStorage; -}; - class ShortTermStorageLevel: private ConstraintFactory { public: - ShortTermStorageLevel(ConstraintBuilder& builder, ShortTermStorageLevelData& data): + ShortTermStorageLevel(ConstraintBuilder& builder, ShortTermStorageData& data): ConstraintFactory(builder), data(data) { @@ -41,5 +34,5 @@ class ShortTermStorageLevel: private ConstraintFactory void add(int pdt, int pays); private: - ShortTermStorageLevelData& data; + ShortTermStorageData& 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 fafb4f2e45..f05b6eb15a 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 @@ -99,6 +99,10 @@ class VariableNamer: public Namer void ShortTermStorageInjection(unsigned int variable, const std::string& shortTermStorageName); void ShortTermStorageWithdrawal(unsigned int variable, const std::string& shortTermStorageName); void ShortTermStorageLevel(unsigned int variable, const std::string& shortTermStorageName); + void ShortTermStorageCostVariationInjection(unsigned int variable, + const std::string& shortTermStorageName); + void ShortTermStorageCostVariationWithdrawal(unsigned int variable, + const std::string& shortTermStorageName); void HydProd(unsigned int variable); void HydProdDown(unsigned int variable); void HydProdUp(unsigned int variable); @@ -158,6 +162,10 @@ class ConstraintNamer: public Namer void CsrAreaBalance(unsigned int constraint); void CsrBindingConstraintHour(unsigned int constraint, const std::string& name); + void ShortTermStorageCostVariation(const std::string& constraint_name, + unsigned int constraint, + const std::string& short_term_name); + private: void nameWithTimeGranularity(unsigned int constraint, const std::string& name, diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp index c1aa0e2991..d2e68570e9 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp @@ -109,6 +109,29 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaire(PROBLEME_HEBD = VARIABLE_BORNEE_DES_DEUX_COTES; variableNamer.ShortTermStorageLevel(NombreDeVariables, storage.name); NombreDeVariables++; + + // 4. Cost Variation Injection + if (storage.penalizeVariationInjection) + { + variableManager.ShortTermStorageCostVariationInjection(clusterGlobalIndex, pdt) + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_INFERIEUREMENT; + variableNamer.ShortTermStorageCostVariationInjection(NombreDeVariables, + storage.name); + ++NombreDeVariables; + } + // 5. Cost Variation Withdrawal + if (storage.penalizeVariationWithdrawal) + { + variableManager.ShortTermStorageCostVariationWithdrawal(clusterGlobalIndex, pdt) + = NombreDeVariables; + ProblemeAResoudre->TypeDeVariable[NombreDeVariables] + = VARIABLE_BORNEE_INFERIEUREMENT; + variableNamer.ShortTermStorageCostVariationWithdrawal(NombreDeVariables, + storage.name); + ++NombreDeVariables; + } } variableManager.PositiveUnsuppliedEnergy(pays, pdt) = NombreDeVariables; diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp index 1df4f0b3df..d1a0f00ea2 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp @@ -146,10 +146,10 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* the reference document) */ ProblemeAResoudre ->NombreDeContraintes++; /* 1 constraint setting the level variation over the period - (10b in the reference document) */ + (10b in the reference document) */ ProblemeAResoudre ->NombreDeContraintes++; /* 1 constraint bounding the overall energy pumped over the - period (10c in the reference document) */ + period (10c in the reference document) */ } if (!Pump && TurbEntreBornes && !MonitorHourlyLev) @@ -194,14 +194,14 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* the reference document) */ ProblemeAResoudre ->NombreDeContraintes++; /* 1 constraint setting the level variation over the period - (10b in the reference document) */ + (10b in the reference document) */ ProblemeAResoudre ->NombreDeContraintes++; /* 1 constraint bounding the overall energy pumped over the - period (10c in the reference document) */ + period (10c in the reference document) */ ProblemeAResoudre->NombreDeContraintes += nombreDePasDeTempsPourUneOptimisation; /* T constraints expressing the level hourly - variations (14a in the reference - document) */ + variations (14a in the reference + document) */ } if (!Pump && !TurbEntreBornes && MonitorHourlyLev) { @@ -210,7 +210,6 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* + areaName); } } - // Short term storage { const uint nbSTS = problemeHebdo->NumberOfShortTermStorages; @@ -218,6 +217,36 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* ProblemeAResoudre->NombreDeVariables += 3 * nbSTS * nombreDePasDeTempsPourUneOptimisation; // Level equation (Level[h+1] = Level[h] + ...) ProblemeAResoudre->NombreDeContraintes += nbSTS * nombreDePasDeTempsPourUneOptimisation; + + for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; ++pays) + { + for (const auto& storage: problemeHebdo->ShortTermStorage[pays]) + { + /* + * ShortTermStorageCostVariationInjectionBackward + * ShortTermStorageCostVariationInjectionForward + */ + if (storage.penalizeVariationInjection) + { + // CostVariationInjection + ProblemeAResoudre->NombreDeVariables += nombreDePasDeTempsPourUneOptimisation; + ProblemeAResoudre->NombreDeContraintes + += 2 * nombreDePasDeTempsPourUneOptimisation; + } + + /* + * ShortTermStorageCostVariationWithdrawalBackward + * ShortTerStorageCostVariationWithdrawalForward + */ + if (storage.penalizeVariationWithdrawal) + { + // CostVariationWithdrawal + ProblemeAResoudre->NombreDeVariables += nombreDePasDeTempsPourUneOptimisation; + ProblemeAResoudre->NombreDeContraintes + += 2 * nombreDePasDeTempsPourUneOptimisation; + } + } + } } for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) @@ -230,7 +259,6 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* ProblemeAResoudre->NombreDeVariables += nombreDePasDeTempsPourUneOptimisation * 2; ProblemeAResoudre->NombreDeContraintes += nombreDePasDeTempsPourUneOptimisation; } - else if (problemeHebdo->TypeDeLissageHydraulique == LISSAGE_HYDRAULIQUE_SUR_VARIATION_MAX) { 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 50c63133fc..5c507fbed7 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp @@ -191,7 +191,28 @@ static void setBoundsForShortTermStorage(PROBLEME_HEBDO* problemeHebdo, * storage.series->upperRuleCurve[hourInTheYear]; } AddressForVars[varLevel] = &STSResult.level[storageIndex]; + // 4. Cost Variation Injection + // is this necessary? + if (storage.penalizeVariationInjection) + { + int varCostVariationInjection = variableManager + .ShortTermStorageCostVariationInjection( + clusterGlobalIndex, + pdtJour); + + Xmin[varCostVariationInjection] = 0.; + } + // 5. Cost Variation Withdrawal + // is this necessary? + if (storage.penalizeVariationWithdrawal) + { + int varCostVariationWithdrawal = variableManager + .ShortTermStorageCostVariationWithdrawal( + clusterGlobalIndex, + pdtJour); + Xmin[varCostVariationWithdrawal] = 0.; + } storageIndex++; } } 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 893575110d..be6d609387 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp @@ -64,6 +64,23 @@ static void shortTermStorageCost( { linearCost[varWithdrawal] = storage.series->costWithdrawal[pdtHebdo]; } + if (const int varCostVariationInjection = variableManager + .ShortTermStorageCostVariationInjection( + clusterGlobalIndex, + pdtJour); + storage.penalizeVariationInjection && varCostVariationInjection >= 0) + { + linearCost[varCostVariationInjection] = storage.series + ->costVariationInjection[pdtHebdo]; + } + if (const int varCostVariationWithdrawal + = variableManager.ShortTermStorageCostVariationWithdrawal(clusterGlobalIndex, + pdtJour); + storage.penalizeVariationWithdrawal && varCostVariationWithdrawal >= 0) + { + linearCost[varCostVariationWithdrawal] = storage.series + ->costVariationWithdrawal[pdtHebdo]; + } } } } 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 a824066209..36bb303964 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp @@ -36,8 +36,8 @@ static void shortTermStorageLevelsRHS( for (auto& storage: shortTermStorageInput[areaIndex]) { const int clusterGlobalIndex = storage.clusterGlobalIndex; - const int cnt = CorrespondanceCntNativesCntOptim - .ShortTermStorageLevelConstraint[clusterGlobalIndex]; + int cnt = CorrespondanceCntNativesCntOptim + .ShortTermStorageLevelConstraint[clusterGlobalIndex]; SecondMembre[cnt] = storage.series->inflows[hourInTheYear]; } } diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index 1324c54fd8..a92553e5e6 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -180,6 +180,18 @@ void VariableNamer::ShortTermStorageLevel(unsigned int variable, SetShortTermStorageVariableName(variable, "Level", shortTermStorageName); } +void VariableNamer::ShortTermStorageCostVariationInjection(unsigned int variable, + const std::string& shortTermStorageName) +{ + SetShortTermStorageVariableName(variable, "CostVariationInjection", shortTermStorageName); +} + +void VariableNamer::ShortTermStorageCostVariationWithdrawal(unsigned int variable, + const std::string& shortTermStorageName) +{ + SetShortTermStorageVariableName(variable, "CostVariationWithdrawal", shortTermStorageName); +} + void VariableNamer::HydProd(unsigned int variable) { SetAreaElementNameHour(variable, "HydProd"); @@ -390,3 +402,15 @@ void ConstraintNamer::BindingConstraintWeek(unsigned int constraint, const std:: { nameWithTimeGranularity(constraint, name, WEEK); } + +void ConstraintNamer::ShortTermStorageCostVariation(const std::string& constraint_name, + unsigned int constraint, + const std::string& short_term_name) +{ + targetUpdater_.UpdateTargetAtIndex(BuildName(constraint_name, + LocationIdentifier(area_, AREA) + SEPARATOR + + "ShortTermStorage" + "<" + short_term_name + + ">", + TimeIdentifier(timeStep_, HOUR)), + constraint); +} diff --git a/src/solver/optimisation/variables/VariableManagement.cpp b/src/solver/optimisation/variables/VariableManagement.cpp index 6187670c97..37d50b5f97 100644 --- a/src/solver/optimisation/variables/VariableManagement.cpp +++ b/src/solver/optimisation/variables/VariableManagement.cpp @@ -136,6 +136,26 @@ int& VariableManager::ShortTermStorageLevel(unsigned int index, return CorrespondanceVarNativesVarOptim_[pdt].SIM_ShortTermStorage.LevelVariable[index]; } +int& VariableManager::ShortTermStorageCostVariationInjection(unsigned int index, + unsigned int hourInWeek, + int offset, + int delta) +{ + auto pdt = GetShiftedTimeStep(offset, delta, hourInWeek); + return CorrespondanceVarNativesVarOptim_[pdt] + .SIM_ShortTermStorage.CostVariationInjection[index]; +} + +int& VariableManager::ShortTermStorageCostVariationWithdrawal(unsigned int index, + unsigned int hourInWeek, + int offset, + int delta) +{ + auto pdt = GetShiftedTimeStep(offset, delta, hourInWeek); + return CorrespondanceVarNativesVarOptim_[pdt] + .SIM_ShortTermStorage.CostVariationWithdrawal[index]; +} + int& VariableManager::HydProd(unsigned int index, unsigned int hourInWeek, int offset, int delta) { auto pdt = GetShiftedTimeStep(offset, delta, hourInWeek); diff --git a/src/solver/optimisation/variables/VariableManagement.h b/src/solver/optimisation/variables/VariableManagement.h index b5054a121c..252c4007dd 100644 --- a/src/solver/optimisation/variables/VariableManagement.h +++ b/src/solver/optimisation/variables/VariableManagement.h @@ -66,6 +66,14 @@ class VariableManager unsigned int hourInWeek, int offset = 0, int delta = 0); + int& ShortTermStorageCostVariationInjection(unsigned int index, + unsigned int hourInWeek, + int offset = 0, + int delta = 0); + int& ShortTermStorageCostVariationWithdrawal(unsigned int index, + unsigned int hourInWeek, + int offset = 0, + int delta = 0); int& HydProd(unsigned int index, unsigned int hourInWeek, int offset = 0, int delta = 0); 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 3a261bf40f..d24fb25bc4 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 @@ -69,6 +69,8 @@ struct CORRESPONDANCES_DES_VARIABLES std::vector InjectionVariable; std::vector WithdrawalVariable; std::vector LevelVariable; + std::vector CostVariationInjection; + std::vector CostVariationWithdrawal; } SIM_ShortTermStorage; }; @@ -95,6 +97,10 @@ struct CORRESPONDANCES_DES_CONTRAINTES std::vector NumeroDeContrainteDesNiveauxPays; std::vector ShortTermStorageLevelConstraint; + std::vector ShortTermStorageCostVariationInjectionForward; + std::vector ShortTermStorageCostVariationInjectionBackward; + std::vector ShortTermStorageCostVariationWithdrawalForward; + std::vector ShortTermStorageCostVariationWithdrawalBackward; }; struct CORRESPONDANCES_DES_CONTRAINTES_JOURNALIERES @@ -172,6 +178,8 @@ struct PROPERTIES double withdrawalEfficiency; double initialLevel; bool initialLevelOptim; + bool penalizeVariationWithdrawal; + bool penalizeVariationInjection; std::shared_ptr series; diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index df829e70df..d735191ff7 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -180,6 +180,11 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, variablesMapping.SIM_ShortTermStorage.WithdrawalVariable.assign(shortTermStorageCount, 0); variablesMapping.SIM_ShortTermStorage.LevelVariable.assign(shortTermStorageCount, 0); + variablesMapping.SIM_ShortTermStorage.CostVariationInjection.assign(shortTermStorageCount, + 0); + variablesMapping.SIM_ShortTermStorage.CostVariationWithdrawal.assign(shortTermStorageCount, + 0); + problem.CorrespondanceCntNativesCntOptim[k].NumeroDeContrainteDesBilansPays.assign(nbPays, 0); problem.CorrespondanceCntNativesCntOptim[k] @@ -190,6 +195,15 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, problem.CorrespondanceCntNativesCntOptim[k] .ShortTermStorageLevelConstraint.assign(shortTermStorageCount, 0); + problem.CorrespondanceCntNativesCntOptim[k] + .ShortTermStorageCostVariationInjectionForward.assign(shortTermStorageCount, 0); + problem.CorrespondanceCntNativesCntOptim[k] + .ShortTermStorageCostVariationInjectionBackward.assign(shortTermStorageCount, 0); + problem.CorrespondanceCntNativesCntOptim[k] + .ShortTermStorageCostVariationWithdrawalForward.assign(shortTermStorageCount, 0); + problem.CorrespondanceCntNativesCntOptim[k] + .ShortTermStorageCostVariationWithdrawalBackward.assign(shortTermStorageCount, 0); + problem.CorrespondanceCntNativesCntOptim[k] .NumeroPremiereContrainteDeReserveParZone.assign(nbPays, 0); problem.CorrespondanceCntNativesCntOptim[k] diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 79e6635613..3d29d3ee42 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -56,6 +56,8 @@ static void importShortTermStorages( toInsert.withdrawalNominalCapacity = st.properties.withdrawalNominalCapacity.value(); toInsert.initialLevel = st.properties.initialLevel; toInsert.initialLevelOptim = st.properties.initialLevelOptim; + toInsert.penalizeVariationInjection = st.properties.penalizeVariationInjection; + toInsert.penalizeVariationWithdrawal = st.properties.penalizeVariationWithdrawal; toInsert.name = st.properties.name; toInsert.series = st.series; diff --git a/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp b/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp index 427eeadb73..265135c7d4 100644 --- a/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp +++ b/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp @@ -38,6 +38,13 @@ namespace fs = std::filesystem; namespace { + +struct PenaltyCostOnVariation +{ + bool injection = false; + bool withdrawal = false; +}; + fs::path getFolder() { return fs::temp_directory_path(); @@ -54,6 +61,9 @@ void resizeFillVectors(ShortTermStorage::Series& series, double value, unsigned series.costInjection.resize(size, value); series.costWithdrawal.resize(size, value); series.costLevel.resize(size, value); + + series.costVariationInjection.resize(size, value); + series.costVariationWithdrawal.resize(size, value); } void createIndividualFileSeries(const fs::path& path, double value, unsigned int size) @@ -95,6 +105,8 @@ void createFileSeries(double value, unsigned int size) createIndividualFileSeries(folder / "cost-injection.txt", value, size); createIndividualFileSeries(folder / "cost-withdrawal.txt", value, size); createIndividualFileSeries(folder / "cost-level.txt", value, size); + createIndividualFileSeries(folder / "cost-variation-injection.txt", value, size); + createIndividualFileSeries(folder / "cost-variation-withdrawal.txt", value, size); } void createFileSeries(unsigned int size) @@ -110,6 +122,9 @@ void createFileSeries(unsigned int size) createIndividualFileSeries(folder / "cost-injection.txt", size); createIndividualFileSeries(folder / "cost-withdrawal.txt", size); createIndividualFileSeries(folder / "cost-level.txt", size); + + createIndividualFileSeries(folder / "cost-variation-injection.txt", size); + createIndividualFileSeries(folder / "cost-variation-withdrawal.txt", size); } void createIniFile(bool enabled) @@ -132,6 +147,23 @@ void createIniFile(bool enabled) outfile.close(); } +void createIniFile(const PenaltyCostOnVariation& penaltyCostOnVariation) +{ + fs::path folder = getFolder(); + + std::ofstream outfile; + outfile.open(folder / "list.ini", std::ofstream::out | std::ofstream::trunc); + + outfile << "[area]" << std::endl; + outfile << "name = area" << std::endl; + outfile << "group = PSP_open" << std::endl; + outfile << "penalize-variation-injection = " << std::boolalpha + << penaltyCostOnVariation.injection << std::endl; + outfile << "penalize-variation-withdrawal = " << std::boolalpha + << penaltyCostOnVariation.withdrawal << std::endl; + outfile.close(); +} + void createIniFileWrongValue() { fs::path folder = getFolder(); @@ -190,6 +222,9 @@ struct Fixture fs::remove(folder / "cost-injection.txt"); fs::remove(folder / "cost-withdrawal.txt"); fs::remove(folder / "cost-level.txt"); + + fs::remove(folder / "cost-variation-injection.txt"); + fs::remove(folder / "cost-variation-withdrawal.txt"); } fs::path folder = getFolder(); @@ -198,6 +233,8 @@ struct Fixture ShortTermStorage::Properties properties; ShortTermStorage::STStorageCluster cluster; ShortTermStorage::STStorageInput container; + + PenaltyCostOnVariation penaltyCostOnVariation; }; // ================== @@ -222,7 +259,8 @@ BOOST_FIXTURE_TEST_CASE(check_series_folder_loading, Fixture) BOOST_CHECK(series.loadFromFolder(folder)); BOOST_CHECK(series.validate()); BOOST_CHECK(series.inflows[0] == 1 && series.maxInjectionModulation[8759] == 1 - && series.upperRuleCurve[1343] == 1); + && series.upperRuleCurve[1343] == 1 && series.costVariationInjection[0] == 1 + && series.costVariationWithdrawal[0] == 1); } BOOST_FIXTURE_TEST_CASE(check_series_folder_loading_different_values, Fixture) @@ -283,7 +321,9 @@ BOOST_FIXTURE_TEST_CASE(check_cluster_series_load_vector, Fixture) BOOST_CHECK(cluster.series->validate()); BOOST_CHECK(cluster.series->maxWithdrawalModulation[0] == 0.5 && cluster.series->inflows[2756] == 0.5 - && cluster.series->lowerRuleCurve[6392] == 0.5); + && cluster.series->lowerRuleCurve[6392] == 0.5 + && cluster.series->costVariationInjection[15] == 0.5 + && cluster.series->costVariationWithdrawal[756] == 0.5); } BOOST_FIXTURE_TEST_CASE(check_container_properties_enabled_load, Fixture) @@ -297,6 +337,55 @@ BOOST_FIXTURE_TEST_CASE(check_container_properties_enabled_load, Fixture) BOOST_CHECK(properties.enabled); BOOST_CHECK_EQUAL(container.count(), 1); BOOST_CHECK(properties.validate()); + BOOST_CHECK(!properties.penalizeVariationInjection); + BOOST_CHECK(!properties.penalizeVariationWithdrawal); + + removeIniFile(); +} + +BOOST_FIXTURE_TEST_CASE(check_container_properties_enabled_load_with_cost_variation_injection, + Fixture) +{ + penaltyCostOnVariation = {.injection = true, .withdrawal = false}; + createIniFile(penaltyCostOnVariation); + + BOOST_CHECK(container.createSTStorageClustersFromIniFile(folder)); + + auto& properties = container.storagesByIndex[0].properties; + + BOOST_CHECK(properties.penalizeVariationInjection); + + removeIniFile(); +} + +BOOST_FIXTURE_TEST_CASE(check_container_properties_enabled_load_with_cost_variation_withdrawal, + Fixture) +{ + penaltyCostOnVariation = {.injection = false, .withdrawal = true}; + createIniFile(penaltyCostOnVariation); + + BOOST_CHECK(container.createSTStorageClustersFromIniFile(folder)); + + auto& properties = container.storagesByIndex[0].properties; + + BOOST_CHECK(properties.penalizeVariationWithdrawal); + + removeIniFile(); +} + +BOOST_FIXTURE_TEST_CASE( + check_container_properties_enabled_load_with_cost_variation_injection_and_withdrawal, + Fixture) +{ + penaltyCostOnVariation = {.injection = true, .withdrawal = true}; + createIniFile(penaltyCostOnVariation); + + BOOST_CHECK(container.createSTStorageClustersFromIniFile(folder)); + + auto& properties = container.storagesByIndex[0].properties; + + BOOST_CHECK(properties.penalizeVariationInjection); + BOOST_CHECK(properties.penalizeVariationWithdrawal); removeIniFile(); } From f7422c715b7c47adf417a4c4a0c6096d533d9adb Mon Sep 17 00:00:00 2001 From: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Date: Thu, 28 Nov 2024 09:49:16 +0100 Subject: [PATCH 063/103] Remove direct use of Sirius solver (ANT-1152) (#2450) This PR intends to be a first work in order to remove the direct call of **Sirius** as a solver, **regarding the optimization weekly problem only**. We want to keep the use of **Sirius**, but only called through **or-tools** interface. The associated **gopro** ticket is [this one](https://gopro-tickets.rte-france.com/browse/ANT-1152). Here we intend to : - remove the use of command line option **--use-ortools** - rename current command line option **--ortools-solver** into **--solver** - handle direct consequences of these changes. - adapt legacy GUI (especially remove **use ortools** check box) So this PR does not intend to be thorough : these first changes leave remaining dead code to be removed and renaming to be done. This further changes will be done in a coming PR. **Remaining to be done** : - or-tools (even if we use **Sirius** behind it) does not print correctly MPS for named problems : optimization variables names are composed with time steps, set once for all (0, ..., 167) before running any year, and not updated at each week (we could expect step numbers to be inside [0, ..., 8759] depending on the week). So we left the code that print these correctly. We'll have to find a solution for this. We could leave the responsibility of printing these named MPS to Antares code (as it did when Sirius was run alone) for a moment - Banish all direct calls to **Sirius** from **Antares Simulator** (calls to **Sirius** are done in **hydro heuristics**, **adequacy patch CSR** and annual **quadratic** post-treatments of flows) does not seem to be suitable and urgent for now. - What else ? --------- Co-authored-by: Florian OMNES --- .github/workflows/cucumber-tests/action.yml | 2 +- docs/developer-guide/CHANGELOG.md | 1 + docs/user-guide/solver/02-command-line.md | 3 +- .../solver/optional-features/xpress.md | 2 +- .../InfoCollection/StudyInfoCollector.cpp | 16 +--- .../infoCollection/StudyInfoCollector.h | 1 - .../antares/checks/checkLoadedInputData.cpp | 13 +-- .../antares/checks/checkLoadedInputData.h | 1 - .../antares/optimization-options/options.h | 2 - src/libs/antares/study/parameters.cpp | 9 +- src/solver/application/application.cpp | 1 - src/solver/misc/options.cpp | 30 ++---- .../solver/optimisation/opt_fonctions.h | 2 +- .../opt_appel_solveur_lineaire.cpp | 73 ++++---------- .../opt_liberation_problemes_simplexe.cpp | 12 +-- .../optimisation/opt_optimisation_hebdo.cpp | 4 +- .../include/antares/solver/utils/mps_utils.h | 5 +- src/solver/utils/mps_utils.cpp | 11 +-- src/tests/CMakeLists.txt | 10 +- .../steps/common_steps/simulator_utils.py | 12 +-- .../end-to-end/simple_study/simple-study.cpp | 2 - src/tests/end-to-end/test_simple-test.py | 95 ------------------- .../actions_on_study/study_run.py | 15 ++- src/tests/run-study-tests/conftest.py | 17 ++-- src/tests/run-study-tests/fixtures.py | 4 +- src/tests/run-study-tests/readme.md | 9 +- src/ui/simulator/application/study.cpp | 13 +-- src/ui/simulator/application/study.h | 6 +- src/ui/simulator/windows/simulation/run.cpp | 37 +------- src/ui/simulator/windows/simulation/run.h | 3 - 30 files changed, 88 insertions(+), 323 deletions(-) delete mode 100644 src/tests/end-to-end/test_simple-test.py diff --git a/.github/workflows/cucumber-tests/action.yml b/.github/workflows/cucumber-tests/action.yml index f927c9456a..475d3310b3 100644 --- a/.github/workflows/cucumber-tests/action.yml +++ b/.github/workflows/cucumber-tests/action.yml @@ -20,4 +20,4 @@ runs: shell: bash run: | cd src/tests/cucumber - behave --tags ${{ inputs.tags }} ${{ inputs.feature }} --define use-ortools=false + behave --tags ${{ inputs.tags }} ${{ inputs.feature }} diff --git a/docs/developer-guide/CHANGELOG.md b/docs/developer-guide/CHANGELOG.md index ca785b77d5..2b650deb55 100644 --- a/docs/developer-guide/CHANGELOG.md +++ b/docs/developer-guide/CHANGELOG.md @@ -16,6 +16,7 @@ toc_depth: 2 #### Removed features * Remove hydro hotstart (#2131) * Remove adequacy patch lmr [ANT-1933] (#2341) +* Possibility to disable OR-Tools. All problems are now solved through OR-Tools (#2450) #### Improvements * Changed the formula for the number of cores [details](../user-guide/solver/optional-features/multi-threading.md) diff --git a/docs/user-guide/solver/02-command-line.md b/docs/user-guide/solver/02-command-line.md index 346e9cfdfc..7cc927a662 100644 --- a/docs/user-guide/solver/02-command-line.md +++ b/docs/user-guide/solver/02-command-line.md @@ -17,8 +17,7 @@ hide: | --adequacy | Force the simulation in [adequacy](static-modeler/04-parameters.md#mode) mode | | --parallel | Enable [parallel](optional-features/multi-threading.md) computation of MC years | | --force-parallel=VALUE | Override the max number of years computed [simultaneously](optional-features/multi-threading.md) | -| --use-ortools | Use the [OR-Tools](https://developers.google.com/optimization) modelling library (under the hood) | -| --ortools-solver=VALUE | The solver to use (only available if use-ortools is activated). Possible values are: `sirius` (default), `coin`, `xpress`, `scip` | +| --ortools-solver=VALUE | The optimization solver to use. Possible values are: `sirius` (default), `coin`, `xpress`, `scip` | ## Parameters diff --git a/docs/user-guide/solver/optional-features/xpress.md b/docs/user-guide/solver/optional-features/xpress.md index 961ad83b50..e8e5242f73 100644 --- a/docs/user-guide/solver/optional-features/xpress.md +++ b/docs/user-guide/solver/optional-features/xpress.md @@ -10,7 +10,7 @@ Antares Solver only uses LP, with plans to use MILP at some point in the future. ## Using Xpress in the command-line ``` -antares-x.y-solver --use-ortools --ortools-solver xpress [options] +antares-solver --ortools-solver xpress [options] ``` ## Setup diff --git a/src/libs/antares/InfoCollection/StudyInfoCollector.cpp b/src/libs/antares/InfoCollection/StudyInfoCollector.cpp index 33b59d915e..7d07df9690 100644 --- a/src/libs/antares/InfoCollection/StudyInfoCollector.cpp +++ b/src/libs/antares/InfoCollection/StudyInfoCollector.cpp @@ -45,7 +45,6 @@ void StudyInfoCollector::toFileContent(FileContent& file_content) unitCommitmentModeToFileContent(file_content); maxNbYearsInParallelToFileContent(file_content); solverVersionToFileContent(file_content); - ORToolsUsed(file_content); ORToolsSolver(file_content); } @@ -144,21 +143,10 @@ void StudyInfoCollector::solverVersionToFileContent(FileContent& file_content) file_content.addItemToSection("study", "antares version", version); } -void StudyInfoCollector::ORToolsUsed(FileContent& file_content) -{ - const bool& ortoolsUsed = study_.parameters.optOptions.ortoolsUsed; - file_content.addItemToSection("study", "ortools used", ortoolsUsed ? "true" : "false"); -} - void StudyInfoCollector::ORToolsSolver(FileContent& file_content) { - const bool& ortoolsUsed = study_.parameters.optOptions.ortoolsUsed; - std::string ortoolsSolver = "none"; - if (ortoolsUsed) - { - ortoolsSolver = study_.parameters.optOptions.ortoolsSolver; - } - file_content.addItemToSection("study", "ortools solver", ortoolsSolver); + std::string solverName = study_.parameters.optOptions.ortoolsSolver; + file_content.addItemToSection("study", "ortools solver", solverName); } // Collecting data optimization problem diff --git a/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h b/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h index 2ac5a06c12..f12f40b4c0 100644 --- a/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h +++ b/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h @@ -51,7 +51,6 @@ class StudyInfoCollector void maxNbYearsInParallelToFileContent(FileContent& file_content); void solverVersionToFileContent(FileContent& file_content); - void ORToolsUsed(FileContent& file_content); void ORToolsSolver(FileContent& file_content); // Member data diff --git a/src/libs/antares/checks/checkLoadedInputData.cpp b/src/libs/antares/checks/checkLoadedInputData.cpp index e7ae0d1238..57cbbc3f46 100644 --- a/src/libs/antares/checks/checkLoadedInputData.cpp +++ b/src/libs/antares/checks/checkLoadedInputData.cpp @@ -30,21 +30,12 @@ namespace Antares::Check { void checkSolverMILPincompatibility(Antares::Data::UnitCommitmentMode ucMode, - bool ortoolsUsed, const std::string& solverName) { using namespace Antares::Data; - if (ucMode == UnitCommitmentMode::ucMILP) + if (ucMode == UnitCommitmentMode::ucMILP && solverName == "sirius") { - if (!ortoolsUsed) - { - throw Error::IncompatibleMILPWithoutOrtools(); - } - - if (solverName == "sirius") - { - throw Error::IncompatibleMILPOrtoolsSolver(); - } + throw Error::IncompatibleMILPOrtoolsSolver(); } } diff --git a/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h b/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h index 6a82fb4986..14ac20635c 100644 --- a/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h +++ b/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h @@ -25,7 +25,6 @@ namespace Antares::Check { void checkSolverMILPincompatibility(Antares::Data::UnitCommitmentMode ucMode, - bool ortoolsUsed, const std::string& solverName); void checkStudyVersion(const AnyString& optStudyFolder); diff --git a/src/libs/antares/optimization-options/include/antares/optimization-options/options.h b/src/libs/antares/optimization-options/include/antares/optimization-options/options.h index d1e60353ab..19fea8b2e6 100644 --- a/src/libs/antares/optimization-options/include/antares/optimization-options/options.h +++ b/src/libs/antares/optimization-options/include/antares/optimization-options/options.h @@ -27,8 +27,6 @@ namespace Antares::Solver::Optimization struct OptimizationOptions { - //! Force ortools use - bool ortoolsUsed = false; //! The solver name, sirius is the default std::string ortoolsSolver = "sirius"; bool solverLogs = false; diff --git a/src/libs/antares/study/parameters.cpp b/src/libs/antares/study/parameters.cpp index 8beca3503a..e26e57c6f7 100644 --- a/src/libs/antares/study/parameters.cpp +++ b/src/libs/antares/study/parameters.cpp @@ -1230,7 +1230,6 @@ bool Parameters::loadFromINI(const IniFile& ini, const StudyVersion& version) void Parameters::handleOptimizationOptions(const StudyLoadOptions& options) { // Options only set from the command-line - optOptions.ortoolsUsed = options.optOptions.ortoolsUsed; optOptions.ortoolsSolver = options.optOptions.ortoolsSolver; optOptions.solverParameters = options.optOptions.solverParameters; @@ -1724,12 +1723,8 @@ void Parameters::prepareForSimulation(const StudyLoadOptions& options) logs.info() << " :: ignoring hurdle costs"; } - // Indicate ortools solver used - if (options.optOptions.ortoolsUsed) - { - logs.info() << " :: ortools solver " << options.optOptions.ortoolsSolver - << " used for problem resolution"; - } + logs.info() << " :: solver " << options.optOptions.ortoolsSolver + << " is used for problem resolution"; // indicated that Problems will be named if (namedProblems) diff --git a/src/solver/application/application.cpp b/src/solver/application/application.cpp index 6a51546304..2d1695bcf0 100644 --- a/src/solver/application/application.cpp +++ b/src/solver/application/application.cpp @@ -278,7 +278,6 @@ void Application::postParametersChecks() const { // Some more checks require the existence of pParameters, hence of a study. // Their execution is delayed up to this point. checkSolverMILPincompatibility(pParameters->unitCommitment.ucMode, - pParameters->optOptions.ortoolsUsed, pParameters->optOptions.ortoolsSolver); checkSimplexRangeHydroPricing(pParameters->simplexOptimizationRange, diff --git a/src/solver/misc/options.cpp b/src/solver/misc/options.cpp index 8cf5d190e3..6470023aff 100644 --- a/src/solver/misc/options.cpp +++ b/src/solver/misc/options.cpp @@ -75,19 +75,11 @@ std::unique_ptr CreateParser(Settings& settings, StudyLoad "force-parallel", "Override the max number of years computed simultaneously"); - // add option for ortools use - // --use-ortools - parser->addFlag(options.optOptions.ortoolsUsed, - ' ', - "use-ortools", - "Use ortools library to launch solver"); - //--ortools-solver parser->add(options.optOptions.ortoolsSolver, ' ', - "ortools-solver", - "Ortools solver used for simulation (only available with use-ortools " - "option)\nAvailable solver list : " + "solver", + "Solver used for simulation\nAvailable solver list : " + availableOrToolsSolversString()); //--xpress-parameters @@ -265,18 +257,14 @@ void checkAndCorrectSettingsAndOptions(Settings& settings, Data::StudyLoadOption void checkOrtoolsSolver(const Antares::Solver::Optimization::OptimizationOptions& optOptions) { - if (optOptions.ortoolsUsed) - { - const std::string& solverName = optOptions.ortoolsSolver; - const std::list availableSolverList = getAvailableOrtoolsSolverName(); + const std::string& solverName = optOptions.ortoolsSolver; + const std::list availableSolverList = getAvailableOrtoolsSolverName(); - // Check if solver is available - bool found = (std::ranges::find(availableSolverList, solverName) - != availableSolverList.end()); - if (!found) - { - throw Error::InvalidSolver(optOptions.ortoolsSolver, availableOrToolsSolversString()); - } + // Check if solver is available + bool found = (std::ranges::find(availableSolverList, solverName) != availableSolverList.end()); + if (!found) + { + throw Error::InvalidSolver(optOptions.ortoolsSolver, availableOrToolsSolversString()); } } diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h index bd27921f8f..55cccc4e64 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h @@ -81,7 +81,7 @@ bool OPT_AppelDuSimplexe(const OptimizationOptions& options, const int, const OptPeriodStringGenerator&, Antares::Solver::IResultWriter& writer); -void OPT_LiberationProblemesSimplexe(const OptimizationOptions& options, const PROBLEME_HEBDO*); +void OPT_LiberationProblemesSimplexe(const PROBLEME_HEBDO*); bool OPT_OptimisationLineaire(const OptimizationOptions& options, PROBLEME_HEBDO* problemeHebdo, diff --git a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp index 4aee790ea9..2f6f907c5a 100644 --- a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp +++ b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp @@ -90,8 +90,7 @@ static SimplexResult OPT_TryToCallSimplex(const OptimizationOptions& options, IResultWriter& writer) { const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; - auto ProbSpx = (PROBLEME_SPX*)(ProblemeAResoudre->ProblemesSpx[(int)NumIntervalle]); - auto solver = (MPSolver*)(ProblemeAResoudre->ProblemesSpx[(int)NumIntervalle]); + auto solver = (MPSolver*)(ProblemeAResoudre->ProblemesSpx[NumIntervalle]); const int opt = optimizationNumber - 1; assert(opt >= 0 && opt < 2); @@ -99,11 +98,10 @@ static SimplexResult OPT_TryToCallSimplex(const OptimizationOptions& options, TIME_MEASURE timeMeasure; if (!PremierPassage) { - ProbSpx = nullptr; solver = nullptr; } - if (ProbSpx == nullptr && solver == nullptr) + if (solver == nullptr) { Probleme.Contexte = SIMPLEXE_SEUL; Probleme.BaseDeDepartFournie = NON_SPX; @@ -112,17 +110,13 @@ static SimplexResult OPT_TryToCallSimplex(const OptimizationOptions& options, { if (problemeHebdo->ReinitOptimisation) { - if (options.ortoolsUsed && solver) + if (solver) { ORTOOLS_LibererProbleme(solver); } - else if (ProbSpx != nullptr) - { - SPX_LibererProbleme(ProbSpx); - } + ProblemeAResoudre->ProblemesSpx[NumIntervalle] = nullptr; - ProbSpx = nullptr; solver = nullptr; Probleme.Contexte = SIMPLEXE_SEUL; Probleme.BaseDeDepartFournie = NON_SPX; @@ -133,31 +127,20 @@ static SimplexResult OPT_TryToCallSimplex(const OptimizationOptions& options, Probleme.BaseDeDepartFournie = UTILISER_LA_BASE_DU_PROBLEME_SPX; TimeMeasurement updateMeasure; - if (options.ortoolsUsed) - { - ORTOOLS_ModifierLeVecteurCouts(solver, - ProblemeAResoudre->CoutLineaire.data(), - ProblemeAResoudre->NombreDeVariables); - ORTOOLS_ModifierLeVecteurSecondMembre(solver, - ProblemeAResoudre->SecondMembre.data(), - ProblemeAResoudre->Sens.data(), - ProblemeAResoudre->NombreDeContraintes); - ORTOOLS_CorrigerLesBornes(solver, - ProblemeAResoudre->Xmin.data(), - ProblemeAResoudre->Xmax.data(), - ProblemeAResoudre->TypeDeVariable.data(), - ProblemeAResoudre->NombreDeVariables); - } - else - { - SPX_ModifierLeVecteurCouts(ProbSpx, + + ORTOOLS_ModifierLeVecteurCouts(solver, ProblemeAResoudre->CoutLineaire.data(), ProblemeAResoudre->NombreDeVariables); - SPX_ModifierLeVecteurSecondMembre(ProbSpx, + ORTOOLS_ModifierLeVecteurSecondMembre(solver, ProblemeAResoudre->SecondMembre.data(), ProblemeAResoudre->Sens.data(), ProblemeAResoudre->NombreDeContraintes); - } + ORTOOLS_CorrigerLesBornes(solver, + ProblemeAResoudre->Xmin.data(), + ProblemeAResoudre->Xmax.data(), + ProblemeAResoudre->TypeDeVariable.data(), + ProblemeAResoudre->NombreDeVariables); + updateMeasure.tick(); timeMeasure.updateTime = updateMeasure.duration_ms(); optimizationStatistics.addUpdateTime(timeMeasure.updateTime); @@ -214,7 +197,7 @@ static SimplexResult OPT_TryToCallSimplex(const OptimizationOptions& options, FillContext fillCtx(0, 167); LinearProblemBuilder linearProblemBuilder(fillersCollection); - if (options.ortoolsUsed && solver == nullptr) + if (solver == nullptr) { linearProblemBuilder.build(*ortoolsProblem, LP_Data, fillCtx); solver = ortoolsProblem->getMpSolver(); @@ -225,30 +208,20 @@ static SimplexResult OPT_TryToCallSimplex(const OptimizationOptions& options, problemeHebdo->exportMPSOnError, optimizationNumber, &Probleme, - options.ortoolsUsed, solver); auto mps_writer = mps_writer_factory.create(); mps_writer->runIfNeeded(writer, filename); TimeMeasurement measure; - if (options.ortoolsUsed) - { - const bool keepBasis = (optimizationNumber == PREMIERE_OPTIMISATION); - solver = ORTOOLS_Simplexe(&Probleme, solver, keepBasis, options); - if (solver != nullptr) - { - ProblemeAResoudre->ProblemesSpx[NumIntervalle] = (void*)solver; - } - } - else + + const bool keepBasis = (optimizationNumber == PREMIERE_OPTIMISATION); + solver = ORTOOLS_Simplexe(&Probleme, solver, keepBasis, options); + if (solver) { - ProbSpx = SPX_Simplexe(&Probleme, ProbSpx); - if (ProbSpx != nullptr) - { - ProblemeAResoudre->ProblemesSpx[NumIntervalle] = (void*)ProbSpx; - } + ProblemeAResoudre->ProblemesSpx[NumIntervalle] = (void*)solver; } + measure.tick(); timeMeasure.solveTime = measure.duration_ms(); optimizationStatistics.addSolveTime(timeMeasure.solveTime); @@ -258,14 +231,10 @@ static SimplexResult OPT_TryToCallSimplex(const OptimizationOptions& options, { if (ProblemeAResoudre->ExistenceDUneSolution != SPX_ERREUR_INTERNE) { - if (options.ortoolsUsed && solver) + if (solver) { ORTOOLS_LibererProbleme(solver); } - else if (ProbSpx != nullptr) - { - SPX_LibererProbleme(ProbSpx); - } logs.info() << " Solver: Standard resolution failed"; logs.info() << " Solver: Retry in safe mode"; // second trial w/o scaling diff --git a/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp b/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp index b1df3a06c9..d2a3922149 100644 --- a/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp +++ b/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp @@ -21,14 +21,12 @@ #include -#include "antares/optimization-options/options.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "antares/solver/utils/ortools_utils.h" using namespace Antares::Solver::Optimization; -void OPT_LiberationProblemesSimplexe(const OptimizationOptions& options, - const PROBLEME_HEBDO* problemeHebdo) +void OPT_LiberationProblemesSimplexe(const PROBLEME_HEBDO* problemeHebdo) { int NombreDePasDeTempsPourUneOptimisation; if (!problemeHebdo->OptimisationAuPasHebdomadaire) @@ -52,19 +50,13 @@ void OPT_LiberationProblemesSimplexe(const OptimizationOptions& options, { for (int numIntervalle = 0; numIntervalle < nbIntervalles; numIntervalle++) { - auto ProbSpx = (PROBLEME_SPX*)(ProblemeAResoudre->ProblemesSpx[numIntervalle]); auto solver = (MPSolver*)(ProblemeAResoudre->ProblemesSpx[numIntervalle]); - if (options.ortoolsUsed && solver) + if (solver) { ORTOOLS_LibererProbleme(solver); solver = nullptr; } - else if (ProbSpx) - { - SPX_LibererProbleme(ProbSpx); - ProbSpx = nullptr; - } } } } diff --git a/src/solver/optimisation/opt_optimisation_hebdo.cpp b/src/solver/optimisation/opt_optimisation_hebdo.cpp index 8317514098..bd0d78d037 100644 --- a/src/solver/optimisation/opt_optimisation_hebdo.cpp +++ b/src/solver/optimisation/opt_optimisation_hebdo.cpp @@ -34,7 +34,7 @@ bool OPT_PilotageOptimisationLineaire(const OptimizationOptions&, Solver::IResultWriter&, Solver::Simulation::ISimulationObserver&); bool OPT_PilotageOptimisationQuadratique(PROBLEME_HEBDO*); -void OPT_LiberationProblemesSimplexe(const OptimizationOptions&, const PROBLEME_HEBDO*); +void OPT_LiberationProblemesSimplexe(const PROBLEME_HEBDO*); void OPT_OptimisationHebdomadaire(const OptimizationOptions& options, PROBLEME_HEBDO* pProblemeHebdo, @@ -51,7 +51,7 @@ void OPT_OptimisationHebdomadaire(const OptimizationOptions& options, } else if (pProblemeHebdo->TypeDOptimisation == OPTIMISATION_QUADRATIQUE) { - OPT_LiberationProblemesSimplexe(options, pProblemeHebdo); + OPT_LiberationProblemesSimplexe(pProblemeHebdo); if (!OPT_PilotageOptimisationQuadratique(pProblemeHebdo)) { logs.error() << "Quadratic optimization failed"; diff --git a/src/solver/utils/include/antares/solver/utils/mps_utils.h b/src/solver/utils/include/antares/solver/utils/mps_utils.h index 0afe5901ff..abd9ba2451 100644 --- a/src/solver/utils/include/antares/solver/utils/mps_utils.h +++ b/src/solver/utils/include/antares/solver/utils/mps_utils.h @@ -57,6 +57,9 @@ class I_MPS_writer uint current_optim_number_ = 0; }; +// Caution : this class should be removed if we want Sirius behind or-tools +// But we want to keep the way we write MPS files for a named problem, +// so we keep it for now. class fullMPSwriter final: public I_MPS_writer { public: @@ -98,7 +101,6 @@ class mpsWriterFactory bool exportMPSOnError, const int current_optim_number, PROBLEME_SIMPLEXE_NOMME* named_splx_problem, - bool ortoolsUsed, MPSolver* solver); std::unique_ptr create(); @@ -113,7 +115,6 @@ class mpsWriterFactory Data::mpsExportStatus export_mps_; bool export_mps_on_error_; PROBLEME_SIMPLEXE_NOMME* named_splx_problem_ = nullptr; - bool ortools_used_; MPSolver* solver_ = nullptr; uint current_optim_number_; }; diff --git a/src/solver/utils/mps_utils.cpp b/src/solver/utils/mps_utils.cpp index 06b86f9a7c..02d023c5f5 100644 --- a/src/solver/utils/mps_utils.cpp +++ b/src/solver/utils/mps_utils.cpp @@ -163,12 +163,10 @@ mpsWriterFactory::mpsWriterFactory(Data::mpsExportStatus exportMPS, bool exportMPSOnError, const int current_optim_number, PROBLEME_SIMPLEXE_NOMME* named_splx_problem, - bool ortoolsUsed, MPSolver* solver): export_mps_(exportMPS), export_mps_on_error_(exportMPSOnError), named_splx_problem_(named_splx_problem), - ortools_used_(ortoolsUsed), solver_(solver), current_optim_number_(current_optim_number) { @@ -211,12 +209,5 @@ std::unique_ptr mpsWriterFactory::createOnOptimizationError() std::unique_ptr mpsWriterFactory::createFullmpsWriter() { - if (ortools_used_) - { - return std::make_unique(solver_, current_optim_number_); - } - else - { - return std::make_unique(named_splx_problem_, current_optim_number_); - } + return std::make_unique(solver_, current_optim_number_); } diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 2babe91fab..7c71c0918e 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -49,31 +49,31 @@ if(Python3_Interpreter_FOUND) # TODO : add more study batches add_test( NAME unfeasible - COMMAND Python3::Interpreter -m pytest -m unfeasible --solver-path=$ + COMMAND Python3::Interpreter -m pytest -m unfeasible --antares-simu-path=$ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/run-study-tests" ) add_test( NAME json - COMMAND Python3::Interpreter -m pytest -m json --solver-path=$ + COMMAND Python3::Interpreter -m pytest -m json --antares-simu-path=$ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/run-study-tests" ) add_test( NAME named-mps - COMMAND Python3::Interpreter -m pytest -m json --solver-path=$ --named-mps-problems + COMMAND Python3::Interpreter -m pytest -m json --antares-simu-path=$ --named-mps-problems WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/run-study-tests" ) add_test( NAME milp-cbc - COMMAND Python3::Interpreter -m pytest -m json --solver-path=$ --use-ortools --ortools-solver coin + COMMAND Python3::Interpreter -m pytest -m json --antares-simu-path=$ --solver coin WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/run-study-tests" ) add_test( NAME parallel - COMMAND Python3::Interpreter -m pytest -m json --solver-path=$ --force-parallel + COMMAND Python3::Interpreter -m pytest -m json --antares-simu-path=$ --force-parallel WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/run-study-tests" ) diff --git a/src/tests/cucumber/features/steps/common_steps/simulator_utils.py b/src/tests/cucumber/features/steps/common_steps/simulator_utils.py index 6f6349f773..e48b5a9da3 100644 --- a/src/tests/cucumber/features/steps/common_steps/simulator_utils.py +++ b/src/tests/cucumber/features/steps/common_steps/simulator_utils.py @@ -28,13 +28,11 @@ def init_simu(context): def build_antares_solver_command(context): command = [context.config.userdata["antares-solver"], "-i", str(context.study_path)] - if "use-ortools" in context.config.userdata and context.config.userdata["use-ortools"].lower() == 'true': - command.append('--use-ortools') - if "ortools-solver" in context.config.userdata: - solver = context.config.userdata["ortools-solver"] - else: - solver = "sirius" - command.append('--ortools-solver=' + solver) + solver = "sirius" + if "solver" in context.config.userdata: + solver = context.config.userdata["solver"] + command.append('--solver=' + solver) + if context.named_mps_problems: command.append('--named-mps-problems') if context.parallel: diff --git a/src/tests/end-to-end/simple_study/simple-study.cpp b/src/tests/end-to-end/simple_study/simple-study.cpp index 2664dc97d0..dbc29c2ae4 100644 --- a/src/tests/end-to-end/simple_study/simple-study.cpp +++ b/src/tests/end-to-end/simple_study/simple-study.cpp @@ -201,7 +201,6 @@ BOOST_FIXTURE_TEST_CASE(milp_two_mc_single_unit_single_scenario, StudyFixture) // Use OR-Tools / COIN for MILP auto& p = study->parameters; p.unitCommitment.ucMode = ucMILP; - p.optOptions.ortoolsUsed = true; p.optOptions.ortoolsSolver = "coin"; simulation->create(); @@ -230,7 +229,6 @@ BOOST_FIXTURE_TEST_CASE(milp_two_mc_two_unit_single_scenario, StudyFixture) // Use OR-Tools / COIN for MILP auto& p = study->parameters; p.unitCommitment.ucMode = ucMILP; - p.optOptions.ortoolsUsed = true; p.optOptions.ortoolsSolver = "coin"; simulation->create(); diff --git a/src/tests/end-to-end/test_simple-test.py b/src/tests/end-to-end/test_simple-test.py deleted file mode 100644 index 83ee9a0f9e..0000000000 --- a/src/tests/end-to-end/test_simple-test.py +++ /dev/null @@ -1,95 +0,0 @@ -import os -import sys -from pathlib import Path -import tempfile as tpf -from distutils.dir_util import copy_tree - -import subprocess - -import numpy as np - -def find_integrity_path(output_dir): - op = [] - for path in Path(output_dir).rglob('checkIntegrity.txt'): - op.append(path) - assert len(op) == 1 - return op[0] - -def get_integrity_check_values(output : Path) -> np.array : - integrity_path = find_integrity_path(output) - integrity_file = open(str(integrity_path), 'r') - output_values = list() - for x in integrity_file: - output_values.append(float(x)) - assert len(output_values) == 8 - return output_values - -def find_solver_path(): - def is_exe(fpath): - if sys.platform == 'linux': - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) - elif sys.platform == 'win32': - return fpath.endswith('.exe') - - search_result = list() - for path in Path.cwd().parent.parent.parent.rglob('solver/antares-*.*-solver*'): - search_result.append(path) - # Eliminate swap version - solver = list(filter(lambda x: "swap" not in str(x) and is_exe(x), search_result)) - assert len(solver) == 1 - return str(solver[0]) - -def launch_solver(study_path, use_ortools = False, ortools_solver = "sirius"): - # Find solver executable - solver_path = find_solver_path() - - command = [solver_path, "-i", str(study_path)] - if use_ortools: - command.append('--use-ortools') - command.append('--ortools-solver='+ortools_solver) - process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None) - output = process.communicate() - - # TODO check return value - assert "Solver returned error" not in output[0].decode('utf-8') - - -def test_free_data_sample_no_ortools(tmp_path): - # Study copied to temporary directory - fds = Path.cwd().parent / 'data' / 'free_data_sample' - copy_tree(str(fds), str(tmp_path)) - study_path = str(tmp_path) - # Launch antares-solver - launch_solver(study_path) - # Check results - expected_values = np.array([2.85657392370263e+11, - 0.00000000000000e+00, - 2.85657392370263e+11, - 2.85657392370263e+11, - 2.85657544872729e+11, - 0.00000000000000e+00, - 2.85657544872729e+11, - 2.85657544872729e+11]) - output_path = Path(study_path) / 'output' - output_values = get_integrity_check_values(output_path) - np.testing.assert_equal(expected_values, output_values) - -def test_free_data_sample_ortools(tmp_path): - # Study copied to temporary directory - fds = Path.cwd().parent / 'data' / 'free_data_sample' - copy_tree(str(fds), str(tmp_path)) - study_path = str(tmp_path) - # Launch antares-solver - launch_solver(study_path, True, 'sirius') - # Check results - expected_values = np.array([2.85657392370263e+11, - 0.00000000000000e+00, - 2.85657392370263e+11, - 2.85657392370263e+11, - 2.85657544872729e+11, - 0.00000000000000e+00, - 2.85657544872729e+11, - 2.85657544872729e+11]) - output_path = Path(study_path) / 'output' - output_values = get_integrity_check_values(output_path) - np.testing.assert_equal(expected_values, output_values) diff --git a/src/tests/run-study-tests/actions_on_study/study_run.py b/src/tests/run-study-tests/actions_on_study/study_run.py index 8867aafda5..0ccb598a46 100644 --- a/src/tests/run-study-tests/actions_on_study/study_run.py +++ b/src/tests/run-study-tests/actions_on_study/study_run.py @@ -4,11 +4,10 @@ from utils.assertions import check class study_run: - def __init__(self, study_path, solver_path, use_ortools, ortools_solver, named_mps_problems, parallel): + def __init__(self, study_path, antares_simu_path, solver_name, named_mps_problems, parallel): self.study_path = study_path - self.solver_path = solver_path - self.use_ortools = use_ortools - self.ortools_solver = ortools_solver + self.antares_simu_path = antares_simu_path + self.solverName = solver_name self.named_mps_problems = named_mps_problems self.parallel = parallel self.raise_exception_on_failure = True @@ -20,12 +19,10 @@ def no_exception_raised_on_failure(self): def run(self): print("\nRunning the study") - solver_full_path = str(Path(self.solver_path).resolve()) + antares_full_path = str(Path(self.antares_simu_path).resolve()) - command = [solver_full_path, "-i", str(self.study_path)] - if self.use_ortools: - command.append('--use-ortools') - command.append('--ortools-solver=' + self.ortools_solver) + command = [antares_full_path, "-i", str(self.study_path)] + command.append('--solver=' + self.solverName) if self.named_mps_problems: command.append('--named-mps-problems') if self.parallel: diff --git a/src/tests/run-study-tests/conftest.py b/src/tests/run-study-tests/conftest.py index f38b048ca0..c92312841e 100644 --- a/src/tests/run-study-tests/conftest.py +++ b/src/tests/run-study-tests/conftest.py @@ -1,24 +1,19 @@ import pytest def pytest_addoption(parser): - parser.addoption("--use-ortools", action="store_true", default=False) - parser.addoption("--ortools-solver", action="store", default="sirius") - parser.addoption("--solver-path", action="store") + parser.addoption("--solver", action="store", default="sirius") + parser.addoption("--antares-simu-path", action="store") parser.addoption("--named-mps-problems", action="store_true", default=False) parser.addoption("--force-parallel", action="store_true", default=False) parser.addoption("--ts-generator", action="store_true", default=False) @pytest.fixture() -def ortools_solver(request): - return request.config.getoption("--ortools-solver") +def solver_name(request): + return request.config.getoption("--solver") @pytest.fixture() -def use_ortools(request): - return request.config.getoption("--use-ortools") - -@pytest.fixture() -def solver_path(request): - return request.config.getoption("--solver-path") +def antares_simu_path(request): + return request.config.getoption("--antares-simu-path") @pytest.fixture() def named_mps_problems(request): diff --git a/src/tests/run-study-tests/fixtures.py b/src/tests/run-study-tests/fixtures.py index 5f4945f379..c3ee38ee1b 100644 --- a/src/tests/run-study-tests/fixtures.py +++ b/src/tests/run-study-tests/fixtures.py @@ -40,8 +40,8 @@ def resultsRemover(study_path): return results_remover(study_path) @pytest.fixture -def simulation(study_path, solver_path, use_ortools, ortools_solver, named_mps_problems, parallel): - return study_run(study_path, solver_path, use_ortools, ortools_solver, named_mps_problems, parallel) +def simulation(study_path, antares_simu_path, solver_name, named_mps_problems, parallel): + return study_run(study_path, antares_simu_path, solver_name, named_mps_problems, parallel) @pytest.fixture(autouse=True) def check_runner(simulation, resultsRemover): diff --git a/src/tests/run-study-tests/readme.md b/src/tests/run-study-tests/readme.md index d2536dab64..3eb4d27ebb 100644 --- a/src/tests/run-study-tests/readme.md +++ b/src/tests/run-study-tests/readme.md @@ -5,8 +5,11 @@ Here is an automatic testing python script system. This program performs the following : 1. Searches for all studies in a given directory 2. From each study, retrieves the specifications to make checks on the simulation results of that study (see items below) -3. Runs a simlulation on each study -4. Given the results of the simulation on a study, makes the checks retrieved at step 2 on these results (for instance : make sure current results and reference resuts are identical, check for existence or content of output files,...) +3. Runs a simulation on each study +4. Given the results of the simulation on a study, makes the checks retrieved at step 2 on these results. + Examples : + - make sure current results and reference resuts are identical + - check for existence or even content of output files Note that each study found is supposed to contain the definition of checks performed by scripts after the simulation on the study is completed. So, each study is supposed to contain a file **check-config.json** for that purpose. This file is build manually for each study. @@ -42,7 +45,7 @@ In the following, we comment the content of this script. Lines of this scripts a ## Fixtures **pytest** comes with the notion of **fixture**. Fixtures allow executing a piece of code just before a test runs. -To take bebefit of a fixture, a test needs to be given this fixture as argument. +To take benefit of a fixture, a test needs to be given this fixture as argument. Fixture themselves can also be given arguments, we'll see how we do it (in the context of the current testing system) when we talk about **parametrization**. Fixtures return a result to be used in the test. Let's look at a simple test : diff --git a/src/ui/simulator/application/study.cpp b/src/ui/simulator/application/study.cpp index e2b5a1416f..c19ea5a1f8 100644 --- a/src/ui/simulator/application/study.cpp +++ b/src/ui/simulator/application/study.cpp @@ -1090,8 +1090,7 @@ void RunSimulationOnTheStudy(Data::Study::Ptr study, bool ignoreWarnings, Solver::Feature features, bool preproOnly, - bool useOrtools, - const std::string& ortoolsSolver) + const std::string& solverName) { if (!study) // A valid study would be better { @@ -1207,14 +1206,8 @@ void RunSimulationOnTheStudy(Data::Study::Ptr study, if (features == Solver::parallel) cmd << " --parallel"; - // Use ortools ? - if (useOrtools) - { - cmd << " --use-ortools"; - - // add solver name for ortools - cmd << " --ortools-solver=" << ortoolsSolver; - } + // add solver name for ortools + cmd << " --solver=" << solverName; // Go go go ! logs.debug() << "running " << cmd; diff --git a/src/ui/simulator/application/study.h b/src/ui/simulator/application/study.h index 569de2e9e4..aa27d529e8 100644 --- a/src/ui/simulator/application/study.h +++ b/src/ui/simulator/application/study.h @@ -113,8 +113,7 @@ bool CheckIfInsideAStudyFolder(const AnyString& path, bool quiet = false); ** \param simuName User-Name of the simulation ** \param simuComments Comments for the simulation ** \param ignoreWarnings True if warnings can be silently ignored -** \param useOrtools True if ortools must be used by antares-solver -** \param ortoolsSolver Ortools solver used in case of ortools use by antares-solver +** \param solverName Solver used */ void RunSimulationOnTheStudy(Data::Study::Ptr study, const YString& simuName, @@ -122,8 +121,7 @@ void RunSimulationOnTheStudy(Data::Study::Ptr study, bool ignoreWarnings, Solver::Feature features = Solver::standard, bool preproOnly = false, - bool useOrtools = false, - const std::string& ortoolsSolver = "sirius"); + const std::string& solverName = "sirius"); /*! ** \brief Update the state of controls diff --git a/src/ui/simulator/windows/simulation/run.cpp b/src/ui/simulator/windows/simulation/run.cpp index e32fb55101..e4bfa1cc69 100644 --- a/src/ui/simulator/windows/simulation/run.cpp +++ b/src/ui/simulator/windows/simulation/run.cpp @@ -309,32 +309,18 @@ Run::Run(wxWindow* parent, bool preproOnly) : // Ortools use { - // Ortools use - auto* ortoolsCheckBox = new wxCheckBox(pBigDaddy, wxID_ANY, wxT("")); - ortoolsCheckBox->SetValue(false); - - Connect(ortoolsCheckBox->GetId(), - wxEVT_COMMAND_CHECKBOX_CLICKED, - wxCommandEventHandler(Run::onOrtoolsCheckboxChanged)); - pOrtoolsCheckBox = ortoolsCheckBox; - // Ortools solver selection pTitleOrtoolsSolverCombox = Antares::Component::CreateLabel(pBigDaddy, wxT("Ortools solver : ")); pOrtoolsSolverCombox = new wxComboBox(pBigDaddy, wxID_ANY); - std::list ortoolsSolverList = getAvailableOrtoolsSolverName(); - for (const std::string& ortoolsSolver : ortoolsSolverList) + std::list solverList = getAvailableOrtoolsSolverName(); + for (const std::string& solverName : solverList) { - pOrtoolsSolverCombox->Append(ortoolsSolver); + pOrtoolsSolverCombox->Append(solverName); } - // Ortools solver selection visibility - pTitleOrtoolsSolverCombox->Show(pOrtoolsCheckBox->GetValue()); - pOrtoolsSolverCombox->Show(pOrtoolsCheckBox->GetValue()); - - // Display 2 rows for ortools option - gridAppend(*s, wxT("Ortools use : "), ortoolsCheckBox); + // Display ortools solver list gridAppend(*s, pTitleOrtoolsSolverCombox, pOrtoolsSolverCombox); } @@ -632,7 +618,6 @@ void Run::onRun(void*) pIgnoreWarnings->GetValue(), // Ignore warnings featuresAlias[pFeatureIndex], // Features pPreproOnly->GetValue(), // Prepro Only ? - pOrtoolsCheckBox->IsChecked(), // Ortools use pOrtoolsSolverCombox->GetValue().ToStdString()); // Ortools solver // Remove the temporary file @@ -810,20 +795,6 @@ void Run::onInternalMotion(wxMouseEvent&) Antares::Component::Panel::OnMouseMoveFromExternalComponent(); } -void Run::onOrtoolsCheckboxChanged(wxCommandEvent& WXUNUSED(event)) -{ - pTitleOrtoolsSolverCombox->Show(pOrtoolsCheckBox->GetValue()); - pOrtoolsSolverCombox->Show(pOrtoolsCheckBox->GetValue()); - - // Layout update - auto* sizer = pBigDaddy->GetSizer(); - if (sizer) - sizer->Fit(pBigDaddy); - sizer = GetSizer(); - if (sizer) - sizer->Fit(this); -} - } // namespace Antares::Window::Simulation diff --git a/src/ui/simulator/windows/simulation/run.h b/src/ui/simulator/windows/simulation/run.h index f9a7ef395c..ca554e9f14 100644 --- a/src/ui/simulator/windows/simulation/run.h +++ b/src/ui/simulator/windows/simulation/run.h @@ -107,14 +107,11 @@ class Run final : public wxDialog //! Mouse move void onInternalMotion(wxMouseEvent&); - void onOrtoolsCheckboxChanged(wxCommandEvent& event); - private: //! The main control parent wxWindow* pBigDaddy; //! Solver mode Antares::Component::Button* pBtnMode; - wxCheckBox* pOrtoolsCheckBox; wxStaticText* pTitleOrtoolsSolverCombox; wxComboBox* pOrtoolsSolverCombox; From a26436eca8b7289e4b7556103e5e2e65d46c477e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Thu, 28 Nov 2024 12:30:01 +0100 Subject: [PATCH 064/103] Fix build after the removal of bool OptimizationOptions::ortoolsUsed (#2505) We missed out some instances of `ortoolsUsed` because #2450 and #2502 were concurrent. --- src/tests/src/api_internal/test_api.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/tests/src/api_internal/test_api.cpp b/src/tests/src/api_internal/test_api.cpp index 082972bcc3..5214aa8c10 100644 --- a/src/tests/src/api_internal/test_api.cpp +++ b/src/tests/src/api_internal/test_api.cpp @@ -105,8 +105,7 @@ BOOST_AUTO_TEST_CASE(result_with_ortools_coin) { Antares::API::APIInternal api; auto study_loader = std::make_unique(); - const Antares::Solver::Optimization::OptimizationOptions opt{.ortoolsUsed = true, - .ortoolsSolver = "coin", + const Antares::Solver::Optimization::OptimizationOptions opt{.ortoolsSolver = "coin", .solverLogs = false, .solverParameters = ""}; @@ -123,7 +122,6 @@ BOOST_AUTO_TEST_CASE(invalid_ortools_solver) Antares::API::APIInternal api; auto study_loader = std::make_unique(); const Antares::Solver::Optimization::OptimizationOptions opt{ - .ortoolsUsed = true, .ortoolsSolver = "this-solver-does-not-exist", .solverLogs = true, .solverParameters = ""}; From d4a660ecd6e4c7dbfaaa8943870ed6889e210d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Thu, 28 Nov 2024 13:20:34 +0100 Subject: [PATCH 065/103] Fix timestamp = 0 in file info.antares-output (ANT-2494) (#2508) and read of initialized variable --- src/libs/antares/study/study.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/antares/study/study.cpp b/src/libs/antares/study/study.cpp index 9db4360b03..0595bfadb5 100644 --- a/src/libs/antares/study/study.cpp +++ b/src/libs/antares/study/study.cpp @@ -490,6 +490,8 @@ fs::path StudyCreateOutputPath(SimulationMode mode, void Study::prepareOutput() { + pStartTime = DateTime::Now(); + if (parameters.noOutput || !usedByTheSolver) { return; From 225c7a81f60a899ec63f6d012cfaffbd6d63baa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 2 Dec 2024 12:46:16 +0100 Subject: [PATCH 066/103] Rename thread_number -> numSpace for consistency (#2515) Even though numSpace isn't a great name, we should stick to it for consistency. Otherwise it's confusing. --- .../adq_patch_post_process_list.cpp | 12 +++++----- .../adq_patch_post_process_list.h | 2 +- .../optimisation/optim_post_process_list.h | 2 +- .../optimisation/post_process_commands.h | 16 ++++++------- .../optimisation/optim_post_process_list.cpp | 8 +++---- .../optimisation/post_process_commands.cpp | 24 +++++++++---------- src/solver/simulation/base_post_process.cpp | 8 +++---- .../solver/simulation/base_post_process.h | 6 ++--- 8 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp b/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp index 996ec70c6e..1d54cb0da0 100644 --- a/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp +++ b/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp @@ -27,15 +27,15 @@ namespace Antares::Solver::Simulation { AdqPatchPostProcessList::AdqPatchPostProcessList(const AdqPatchParams& adqPatchParams, PROBLEME_HEBDO* problemeHebdo, - uint thread_number, + uint numSpace, AreaList& areas, SheddingPolicy sheddingPolicy, SimplexOptimization splxOptimization, Calendar& calendar): - interfacePostProcessList(problemeHebdo, thread_number) + interfacePostProcessList(problemeHebdo, numSpace) { post_process_list.push_back( - std::make_unique(problemeHebdo_, thread_number_, areas)); + std::make_unique(problemeHebdo_, numSpace_, areas)); post_process_list.push_back( std::make_unique(problemeHebdo_, areas, false, false)); @@ -43,16 +43,16 @@ AdqPatchPostProcessList::AdqPatchPostProcessList(const AdqPatchParams& adqPatchP areas, sheddingPolicy, splxOptimization, - thread_number)); + numSpace)); // Here a post process particular to adq patch post_process_list.push_back(std::make_unique(adqPatchParams, problemeHebdo_, areas, - thread_number_)); + numSpace_)); // Here a post process particular to adq patch post_process_list.push_back( - std::make_unique(problemeHebdo_, areas, thread_number)); + std::make_unique(problemeHebdo_, areas, numSpace)); post_process_list.push_back( std::make_unique(problemeHebdo_, areas, true, false)); post_process_list.push_back( diff --git a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.h b/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.h index cba4657fb2..d73ce8cfd2 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.h @@ -34,7 +34,7 @@ class AdqPatchPostProcessList: public interfacePostProcessList public: AdqPatchPostProcessList(const AdqPatchParams& adqPatchParams, PROBLEME_HEBDO* problemeHebdo, - uint thread_number, + uint numSpace, AreaList& areas, SheddingPolicy sheddingPolicy, SimplexOptimization splxOptimization, diff --git a/src/solver/optimisation/include/antares/solver/optimisation/optim_post_process_list.h b/src/solver/optimisation/include/antares/solver/optimisation/optim_post_process_list.h index eecd9edfba..833a556db1 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/optim_post_process_list.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/optim_post_process_list.h @@ -29,7 +29,7 @@ class OptPostProcessList: public interfacePostProcessList { public: OptPostProcessList(PROBLEME_HEBDO* problemeHebdo, - uint thread_number, + uint numSpace, AreaList& areas, SheddingPolicy sheddingPolicy, SimplexOptimization splxOptimization, diff --git a/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h b/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h index 5bf5ecf314..4c3fd49bd1 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h @@ -28,12 +28,12 @@ class DispatchableMarginPostProcessCmd: public basePostProcessCommand { public: DispatchableMarginPostProcessCmd(PROBLEME_HEBDO* problemeHebdo, - unsigned int thread_number, + unsigned int numSpace, AreaList& areas); void execute(const optRuntimeData& opt_runtime_data) override; private: - unsigned int thread_number_ = 0; + unsigned int numSpace_ = 0; const AreaList& area_list_; }; @@ -59,12 +59,12 @@ class RemixHydroPostProcessCmd: public basePostProcessCommand AreaList& areas, SheddingPolicy sheddingPolicy, SimplexOptimization simplexOptimization, - unsigned int thread_number); + unsigned int numSpace); void execute(const optRuntimeData& opt_runtime_data) override; private: const AreaList& area_list_; - unsigned int thread_number_ = 0; + unsigned int numSpace_ = 0; SheddingPolicy shedding_policy_; SimplexOptimization splx_optimization_; }; @@ -76,13 +76,13 @@ class DTGmarginForAdqPatchPostProcessCmd: public basePostProcessCommand public: DTGmarginForAdqPatchPostProcessCmd(PROBLEME_HEBDO* problemeHebdo, AreaList& areas, - unsigned int thread_number); + unsigned int numSpace); void execute(const optRuntimeData& opt_runtime_data) override; private: const AreaList& area_list_; - unsigned int thread_number_ = 0; + unsigned int numSpace_ = 0; }; class InterpolateWaterValuePostProcessCmd: public basePostProcessCommand @@ -118,7 +118,7 @@ class CurtailmentSharingPostProcessCmd: public basePostProcessCommand CurtailmentSharingPostProcessCmd(const AdqPatchParams& adqPatchParams, PROBLEME_HEBDO* problemeHebdo, AreaList& areas, - unsigned int thread_number); + unsigned int numSpace); void execute(const optRuntimeData& opt_runtime_data) override; @@ -130,7 +130,7 @@ class CurtailmentSharingPostProcessCmd: public basePostProcessCommand const AreaList& area_list_; const AdqPatchParams& adqPatchParams_; - unsigned int thread_number_ = 0; + unsigned int numSpace_ = 0; }; } // namespace Antares::Solver::Simulation diff --git a/src/solver/optimisation/optim_post_process_list.cpp b/src/solver/optimisation/optim_post_process_list.cpp index a9eb38f7e8..9f52a11ac1 100644 --- a/src/solver/optimisation/optim_post_process_list.cpp +++ b/src/solver/optimisation/optim_post_process_list.cpp @@ -26,24 +26,24 @@ namespace Antares::Solver::Simulation { OptPostProcessList::OptPostProcessList(PROBLEME_HEBDO* problemeHebdo, - uint thread_number, + uint numSpace, AreaList& areas, SheddingPolicy sheddingPolicy, SimplexOptimization splxOptimization, Calendar& calendar) : - interfacePostProcessList(problemeHebdo, thread_number) + interfacePostProcessList(problemeHebdo, numSpace) { post_process_list.push_back( - std::make_unique(problemeHebdo_, thread_number_, areas)); + std::make_unique(problemeHebdo_, numSpace_, areas)); post_process_list.push_back( std::make_unique(problemeHebdo_, areas, false, false)); post_process_list.push_back(std::make_unique(problemeHebdo_, areas, sheddingPolicy, splxOptimization, - thread_number)); + numSpace)); post_process_list.push_back( std::make_unique(problemeHebdo_, areas, true, false)); post_process_list.push_back( diff --git a/src/solver/optimisation/post_process_commands.cpp b/src/solver/optimisation/post_process_commands.cpp index 7ca5a4b0d5..b069050960 100644 --- a/src/solver/optimisation/post_process_commands.cpp +++ b/src/solver/optimisation/post_process_commands.cpp @@ -34,10 +34,10 @@ const uint nbHoursInWeek = 168; // Dispatchable Margin // ----------------------------- DispatchableMarginPostProcessCmd::DispatchableMarginPostProcessCmd(PROBLEME_HEBDO* problemeHebdo, - unsigned int thread_number, + unsigned int numSpace, AreaList& areas): basePostProcessCommand(problemeHebdo), - thread_number_(thread_number), + numSpace_(numSpace), area_list_(areas) { } @@ -49,7 +49,7 @@ void DispatchableMarginPostProcessCmd::execute(const optRuntimeData& opt_runtime area_list_.each( [this, &hourInYear, &year](Data::Area& area) { - double* dtgmrg = area.scratchpad[thread_number_].dispatchableGenerationMargin; + double* dtgmrg = area.scratchpad[numSpace_].dispatchableGenerationMargin; for (uint h = 0; h != nbHoursInWeek; ++h) { dtgmrg[h] = 0.; @@ -96,10 +96,10 @@ RemixHydroPostProcessCmd::RemixHydroPostProcessCmd(PROBLEME_HEBDO* problemeHebdo AreaList& areas, SheddingPolicy sheddingPolicy, SimplexOptimization simplexOptimization, - unsigned int thread_number): + unsigned int numSpace): basePostProcessCommand(problemeHebdo), area_list_(areas), - thread_number_(thread_number), + numSpace_(numSpace), shedding_policy_(sheddingPolicy), splx_optimization_(simplexOptimization) { @@ -112,7 +112,7 @@ void RemixHydroPostProcessCmd::execute(const optRuntimeData& opt_runtime_data) *problemeHebdo_, shedding_policy_, splx_optimization_, - thread_number_, + numSpace_, hourInYear); } @@ -124,10 +124,10 @@ using namespace Antares::Data::AdequacyPatch; DTGmarginForAdqPatchPostProcessCmd::DTGmarginForAdqPatchPostProcessCmd( PROBLEME_HEBDO* problemeHebdo, AreaList& areas, - unsigned int thread_number): + unsigned int numSpace): basePostProcessCommand(problemeHebdo), area_list_(areas), - thread_number_(thread_number) + numSpace_(numSpace) { } @@ -147,7 +147,7 @@ void DTGmarginForAdqPatchPostProcessCmd::execute(const optRuntimeData&) for (uint hour = 0; hour < nbHoursInWeek; hour++) { auto& hourlyResults = problemeHebdo_->ResultatsHoraires[Area]; - const auto& scratchpad = area_list_[Area]->scratchpad[thread_number_]; + const auto& scratchpad = area_list_[Area]->scratchpad[numSpace_]; const double dtgMrg = scratchpad.dispatchableGenerationMargin[hour]; const double ens = hourlyResults.ValeursHorairesDeDefaillancePositive[hour]; const bool triggered = problemeHebdo_->adequacyPatchRuntimeData @@ -211,11 +211,11 @@ CurtailmentSharingPostProcessCmd::CurtailmentSharingPostProcessCmd( const AdqPatchParams& adqPatchParams, PROBLEME_HEBDO* problemeHebdo, AreaList& areas, - unsigned int thread_number): + unsigned int numSpace): basePostProcessCommand(problemeHebdo), area_list_(areas), adqPatchParams_(adqPatchParams), - thread_number_(thread_number) + numSpace_(numSpace) { } @@ -256,7 +256,7 @@ double CurtailmentSharingPostProcessCmd::calculateDensNewAndTotalLmrViolation() // adjust densNew according to the new specification/request by ELIA /* DENS_new (node A) = max [ 0; ENS_init (node A) + net_position_init (node A) + ? flows (node 1 -> node A) - DTG.MRG(node A)] */ - const auto& scratchpad = area_list_[Area]->scratchpad[thread_number_]; + const auto& scratchpad = area_list_[Area]->scratchpad[numSpace_]; double dtgMrg = scratchpad.dispatchableGenerationMargin[hour]; // write down densNew values for all the hours problemeHebdo_->ResultatsHoraires[Area].ValeursHorairesDENS[hour] = std::max( diff --git a/src/solver/simulation/base_post_process.cpp b/src/solver/simulation/base_post_process.cpp index 4cd7bb8cf9..d3c2da7f3c 100644 --- a/src/solver/simulation/base_post_process.cpp +++ b/src/solver/simulation/base_post_process.cpp @@ -36,14 +36,14 @@ basePostProcessCommand::basePostProcessCommand(PROBLEME_HEBDO* problemeHebdo): interfacePostProcessList::interfacePostProcessList(PROBLEME_HEBDO* problemesHebdo, uint numSpace): problemeHebdo_(problemesHebdo), - thread_number_(numSpace) + numSpace_(numSpace) { } std::unique_ptr interfacePostProcessList::create( AdqPatchParams& adqPatchParams, PROBLEME_HEBDO* problemeHebdo, - uint thread_number, + uint numSpace, AreaList& areas, SheddingPolicy sheddingPolicy, SimplexOptimization splxOptimization, @@ -53,7 +53,7 @@ std::unique_ptr interfacePostProcessList::create( { return std::make_unique(adqPatchParams, problemeHebdo, - thread_number, + numSpace, areas, sheddingPolicy, splxOptimization, @@ -62,7 +62,7 @@ std::unique_ptr interfacePostProcessList::create( else { return std::make_unique(problemeHebdo, - thread_number, + numSpace, areas, sheddingPolicy, splxOptimization, diff --git a/src/solver/simulation/include/antares/solver/simulation/base_post_process.h b/src/solver/simulation/include/antares/solver/simulation/base_post_process.h index 6918fb85d3..f1e6215415 100644 --- a/src/solver/simulation/include/antares/solver/simulation/base_post_process.h +++ b/src/solver/simulation/include/antares/solver/simulation/base_post_process.h @@ -71,7 +71,7 @@ class interfacePostProcessList // gp : the constructors' signatures of the post process list classes. static std::unique_ptr create(AdqPatchParams& adqPatchParams, PROBLEME_HEBDO* problemeHebdo, - uint thread_number, + uint numSpace, AreaList& areas, SheddingPolicy sheddingPolicy, SimplexOptimization splxOptimization, @@ -80,11 +80,11 @@ class interfacePostProcessList protected: // Member functions - interfacePostProcessList(PROBLEME_HEBDO* problemeHebdo, uint thread_number); + interfacePostProcessList(PROBLEME_HEBDO* problemeHebdo, uint numSpace); // Data mambers PROBLEME_HEBDO* const problemeHebdo_ = nullptr; - const unsigned int thread_number_ = 0; + const unsigned int numSpace_; std::vector> post_process_list; }; From 6f017c664581d90b7394a80a7ed998023bce8313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 2 Dec 2024 20:34:15 +0100 Subject: [PATCH 067/103] Fix variable bounds for 1st week in the year (#2517) See function `ORTOOLS_CorrigerLesBornes`. --- src/solver/optimisation/LegacyFiller.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/solver/optimisation/LegacyFiller.cpp b/src/solver/optimisation/LegacyFiller.cpp index 7cbcaff820..c1f2f7edcb 100644 --- a/src/solver/optimisation/LegacyFiller.cpp +++ b/src/solver/optimisation/LegacyFiller.cpp @@ -46,9 +46,18 @@ void LegacyFiller::CopyMatrix(ILinearProblem& pb) const void LegacyFiller::CreateVariable(unsigned idxVar, ILinearProblem& pb) const { - double min_l = problemeSimplexe_->Xmin[idxVar]; - double max_l = problemeSimplexe_->Xmax[idxVar]; - bool isIntegerVariable = problemeSimplexe_->IntegerVariable(idxVar); + const double bMin = problemeSimplexe_->Xmin[idxVar]; + const double bMax = problemeSimplexe_->Xmax[idxVar]; + const int typeVar = problemeSimplexe_->TypeDeVariable[idxVar]; + + double min_l = (typeVar == VARIABLE_NON_BORNEE || typeVar == VARIABLE_BORNEE_SUPERIEUREMENT) + ? -pb.infinity() + : bMin; + double max_l = (typeVar == VARIABLE_NON_BORNEE || typeVar == VARIABLE_BORNEE_INFERIEUREMENT) + ? pb.infinity() + : bMax; + const bool isIntegerVariable = problemeSimplexe_->IntegerVariable(idxVar); + auto* var = pb.addVariable(min_l, max_l, isIntegerVariable, GetVariableName(idxVar)); pb.setObjectiveCoefficient(var, problemeSimplexe_->CoutLineaire[idxVar]); } From 9022814e71efd409cccf7fa12931e3bbbf948555 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:03:24 +0100 Subject: [PATCH 068/103] Fix segfault when there are more districts than areas [ANT-2452] (#2516) --- src/solver/variable/surveyresults/surveyresults.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/solver/variable/surveyresults/surveyresults.cpp b/src/solver/variable/surveyresults/surveyresults.cpp index 6a89d2cb14..cb88d34003 100644 --- a/src/solver/variable/surveyresults/surveyresults.cpp +++ b/src/solver/variable/surveyresults/surveyresults.cpp @@ -553,16 +553,12 @@ SurveyResults::SurveyResults(const Data::Study& s, const Yuni::String& o, IResul } uint nbAreas = s.areas.size(); - uint nbSetsOfAreas = s.areas.size(); + uint nbSetsOfAreas = s.setsOfAreas.size(); digestSize = (nbAreas > nbSetsOfAreas) ? nbAreas : nbSetsOfAreas; digestNonApplicableStatus = new bool*[digestSize]; for (uint i = 0; i < digestSize; i++) { - digestNonApplicableStatus[i] = new bool[maxVariables]; - for (uint v = 0; v < maxVariables; v++) - { - digestNonApplicableStatus[i][v] = false; - } + digestNonApplicableStatus[i] = new bool[maxVariables]{false}; } } From 9355700f69a19ba8039eb31c71879b417c0c0c5f Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:55:27 +0100 Subject: [PATCH 069/103] 9.2 rc 6 (#2520) --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e1fca9a3d2..24ef38e558 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,7 +8,7 @@ set(ANTARES_VERSION_REVISION 0) # Beta release set(ANTARES_BETA 0) -set(ANTARES_RC 5) +set(ANTARES_RC 6) set(ANTARES_VERSION_YEAR 2024) From b7e529190463a18eb566b67972e66a73722c8222 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:10:01 +0100 Subject: [PATCH 070/103] Bump simtest to 9.2f (#2521) --- simtest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simtest.json b/simtest.json index 03ea9af205..26875e3a2e 100644 --- a/simtest.json +++ b/simtest.json @@ -1,3 +1,3 @@ { - "version": "v9.2.0e" + "version": "v9.2.0f" } From 47ca3b01a1bca8d167d991a94a5728548236ea96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Tue, 3 Dec 2024 16:20:12 +0100 Subject: [PATCH 071/103] Update doc for command invokation : --ortools-solver -> --solver (#2507) Following #2450 --------- Co-authored-by: Vincent Payet --- docs/developer-guide/ortools-integration.md | 6 +++--- docs/user-guide/04-migration-guides.md | 7 +++++++ docs/user-guide/solver/02-command-line.md | 2 +- docs/user-guide/solver/optional-features/xpress.md | 2 +- src/solver/misc/options.cpp | 2 +- src/tests/examples/conftest.py | 10 ++-------- src/tests/examples/specific_test.py | 6 ++---- src/tools/batchrun/main.cpp | 2 +- 8 files changed, 18 insertions(+), 19 deletions(-) diff --git a/docs/developer-guide/ortools-integration.md b/docs/developer-guide/ortools-integration.md index 4c0b4b8d8d..c953e04d57 100644 --- a/docs/developer-guide/ortools-integration.md +++ b/docs/developer-guide/ortools-integration.md @@ -52,10 +52,10 @@ These are the solver names and enum, defined in the [OR-Tools API](https://githu * A mixed real integer solver While the OR-Tools interface allows using multiple solvers, Antares restricts this usage. -The *Antares Simulator* user can select the solvers using the `ortools-solver` command-line option. Here are the allowed +The *Antares Simulator* user can select the solvers using the `solver` command-line option. Here are the allowed values: -| `ortools-solver` | Linear solver | Mixed real integer solver | +| `solver` | Linear solver | Mixed real integer solver | |:-------------------|--------------------------------|----------------------------------| | `sirius` (default) | SIRIUS_LINEAR_PROGRAMMING | SIRIUS_MIXED_INTEGER_PROGRAMMING | | `coin` | CLP_LINEAR_PROGRAMMING | CBC_MIXED_INTEGER_PROGRAMMING | @@ -65,7 +65,7 @@ values: The following commercial solvers are not yet supported by *Antares Simulator*, because of unmet pre-requisites: -| `ortools-solver` | Linear solver | Mixed real integer | Waiting for | +| `solver` | Linear solver | Mixed real integer | Waiting for | |:-----------------|---------------------------|----------------------------------|-----------------------------------------------------| | `cplex` | CPLEX_LINEAR_PROGRAMMING | CPLEX_MIXED_INTEGER_PROGRAMMING | Update OR-Tools building process for CPLEX support | | `gurobi` | GUROBI_LINEAR_PROGRAMMING | GUROBI_MIXED_INTEGER_PROGRAMMING | Update OR-Tools building process for GUROBI support | diff --git a/docs/user-guide/04-migration-guides.md b/docs/user-guide/04-migration-guides.md index 23f10a2668..1088f3766a 100644 --- a/docs/user-guide/04-migration-guides.md +++ b/docs/user-guide/04-migration-guides.md @@ -183,6 +183,13 @@ Using this property requires OR-Tools and a MILP solver (XPRESS, COIN) antares-8.8-solver --use-ortools --ortools-solver coin|xpress ... ``` +Starting from version 9.2, the syntax is as following + +``` +antares-solver --solver coin|xpress ... +``` + + ### Output ### Cashflow by short-term storage diff --git a/docs/user-guide/solver/02-command-line.md b/docs/user-guide/solver/02-command-line.md index 7cc927a662..88defa9062 100644 --- a/docs/user-guide/solver/02-command-line.md +++ b/docs/user-guide/solver/02-command-line.md @@ -17,7 +17,7 @@ hide: | --adequacy | Force the simulation in [adequacy](static-modeler/04-parameters.md#mode) mode | | --parallel | Enable [parallel](optional-features/multi-threading.md) computation of MC years | | --force-parallel=VALUE | Override the max number of years computed [simultaneously](optional-features/multi-threading.md) | -| --ortools-solver=VALUE | The optimization solver to use. Possible values are: `sirius` (default), `coin`, `xpress`, `scip` | +| --solver=VALUE | The optimization solver to use. Possible values are: `sirius` (default), `coin`, `xpress`, `scip` | ## Parameters diff --git a/docs/user-guide/solver/optional-features/xpress.md b/docs/user-guide/solver/optional-features/xpress.md index e8e5242f73..dfa1a07438 100644 --- a/docs/user-guide/solver/optional-features/xpress.md +++ b/docs/user-guide/solver/optional-features/xpress.md @@ -10,7 +10,7 @@ Antares Solver only uses LP, with plans to use MILP at some point in the future. ## Using Xpress in the command-line ``` -antares-solver --ortools-solver xpress [options] +antares-solver --solver xpress [options] ``` ## Setup diff --git a/src/solver/misc/options.cpp b/src/solver/misc/options.cpp index 6470023aff..d72bd4c692 100644 --- a/src/solver/misc/options.cpp +++ b/src/solver/misc/options.cpp @@ -75,7 +75,7 @@ std::unique_ptr CreateParser(Settings& settings, StudyLoad "force-parallel", "Override the max number of years computed simultaneously"); - //--ortools-solver + //--solver parser->add(options.optOptions.ortoolsSolver, ' ', "solver", diff --git a/src/tests/examples/conftest.py b/src/tests/examples/conftest.py index 49bfbdbce4..89d6f8ca7b 100644 --- a/src/tests/examples/conftest.py +++ b/src/tests/examples/conftest.py @@ -1,19 +1,13 @@ import pytest def pytest_addoption(parser): - parser.addoption("--use-ortools", action="store_true", default=False) - parser.addoption("--ortools-solver", action="store", default="sirius") + parser.addoption("--solver", action="store", default="sirius") parser.addoption("--solver-path", action="store") @pytest.fixture() def ortools_solver(request): - return request.config.getoption("--ortools-solver") + return request.config.getoption("--solver") -@pytest.fixture() -def use_ortools(request): - return request.config.getoption("--use-ortools") - @pytest.fixture() def solver_path(request): return request.config.getoption("--solver-path") - diff --git a/src/tests/examples/specific_test.py b/src/tests/examples/specific_test.py index 6372f5892a..bf4d997381 100644 --- a/src/tests/examples/specific_test.py +++ b/src/tests/examples/specific_test.py @@ -72,16 +72,14 @@ def remove_outputs(study_path): shutil.rmtree(f) -def launch_solver(solver_path, study_path, use_ortools=False, ortools_solver="sirius"): +def launch_solver(solver_path, study_path, ortools_solver="sirius"): # Clean study output remove_outputs(study_path) solver_path_full = str(Path(solver_path).resolve()) command = [solver_path_full, "-i", str(study_path)] - if use_ortools: - command.append('--use-ortools') - command.append('--ortools-solver=' + ortools_solver) + command.append('--solver=' + ortools_solver) process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None) output = process.communicate() diff --git a/src/tools/batchrun/main.cpp b/src/tools/batchrun/main.cpp index 420dc060dd..4da485effd 100644 --- a/src/tools/batchrun/main.cpp +++ b/src/tools/batchrun/main.cpp @@ -175,7 +175,7 @@ int main(int argc, const char* argv[]) { // Wrap spaces around quotes, if any // example - // antares-batchrun directory --use-ortools --ortools-solver xpress + // antares-batchrun directory --solver xpress // --solver-parameters "PRESOLVE 1" cmd << " \"" << arg << "\""; } From c2335ca316ac214357c9c8136bb46b32892c177f Mon Sep 17 00:00:00 2001 From: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:15:35 +0100 Subject: [PATCH 072/103] Fix/centos build (#2509) (#2510) Co-authored-by: payetvin <113102157+payetvin@users.noreply.github.com> --- .github/workflows/centos7.yml | 228 +++++++++++++++------------------- docker/AntaresDeps | 37 ++++++ docker/Dockerfile | 95 ++++++++++++++ 3 files changed, 232 insertions(+), 128 deletions(-) create mode 100644 docker/AntaresDeps create mode 100644 docker/Dockerfile diff --git a/.github/workflows/centos7.yml b/.github/workflows/centos7.yml index 330df8e719..61ac1ec3dd 100644 --- a/.github/workflows/centos7.yml +++ b/.github/workflows/centos7.yml @@ -2,7 +2,7 @@ name: Centos7 CI (push and/or release) on: release: - types: [created] + types: [ created ] push: branches: - develop @@ -29,135 +29,107 @@ jobs: build: name: Build - env: - ORTOOLSDIR: ${{ github.workspace }}/or-tools runs-on: ubuntu-latest - container: 'antaresrte/rte-antares:centos7-simulator-no-deps' steps: - - name: Checkout - run: | - git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git -b ${{ env.REF }} . - - - name: Install gcc 10 - run: | - # update mirrors, official centos7 is deprecated - sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo &&\ - sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo &&\ - sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo &&\ - yum update -y - - # not a typo, centos-release-scl is needed to install devtoolset-10 but introduce deprecated mirror - sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo &&\ - sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo &&\ - sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo - - yum install -y centos-release-scl - yum install -y devtoolset-11-gcc* - - - name: Install cmake 3.28 - run: pip3 install cmake==3.28.4 - - - name: Install VCPKG - # Note: we need to use environment variables instead of workflow variables - # because github messes up path variables when running in container, - # see https://github.com/actions/runner/issues/2058 - run: | - git submodule update --init vcpkg && ./vcpkg/bootstrap-vcpkg.sh -disableMetrics - echo "VCPKG_ROOT=$GITHUB_WORKSPACE/vcpkg" >> $GITHUB_ENV - echo "VCPKG_CACHE_DIR=$GITHUB_WORKSPACE/vcpkg_cache" >> $GITHUB_ENV - echo "VCPKG_BINARY_SOURCES=clear;files,$GITHUB_WORKSPACE/vcpkg_cache,readwrite" >> $GITHUB_ENV - - - name: Restore vcpkg binary dir from cache - id: cache-vcpkg-binary - # Note: we are stuck with v3, because v4 is not compatible with oracle8 image - uses: actions/cache/restore@v3 - with: - path: ${{ env.VCPKG_CACHE_DIR }} - key: vcpkg-cache-centos7-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} - # Allows to restore a cache when deps have only partially changed (like adding a dependency) - restore-keys: vcpkg-cache-centos7- - - - name: Init submodule - run: | - git submodule update --init --remote src/tests/resources/Antares_Simulator_Tests - - - name: Config OR-Tools URL - run: | - echo "URL_ORTOOLS=https://github.com/rte-france/or-tools-rte/releases/download/$(cat ortools_tag)/ortools_cxx_centos7_static_sirius.zip" >> $GITHUB_ENV - - - name: Download OR-Tools - id: ortools - run: | - mkdir -p ${{ env.ORTOOLSDIR }} && cd ${{ env.ORTOOLSDIR }} - wget -q -O ortools.zip ${{ env.URL_ORTOOLS }} - unzip -q ortools.zip - rm ortools.zip - - - name: Install gh if needed - if: ${{ env.IS_RELEASE == 'true' }} - run: | - wget https://github.com/cli/cli/releases/download/v2.52.0/gh_2.52.0_linux_amd64.rpm - rpm -i gh_2.52.0_linux_amd64.rpm - gh --version - - - name: Configure - run: | - source /opt/rh/devtoolset-11/enable - source /opt/rh/rh-git227/enable - cmake -B _build -S src \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/vcpkg/scripts/buildsystems/vcpkg.cmake \ - -DVCPKG_TARGET_TRIPLET=x64-linux-release \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_TESTING=ON \ - -DBUILD_TOOLS=ON \ - -DBUILD_UI=OFF \ - -DCMAKE_PREFIX_PATH=${{ env.ORTOOLSDIR }}/install \ - - - - name: Build - run: | - source /opt/rh/devtoolset-11/enable - source /opt/rh/rh-git227/enable - cmake --build _build --config Release -j$(nproc) - ccache -s - - - name: Installer .rpm creation - run: | - cd _build - cpack -G RPM - - - name: Solver archive creation - run: | - cd _build - cmake --install . --prefix install - pushd . - cd install/bin - tar czf ../../antares-solver_centos7.tar.gz antares-solver libsirius_solver.so - popd - rm -rf install - - - name: .tar.gz creation - run: | - cd _build - cpack -G TGZ - - - name: Publish assets - if: ${{ env.IS_RELEASE == 'true' }} - env: - GITHUB_TOKEN: ${{ github.token }} - tag: ${{ github.event.inputs.release_tag }} - run: | - gh release upload "$tag" _build/*.tar.gz _build/*.rpm - - - name: Cache vcpkg binary dir - if: always() - id: save-cache-vcpkg-binary - uses: actions/cache/save@v3 - with: - path: ${{ env.VCPKG_CACHE_DIR }} - key: vcpkg-cache-centos7-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} + + #sparse checkout -- only needed files + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + sparse-checkout: | + docker + src/vcpkg.json + ref: ${{ env.REF }} + + - name: set env variables -- DockerFiles + run: | + echo "DOCKERFILE=$(pwd)/docker/Dockerfile" >> $GITHUB_ENV + echo "DOCKERDIR=$(pwd)/docker" >> $GITHUB_ENV + + + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v45 + with: + files: | + docker/AntaresDeps + + - name: Docker file push + id: docker_push + + if: steps.changed-files.outputs.any_changed == 'true' + uses: elgohr/Publish-Docker-Github-Action@main + with: + name: antaresrte/antaressystemdeps + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + workdir: ${{ env.DOCKERDIR }} + dockerfile: ${{ env.DOCKERDIR }}/AntaresDeps + cache: false + tags: latest + + - name: create vcpkg cache dir + run: | + echo "VCPKG_CACHE_DIR=$GITHUB_WORKSPACE/vcpkg_cache" >> $GITHUB_ENV + mkdir -p ${{ github.workspace }}/vcpkg_cache + + + - name: Restore vcpkg binary dir from cache + id: cache-vcpkg-binary + uses: actions/cache/restore@v4 + with: + path: ${{ github.workspace }}/vcpkg_cache + key: vcpkg-cache-centos7-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} + # Allows to restore a cache when deps have only partially changed (like adding a dependency) + restore-keys: vcpkg-cache-centos7- + + - name: Setup ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: centos7-on-${{ runner.os }} + + + - name: Build the image and Antares + run: | + ls -latr .ccache/ && \ + docker build \ + -t antares:centos7 \ + --build-arg="BRANCH=${{ env.REF }}" \ + --build-arg="NPROC=$(nproc)" \ + --build-arg="VCPKG_CACHE_DIR=./vcpkg_cache" \ + --build-arg CCACHE_DIR=./.ccache \ + --build-arg CCACHE_KEY=centos7-on-${{ runner.os }} \ + -f ${{ env.DOCKERFILE }} . + + + - name: create a container without starting it && retrieve the .tgz + run: | + container_id=$(docker create antares:centos7) + docker cp $container_id:/workspace/Antares_Simulator/_build/archive archive + docker cp $container_id:/workspace/vcpkg_cache ${{ env.VCPKG_CACHE_DIR }} + docker cp $container_id:/workspace/.ccache/. .ccache + ls -la .ccache + docker rm $container_id + + + - name: Publish assets + if: ${{ env.IS_RELEASE == 'true' }} + env: + GITHUB_TOKEN: ${{ github.token }} + tag: ${{ github.event.inputs.release_tag }} + run: | + gh release upload "$tag" archive/*.tar.gz archive/*.rpm + + + - name: Cache vcpkg binary dir + if: always() + id: save-cache-vcpkg-binary + uses: actions/cache/save@v4 + with: + path: ${{ github.workspace }}/vcpkg_cache + key: vcpkg-cache-centos7-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} + diff --git a/docker/AntaresDeps b/docker/AntaresDeps new file mode 100644 index 0000000000..bfe47cb44e --- /dev/null +++ b/docker/AntaresDeps @@ -0,0 +1,37 @@ +FROM centos:7 + +ENV LANG=en_US.UTF-8 \ + LC_ALL=en_US.UTF-8 \ + DEBIAN_FRONTEND=noninteractive \ + VCPKG_ROOT=/vcpkg \ + ORTOOLS_DIR=ortools + +CMD ["/bin/bash"] + +# Install requirements : update repo +RUN sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo &&\ + sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo &&\ + sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo &&\ + yum install -y epel-release &&\ + yum install -y git redhat-lsb-core make wget centos-release-scl scl-utils python3 &&\ + sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo &&\ + sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo &&\ + sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo + +RUN yum update -y +RUN yum install -y epel-release +RUN yum install -y git redhat-lsb-core make wget centos-release-scl scl-utils rpm-build && \ + yum install -y devtoolset-11 && \ + yum install -y rh-git227-git ccache +RUN yum install -y unzip libuuid-devel wxGTK3-devel +RUN yum install -y python3-pip && python3 -m pip install --upgrade pip && pip3 install pytest numpy pandas + +# Install requirements +RUN rm -rf /var/cache/yum + +RUN echo "source /opt/rh/devtoolset-11/enable" >> /etc/bashrc +SHELL ["/bin/bash", "--login", "-c"] + +# Install CMake +RUN pip3 install cmake==3.28.4 + diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000000..17a21b3063 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,95 @@ +FROM antaresrte/antaressystemdeps:latest + + + +CMD ["/bin/bash"] + +RUN mkdir /workspace + +RUN echo "source /opt/rh/devtoolset-11/enable" >> /etc/bashrc +SHELL ["/bin/bash", "--login", "-c"] + + +RUN mkdir -p /workspace/vcpkg_cache +ARG VCPKG_CACHE_DIR +COPY $VCPKG_CACHE_DIR /workspace/ + + +ARG BRANCH=develop +RUN cd /workspace && \ + git clone https://github.com/AntaresSimulatorTeam/Antares_Simulator.git --branch $BRANCH && \ + cd Antares_Simulator && \ + git submodule update --init vcpkg && ./vcpkg/bootstrap-vcpkg.sh -disableMetrics && \ + export VCPKG_ROOT=/workspace/Antares_Simulator/vcpkg + + + + + +RUN ORTOOLS_TAG=$(cat /workspace/Antares_Simulator/ortools_tag) && \ + echo "ORTOOLS_TAG=$ORTOOLS_TAG" && \ + URL_ORTOOLS=https://github.com/rte-france/or-tools-rte/releases/download/$ORTOOLS_TAG/ortools_cxx_centos7_static_sirius.zip && \ + mkdir -p ortools && cd ortools && \ + wget -q -O ortools.zip $URL_ORTOOLS && \ + unzip -q ortools.zip && \ + rm ortools.zip + +WORKDIR /workspace/Antares_Simulator +# Accept build arguments for ccache +ARG CCACHE_DIR +ARG CCACHE_KEY + +# Copy ccache directory into the container +COPY ${CCACHE_DIR:-/dev/null} /workspace/.ccache + +# Configure ccache environment variables +ENV CCACHE_DIR=/workspace/.ccache +ENV CCACHE_BASEDIR=/workspace +ENV CCACHE_COMPRESS=1 +ENV PATH="/usr/lib/ccache:$PATH" + +RUN source /opt/rh/devtoolset-11/enable && \ + source /opt/rh/rh-git227/enable && \ + export VCPKG_BINARY_SOURCES="clear;files,/workspace/vcpkg_cache,readwrite" && \ + cmake -B _build -S src \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_TOOLCHAIN_FILE=/workspace/Antares_Simulator/vcpkg/scripts/buildsystems/vcpkg.cmake \ + -DVCPKG_TARGET_TRIPLET=x64-linux-release \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTING=OFF \ + -DBUILD_TOOLS=ON \ + -DBUILD_UI=OFF \ + -DCMAKE_PREFIX_PATH=/ortools/install + +ARG NPROC=2 +RUN source /opt/rh/devtoolset-11/enable && \ + source /opt/rh/rh-git227/enable && \ + export VCPKG_BINARY_SOURCES="clear;files,/workspace/vcpkg_cache,readwrite" && \ + cmake --build _build --config Release -j${NPROC} &&\ + ccache -s + +#Installer .rpm creation +RUN cd _build && \ + cpack -G RPM + +#Solver archive creation +RUN cd _build && \ + cpack -G RPM + +RUN cd _build && \ + cmake --install . --prefix install && \ + pushd . && \ + cd install/bin && \ + tar czf ../../antares-solver_centos7.tar.gz antares-solver libsirius_solver.so && \ + popd && \ + rm -rf install + +#.tar.gz creation +RUN cd _build && \ + cpack -G TGZ +#mv .rpm and .tar.gz +RUN cd _build && \ + mkdir archive && \ + mv *.tar.gz archive && \ + mv *.rpm archive From c67e3129c045f50f68490fe433b536539a720a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Wed, 4 Dec 2024 15:05:15 +0100 Subject: [PATCH 073/103] Fix cost for ST storage (#2522) --- .../opt_gestion_des_couts_cas_lineaire.cpp | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) 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 be6d609387..aa6219d905 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp @@ -26,6 +26,7 @@ void OPT_InitialiserLesCoutsLineaireCoutsDeDemarrage(PROBLEME_HEBDO*, const int, const int); static void shortTermStorageCost( + int weekInTheYear, int PremierPdtDeLIntervalle, int DernierPdtDeLIntervalle, int NombreDePays, @@ -33,6 +34,7 @@ static void shortTermStorageCost( VariableManagement::VariableManager& variableManager, std::vector& linearCost) { + const int weekFirstHour = weekInTheYear * 168; for (int pays = 0; pays < NombreDePays; ++pays) { for (const auto& storage: shortTermStorageInput[pays]) @@ -41,12 +43,13 @@ static void shortTermStorageCost( pdtHebdo < DernierPdtDeLIntervalle; pdtHebdo++, pdtJour++) { + int hourInTheYear = weekFirstHour + pdtHebdo; const int clusterGlobalIndex = storage.clusterGlobalIndex; if (const int varLevel = variableManager.ShortTermStorageLevel(clusterGlobalIndex, pdtJour); varLevel >= 0) { - linearCost[varLevel] = storage.series->costLevel[pdtHebdo]; + linearCost[varLevel] = storage.series->costLevel[hourInTheYear]; } if (const int varInjection = variableManager.ShortTermStorageInjection( @@ -54,7 +57,7 @@ static void shortTermStorageCost( pdtJour); varInjection >= 0) { - linearCost[varInjection] = storage.series->costInjection[pdtHebdo]; + linearCost[varInjection] = storage.series->costInjection[hourInTheYear]; } if (const int varWithdrawal = variableManager.ShortTermStorageWithdrawal( @@ -62,7 +65,7 @@ static void shortTermStorageCost( pdtJour); varWithdrawal >= 0) { - linearCost[varWithdrawal] = storage.series->costWithdrawal[pdtHebdo]; + linearCost[varWithdrawal] = storage.series->costWithdrawal[hourInTheYear]; } if (const int varCostVariationInjection = variableManager .ShortTermStorageCostVariationInjection( @@ -70,16 +73,16 @@ static void shortTermStorageCost( pdtJour); storage.penalizeVariationInjection && varCostVariationInjection >= 0) { - linearCost[varCostVariationInjection] = storage.series - ->costVariationInjection[pdtHebdo]; + linearCost[varCostVariationInjection] = storage.series->costVariationInjection + [hourInTheYear]; } if (const int varCostVariationWithdrawal = variableManager.ShortTermStorageCostVariationWithdrawal(clusterGlobalIndex, pdtJour); storage.penalizeVariationWithdrawal && varCostVariationWithdrawal >= 0) { - linearCost[varCostVariationWithdrawal] = storage.series - ->costVariationWithdrawal[pdtHebdo]; + linearCost[varCostVariationWithdrawal] = storage.series->costVariationWithdrawal + [hourInTheYear]; } } } @@ -97,7 +100,8 @@ void OPT_InitialiserLesCoutsLineaire(PROBLEME_HEBDO* problemeHebdo, ProblemeAResoudre->CoutQuadratique.assign(ProblemeAResoudre->NombreDeVariables, 0.); auto variableManager = VariableManagerFromProblemHebdo(problemeHebdo); - shortTermStorageCost(PremierPdtDeLIntervalle, + shortTermStorageCost(problemeHebdo->weekInTheYear, + PremierPdtDeLIntervalle, DernierPdtDeLIntervalle, problemeHebdo->NombreDePays, problemeHebdo->ShortTermStorage, From e80945a30dc4606e54baa58d2ef069747bb5caa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Thu, 5 Dec 2024 10:01:05 +0100 Subject: [PATCH 074/103] Fix launch studies with empty solver (#2523) By default, the "solver" field is empty. So the command line looks like this ``` antares-solver --progress "029 Pumped storage" --solver= ``` which is invalid. Unless the user provides a solver, don't append "--solver=" at the end of the command line. --- src/ui/simulator/application/study.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ui/simulator/application/study.cpp b/src/ui/simulator/application/study.cpp index c19ea5a1f8..ab4e65e472 100644 --- a/src/ui/simulator/application/study.cpp +++ b/src/ui/simulator/application/study.cpp @@ -1207,7 +1207,10 @@ void RunSimulationOnTheStudy(Data::Study::Ptr study, cmd << " --parallel"; // add solver name for ortools - cmd << " --solver=" << solverName; + if (!solverName.empty()) + { + cmd << " --solver=" << solverName; + } // Go go go ! logs.debug() << "running " << cmd; From 0abda66be5f2affabc0ac57c20f7e8d65d8c5612 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:24:23 +0100 Subject: [PATCH 075/103] Default solver in GUI (#2524) Add sirius as the default solver in the run window --- src/ui/simulator/windows/simulation/run.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/simulator/windows/simulation/run.cpp b/src/ui/simulator/windows/simulation/run.cpp index e4bfa1cc69..086a405e08 100644 --- a/src/ui/simulator/windows/simulation/run.cpp +++ b/src/ui/simulator/windows/simulation/run.cpp @@ -313,7 +313,7 @@ Run::Run(wxWindow* parent, bool preproOnly) : pTitleOrtoolsSolverCombox = Antares::Component::CreateLabel(pBigDaddy, wxT("Ortools solver : ")); - pOrtoolsSolverCombox = new wxComboBox(pBigDaddy, wxID_ANY); + pOrtoolsSolverCombox = new wxComboBox(pBigDaddy, wxID_ANY, "sirius"); std::list solverList = getAvailableOrtoolsSolverName(); for (const std::string& solverName : solverList) { From a276477a65059ce313bf0ab409b9e0347a84a1c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Thu, 5 Dec 2024 16:07:48 +0100 Subject: [PATCH 076/103] Fix function `ThermalCluster::getMarketBidCost` [ANT-2527] (#2525) The index was wrong, we expected an hour in the year 0..8659, but got an index 0..infinity. --- .../antares/study/parts/thermal/cluster.cpp | 9 ++++---- .../thermal-price-definition.cpp | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index 85abd8090a..eaab3cada8 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -386,8 +386,8 @@ void ThermalCluster::ComputeProductionCostTS() for (uint hour = 0; hour < HOURS_PER_YEAR; ++hour) { - double& houtlyModulation = modulation[Data::thermalModulationCost][hour]; - productionCostTS[hour] = marginalCostTS[hour] * houtlyModulation; + double hourlyModulation = modulation[Data::thermalModulationCost][hour]; + productionCostTS[hour] = marginalCostTS[hour] * hourlyModulation; } } } @@ -748,9 +748,7 @@ double ThermalCluster::getMarginalCost(uint serieIndex, uint hourInTheYear) cons double ThermalCluster::getMarketBidCost(uint hourInTheYear, uint year) const { - uint serieIndex = series.getSeriesIndex(year); - - double mod = modulation[thermalModulationMarketBid][serieIndex]; + const double mod = modulation[thermalModulationMarketBid][hourInTheYear]; if (costgeneration == Data::setManually) { @@ -758,6 +756,7 @@ double ThermalCluster::getMarketBidCost(uint hourInTheYear, uint year) const } else { + const uint serieIndex = series.getSeriesIndex(year); const uint tsIndex = std::min(serieIndex, (uint)costsTimeSeries.size() - 1); return costsTimeSeries[tsIndex].marketBidCostTS[hourInTheYear] * mod; } diff --git a/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp b/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp index cfef5909e5..3aad7c0cec 100644 --- a/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp +++ b/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp @@ -265,4 +265,27 @@ BOOST_FIXTURE_TEST_CASE(computeMarketBidCost, FixtureFull) BOOST_CHECK_CLOSE(cluster->computeMarketBidCost(1, 2, 1), 24.12, 0.001); } + +BOOST_AUTO_TEST_CASE(non_constant_marketbid_modulation) +{ + Area area; + ThermalCluster cluster(&area); + cluster.costgeneration = setManually; + cluster.marketBidCost = 120; + + auto& mod = cluster.modulation; + mod.resize(thermalModulationMax, HOURS_PER_YEAR); + mod.fill(1.); + + { + mod[thermalModulationMarketBid][0] = .5; + BOOST_CHECK_EQUAL(cluster.getMarketBidCost(0, 0), .5 * 120); + } + + { + mod[thermalModulationMarketBid][1] = .8; + BOOST_CHECK_EQUAL(cluster.getMarketBidCost(1, 0), .8 * 120); + } +} + BOOST_AUTO_TEST_SUITE_END() From 2fc0adac9ead16d56c2f4a74a2f5a523392246ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Fri, 6 Dec 2024 14:25:50 +0100 Subject: [PATCH 077/103] Add compatibility parameter for hydro pmax I/O [ANT-2278] (#2514) Co-authored-by: payetvin <113102157+payetvin@users.noreply.github.com> Co-authored-by: Vincent Payet --- simtest.json | 2 +- src/CMakeLists.txt | 2 +- src/libs/antares/study/area/list.cpp | 13 ++++- .../study/include/antares/study/parameters.h | 15 ++++++ .../antares/study/parts/hydro/series.h | 6 ++- src/libs/antares/study/parameters.cpp | 53 ++++++++++++++++++- .../antares/study/parts/hydro/container.cpp | 3 +- src/libs/antares/study/parts/hydro/series.cpp | 3 +- .../study/parameters/parameters-tests.cpp | 25 ++++++++- 9 files changed, 113 insertions(+), 9 deletions(-) diff --git a/simtest.json b/simtest.json index 26875e3a2e..11b8cee038 100644 --- a/simtest.json +++ b/simtest.json @@ -1,3 +1,3 @@ { - "version": "v9.2.0f" + "version": "v9.2.0g" } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 24ef38e558..56dc5e2bf8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,7 +8,7 @@ set(ANTARES_VERSION_REVISION 0) # Beta release set(ANTARES_BETA 0) -set(ANTARES_RC 6) +set(ANTARES_RC 7) set(ANTARES_VERSION_YEAR 2024) diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index b9353937d9..cf2624515f 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -950,20 +950,29 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, ret = area.hydro.series->loadGenerationTS(area.id, hydroSeries, studyVersion) && ret; } - if (studyVersion < StudyVersion(9, 1)) + switch (study.parameters.compatibility.hydroPmax) + { + case Parameters::Compatibility::HydroPmax::Daily: { HydroMaxTimeSeriesReader reader(area.hydro, area.id.to(), area.name.to()); ret = reader.read(pathHydro.string(), study.usedByTheSolver) && ret; + break; } - else + case Parameters::Compatibility::HydroPmax::Hourly: { ret = area.hydro.series->LoadMaxPower(area.id, hydroSeries) && ret; + break; + } + default: + throw std::invalid_argument( + "Value not supported for study.parameters.compatibility.hydroPmax"); } area.hydro.series->resizeTSinDeratedMode(study.parameters.derated, studyVersion, + study.parameters.compatibility.hydroPmax, study.usedByTheSolver); } diff --git a/src/libs/antares/study/include/antares/study/parameters.h b/src/libs/antares/study/include/antares/study/parameters.h index 0df3a8b157..38228bc23b 100644 --- a/src/libs/antares/study/include/antares/study/parameters.h +++ b/src/libs/antares/study/include/antares/study/parameters.h @@ -399,6 +399,18 @@ class Parameters final } include; + struct Compatibility + { + enum class HydroPmax + { + Daily, + Hourly + }; + HydroPmax hydroPmax = HydroPmax::Daily; + }; + + Compatibility compatibility; + // Shedding struct { @@ -518,6 +530,9 @@ const char* SimulationModeToCString(SimulationMode mode); */ bool StringToSimulationMode(SimulationMode& mode, Yuni::CString<20, false> text); +const char* CompatibilityHydroPmaxToCString(Parameters::Compatibility::HydroPmax); +bool StringToCompatibilityHydroPmax(Parameters::Compatibility::HydroPmax&, const std::string& text); + } // namespace Antares::Data #endif // __ANTARES_LIBS_STUDY_PARAMETERS_H__ diff --git a/src/libs/antares/study/include/antares/study/parts/hydro/series.h b/src/libs/antares/study/include/antares/study/parts/hydro/series.h index 4bb8367ac3..c3b587c0de 100644 --- a/src/libs/antares/study/include/antares/study/parts/hydro/series.h +++ b/src/libs/antares/study/include/antares/study/parts/hydro/series.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "../../fwd.h" @@ -137,7 +138,10 @@ class DataSeriesHydro uint TScount() const; // Setting TS's when derated mode is on - void resizeTSinDeratedMode(bool derated, StudyVersion version, bool useBySolver); + void resizeTSinDeratedMode(bool derated, + StudyVersion version, + Parameters::Compatibility::HydroPmax hydroPmax, + bool useBySolver); }; // class DataSeriesHydro } // namespace Data } // namespace Antares diff --git a/src/libs/antares/study/parameters.cpp b/src/libs/antares/study/parameters.cpp index e26e57c6f7..54f5b6db74 100644 --- a/src/libs/antares/study/parameters.cpp +++ b/src/libs/antares/study/parameters.cpp @@ -208,6 +208,39 @@ const char* SimulationModeToCString(SimulationMode mode) } } +const char* CompatibilityHydroPmaxToCString(Parameters::Compatibility::HydroPmax mode) +{ + switch (mode) + { + case Parameters::Compatibility::HydroPmax::Daily: + return "daily"; + case Parameters::Compatibility::HydroPmax::Hourly: + return "hourly"; + default: + return "Unknown"; + } +} + +bool StringToCompatibilityHydroPmax(Parameters::Compatibility::HydroPmax& mode, + const std::string& text) +{ + if (text.empty()) + { + return false; + } + if (text == "daily") + { + mode = Parameters::Compatibility::HydroPmax::Daily; + return true; + } + if (text == "hourly") + { + mode = Parameters::Compatibility::HydroPmax::Hourly; + return true; + } + return false; +} + bool Parameters::economy() const { return mode == SimulationMode::Economy; @@ -1053,6 +1086,19 @@ static bool SGDIntLoadFamily_SeedsMersenneTwister(Parameters& d, return false; } +static bool SGDIntLoadFamily_Compatibility(Parameters& d, + const String& key, + const String& value, + const String&) +{ + if (key == "hydro-pmax") + { + return StringToCompatibilityHydroPmax(d.compatibility.hydroPmax, value); + } + + return false; +} + static bool SGDIntLoadFamily_Legacy(Parameters& d, const String& key, const String& value, @@ -1170,7 +1216,8 @@ bool Parameters::loadFromINI(const IniFile& ini, const StudyVersion& version) {"advanced parameters", &SGDIntLoadFamily_AdvancedParameters}, {"playlist", &SGDIntLoadFamily_Playlist}, {"variables selection", &SGDIntLoadFamily_VariablesSelection}, - {"seeds - mersenne twister", &SGDIntLoadFamily_SeedsMersenneTwister}}; + {"seeds - mersenne twister", &SGDIntLoadFamily_SeedsMersenneTwister}, + {"compatibility", &SGDIntLoadFamily_Compatibility}}; Callback handleAllKeysInSection; // Foreach section on the ini file... @@ -1967,6 +2014,10 @@ void Parameters::saveToINI(IniFile& ini) const section->add(SeedToID((SeedIndex)sd), seed[sd]); } } + { + auto* section = ini.addSection("compatibility"); + section->add("hydro-pmax", CompatibilityHydroPmaxToCString(compatibility.hydroPmax)); + } } bool Parameters::loadFromFile(const std::filesystem::path& filename, const StudyVersion& version) diff --git a/src/libs/antares/study/parts/hydro/container.cpp b/src/libs/antares/study/parts/hydro/container.cpp index 6ee131b4f3..52e6ef1d83 100644 --- a/src/libs/antares/study/parts/hydro/container.cpp +++ b/src/libs/antares/study/parts/hydro/container.cpp @@ -156,7 +156,8 @@ bool PartHydro::LoadFromFolder(Study& study, const fs::path& folder) area.hydro.pumpingEfficiency = 1.; area.hydro.deltaBetweenFinalAndInitialLevels.resize(study.parameters.nbYears); - if (study.header.version >= StudyVersion(9, 1)) + if (study.parameters.compatibility.hydroPmax + == Parameters::Compatibility::HydroPmax::Hourly) { // GUI part patch : // We need to know, when estimating the RAM required by the solver, if the current diff --git a/src/libs/antares/study/parts/hydro/series.cpp b/src/libs/antares/study/parts/hydro/series.cpp index a9f62664c8..2ae774fbdf 100644 --- a/src/libs/antares/study/parts/hydro/series.cpp +++ b/src/libs/antares/study/parts/hydro/series.cpp @@ -230,6 +230,7 @@ uint DataSeriesHydro::TScount() const void DataSeriesHydro::resizeTSinDeratedMode(bool derated, StudyVersion studyVersion, + Parameters::Compatibility::HydroPmax hydroPmax, bool usedBySolver) { if (!(derated && usedBySolver)) @@ -243,7 +244,7 @@ void DataSeriesHydro::resizeTSinDeratedMode(bool derated, { mingen.averageTimeseries(); - if (studyVersion >= StudyVersion(9, 1)) + if (hydroPmax == Parameters::Compatibility::HydroPmax::Hourly) { maxHourlyGenPower.averageTimeseries(); maxHourlyPumpPower.averageTimeseries(); diff --git a/src/tests/src/libs/antares/study/parameters/parameters-tests.cpp b/src/tests/src/libs/antares/study/parameters/parameters-tests.cpp index 5e0da57a10..6015fcbbc0 100644 --- a/src/tests/src/libs/antares/study/parameters/parameters-tests.cpp +++ b/src/tests/src/libs/antares/study/parameters/parameters-tests.cpp @@ -104,6 +104,26 @@ BOOST_FIXTURE_TEST_CASE(invalidValues, Fixture) BOOST_CHECK_EQUAL(p.renewableGeneration(), rgUnknown); } +BOOST_FIXTURE_TEST_CASE(hydroPmax, Fixture) +{ + BOOST_CHECK(p.compatibility.hydroPmax == Parameters::Compatibility::HydroPmax::Daily); + + writeValidFile(); + BOOST_CHECK(p.loadFromFile(path.string(), version)); + p.validateOptions(options); + p.fixBadValues(); + + BOOST_CHECK(p.compatibility.hydroPmax == Parameters::Compatibility::HydroPmax::Hourly); + + BOOST_CHECK_EQUAL(CompatibilityHydroPmaxToCString(p.compatibility.hydroPmax), "hourly"); + BOOST_CHECK_EQUAL(CompatibilityHydroPmaxToCString(Parameters::Compatibility::HydroPmax::Daily), + "daily"); + + BOOST_CHECK(StringToCompatibilityHydroPmax(p.compatibility.hydroPmax, "daily")); + BOOST_CHECK(!StringToCompatibilityHydroPmax(p.compatibility.hydroPmax, "")); + BOOST_CHECK(!StringToCompatibilityHydroPmax(p.compatibility.hydroPmax, "abc")); +} + BOOST_AUTO_TEST_SUITE_END() void Fixture::writeInvalidFile() @@ -215,7 +235,10 @@ void Fixture::writeValidFile() seed-spilled-energy-costs = 7005489 seed-thermal-costs = 8005489 seed-hydro-costs = 9005489 - seed-initial-reservoir-levels = 10005489)"; + seed-initial-reservoir-levels = 10005489 + + [compatibility] + hydro-pmax = hourly)"; outfile.close(); } From 6b0c5ca42931133e97564ef797778a08e78dd228 Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Fri, 6 Dec 2024 15:03:56 +0100 Subject: [PATCH 078/103] Component Filler (2.3) [ANT-2305] (#2504) Signed-off-by: Peter Mitri Co-authored-by: Guillaume PIERRE Co-authored-by: payetvin <113102157+payetvin@users.noreply.github.com> Co-authored-by: Florian OMNES --- src/solver/CMakeLists.txt | 1 + .../antares/solver/expressions/NodeRegistry.h | 7 +- .../solver/modeler/api/linearProblem.h | 2 +- .../antares/solver/modeler/api/mipVariable.h | 2 + .../solver/modeler/ortoolsImpl/mipVariable.h | 2 + .../modeler/ortoolsImpl/mipVariable.cpp | 5 + src/solver/optim-model-filler/CMakeLists.txt | 29 + .../optim-model-filler/ComponentFiller.cpp | 95 ++++ .../optim-model-filler/LinearExpression.cpp | 120 ++++ .../ReadLinearConstraintVisitor.cpp | 131 +++++ .../ReadLinearExpressionVisitor.cpp | 124 +++++ .../optim-model-filler/ComponentFiller.h | 62 +++ .../optim-model-filler/LinearExpression.h | 73 +++ .../ReadLinearConstraintVisitor.h | 76 +++ .../ReadLinearExpressionVisitor.h | 62 +++ src/study/system-model/CMakeLists.txt | 2 +- src/study/system-model/component.cpp | 8 +- .../antares/study/system-model/component.h | 24 +- .../antares/study/system-model/expression.h | 19 +- .../antares/study/system-model/model.h | 2 + src/study/system-model/model.cpp | 4 +- src/tests/src/solver/CMakeLists.txt | 1 + .../testModelerLinearProblemWithOrtools.cpp | 2 + .../solver/optim-model-filler/CMakeLists.txt | 29 + .../test_componentFiller.cpp | 514 ++++++++++++++++++ .../test_linearExpression.cpp | 150 +++++ .../solver/optim-model-filler/test_main.cpp | 26 + .../test_readLinearConstraintVisitor.cpp | 129 +++++ .../test_readLinearExpressionVisitor.cpp | 179 ++++++ .../src/study/system-model/CMakeLists.txt | 2 +- .../src/study/system-model/test_component.cpp | 31 +- .../src/study/system-model/test_system.cpp | 4 +- 32 files changed, 1894 insertions(+), 23 deletions(-) create mode 100644 src/solver/optim-model-filler/CMakeLists.txt create mode 100644 src/solver/optim-model-filler/ComponentFiller.cpp create mode 100644 src/solver/optim-model-filler/LinearExpression.cpp create mode 100644 src/solver/optim-model-filler/ReadLinearConstraintVisitor.cpp create mode 100644 src/solver/optim-model-filler/ReadLinearExpressionVisitor.cpp create mode 100644 src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ComponentFiller.h create mode 100644 src/solver/optim-model-filler/include/antares/solver/optim-model-filler/LinearExpression.h create mode 100644 src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearConstraintVisitor.h create mode 100644 src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearExpressionVisitor.h create mode 100644 src/tests/src/solver/optim-model-filler/CMakeLists.txt create mode 100644 src/tests/src/solver/optim-model-filler/test_componentFiller.cpp create mode 100644 src/tests/src/solver/optim-model-filler/test_linearExpression.cpp create mode 100644 src/tests/src/solver/optim-model-filler/test_main.cpp create mode 100644 src/tests/src/solver/optim-model-filler/test_readLinearConstraintVisitor.cpp create mode 100644 src/tests/src/solver/optim-model-filler/test_readLinearExpressionVisitor.cpp diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index adf9825864..5ae822209b 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -23,6 +23,7 @@ add_subdirectory(simulation) add_subdirectory(ts-generator) add_subdirectory(utils) add_subdirectory(variable) +add_subdirectory(optim-model-filler) # # Resource file for Windows diff --git a/src/solver/expressions/include/antares/solver/expressions/NodeRegistry.h b/src/solver/expressions/include/antares/solver/expressions/NodeRegistry.h index 994b8f6886..22b40bf011 100644 --- a/src/solver/expressions/include/antares/solver/expressions/NodeRegistry.h +++ b/src/solver/expressions/include/antares/solver/expressions/NodeRegistry.h @@ -9,14 +9,13 @@ class NodeRegistry { public: NodeRegistry() = default; - NodeRegistry(Antares::Solver::Nodes::Node* node, - Antares::Solver::Registry registry); + NodeRegistry(Nodes::Node* node, Registry registry); // Shallow copy NodeRegistry(NodeRegistry&&) = default; NodeRegistry& operator=(NodeRegistry&&) = default; - Antares::Solver::Nodes::Node* node; - Antares::Solver::Registry registry; + Nodes::Node* node; + Registry registry; }; } // namespace Antares::Solver diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h index 94c95e4e31..6885d81ac1 100644 --- a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h @@ -35,7 +35,7 @@ namespace Antares::Solver::Modeler::Api /** * Linear Problem * This class is aimed at creating and manipulating variables/constraints - * Also used to to control the objective, maximization or minimization, and to solve the problem + * Also used to control the objective, maximization or minimization, and to solve the problem */ class ILinearProblem { diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/mipVariable.h b/src/solver/modeler/api/include/antares/solver/modeler/api/mipVariable.h index 1caac002bf..c8e93acb53 100644 --- a/src/solver/modeler/api/include/antares/solver/modeler/api/mipVariable.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/mipVariable.h @@ -29,6 +29,8 @@ namespace Antares::Solver::Modeler::Api class IMipVariable: public IHasBounds, public IHasName { +public: + virtual bool isInteger() const = 0; }; } // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipVariable.h b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipVariable.h index 528ee0cd9e..a1c0a3fa91 100644 --- a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipVariable.h +++ b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipVariable.h @@ -44,6 +44,8 @@ class OrtoolsMipVariable final: public Api::IMipVariable const std::string& getName() const override; + bool isInteger() const override; + const operations_research::MPVariable* getMpVar() const; ~OrtoolsMipVariable() override = default; diff --git a/src/solver/modeler/ortoolsImpl/mipVariable.cpp b/src/solver/modeler/ortoolsImpl/mipVariable.cpp index 5e21924a8f..b29d0000a3 100644 --- a/src/solver/modeler/ortoolsImpl/mipVariable.cpp +++ b/src/solver/modeler/ortoolsImpl/mipVariable.cpp @@ -66,4 +66,9 @@ const std::string& OrtoolsMipVariable::getName() const return mpVar_->name(); } +bool OrtoolsMipVariable::isInteger() const +{ + return mpVar_->integer(); +} + } // namespace Antares::Solver::Modeler::OrtoolsImpl diff --git a/src/solver/optim-model-filler/CMakeLists.txt b/src/solver/optim-model-filler/CMakeLists.txt new file mode 100644 index 0000000000..8fb6bdc0e0 --- /dev/null +++ b/src/solver/optim-model-filler/CMakeLists.txt @@ -0,0 +1,29 @@ +set(PROJ optim-model-filler) + +set(SRC_optim_model_filler + include/antares/solver/optim-model-filler/ComponentFiller.h + include/antares/solver/optim-model-filler/LinearExpression.h + include/antares/solver/optim-model-filler/ReadLinearConstraintVisitor.h + include/antares/solver/optim-model-filler/ReadLinearExpressionVisitor.h + ComponentFiller.cpp + LinearExpression.cpp + ReadLinearConstraintVisitor.cpp + ReadLinearExpressionVisitor.cpp +) + +add_library(${PROJ} ${SRC_optim_model_filler}) +add_library(Antares::${PROJ} ALIAS ${PROJ}) + +set_target_properties(${PROJ} PROPERTIES LINKER_LANGUAGE CXX) + +target_link_libraries(${PROJ} + PRIVATE + Antares::solver-expressions + Antares::antares-study-system-model + Antares::modeler_api +) + +target_include_directories(${PROJ} + PUBLIC + $ +) diff --git a/src/solver/optim-model-filler/ComponentFiller.cpp b/src/solver/optim-model-filler/ComponentFiller.cpp new file mode 100644 index 0000000000..49a66cda11 --- /dev/null +++ b/src/solver/optim-model-filler/ComponentFiller.cpp @@ -0,0 +1,95 @@ +/* + * 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 + +#include +#include +#include +#include +#include + +namespace Antares::Optimization +{ + +ComponentFiller::ComponentFiller(const Study::SystemModel::Component& component): + component_(component), + evaluationContext_(component_.getParameterValues(), {}) +{ +} + +void ComponentFiller::addVariables(Solver::Modeler::Api::ILinearProblem& pb, + Solver::Modeler::Api::LinearProblemData& data, + Solver::Modeler::Api::FillContext& ctx) +{ + auto evaluator = std::make_unique(evaluationContext_); + for (const auto& variable: component_.getModel()->Variables() | std::views::values) + { + pb.addVariable(evaluator->dispatch(variable.LowerBound().RootNode()), + evaluator->dispatch(variable.UpperBound().RootNode()), + variable.Type() != Study::SystemModel::ValueType::FLOAT, + component_.Id() + "." + variable.Id()); + } +} + +void ComponentFiller::addConstraints(Solver::Modeler::Api::ILinearProblem& pb, + Solver::Modeler::Api::LinearProblemData& data, + Solver::Modeler::Api::FillContext& ctx) +{ + ReadLinearConstraintVisitor visitor(evaluationContext_); + for (const auto& constraint: component_.getModel()->getConstraints() | std::views::values) + { + auto linear_constraint = visitor.dispatch(constraint.expression().RootNode()); + auto* ct = pb.addConstraint(linear_constraint.lb, + linear_constraint.ub, + component_.Id() + "." + constraint.Id()); + for (auto [var_id, coef]: linear_constraint.coef_per_var) + { + auto* variable = pb.getVariable(component_.Id() + "." + var_id); + ct->setCoefficient(variable, coef); + } + } +} + +void ComponentFiller::addObjective(Solver::Modeler::Api::ILinearProblem& pb, + Solver::Modeler::Api::LinearProblemData& data, + Solver::Modeler::Api::FillContext& ctx) +{ + if (component_.getModel()->Objective().Empty()) + { + return; + } + ReadLinearExpressionVisitor visitor(evaluationContext_); + auto linear_expression = visitor.dispatch(component_.getModel()->Objective().RootNode()); + if (abs(linear_expression.offset()) > 1e-10) + { + throw std::invalid_argument("Antares does not support objective offsets (found in model '" + + component_.getModel()->Id() + "' of component '" + + component_.Id() + "')."); + } + for (auto [var_id, coef]: linear_expression.coefPerVar()) + { + auto* variable = pb.getVariable(component_.Id() + "." + var_id); + pb.setObjectiveCoefficient(variable, coef); + } +} + +} // namespace Antares::Optimization diff --git a/src/solver/optim-model-filler/LinearExpression.cpp b/src/solver/optim-model-filler/LinearExpression.cpp new file mode 100644 index 0000000000..dd3d961215 --- /dev/null +++ b/src/solver/optim-model-filler/LinearExpression.cpp @@ -0,0 +1,120 @@ +/* + * 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 + +#include + +namespace Antares::Optimization +{ + +/** + * Element-wise sum of two [string, double] maps, preceded an element-wise multiplication of the + * right-hand-side map. Keys that do not exist in one of the two maps are considered to have a zero + * value. For every key: value = left_value + rhs_multiplier * right_value + * @param left The left hand side map + * @param right The right hand side map + * @param rhs_multiplier The multiplier to apply to the right hand side map + * @return The map resulting from the operation + */ +static std::map add_maps(const std::map& left, + const std::map& right, + double rhs_multiplier) +{ + std::map result(left); + for (auto [key, value]: right) + { + if (result.contains(key)) + { + result[key] += rhs_multiplier * value; + } + else + { + result[key] = rhs_multiplier * value; + } + } + return result; +} + +/** + * Element-wise multiplication of a map by a scale. + * For every key: final_value = scale * initial_value + * @param map The [string, double] map to scale + * @param scale The scale + * @return The scaled map + */ +static std::map scale_map(const std::map& map, + double scale) +{ + std::map result; + for (auto [key, value]: map) + { + result[key] = scale * value; + } + return result; +} + +LinearExpression::LinearExpression(double offset, std::map coef_per_var): + offset_(offset), + coef_per_var_(std::move(coef_per_var)) +{ +} + +LinearExpression LinearExpression::operator+(const LinearExpression& other) const +{ + return {offset_ + other.offset_, add_maps(coef_per_var_, other.coef_per_var_, 1)}; +} + +LinearExpression LinearExpression::operator-(const LinearExpression& other) const +{ + return {offset_ - other.offset_, add_maps(coef_per_var_, other.coef_per_var_, -1)}; +} + +LinearExpression LinearExpression::operator*(const LinearExpression& other) const +{ + if (coef_per_var_.empty()) + { + return {offset_ * other.offset_, scale_map(other.coef_per_var_, offset_)}; + } + else if (other.coef_per_var_.empty()) + { + return {offset_ * other.offset_, scale_map(coef_per_var_, other.offset_)}; + } + else + { + throw std::invalid_argument("A linear expression can't have quadratic terms."); + } +} + +LinearExpression LinearExpression::operator/(const LinearExpression& other) const +{ + if (!other.coef_per_var_.empty()) + { + throw std::invalid_argument("A linear expression can't have a variable as a dividend."); + } + return LinearExpression(offset_ / other.offset_, scale_map(coef_per_var_, 1 / other.offset_)); +} + +LinearExpression LinearExpression::negate() const +{ + return {-offset_, scale_map(coef_per_var_, -1)}; +} +} // namespace Antares::Optimization diff --git a/src/solver/optim-model-filler/ReadLinearConstraintVisitor.cpp b/src/solver/optim-model-filler/ReadLinearConstraintVisitor.cpp new file mode 100644 index 0000000000..9e33b5868e --- /dev/null +++ b/src/solver/optim-model-filler/ReadLinearConstraintVisitor.cpp @@ -0,0 +1,131 @@ +/* + * 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 +#include +#include + +using namespace Antares::Solver::Nodes; + +namespace Antares::Optimization +{ + +ReadLinearConstraintVisitor::ReadLinearConstraintVisitor( + Solver::Visitors::EvaluationContext context): + linear_expression_visitor_(std::move(context)) +{ +} + +std::string ReadLinearConstraintVisitor::name() const +{ + return "ReadLinearConstraintVisitor"; +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const EqualNode* node) +{ + auto leftMinusRight = linear_expression_visitor_.dispatch(node->left()) + - linear_expression_visitor_.dispatch(node->right()); + return LinearConstraint{.coef_per_var = leftMinusRight.coefPerVar(), + .lb = -leftMinusRight.offset(), + .ub = -leftMinusRight.offset()}; +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const LessThanOrEqualNode* node) +{ + auto leftMinusRight = linear_expression_visitor_.dispatch(node->left()) + - linear_expression_visitor_.dispatch(node->right()); + return LinearConstraint{.coef_per_var = leftMinusRight.coefPerVar(), + .ub = -leftMinusRight.offset()}; +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const GreaterThanOrEqualNode* node) +{ + auto leftMinusRight = linear_expression_visitor_.dispatch(node->left()) + - linear_expression_visitor_.dispatch(node->right()); + return LinearConstraint{.coef_per_var = leftMinusRight.coefPerVar(), + .lb = -leftMinusRight.offset()}; +} + +static std::invalid_argument IllegalNodeException() +{ + return std::invalid_argument("Root node of a constraint must be a comparator."); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const SumNode* sum_node) +{ + throw IllegalNodeException(); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const SubtractionNode* node) +{ + throw IllegalNodeException(); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const MultiplicationNode* node) +{ + throw IllegalNodeException(); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const DivisionNode* node) +{ + throw IllegalNodeException(); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const NegationNode* node) +{ + throw IllegalNodeException(); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const VariableNode* node) +{ + throw IllegalNodeException(); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const ParameterNode* node) +{ + throw IllegalNodeException(); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const LiteralNode* node) +{ + throw IllegalNodeException(); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const PortFieldNode* node) +{ + throw IllegalNodeException(); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const PortFieldSumNode* node) +{ + throw IllegalNodeException(); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const ComponentVariableNode* node) +{ + throw IllegalNodeException(); +} + +LinearConstraint ReadLinearConstraintVisitor::visit(const ComponentParameterNode* node) +{ + throw IllegalNodeException(); +} +} // namespace Antares::Optimization diff --git a/src/solver/optim-model-filler/ReadLinearExpressionVisitor.cpp b/src/solver/optim-model-filler/ReadLinearExpressionVisitor.cpp new file mode 100644 index 0000000000..ccc722bdc0 --- /dev/null +++ b/src/solver/optim-model-filler/ReadLinearExpressionVisitor.cpp @@ -0,0 +1,124 @@ +/* + * 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 + +#include +#include +#include +#include + +using namespace Antares::Solver::Nodes; + +namespace Antares::Optimization +{ + +ReadLinearExpressionVisitor::ReadLinearExpressionVisitor( + Solver::Visitors::EvaluationContext context): + context_(std::move(context)) +{ +} + +std::string ReadLinearExpressionVisitor::name() const +{ + return "ReadLinearExpressionVisitor"; +} + +LinearExpression ReadLinearExpressionVisitor::visit(const SumNode* node) +{ + auto operands = node->getOperands(); + return std::accumulate(std::begin(operands), + std::end(operands), + LinearExpression(), + [this](LinearExpression sum, Node* operand) + { return sum + dispatch(operand); }); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const SubtractionNode* node) +{ + return dispatch(node->left()) - dispatch(node->right()); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const MultiplicationNode* node) +{ + return dispatch(node->left()) * dispatch(node->right()); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const DivisionNode* node) +{ + return dispatch(node->left()) / dispatch(node->right()); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const EqualNode* node) +{ + throw std::invalid_argument("A linear expression can't contain comparison operators."); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const LessThanOrEqualNode* node) +{ + throw std::invalid_argument("A linear expression can't contain comparison operators."); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const GreaterThanOrEqualNode* node) +{ + throw std::invalid_argument("A linear expression can't contain comparison operators."); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const NegationNode* node) +{ + return dispatch(node->child()).negate(); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const VariableNode* node) +{ + return LinearExpression(0, {{node->value(), 1}}); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const ParameterNode* node) +{ + return {context_.getParameterValue(node->value()), {}}; +} + +LinearExpression ReadLinearExpressionVisitor::visit(const LiteralNode* node) +{ + return {node->value(), {}}; +} + +LinearExpression ReadLinearExpressionVisitor::visit(const PortFieldNode* node) +{ + throw std::invalid_argument("ReadLinearExpressionVisitor cannot visit PortFieldNodes"); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const PortFieldSumNode* node) +{ + throw std::invalid_argument("ReadLinearExpressionVisitor cannot visit PortFieldSumNodes"); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const ComponentVariableNode* node) +{ + throw std::invalid_argument("ReadLinearExpressionVisitor cannot visit ComponentVariableNodes"); +} + +LinearExpression ReadLinearExpressionVisitor::visit(const ComponentParameterNode* node) +{ + throw std::invalid_argument("ReadLinearExpressionVisitor cannot visit ComponentParameterNodes"); +} +} // namespace Antares::Optimization diff --git a/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ComponentFiller.h b/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ComponentFiller.h new file mode 100644 index 0000000000..db75c170b5 --- /dev/null +++ b/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ComponentFiller.h @@ -0,0 +1,62 @@ +/* + * 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 +#include "antares/solver/expressions/visitors/EvaluationContext.h" + +namespace Antares::Study::SystemModel +{ +class Component; +} + +namespace Antares::Optimization +{ +/** + * Component filler + * Implements LinearProbleFiller interface. + * Fills a LinearProblem with variables, constraints, and objective coefficients of a Component + */ +class ComponentFiller: public Solver::Modeler::Api::LinearProblemFiller +{ +public: + ComponentFiller() = delete; + ComponentFiller(ComponentFiller& other) = delete; + /// Create a ComponentFiller for a Component + explicit ComponentFiller(const Study::SystemModel::Component& component); + + void addVariables(Solver::Modeler::Api::ILinearProblem& pb, + Solver::Modeler::Api::LinearProblemData& data, + Solver::Modeler::Api::FillContext& ctx) override; + void addConstraints(Solver::Modeler::Api::ILinearProblem& pb, + Solver::Modeler::Api::LinearProblemData& data, + Solver::Modeler::Api::FillContext& ctx) override; + void addObjective(Solver::Modeler::Api::ILinearProblem& pb, + Solver::Modeler::Api::LinearProblemData& data, + Solver::Modeler::Api::FillContext& ctx) override; + +private: + const Study::SystemModel::Component& component_; + Solver::Visitors::EvaluationContext evaluationContext_; +}; +} // namespace Antares::Optimization diff --git a/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/LinearExpression.h b/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/LinearExpression.h new file mode 100644 index 0000000000..e53877b774 --- /dev/null +++ b/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/LinearExpression.h @@ -0,0 +1,73 @@ +/* + * 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::Optimization +{ +/** + * Linear Expression + * Represents an expression that is linear in regard to an optimization problem's variables. + * It can be fully defined by: + * - the non-zero coefficients of the variables + * - a scalar offset + */ +class LinearExpression +{ +public: + /// Build a linear expression with zero offset and zero coefficients + LinearExpression() = default; + /// Build a linear expression with a given offset and a given map of non-zero coefficients per + /// variable ID + LinearExpression(double offset, std::map coef_per_var); + /// Sum two linear expressions + LinearExpression operator+(const LinearExpression& other) const; + /// Subtract two linear expressions + LinearExpression operator-(const LinearExpression& other) const; + /// Multiply two linear expressions + /// Only one can have non-zero coefficients, otherwise the result cannot be linear + LinearExpression operator*(const LinearExpression& other) const; + /// Divide two linear expressions + /// Only first expression can have non-zero coefficients, otherwise the result cannot be linear + LinearExpression operator/(const LinearExpression& other) const; + /// Multiply linear expression by -1 + LinearExpression negate() const; + + /// Get the offset + double offset() const + { + return offset_; + } + + /// Get the non-zero coefficients per variable ID + std::map coefPerVar() const + { + return coef_per_var_; + } + +private: + double offset_ = 0; + std::map coef_per_var_; +}; +} // namespace Antares::Optimization diff --git a/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearConstraintVisitor.h b/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearConstraintVisitor.h new file mode 100644 index 0000000000..dfddc5db2f --- /dev/null +++ b/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearConstraintVisitor.h @@ -0,0 +1,76 @@ +/* + * 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 + +#include "ReadLinearExpressionVisitor.h" + +/** + * Read Linear Constraint Visitor + * Visits a Node and produces a Linear Constraint (defined by its Linear Expression and bounds). + * The root node is expected to be a comparison node. + */ +namespace Antares::Optimization +{ + +/** + * Linear Constraint + * Represents a linear constraint in an optimization problem. + * It is fully defined by: + * - a Linear Expression (defined by an offset and non-zero variable coefficients) + * - a lower and an upper bounds + */ +struct LinearConstraint +{ + std::map coef_per_var; + double lb = -std::numeric_limits::infinity(); + double ub = std::numeric_limits::infinity(); +}; + +class ReadLinearConstraintVisitor: public Solver::Visitors::NodeVisitor +{ +public: + ReadLinearConstraintVisitor() = default; + explicit ReadLinearConstraintVisitor(Solver::Visitors::EvaluationContext context); + std::string name() const override; + +private: + ReadLinearExpressionVisitor linear_expression_visitor_; + LinearConstraint visit(const Solver::Nodes::SumNode* node) override; + LinearConstraint visit(const Solver::Nodes::SubtractionNode* node) override; + LinearConstraint visit(const Solver::Nodes::MultiplicationNode* node) override; + LinearConstraint visit(const Solver::Nodes::DivisionNode* node) override; + LinearConstraint visit(const Solver::Nodes::EqualNode* node) override; + LinearConstraint visit(const Solver::Nodes::LessThanOrEqualNode* node) override; + LinearConstraint visit(const Solver::Nodes::GreaterThanOrEqualNode* node) override; + LinearConstraint visit(const Solver::Nodes::NegationNode* node) override; + LinearConstraint visit(const Solver::Nodes::VariableNode* node) override; + LinearConstraint visit(const Solver::Nodes::ParameterNode* node) override; + LinearConstraint visit(const Solver::Nodes::LiteralNode* node) override; + LinearConstraint visit(const Solver::Nodes::PortFieldNode* node) override; + LinearConstraint visit(const Solver::Nodes::PortFieldSumNode* node) override; + LinearConstraint visit(const Solver::Nodes::ComponentVariableNode* node) override; + LinearConstraint visit(const Solver::Nodes::ComponentParameterNode* node) override; +}; +} // namespace Antares::Optimization diff --git a/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearExpressionVisitor.h b/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearExpressionVisitor.h new file mode 100644 index 0000000000..ed86bf9617 --- /dev/null +++ b/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearExpressionVisitor.h @@ -0,0 +1,62 @@ +/* + * 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 +#include + +/** + * Read Linear Expression Visitor + * Visits a Node and produces a Linear Expression (defined by an offset and non-zero + * coefficients of variables) + * Comparison Nodes are not allowed + */ +namespace Antares::Optimization +{ + +class ReadLinearExpressionVisitor: public Solver::Visitors::NodeVisitor +{ +public: + ReadLinearExpressionVisitor() = default; + explicit ReadLinearExpressionVisitor(Solver::Visitors::EvaluationContext context); + std::string name() const override; + +private: + const Solver::Visitors::EvaluationContext context_; + LinearExpression visit(const Solver::Nodes::SumNode* node) override; + LinearExpression visit(const Solver::Nodes::SubtractionNode* node) override; + LinearExpression visit(const Solver::Nodes::MultiplicationNode* node) override; + LinearExpression visit(const Solver::Nodes::DivisionNode* node) override; + LinearExpression visit(const Solver::Nodes::EqualNode* node) override; + LinearExpression visit(const Solver::Nodes::LessThanOrEqualNode* node) override; + LinearExpression visit(const Solver::Nodes::GreaterThanOrEqualNode* node) override; + LinearExpression visit(const Solver::Nodes::NegationNode* node) override; + LinearExpression visit(const Solver::Nodes::VariableNode* node) override; + LinearExpression visit(const Solver::Nodes::ParameterNode* node) override; + LinearExpression visit(const Solver::Nodes::LiteralNode* node) override; + LinearExpression visit(const Solver::Nodes::PortFieldNode* node) override; + LinearExpression visit(const Solver::Nodes::PortFieldSumNode* node) override; + LinearExpression visit(const Solver::Nodes::ComponentVariableNode* node) override; + LinearExpression visit(const Solver::Nodes::ComponentParameterNode* node) override; +}; +} // namespace Antares::Optimization diff --git a/src/study/system-model/CMakeLists.txt b/src/study/system-model/CMakeLists.txt index 19cbfa7abb..c7e2208c41 100644 --- a/src/study/system-model/CMakeLists.txt +++ b/src/study/system-model/CMakeLists.txt @@ -31,7 +31,7 @@ target_include_directories(antares-study-system-model ) target_link_libraries(antares-study-system-model PUBLIC - Antares::solver-expressions + Antares::solver-expressions ) install(DIRECTORY include/antares DESTINATION "include" diff --git a/src/study/system-model/component.cpp b/src/study/system-model/component.cpp index b9b7c6a03b..1c3d360e64 100644 --- a/src/study/system-model/component.cpp +++ b/src/study/system-model/component.cpp @@ -81,7 +81,7 @@ ComponentBuilder& ComponentBuilder::withId(const std::string_view id) * \param model The model to set. * \return Reference to the ComponentBuilder object. */ -ComponentBuilder& ComponentBuilder::withModel(Model* model) +ComponentBuilder& ComponentBuilder::withModel(const Model* model) { data_.model = model; return *this; @@ -118,9 +118,11 @@ ComponentBuilder& ComponentBuilder::withScenarioGroupId(const std::string& scena * * \return The constructed Component object. */ -Component ComponentBuilder::build() const +Component ComponentBuilder::build() { - return Component(data_); + Component component(data_); + data_.reset(); // makes the ComponentBuilder re-usable + return component; } } // namespace Antares::Study::SystemModel diff --git a/src/study/system-model/include/antares/study/system-model/component.h b/src/study/system-model/include/antares/study/system-model/component.h index d3be08ba80..6195a6496c 100644 --- a/src/study/system-model/include/antares/study/system-model/component.h +++ b/src/study/system-model/include/antares/study/system-model/component.h @@ -31,12 +31,21 @@ namespace Antares::Study::SystemModel * Defines the attributes of the Component class * Made into a struct to avoid duplication in ComponentBuilder */ -struct ComponentData +class ComponentData { +public: std::string id; - Model* model = nullptr; + const Model* model = nullptr; std::map parameter_values; std::string scenario_group_id; + + void reset() + { + id.clear(); + model = nullptr; + parameter_values.clear(); + scenario_group_id.clear(); + } }; /** @@ -53,11 +62,16 @@ class Component return data_.id; } - Model* getModel() const + const Model* getModel() const { return data_.model; } + const std::map& getParameterValues() const + { + return data_.parameter_values; + } + double getParameterValue(const std::string& parameter_id) const { if (!data_.parameter_values.contains(parameter_id)) @@ -84,10 +98,10 @@ class ComponentBuilder { public: ComponentBuilder& withId(std::string_view id); - ComponentBuilder& withModel(Model* model); + ComponentBuilder& withModel(const Model* model); ComponentBuilder& withParameterValues(std::map parameter_values); ComponentBuilder& withScenarioGroupId(const std::string& scenario_group_id); - Component build() const; + Component build(); private: ComponentData data_; diff --git a/src/study/system-model/include/antares/study/system-model/expression.h b/src/study/system-model/include/antares/study/system-model/expression.h index 0b52d82f91..cf8ea30a61 100644 --- a/src/study/system-model/include/antares/study/system-model/expression.h +++ b/src/study/system-model/include/antares/study/system-model/expression.h @@ -32,14 +32,16 @@ class Node; namespace Antares::Study::SystemModel { +// TODO: add unit tests for this class class Expression { public: Expression() = default; - explicit Expression(const std::string& value, Antares::Solver::NodeRegistry root): + explicit Expression(const std::string& value, Solver::NodeRegistry root): value_(value), - root_(std::move(root)) + root_(std::move(root)), + empty_(false) { } @@ -48,9 +50,20 @@ class Expression return value_; } + Solver::Nodes::Node* RootNode() const + { + return root_.node; + } + + bool Empty() const + { + return empty_; + } + private: std::string value_; - Antares::Solver::NodeRegistry root_; + Solver::NodeRegistry root_; + bool empty_ = true; }; } // namespace Antares::Study::SystemModel diff --git a/src/study/system-model/include/antares/study/system-model/model.h b/src/study/system-model/include/antares/study/system-model/model.h index a050424131..a878838315 100644 --- a/src/study/system-model/include/antares/study/system-model/model.h +++ b/src/study/system-model/include/antares/study/system-model/model.h @@ -36,6 +36,7 @@ namespace Antares::Study::SystemModel * Defines a model that can be referenced by actual components. * A model defines the behaviour of those components. */ +// TODO: add unit tests for this class class Model { public: @@ -69,6 +70,7 @@ class Model const std::map& Variables() const { + // TODO : convert to vector? return variables_; } diff --git a/src/study/system-model/model.cpp b/src/study/system-model/model.cpp index fd77cb3cf2..18d6b15e8c 100644 --- a/src/study/system-model/model.cpp +++ b/src/study/system-model/model.cpp @@ -36,7 +36,9 @@ namespace Antares::Study::SystemModel */ Model ModelBuilder::build() { - return std::move(model_); + Model model = std::move(model_); + model_ = Model(); // makes ModelBuilder re-usable + return std::move(model); } /** diff --git a/src/tests/src/solver/CMakeLists.txt b/src/tests/src/solver/CMakeLists.txt index 2152a8e1bf..9cf4843bd8 100644 --- a/src/tests/src/solver/CMakeLists.txt +++ b/src/tests/src/solver/CMakeLists.txt @@ -4,5 +4,6 @@ add_subdirectory(lps) add_subdirectory(modelParser) add_subdirectory(modeler) add_subdirectory(optimisation) +add_subdirectory(optim-model-filler) add_subdirectory(simulation) add_subdirectory(utils) diff --git a/src/tests/src/solver/modeler/api/testModelerLinearProblemWithOrtools.cpp b/src/tests/src/solver/modeler/api/testModelerLinearProblemWithOrtools.cpp index 7c1f8f84e3..efad36d77c 100644 --- a/src/tests/src/solver/modeler/api/testModelerLinearProblemWithOrtools.cpp +++ b/src/tests/src/solver/modeler/api/testModelerLinearProblemWithOrtools.cpp @@ -65,6 +65,7 @@ BOOST_FIXTURE_TEST_CASE(add_int_variable_to_problem___check_var_exists, FixtureE pb->addIntVariable(5, 15, "var"); auto* var = pb->getVariable("var"); BOOST_CHECK(var); + BOOST_CHECK(var->isInteger()); BOOST_CHECK_EQUAL(var->getLb(), 5); BOOST_CHECK_EQUAL(var->getUb(), 15); } @@ -74,6 +75,7 @@ BOOST_FIXTURE_TEST_CASE(add_num_variable_to_problem___check_var_exists, FixtureE pb->addNumVariable(2., 7., "var"); auto* var = pb->getVariable("var"); BOOST_CHECK(var); + BOOST_CHECK(!var->isInteger()); BOOST_CHECK_EQUAL(var->getLb(), 2.); BOOST_CHECK_EQUAL(var->getUb(), 7.); } diff --git a/src/tests/src/solver/optim-model-filler/CMakeLists.txt b/src/tests/src/solver/optim-model-filler/CMakeLists.txt new file mode 100644 index 0000000000..fa81c819b7 --- /dev/null +++ b/src/tests/src/solver/optim-model-filler/CMakeLists.txt @@ -0,0 +1,29 @@ +set(EXECUTABLE_NAME unit-tests-for-component-filler) +add_executable(${EXECUTABLE_NAME}) + +target_sources(${EXECUTABLE_NAME} + PRIVATE + test_main.cpp + test_componentFiller.cpp + test_linearExpression.cpp + test_readLinearExpressionVisitor.cpp + test_readLinearConstraintVisitor.cpp +) +target_include_directories(${EXECUTABLE_NAME} + PRIVATE + "${src_solver_optimisation}" +) + +target_link_libraries(${EXECUTABLE_NAME} + PRIVATE + Boost::unit_test_framework + antares-study-system-model + Antares::modeler-ortools-impl + Antares::optim-model-filler + test_utils_unit +) + +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) +add_test(NAME ${EXECUTABLE_NAME} COMMAND ${EXECUTABLE_NAME}) +set_property(TEST ${EXECUTABLE_NAME} PROPERTY LABELS unit) + diff --git a/src/tests/src/solver/optim-model-filler/test_componentFiller.cpp b/src/tests/src/solver/optim-model-filler/test_componentFiller.cpp new file mode 100644 index 0000000000..c1a5a52ec9 --- /dev/null +++ b/src/tests/src/solver/optim-model-filler/test_componentFiller.cpp @@ -0,0 +1,514 @@ +/* + * 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 . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include "antares/solver/expressions/nodes/ExpressionsNodes.h" +#include "antares/solver/modeler/api/linearProblemBuilder.h" +#include "antares/solver/modeler/ortoolsImpl/linearProblem.h" +#include "antares/solver/optim-model-filler/ComponentFiller.h" +#include "antares/study/system-model/component.h" +#include "antares/study/system-model/parameter.h" + +#include "unit_test_utils.h" + +using namespace Antares::Solver::Modeler::Api; +using namespace Antares::Study::SystemModel; +using namespace Antares::Optimization; +using namespace Antares::Solver::Nodes; +using namespace std; + +struct VariableData +{ + string id; + ValueType type; + Node* lb; + Node* ub; +}; + +struct ConstraintData +{ + string id; + Node* expression; +}; + +struct LinearProblemBuildingFixture +{ + map models; + Antares::Solver::Registry nodes; + vector components; + unique_ptr pb; + + void createModel(string modelId, + vector parameterIds, + vector variablesData, + vector constraintsData, + Node* objective = nullptr); + + void createModelWithOneFloatVar(const string& modelId, + const vector& parameterIds, + const string& varId, + Node* lb, + Node* ub, + const vector& constraintsData, + Node* objective = nullptr) + { + createModel(modelId, + parameterIds, + {{varId, ValueType::FLOAT, lb, ub}}, + constraintsData, + objective); + } + + void createComponent(const string& modelId, + const string& componentId, + map parameterValues = {}); + + Node* literal(double value) + { + return nodes.create(value); + } + + Node* parameter(const string& paramId) + { + return nodes.create(paramId); + } + + Node* variable(const string& varId) + { + return nodes.create(varId); + } + + Node* multiply(Node* node1, Node* node2) + { + return nodes.create(node1, node2); + } + + Node* negate(Node* node) + { + return nodes.create(node); + } + + void buildLinearProblem(); +}; + +void LinearProblemBuildingFixture::createModel(string modelId, + vector parameterIds, + vector variablesData, + vector constraintsData, + Node* objective) +{ + auto createExpression = [this](Node* node) + { + Antares::Solver::NodeRegistry node_registry(node, move(nodes)); + Expression expression("expression", move(node_registry)); + return move(expression); + }; + vector parameters; + for (auto parameter_id: parameterIds) + { + parameters.push_back( + Parameter(parameter_id, Parameter::TimeDependent::NO, Parameter::ScenarioDependent::NO)); + } + vector variables; + for (auto [id, type, lb, ub]: variablesData) + { + variables.push_back(move(Variable(id, createExpression(lb), createExpression(ub), type))); + } + vector constraints; + for (auto [id, expression]: constraintsData) + { + constraints.push_back(move(Constraint(id, createExpression(expression)))); + } + ModelBuilder model_builder; + model_builder.withId(modelId) + .withParameters(move(parameters)) + .withVariables(move(variables)) + .withConstraints(move(constraints)); + if (objective) + { + model_builder.withObjective(createExpression(objective)); + } + auto model = model_builder.build(); + models[modelId] = move(model); +} + +void LinearProblemBuildingFixture::createComponent(const string& modelId, + const string& componentId, + map parameterValues) +{ + BOOST_CHECK_NO_THROW(models.at(modelId)); + ComponentBuilder component_builder; + auto component = component_builder.withId(componentId) + .withModel(&models.at(modelId)) + .withScenarioGroupId("scenario_group") + .withParameterValues(move(parameterValues)) + .build(); + components.push_back(move(component)); +} + +void LinearProblemBuildingFixture::buildLinearProblem() +{ + vector> fillers; + vector fillers_ptr; + for (auto& component: components) + { + auto cf = make_unique(component); + fillers.push_back(move(cf)); + } + for (auto& component_filler: fillers) + { + fillers_ptr.push_back(component_filler.get()); + } + pb = make_unique(false, "scip"); + LinearProblemBuilder linear_problem_builder(fillers_ptr); + LinearProblemData dummy_data; + FillContext dummy_time_scenario_ctx = {0, 0}; + linear_problem_builder.build(*pb.get(), dummy_data, dummy_time_scenario_ctx); +} + +BOOST_FIXTURE_TEST_SUITE(_ComponentFiller_addVariables_, LinearProblemBuildingFixture) + +BOOST_AUTO_TEST_CASE(var_with_literal_bounds_to_filler__problem_contains_one_var) +{ + createModelWithOneFloatVar("some_model", {}, "var1", literal(-5), literal(10), {}); + createComponent("some_model", "some_component"); + buildLinearProblem(); + + BOOST_CHECK_EQUAL(pb->variableCount(), 1); + BOOST_CHECK_EQUAL(pb->constraintCount(), 0); + auto* var = pb->getVariable("some_component.var1"); + BOOST_CHECK(var); + BOOST_CHECK_EQUAL(var->getLb(), -5); + BOOST_CHECK_EQUAL(var->getUb(), 10); + BOOST_CHECK(!var->isInteger()); + BOOST_CHECK_EQUAL(pb->getObjectiveCoefficient(var), 0); +} + +BOOST_AUTO_TEST_CASE(var_with_wrong_parameter_lb__exception_is_raised) +{ + createModel("my-model", + {}, + {{"variable", ValueType::FLOAT, parameter("parameter-not-in-model"), literal(10)}}, + {}); + createComponent("my-model", "my-component"); + // TODO : improve exception message in eval visitor + BOOST_CHECK_THROW(buildLinearProblem(), out_of_range); +} + +BOOST_AUTO_TEST_CASE(var_with_wrong_variable_ub__exception_is_raised) +{ + createModel("my-model", + {}, + {{"variable", ValueType::FLOAT, literal(10), variable("variable")}}, + {}); + createComponent("my-model", "my-component"); + // TODO : improve exception message in eval visitor + BOOST_CHECK_THROW(buildLinearProblem(), out_of_range); +} + +BOOST_AUTO_TEST_CASE(two_variables_given_to_different_fillers__LP_contains_the_two_variables) +{ + createModelWithOneFloatVar("m1", {}, "var1", literal(-1), literal(6), {}); + createModelWithOneFloatVar("m2", {}, "var2", literal(-3), literal(2), {}); + createComponent("m1", "component_1"); + createComponent("m2", "component_2"); + buildLinearProblem(); + + BOOST_CHECK_EQUAL(pb->variableCount(), 2); + + auto* var1 = pb->getVariable("component_1.var1"); + BOOST_CHECK(var1); + BOOST_CHECK(!var1->isInteger()); + BOOST_CHECK_EQUAL(var1->getLb(), -1.); + BOOST_CHECK_EQUAL(var1->getUb(), 6.); + + auto* var2 = pb->getVariable("component_2.var2"); + BOOST_CHECK(var2); + BOOST_CHECK(!var2->isInteger()); + BOOST_CHECK_EQUAL(var2->getLb(), -3.); + BOOST_CHECK_EQUAL(var2->getUb(), 2.); +} + +BOOST_AUTO_TEST_CASE(var_whose_bounds_are_parameters_given_to_component__problem_contains_this_var) +{ + createModel("model", + {"pmin", "pmax"}, + {{"var1", ValueType::INTEGER, parameter("pmin"), parameter("pmax")}}, + {}); + createComponent("model", "componentToto", {{"pmin", -3.}, {"pmax", 4.}}); + buildLinearProblem(); + + BOOST_CHECK_EQUAL(pb->variableCount(), 1); + BOOST_CHECK_EQUAL(pb->constraintCount(), 0); + auto* var = pb->getVariable("componentToto.var1"); + BOOST_CHECK(var); + BOOST_CHECK(var->isInteger()); + BOOST_CHECK_EQUAL(var->getLb(), -3.); + BOOST_CHECK_EQUAL(var->getUb(), 4.); +} + +BOOST_AUTO_TEST_CASE(three_different_vars__exist) +{ + VariableData var1 = {"is_cluster_on", ValueType::BOOL, literal(0), literal(1)}; + VariableData var2 = {"n_started_units", ValueType::INTEGER, literal(0), parameter("nUnits")}; + VariableData var3 = {"p_per_unit", ValueType::FLOAT, parameter("pmin"), parameter("pmax")}; + createModel("thermalClusterModel", {"pmin", "pmax", "nUnits"}, {var1, var2, var3}, {}); + createComponent("thermalClusterModel", + "thermalCluster1", + {{"pmin", 100.248}, {"pmax", 950.6784}, {"nUnits", 17.}}); + buildLinearProblem(); + + BOOST_CHECK_EQUAL(pb->variableCount(), 3); + BOOST_CHECK_EQUAL(pb->constraintCount(), 0); + auto* is_cluster_on = pb->getVariable("thermalCluster1.is_cluster_on"); + BOOST_CHECK(is_cluster_on); + BOOST_CHECK(is_cluster_on->isInteger()); + BOOST_CHECK_EQUAL(is_cluster_on->getLb(), 0); + BOOST_CHECK_EQUAL(is_cluster_on->getUb(), 1); + auto* n_started_units = pb->getVariable("thermalCluster1.n_started_units"); + BOOST_CHECK(n_started_units); + BOOST_CHECK(n_started_units->isInteger()); + BOOST_CHECK_EQUAL(n_started_units->getLb(), 0); + BOOST_CHECK_EQUAL(n_started_units->getUb(), 17); + auto* p_per_unit = pb->getVariable("thermalCluster1.p_per_unit"); + BOOST_CHECK(p_per_unit); + BOOST_CHECK(!p_per_unit->isInteger()); + BOOST_CHECK_EQUAL(p_per_unit->getLb(), 100.248); + BOOST_CHECK_EQUAL(p_per_unit->getUb(), 950.6784); +} + +BOOST_AUTO_TEST_CASE(one_model_two_components__dont_clash) +{ + createModelWithOneFloatVar("m1", {"ub"}, "var1", literal(-100), parameter("ub"), {}); + createComponent("m1", "component_1", {{"ub", 15}}); + createComponent("m1", "component_2", {{"ub", 48}}); + buildLinearProblem(); + + BOOST_CHECK_EQUAL(pb->variableCount(), 2); + BOOST_CHECK_EQUAL(pb->constraintCount(), 0); + auto* c1_var1 = pb->getVariable("component_1.var1"); + BOOST_CHECK(c1_var1); + BOOST_CHECK(!c1_var1->isInteger()); + BOOST_CHECK_EQUAL(c1_var1->getLb(), -100); + BOOST_CHECK_EQUAL(c1_var1->getUb(), 15); + auto* c2_var1 = pb->getVariable("component_2.var1"); + BOOST_CHECK(c2_var1); + BOOST_CHECK(!c2_var1->isInteger()); + BOOST_CHECK_EQUAL(c2_var1->getLb(), -100); + BOOST_CHECK_EQUAL(c2_var1->getUb(), 48); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_FIXTURE_TEST_SUITE(_ComponentFiller_addConstraints_, LinearProblemBuildingFixture) + +BOOST_AUTO_TEST_CASE(ct_one_var__pb_contains_the_ct) +{ + // var1 <= 3 + auto var_node = variable("var1"); + auto three = literal(3); + auto ct_node = nodes.create(var_node, three); + createModel("model", + {}, + {{"var1", ValueType::BOOL, literal(-5), literal(10)}}, + {{"ct1", ct_node}}); + createComponent("model", "componentToto"); + buildLinearProblem(); + + auto var = pb->getVariable("componentToto.var1"); + BOOST_CHECK(var); + BOOST_CHECK(var->isInteger()); + BOOST_CHECK_EQUAL(pb->variableCount(), 1); + BOOST_CHECK_EQUAL(pb->constraintCount(), 1); + auto ct = pb->getConstraint("componentToto.ct1"); + BOOST_CHECK(ct); + BOOST_CHECK_EQUAL(ct->getLb(), -pb->infinity()); + BOOST_CHECK_EQUAL(ct->getUb(), 3); + BOOST_CHECK_EQUAL(ct->getCoefficient(var), 1); +} + +BOOST_AUTO_TEST_CASE(ct_one_var_with_coef__pb_contains_the_ct) +{ + // 3 * var1 >= 5 * var1 + 5 + // simplified to : -2 * var1 >= 5 + auto var_node = variable("var__1"); + auto five = literal(5); + auto coef_node_left = multiply(literal(3), var_node); + auto coef_node_right = multiply(var_node, five); + auto sum_node_right = nodes.create(coef_node_right, five); + auto ct_node = nodes.create(coef_node_left, sum_node_right); + + createModelWithOneFloatVar("model", + {}, + "var__1", + literal(-5), + literal(10), + {{"ct_1", ct_node}}); + createComponent("model", "componentTata"); + buildLinearProblem(); + + BOOST_CHECK_EQUAL(pb->variableCount(), 1); + BOOST_CHECK_NO_THROW(pb->getVariable("componentTata.var__1")); + auto var = pb->getVariable("componentTata.var__1"); + BOOST_CHECK_EQUAL(pb->constraintCount(), 1); + BOOST_CHECK_NO_THROW(pb->getConstraint("componentTata.ct_1")); + auto ct = pb->getConstraint("componentTata.ct_1"); + BOOST_CHECK(ct); + BOOST_CHECK_EQUAL(ct->getLb(), 5); + BOOST_CHECK_EQUAL(ct->getUb(), pb->infinity()); + BOOST_CHECK_EQUAL(ct->getCoefficient(var), -2); +} + +BOOST_AUTO_TEST_CASE(ct_with_two_vars) +{ + // param1(-16) * v1 + 8 * v2 + 5 - param2(8) = 7 * v1 + param3(5) * v2 + 89 + 5 * param4(-3) + // simplifies to: -23 * v1 + 3 * v2 = 77 + vector params = {"param1", "param2", "param3", "param4"}; + VariableData var1Data = {"v1", ValueType::FLOAT, literal(-50.), literal(300.)}; + VariableData var2Data = {"v2", ValueType::FLOAT, literal(60.), literal(75.)}; + + auto sum_node_left = nodes.create(multiply(variable("v1"), parameter("param1")), + multiply(literal(8), variable("v2")), + literal(5), + negate(parameter("param2"))); + auto sum_node_right = nodes.create(multiply(variable("v1"), literal(7)), + multiply(parameter("param3"), variable("v2")), + literal(89), + multiply(literal(5), parameter("param4"))); + auto ct_node = nodes.create(sum_node_left, sum_node_right); + + createModel("my_new_model", params, {var1Data, var2Data}, {{"constraint1", ct_node}}); + createComponent("my_new_model", + "my_component", + {{"param1", -16}, {"param2", 8}, {"param3", 5}, {"param4", -3}}); + buildLinearProblem(); + + BOOST_CHECK_EQUAL(pb->variableCount(), 2); + BOOST_CHECK_EQUAL(pb->constraintCount(), 1); + BOOST_CHECK_NO_THROW(pb->getConstraint("my_component.constraint1")); + auto ct = pb->getConstraint("my_component.constraint1"); + BOOST_CHECK(ct); + BOOST_CHECK_EQUAL(ct->getLb(), 77); + BOOST_CHECK_EQUAL(ct->getUb(), 77); + BOOST_CHECK_EQUAL(ct->getCoefficient(pb->getVariable("my_component.v1")), -23); + BOOST_CHECK_EQUAL(ct->getCoefficient(pb->getVariable("my_component.v2")), 3); +} + +BOOST_AUTO_TEST_CASE(two_constraints__they_are_created) +{ + // 3 * v1 -2 <= v2 (simplifies to : 3 * v1 - 2 * v2 <= 2) + // v2 <= v1 / 2 (simplifies to : -0.5 * v1 + v2 <= 0) + VariableData var1Data = {"v1", ValueType::FLOAT, literal(-50.), literal(300.)}; + VariableData var2Data = {"v2", ValueType::FLOAT, literal(60.), literal(75.)}; + + auto ct1_node = nodes.create( + nodes.create(multiply(literal(3), variable("v1")), literal(2)), + variable("v2")); + auto ct2_node = nodes.create(variable("v2"), + nodes.create(variable("v1"), + literal(2))); + + createModel("my_new_model", {}, {var1Data, var2Data}, {{"ct1", ct1_node}, {"ct2", ct2_node}}); + createComponent("my_new_model", "my_component", {}); + buildLinearProblem(); + + BOOST_CHECK_EQUAL(pb->variableCount(), 2); + BOOST_CHECK_EQUAL(pb->constraintCount(), 2); + + BOOST_CHECK_NO_THROW(pb->getConstraint("my_component.ct1")); + auto ct1 = pb->getConstraint("my_component.ct1"); + BOOST_CHECK(ct1); + BOOST_CHECK_EQUAL(ct1->getLb(), -numeric_limits::infinity()); + BOOST_CHECK_EQUAL(ct1->getUb(), 2); + BOOST_CHECK_EQUAL(ct1->getCoefficient(pb->getVariable("my_component.v1")), 3); + BOOST_CHECK_EQUAL(ct1->getCoefficient(pb->getVariable("my_component.v2")), -1); + + BOOST_CHECK_NO_THROW(pb->getConstraint("my_component.ct2")); + auto ct2 = pb->getConstraint("my_component.ct2"); + BOOST_CHECK(ct2); + BOOST_CHECK_EQUAL(ct2->getLb(), -numeric_limits::infinity()); + BOOST_CHECK_EQUAL(ct2->getUb(), 0); + BOOST_CHECK_EQUAL(ct2->getCoefficient(pb->getVariable("my_component.v1")), -0.5); + BOOST_CHECK_EQUAL(ct2->getCoefficient(pb->getVariable("my_component.v2")), 1); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_FIXTURE_TEST_SUITE(_ComponentFiller_addObjective_, LinearProblemBuildingFixture) + +BOOST_AUTO_TEST_CASE(one_var_with_objective) +{ + auto objective = variable("x"); + createModelWithOneFloatVar("model", {}, "x", literal(-50), literal(-40), {}, objective); + createComponent("model", "componentA", {}); + buildLinearProblem(); + + BOOST_CHECK_EQUAL(pb->variableCount(), 1); + BOOST_CHECK_NO_THROW(pb->getVariable("componentA.x")); + BOOST_CHECK_EQUAL(pb->getObjectiveCoefficient(pb->getVariable("componentA.x")), 1); +} + +BOOST_AUTO_TEST_CASE(two_vars_but_only_one_in_objective) +{ + VariableData var1Data = {"v1", ValueType::FLOAT, literal(-50.), literal(300.)}; + VariableData var2Data = {"v2", ValueType::FLOAT, literal(60.), literal(75.)}; + auto objective = multiply(variable("v2"), literal(37)); + + createModel("model", {}, {var1Data, var2Data}, {}, objective); + createComponent("model", "componentA", {}); + buildLinearProblem(); + + BOOST_CHECK_EQUAL(pb->variableCount(), 2); + BOOST_CHECK_NO_THROW(pb->getVariable("componentA.v1")); + BOOST_CHECK_NO_THROW(pb->getVariable("componentA.v2")); + BOOST_CHECK_EQUAL(pb->getObjectiveCoefficient(pb->getVariable("componentA.v1")), 0); + BOOST_CHECK_EQUAL(pb->getObjectiveCoefficient(pb->getVariable("componentA.v2")), 37); +} + +BOOST_AUTO_TEST_CASE(one_var_with_param_objective) +{ + // -param(5)*param(5) * x + auto objective = multiply(negate(multiply(parameter("param"), parameter("param"))), + variable("x")); + createModelWithOneFloatVar("model", {"param"}, "x", literal(-50), literal(-40), {}, objective); + createComponent("model", "componentA", {{"param", 5}}); + buildLinearProblem(); + + BOOST_CHECK_EQUAL(pb->variableCount(), 1); + BOOST_CHECK_NO_THROW(pb->getVariable("componentA.x")); + BOOST_CHECK_EQUAL(pb->getObjectiveCoefficient(pb->getVariable("componentA.x")), -25); +} + +BOOST_AUTO_TEST_CASE(offset_in_objective__throws_exception) +{ + auto objective = literal(6); + createModelWithOneFloatVar("model", {}, "x", literal(-50), literal(-40), {}, objective); + createComponent("model", "componentA", {}); + BOOST_CHECK_EXCEPTION(buildLinearProblem(), + invalid_argument, + checkMessage("Antares does not support objective offsets (found in model " + "'model' of component 'componentA').")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/optim-model-filler/test_linearExpression.cpp b/src/tests/src/solver/optim-model-filler/test_linearExpression.cpp new file mode 100644 index 0000000000..b8e7ed0441 --- /dev/null +++ b/src/tests/src/solver/optim-model-filler/test_linearExpression.cpp @@ -0,0 +1,150 @@ +/* + * 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 . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +#include + +using namespace Antares::Optimization; + +BOOST_AUTO_TEST_SUITE(_linear_expressions_) + +BOOST_AUTO_TEST_CASE(default_linear_expression) +{ + LinearExpression linearExpression; + + BOOST_CHECK_EQUAL(linearExpression.offset(), 0.); + BOOST_CHECK(linearExpression.coefPerVar().empty()); +} + +BOOST_AUTO_TEST_CASE(linear_expression_explicit_construction) +{ + LinearExpression linearExpression(4., {{"some key", -5.}}); + + BOOST_CHECK_EQUAL(linearExpression.offset(), 4.); + BOOST_CHECK_EQUAL(linearExpression.coefPerVar().size(), 1); + BOOST_CHECK_EQUAL(linearExpression.coefPerVar()["some key"], -5.); +} + +BOOST_AUTO_TEST_CASE(sum_two_linear_expressions) +{ + LinearExpression linearExpression1(4., {{"var1", -5.}, {"var2", 6.}}); + LinearExpression linearExpression2(-1., {{"var3", 20.}, {"var2", -4.}}); + + auto sum = linearExpression1 + linearExpression2; + + BOOST_CHECK_EQUAL(sum.offset(), 3.); + BOOST_CHECK_EQUAL(sum.coefPerVar().size(), 3); + BOOST_CHECK_EQUAL(sum.coefPerVar()["var1"], -5.); + BOOST_CHECK_EQUAL(sum.coefPerVar()["var2"], 2.); + BOOST_CHECK_EQUAL(sum.coefPerVar()["var3"], 20.); +} + +BOOST_AUTO_TEST_CASE(subtract_two_linear_expressions) +{ + LinearExpression linearExpression1(4., {{"var1", -5.}, {"var2", 6.}}); + LinearExpression linearExpression2(-1., {{"var2", -4.}, {"var3", 20.}}); + + auto subtract = linearExpression1 - linearExpression2; + + BOOST_CHECK_EQUAL(subtract.offset(), 5.); + BOOST_CHECK_EQUAL(subtract.coefPerVar().size(), 3); + BOOST_CHECK_EQUAL(subtract.coefPerVar()["var1"], -5.); + BOOST_CHECK_EQUAL(subtract.coefPerVar()["var2"], 10.); + BOOST_CHECK_EQUAL(subtract.coefPerVar()["var3"], -20.); +} + +BOOST_AUTO_TEST_CASE(multiply_linear_expression_by_scalar) +{ + LinearExpression linearExpression(4., {{"var1", -5.}, {"var2", 6.}}); + LinearExpression someScalar(-2., {}); + + auto product = linearExpression * someScalar; + + BOOST_CHECK_EQUAL(product.offset(), -8.); + BOOST_CHECK_EQUAL(product.coefPerVar().size(), 2); + BOOST_CHECK_EQUAL(product.coefPerVar()["var1"], 10.); + BOOST_CHECK_EQUAL(product.coefPerVar()["var2"], -12.); +} + +BOOST_AUTO_TEST_CASE(multiply_scalar_by_linear_expression) +{ + LinearExpression linearExpression(4., {{"var1", -5.}, {"var2", 6.}}); + LinearExpression someScalar(-2., {}); + + auto product = someScalar * linearExpression; + + BOOST_CHECK_EQUAL(product.offset(), -8.); + BOOST_CHECK_EQUAL(product.coefPerVar().size(), 2); + BOOST_CHECK_EQUAL(product.coefPerVar()["var1"], 10.); + BOOST_CHECK_EQUAL(product.coefPerVar()["var2"], -12.); +} + +BOOST_AUTO_TEST_CASE(multiply_two_linear_expressions_containing_variables__exception_raised) +{ + LinearExpression linearExpression1(4., {{"var1", -5.}, {"var2", 6.}}); + LinearExpression linearExpression2(-1., {{"var2", -4.}, {"var3", 20.}}); + + BOOST_CHECK_EXCEPTION(linearExpression1 * linearExpression2, + std::invalid_argument, + checkMessage("A linear expression can't have quadratic terms.")); +} + +BOOST_AUTO_TEST_CASE(divide_linear_expression_by_scalar) +{ + LinearExpression linearExpression(4., {{"var1", -5.}, {"var2", 6.}}); + LinearExpression someScalar(-2., {}); + + auto product = linearExpression / someScalar; + + BOOST_CHECK_EQUAL(product.offset(), -2.); + BOOST_CHECK_EQUAL(product.coefPerVar().size(), 2); + BOOST_CHECK_EQUAL(product.coefPerVar()["var1"], 2.5); + BOOST_CHECK_EQUAL(product.coefPerVar()["var2"], -3.); +} + +BOOST_AUTO_TEST_CASE(divide_scalar_by_linear_expression__exception_raised) +{ + LinearExpression linearExpression(4., {{"var1", -5.}, {"var2", 6.}}); + LinearExpression someScalar(-2., {}); + + BOOST_CHECK_EXCEPTION(someScalar / linearExpression, + std::invalid_argument, + checkMessage("A linear expression can't have a variable as a dividend.")); +} + +BOOST_AUTO_TEST_CASE(negate_linear_expression) +{ + LinearExpression linearExpression(4., {{"var1", -5.}, {"var2", 6.}}); + + auto negative = linearExpression.negate(); + + BOOST_CHECK_EQUAL(negative.offset(), -4.); + BOOST_CHECK_EQUAL(negative.coefPerVar().size(), 2); + BOOST_CHECK_EQUAL(negative.coefPerVar()["var1"], 5.); + BOOST_CHECK_EQUAL(negative.coefPerVar()["var2"], -6.); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/optim-model-filler/test_main.cpp b/src/tests/src/solver/optim-model-filler/test_main.cpp new file mode 100644 index 0000000000..6f0c4178e7 --- /dev/null +++ b/src/tests/src/solver/optim-model-filler/test_main.cpp @@ -0,0 +1,26 @@ +/* + * 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 . + */ + +#define BOOST_TEST_MODULE test modeler impl + +#define WIN32_LEAN_AND_MEAN + +#include diff --git a/src/tests/src/solver/optim-model-filler/test_readLinearConstraintVisitor.cpp b/src/tests/src/solver/optim-model-filler/test_readLinearConstraintVisitor.cpp new file mode 100644 index 0000000000..da7b16eb86 --- /dev/null +++ b/src/tests/src/solver/optim-model-filler/test_readLinearConstraintVisitor.cpp @@ -0,0 +1,129 @@ +/* + * 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 . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +#include +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; +using namespace Antares::Solver::Visitors; + +using namespace Antares::Optimization; + +BOOST_AUTO_TEST_SUITE(_read_linear_constraint_visitor_) + +BOOST_AUTO_TEST_CASE(test_name) +{ + ReadLinearConstraintVisitor visitor; + BOOST_CHECK_EQUAL(visitor.name(), "ReadLinearConstraintVisitor"); +} + +BOOST_FIXTURE_TEST_CASE(test_visit_equal_node, Registry) +{ + // 5 + var1 = var2 + 3 * var1 - param1(9) ==> -2 * var1 - var2 = -14 + Node* lhs = create(create(5.), create("var1")); + Node* rhs = create(create("var2"), + create(create(3.), + create("var1")), + create(create("param1"))); + Node* node = create(lhs, rhs); + EvaluationContext context({{"param1", 9.}}, {}); + ReadLinearConstraintVisitor visitor(context); + auto constraint = visitor.dispatch(node); + BOOST_CHECK_EQUAL(constraint.lb, -14.); + BOOST_CHECK_EQUAL(constraint.ub, -14.); + BOOST_CHECK_EQUAL(constraint.coef_per_var.size(), 2); + BOOST_CHECK_EQUAL(constraint.coef_per_var["var1"], -2); + BOOST_CHECK_EQUAL(constraint.coef_per_var["var2"], -1); +} + +BOOST_FIXTURE_TEST_CASE(test_visit_less_than_or_equal_node, Registry) +{ + // -9 + var3 <= var1 + 5 * var2 - param1(10) ==> - var1 - 5 * var2 + var3 <= -1 + Node* lhs = create(create(-9.), create("var3")); + Node* rhs = create(create("var1"), + create(create(5.), + create("var2")), + create(create("param1"))); + Node* node = create(lhs, rhs); + EvaluationContext context({{"param1", 10.}}, {}); + ReadLinearConstraintVisitor visitor(context); + auto constraint = visitor.dispatch(node); + BOOST_CHECK_EQUAL(constraint.lb, -std::numeric_limits::infinity()); + BOOST_CHECK_EQUAL(constraint.ub, -1.); + BOOST_CHECK_EQUAL(constraint.coef_per_var.size(), 3); + BOOST_CHECK_EQUAL(constraint.coef_per_var["var1"], -1); + BOOST_CHECK_EQUAL(constraint.coef_per_var["var2"], -5); + BOOST_CHECK_EQUAL(constraint.coef_per_var["var3"], 1); +} + +BOOST_FIXTURE_TEST_CASE(test_visit_greater_than_or_equal_node, Registry) +{ + // 5 + var1 >= var2 + 3 * var1 - param1(9) ==> -2 * var1 - var2 >= -14 + Node* lhs = create(create(5.), create("var1")); + Node* rhs = create(create("var2"), + create(create(3.), + create("var1")), + create(create("param1"))); + Node* node = create(lhs, rhs); + EvaluationContext context({{"param1", 9.}}, {}); + ReadLinearConstraintVisitor visitor(context); + auto constraint = visitor.dispatch(node); + BOOST_CHECK_EQUAL(constraint.lb, -14); + BOOST_CHECK_EQUAL(constraint.ub, std::numeric_limits::infinity()); + BOOST_CHECK_EQUAL(constraint.coef_per_var.size(), 2); + BOOST_CHECK_EQUAL(constraint.coef_per_var["var1"], -2); + BOOST_CHECK_EQUAL(constraint.coef_per_var["var2"], -1); +} + +BOOST_FIXTURE_TEST_CASE(test_visit_illegal_node, Registry) +{ + auto lit = create(5.); + std::vector illegal_nodes = {create(), + create(lit, lit), + create(lit, lit), + create(lit, lit), + create(lit), + create("var"), + create("param"), + create(5.), + create("port", "field"), + create("port", "field"), + create("x", "y"), + create("x", "y")}; + + for (Node* node: illegal_nodes) + { + ReadLinearConstraintVisitor visitor; + BOOST_CHECK_EXCEPTION(visitor.dispatch(node), + std::invalid_argument, + checkMessage("Root node of a constraint must be a comparator.")); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/optim-model-filler/test_readLinearExpressionVisitor.cpp b/src/tests/src/solver/optim-model-filler/test_readLinearExpressionVisitor.cpp new file mode 100644 index 0000000000..e9ce35c934 --- /dev/null +++ b/src/tests/src/solver/optim-model-filler/test_readLinearExpressionVisitor.cpp @@ -0,0 +1,179 @@ +/* + * 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 . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +#include +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; +using namespace Antares::Solver::Visitors; + +using namespace Antares::Optimization; + +BOOST_AUTO_TEST_SUITE(_read_linear_expression_visitor_) + +BOOST_AUTO_TEST_CASE(name) +{ + ReadLinearExpressionVisitor visitor; + BOOST_CHECK_EQUAL(visitor.name(), "ReadLinearExpressionVisitor"); +} + +BOOST_FIXTURE_TEST_CASE(visit_literal, Registry) +{ + Node* node = create(5.); + ReadLinearExpressionVisitor visitor; + auto linear_expression = visitor.dispatch(node); + BOOST_CHECK_EQUAL(linear_expression.offset(), 5.); + BOOST_CHECK(linear_expression.coefPerVar().empty()); +} + +BOOST_FIXTURE_TEST_CASE(visit_literal_plus_param, Registry) +{ + // 5 + param(3) = 8 + Node* sum = create(create(5.), create("param")); + EvaluationContext evaluation_context({{"param", 3.}}, {}); + ReadLinearExpressionVisitor visitor(evaluation_context); + auto linear_expression = visitor.dispatch(sum); + BOOST_CHECK_EQUAL(linear_expression.offset(), 8.); + BOOST_CHECK(linear_expression.coefPerVar().empty()); +} + +BOOST_FIXTURE_TEST_CASE(visit_literal_plus_param_plus_var, Registry) +{ + // 60 + param(-5) + 7 * var = { 55, {var : 7} } + Node* product = create(create(7.), + create("var")); + Node* sum = create(create(60.), create("param"), product); + EvaluationContext evaluation_context({{"param", -5.}}, {}); + ReadLinearExpressionVisitor visitor(evaluation_context); + auto linear_expression = visitor.dispatch(sum); + BOOST_CHECK_EQUAL(linear_expression.offset(), 55.); + BOOST_CHECK_EQUAL(linear_expression.coefPerVar().size(), 1); + BOOST_CHECK_EQUAL(linear_expression.coefPerVar()["var"], 7.); +} + +BOOST_FIXTURE_TEST_CASE(visit_negate_literal_plus_var, Registry) +{ + // -(60 + 7 * var) = { -60, {var : -7} } + Node* product = create(create(7.), + create("var")); + Node* sum = create(create(60.), product); + Node* neg = create(sum); + ReadLinearExpressionVisitor visitor; + auto linear_expression = visitor.dispatch(neg); + BOOST_CHECK_EQUAL(linear_expression.offset(), -60.); + BOOST_CHECK_EQUAL(linear_expression.coefPerVar().size(), 1); + BOOST_CHECK_EQUAL(linear_expression.coefPerVar()["var"], -7.); +} + +BOOST_FIXTURE_TEST_CASE(visit_literal_minus_var, Registry) +{ + // 60 - 7 * var = { 60, {var : -7} } + Node* product = create(create(7.), + create("var")); + Node* sub = create(create(60.), product); + ReadLinearExpressionVisitor visitor; + auto linear_expression = visitor.dispatch(sub); + BOOST_CHECK_EQUAL(linear_expression.offset(), 60.); + BOOST_CHECK_EQUAL(linear_expression.coefPerVar().size(), 1); + BOOST_CHECK_EQUAL(linear_expression.coefPerVar()["var"], -7.); +} + +BOOST_FIXTURE_TEST_CASE(visit_complex_expression, Registry) +{ + // 2 * (13 + 3 * param1(-2) + 14 * var1) / 7 + param2(8) + 6 * var2 = {10 ; {var1:4, var2:6}} + + // small_sum = 13 + 3 * param1(-2) + 14 * var1 + Node* small_sum = create(create(13.), + create(create(3), + create("param1")), + create(create(14), + create("var1"))); + + // big_sum = 2 * small_sum / 7 + param2(8) + 6 * var2 + Node* big_sum = create( + create(create(create(2.), small_sum), + create(7.)), // 2 * small_sum / 7 + create("param2"), // param2 + create(create(6.), create("var2")) // 6 * var2 + ); + + EvaluationContext evaluation_context({{"param1", -2.}, {"param2", 8.}}, {}); + ReadLinearExpressionVisitor visitor(evaluation_context); + auto linear_expression = visitor.dispatch(big_sum); + BOOST_CHECK_EQUAL(linear_expression.offset(), 10.); + BOOST_CHECK_EQUAL(linear_expression.coefPerVar().size(), 2); + BOOST_CHECK_EQUAL(linear_expression.coefPerVar()["var1"], 4.); + BOOST_CHECK_EQUAL(linear_expression.coefPerVar()["var2"], 6.); +} + +BOOST_FIXTURE_TEST_CASE(comparison_nodes__exception_thrown, Registry) +{ + Node* literal = create(5.); + ReadLinearExpressionVisitor visitor; + auto predicate = checkMessage("A linear expression can't contain comparison operators."); + + Node* node = create(literal, literal); + BOOST_CHECK_EXCEPTION(visitor.dispatch(node), std::invalid_argument, predicate); + + node = create(literal, literal); + BOOST_CHECK_EXCEPTION(visitor.dispatch(node), std::invalid_argument, predicate); + + node = create(literal, literal); + BOOST_CHECK_EXCEPTION(visitor.dispatch(node), std::invalid_argument, predicate); +} + +BOOST_FIXTURE_TEST_CASE(not_implemented_nodes__exception_thrown, Registry) +{ + ReadLinearExpressionVisitor visitor; + + Node* node = create("port", "field"); + BOOST_CHECK_EXCEPTION(visitor.dispatch(node), + std::invalid_argument, + checkMessage("ReadLinearExpressionVisitor cannot visit PortFieldNodes")); + + node = create("port", "field"); + BOOST_CHECK_EXCEPTION(visitor.dispatch(node), + std::invalid_argument, + checkMessage( + "ReadLinearExpressionVisitor cannot visit PortFieldSumNodes")); + + node = create("id", "y"); + BOOST_CHECK_EXCEPTION(visitor.dispatch(node), + std::invalid_argument, + checkMessage( + "ReadLinearExpressionVisitor cannot visit ComponentVariableNodes")); + + node = create("id", "y"); + BOOST_CHECK_EXCEPTION(visitor.dispatch(node), + std::invalid_argument, + checkMessage( + "ReadLinearExpressionVisitor cannot visit ComponentParameterNodes")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/study/system-model/CMakeLists.txt b/src/tests/src/study/system-model/CMakeLists.txt index 0f5f956ac8..727635be3e 100644 --- a/src/tests/src/study/system-model/CMakeLists.txt +++ b/src/tests/src/study/system-model/CMakeLists.txt @@ -12,7 +12,7 @@ target_link_libraries(${EXECUTABLE_NAME} PRIVATE Boost::unit_test_framework antares-study-system-model - test_utils_unit + test_utils_unit ) set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) diff --git a/src/tests/src/study/system-model/test_component.cpp b/src/tests/src/study/system-model/test_component.cpp index e8c69007a9..3f52b33880 100644 --- a/src/tests/src/study/system-model/test_component.cpp +++ b/src/tests/src/study/system-model/test_component.cpp @@ -21,12 +21,12 @@ #define WIN32_LEAN_AND_MEAN +#include + #include #include "antares/study/system-model/component.h" -#include "../../utils/unit_test_utils.h" - using namespace Antares::Study::SystemModel; struct ComponentBuilderCreationFixture @@ -98,6 +98,33 @@ BOOST_AUTO_TEST_CASE(nominal_build_without_parameters2) BOOST_CHECK_EQUAL(component.getScenarioGroupId(), "scenario_group3"); } +BOOST_AUTO_TEST_CASE(reuse_builder) +{ + Model model1 = createModelWithoutParameters(); + auto component1 = component_builder.withId("component1") + .withModel(&model1) + .withScenarioGroupId("scenario_group1") + .build(); + Model model2 = createModelWithParameters(); + auto component2 = component_builder.withId("component2") + .withModel(&model2) + .withParameterValues({{"param1", 5}, {"param2", 3}}) + .withScenarioGroupId("scenario_group2") + .build(); + + BOOST_CHECK_EQUAL(component1.Id(), "component1"); + BOOST_CHECK_EQUAL(component1.getModel(), &model1); + BOOST_CHECK_EQUAL(component1.getScenarioGroupId(), "scenario_group1"); + BOOST_CHECK(component1.getParameterValues().empty()); + + BOOST_CHECK_EQUAL(component2.Id(), "component2"); + BOOST_CHECK_EQUAL(component2.getModel(), &model2); + BOOST_CHECK_EQUAL(component2.getScenarioGroupId(), "scenario_group2"); + BOOST_CHECK_EQUAL(component2.getParameterValues().size(), 2); + BOOST_CHECK_EQUAL(component2.getParameterValues().at("param1"), 5); + BOOST_CHECK_EQUAL(component2.getParameterValues().at("param2"), 3); +} + BOOST_AUTO_TEST_CASE(fail_on_no_id) { Model model = createModelWithoutParameters(); diff --git a/src/tests/src/study/system-model/test_system.cpp b/src/tests/src/study/system-model/test_system.cpp index 9500b6118b..550ca59693 100644 --- a/src/tests/src/study/system-model/test_system.cpp +++ b/src/tests/src/study/system-model/test_system.cpp @@ -21,12 +21,12 @@ #define WIN32_LEAN_AND_MEAN +#include + #include #include "antares/study/system-model/system.h" -#include "../../utils/unit_test_utils.h" - using namespace Antares::Study::SystemModel; struct SystemBuilderCreationFixture From 7a793305d87581f74391b4784433fe5fc4235569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Fri, 6 Dec 2024 16:12:03 +0100 Subject: [PATCH 079/103] Fix build for CentOS7/OL8 (#2528) --- .../solver/optim-model-filler/ReadLinearConstraintVisitor.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearConstraintVisitor.h b/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearConstraintVisitor.h index dfddc5db2f..2951f7d1bf 100644 --- a/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearConstraintVisitor.h +++ b/src/solver/optim-model-filler/include/antares/solver/optim-model-filler/ReadLinearConstraintVisitor.h @@ -21,6 +21,8 @@ #pragma once +#include + #include #include From 001e6d534e802167dd71398dbfc94ae92059ccd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Tue, 10 Dec 2024 13:34:21 +0100 Subject: [PATCH 080/103] Add interface for Thermal costs, fix wrong values in GUI (#2526) # Advantages - Better separation of responsabilities, remove a lot of `if..else` - Make sure that if costgeneration = setManually (legacy behavior), no new code is executed # Cons - The caller needs to call function `ThermalCluster::getCostProvider` first # GUI Previously, the formula used for modulation columns was "netCost = modulation * modulation * originalCost" for market bid & marginal costs. We fix this formula to "netCost = modulation * originalCost" --- src/libs/antares/study/CMakeLists.txt | 3 + .../antares/study/parts/thermal/cluster.h | 42 ++--- .../study/parts/thermal/cost_provider.h | 82 +++++++++ .../antares/study/parts/thermal/defines.h | 7 +- .../antares/study/parts/thermal/cluster.cpp | 163 ++---------------- .../study/parts/thermal/cluster_list.cpp | 1 - .../parts/thermal/constant_cost_provider.cpp | 47 +++++ .../thermal/scenarized_cost_provider.cpp | 131 ++++++++++++++ src/solver/simulation/common-eco-adq.cpp | 2 +- .../solver/variable/economy/profitByPlant.h | 2 +- src/solver/variable/state.cpp | 5 +- .../thermal-price-definition.cpp | 40 ++--- .../renderer/area/thermalmodulation.cpp | 17 +- .../windows/inspector/property.update.cpp | 5 - 14 files changed, 322 insertions(+), 225 deletions(-) create mode 100644 src/libs/antares/study/include/antares/study/parts/thermal/cost_provider.h create mode 100644 src/libs/antares/study/parts/thermal/constant_cost_provider.cpp create mode 100644 src/libs/antares/study/parts/thermal/scenarized_cost_provider.cpp diff --git a/src/libs/antares/study/CMakeLists.txt b/src/libs/antares/study/CMakeLists.txt index a354de3058..29a89fc631 100644 --- a/src/libs/antares/study/CMakeLists.txt +++ b/src/libs/antares/study/CMakeLists.txt @@ -71,8 +71,11 @@ set(SRC_STUDY_PART_THERMAL include/antares/study/parts/thermal/ecoInput.h parts/thermal/ecoInput.cpp include/antares/study/parts/thermal/cluster.h + 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 include/antares/study/parts/thermal/cluster_list.h parts/thermal/cluster_list.cpp include/antares/study/parts/thermal/pollutant.h diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h b/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h index 09ada6b8c1..6b6523673c 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h @@ -34,6 +34,7 @@ #include "../../fwd.h" #include "../common/cluster.h" +#include "cost_provider.h" #include "defines.h" #include "ecoInput.h" #include "pollutant.h" @@ -64,6 +65,12 @@ enum class LocalTSGenerationBehavior forceNoGen }; +double computeMarketBidCost(double fuelCost, + double fuelEfficiency, + double co2EmissionFactor, + double co2cost, + double variableomcost); + /*! ** \brief A single thermal cluster */ @@ -147,13 +154,6 @@ class ThermalCluster final: public Cluster, public std::enable_shared_from_this< */ void calculationOfSpinning(); - //! \name MarketBid and Marginal Costs - //@{ - /*! - ** \brief Calculation of market bid and marginals costs per hour - */ - void ComputeCostTimeSeries(); - /*! ** \brief Calculation of spinning (reverse) ** @@ -207,10 +207,6 @@ class ThermalCluster final: public Cluster, public std::enable_shared_from_this< bool doWeGenerateTS(bool globalTSgeneration) const; - double getOperatingCost(uint tsIndex, uint hourInTheYear) const; - double getMarginalCost(uint tsIndex, uint hourInTheYear) const; - double getMarketBidCost(uint hourInTheYear, uint year) const; - // Check & correct availability timeseries for thermal availability // Only applies if time-series are ready-made void checkAndCorrectAvailability(); @@ -349,29 +345,16 @@ class ThermalCluster final: public Cluster, public std::enable_shared_from_this< //! Data for the preprocessor std::unique_ptr prepro; - /*! - ** \brief Production Cost, Market Bid Cost and Marginal Cost Matrixes - Per Hour and per Time - *Series - */ - struct CostsTimeSeries - { - std::array productionCostTs; - std::array marketBidCostTS; - std::array marginalCostTS; - }; - - std::vector costsTimeSeries; - EconomicInputData ecoInput; LocalTSGenerationBehavior tsGenBehavior = LocalTSGenerationBehavior::useGlobalParameter; friend class ThermalClusterList; - double computeMarketBidCost(double fuelCost, double co2EmissionFactor, double co2cost); - unsigned int precision() const override; + CostProvider& getCostProvider(); + private: // Calculation of marketBid and marginal costs hourly time series // @@ -383,12 +366,7 @@ class ThermalCluster final: public Cluster, public std::enable_shared_from_this< // Marginal_Cost[€/MWh] = Market_Bid_Cost[€/MWh] = (Fuel_Cost[€/GJ] * 3.6 * 100 / Efficiency[%]) // CO2_emission_factor[tons/MWh] * C02_cost[€/tons] + Variable_O&M_cost[€/MWh] - void fillMarketBidCostTS(); - void fillMarginalCostTS(); - void resizeCostTS(); - void ComputeMarketBidTS(); - void MarginalCostEqualsMarketBid(); - void ComputeProductionCostTS(); + std::unique_ptr costProvider; }; // class ThermalCluster } // namespace Data diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/cost_provider.h b/src/libs/antares/study/include/antares/study/parts/thermal/cost_provider.h new file mode 100644 index 0000000000..2a3b1b1d54 --- /dev/null +++ b/src/libs/antares/study/include/antares/study/parts/thermal/cost_provider.h @@ -0,0 +1,82 @@ +/* + * 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 +{ +class CostProvider +{ +public: + virtual ~CostProvider() = default; + virtual double getOperatingCost(uint serieIndex, uint hourInTheYear) const = 0; + virtual double getMarginalCost(uint serieIndex, uint hourInTheYear) const = 0; + virtual double getMarketBidCost(uint hourInTheYear, uint year) const = 0; +}; + +class ThermalCluster; + +class ConstantCostProvider: public CostProvider +{ +public: + explicit ConstantCostProvider(const ThermalCluster& cluster); + virtual ~ConstantCostProvider() = default; + double getOperatingCost(uint serieIndex, uint hourInTheYear) const override; + double getMarginalCost(uint serieIndex, uint hourInTheYear) const override; + double getMarketBidCost(uint hourInTheYear, uint year) const override; + +private: + const ThermalCluster& cluster; +}; + +class ScenarizedCostProvider: public CostProvider +{ +public: + explicit ScenarizedCostProvider(const ThermalCluster& cluster); + virtual ~ScenarizedCostProvider() = default; + double getOperatingCost(uint serieIndex, uint hourInTheYear) const override; + double getMarginalCost(uint serieIndex, uint hourInTheYear) const override; + double getMarketBidCost(uint hourInTheYear, uint year) const override; + +private: + /*! + ** \brief Production Cost, Market Bid Cost and Marginal Cost Matrixes - Per Hour and per Time + *Series + */ + struct CostsTimeSeries + { + std::array productionCostTs; + std::array marketBidCostTS; + std::array marginalCostTS; + }; + + void resizeCostTS(); + void ComputeMarketBidTS(); + void MarginalCostEqualsMarketBid(); + void ComputeProductionCostTS(); + + std::vector costsTimeSeries; + const ThermalCluster& cluster; +}; +} // namespace Antares::Data diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/defines.h b/src/libs/antares/study/include/antares/study/parts/thermal/defines.h index 5d74c795ff..52d7cd9798 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/defines.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/defines.h @@ -21,16 +21,13 @@ #ifndef __ANTARES_LIBS_STUDY_PARTS_THERMAL_DEFINES_H__ #define __ANTARES_LIBS_STUDY_PARTS_THERMAL_DEFINES_H__ -namespace Antares -{ -namespace Data +namespace Antares::Data { // Forward declaration class ThermalCluster; class ThermalClusterList; class PreproAvailability; -} // namespace Data -} // namespace Antares +} // namespace Antares::Data #endif // __ANTARES_LIBS_STUDY_PARTS_THERMAL_DEFINES_H__ diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index eaab3cada8..96b2d87826 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -120,8 +120,7 @@ namespace Data { Data::ThermalCluster::ThermalCluster(Area* parent): Cluster(parent), - PthetaInf(HOURS_PER_YEAR, 0), - costsTimeSeries(1, CostsTimeSeries()) + PthetaInf(HOURS_PER_YEAR, 0) { // assert assert(parent && "A parent for a thermal dispatchable cluster can not be null"); @@ -184,8 +183,6 @@ void Data::ThermalCluster::copyFrom(const ThermalCluster& cluster) fixedCost = cluster.fixedCost; startupCost = cluster.startupCost; marketBidCost = cluster.marketBidCost; - // assignment “=” operator can be used to copy-paste vector by value - costsTimeSeries = cluster.costsTimeSeries; // modulation modulation = cluster.modulation; @@ -299,106 +296,6 @@ void Data::ThermalCluster::calculationOfSpinning() } } -void Data::ThermalCluster::ComputeCostTimeSeries() -{ - switch (costgeneration) - { - case Data::setManually: - fillMarketBidCostTS(); - fillMarginalCostTS(); - break; - case Data::useCostTimeseries: - resizeCostTS(); - ComputeMarketBidTS(); - MarginalCostEqualsMarketBid(); - ComputeProductionCostTS(); - break; - } -} - -void Data::ThermalCluster::fillMarketBidCostTS() -{ - std::fill(costsTimeSeries[0].marketBidCostTS.begin(), - costsTimeSeries[0].marketBidCostTS.end(), - marketBidCost); -} - -void Data::ThermalCluster::fillMarginalCostTS() -{ - std::fill(costsTimeSeries[0].marginalCostTS.begin(), - costsTimeSeries[0].marginalCostTS.end(), - marginalCost); -} - -void ThermalCluster::resizeCostTS() -{ - const uint fuelCostWidth = ecoInput.fuelcost.width; - const uint co2CostWidth = ecoInput.co2cost.width; - const uint tsCount = std::max(fuelCostWidth, co2CostWidth); - - costsTimeSeries.resize(tsCount, CostsTimeSeries()); -} - -void ThermalCluster::ComputeMarketBidTS() -{ - const uint fuelCostWidth = ecoInput.fuelcost.width; - const uint co2CostWidth = ecoInput.co2cost.width; - - double& co2EmissionFactor = emissions.factors[Pollutant::CO2]; - - for (uint tsIndex = 0; tsIndex < costsTimeSeries.size(); ++tsIndex) - { - uint tsIndexFuel = std::min(fuelCostWidth - 1, tsIndex); - uint tsIndexCo2 = std::min(co2CostWidth - 1, tsIndex); - for (uint hour = 0; hour < HOURS_PER_YEAR; ++hour) - { - double& marketBidCostTS = costsTimeSeries[tsIndex].marketBidCostTS[hour]; - - double& fuelcost = ecoInput.fuelcost[tsIndexFuel][hour]; - double& co2cost = ecoInput.co2cost[tsIndexCo2][hour]; - - marketBidCostTS = computeMarketBidCost(fuelcost, co2EmissionFactor, co2cost); - } - } -} - -void ThermalCluster::MarginalCostEqualsMarketBid() -{ - for (auto& timeSeries: costsTimeSeries) - { - auto& source = timeSeries.marketBidCostTS; - auto& destination = timeSeries.marginalCostTS; - std::copy(source.begin(), source.end(), destination.begin()); - } -} - -void ThermalCluster::ComputeProductionCostTS() -{ - if (modulation.width == 0) - { - return; - } - - for (auto& timeSeries: costsTimeSeries) - { - auto& productionCostTS = timeSeries.productionCostTs; - auto& marginalCostTS = timeSeries.marginalCostTS; - - for (uint hour = 0; hour < HOURS_PER_YEAR; ++hour) - { - double hourlyModulation = modulation[Data::thermalModulationCost][hour]; - productionCostTS[hour] = marginalCostTS[hour] * hourlyModulation; - } - } -} - -double Data::ThermalCluster::computeMarketBidCost(double fuelCost, - double co2EmissionFactor, - double co2cost) -{ - return fuelCost * 360.0 / fuelEfficiency + co2EmissionFactor * co2cost + variableomcost; -} - void Data::ThermalCluster::reverseCalculationOfSpinning() { // Nothing to do if the spinning is equal to zero @@ -464,7 +361,6 @@ void Data::ThermalCluster::reset() startupCost = 0.; marketBidCost = 0.; variableomcost = 0.; - costsTimeSeries.resize(1, CostsTimeSeries()); // modulation modulation.resize(thermalModulationMax, HOURS_PER_YEAR); @@ -714,52 +610,23 @@ unsigned int ThermalCluster::precision() const return 0; } -double ThermalCluster::getOperatingCost(uint serieIndex, uint hourInTheYear) const -{ - if (costgeneration == Data::setManually) - { - const auto* modCost = modulation[thermalModulationCost]; - return marginalCost * modCost[hourInTheYear]; - } - else - { - const uint tsIndex = std::min(serieIndex, (uint)costsTimeSeries.size() - 1); - return costsTimeSeries[tsIndex].productionCostTs[hourInTheYear]; - } -} - -double ThermalCluster::getMarginalCost(uint serieIndex, uint hourInTheYear) const +CostProvider& ThermalCluster::getCostProvider() { - const double mod = modulation[Data::thermalModulationCost][hourInTheYear]; - - if (costgeneration == Data::setManually) + if (!costProvider) { - return marginalCost * mod; - } - else - { - const uint tsIndex = std::min(serieIndex, (uint)costsTimeSeries.size() - 1); - return costsTimeSeries[tsIndex].marginalCostTS[hourInTheYear] * mod; - } - /* std::min is necessary in case Availability has e.g 10 TS and both FuelCost & Co2Cost have - only 1TS. Then - > In order to save memory marginalCostTS vector has only one array - inside -> that is used for all (e.g.10) TS*/ -} - -double ThermalCluster::getMarketBidCost(uint hourInTheYear, uint year) const -{ - const double mod = modulation[thermalModulationMarketBid][hourInTheYear]; - - if (costgeneration == Data::setManually) - { - return marketBidCost * mod; - } - else - { - const uint serieIndex = series.getSeriesIndex(year); - const uint tsIndex = std::min(serieIndex, (uint)costsTimeSeries.size() - 1); - return costsTimeSeries[tsIndex].marketBidCostTS[hourInTheYear] * mod; + switch (costgeneration) + { + case Data::setManually: + costProvider = std::make_unique(*this); + break; + case Data::useCostTimeseries: + costProvider = std::make_unique(*this); + break; + default: + throw std::runtime_error("Invalid costgeneration parameter"); + } } + return *costProvider; } void ThermalCluster::checkAndCorrectAvailability() diff --git a/src/libs/antares/study/parts/thermal/cluster_list.cpp b/src/libs/antares/study/parts/thermal/cluster_list.cpp index 99d7fc21ac..e9d7e785e9 100644 --- a/src/libs/antares/study/parts/thermal/cluster_list.cpp +++ b/src/libs/antares/study/parts/thermal/cluster_list.cpp @@ -622,7 +622,6 @@ bool ThermalClusterList::loadEconomicCosts(Study& study, const fs::path& folder) auto filePath = folder / c->parentArea->id.c_str() / c->id(); bool result = c->ecoInput.loadFromFolder(study, filePath); - c->ComputeCostTimeSeries(); return result; }); } diff --git a/src/libs/antares/study/parts/thermal/constant_cost_provider.cpp b/src/libs/antares/study/parts/thermal/constant_cost_provider.cpp new file mode 100644 index 0000000000..0f7133f19d --- /dev/null +++ b/src/libs/antares/study/parts/thermal/constant_cost_provider.cpp @@ -0,0 +1,47 @@ +/* + * 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/thermal/cluster.h" + +namespace Antares::Data +{ +ConstantCostProvider::ConstantCostProvider(const ThermalCluster& cluster): + cluster(cluster) +{ +} + +double ConstantCostProvider::getOperatingCost(uint serieIndex, uint hourInTheYear) const +{ + const auto* modCost = cluster.modulation[thermalModulationCost]; + return cluster.marginalCost * modCost[hourInTheYear]; +} + +double ConstantCostProvider::getMarginalCost(uint serieIndex, uint hourInTheYear) const +{ + const double mod = cluster.modulation[Data::thermalModulationCost][hourInTheYear]; + return cluster.marginalCost * mod; +} + +double ConstantCostProvider::getMarketBidCost(uint hourInTheYear, uint year) const +{ + const double mod = cluster.modulation[thermalModulationMarketBid][hourInTheYear]; + return cluster.marketBidCost * mod; +} +} // namespace Antares::Data diff --git a/src/libs/antares/study/parts/thermal/scenarized_cost_provider.cpp b/src/libs/antares/study/parts/thermal/scenarized_cost_provider.cpp new file mode 100644 index 0000000000..7a3232db40 --- /dev/null +++ b/src/libs/antares/study/parts/thermal/scenarized_cost_provider.cpp @@ -0,0 +1,131 @@ +/* + * 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/thermal/cluster.h" + +namespace Antares::Data +{ + +ScenarizedCostProvider::ScenarizedCostProvider(const ThermalCluster& cluster): + cluster(cluster) +{ + resizeCostTS(); + ComputeMarketBidTS(); + MarginalCostEqualsMarketBid(); + ComputeProductionCostTS(); +} + +void ScenarizedCostProvider::ComputeProductionCostTS() +{ + if (cluster.modulation.width == 0) + { + return; + } + + for (auto& timeSeries: costsTimeSeries) + { + auto& productionCostTS = timeSeries.productionCostTs; + auto& marginalCostTS = timeSeries.marginalCostTS; + + for (uint hour = 0; hour < HOURS_PER_YEAR; ++hour) + { + double hourlyModulation = cluster.modulation[Data::thermalModulationCost][hour]; + productionCostTS[hour] = marginalCostTS[hour] * hourlyModulation; + } + } +} + +void ScenarizedCostProvider::resizeCostTS() +{ + const uint fuelCostWidth = cluster.ecoInput.fuelcost.width; + const uint co2CostWidth = cluster.ecoInput.co2cost.width; + const uint tsCount = std::max(fuelCostWidth, co2CostWidth); + + costsTimeSeries.resize(tsCount, CostsTimeSeries()); +} + +void ScenarizedCostProvider::MarginalCostEqualsMarketBid() +{ + for (auto& timeSeries: costsTimeSeries) + { + auto& source = timeSeries.marketBidCostTS; + auto& destination = timeSeries.marginalCostTS; + std::copy(source.begin(), source.end(), destination.begin()); + } +} + +double computeMarketBidCost(double fuelCost, + double fuelEfficiency, + double co2EmissionFactor, + double co2cost, + double variableomcost) +{ + return fuelCost * 360.0 / fuelEfficiency + co2EmissionFactor * co2cost + variableomcost; +} + +void ScenarizedCostProvider::ComputeMarketBidTS() +{ + const uint fuelCostWidth = cluster.ecoInput.fuelcost.width; + const uint co2CostWidth = cluster.ecoInput.co2cost.width; + + double co2EmissionFactor = cluster.emissions.factors[Pollutant::CO2]; + + for (uint tsIndex = 0; tsIndex < costsTimeSeries.size(); ++tsIndex) + { + uint tsIndexFuel = std::min(fuelCostWidth - 1, tsIndex); + uint tsIndexCo2 = std::min(co2CostWidth - 1, tsIndex); + for (uint hour = 0; hour < HOURS_PER_YEAR; ++hour) + { + double fuelcost = cluster.ecoInput.fuelcost[tsIndexFuel][hour]; + double co2cost = cluster.ecoInput.co2cost[tsIndexCo2][hour]; + + costsTimeSeries[tsIndex].marketBidCostTS[hour] = computeMarketBidCost( + fuelcost, + cluster.fuelEfficiency, + co2EmissionFactor, + co2cost, + cluster.variableomcost); + } + } +} + +double ScenarizedCostProvider::getOperatingCost(uint serieIndex, uint hourInTheYear) const +{ + const uint tsIndex = std::min(serieIndex, static_cast(costsTimeSeries.size()) - 1); + return costsTimeSeries[tsIndex].productionCostTs[hourInTheYear]; +} + +double ScenarizedCostProvider::getMarginalCost(uint serieIndex, uint hourInTheYear) const +{ + const double mod = cluster.modulation[thermalModulationMarketBid][hourInTheYear]; + const uint tsIndex = std::min(serieIndex, static_cast(costsTimeSeries.size()) - 1); + return costsTimeSeries[tsIndex].marginalCostTS[hourInTheYear] * mod; +} + +double ScenarizedCostProvider::getMarketBidCost(uint hourInTheYear, uint year) const +{ + const double mod = cluster.modulation[thermalModulationMarketBid][hourInTheYear]; + const uint serieIndex = cluster.series.getSeriesIndex(year); + const uint tsIndex = std::min(serieIndex, static_cast(costsTimeSeries.size()) - 1); + return costsTimeSeries[tsIndex].marketBidCostTS[hourInTheYear] * mod; +} + +} // namespace Antares::Data diff --git a/src/solver/simulation/common-eco-adq.cpp b/src/solver/simulation/common-eco-adq.cpp index 5b46e35cce..59eb02e9b4 100644 --- a/src/solver/simulation/common-eco-adq.cpp +++ b/src/solver/simulation/common-eco-adq.cpp @@ -378,7 +378,7 @@ void BuildThermalPartOfWeeklyProblem(Data::Study& study, .PuissanceDisponibleEtCout[cluster->index]; Pt.CoutHoraireDeProductionDuPalierThermique[hourInWeek] - = cluster->getMarketBidCost(hourInYear, year) + = cluster->getCostProvider().getMarketBidCost(hourInYear, year) + thermalNoises[areaIdx][cluster->areaWideIndex]; Pt.PuissanceDisponibleDuPalierThermique[hourInWeek] = cluster->series diff --git a/src/solver/variable/include/antares/solver/variable/economy/profitByPlant.h b/src/solver/variable/include/antares/solver/variable/economy/profitByPlant.h index 2dd9378067..20e1d6e228 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/profitByPlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/profitByPlant.h @@ -288,7 +288,7 @@ class ProfitByPlant: public Variable::IVariable, NextT, VCa pValuesForTheCurrentYear[numSpace][cluster->areaWideIndex].hour[hourInTheYear] = std::max((hourlyClusterProduction - cluster->PthetaInf[hourInTheYear]), 0.) * (-areaMarginalCosts[hourInTheWeek] - - cluster->getMarginalCost(tsIndex, hourInTheYear)); + - cluster->getCostProvider().getMarginalCost(tsIndex, hourInTheYear)); } // Next variable diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index 6657a5a23b..0e9f0eca8e 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -199,7 +199,7 @@ void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideInde // calculating the operating cost for the current hour // O(h) = MA * P(h) * Modulation thermal[area->index].thermalClustersOperatingCost[clusterAreaWideIndex] - = (p * thermalCluster->getOperatingCost(serieIndex, hourInTheYear)); + = (p * thermalCluster->getCostProvider().getOperatingCost(serieIndex, hourInTheYear)); // Startup cost if (newUnitCount > previousUnitCount && hourInTheSimulation != 0u) @@ -297,7 +297,8 @@ void State::yearEndBuildFromThermalClusterIndex(const uint clusterAreaWideIndex) uint serieIndex = currentCluster->series.timeseriesNumbers[this->year]; thermalClusterOperatingCostForYear[h] = thermalClusterProduction - * currentCluster->getOperatingCost(serieIndex, h); + * currentCluster->getCostProvider() + .getOperatingCost(serieIndex, h); switch (unitCommitmentMode) { diff --git a/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp b/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp index 3aad7c0cec..b8eeb41d51 100644 --- a/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp +++ b/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp @@ -101,13 +101,6 @@ struct TimeSeriesFile const std::string name_; }; -void fillThermalEconomicTimeSeries(ThermalCluster* c) -{ - c->costsTimeSeries[0].productionCostTs.fill(1); - c->costsTimeSeries[0].marketBidCostTS.fill(1); - c->costsTimeSeries[0].marginalCostTS.fill(1); -} - // ================= // The fixture // ================= @@ -231,11 +224,14 @@ BOOST_FIXTURE_TEST_CASE(ThermalCluster_costGenManualCalculationOfMarketBidAndMar clusterList.loadFromFolder(*study, folder, area); auto cluster = clusterList.findInAll("some cluster"); + cluster->modulation.resize(thermalModulationMax, HOURS_PER_YEAR); + cluster->modulation.fill(1.); + cluster->costgeneration = Data::setManually; - cluster->ComputeCostTimeSeries(); - BOOST_CHECK_EQUAL(cluster->costsTimeSeries[0].marketBidCostTS[2637], 35); - BOOST_CHECK_EQUAL(cluster->costsTimeSeries[0].marginalCostTS[6737], 23); + auto& cp = cluster->getCostProvider(); + BOOST_CHECK_EQUAL(cp.getMarketBidCost(2637, 0), 35); + BOOST_CHECK_EQUAL(cp.getMarginalCost(6737, 0), 23); } BOOST_FIXTURE_TEST_CASE( @@ -248,22 +244,26 @@ BOOST_FIXTURE_TEST_CASE( clusterList.loadFromFolder(*study, folder, area); auto cluster = clusterList.findInAll("some cluster"); - cluster->modulation.reset(1, 8760); + cluster->modulation.resize(thermalModulationMax, HOURS_PER_YEAR); + cluster->modulation.fill(1.); + cluster->ecoInput.loadFromFolder(*study, folder); - fillThermalEconomicTimeSeries(cluster); - cluster->ComputeCostTimeSeries(); + cluster->tsNumbers.reset(1); - BOOST_CHECK_CLOSE(cluster->costsTimeSeries[0].marketBidCostTS[0], 24.12, 0.001); - BOOST_CHECK_CLOSE(cluster->costsTimeSeries[0].marketBidCostTS[2637], 24.12, 0.001); + auto& cp = cluster->getCostProvider(); + BOOST_CHECK_CLOSE(cp.getMarginalCost(0, 0), 24.12, 0.001); + BOOST_CHECK_CLOSE(cp.getMarketBidCost(2637, 0), 24.12, 0.001); } -BOOST_FIXTURE_TEST_CASE(computeMarketBidCost, FixtureFull) +BOOST_FIXTURE_TEST_CASE(computeMarketBidCost_useTimeSeries, FixtureFull) { clusterList.loadFromFolder(*study, folder, area); auto cluster = clusterList.findInAll("some cluster"); - - BOOST_CHECK_CLOSE(cluster->computeMarketBidCost(1, 2, 1), 24.12, 0.001); + BOOST_CHECK_CLOSE( + computeMarketBidCost(1, cluster->fuelEfficiency, 2, 1, cluster->variableomcost), + 24.12, + 0.001); } BOOST_AUTO_TEST_CASE(non_constant_marketbid_modulation) @@ -279,12 +279,12 @@ BOOST_AUTO_TEST_CASE(non_constant_marketbid_modulation) { mod[thermalModulationMarketBid][0] = .5; - BOOST_CHECK_EQUAL(cluster.getMarketBidCost(0, 0), .5 * 120); + BOOST_CHECK_EQUAL(cluster.getCostProvider().getMarketBidCost(0, 0), .5 * 120); } { mod[thermalModulationMarketBid][1] = .8; - BOOST_CHECK_EQUAL(cluster.getMarketBidCost(1, 0), .8 * 120); + BOOST_CHECK_EQUAL(cluster.getCostProvider().getMarketBidCost(1, 0), .8 * 120); } } diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/area/thermalmodulation.cpp b/src/ui/simulator/toolbox/components/datagrid/renderer/area/thermalmodulation.cpp index bf72ed3dc0..a53872ee64 100644 --- a/src/ui/simulator/toolbox/components/datagrid/renderer/area/thermalmodulation.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/area/thermalmodulation.cpp @@ -95,17 +95,16 @@ wxString ThermalClusterCommonModulation::cellValue(int x, int y) const return DoubleToWxString(Math::Round((*pMatrix)[Data::thermalMinGenModulation][y], 3)); case (Data::thermalModulationCost + Data::thermalModulationMax): return DoubleToWxString( - Math::Round((*pMatrix)[Data::thermalModulationCost][y] - * pCluster->costsTimeSeries[0].marginalCostTS[y], + Math::Round(pCluster->getCostProvider().getMarginalCost(0, y), 3)); case (Data::thermalModulationMarketBid + Data::thermalModulationMax): return DoubleToWxString( - Math::Round((*pMatrix)[Data::thermalModulationMarketBid][y] - * pCluster->costsTimeSeries[0].marketBidCostTS[y], + Math::Round(pCluster->getCostProvider().getMarketBidCost(y, 0), 3)); case (Data::thermalModulationCapacity + Data::thermalModulationMax): - return DoubleToWxString(Math::Round( - (*pMatrix)[Data::thermalModulationCapacity][y] * pCluster->nominalCapacity, 2)); + return DoubleToWxString(Math::Round((*pMatrix)[Data::thermalModulationCapacity][y] + * pCluster->nominalCapacity, + 2)); case (Data::thermalMinGenModulation + Data::thermalModulationMax): return DoubleToWxString(Math::Round((*pMatrix)[Data::thermalMinGenModulation][y] * pCluster->unitCount * pCluster->nominalCapacity, @@ -131,11 +130,9 @@ double ThermalClusterCommonModulation::cellNumericValue(int x, int y) const case Data::thermalMinGenModulation: return (*pMatrix)[Data::thermalMinGenModulation][y]; case (Data::thermalModulationCost + Data::thermalModulationMax): - return (*pMatrix)[Data::thermalModulationCost][y] - * pCluster->costsTimeSeries[0].marginalCostTS[y]; + return pCluster->getCostProvider().getMarginalCost(0, y); case (Data::thermalModulationMarketBid + Data::thermalModulationMax): - return (*pMatrix)[Data::thermalModulationMarketBid][y] - * pCluster->costsTimeSeries[0].marketBidCostTS[y]; + return pCluster->getCostProvider().getMarketBidCost(y, 0); case (Data::thermalModulationCapacity + Data::thermalModulationMax): return (*pMatrix)[Data::thermalModulationCapacity][y] * pCluster->nominalCapacity; case (Data::thermalMinGenModulation + Data::thermalModulationMax): diff --git a/src/ui/simulator/windows/inspector/property.update.cpp b/src/ui/simulator/windows/inspector/property.update.cpp index 1c1879dfae..dc0e7eef1e 100644 --- a/src/ui/simulator/windows/inspector/property.update.cpp +++ b/src/ui/simulator/windows/inspector/property.update.cpp @@ -724,7 +724,6 @@ bool InspectorGrid::onPropertyChanging_ThermalCluster(wxPGProperty*, for (; i != end; ++i) { (*i)->fuelEfficiency = d; - (*i)->ComputeCostTimeSeries(); } // update } OnStudyThermalClusterCommonSettingsChanged(); @@ -750,7 +749,6 @@ bool InspectorGrid::onPropertyChanging_ThermalCluster(wxPGProperty*, for (; i != end; ++i) { (*i)->costgeneration = costgeneration; - (*i)->ComputeCostTimeSeries(); // update } AccumulatorCheck::ApplyGreyColor( pFrame.pPGThClusterMarginalCost, @@ -796,7 +794,6 @@ bool InspectorGrid::onPropertyChanging_ThermalCluster(wxPGProperty*, for (; i != end; ++i) { (*i)->marginalCost = d; - (*i)->ComputeCostTimeSeries(); // update } pFrame.delayApply(); @@ -879,7 +876,6 @@ bool InspectorGrid::onPropertyChanging_ThermalCluster(wxPGProperty*, for (; i != end; ++i) { (*i)->marketBidCost = d; - (*i)->ComputeCostTimeSeries(); } pFrame.delayApply(); @@ -922,7 +918,6 @@ bool InspectorGrid::onPropertyChanging_ThermalCluster(wxPGProperty*, for (; i != end; ++i) { (*i)->variableomcost = d; - (*i)->ComputeCostTimeSeries(); // update } } OnStudyThermalClusterCommonSettingsChanged(); From 61bb933924754070d4a2e0da9bb17ee8ff8dfab8 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:20:13 +0100 Subject: [PATCH 081/103] Add a warning if sts group property is empty [ANT-2026] (#2534) --- .../antares/study/parts/short-term-storage/properties.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/antares/study/parts/short-term-storage/properties.cpp b/src/libs/antares/study/parts/short-term-storage/properties.cpp index 3805b239a2..cbed02122e 100644 --- a/src/libs/antares/study/parts/short-term-storage/properties.cpp +++ b/src/libs/antares/study/parts/short-term-storage/properties.cpp @@ -213,6 +213,12 @@ bool Properties::validate() << " should be inferior to 1, value has been set to " << initialLevel; } + if (groupName.empty()) + { + logs.warning() << "Group name is empty for short term storage " << name; + return false; + } + return true; } From 7ead326b284a027398ef9ece7cc6c9e81e9356fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 16 Dec 2024 17:06:20 +0100 Subject: [PATCH 082/103] Use sirius-solver@antares-integration-v1.6 (#2533) --- src/ports/sirius-solver/portfile.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ports/sirius-solver/portfile.cmake b/src/ports/sirius-solver/portfile.cmake index 287994c152..bf6ac68a36 100644 --- a/src/ports/sirius-solver/portfile.cmake +++ b/src/ports/sirius-solver/portfile.cmake @@ -1,8 +1,8 @@ vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO "rte-france/sirius-solver" - REF "antares-integration-v1.5" - SHA512 19c6c156861bdeb58c2f17f703124d52020c79f9b81734057bf1bc5dff3dbc464179f99aeab6c8c44a84de1f84ed8f4929f9a919d2bf8bd49ac737f656088e19 + REF "antares-integration-v1.6" + SHA512 8d5992f036f35b73c11261e68e030c58c3ffe22b411921c7e08e62274feeed41227b59365a00a4e32e49f35cdaa733b079cfc0a7d98347825253ae67d9c69e4a HEAD_REF main ) From ce061834cd596744f30eab2919b5207be55bde84 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:06:28 +0100 Subject: [PATCH 083/103] Modeler 4.6: system import [ANT-2207] (#2530) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR add the ability to read a YAML file containing all the infos about the electric system and which models they're related to, converting it into system-model structures. --------- Co-authored-by: Florian Omnès --- src/solver/CMakeLists.txt | 1 + src/solver/systemParser/CMakeLists.txt | 32 ++ src/solver/systemParser/converter.cpp | 131 ++++++++ src/solver/systemParser/encoders.hxx | 95 ++++++ .../antares/solver/systemParser/converter.h | 35 +++ .../antares/solver/systemParser/parser.h | 32 ++ .../antares/solver/systemParser/system.h | 55 ++++ src/solver/systemParser/parser.cpp | 40 +++ src/study/system-model/component.cpp | 4 +- .../antares/study/system-model/system.h | 2 +- src/study/system-model/system.cpp | 2 +- .../src/solver/modelParser/CMakeLists.txt | 5 +- .../modelParser/testSystemConverter.cpp | 281 ++++++++++++++++++ .../solver/modelParser/testSystemParser.cpp | 184 ++++++++++++ .../src/study/system-model/test_component.cpp | 18 +- .../src/study/system-model/test_system.cpp | 19 +- 16 files changed, 916 insertions(+), 20 deletions(-) create mode 100644 src/solver/systemParser/CMakeLists.txt create mode 100644 src/solver/systemParser/converter.cpp create mode 100644 src/solver/systemParser/encoders.hxx create mode 100644 src/solver/systemParser/include/antares/solver/systemParser/converter.h create mode 100644 src/solver/systemParser/include/antares/solver/systemParser/parser.h create mode 100644 src/solver/systemParser/include/antares/solver/systemParser/system.h create mode 100644 src/solver/systemParser/parser.cpp create mode 100644 src/tests/src/solver/modelParser/testSystemConverter.cpp create mode 100644 src/tests/src/solver/modelParser/testSystemParser.cpp diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 5ae822209b..b37cb7f1cf 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory(lps) add_subdirectory(misc) add_subdirectory(modelConverter) add_subdirectory(modelParser) +add_subdirectory(systemParser) add_subdirectory(modeler) add_subdirectory(optimisation) add_subdirectory(signal-handling) diff --git a/src/solver/systemParser/CMakeLists.txt b/src/solver/systemParser/CMakeLists.txt new file mode 100644 index 0000000000..79e1262644 --- /dev/null +++ b/src/solver/systemParser/CMakeLists.txt @@ -0,0 +1,32 @@ +find_package(yaml-cpp REQUIRED) + +set(SOURCES + parser.cpp + converter.cpp + encoders.hxx + include/antares/solver/systemParser/parser.h + include/antares/solver/systemParser/converter.h + include/antares/solver/systemParser/system.h +) + +# Create the library +add_library(systemParser STATIC ${SOURCES}) +add_library(Antares::systemParser ALIAS systemParser) + +# Specify include directories +target_include_directories(systemParser + PUBLIC + $ +) + +# Link dependencies (if any) +target_link_libraries(systemParser + PUBLIC + Antares::antares-study-system-model + PRIVATE + yaml-cpp +) + +install(DIRECTORY include/antares + DESTINATION "include" +) diff --git a/src/solver/systemParser/converter.cpp b/src/solver/systemParser/converter.cpp new file mode 100644 index 0000000000..b78b8abb8a --- /dev/null +++ b/src/solver/systemParser/converter.cpp @@ -0,0 +1,131 @@ +/* + * 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/systemParser/converter.h" + +#include + +#include "antares/solver/systemParser/system.h" +#include "antares/study/system-model/system.h" + +using namespace Antares::Study; + +namespace Antares::Solver::SystemConverter +{ + +class ErrorWhileSplittingLibraryAndModel: public std::runtime_error +{ +public: + explicit ErrorWhileSplittingLibraryAndModel(const std::string& s): + runtime_error("'.' not found while splitting library and model: " + s) + { + } +}; + +class LibraryNotFound: public std::runtime_error +{ +public: + explicit LibraryNotFound(const std::string& s): + runtime_error("No library found with this name: " + s) + { + } +}; + +class ModelNotFound: public std::runtime_error +{ +public: + explicit ModelNotFound(const std::string& s): + runtime_error("No model found with this name: " + s) + { + } +}; + +static std::pair splitLibraryModelString(const std::string& s) +{ + size_t pos = s.find('.'); + if (pos == std::string::npos) + { + throw ErrorWhileSplittingLibraryAndModel(s); + } + + std::string library = s.substr(0, pos); + std::string model = s.substr(pos + 1); + return {library, model}; +} + +static const SystemModel::Model& getModel(const std::vector& libraries, + const std::string& libraryId, + const std::string& modelId) +{ + auto lib = std::ranges::find_if(libraries, + [&libraryId](const auto& l) { return l.Id() == libraryId; }); + if (lib == libraries.end()) + { + throw LibraryNotFound(libraryId); + } + + auto search = lib->Models().find(modelId); + if (search == lib->Models().end()) + { + throw ModelNotFound(modelId); + } + + return search->second; +} + +static SystemModel::Component createComponent(const SystemParser::Component& c, + const std::vector& libraries) +{ + const auto [libraryId, modelId] = splitLibraryModelString(c.model); + SystemModel::ModelBuilder model_builder; + + const SystemModel::Model& model = getModel(libraries, libraryId, modelId); + + SystemModel::ComponentBuilder component_builder; + + std::map parameters; + for (const auto& p: c.parameters) + { + parameters.try_emplace(p.id, p.value); + } + + auto component = component_builder.withId(c.id) + .withModel(&model) + .withScenarioGroupId(c.scenarioGroup) + .withParameterValues(parameters) + .build(); + return component; +} + +SystemModel::System convert(const SystemParser::System& parserSystem, + const std::vector& libraries) +{ + std::vector components; + for (const auto& c: parserSystem.components) + { + components.push_back(createComponent(c, libraries)); + } + + SystemModel::SystemBuilder builder; + return builder.withId(parserSystem.id).withComponents(components).build(); +} + +} // namespace Antares::Solver::SystemConverter diff --git a/src/solver/systemParser/encoders.hxx b/src/solver/systemParser/encoders.hxx new file mode 100644 index 0000000000..17135195e9 --- /dev/null +++ b/src/solver/systemParser/encoders.hxx @@ -0,0 +1,95 @@ +/* + * 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 "antares/solver/systemParser/system.h" + +#include "yaml-cpp/yaml.h" + +// Implement convert specializations +namespace YAML +{ + +/** + * @brief shortend to default construct a value when node is null + * @tparam T Type to convert the node to + * @param n node + * @return Object of type T + * It's just to simplify repertitve and verbose lines + * as_fallback_default>( +node["parameters"]) is equivalent to + node["parameters"].as>(std::vector()) + */ +template +inline T as_fallback_default(const Node& n) +{ + return n.as(T()); +} + +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::SystemParser::Parameter& rhs) + { + if (!node.IsMap()) + { + return false; + } + rhs.id = node["id"].as(); + rhs.type = node["type"].as(); + rhs.value = node["value"].as(); + return true; + } +}; + +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::SystemParser::Component& rhs) + { + if (!node.IsMap()) + { + return false; + } + rhs.id = node["id"].as(); + rhs.model = node["model"].as(); + rhs.scenarioGroup = node["scenario-group"].as(); + rhs.parameters = as_fallback_default>( + node["parameters"]); + return true; + } +}; + +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::SystemParser::System& rhs) + { + rhs.id = node["id"].as(); + rhs.libraries = as_fallback_default>(node["model-libraries"]); + rhs.components = as_fallback_default>( + node["components"]); + return true; + } +}; + +} // namespace YAML diff --git a/src/solver/systemParser/include/antares/solver/systemParser/converter.h b/src/solver/systemParser/include/antares/solver/systemParser/converter.h new file mode 100644 index 0000000000..32c607b6e8 --- /dev/null +++ b/src/solver/systemParser/include/antares/solver/systemParser/converter.h @@ -0,0 +1,35 @@ +/* + * 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 + +#include "parser.h" + +namespace Antares::Solver::SystemConverter +{ + +Study::SystemModel::System convert(const SystemParser::System& parserSystem, + const std::vector& libraries); + +} // namespace Antares::Solver::SystemConverter diff --git a/src/solver/systemParser/include/antares/solver/systemParser/parser.h b/src/solver/systemParser/include/antares/solver/systemParser/parser.h new file mode 100644 index 0000000000..94aad258be --- /dev/null +++ b/src/solver/systemParser/include/antares/solver/systemParser/parser.h @@ -0,0 +1,32 @@ +/* + * 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 "antares/solver/systemParser/system.h" + +namespace Antares::Solver::SystemParser +{ +class Parser +{ +public: + System parse(const std::string& content); +}; +} // namespace Antares::Solver::SystemParser diff --git a/src/solver/systemParser/include/antares/solver/systemParser/system.h b/src/solver/systemParser/include/antares/solver/systemParser/system.h new file mode 100644 index 0000000000..888d136d5a --- /dev/null +++ b/src/solver/systemParser/include/antares/solver/systemParser/system.h @@ -0,0 +1,55 @@ +/* + * 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::Solver::SystemParser +{ + +struct Parameter +{ + std::string id; + std::string type; + double value; +}; + +struct Component +{ + std::string id; + std::string model; + std::string scenarioGroup; + std::vector parameters; +}; + +struct System +{ + std::string id; + std::vector libraries; + std::vector components; + + // will be implemented later + // std::vector connections; +}; + +} // namespace Antares::Solver::SystemParser diff --git a/src/solver/systemParser/parser.cpp b/src/solver/systemParser/parser.cpp new file mode 100644 index 0000000000..76f7fa15d5 --- /dev/null +++ b/src/solver/systemParser/parser.cpp @@ -0,0 +1,40 @@ +/* + * 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/systemParser/parser.h" + +#include "antares/solver/systemParser/system.h" + +#include "encoders.hxx" + +namespace Antares::Solver::SystemParser +{ + +System Parser::parse(const std::string& content) +{ + YAML::Node root = YAML::Load(content); + + System system = root["system"].as(); + + return system; +} + +} // namespace Antares::Solver::SystemParser diff --git a/src/study/system-model/component.cpp b/src/study/system-model/component.cpp index 1c3d360e64..87b9991865 100644 --- a/src/study/system-model/component.cpp +++ b/src/study/system-model/component.cpp @@ -45,14 +45,14 @@ static void checkComponentDataValidity(const ComponentData& data) if (data.model->Parameters().size() != data.parameter_values.size()) { throw std::invalid_argument( - "The component has " + std::to_string(data.parameter_values.size()) + "The component \"" + data.id + "\" has " + std::to_string(data.parameter_values.size()) + " parameter(s), but its model has " + std::to_string(data.model->Parameters().size())); } for (const auto param: data.model->Parameters() | std::views::keys) { if (!data.parameter_values.contains(param)) { - throw std::invalid_argument("The component has no value for parameter '" + param + "'"); + throw std::invalid_argument("The component \"" + data.id + "\" has no value for parameter '" + param + "'"); } } } diff --git a/src/study/system-model/include/antares/study/system-model/system.h b/src/study/system-model/include/antares/study/system-model/system.h index 50fa196399..80b042388e 100644 --- a/src/study/system-model/include/antares/study/system-model/system.h +++ b/src/study/system-model/include/antares/study/system-model/system.h @@ -68,7 +68,7 @@ class SystemBuilder { public: SystemBuilder& withId(std::string_view id); - SystemBuilder& withComponents(std::vector&& components); + SystemBuilder& withComponents(std::vector& components); System build() const; private: diff --git a/src/study/system-model/system.cpp b/src/study/system-model/system.cpp index 20a26287e1..70c1807d30 100644 --- a/src/study/system-model/system.cpp +++ b/src/study/system-model/system.cpp @@ -71,7 +71,7 @@ SystemBuilder& SystemBuilder::withId(std::string_view id) * \param components A vector of components to set. * \return Reference to the SystemBuilder object. */ -SystemBuilder& SystemBuilder::withComponents(std::vector&& components) +SystemBuilder& SystemBuilder::withComponents(std::vector& components) { components_ = std::move(components); return *this; diff --git a/src/tests/src/solver/modelParser/CMakeLists.txt b/src/tests/src/solver/modelParser/CMakeLists.txt index 9f884255d8..9c5fad1f82 100644 --- a/src/tests/src/solver/modelParser/CMakeLists.txt +++ b/src/tests/src/solver/modelParser/CMakeLists.txt @@ -5,6 +5,8 @@ set(SOURCE_FILES testConvertorVisitor.cpp test_full.cpp enum_operators.h + testSystemParser.cpp + testSystemConverter.cpp ) # Add executable @@ -14,9 +16,10 @@ add_executable(TestModelParser ${SOURCE_FILES}) target_link_libraries(TestModelParser PRIVATE Boost::unit_test_framework - Antares::solver-expressions + Antares::solver-expressions Antares::modelConverter Antares::modelParser + Antares::systemParser Antares::antares-study-system-model Antares::antlr-interface ) diff --git a/src/tests/src/solver/modelParser/testSystemConverter.cpp b/src/tests/src/solver/modelParser/testSystemConverter.cpp new file mode 100644 index 0000000000..1ba1bbb1fd --- /dev/null +++ b/src/tests/src/solver/modelParser/testSystemConverter.cpp @@ -0,0 +1,281 @@ +/* + * 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 . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include +#include +#include +#include "antares/solver/modelConverter/modelConverter.h" +#include "antares/solver/modelParser/parser.h" +#include "antares/study/system-model/library.h" + +using namespace std::string_literals; +using namespace Antares::Solver; +using namespace Antares::Study; + +struct LibraryObjects +{ + ModelParser::Model model1{.id = "node", + .description = "description", + .parameters = {{"cost", true, false}}, + .variables = {}, + .ports = {}, + .port_field_definitions = {}, + .constraints = {{"constraint1", "cost"}}, + .objective = ""}; + + SystemParser::Parser parser; + ModelParser::Library library; + std::vector libraries; + + LibraryObjects() + { + library.id = "std"; + library.models = {model1}; + libraries = {ModelConverter::convert(library)}; + } + + ~LibraryObjects() = default; +}; + +BOOST_FIXTURE_TEST_CASE(full_model_system, LibraryObjects) +{ + const auto system = R"( + system: + id: base_system + description: real application model + model-libraries: [std] + components: + - id: N + model: std.node + scenario-group: group-234 + parameters: + - id: cost + type: constant + value: 30 + )"s; + + SystemParser::System systemObj = parser.parse(system); + + auto systemModel = SystemConverter::convert(systemObj, libraries); + + BOOST_CHECK_EQUAL(systemModel.Components().size(), 1); + BOOST_CHECK_EQUAL(systemModel.Components().at("N").Id(), "N"); + BOOST_CHECK_EQUAL(systemModel.Components().at("N").getModel()->Id(), "node"); + BOOST_CHECK_EQUAL(systemModel.Components().at("N").getParameterValue("cost"), 30); +} + +BOOST_FIXTURE_TEST_CASE(bad_param_name_in_component, LibraryObjects) +{ + const auto system = R"( + system: + id: base_system + description: real application model + model-libraries: [std] + components: + - id: N + model: std.node + scenario-group: group-234 + parameters: + - id: param_not_in_model + type: constant + value: 30 + )"s; + + SystemParser::System systemObj = parser.parse(system); + + BOOST_CHECK_THROW(SystemConverter::convert(systemObj, libraries), std::invalid_argument); +} + +BOOST_FIXTURE_TEST_CASE(library_not_existing, LibraryObjects) +{ + const auto system = R"( + system: + id: base_system + model-libraries: [abc] + components: + - id: N + model: abc.node + scenario-group: group-234 + )"s; + + SystemParser::System systemObj = parser.parse(system); + + BOOST_CHECK_THROW(SystemConverter::convert(systemObj, libraries), std::runtime_error); +} + +BOOST_FIXTURE_TEST_CASE(model_not_existing, LibraryObjects) +{ + const auto system = R"( + system: + id: base_system + model-libraries: [std] + components: + - id: N + model: std.abc + scenario-group: group-234 + )"s; + + SystemParser::System systemObj = parser.parse(system); + + BOOST_CHECK_THROW(SystemConverter::convert(systemObj, libraries), std::runtime_error); +} + +BOOST_FIXTURE_TEST_CASE(bad_library_model_format, LibraryObjects) +{ + const auto system = R"( + system: + id: base_system + model-libraries: [std] + components: + - id: N + model: std___node + scenario-group: group-234 + parameters: + - id: cost + type: constant + value: 30 + )"s; + + SystemParser::System systemObj = parser.parse(system); + + BOOST_CHECK_THROW(SystemConverter::convert(systemObj, libraries), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(Full_system_test) +{ + const auto libraryYaml = R"( + library: + id: std + description: Standard library + port-types: [] + + models: + - id: generator + description: A basic generator model + parameters: + - id: cost + time-dependent: false + scenario-dependent: false + - id: p_max + time-dependent: false + scenario-dependent: false + variables: + - id: generation + lower-bound: 0 + upper-bound: p_max + ports: + - id: injection_port + type: flow + port-field-definitions: + - port: injection_port + field: flow + definition: generation + objective: cost * generation + + - id: node + description: A basic balancing node model + ports: + - id: injection_port + type: flow + binding-constraints: + - id: balance + expression: injection_port.flow = 0 + )"s; + + const auto libraryYaml2 = R"( + library: + id: mylib + description: Extra library + port-types: [] + + models: + - id: demand + description: A basic fixed demand model + parameters: + - id: demand + time-dependent: true + scenario-dependent: true + ports: + - id: injection_port + type: flow + port-field-definitions: + - port: injection_port + field: flow + definition: -demand + )"s; + + const auto systemYaml = R"( + system: + id: system1 + description: basic description + model-libraries: [std, mylib] + + components: + - id: N + model: std.node + scenario-group: group-234 + + - id: G + model: std.generator + scenario-group: group-234 + parameters: + - id: cost + type: constant + value: 30 + - id: p_max + type: constant + value: 100 + + - id: D + model: mylib.demand + scenario-group: group-qsf + parameters: + - id: demand + type: constant + value: 100 + )"s; + + ModelParser::Parser parserModel; + SystemParser::Parser parserSystem; + + std::vector libraries; + libraries.push_back(ModelConverter::convert(parserModel.parse(libraryYaml))); + libraries.push_back(ModelConverter::convert(parserModel.parse(libraryYaml2))); + + SystemParser::System systemObj = parserSystem.parse(systemYaml); + auto systemModel = SystemConverter::convert(systemObj, libraries); + + BOOST_CHECK_EQUAL(systemModel.Components().size(), 3); + BOOST_CHECK_EQUAL(systemModel.Components().at("N").Id(), "N"); + BOOST_CHECK_EQUAL(systemModel.Components().at("N").getModel()->Id(), "node"); + BOOST_CHECK_EQUAL(systemModel.Components().at("N").getScenarioGroupId(), "group-234"); + + BOOST_CHECK_EQUAL(systemModel.Components().at("G").getModel()->Id(), "generator"); + BOOST_CHECK_EQUAL(systemModel.Components().at("G").getParameterValue("cost"), 30); + BOOST_CHECK_EQUAL(systemModel.Components().at("G").getParameterValue("p_max"), 100); + + BOOST_CHECK_EQUAL(systemModel.Components().at("D").getModel()->Id(), "demand"); + BOOST_CHECK_EQUAL(systemModel.Components().at("D").getParameterValue("demand"), 100); +} diff --git a/src/tests/src/solver/modelParser/testSystemParser.cpp b/src/tests/src/solver/modelParser/testSystemParser.cpp new file mode 100644 index 0000000000..892e29467d --- /dev/null +++ b/src/tests/src/solver/modelParser/testSystemParser.cpp @@ -0,0 +1,184 @@ +/* + * 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 . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include +#include +#include + +using namespace std::string_literals; +using namespace Antares::Solver; +using namespace Antares::Study; + +BOOST_AUTO_TEST_CASE(empty_system) +{ + SystemParser::Parser parser; + const auto system = R"( + system: + id: "" + description: "" + model-libraries: [] + components: [] + )"s; + SystemParser::System systemObj = parser.parse(system); + BOOST_CHECK(systemObj.id.empty()); + BOOST_CHECK(systemObj.libraries.empty()); + BOOST_CHECK(systemObj.components.empty()); +} + +BOOST_AUTO_TEST_CASE(simple_id) +{ + SystemParser::Parser parser; + const auto system = R"( + system: + id: base_system + description: a basic system + )"s; + SystemParser::System systemObj = parser.parse(system); + BOOST_CHECK_EQUAL(systemObj.id, "base_system"); +} + +BOOST_AUTO_TEST_CASE(libraries_one_model) +{ + SystemParser::Parser parser; + const auto system = R"( + system: + id: base_system + model-libraries: [abc] + )"s; + SystemParser::System systemObj = parser.parse(system); + BOOST_CHECK_EQUAL(systemObj.libraries[0], "abc"); +} + +BOOST_AUTO_TEST_CASE(libraries_list_of_models) +{ + SystemParser::Parser parser; + const auto system = R"( + system: + id: base_system + description: 3 model libraries + model-libraries: [abc, def, 123] + components: [] + )"s; + SystemParser::System systemObj = parser.parse(system); + BOOST_CHECK_EQUAL(systemObj.libraries[0], "abc"); + BOOST_CHECK_EQUAL(systemObj.libraries[1], "def"); + BOOST_CHECK_EQUAL(systemObj.libraries[2], "123"); + BOOST_CHECK(systemObj.components.empty()); +} + +BOOST_AUTO_TEST_CASE(one_component) +{ + SystemParser::Parser parser; + const auto system = R"( + system: + id: base_system + description: one simple component + components: + - id: N + model: abcde + scenario-group: group-234 + )"s; + SystemParser::System systemObj = parser.parse(system); + BOOST_CHECK_EQUAL(systemObj.components[0].id, "N"); + BOOST_CHECK_EQUAL(systemObj.components[0].model, "abcde"); + BOOST_CHECK_EQUAL(systemObj.components[0].scenarioGroup, "group-234"); +} + +BOOST_AUTO_TEST_CASE(two_components) +{ + SystemParser::Parser parser; + const auto system = R"( + system: + id: base_system + description: two components + components: + - id: N + model: std.node + scenario-group: group-234 + - id: G + model: std.generator + scenario-group: group-thermal + )"s; + SystemParser::System systemObj = parser.parse(system); + BOOST_CHECK_EQUAL(systemObj.components[0].id, "N"); + BOOST_CHECK_EQUAL(systemObj.components[0].model, "std.node"); + BOOST_CHECK_EQUAL(systemObj.components[0].scenarioGroup, "group-234"); + BOOST_CHECK_EQUAL(systemObj.components[1].id, "G"); + BOOST_CHECK_EQUAL(systemObj.components[1].model, "std.generator"); + BOOST_CHECK_EQUAL(systemObj.components[1].scenarioGroup, "group-thermal"); +} + +BOOST_AUTO_TEST_CASE(component_parameter) +{ + SystemParser::Parser parser; + const auto system = R"( + system: + id: base_system + description: one component with one parameter + components: + - id: N + model: std.node + scenario-group: group-234 + parameters: + - id: cost + type: constant + value: 30 + )"s; + SystemParser::System systemObj = parser.parse(system); + const auto& param = systemObj.components[0].parameters[0]; + BOOST_CHECK_EQUAL(param.id, "cost"); + BOOST_CHECK_EQUAL(param.type, "constant"); + BOOST_CHECK_EQUAL(param.value, 30); +} + +BOOST_AUTO_TEST_CASE(component_two_parameters) +{ + SystemParser::Parser parser; + const auto system = R"( + system: + id: base_system + description: one component with one parameter + components: + - id: N + model: std.node + scenario-group: group-234 + parameters: + - id: cost + type: constant + value: 30 + - id: p_max + type: constant + value: 100 + )"s; + SystemParser::System systemObj = parser.parse(system); + const auto& param = systemObj.components[0].parameters[0]; + const auto& param2 = systemObj.components[0].parameters[1]; + BOOST_CHECK_EQUAL(param.id, "cost"); + BOOST_CHECK_EQUAL(param.type, "constant"); + BOOST_CHECK_EQUAL(param.value, 30); + BOOST_CHECK_EQUAL(param2.id, "p_max"); + BOOST_CHECK_EQUAL(param2.type, "constant"); + BOOST_CHECK_EQUAL(param2.value, 100); +} diff --git a/src/tests/src/study/system-model/test_component.cpp b/src/tests/src/study/system-model/test_component.cpp index 3f52b33880..ca8e0c93f4 100644 --- a/src/tests/src/study/system-model/test_component.cpp +++ b/src/tests/src/study/system-model/test_component.cpp @@ -159,7 +159,8 @@ BOOST_AUTO_TEST_CASE(fail_on_no_params1) .withScenarioGroupId("scenario_group"); BOOST_CHECK_EXCEPTION(component_builder.build(), std::invalid_argument, - checkMessage("The component has 0 parameter(s), but its model has 2")); + checkMessage( + "The component \"component\" has 0 parameter(s), but its model has 2")); } BOOST_AUTO_TEST_CASE(fail_on_no_params2) @@ -171,7 +172,8 @@ BOOST_AUTO_TEST_CASE(fail_on_no_params2) .withScenarioGroupId("scenario_group"); BOOST_CHECK_EXCEPTION(component_builder.build(), std::invalid_argument, - checkMessage("The component has 0 parameter(s), but its model has 2")); + checkMessage( + "The component \"component\" has 0 parameter(s), but its model has 2")); } BOOST_AUTO_TEST_CASE(fail_on_missing_param) @@ -183,7 +185,8 @@ BOOST_AUTO_TEST_CASE(fail_on_missing_param) .withScenarioGroupId("scenario_group"); BOOST_CHECK_EXCEPTION(component_builder.build(), std::invalid_argument, - checkMessage("The component has 1 parameter(s), but its model has 2")); + checkMessage( + "The component \"component\" has 1 parameter(s), but its model has 2")); } BOOST_AUTO_TEST_CASE(fail_on_missing_wrong_param) @@ -195,7 +198,8 @@ BOOST_AUTO_TEST_CASE(fail_on_missing_wrong_param) .withScenarioGroupId("scenario_group"); BOOST_CHECK_EXCEPTION(component_builder.build(), std::invalid_argument, - checkMessage("The component has no value for parameter 'param1'")); + checkMessage( + "The component \"component\" has no value for parameter 'param1'")); } BOOST_AUTO_TEST_CASE(fail_on_too_many_params1) @@ -207,7 +211,8 @@ BOOST_AUTO_TEST_CASE(fail_on_too_many_params1) .withScenarioGroupId("scenario_group"); BOOST_CHECK_EXCEPTION(component_builder.build(), std::invalid_argument, - checkMessage("The component has 3 parameter(s), but its model has 2")); + checkMessage( + "The component \"component\" has 3 parameter(s), but its model has 2")); } BOOST_AUTO_TEST_CASE(fail_on_too_many_params2) @@ -219,7 +224,8 @@ BOOST_AUTO_TEST_CASE(fail_on_too_many_params2) .withScenarioGroupId("scenario_group"); BOOST_CHECK_EXCEPTION(component_builder.build(), std::invalid_argument, - checkMessage("The component has 1 parameter(s), but its model has 0")); + checkMessage( + "The component \"component\" has 1 parameter(s), but its model has 0")); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/study/system-model/test_system.cpp b/src/tests/src/study/system-model/test_system.cpp index 550ca59693..03436fa365 100644 --- a/src/tests/src/study/system-model/test_system.cpp +++ b/src/tests/src/study/system-model/test_system.cpp @@ -32,6 +32,7 @@ using namespace Antares::Study::SystemModel; struct SystemBuilderCreationFixture { SystemBuilder system_builder; + std::vector components; }; static Component createComponent(std::string id) @@ -50,9 +51,8 @@ BOOST_AUTO_TEST_SUITE(_System_) BOOST_FIXTURE_TEST_CASE(nominal_build, SystemBuilderCreationFixture) { - auto system = system_builder.withId("system") - .withComponents({createComponent("component1"), createComponent("component2")}) - .build(); + components = {createComponent("component1"), createComponent("component2")}; + auto system = system_builder.withId("system").withComponents(components).build(); BOOST_CHECK_EQUAL(system.Id(), "system"); BOOST_CHECK_EQUAL(system.Components().size(), 2); BOOST_CHECK_EQUAL(system.Components().at("component1").Id(), "component1"); @@ -61,7 +61,8 @@ BOOST_FIXTURE_TEST_CASE(nominal_build, SystemBuilderCreationFixture) BOOST_FIXTURE_TEST_CASE(fail_on_no_id, SystemBuilderCreationFixture) { - system_builder.withComponents({createComponent("component1"), createComponent("component2")}); + components = {createComponent("component1"), createComponent("component2")}; + system_builder.withComponents(components); BOOST_CHECK_EXCEPTION(system_builder.build(), std::invalid_argument, checkMessage("A system can't have an empty id")); @@ -77,7 +78,7 @@ BOOST_FIXTURE_TEST_CASE(fail_on_no_component1, SystemBuilderCreationFixture) BOOST_FIXTURE_TEST_CASE(fail_on_no_component2, SystemBuilderCreationFixture) { - system_builder.withId("system").withComponents({}); + system_builder.withId("system").withComponents(components); BOOST_CHECK_EXCEPTION(system_builder.build(), std::invalid_argument, checkMessage("A system must contain at least one component")); @@ -85,10 +86,10 @@ BOOST_FIXTURE_TEST_CASE(fail_on_no_component2, SystemBuilderCreationFixture) BOOST_FIXTURE_TEST_CASE(fail_on_components_with_same_id, SystemBuilderCreationFixture) { - system_builder.withId("system").withComponents({}).withComponents( - {createComponent("component1"), - createComponent("component2"), - createComponent("component2")}); + components = {createComponent("component1"), + createComponent("component2"), + createComponent("component2")}; + system_builder.withId("system").withComponents({components}); BOOST_CHECK_EXCEPTION(system_builder.build(), std::invalid_argument, checkMessage("System has at least two components with the same id " From 5b14f61ccbd4b05356380b074bbf8f73b9477eab Mon Sep 17 00:00:00 2001 From: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:35:59 +0100 Subject: [PATCH 084/103] Adding constraints on injection-witdrawal cumulation with constant RHS [ANT-1885] (#2535) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request introduces new functionality for handling additional constraints in the short-term storage component of the Antares Simulator. The changes include adding new files, modifying existing classes to support the new constraints, and updating the build configuration to include the new files. Below are the most important changes: ### New Functionality for Additional Constraints * Added `AdditionalConstraint` structure and related methods to handle validation and storage of constraints. (`src/libs/antares/study/include/antares/study/parts/short-term-storage/AdditionalConstraint.h`, [src/libs/antares/study/include/antares/study/parts/short-term-storage/AdditionalConstraint.hR1-R53](diffhunk://#diff-28f2057f7eba48ae42dec99b653d4022ea6604fa48a13ae8ac1b806315506e27R1-R53)) * Implemented methods to load additional constraints from an INI file and validate them. (`src/libs/antares/study/parts/short-term-storage/AdditionalConstraint.cpp`, [src/libs/antares/study/parts/short-term-storage/AdditionalConstraint.cppR1-R65](diffhunk://#diff-3621d191c85fb5b66bcbfeaf356663b248edc889bb73333496d195ab52e278f5R1-R65)) ### Modifications to Existing Classes * Updated `STStorageCluster` to include a vector of `AdditionalConstraint` objects and added necessary methods to handle these constraints. (`src/libs/antares/study/include/antares/study/parts/short-term-storage/cluster.h`, [src/libs/antares/study/include/antares/study/parts/short-term-storage/cluster.hR39-R54](diffhunk://#diff-bdfebe31db8d5e9aa119ac2793a107597bca647f65f399d1f408060f4e945ef9R39-R54)) * Modified `STStorageInput` to load constraints from an INI file and calculate the cumulative constraint count. (`src/libs/antares/study/include/antares/study/parts/short-term-storage/container.h`, [[1]](diffhunk://#diff-52dc8a33c0238cd4143e96739e689b64a1723f13f3d09a4aca5ac9f62f21b882R35-R57); `src/libs/antares/study/parts/short-term-storage/container.cpp`, [[2]](diffhunk://#diff-cec1ba69ce05b7ff57b2fa19d1fd601b94db222e9fdd0b784d6be9313ce4f790R78-R154) [[3]](diffhunk://#diff-cec1ba69ce05b7ff57b2fa19d1fd601b94db222e9fdd0b784d6be9313ce4f790R195-R203) ### Build Configuration Updates * Updated `CMakeLists.txt` to include new header and source files for additional constraints. (`src/libs/antares/study/CMakeLists.txt`, [[1]](diffhunk://#diff-8710cc094e1d5a6f4a53b07116cd0d335fe1efb285e154dcd5b3a3c297079647R105-R107); `src/solver/optimisation/CMakeLists.txt`, [[2]](diffhunk://#diff-8d1079b5acad0fbdef8bc452ff03744eae4089d018b72461e91e31eba16ec714R85-R87) ### Solver Integration * Integrated the handling of additional constraints into the solver's optimization process by adding new methods and including the necessary headers. (`src/solver/optimisation/constraints/Group1.cpp`, [[1]](diffhunk://#diff-819577c61bf6475f45b1df04e74fb7d665c6fc52c36f3484a1a0dc1c0421facdR25) [[2]](diffhunk://#diff-819577c61bf6475f45b1df04e74fb7d665c6fc52c36f3484a1a0dc1c0421facdR53-R59) [[3]](diffhunk://#diff-819577c61bf6475f45b1df04e74fb7d665c6fc52c36f3484a1a0dc1c0421facdR100-R104) [[4]](diffhunk://#diff-819577c61bf6475f45b1df04e74fb7d665c6fc52c36f3484a1a0dc1c0421facdR139-R143) ### Runtime Information * Enhanced `StudyRuntimeInfos` to include cumulative constraint counts for short-term storage. (`src/libs/antares/study/runtime/runtime.h`, [[1]](diffhunk://#diff-458433d2f769bbbcbc330ee42ec7258665121c44c7971082cfda8f95bae3b029R113); `src/libs/antares/study/runtime/runtime.cpp`, [[2]](diffhunk://#diff-c5ee413f02cb61b2ec6d93145fcd7254e1d566a391a7ffccf66da9851fc8e746R97-R98) [[3]](diffhunk://#diff-c5ee413f02cb61b2ec6d93145fcd7254e1d566a391a7ffccf66da9851fc8e746R368-R369) These changes collectively add support for additional constraints in the short-term storage component, ensuring they are loaded, validated, and integrated into the simulation and optimization processes. --------- Co-authored-by: Florian Omnès --- src/libs/antares/study/CMakeLists.txt | 10 +- src/libs/antares/study/area/list.cpp | 1 + .../short-term-storage/AdditionalConstraint.h | 53 ++++++ .../study/parts/short-term-storage/cluster.h | 5 + .../parts/short-term-storage/container.h | 12 +- .../include/antares/study/runtime/runtime.h | 1 + .../AdditionalConstraint.cpp | 65 ++++++++ .../parts/short-term-storage/cluster.cpp | 2 - .../parts/short-term-storage/container.cpp | 89 +++++++++- src/libs/antares/study/runtime/runtime.cpp | 4 + src/solver/optimisation/CMakeLists.txt | 2 + .../optimisation/constraints/Group1.cpp | 18 ++ .../ShortTermStorageCumulation.cpp | 157 ++++++++++++++++++ .../constraints/ConstraintBuilder.h | 5 + .../solver/optimisation/constraints/Group1.h | 3 + .../constraints/ShortTermStorageCumulation.h | 39 +++++ .../solver/optimisation/opt_rename_problem.h | 10 ++ .../opt_decompte_variables_et_contraintes.cpp | 36 ++-- ...opt_gestion_second_membre_cas_lineaire.cpp | 25 ++- .../optimisation/opt_rename_problem.cpp | 17 +- .../simulation/sim_alloc_probleme_hebdo.h | 2 + .../sim_structure_probleme_economique.h | 3 +- .../simulation/sim_alloc_probleme_hebdo.cpp | 8 + .../simulation/sim_calcul_economique.cpp | 8 +- 24 files changed, 546 insertions(+), 29 deletions(-) create mode 100644 src/libs/antares/study/include/antares/study/parts/short-term-storage/AdditionalConstraint.h create mode 100644 src/libs/antares/study/parts/short-term-storage/AdditionalConstraint.cpp create mode 100644 src/solver/optimisation/constraints/ShortTermStorageCumulation.cpp create mode 100644 src/solver/optimisation/include/antares/solver/optimisation/constraints/ShortTermStorageCumulation.h 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 From a570a0ec9b24cdc6f3894e4ec2273314aac6f11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Thu, 19 Dec 2024 15:21:09 +0100 Subject: [PATCH 085/103] Rebase the 8.8.x branch on top of develop to take multiple fixes into account (#2512) Co-authored-by: Jason Marechal Co-authored-by: payetvin <113102157+payetvin@users.noreply.github.com> Co-authored-by: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Co-authored-by: Abdoulbari Zakir Co-authored-by: Vincent Payet Co-authored-by: Juliette-Gerbaux <130555142+Juliette-Gerbaux@users.noreply.github.com> Co-authored-by: OMNES Florian Co-authored-by: Guillaume PIERRE --- .github/workflows/ubuntu.yml | 30 +- .github/workflows/windows-vcpkg.yml | 8 + sonar-project.properties | 21 + src/CMakeLists.txt | 1 - src/libs/antares/exception/LoadingError.cpp | 5 +- .../antares/exception/LoadingError.hpp | 2 +- .../study/parameters/adq-patch-params.cpp | 4 + .../antares/study/parts/thermal/cluster.cpp | 5 + src/solver/misc/options.cpp | 8 +- src/solver/optimisation/CMakeLists.txt | 2 - .../adq_patch_curtailment_sharing.cpp | 3 +- .../adq_patch_post_process_list.cpp | 9 +- .../adequacy_patch_csr/post_processing.cpp | 62 --- .../adequacy_patch_csr/solve_problem.h | 14 + .../adequacy_patch_csr/hourly_csr_problem.h | 134 +++--- .../adequacy_patch_csr/post_processing.h | 29 -- .../solver/optimisation/opt_fonctions.h | 7 - .../optimisation/post_process_commands.h | 25 +- .../opt_appel_solveur_lineaire.cpp | 3 +- .../optimisation/post_process_commands.cpp | 90 ++-- .../simulation/sim_alloc_probleme_hebdo.cpp | 1 + src/solver/variable/CMakeLists.txt | 4 +- src/solver/variable/economy/max-mrg.cpp | 193 --------- .../antares/solver/variable/economy/all.h | 113 ++--- .../antares/solver/variable/economy/loldCsr.h | 242 +++++++++++ .../antares/solver/variable/economy/lolpCsr.h | 242 +++++++++++ .../solver/variable/economy/max-mrg-csr.h | 243 +++++++++++ .../solver/variable/economy/max-mrg-utils.h | 56 +++ .../antares/solver/variable/economy/max-mrg.h | 15 +- .../solver/variable/economy/overallCostCsr.h | 253 ++++++++++++ .../variable/economy/unsupliedEnergyCsr.h | 2 - src/solver/variable/max-mrg-utils.cpp | 171 ++++++++ .../libs/antares/writer/test_zip_writer.cpp | 127 ++++++ .../solver/optimisation/adequacy_patch.cpp | 386 ++++++++++++++++++ .../adequacy_patch/adequacy_patch.cpp | 73 ---- src/ui/simulator/application/main/create.cpp | 8 +- .../simulator/application/main/internal-ids.h | 10 + src/ui/simulator/application/main/main.cpp | 65 +++ src/ui/simulator/application/main/main.h | 45 ++ src/ui/simulator/application/main/menu.cpp | 15 + .../simulator/application/main/statusbar.cpp | 226 +++++++++- src/ui/simulator/cmake/components.cmake | 1 + .../toolbox/components/datagrid/dbgrid.cpp | 19 + .../components/datagrid/selectionoperation.h | 247 +++++++++++ 44 files changed, 2647 insertions(+), 572 deletions(-) delete mode 100644 src/solver/optimisation/adequacy_patch_csr/post_processing.cpp create mode 100644 src/solver/optimisation/adequacy_patch_csr/solve_problem.h delete mode 100644 src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h delete mode 100644 src/solver/variable/economy/max-mrg.cpp create mode 100644 src/solver/variable/include/antares/solver/variable/economy/loldCsr.h create mode 100644 src/solver/variable/include/antares/solver/variable/economy/lolpCsr.h create mode 100644 src/solver/variable/include/antares/solver/variable/economy/max-mrg-csr.h create mode 100644 src/solver/variable/include/antares/solver/variable/economy/max-mrg-utils.h create mode 100644 src/solver/variable/include/antares/solver/variable/economy/overallCostCsr.h create mode 100644 src/solver/variable/max-mrg-utils.cpp create mode 100644 src/tests/src/libs/antares/writer/test_zip_writer.cpp create mode 100644 src/tests/src/solver/optimisation/adequacy_patch.cpp create mode 100644 src/ui/simulator/toolbox/components/datagrid/selectionoperation.h diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 2c73097adb..daceabc0ff 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -170,6 +170,7 @@ jobs: run: | cd _build ctest -C Release --output-on-failure -L "unit|end-to-end" + - name: Upload logs for failed tests if: ${{ failure() }} @@ -177,7 +178,7 @@ jobs: with: name: test-log path: ${{ github.workspace }}/_build/Testing/Temporary/LastTest.log - + - name: Run tests about infinity on BCs RHS if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} uses: ./.github/workflows/run-tests @@ -185,7 +186,7 @@ jobs: simtest-tag: ${{ env.SIMTEST }} batch-name: valid-v830 os: ${{ env.os }} - + - name: Run MILP with CBC if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} uses: ./.github/workflows/run-tests @@ -195,6 +196,23 @@ jobs: variant: "milp-cbc" os: ${{ env.os }} + - name: Run tests on adequacy patch (CSR) + if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{steps.simtest-version.outputs.prop}} + batch-name: adequacy-patch-CSR + os: ${{ env.os }} + + - name: Run parallel tests + if: ${{ env.RUN_EXTENDED_TESTS == 'true' }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{steps.simtest-version.outputs.prop}} + batch-name: valid-parallel + os: ${{ env.os }} + variant: "parallel" + - name: Run tests introduced in 8.6.0 if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} uses: ./.github/workflows/run-tests @@ -248,14 +266,6 @@ jobs: batch-name: valid-mps os: ${{ env.os }} - - name: Run tests for adequacy patch (CSR) - if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{ env.SIMTEST }} - batch-name: adequacy-patch-CSR - os: ${{ env.os }} - - name: Run parallel tests if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }} uses: ./.github/workflows/run-tests diff --git a/.github/workflows/windows-vcpkg.yml b/.github/workflows/windows-vcpkg.yml index 5fb4b19603..37d47eaadf 100644 --- a/.github/workflows/windows-vcpkg.yml +++ b/.github/workflows/windows-vcpkg.yml @@ -188,6 +188,14 @@ jobs: batch-name: adequacy-patch-CSR os: ${{ env.os }} + - name: Run tests about infinity on BCs RHS + if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{steps.simtest-version.outputs.prop}} + batch-name: valid-v830 + os: ${{ env.test-platform }} + - name: Run tests about infinity on BCs RHS if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} uses: ./.github/workflows/run-tests diff --git a/sonar-project.properties b/sonar-project.properties index 0c74bd252a..d4ba8cce37 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,3 +1,24 @@ +# +# 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 . +# + sonar.projectName=Antares_Simulator sonar.projectKey=AntaresSimulatorTeam_Antares_Simulator sonar.organization=antaressimulatorteam diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 56dc5e2bf8..13c67fe7a0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,7 +5,6 @@ set(ANTARES_VERSION_HI 9) set(ANTARES_VERSION_LO 2) set(ANTARES_VERSION_REVISION 0) - # Beta release set(ANTARES_BETA 0) set(ANTARES_RC 7) diff --git a/src/libs/antares/exception/LoadingError.cpp b/src/libs/antares/exception/LoadingError.cpp index cea447153e..32f4b3b1c1 100644 --- a/src/libs/antares/exception/LoadingError.cpp +++ b/src/libs/antares/exception/LoadingError.cpp @@ -96,9 +96,8 @@ InvalidSolverSpecificParameters::InvalidSolverSpecificParameters(const std::stri { } -InvalidStudy::InvalidStudy(const Yuni::String& study): - LoadingError(std::string("The folder `") + study.c_str() - + "` does not seem to be a valid study") +InvalidStudy::InvalidStudy(const std::string& study): + LoadingError(std::string("The folder `") + study + "` does not seem to be a valid study") { } diff --git a/src/libs/antares/exception/include/antares/exception/LoadingError.hpp b/src/libs/antares/exception/include/antares/exception/LoadingError.hpp index d70820e5e9..9a5ff14002 100644 --- a/src/libs/antares/exception/include/antares/exception/LoadingError.hpp +++ b/src/libs/antares/exception/include/antares/exception/LoadingError.hpp @@ -140,7 +140,7 @@ class InvalidSolverSpecificParameters: public LoadingError class InvalidStudy: public LoadingError { public: - explicit InvalidStudy(const Yuni::String& study); + explicit InvalidStudy(const std::string& study); }; class NoStudyProvided: public LoadingError diff --git a/src/libs/antares/study/parameters/adq-patch-params.cpp b/src/libs/antares/study/parameters/adq-patch-params.cpp index ebf6de321e..800f2d19f8 100644 --- a/src/libs/antares/study/parameters/adq-patch-params.cpp +++ b/src/libs/antares/study/parameters/adq-patch-params.cpp @@ -146,6 +146,10 @@ void AdqPatchParams::addExcludedVariables(std::vector& out) const out.emplace_back("LMR VIOL."); out.emplace_back("UNSP. ENRG CSR"); out.emplace_back("DTG MRG CSR"); + out.emplace_back("LOLD CSR"); + out.emplace_back("LOLP CSR"); + out.emplace_back("MAX MRG CSR"); + out.emplace_back("OV. COST CSR"); } } diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index 96b2d87826..cfd16f521e 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -298,6 +298,11 @@ void Data::ThermalCluster::calculationOfSpinning() void Data::ThermalCluster::reverseCalculationOfSpinning() { + if (tsGenBehavior == LocalTSGenerationBehavior::forceNoGen) + { + return; + } + // Nothing to do if the spinning is equal to zero // because it will the same multiply all entries of the matrix by 1. if (Utils::isZero(spinning)) diff --git a/src/solver/misc/options.cpp b/src/solver/misc/options.cpp index d72bd4c692..00572039a9 100644 --- a/src/solver/misc/options.cpp +++ b/src/solver/misc/options.cpp @@ -82,14 +82,14 @@ std::unique_ptr CreateParser(Settings& settings, StudyLoad "Solver used for simulation\nAvailable solver list : " + availableOrToolsSolversString()); - //--xpress-parameters + //--solver-parameters parser->add( options.optOptions.solverParameters, ' ', "solver-parameters", - "Set xpress solver specific parameters. The specified string must be wrapped into quotes: " - "--solver-parameters=\"param1 value1 param2 value2\". The syntax of parameters is solver " - "specfic, examples are given in Antares-Simulator online documentation."); + "Set solver-specific parameters, for instance --solver-parameters=\"THREADS 1 PRESOLVE 1\"" + "for XPRESS or --solver-parameters=\"parallel/maxnthreads 1, lp/presolving TRUE\" for SCIP." + "Syntax is solver-dependent, and only supported for SCIP & XPRESS."); parser->addParagraph("\nParameters"); // --name diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index ec98f298e8..0d64d42e44 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -47,9 +47,7 @@ set(RTESOLVER_OPT post_process_commands.cpp include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.h - include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h adequacy_patch_csr/adq_patch_post_process_list.cpp - adequacy_patch_csr/post_processing.cpp include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.h adequacy_patch_csr/adq_patch_curtailment_sharing.cpp adequacy_patch_csr/solve_problem.cpp diff --git a/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp b/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp index b480108379..731aaac79c 100644 --- a/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp +++ b/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp @@ -25,9 +25,10 @@ #include "antares/solver/optimisation/adequacy_patch_csr/count_constraints_variables.h" #include "antares/solver/optimisation/adequacy_patch_csr/csr_quadratic_problem.h" -#include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/simulation/adequacy_patch_runtime_data.h" +#include "solve_problem.h" + using namespace Yuni; namespace Antares::Data::AdequacyPatch diff --git a/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp b/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp index 1d54cb0da0..f9f8aa389b 100644 --- a/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp +++ b/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp @@ -36,7 +36,7 @@ AdqPatchPostProcessList::AdqPatchPostProcessList(const AdqPatchParams& adqPatchP { post_process_list.push_back( std::make_unique(problemeHebdo_, numSpace_, areas)); - + // Here a post process particular to adq patch post_process_list.push_back( std::make_unique(problemeHebdo_, areas, false, false)); post_process_list.push_back(std::make_unique(problemeHebdo_, @@ -44,15 +44,14 @@ AdqPatchPostProcessList::AdqPatchPostProcessList(const AdqPatchParams& adqPatchP sheddingPolicy, splxOptimization, numSpace)); - - // Here a post process particular to adq patch post_process_list.push_back(std::make_unique(adqPatchParams, problemeHebdo_, areas, numSpace_)); - // Here a post process particular to adq patch post_process_list.push_back( - std::make_unique(problemeHebdo_, areas, numSpace)); + std::make_unique(problemeHebdo_, areas, numSpace)); + post_process_list.push_back( + std::make_unique(problemeHebdo_, areas, numSpace)); post_process_list.push_back( std::make_unique(problemeHebdo_, areas, true, false)); post_process_list.push_back( diff --git a/src/solver/optimisation/adequacy_patch_csr/post_processing.cpp b/src/solver/optimisation/adequacy_patch_csr/post_processing.cpp deleted file mode 100644 index bc946a3c57..0000000000 --- a/src/solver/optimisation/adequacy_patch_csr/post_processing.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* -** 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/adequacy_patch_csr/post_processing.h" - -#include - -namespace Antares::Data::AdequacyPatch -{ -double recomputeDTG_MRG(bool triggered, double dtgMrg, double ens) -{ - if (triggered) - { - return std::max(0.0, dtgMrg - ens); - } - else - { - return dtgMrg; - } -} - -double recomputeENS_MRG(bool triggered, double dtgMrg, double ens) -{ - if (triggered) - { - return std::max(0.0, ens - dtgMrg); - } - else - { - return ens; - } -} - -double recomputeMRGPrice(double ensCsr, double originalCost, double unsuppliedEnergyCost) -{ - if (ensCsr > 0.5) - { - return -unsuppliedEnergyCost; - } - else - { - return originalCost; - } -} -} // namespace Antares::Data::AdequacyPatch diff --git a/src/solver/optimisation/adequacy_patch_csr/solve_problem.h b/src/solver/optimisation/adequacy_patch_csr/solve_problem.h new file mode 100644 index 0000000000..59b0619ca2 --- /dev/null +++ b/src/solver/optimisation/adequacy_patch_csr/solve_problem.h @@ -0,0 +1,14 @@ + +#pragma once + +#include "antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h" +#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" +#include "antares/study/parameters/adq-patch-params.h" + +using namespace Antares::Data::AdequacyPatch; + +bool ADQ_PATCH_CSR(PROBLEME_ANTARES_A_RESOUDRE&, + HourlyCSRProblem&, + const AdqPatchParams&, + unsigned int week, + int year); diff --git a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h b/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h index c7fb554c22..6ebb9734e4 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h @@ -31,10 +31,69 @@ #include "../variables/VariableManagerUtils.h" +struct LinkVariable +{ + LinkVariable(): + directVar(-1), + indirectVar(-1) + { + } + + LinkVariable(int direct, int indirect): + directVar(direct), + indirectVar(indirect) + { + } + + inline bool check() const + { + if (directVar < 0) + { + Antares::logs.warning() << "directVar < 0 detected, this should not happen"; + } + if (indirectVar < 0) + { + Antares::logs.warning() << "indirectVar < 0 detected, this should not happen"; + } + + return (directVar >= 0) && (indirectVar >= 0); + } + + int directVar; + int indirectVar; +}; + struct PROBLEME_HEBDO; class HourlyCSRProblem { + using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams; + +public: + explicit HourlyCSRProblem(const AdqPatchParams& adqPatchParams, PROBLEME_HEBDO* p): + adqPatchParams_(adqPatchParams), + variableManager_(p->CorrespondanceVarNativesVarOptim, + p->NumeroDeVariableStockFinal, + p->NumeroDeVariableDeTrancheDeStock, + p->NombreDePasDeTempsPourUneOptimisation), + problemeHebdo_(p) + { + double temp = pow(10, -adqPatchParams.curtailmentSharing.thresholdVarBoundsRelaxation); + belowThisThresholdSetToZero = std::min(temp, 0.1); + + allocateProblem(); + } + + HourlyCSRProblem(const HourlyCSRProblem&) = delete; + HourlyCSRProblem& operator=(const HourlyCSRProblem&) = delete; + + inline void setHour(int hour) + { + triggeredHour = hour; + } + + void run(uint week, uint year); + private: void calculateCsrParameters(); @@ -65,85 +124,26 @@ class HourlyCSRProblem void setQuadraticCost(); void setLinearCost(); -private: - using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams; +public: + // TODO [gp] : try to make these members private + double belowThisThresholdSetToZero; + std::map numberOfConstraintCsrAreaBalance; + std::set ensVariablesInsideAdqPatch; // place inside only ENS inside adq-patch + std::set varToBeSetToZeroIfBelowThreshold; // place inside only ENS and Spillage variable + int triggeredHour; + const AdqPatchParams& adqPatchParams_; VariableManagement::VariableManager variableManager_; -public: - void run(uint week, uint year); - - // TODO[FOM] Make these members private - int triggeredHour; - double belowThisThresholdSetToZero; PROBLEME_HEBDO* problemeHebdo_; PROBLEME_ANTARES_A_RESOUDRE problemeAResoudre_; - explicit HourlyCSRProblem(const AdqPatchParams& adqPatchParams, PROBLEME_HEBDO* p): - adqPatchParams_(adqPatchParams), - variableManager_(p->CorrespondanceVarNativesVarOptim, - p->NumeroDeVariableStockFinal, - p->NumeroDeVariableDeTrancheDeStock, - p->NombreDePasDeTempsPourUneOptimisation), - problemeHebdo_(p) - { - double temp = pow(10, -adqPatchParams.curtailmentSharing.thresholdVarBoundsRelaxation); - belowThisThresholdSetToZero = std::min(temp, 0.1); - - allocateProblem(); - } - - ~HourlyCSRProblem() = default; - - HourlyCSRProblem(const HourlyCSRProblem&) = delete; - HourlyCSRProblem& operator=(const HourlyCSRProblem&) = delete; - - inline void setHour(int hour) - { - triggeredHour = hour; - } - std::map numberOfConstraintCsrEns; - std::map numberOfConstraintCsrAreaBalance; std::map numberOfConstraintCsrFlowDissociation; std::map numberOfConstraintCsrHourlyBinding; // length is number of binding constraint // contains interco 2-2 std::map rhsAreaBalanceValues; - std::set varToBeSetToZeroIfBelowThreshold; // place inside only ENS and Spillage variable - std::set ensVariablesInsideAdqPatch; // place inside only ENS inside adq-patch - - struct LinkVariable - { - LinkVariable(): - directVar(-1), - indirectVar(-1) - { - } - - LinkVariable(int direct, int indirect): - directVar(direct), - indirectVar(indirect) - { - } - - inline bool check() const - { - if (directVar < 0) - { - Antares::logs.warning() << "directVar < 0 detected, this should not happen"; - } - if (indirectVar < 0) - { - Antares::logs.warning() << "indirectVar < 0 detected, this should not happen"; - } - - return (directVar >= 0) && (indirectVar >= 0); - } - - int directVar; - int indirectVar; - }; // links between two areas inside the adq-patch domain std::map linkInsideAdqPatch; diff --git a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h b/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h deleted file mode 100644 index 3ae5ee2d91..0000000000 --- a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -** 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 - -namespace Antares::Data::AdequacyPatch -{ -double recomputeDTG_MRG(bool triggered, double dtgMrg, double ens); -double recomputeENS_MRG(bool triggered, double dtgMrg, double ens); -double recomputeMRGPrice(double ensCsr, double originalCost, double unsuppliedEnergyCost); -} // namespace Antares::Data::AdequacyPatch diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h index 55cccc4e64..4d761bd558 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h @@ -56,13 +56,6 @@ void OPT_InitialiserLesCoutsLineaire(PROBLEME_HEBDO*, const int, const int); void OPT_InitialiserLesCoutsQuadratiques(PROBLEME_HEBDO*, int); bool OPT_AppelDuSolveurQuadratique(PROBLEME_ANTARES_A_RESOUDRE*, const int); -using namespace Antares::Data::AdequacyPatch; -bool ADQ_PATCH_CSR(PROBLEME_ANTARES_A_RESOUDRE&, - HourlyCSRProblem&, - const AdqPatchParams&, - uint week, - int year); - bool OPT_PilotageOptimisationLineaire(const OptimizationOptions& options, PROBLEME_HEBDO* problemeHebdo, Solver::IResultWriter& writer, diff --git a/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h b/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h index 4c3fd49bd1..b7e125ad03 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h @@ -69,16 +69,24 @@ class RemixHydroPostProcessCmd: public basePostProcessCommand SimplexOptimization splx_optimization_; }; -class DTGmarginForAdqPatchPostProcessCmd: public basePostProcessCommand +class UpdateMrgPriceAfterCSRcmd: public basePostProcessCommand { - using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams; - public: - DTGmarginForAdqPatchPostProcessCmd(PROBLEME_HEBDO* problemeHebdo, - AreaList& areas, - unsigned int numSpace); + UpdateMrgPriceAfterCSRcmd(PROBLEME_HEBDO* problemeHebdo, + AreaList& areas, + unsigned int numSpace); + void execute(const optRuntimeData&) override; - void execute(const optRuntimeData& opt_runtime_data) override; +private: + const AreaList& area_list_; + unsigned int numSpace_ = 0; +}; + +class DTGnettingAfterCSRcmd: public basePostProcessCommand +{ +public: + DTGnettingAfterCSRcmd(PROBLEME_HEBDO* problemeHebdo, AreaList& areas, unsigned int numSpace); + void execute(const optRuntimeData&) override; private: const AreaList& area_list_; @@ -112,8 +120,6 @@ class HydroLevelsFinalUpdatePostProcessCmd: public basePostProcessCommand class CurtailmentSharingPostProcessCmd: public basePostProcessCommand { - using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams; - public: CurtailmentSharingPostProcessCmd(const AdqPatchParams& adqPatchParams, PROBLEME_HEBDO* problemeHebdo, @@ -128,6 +134,7 @@ class CurtailmentSharingPostProcessCmd: public basePostProcessCommand std::set identifyHoursForCurtailmentSharing(const std::vector& sumENS) const; std::set getHoursRequiringCurtailmentSharing() const; + using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams; const AreaList& area_list_; const AdqPatchParams& adqPatchParams_; unsigned int numSpace_ = 0; diff --git a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp index 2f6f907c5a..304aab13df 100644 --- a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp +++ b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp @@ -214,10 +214,9 @@ static SimplexResult OPT_TryToCallSimplex(const OptimizationOptions& options, mps_writer->runIfNeeded(writer, filename); TimeMeasurement measure; - const bool keepBasis = (optimizationNumber == PREMIERE_OPTIMISATION); solver = ORTOOLS_Simplexe(&Probleme, solver, keepBasis, options); - if (solver) + if (solver != nullptr) { ProblemeAResoudre->ProblemesSpx[NumIntervalle] = (void*)solver; } diff --git a/src/solver/optimisation/post_process_commands.cpp b/src/solver/optimisation/post_process_commands.cpp index b069050960..3ddc06ddde 100644 --- a/src/solver/optimisation/post_process_commands.cpp +++ b/src/solver/optimisation/post_process_commands.cpp @@ -22,7 +22,6 @@ #include "antares/solver/optimisation/post_process_commands.h" #include "antares/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.h" -#include "antares/solver/optimisation/adequacy_patch_csr/post_processing.h" #include "antares/solver/simulation/adequacy_patch_runtime_data.h" #include "antares/solver/simulation/common-eco-adq.h" @@ -116,53 +115,84 @@ void RemixHydroPostProcessCmd::execute(const optRuntimeData& opt_runtime_data) hourInYear); } -// ----------------------------- -// DTG margin for adq patch -// ----------------------------- +// ---------------------------------- +// Update marginal price after CSR +// ---------------------------------- using namespace Antares::Data::AdequacyPatch; -DTGmarginForAdqPatchPostProcessCmd::DTGmarginForAdqPatchPostProcessCmd( - PROBLEME_HEBDO* problemeHebdo, - AreaList& areas, - unsigned int numSpace): +UpdateMrgPriceAfterCSRcmd::UpdateMrgPriceAfterCSRcmd(PROBLEME_HEBDO* problemeHebdo, + AreaList& areas, + unsigned int numSpace): basePostProcessCommand(problemeHebdo), area_list_(areas), numSpace_(numSpace) { } -/*! -** Calculate Dispatchable margin for all areas after CSR optimization and adjust ENS -** values if neccessary. If LOLD=1, Sets MRG COST to the max value (unsupplied energy cost) -** */ -void DTGmarginForAdqPatchPostProcessCmd::execute(const optRuntimeData&) +void UpdateMrgPriceAfterCSRcmd::execute(const optRuntimeData&) { for (uint32_t Area = 0; Area < problemeHebdo_->NombreDePays; Area++) { - if (problemeHebdo_->adequacyPatchRuntimeData->areaMode[Area] != physicalAreaInsideAdqPatch) + auto& hourlyResults = problemeHebdo_->ResultatsHoraires[Area]; + const auto& scratchpad = area_list_[Area]->scratchpad[numSpace_]; + const double unsuppliedEnergyCost = area_list_[Area]->thermal.unsuppliedEnergyCost; + const bool areaInside = problemeHebdo_->adequacyPatchRuntimeData->areaMode[Area] + == physicalAreaInsideAdqPatch; + for (uint hour = 0; hour < nbHoursInWeek; hour++) { - continue; + const bool isHourTriggeredByCsr = problemeHebdo_->adequacyPatchRuntimeData + ->wasCSRTriggeredAtAreaHour(Area, hour); + + if (isHourTriggeredByCsr + && hourlyResults.ValeursHorairesDeDefaillancePositive[hour] > 0.5 && areaInside) + { + hourlyResults.CoutsMarginauxHoraires[hour] = -unsuppliedEnergyCost; + } } + } +} + +// ----------------------------- +// DTG margin for adq patch +// ----------------------------- +DTGnettingAfterCSRcmd::DTGnettingAfterCSRcmd(PROBLEME_HEBDO* problemeHebdo, + AreaList& areas, + unsigned int numSpace): + basePostProcessCommand(problemeHebdo), + area_list_(areas), + numSpace_(numSpace) +{ +} + +void DTGnettingAfterCSRcmd::execute(const optRuntimeData&) +{ + for (uint32_t Area = 0; Area < problemeHebdo_->NombreDePays; Area++) + { + auto& hourlyResults = problemeHebdo_->ResultatsHoraires[Area]; + const auto& scratchpad = area_list_[Area]->scratchpad[numSpace_]; for (uint hour = 0; hour < nbHoursInWeek; hour++) { - auto& hourlyResults = problemeHebdo_->ResultatsHoraires[Area]; - const auto& scratchpad = area_list_[Area]->scratchpad[numSpace_]; + const bool isHourTriggeredByCsr = problemeHebdo_->adequacyPatchRuntimeData + ->wasCSRTriggeredAtAreaHour(Area, hour); + const double dtgMrg = scratchpad.dispatchableGenerationMargin[hour]; const double ens = hourlyResults.ValeursHorairesDeDefaillancePositive[hour]; - const bool triggered = problemeHebdo_->adequacyPatchRuntimeData - ->wasCSRTriggeredAtAreaHour(Area, hour); - hourlyResults.ValeursHorairesDtgMrgCsr[hour] = recomputeDTG_MRG(triggered, dtgMrg, ens); - hourlyResults.ValeursHorairesDeDefaillancePositiveCSR[hour] = recomputeENS_MRG( - triggered, - dtgMrg, - ens); - - const double unsuppliedEnergyCost = area_list_[Area]->thermal.unsuppliedEnergyCost; - hourlyResults.CoutsMarginauxHoraires[hour] = recomputeMRGPrice( - hourlyResults.ValeursHorairesDtgMrgCsr[hour], - hourlyResults.CoutsMarginauxHoraires[hour], - unsuppliedEnergyCost); + const bool areaInside = problemeHebdo_->adequacyPatchRuntimeData->areaMode[Area] + == physicalAreaInsideAdqPatch; + if (isHourTriggeredByCsr && areaInside) + { + hourlyResults.ValeursHorairesDtgMrgCsr[hour] = std::max(0.0, dtgMrg - ens); + hourlyResults.ValeursHorairesDeDefaillancePositiveCSR[hour] = std::max(0.0, + ens + - dtgMrg); + } + else + { + // Default value (when the hour is not triggered by CSR) + hourlyResults.ValeursHorairesDtgMrgCsr[hour] = dtgMrg; + hourlyResults.ValeursHorairesDeDefaillancePositiveCSR[hour] = ens; + } } } } diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index 78785f0fd3..dd7480671c 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -394,6 +394,7 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, problem.ResultatsHoraires[k].ValeursHorairesDeDefaillanceNegative.assign(NombreDePasDeTemps, 0.); + problem.ResultatsHoraires[k].TurbinageHoraire.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].PompageHoraire.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].CoutsMarginauxHoraires.assign(NombreDePasDeTemps, 0.); diff --git a/src/solver/variable/CMakeLists.txt b/src/solver/variable/CMakeLists.txt index 5022d5b542..ed7c017f5b 100644 --- a/src/solver/variable/CMakeLists.txt +++ b/src/solver/variable/CMakeLists.txt @@ -78,8 +78,9 @@ set(SRC_VARIABLE_ECONOMY include/antares/solver/variable/economy/links.h # Variables for Economy + include/antares/solver/variable/economy/max-mrg-utils.h + max-mrg-utils.cpp include/antares/solver/variable/economy/max-mrg.h - economy/max-mrg.cpp include/antares/solver/variable/economy/price.h include/antares/solver/variable/economy/balance.h include/antares/solver/variable/economy/operatingCost.h @@ -127,6 +128,7 @@ set(SRC_VARIABLE_ECONOMY include/antares/solver/variable/economy/links/congestionFeeAbs.h include/antares/solver/variable/economy/links/marginalCost.h include/antares/solver/variable/economy/links/congestionProbability.h + include/antares/solver/variable/economy/overallCostCsr.h # Binding constraints include/antares/solver/variable/economy/bindingConstraints/bindingConstraintsMarginalCost.h diff --git a/src/solver/variable/economy/max-mrg.cpp b/src/solver/variable/economy/max-mrg.cpp deleted file mode 100644 index 7cb565037f..0000000000 --- a/src/solver/variable/economy/max-mrg.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* -** 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/variable/economy/max-mrg.h" - -#include - -#include -#include - -using namespace Yuni; - -namespace Antares::Solver::Variable::Economy -{ -template -struct SpillageSelector -{ - template - static auto Value(const State&, - const U& weeklyResults, - uint) -> decltype(weeklyResults.ValeursHorairesDeDefaillanceNegative) - { - return weeklyResults.ValeursHorairesDeDefaillanceNegative; - } -}; - -template<> -struct SpillageSelector -{ - template - static auto Value(const State& state, const U&, uint index) -> decltype(state.resSpilled[index]) - { - return state.resSpilled[index]; - } -}; - -template -inline void PrepareMaxMRGFor(const State& state, double* opmrg, uint numSpace) -{ - assert(168 + state.hourInTheYear <= HOURS_PER_YEAR); - assert(opmrg && "Invalid OP.MRG target"); - - enum - { - offset = 0, - endHour = 168, - }; - - // current area - auto& area = *state.area; - // index of the current area - auto index = area.index; - assert(area.index < 50000 && "seems invalid"); - - // current problem - auto& problem = *state.problemeHebdo; - // Weekly results from solver for the current area - auto& weeklyResults = problem.ResultatsHoraires[index]; - // Unsupplied enery for the current area - auto& D = weeklyResults.ValeursHorairesDeDefaillancePositive; - // Spillage - auto S = SpillageSelector::Value(state, weeklyResults, area.index); - - double OI[168]; - - // H.STOR - std::vector& H = weeklyResults.TurbinageHoraire; - - // energie turbinee de la semaine - { - // DTG MRG - const double* M = area.scratchpad[numSpace].dispatchableGenerationMargin; - - double WH = 0.; - { - // H.STOR - for (uint i = offset; i != endHour; ++i) - { - WH += H[i]; - } - } - - if (Utils::isZero(WH)) // no hydro - { - for (uint i = offset; i != endHour; ++i) - { - opmrg[i] = +S[i] + M[i] - D[i]; - } - return; - } - - // initialisation - for (uint i = offset; i != endHour; ++i) - { - OI[i] = +S[i] + M[i] - D[i]; - } - } - - double bottom = +std::numeric_limits::max(); - double top = 0; - - for (uint i = offset; i != endHour; ++i) - { - double oii = OI[i]; - if (oii > top) - { - top = oii; - } - if (oii < bottom) - { - bottom = oii; - } - } - - double ecart = 1.; - uint loop = 100; // arbitrary - maximum number of iterations - - // Pmax - const uint y = problem.year; - const auto& P = area.hydro.series->maxHourlyGenPower; - - do - { - double niveau = (top + bottom) * 0.5; - double SP = 0; // S+ - double SM = 0; // S- - - for (uint i = offset; i != endHour; ++i) - { - assert(i < HOURS_PER_YEAR && "calendar overflow"); - if (niveau > OI[i]) - { - opmrg[i] = std::min(niveau, - OI[i] + P.getCoefficient(y, i + state.hourInTheYear) - H[i]); - SM += opmrg[i] - OI[i]; - } - else - { - opmrg[i] = std::max(niveau, OI[i] - H[i]); - SP += OI[i] - opmrg[i]; - } - } - - ecart = SP - SM; - if (ecart > 0) - { - bottom = niveau; - } - else - { - top = niveau; - } - - if (!--loop) - { - logs.error() << "OP.MRG: " << area.name - << ": infinite loop detected. please check input data"; - return; - } - } while (ecart * ecart > 0.25); -} - -void PrepareMaxMRG(const State& state, double* opmrg, uint numSpace) -{ - if (state.simplexRunNeeded) - { - PrepareMaxMRGFor(state, opmrg, numSpace); - } - else - { - PrepareMaxMRGFor(state, opmrg, numSpace); - } -} - -} // namespace Antares::Solver::Variable::Economy diff --git a/src/solver/variable/include/antares/solver/variable/economy/all.h b/src/solver/variable/include/antares/solver/variable/economy/all.h index 8e1c2ed307..17207c22db 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/all.h +++ b/src/solver/variable/include/antares/solver/variable/economy/all.h @@ -49,12 +49,16 @@ #include "inflow.h" #include "localMatchingRuleViolations.h" #include "lold.h" +#include "loldCsr.h" #include "lolp.h" +#include "lolpCsr.h" +#include "max-mrg-csr.h" #include "max-mrg.h" #include "nbOfDispatchedUnits.h" #include "nonProportionalCost.h" #include "operatingCost.h" #include "overallCost.h" +#include "overallCostCsr.h" #include "overflow.h" #include "pumping.h" #include "renewableGeneration.h" @@ -91,59 +95,62 @@ namespace Antares::Solver::Variable::Economy /*! ** \brief All variables for a single area (economy) */ -typedef // Prices - OverallCost // Overall Cost (Op. Cost + Unsupplied Eng.) - >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +typedef // Prices + OverallCost // Overall Cost (Op. Cost + Unsupplied Eng.) + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VariablesPerArea; /*! diff --git a/src/solver/variable/include/antares/solver/variable/economy/loldCsr.h b/src/solver/variable/include/antares/solver/variable/economy/loldCsr.h new file mode 100644 index 0000000000..299e83b94f --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/loldCsr.h @@ -0,0 +1,242 @@ +/* +** 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 +*/ +#pragma once + +#include "../variable.h" + +namespace Antares::Solver::Variable::Economy +{ + +struct VCardLOLD_CSR +{ + //! Caption + static std::string Caption() + { + return "LOLD CSR"; + } + + //! Unit + static std::string Unit() + { + return "Hours"; + } + + //! The short description of the variable + static std::string Description() + { + return "LOLD for CSR"; + } + + //! The expecte results + typedef Results>>>> + ResultsType; + + static constexpr uint8_t categoryDataLevel = Category::DataLevel::area; + //! File level (provided by the type of the results) + static constexpr uint8_t categoryFileLevel = ResultsType::categoryFile + & (Category::FileLevel::id + | Category::FileLevel::va); + //! Precision (views) + static constexpr uint8_t precision = Category::all; + //! Indentation (GUI) + static constexpr uint8_t nodeDepthForGUI = +0; + //! Decimal precision + static constexpr uint8_t decimal = 2; + //! Number of columns used by the variable (One ResultsType per column) + static constexpr int columnCount = 1; + //! The Spatial aggregation + static constexpr uint8_t spatialAggregate = Category::spatialAggregateSum; + static constexpr uint8_t spatialAggregateMode = Category::spatialAggregateEachYear; + static constexpr uint8_t spatialAggregatePostProcessing = 0; + //! Intermediate values + static constexpr uint8_t hasIntermediateValues = 1; + //! Can this variable be non applicable (0 : no, 1 : yes) + static constexpr uint8_t isPossiblyNonApplicable = 0; + + typedef IntermediateValues IntermediateValuesBaseType; + typedef IntermediateValues* IntermediateValuesType; + + typedef IntermediateValuesBaseType* IntermediateValuesTypeForSpatialAg; + +}; // class VCard + +/*! +** \brief +*/ +template +class LOLD_CSR: public Variable::IVariable, NextT, VCardLOLD_CSR> +{ +public: + //! Type of the next static variable + typedef NextT NextType; + //! VCard + typedef VCardLOLD_CSR 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: + ~LOLD_CSR() + { + delete[] pValuesForTheCurrentYear; + } + + void initializeFromStudy(Data::Study& study) + { + pNbYearsParallel = study.maxNbYearsInParallel; + + // Intermediate values + 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 simulationBegin() + { + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + { + pValuesForTheCurrentYear[numSpace].reset(); + } + // Next + NextType::simulationBegin(); + } + + 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 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 hourForEachArea(State& state, unsigned int numSpace) + { + if (state.hourlyResults->ValeursHorairesDeDefaillancePositiveCSR[state.hourInTheWeek] > 0.5) + { + pValuesForTheCurrentYear[numSpace][state.hourInTheYear] = 1.; + } + + // 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 LOLD_CSR + +} // namespace Antares::Solver::Variable::Economy diff --git a/src/solver/variable/include/antares/solver/variable/economy/lolpCsr.h b/src/solver/variable/include/antares/solver/variable/economy/lolpCsr.h new file mode 100644 index 0000000000..45d9ed61ac --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/lolpCsr.h @@ -0,0 +1,242 @@ +/* +** 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 +*/ +#pragma once + +#include "../variable.h" + +namespace Antares::Solver::Variable::Economy +{ +struct VCardLOLP_CSR +{ + //! Caption + static std::string Caption() + { + return "LOLP CSR"; + } + + //! Unit + static std::string Unit() + { + return "%"; + } + + //! The short description of the variable + static std::string Description() + { + return "LOLP for CSR"; + } + + //! The expecte results + typedef Results> + ResultsType; + + //! The VCard to look for for calculating spatial aggregates + typedef VCardLOLP_CSR VCardForSpatialAggregate; + + static constexpr uint8_t categoryDataLevel = Category::DataLevel::area; + //! File level (provided by the type of the results) + static constexpr uint8_t categoryFileLevel = ResultsType::categoryFile + & (Category::FileLevel::id + | Category::FileLevel::va); + //! Precision (views) + static constexpr uint8_t precision = Category::all; + //! Indentation (GUI) + static constexpr uint8_t nodeDepthForGUI = +0; + //! Decimal precision + static constexpr uint8_t decimal = 2; + //! Number of columns used by the variable (One ResultsType per column) + static constexpr int columnCount = 1; + //! The Spatial aggregation + static constexpr uint8_t spatialAggregate = Category::spatialAggregateSum; + static constexpr uint8_t spatialAggregateMode = Category::spatialAggregateEachYear; + static constexpr uint8_t spatialAggregatePostProcessing = 0; + //! Intermediate values + static constexpr uint8_t hasIntermediateValues = 1; + //! Can this variable be non applicable (0 : no, 1 : yes) + static constexpr uint8_t isPossiblyNonApplicable = 0; + + typedef IntermediateValues IntermediateValuesBaseType; + typedef IntermediateValues* IntermediateValuesType; + + typedef IntermediateValuesBaseType* IntermediateValuesTypeForSpatialAg; + +}; // class VCard + +/*! +** \brief +*/ +template +class LOLP_CSR: public Variable::IVariable, NextT, VCardLOLP_CSR> +{ +public: + //! Type of the next static variable + typedef NextT NextType; + //! VCard + typedef VCardLOLP_CSR 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: + ~LOLP_CSR() + { + delete[] pValuesForTheCurrentYear; + } + + void initializeFromStudy(Data::Study& study) + { + pNbYearsParallel = study.maxNbYearsInParallel; + + // Intermediate values + 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 simulationBegin() + { + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + { + pValuesForTheCurrentYear[numSpace].reset(); + } + // Next + NextType::simulationBegin(); + } + + 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 yearEnd(unsigned int year, unsigned int numSpace) + { + // Compute all statistics for the current year (daily,weekly,monthly) + pValuesForTheCurrentYear[numSpace].computeStatisticsOrForTheCurrentYear(); + + // 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 hourForEachArea(State& state, unsigned int numSpace) + { + if (state.hourlyResults->ValeursHorairesDeDefaillancePositiveCSR[state.hourInTheWeek] > 0.5) + { + pValuesForTheCurrentYear[numSpace][state.hourInTheYear] = 100; + } + + // 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 LOLP_CSR + +} // namespace Antares::Solver::Variable::Economy diff --git a/src/solver/variable/include/antares/solver/variable/economy/max-mrg-csr.h b/src/solver/variable/include/antares/solver/variable/economy/max-mrg-csr.h new file mode 100644 index 0000000000..2ff8edc89d --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/max-mrg-csr.h @@ -0,0 +1,243 @@ +/* +** 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 +*/ +#pragma once + +#include "../variable.h" +#include "max-mrg-utils.h" + +namespace Antares::Solver::Variable::Economy +{ +struct VCardMAX_MRG_CSR +{ + //! Caption + static std::string Caption() + { + return "MAX MRG CSR"; + } + + //! Unit + static std::string Unit() + { + return "MWh"; + } + + //! The short description of the variable + static std::string Description() + { + return "Max margin for CSR"; + } + + //! The expecte results + typedef Results>>>> + ResultsType; + + //! The VCard to look for for calculating spatial aggregates + typedef VCardMAX_MRG_CSR VCardForSpatialAggregate; + + static constexpr uint8_t categoryDataLevel = Category::DataLevel::area; + //! File level (provided by the type of the results) + static constexpr uint8_t categoryFileLevel = ResultsType::categoryFile + & (Category::FileLevel::id + | Category::FileLevel::va); + //! Precision (views) + static constexpr uint8_t precision = Category::all; + //! Indentation (GUI) + static constexpr uint8_t nodeDepthForGUI = +0; + //! Decimal precision + static constexpr uint8_t decimal = 0; + //! Number of columns used by the variable (One ResultsType per column) + static constexpr int columnCount = 1; + //! The Spatial aggregation + static constexpr uint8_t spatialAggregate = Category::spatialAggregateSum; + static constexpr uint8_t spatialAggregateMode = Category::spatialAggregateEachYear; + static constexpr uint8_t spatialAggregatePostProcessing = 0; + //! Intermediate values + static constexpr uint8_t hasIntermediateValues = 1; + //! Can this variable be non applicable (0 : no, 1 : yes) + static constexpr uint8_t isPossiblyNonApplicable = 0; + + typedef IntermediateValues IntermediateValuesBaseType; + typedef IntermediateValues* IntermediateValuesType; + + typedef IntermediateValuesBaseType* IntermediateValuesTypeForSpatialAg; + +}; // class VCard + +/*! +** \brief Prepare MAX.MRG results for a given week +*/ +template +void PrepareMaxMRGFor(const State& state, double* opmrg, uint numSpace); + +/*! +** \brief Max MRG +*/ +template +class MaxMrgCsr: public Variable::IVariable, NextT, VCardMAX_MRG_CSR> +{ +public: + //! Type of the next static variable + typedef NextT NextType; + //! VCard + typedef VCardMAX_MRG_CSR 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: + ~MaxMrgCsr() + { + delete[] pValuesForTheCurrentYear; + } + + void initializeFromStudy(Data::Study& study) + { + pNbYearsParallel = study.maxNbYearsInParallel; + + // Intermediate values + 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 yearBegin(unsigned int year, unsigned int numSpace) + { + // Reset the values for the current year + pValuesForTheCurrentYear[numSpace].reset(); + // Next variable + NextType::yearBegin(year, numSpace); + } + + 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 weekForEachArea(State& state, unsigned int numSpace) + { + double* rawhourly = Memory::RawPointer(pValuesForTheCurrentYear[numSpace].hour); + + // Getting data required to compute max margin + MaxMrgCSRdataFactory maxMRGcsrDataFactory(state, numSpace); + MaxMRGinput maxMRGinput = maxMRGcsrDataFactory.data(); + computeMaxMRG(rawhourly + state.hourInTheYear, maxMRGinput); + + // next + NextType::weekForEachArea(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 MaxMrgCsr + +} // namespace Antares::Solver::Variable::Economy diff --git a/src/solver/variable/include/antares/solver/variable/economy/max-mrg-utils.h b/src/solver/variable/include/antares/solver/variable/economy/max-mrg-utils.h new file mode 100644 index 0000000000..2a5de71b74 --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/max-mrg-utils.h @@ -0,0 +1,56 @@ +#pragma once + +#include + +#include "../state.h" + +namespace Antares::Solver::Variable::Economy +{ + +struct MaxMRGinput +{ + double* spillage = nullptr; + double* dens = nullptr; + double* hydroGeneration = nullptr; + Antares::Data::TimeSeries* maxHourlyGenPower = nullptr; + double* dtgMargin = nullptr; + unsigned int hourInYear = 0; + unsigned int year = 0; + Date::Calendar* calendar = nullptr; + std::string areaName; +}; + +void computeMaxMRG(double* maxMrgOut, const MaxMRGinput& in); + +class MaxMrgDataFactory +{ +public: + MaxMrgDataFactory(const State& state, unsigned int numSpace); + virtual MaxMRGinput data() = 0; + +protected: + // in data + const State& state_; + const unsigned int numSpace_ = 0; + RESULTATS_HORAIRES& weeklyResults_; + // data to be built + MaxMRGinput maxMRGinput_; +}; + +class MaxMrgUsualDataFactory: public MaxMrgDataFactory +{ + using MaxMrgDataFactory::MaxMrgDataFactory; + +public: + virtual MaxMRGinput data() override; +}; + +class MaxMrgCSRdataFactory: public MaxMrgDataFactory +{ + using MaxMrgDataFactory::MaxMrgDataFactory; + +public: + virtual MaxMRGinput data() override; +}; + +} // namespace Antares::Solver::Variable::Economy diff --git a/src/solver/variable/include/antares/solver/variable/economy/max-mrg.h b/src/solver/variable/include/antares/solver/variable/economy/max-mrg.h index 959d6f16e7..a53b893947 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/max-mrg.h +++ b/src/solver/variable/include/antares/solver/variable/economy/max-mrg.h @@ -23,6 +23,8 @@ #include "antares/solver/variable/variable.h" +#include "max-mrg-utils.h" + namespace Antares { namespace Solver @@ -92,11 +94,6 @@ struct VCardMARGE }; // class VCard -/*! -** \brief Prepare MAX.MRG results for a given week -*/ -void PrepareMaxMRG(const State& state, double* opmrg, uint numSpace); - /*! ** \brief Max MRG */ @@ -206,8 +203,6 @@ class Marge: public Variable::IVariable, NextT, VCardMARGE> { // Compute all statistics for the current year (daily,weekly,monthly) pValuesForTheCurrentYear[numSpace].computeStatisticsForTheCurrentYear(); - // Merge all those values with the global results - // AncestorType::pResults.merge(year, pValuesForTheCurrentYear); // Next variable NextType::yearEnd(year, numSpace); @@ -242,7 +237,11 @@ class Marge: public Variable::IVariable, NextT, VCardMARGE> void weekForEachArea(State& state, unsigned int numSpace) { double* rawhourly = Memory::RawPointer(pValuesForTheCurrentYear[numSpace].hour); - PrepareMaxMRG(state, rawhourly + state.hourInTheYear, numSpace); + + // Getting data required to compute max margin + MaxMrgUsualDataFactory maxMRGdataFactory(state, numSpace); + MaxMRGinput maxMRGinput = maxMRGdataFactory.data(); + computeMaxMRG(rawhourly + state.hourInTheYear, maxMRGinput); // next NextType::weekForEachArea(state, numSpace); diff --git a/src/solver/variable/include/antares/solver/variable/economy/overallCostCsr.h b/src/solver/variable/include/antares/solver/variable/economy/overallCostCsr.h new file mode 100644 index 0000000000..63739b686b --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/overallCostCsr.h @@ -0,0 +1,253 @@ +/* +** 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 +*/ +#pragma once + +#include "../variable.h" + +namespace Antares::Solver::Variable::Economy +{ +struct VCardOverallCostCsr +{ + //! Caption + static std::string Caption() + { + return "OV. COST CSR"; + } + + //! Unit + static std::string Unit() + { + return "Euro"; + } + + //! The short description of the variable + static std::string Description() + { + return "Overall Cost throughout all MC years"; + } + + //! The expecte results + typedef Results, + R::AllYears::Average // Use these values for spatial cluster + > + ResultsType; + + //! The VCard to look for for calculating spatial aggregates + typedef VCardOverallCostCsr VCardForSpatialAggregate; + + static constexpr uint8_t categoryDataLevel = Category::DataLevel::area; + //! File level (provided by the type of the results) + static constexpr uint8_t categoryFileLevel = ResultsType::categoryFile + & (Category::FileLevel::id + | Category::FileLevel::va); + //! Precision (views) + static constexpr uint8_t precision = Category::all; + //! Indentation (GUI) + static constexpr uint8_t nodeDepthForGUI = +0; + //! Decimal precision + static constexpr uint8_t decimal = 0; + //! Number of columns used by the variable (One ResultsType per column) + static constexpr int columnCount = 1; + //! The Spatial aggregation + static constexpr uint8_t spatialAggregate = Category::spatialAggregateSum; + static constexpr uint8_t spatialAggregateMode = Category::spatialAggregateEachYear; + static constexpr uint8_t spatialAggregatePostProcessing = 0; + //! Intermediate values + static constexpr uint8_t hasIntermediateValues = 1; + //! Can this variable be non applicable (0 : no, 1 : yes) + static constexpr uint8_t isPossiblyNonApplicable = 0; + + typedef IntermediateValues IntermediateValuesBaseType; + typedef IntermediateValues* IntermediateValuesType; + + typedef IntermediateValuesBaseType* IntermediateValuesTypeForSpatialAg; + +}; // class VCard + +/*! +** \brief C02 Average value of the overall OverallCostCsr emissions expected from all +** the thermal dispatchable clusters +*/ +template +class OverallCostCsr: public Variable::IVariable, NextT, VCardOverallCostCsr> +{ +public: + //! Type of the next static variable + typedef NextT NextType; + //! VCard + typedef VCardOverallCostCsr 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: + ~OverallCostCsr() + { + delete[] pValuesForTheCurrentYear; + } + + void initializeFromStudy(Data::Study& study) + { + pNbYearsParallel = study.maxNbYearsInParallel; + + // Intermediate values + InitializeResultsFromStudy(AncestorType::pResults, study); + + // Intermediate values + pValuesForTheCurrentYear = new VCardType::IntermediateValuesBaseType[pNbYearsParallel]; + for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) + { + pValuesForTheCurrentYear[numSpace].initializeFromStudy(study); + } + + NextType::initializeFromStudy(study); + } + + template + static void InitializeResultsFromStudy(R& results, Data::Study& study) + { + VariableAccessorType::InitializeAndReset(results, study); + } + + void yearBegin(unsigned int year, unsigned int numSpace) + { + // Reset the values for the current year + pValuesForTheCurrentYear[numSpace].reset(); + + NextType::yearBegin(year, numSpace); + } + + void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) + { + for (unsigned int i = state.study.runtime.rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd]; + ++i) + { + pValuesForTheCurrentYear[numSpace][i] += state.thermalClusterOperatingCostForYear[i]; + } + + NextType::yearEndBuildForEachThermalCluster(state, year, numSpace); + } + + void yearEnd(unsigned int year, unsigned int numSpace) + { + // Compute all statistics for the current year (daily, weekly, monthly) + pValuesForTheCurrentYear[numSpace].computeStatisticsForTheCurrentYear(); + + 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]); + } + + NextType::computeSummary(numSpaceToYear, nbYearsForCurrentSummary); + } + + void hourForEachArea(State& state, unsigned int numSpace) + { + const double costForSpilledOrUnsuppliedEnergyCSR = + // Total UnsupliedEnergy emissions + (state.hourlyResults->ValeursHorairesDeDefaillancePositiveCSR[state.hourInTheWeek] + * state.area->thermal.unsuppliedEnergyCost) + + (state.hourlyResults->ValeursHorairesDeDefaillanceNegative[state.hourInTheWeek] + * state.area->thermal.spilledEnergyCost) + // Current hydro storage and pumping generation costs + + (state.hourlyResults->valeurH2oHoraire[state.hourInTheWeek] + * (state.hourlyResults->TurbinageHoraire[state.hourInTheWeek] + - state.area->hydro.pumpingEfficiency + * state.hourlyResults->PompageHoraire[state.hourInTheWeek])); + + pValuesForTheCurrentYear[numSpace][state.hourInTheYear] + += costForSpilledOrUnsuppliedEnergyCSR; + + 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 OverallCostCsr + +} // namespace Antares::Solver::Variable::Economy diff --git a/src/solver/variable/include/antares/solver/variable/economy/unsupliedEnergyCsr.h b/src/solver/variable/include/antares/solver/variable/economy/unsupliedEnergyCsr.h index e4a989de2c..a83ccb2e03 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/unsupliedEnergyCsr.h +++ b/src/solver/variable/include/antares/solver/variable/economy/unsupliedEnergyCsr.h @@ -60,8 +60,6 @@ struct VCardUnsupliedEnergyCSR //! The VCard to look for for calculating spatial aggregates typedef VCardUnsupliedEnergyCSR VCardForSpatialAggregate; - - //! Data Level static constexpr uint8_t categoryDataLevel = Category::DataLevel::area; //! File level (provided by the type of the results) static constexpr uint8_t categoryFileLevel = ResultsType::categoryFile diff --git a/src/solver/variable/max-mrg-utils.cpp b/src/solver/variable/max-mrg-utils.cpp new file mode 100644 index 0000000000..bfa93c1567 --- /dev/null +++ b/src/solver/variable/max-mrg-utils.cpp @@ -0,0 +1,171 @@ +/* +** 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 +#include +#include + +using namespace Yuni; + +const unsigned int nbHoursInWeek = 168; + +namespace Antares::Solver::Variable::Economy +{ + +MaxMrgDataFactory::MaxMrgDataFactory(const State& state, unsigned int numSpace): + state_(state), + numSpace_(numSpace), + weeklyResults_(state.problemeHebdo->ResultatsHoraires[state.area->index]) +{ + maxMRGinput_.hydroGeneration = weeklyResults_.TurbinageHoraire.data(); + maxMRGinput_.maxHourlyGenPower = &state_.area->hydro.series->maxHourlyGenPower; + maxMRGinput_.dtgMargin = state_.area->scratchpad[numSpace].dispatchableGenerationMargin; + maxMRGinput_.hourInYear = state.hourInTheYear; + maxMRGinput_.year = state.problemeHebdo->year; + maxMRGinput_.calendar = &state.study.calendar; + maxMRGinput_.areaName = state_.area->name.c_str(); +} + +MaxMRGinput MaxMrgUsualDataFactory::data() +{ + if (state_.simplexRunNeeded) + { + maxMRGinput_.spillage = weeklyResults_.ValeursHorairesDeDefaillanceNegative.data(); + } + else + { + maxMRGinput_.spillage = state_.resSpilled[state_.area->index]; + } + + maxMRGinput_.dens = weeklyResults_.ValeursHorairesDeDefaillancePositive.data(); + return maxMRGinput_; +} + +MaxMRGinput MaxMrgCSRdataFactory::data() +{ + maxMRGinput_.spillage = weeklyResults_.ValeursHorairesDeDefaillanceNegative.data(); + maxMRGinput_.dens = weeklyResults_.ValeursHorairesDeDefaillancePositiveCSR.data(); + return maxMRGinput_; +} + +void computeMaxMRG(double* maxMrgOut, const MaxMRGinput& in) +{ + assert(maxMrgOut && "Invalid OP.MRG target"); + + // Following block could be replaced with : + // double weekHydroGen = std::accumulate(in.hydroGeneration, in.hydroGeneration + nbHoursInWeek, + // 0.); + double weekHydroGen = 0.; + for (uint h = 0; h != nbHoursInWeek; ++h) + { + weekHydroGen += in.hydroGeneration[h]; + } + + if (Yuni::Math::Zero(weekHydroGen)) + { + for (uint h = 0; h != nbHoursInWeek; ++h) + { + maxMrgOut[h] = in.spillage[h] + in.dtgMargin[h] - in.dens[h]; + } + return; + } + + // Initialisation + std::vector OI(nbHoursInWeek); + for (uint h = 0; h != nbHoursInWeek; ++h) + { + OI[h] = in.spillage[h] + in.dtgMargin[h] - in.dens[h]; + } + + // Following block could be replaced with : + // double bottom = *std::min_element(OI.begin(), OI.end()); + // double top = *std::max_element(OI.begin(), OI.end()); + double bottom = +std::numeric_limits::max(); + double top = 0; + for (uint i = 0; i != nbHoursInWeek; ++i) + { + double oii = OI[i]; + if (oii > top) + { + top = oii; + } + if (oii < bottom) + { + bottom = oii; + } + } + + double ecart = 1.; + uint loop = 100; // arbitrary - maximum number of iterations + + do + { + double niveau = (top + bottom) * 0.5; + double SP = 0; // S+ + double SM = 0; // S- + + for (uint h = 0; h != nbHoursInWeek; ++h) + { + assert(h < HOURS_PER_YEAR && "calendar overflow"); + if (niveau > OI[h]) + { + maxMrgOut[h] = Math::Min(niveau, + OI[h] + + in.maxHourlyGenPower->getCoefficient(in.year, + h + in.hourInYear) + - in.hydroGeneration[h]); + SM += maxMrgOut[h] - OI[h]; + } + else + { + maxMrgOut[h] = Math::Max(niveau, OI[h] - in.hydroGeneration[h]); + SP += OI[h] - maxMrgOut[h]; + } + } + + ecart = SP - SM; + if (ecart > 0) + { + bottom = niveau; + } + else + { + top = niveau; + } + + if (!--loop) + { + logs.error() << "OP.MRG: " << in.areaName + << ": infinite loop detected. please check input data"; + return; + } + } while (ecart * ecart > 0.25); +} + +} // namespace Antares::Solver::Variable::Economy diff --git a/src/tests/src/libs/antares/writer/test_zip_writer.cpp b/src/tests/src/libs/antares/writer/test_zip_writer.cpp new file mode 100644 index 0000000000..ffa0d89fed --- /dev/null +++ b/src/tests/src/libs/antares/writer/test_zip_writer.cpp @@ -0,0 +1,127 @@ +/* +** 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 +*/ +#define BOOST_TEST_MODULE test - writer tests + +#include +#include + +#include "yuni/job/queue/service.h" + +#include "antares/benchmarking/DurationCollector.h" +#include "antares/writer/i_writer.h" +#include "antares/writer/writer_factory.h" + +#include "utils.h" + +extern "C" +{ +#include +#include +#include +#include +} + +using namespace Yuni::Job; +using Antares::Solver::IResultWriter; +using Benchmarking::IDurationCollector; +using Benchmarking::NullDurationCollector; + +// Handles lifetime of necessary objects +struct TestContext +{ + std::shared_ptr threadPool; + std::unique_ptr durationCollector; + std::shared_ptr writer; +}; + +std::shared_ptr createThreadPool(int size) +{ + auto threadPool = std::make_shared(); + threadPool->maximumThreadCount(size); + threadPool->start(); + return threadPool; +} + +std::string removeExtension(const std::string& name, const std::string& ext) +{ + int length = name.size(); + if (name.size() > ext.size() && name.substr(length - ext.size()) == ext) + { + return name.substr(0, length - ext.size()); + } + return name; +} + +TestContext createContext(const std::filesystem::path zipPath, int threadCount) +{ + auto threadPool = createThreadPool(threadCount); + std::unique_ptr + durationCollector = std::make_unique(); + std::string archiveName = zipPath.string(); + auto writer = Antares::Solver::resultWriterFactory(Antares::Data::zipArchive, + removeExtension(zipPath.string(), ".zip"), + threadPool, + *durationCollector); + return {threadPool, std::move(durationCollector), writer}; +} + +using ZipReaderHandle = void*; + +void checkZipContent(ZipReaderHandle handle, + const std::string& path, + const std::string& expectedContent) +{ + BOOST_CHECK(mz_zip_reader_locate_entry(handle, path.c_str(), 0) == MZ_OK); + BOOST_CHECK(mz_zip_reader_entry_open(handle) == MZ_OK); + char buffer[4096]; + int bytesRead = mz_zip_reader_entry_read(handle, buffer, sizeof(buffer)); + std::string stringRead(buffer, bytesRead); + BOOST_CHECK(stringRead == expectedContent); + mz_zip_reader_entry_close(handle); +} + +BOOST_AUTO_TEST_CASE(test_zip) +{ + // Writer some content to test.zip, possibly from 2 threads + auto working_tmp_dir = CREATE_TMP_DIR_BASED_ON_TEST_NAME(); + auto zipPath = working_tmp_dir / "test.zip"; + auto context = createContext(zipPath, 2); + std::string content1 = "test-content1"; + std::string content2 = "test-content2"; + context.writer->addEntryFromBuffer("test-path", content1); + context.writer->addEntryFromBuffer("test-second-path", content2); + context.writer->flush(); + context.writer->finalize(true); + + // Check content is correct + ZipReaderHandle readerHandle = mz_zip_reader_create(); + std::string zipPathStr = zipPath.string(); + BOOST_CHECK(mz_zip_reader_open_file(readerHandle, zipPathStr.c_str()) == MZ_OK); + checkZipContent(readerHandle, "test-path", "test-content1"); + checkZipContent(readerHandle, "test-second-path", "test-content2"); + mz_zip_reader_close(readerHandle); +} diff --git a/src/tests/src/solver/optimisation/adequacy_patch.cpp b/src/tests/src/solver/optimisation/adequacy_patch.cpp new file mode 100644 index 0000000000..f6c5fddeb0 --- /dev/null +++ b/src/tests/src/solver/optimisation/adequacy_patch.cpp @@ -0,0 +1,386 @@ +#define BOOST_TEST_MODULE test adequacy patch functions + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include + +#include + +#include +#include "antares/study/parameters/adq-patch-params.h" + +#include "adequacy_patch_csr/adq_patch_curtailment_sharing.h" +#include "adequacy_patch_local_matching/adq_patch_local_matching.h" + +static double origineExtremite = -1; +static double extremiteOrigine = 5; + +using namespace Antares::Data::AdequacyPatch; +namespace tt = boost::test_tools; + +static const double flowArea0toArea1_positive = 10; +static const double flowArea0toArea1_negative = -10; +static const double flowArea2toArea0_positive = 30; +static const double flowArea2toArea0_negative = -30; +static const double positiveEnsInit = 50.0; + +std::pair calculateAreaFlowBalanceForOneTimeStep( + double ensInit, + bool includeFlowsOutsideAdqPatchToDensNew, + AdequacyPatchMode Area1Mode, + AdequacyPatchMode Area2Mode, + double flowToArea1, + double flowFromArea2) +{ + PROBLEME_HEBDO problem; + int Area = 0; + uint hour = 0; + + // allocate memory + problem.adequacyPatchRuntimeData = std::make_shared(); + problem.adequacyPatchRuntimeData->originAreaMode.resize(3); + problem.adequacyPatchRuntimeData->extremityAreaMode.resize(3); + + AdqPatchParams adqPatchParams; + + problem.ResultatsHoraires.resize(1); + problem.ResultatsHoraires[0].ValeursHorairesDeDefaillancePositive = std::vector(1); + problem.ValeursDeNTC = std::vector(1); + problem.ValeursDeNTC[0].ValeurDuFlux = std::vector(3); + problem.IndexSuivantIntercoOrigine = std::vector(3); + problem.IndexSuivantIntercoExtremite = std::vector(3); + problem.IndexDebutIntercoOrigine = std::vector(1); + problem.IndexDebutIntercoExtremite = std::vector(1); + + // input values + adqPatchParams.localMatching.setToZeroOutsideInsideLinks + = !includeFlowsOutsideAdqPatchToDensNew; + problem.ResultatsHoraires[Area].ValeursHorairesDeDefaillancePositive[hour] = ensInit; + int Interco = 1; + problem.IndexDebutIntercoOrigine[Area] = Interco; + problem.adequacyPatchRuntimeData->extremityAreaMode[Interco] = Area1Mode; + problem.ValeursDeNTC[hour].ValeurDuFlux[Interco] = flowToArea1; + problem.IndexSuivantIntercoOrigine[Interco] = -1; + + Interco = 2; + problem.IndexDebutIntercoExtremite[Area] = Interco; + problem.adequacyPatchRuntimeData->originAreaMode[Interco] = Area2Mode; + problem.ValeursDeNTC[hour].ValeurDuFlux[Interco] = flowFromArea2; + problem.IndexSuivantIntercoExtremite[Interco] = -1; + + // get results + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew, std::ignore) = calculateAreaFlowBalance( + &problem, + adqPatchParams.localMatching.setToZeroOutsideInsideLinks, + Area, + hour); + + return std::make_pair(netPositionInit, densNew); +} + +AdqPatchParams createParams() +{ + AdqPatchParams p; + p.enabled = true; + p.curtailmentSharing.includeHurdleCost = true; + p.curtailmentSharing.priceTakingOrder = AdqPatchPTO::isDens; + + return p; +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 virtual-area, and Area2-virtual area +// flow from Area0 -> Area1 is positive +// flow from Area2 -> Area0 is positive +// DensNew parameter should NOT include flows from areas outside adq patch +BOOST_AUTO_TEST_CASE( + calculateAreaFlowBalanceForOneTimeStep_virtual_virtual_NotIncludeOut_positiveFlow) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + 0.0, + false, + virtualArea, + virtualArea, + flowArea0toArea1_positive, + flowArea2toArea0_positive); + BOOST_CHECK_EQUAL(netPositionInit, 0.0); + BOOST_CHECK_EQUAL(densNew, 0.0); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area inside adq-patch, and Area2-virtual area +// flow from Area0 -> Area1 is positive +// flow from Area2 -> Area0 is positive +// DensNew parameter should NOT include flows from areas outside adq patch +BOOST_AUTO_TEST_CASE( + calculateAreaFlowBalanceForOneTimeStep_inside_virtual_NotIncludeOut_positiveFlow) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + 0.0, + false, + physicalAreaInsideAdqPatch, + virtualArea, + flowArea0toArea1_positive, + flowArea2toArea0_positive); + BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive); + BOOST_CHECK_EQUAL(densNew, 0.0); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area inside adq-patch, and Area2-virtual area +// flow from Area0 -> Area1 is positive +// flow from Area2 -> Area0 is positive +// DensNew parameter should NOT include flows from areas outside adq patch +// ensInit = 50.0 +BOOST_AUTO_TEST_CASE( + calculateAreaFlowBalanceForOneTimeStep_inside_virtual_NotIncludeOut_positiveFlow_ensInitGraterThanZero) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + positiveEnsInit, + false, + physicalAreaInsideAdqPatch, + virtualArea, + flowArea0toArea1_positive, + flowArea2toArea0_positive); + BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive); + BOOST_CHECK_EQUAL(densNew, positiveEnsInit - flowArea0toArea1_positive); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area inside adq-patch, and Area2 physical area outside adq-patch +// flow from Area0 -> Area1 is positive +// flow from Area2 -> Area0 is positive +// DensNew parameter should NOT include flows from areas outside adq patch +BOOST_AUTO_TEST_CASE( + calculateAreaFlowBalanceForOneTimeStep_inside_outside_NotIncludeOut_positiveFlow) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + 0.0, + false, + physicalAreaInsideAdqPatch, + physicalAreaOutsideAdqPatch, + flowArea0toArea1_positive, + flowArea2toArea0_positive); + BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive); + BOOST_CHECK_EQUAL(densNew, 0.0); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area inside adq-patch, and Area2 physical area inside adq-patch +// flow from Area0 -> Area1 is positive +// flow from Area2 -> Area0 is positive +// DensNew parameter should NOT include flows from areas outside adq patch +BOOST_AUTO_TEST_CASE( + calculateAreaFlowBalanceForOneTimeStep_inside_inside_NotIncludeOut_positiveFlow) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + 0.0, + false, + physicalAreaInsideAdqPatch, + physicalAreaInsideAdqPatch, + flowArea0toArea1_positive, + flowArea2toArea0_positive); + BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive + flowArea2toArea0_positive); + BOOST_CHECK_EQUAL(densNew, -flowArea0toArea1_positive + flowArea2toArea0_positive); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area inside adq-patch, and Area2 physical area outside adq-patch +// flow from Area0 -> Area1 is positive +// flow from Area2 -> Area0 is positive +// DensNew parameter SHOULD include flows from areas outside adq patch +BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_inside_outside_IncludeOut_positiveFlow) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + 0.0, + true, + physicalAreaInsideAdqPatch, + physicalAreaOutsideAdqPatch, + flowArea0toArea1_positive, + flowArea2toArea0_positive); + BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive); + BOOST_CHECK_EQUAL(densNew, -flowArea0toArea1_positive + flowArea2toArea0_positive); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area outside adq-patch, and Area2 physical area outside adq-patch +// flow from Area0 -> Area1 is positive +// flow from Area2 -> Area0 is positive +// DensNew parameter SHOULD include flows from areas outside adq patch +BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_outside_outside_IncludeOut_positiveFlow) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + 0.0, + true, + physicalAreaOutsideAdqPatch, + physicalAreaOutsideAdqPatch, + flowArea0toArea1_positive, + flowArea2toArea0_positive); + BOOST_CHECK_EQUAL(netPositionInit, 0.0); + BOOST_CHECK_EQUAL(densNew, flowArea2toArea0_positive); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area outside adq-patch, and Area2 physical area inside adq-patch +// flow from Area0 -> Area1 is positive +// flow from Area2 -> Area0 is positive +// DensNew parameter SHOULD include flows from areas outside adq patch +BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_outside_inside_IncludeOut_positiveFlow) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + 0.0, + true, + physicalAreaOutsideAdqPatch, + physicalAreaInsideAdqPatch, + flowArea0toArea1_positive, + flowArea2toArea0_positive); + BOOST_CHECK_EQUAL(netPositionInit, +flowArea2toArea0_positive); + BOOST_CHECK_EQUAL(densNew, +flowArea2toArea0_positive); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area inside adq-patch, and Area2 physical area outside adq-patch +// flow from Area0 -> Area1 is negative +// flow from Area2 -> Area0 is negative +// DensNew parameter SHOULD include flows from areas outside adq patch +BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_inside_outside_IncludeOut_negativeFlow) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + 0.0, + true, + physicalAreaInsideAdqPatch, + physicalAreaOutsideAdqPatch, + flowArea0toArea1_negative, + flowArea2toArea0_negative); + BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_negative); + BOOST_CHECK_EQUAL(densNew, -flowArea0toArea1_negative); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area outside adq-patch, and Area2 physical area outside adq-patch +// flow from Area0 -> Area1 is negative +// flow from Area2 -> Area0 is negative +// DensNew parameter SHOULD include flows from areas outside adq patch +BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_outside_outside_IncludeOut_negativeFlow) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + 0.0, + true, + physicalAreaOutsideAdqPatch, + physicalAreaOutsideAdqPatch, + flowArea0toArea1_negative, + flowArea2toArea0_negative); + BOOST_CHECK_EQUAL(netPositionInit, 0.0); + BOOST_CHECK_EQUAL(densNew, -flowArea0toArea1_negative); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area outside adq-patch, and Area2 physical area inside adq-patch +// flow from Area0 -> Area1 is negative +// flow from Area2 -> Area0 is negative +// DensNew parameter SHOULD include flows from areas outside adq patch +BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_outside_inside_IncludeOut_negativeFlow) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + 0.0, + true, + physicalAreaOutsideAdqPatch, + physicalAreaInsideAdqPatch, + flowArea0toArea1_negative, + flowArea2toArea0_negative); + BOOST_CHECK_EQUAL(netPositionInit, flowArea2toArea0_negative); + BOOST_CHECK_EQUAL(densNew, 0.0); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area inside adq-patch, and Area2 physical area inside adq-patch +// flow from Area0 -> Area1 is positiive +// flow from Area2 -> Area0 is negative +// DensNew parameter SHOULD include flows from areas outside adq patch +// ensInit = 50.0 +BOOST_AUTO_TEST_CASE( + calculateAreaFlowBalanceForOneTimeStep_outside_inside_IncludeOut_negativeFlow_initEnsEqualTo50) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + positiveEnsInit, + true, + physicalAreaInsideAdqPatch, + physicalAreaInsideAdqPatch, + flowArea0toArea1_positive, + flowArea2toArea0_negative); + BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive + flowArea2toArea0_negative); + BOOST_CHECK_EQUAL(densNew, positiveEnsInit + netPositionInit); +} + +// Area 0 is physical area inside adq-patch connected to two areas: +// Area1 physical area inside adq-patch, and Area2 physical area inside adq-patch +// flow from Area0 -> Area1 is positiive +// flow from Area2 -> Area0 is negative +// DensNew parameter SHOULD include flows from areas outside adq patch +// ensInit = 2.0 +BOOST_AUTO_TEST_CASE( + calculateAreaFlowBalanceForOneTimeStep_outside_inside_IncludeOut_negativeFlow_initEnsEqualTo0) +{ + double netPositionInit; + double densNew; + std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep( + 2.0, + true, + physicalAreaInsideAdqPatch, + physicalAreaInsideAdqPatch, + flowArea0toArea1_positive, + flowArea2toArea0_negative); + BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive + flowArea2toArea0_negative); + BOOST_CHECK_EQUAL(densNew, 0.0); +} + +BOOST_AUTO_TEST_CASE(check_valid_adq_param) +{ + auto p = createParams(); + BOOST_CHECK_NO_THROW( + p.checkAdqPatchSimulationModeEconomyOnly(Antares::Data::SimulationMode::Economy)); + BOOST_CHECK_NO_THROW(p.checkAdqPatchIncludeHurdleCost(true)); +} + +BOOST_AUTO_TEST_CASE(check_adq_param_wrong_mode) +{ + auto p = createParams(); + BOOST_CHECK_THROW(p.checkAdqPatchSimulationModeEconomyOnly( + Antares::Data::SimulationMode::Adequacy), + Error::IncompatibleSimulationModeForAdqPatch); +} + +BOOST_AUTO_TEST_CASE(check_adq_param_wrong_hurdle_cost) +{ + auto p = createParams(); + BOOST_CHECK_THROW(p.checkAdqPatchIncludeHurdleCost(false), Error::IncompatibleHurdleCostCSR); +} diff --git a/src/tests/src/solver/optimisation/adequacy_patch/adequacy_patch.cpp b/src/tests/src/solver/optimisation/adequacy_patch/adequacy_patch.cpp index ea9762838b..9f716ecb77 100644 --- a/src/tests/src/solver/optimisation/adequacy_patch/adequacy_patch.cpp +++ b/src/tests/src/solver/optimisation/adequacy_patch/adequacy_patch.cpp @@ -31,7 +31,6 @@ #include #include #include "antares/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.h" -#include "antares/solver/optimisation/adequacy_patch_csr/post_processing.h" #include "antares/study/parameters/adq-patch-params.h" static double origineExtremite = -1; @@ -402,75 +401,3 @@ BOOST_AUTO_TEST_CASE(check_adq_param_wrong_hurdle_cost) auto p = createParams(); BOOST_CHECK_THROW(p.checkAdqPatchIncludeHurdleCost(false), Error::IncompatibleHurdleCostCSR); } - -BOOST_AUTO_TEST_SUITE(adq_patch_post_processing) - -BOOST_AUTO_TEST_CASE(dtg_mrg_triggered_low_ens) -{ - const bool triggered = true; - const double dtgMrg = 32.; - const double ens = 21.; - - BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == 11., tt::tolerance(1.e-6)); - - BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens) - == std::abs(dtgMrg - ens), - tt::tolerance(1.e-6)); -} - -BOOST_AUTO_TEST_CASE(dtg_mrg_triggered_high_ens) -{ - const bool triggered = true; - const double dtgMrg = 32.; - const double ens = 42.; - - BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == 0., tt::tolerance(1.e-6)); - - BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens) - == std::abs(dtgMrg - ens), - tt::tolerance(1.e-6)); -} - -BOOST_AUTO_TEST_CASE(dtg_mrg_not_triggered_low_ens) -{ - const bool triggered = false; - const double dtgMrg = 32.; - const double ens = 21.; - - BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == dtgMrg, tt::tolerance(1.e-6)); - BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens) - == dtgMrg + ens, - tt::tolerance(1.e-6)); -} - -BOOST_AUTO_TEST_CASE(dtg_mrg_not_triggered_high_ens) -{ - const bool triggered = false; - const double dtgMrg = 32.; - const double ens = 42.; - - BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == dtgMrg, tt::tolerance(1.e-6)); - BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens) - == dtgMrg + ens, - tt::tolerance(1.e-6)); -} - -BOOST_AUTO_TEST_CASE(mrgprice_high_enscsr) -{ - const double ensCsr = 21.; - const double originalCost = 3.; - const double unsuppliedEnergyCost = 1000.; - BOOST_TEST(recomputeMRGPrice(ensCsr, originalCost, unsuppliedEnergyCost) - == -unsuppliedEnergyCost, - tt::tolerance(1.e-6)); -} - -BOOST_AUTO_TEST_CASE(mrgprice_low_enscsr) -{ - const double ensCsr = 0.; - const double originalCost = 3.; - const double unsuppliedEnergyCost = 1000.; - BOOST_TEST(recomputeMRGPrice(ensCsr, originalCost, unsuppliedEnergyCost) == originalCost, - tt::tolerance(1.e-6)); -} -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/ui/simulator/application/main/create.cpp b/src/ui/simulator/application/main/create.cpp index 03d3f57a71..bb2182d148 100644 --- a/src/ui/simulator/application/main/create.cpp +++ b/src/ui/simulator/application/main/create.cpp @@ -293,7 +293,13 @@ void ApplWnd::internalInitialize() statusbar->SetStatusStyles(2, styles); statusbar->SetMinHeight(14); - statusbar->SetStatusText(wxT(""), 1); + statusbar->Connect(statusbar->GetId(), + wxEVT_CONTEXT_MENU, + wxContextMenuEventHandler(ApplWnd::evtOnContextMenuStatusBar), + nullptr, + this); + + statusbar->SetStatusText(wxT("| "), 1); wxFont f = statusbar->GetFont(); f.SetPointSize(f.GetPointSize() - 1); diff --git a/src/ui/simulator/application/main/internal-ids.h b/src/ui/simulator/application/main/internal-ids.h index 33d8f6f764..57893d5187 100644 --- a/src/ui/simulator/application/main/internal-ids.h +++ b/src/ui/simulator/application/main/internal-ids.h @@ -172,6 +172,16 @@ enum MenusID mnIDLaunchAnalyzer, mnIDLaunchConstraintsBuilder, + //! \name Popup Menu Operator for selected cells on any grid + //@{ + mnIDPopupOpNone, + mnIDPopupOpAverage, + mnIDPopupOpCellCount, + mnIDPopupOpMinimum, + mnIDPopupOpMaximum, + mnIDPopupOpSum, + //@} + //! \name Popup Menu Operator for selected nodes on any layer //@{ mnIDPopupSelectionHide, diff --git a/src/ui/simulator/application/main/main.cpp b/src/ui/simulator/application/main/main.cpp index 137b009c2b..38131d6552 100644 --- a/src/ui/simulator/application/main/main.cpp +++ b/src/ui/simulator/application/main/main.cpp @@ -179,6 +179,14 @@ EVT_MENU(mnInternalLogMessage, ApplWnd::onLogMessage) EVT_MENU(mnIDLaunchAnalyzer, ApplWnd::evtLaunchAnalyzer) EVT_MENU(mnIDLaunchConstraintsBuilder, ApplWnd::evtLaunchConstraintsBuilder) +// Context menu : Operator for selected cells (grid) +EVT_MENU(mnIDPopupOpNone, ApplWnd::evtOnContextMenuChangeOperator) +EVT_MENU(mnIDPopupOpAverage, ApplWnd::evtOnContextMenuChangeOperator) +EVT_MENU(mnIDPopupOpCellCount, ApplWnd::evtOnContextMenuChangeOperator) +EVT_MENU(mnIDPopupOpMinimum, ApplWnd::evtOnContextMenuChangeOperator) +EVT_MENU(mnIDPopupOpMaximum, ApplWnd::evtOnContextMenuChangeOperator) +EVT_MENU(mnIDPopupOpSum, ApplWnd::evtOnContextMenuChangeOperator) + EVT_MENU_OPEN(ApplWnd::evtOnMenuOpen) EVT_MENU_CLOSE(ApplWnd::evtOnMenuClose) @@ -245,6 +253,8 @@ ApplWnd::ApplWnd() : pageRenewableCommon(nullptr), pageNodalOptim(nullptr), pWndBindingConstraints(nullptr), + pGridSelectionOperator(new Component::Datagrid::Selection::CellCount()), + pGridSelectionAttachedGrid(nullptr), pMapContextMenu(nullptr), pUserNotes(nullptr), pMainNotebookAlreadyHasItsComponents(false), @@ -308,6 +318,13 @@ ApplWnd::~ApplWnd() OnStudyAreasChanged.clear(); OnStudyAreaDelete.clear(); + // Delete the grid operator + if (pGridSelectionOperator) + { + delete pGridSelectionOperator; + pGridSelectionOperator = nullptr; // May be needed in some cases + } + // Disconnect all events destroyBoundEvents(); // Unregister the global pointer to the instance @@ -346,6 +363,34 @@ void ApplWnd::selectSystem() pNotebook->select(wxT("sys"), true); } +void ApplWnd::evtOnContextMenuChangeOperator(wxCommandEvent& evt) +{ + switch (evt.GetId()) + { + case mnIDPopupOpNone: + gridOperatorSelectedCells(nullptr); + break; + case mnIDPopupOpAverage: + gridOperatorSelectedCells(new Component::Datagrid::Selection::Average()); + break; + case mnIDPopupOpCellCount: + gridOperatorSelectedCells(new Component::Datagrid::Selection::CellCount()); + break; + case mnIDPopupOpMinimum: + gridOperatorSelectedCells(new Component::Datagrid::Selection::Minimum()); + break; + case mnIDPopupOpMaximum: + gridOperatorSelectedCells(new Component::Datagrid::Selection::Maximum()); + break; + case mnIDPopupOpSum: + gridOperatorSelectedCells(new Component::Datagrid::Selection::Sum()); + break; + default: + break; + } + evt.Skip(); +} + static inline void EnableItem(wxMenuBar* menu, int id, bool opened) { auto* item = menu->FindItem(id); @@ -494,6 +539,7 @@ void ApplWnd::evtOnUpdateGUIAfterStudyIO(bool opened) // Reset the status bar resetDefaultStatusBarText(); + gridOperatorSelectedCellsUpdateResult(pGridSelectionAttachedGrid); // reload the user notes and districts if (not aboutToQuit and study) @@ -519,6 +565,7 @@ void ApplWnd::evtOnUpdateGUIAfterStudyIO(bool opened) { GetSizer()->Clear(true); pUserNotes = nullptr; + pGridSelectionAttachedGrid = nullptr; pBigDaddy = nullptr; pMainSizer = nullptr; pData->wipPanel = nullptr; @@ -778,6 +825,24 @@ void ApplWnd::onRenewableGenerationModellingChanged(bool init) refreshInputMenuOnRenewableModellingChanged(aggregated); } +void ApplWnd::gridOperatorSelectedCells(Component::Datagrid::Selection::IOperator* v) +{ + delete pGridSelectionOperator; + pGridSelectionOperator = v; + gridOperatorSelectedCellsUpdateResult(pGridSelectionAttachedGrid); +} + +Component::Datagrid::Selection::IOperator* ApplWnd::gridOperatorSelectedCells() const +{ + return pGridSelectionOperator; +} + +void ApplWnd::disableGridOperatorIfGrid(wxGrid* grid) +{ + if (pGridSelectionAttachedGrid == grid) + gridOperatorSelectedCellsUpdateResult(nullptr); +} + void ApplWnd::title() { assert(wxIsMainThread() == true and "Must be ran from the main thread"); diff --git a/src/ui/simulator/application/main/main.h b/src/ui/simulator/application/main/main.h index 0b1f9dd8bb..7b7683805e 100644 --- a/src/ui/simulator/application/main/main.h +++ b/src/ui/simulator/application/main/main.h @@ -26,6 +26,7 @@ #include #include "../../toolbox/components/notebook/notebook.h" +#include "../../toolbox/components/datagrid/selectionoperation.h" #include "../../toolbox/components/map/settings.h" #include #include "fwd.h" @@ -105,6 +106,41 @@ class ApplWnd final : public Component::Frame::WxLocalFrame, public Yuni::IEvent */ Map::Component* map() const; + /*! + ** \name Grid operator (for selected cells) + ** + ** A grid operator computes an operation (Sum, average...) on all selected + ** cells of the grid that currently has the focus. The result of this + ** computation is displayed in the status bar. + ** + ** \see Antares::Component::Datagrid::Component::onGridEnter() + ** \see Antares::Component::Datagrid::Component::onGridLeave() + */ + //@{ + /*! + ** \brief Get the current grid operator for selected cells + */ + Component::Datagrid::Selection::IOperator* gridOperatorSelectedCells() const; + + /*! + ** \brief Set the grid operator for selected cells + */ + void gridOperatorSelectedCells(Component::Datagrid::Selection::IOperator* v); + + /*! + ** \brief Update the GUI to display the result of the grid operator + ** + ** This method should be called each time the cells selection changes. + ** \param grid The `wxGrid` that has currently the focus (may be NULL) + */ + void gridOperatorSelectedCellsUpdateResult(wxGrid* grid); + + /*! + ** \brief Disable the grid operator + */ + void disableGridOperatorIfGrid(wxGrid* grid); + //@} + //! \name Title of the Window //@{ void title(); @@ -327,6 +363,8 @@ class ApplWnd final : public Component::Frame::WxLocalFrame, public Yuni::IEvent //! Create a complete menu for the window wxMenuBar* createMenu(); + //! Create a popup menu for all available operators on selected cells (grid) + wxMenu* createPopupMenuOperatorsOnGrid(); //! Create menu: File wxMenu* createMenuFiles(); @@ -398,6 +436,9 @@ class ApplWnd final : public Component::Frame::WxLocalFrame, public Yuni::IEvent //! \name Event: Context menu //@{ + //! Show the context menu associated to the status bar + void evtOnContextMenuStatusBar(wxContextMenuEvent& evt); + void evtOnContextMenuChangeOperator(wxCommandEvent& evt); void evtOnContextMenuMap(int x, int y); //@} @@ -696,6 +737,10 @@ class ApplWnd final : public Component::Frame::WxLocalFrame, public Yuni::IEvent Component::Notebook::Page* pageScBuilderHydroInitialLevels; Component::Notebook::Page* pageScBuilderHydroFinalLevels; + //! The current grid operator to use on selected cells + Component::Datagrid::Selection::IOperator* pGridSelectionOperator; + wxGrid* pGridSelectionAttachedGrid; + //! A context menu for the map wxMenu* pMapContextMenu; diff --git a/src/ui/simulator/application/main/menu.cpp b/src/ui/simulator/application/main/menu.cpp index 11121bce3c..619269b283 100644 --- a/src/ui/simulator/application/main/menu.cpp +++ b/src/ui/simulator/application/main/menu.cpp @@ -64,6 +64,21 @@ wxMenuBar* ApplWnd::createMenu() return ret; } +wxMenu* ApplWnd::createPopupMenuOperatorsOnGrid() +{ + auto* menu = new wxMenu(); + + // Wizard + Menu::CreateItem(menu, mnIDPopupOpNone, wxT("None"), "images/16x16/empty.png"); + menu->AppendSeparator(); + Menu::CreateItem(menu, mnIDPopupOpAverage, wxT("Average ")); + Menu::CreateItem(menu, mnIDPopupOpCellCount, wxT("Cell count ")); + Menu::CreateItem(menu, mnIDPopupOpMinimum, wxT("Minimum ")); + Menu::CreateItem(menu, mnIDPopupOpMaximum, wxT("Maximum ")); + Menu::CreateItem(menu, mnIDPopupOpSum, wxT("Sum ")); + return menu; +} + wxMenu* ApplWnd::createMenuFiles() { delete pMenuFile; diff --git a/src/ui/simulator/application/main/statusbar.cpp b/src/ui/simulator/application/main/statusbar.cpp index a12dd4a290..ed33372524 100644 --- a/src/ui/simulator/application/main/statusbar.cpp +++ b/src/ui/simulator/application/main/statusbar.cpp @@ -22,17 +22,16 @@ #include #include "main.h" #include "../../windows/version.h" -#include "antares/study/study.h" -// Datagrid -#include "../../toolbox/components/datagrid/component.h" +#include "../study.h" #include "../../toolbox/components/datagrid/gridhelper.h" #include #include -namespace Antares -{ -namespace Forms +using namespace Component::Datagrid; + +namespace Antares::Forms { + void ApplWnd::resetDefaultStatusBarText() { assert(wxIsMainThread() == true && "Must be ran from the main thread"); @@ -41,5 +40,216 @@ void ApplWnd::resetDefaultStatusBarText() #endif } -} // namespace Forms -} // namespace Antares + +bool oneCellSelected(wxGrid& grid) +{ + const wxGridCellCoordsArray& cells(grid.GetSelectedCells()); + return cells.size() > 0; +} + +size_t updateStatisticsOpForOneCell(wxGrid& grid, + VGridHelper* gridHelper, + Selection::IOperator* op) +{ + size_t totalCell = 0; + const wxGridCellCoordsArray& cells(grid.GetSelectedCells()); + for (uint i = 0; i < (uint)cells.size(); ++i) + { + auto& cell = cells[i]; + op->appendValue(gridHelper->GetNumericValue(cell.GetRow(), cell.GetCol())); + ++totalCell; + } + return totalCell; +} + +bool rowsSelected(wxGrid& grid) +{ + const wxArrayInt& rows(grid.GetSelectedRows()); + return rows.size() > 0; +} + +size_t updateStatisticsOpForRows(wxGrid& grid, + VGridHelper* gridHelper, + Selection::IOperator* op) +{ + size_t totalCell = 0; + int colCount = grid.GetNumberCols(); + const wxArrayInt& rows(grid.GetSelectedRows()); + for (uint i = 0; i < (uint)rows.size(); ++i) + { + for (int col = 0; col < colCount; ++col) + { + op->appendValue(gridHelper->GetNumericValue(rows[i], col)); + ++totalCell; + } + } + return totalCell; +} + +bool columnsSelected(wxGrid& grid) +{ + const wxArrayInt& cols(grid.GetSelectedCols()); + return cols.size() > 0; +} + +size_t updateStatisticsOpForColumns(wxGrid& grid, + VGridHelper* gridHelper, + Selection::IOperator* op) +{ + size_t totalCell = 0; + int rowCount = grid.GetNumberRows(); + const wxArrayInt& cols(grid.GetSelectedCols()); + for (uint i = 0; i < (uint)cols.size(); ++i) + { + for (int row = 0; row < rowCount; ++row) + { + op->appendValue(gridHelper->GetNumericValue(row, cols[i])); + ++totalCell; + } + } + return totalCell; +} + +bool blockSelected(wxGrid& grid) +{ + // Blocks. We always expect blocks top left and bottom right to have the same size, since their + // entries are supposed to correspond. + const wxGridCellCoordsArray& blockTopLeft(grid.GetSelectionBlockTopLeft()); + const wxGridCellCoordsArray& blockBottomRight(grid.GetSelectionBlockBottomRight()); + return (blockTopLeft.size() == blockBottomRight.size()) && (blockTopLeft.size() > 0); +} + +size_t updateStatisticsOpForBlock(wxGrid& grid, + VGridHelper* gridHelper, + Selection::IOperator* op) +{ + size_t totalCell = 0; + const wxGridCellCoordsArray& blockTopLeft(grid.GetSelectionBlockTopLeft()); + const wxGridCellCoordsArray& blockBottomRight(grid.GetSelectionBlockBottomRight()); + size_t blockSize = blockTopLeft.size(); + + for (uint i = 0; i < blockSize; ++i) + { + const wxGridCellCoords& topLeft = blockTopLeft[i]; + const wxGridCellCoords& bottomRight = blockBottomRight[i]; + for (int row = topLeft.GetRow(); row <= bottomRight.GetRow(); ++row) + { + for (int col = topLeft.GetCol(); col <= bottomRight.GetCol(); ++col) + { + op->appendValue(gridHelper->GetNumericValue(row, col)); + ++totalCell; + } + } + } + return totalCell; +} + +/* +** Applies a functor to all selected cells. Returns the number of selected +** cells. +*/ +static size_t applyOperatorOnSelectedCells(wxGrid& grid, + VGridHelper* gridHelper, + Selection::IOperator* op) +{ + assert(wxIsMainThread() == true and "Must be ran from the main thread"); + + if (oneCellSelected(grid)) + { + return updateStatisticsOpForOneCell(grid, gridHelper, op); + } + + if (rowsSelected(grid)) + { + return updateStatisticsOpForRows(grid, gridHelper, op); + } + + if (columnsSelected(grid)) + { + return updateStatisticsOpForColumns(grid, gridHelper, op); + } + + if (blockSelected(grid)) + { + return updateStatisticsOpForBlock(grid, gridHelper, op); + } + + return 0; +} + +void ApplWnd::gridOperatorSelectedCellsUpdateResult(wxGrid* grid) +{ + assert(wxIsMainThread() == true and "Must be ran from the main thread"); + enum + { + fieldIndex = 1, + }; + // The status bar + auto* statusBar = GetStatusBar(); + pGridSelectionAttachedGrid = grid; + if (statusBar) + { + if (not CurrentStudyIsValid()) + { + statusBar->SetStatusText(wxEmptyString, fieldIndex); + return; + } + if (not pGridSelectionOperator) + { + statusBar->SetStatusText(wxT("| (none)"), fieldIndex); + return; + } + + if (grid and grid->GetTable()) + { + auto* gridHelper = dynamic_cast(grid->GetTable()); + if (gridHelper) + { + // Reset of the operator + pGridSelectionOperator->reset(); + // Browse all selected cells + if (applyOperatorOnSelectedCells(*grid, gridHelper, pGridSelectionOperator)) + { + // Update the GUI + statusBar->SetStatusText(wxString() + << wxT("| ") << pGridSelectionOperator->caption() + << wxT(" = ") << pGridSelectionOperator->result(), + fieldIndex); + return; + } + } + } + // Empty + statusBar->SetStatusText( + wxString(wxT("| (")) << pGridSelectionOperator->caption() << wxT(')'), fieldIndex); + } +} + +void ApplWnd::evtOnContextMenuStatusBar(wxContextMenuEvent& evt) +{ + if (GUIIsLock()) + return; + + wxStatusBar* statusBar = GetStatusBar(); + if (statusBar) + { + wxRect rect; + if (statusBar->GetFieldRect(1, rect)) + { + const wxPoint pos = statusBar->ScreenToClient(evt.GetPosition()); + if (rect.Contains(pos)) + { + if (!pPopupMenuOperatorsGrid) + { + // Popup menu: Operators for selected cells on any grid + pPopupMenuOperatorsGrid = createPopupMenuOperatorsOnGrid(); + } + + statusBar->PopupMenu(pPopupMenuOperatorsGrid); + } + } + } + evt.Skip(); +} + +} // namespace Antares::Forms \ No newline at end of file diff --git a/src/ui/simulator/cmake/components.cmake b/src/ui/simulator/cmake/components.cmake index 0586928a48..df72d40b83 100644 --- a/src/ui/simulator/cmake/components.cmake +++ b/src/ui/simulator/cmake/components.cmake @@ -48,6 +48,7 @@ SET(SRC_TOOLBOX_COM_DBGRID_RENDERERS toolbox/components/datagrid/renderer.h toolbox/components/datagrid/renderer.hxx toolbox/components/datagrid/renderer.cpp + toolbox/components/datagrid/selectionoperation.h toolbox/components/datagrid/renderer/adequacy-patch-area-grid.h toolbox/components/datagrid/renderer/adequacy-patch-area-grid.cpp toolbox/components/datagrid/renderer/area.h diff --git a/src/ui/simulator/toolbox/components/datagrid/dbgrid.cpp b/src/ui/simulator/toolbox/components/datagrid/dbgrid.cpp index dc8624172e..84fe490800 100644 --- a/src/ui/simulator/toolbox/components/datagrid/dbgrid.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/dbgrid.cpp @@ -120,6 +120,11 @@ DBGrid::DBGrid(Component* parent) : DBGrid::~DBGrid() { + // Remove any remaining reference + auto* mainFrm = Forms::ApplWnd::Instance(); + if (mainFrm) + mainFrm->disableGridOperatorIfGrid(this); + pParentComponent = nullptr; otherGrid_ = nullptr; } @@ -128,6 +133,10 @@ void DBGrid::onGridSelectCell(wxGridEvent& evt) { assert(GetParent() && "invalid parent"); + auto* mainFrm = Forms::ApplWnd::Instance(); + if (mainFrm) + mainFrm->gridOperatorSelectedCellsUpdateResult(this); + pCurrentPosition.x = evt.GetCol(); pCurrentPosition.y = evt.GetRow(); auto* r = ((Component*)GetParent())->renderer(); @@ -141,6 +150,9 @@ void DBGrid::onGridRangeSelect(wxGridRangeSelectEvent& evt) { assert(GetGridWindow() && "invalid grid window"); + Forms::ApplWnd* mainFrm = Forms::ApplWnd::Instance(); + if (mainFrm) + mainFrm->gridOperatorSelectedCellsUpdateResult(this); if (GetGridWindow()) GetGridWindow()->SetFocus(); evt.Skip(); @@ -148,6 +160,9 @@ void DBGrid::onGridRangeSelect(wxGridRangeSelectEvent& evt) void DBGrid::onGridLeave(wxFocusEvent& evt) { + auto* mainFrm = Forms::ApplWnd::Instance(); + if (mainFrm) + mainFrm->gridOperatorSelectedCellsUpdateResult(nullptr); evt.Skip(); } @@ -202,6 +217,10 @@ void DBGrid::ensureDataAreLoaded() r->invalidate = false; // Post an event to update the gui after the data are loaded + Forms::ApplWnd* mainFrm = Forms::ApplWnd::Instance(); + if (mainFrm) + mainFrm->disableGridOperatorIfGrid(this); + assert(pAllowRefresh == true); parent->forceRefresh(); if (GetTable()) diff --git a/src/ui/simulator/toolbox/components/datagrid/selectionoperation.h b/src/ui/simulator/toolbox/components/datagrid/selectionoperation.h new file mode 100644 index 0000000000..a7deebcf32 --- /dev/null +++ b/src/ui/simulator/toolbox/components/datagrid/selectionoperation.h @@ -0,0 +1,247 @@ +/* +** Copyright 2007-2018 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 __ANTARES_TOOLBOX_COMPONENT_DATAGRID_SELECTION_OPERATION_H__ +#define __ANTARES_TOOLBOX_COMPONENT_DATAGRID_SELECTION_OPERATION_H__ + +#include "wx-wrapper.h" +#include +#include + +namespace Antares +{ +namespace Component +{ +namespace Datagrid +{ +namespace Selection +{ +class IOperator +{ +public: + IOperator() + { + } + virtual ~IOperator() + { + } + + /*! + ** \brief Caption of the operator + */ + virtual const wxChar* caption() const = 0; + + /*! + ** \brief Reset all internal values + */ + virtual void reset() = 0; + + /*! + ** \brief Manage a new value + */ + virtual void appendValue(const double v) = 0; + + /*! + ** \brief Get the result + */ + virtual double result() const = 0; + +}; // class IOperator + +class Average final : public IOperator +{ +public: + Average() : pValue(0.), pCount(0) + { + } + + virtual ~Average() + { + } + + virtual const wxChar* caption() const + { + return wxT("Average"); + } + + virtual void reset() + { + pValue = 0.; + pCount = 0; + } + + virtual void appendValue(const double v) + { + pValue += v; + ++pCount; + } + + virtual double result() const + { + return pValue / (double)pCount; + } + +private: + double pValue; + uint pCount; + +}; // class Average + +class Sum final : public IOperator +{ +public: + Sum() : pValue(0.) + { + } + + virtual const wxChar* caption() const + { + return wxT("Sum"); + } + + virtual void reset() + { + pValue = 0.; + } + + virtual void appendValue(const double v) + { + pValue += v; + } + + virtual double result() const + { + return pValue; + } + +private: + double pValue; + +}; // class Sum + +class CellCount final : public IOperator +{ +public: + CellCount() : pCount(0) + { + } + + virtual const wxChar* caption() const + { + return wxT("Cell Count"); + } + + virtual void reset() + { + pCount = 0; + } + + virtual void appendValue(const double) + { + ++pCount; + } + + virtual double result() const + { + return (double)pCount; + } + +private: + uint pCount; + +}; // class Average + +class Minimum final : public IOperator +{ +public: + Minimum() : pValue(std::numeric_limits::infinity()) + { + } + + virtual const wxChar* caption() const + { + return wxT("Minimum"); + } + + virtual void reset() + { + pValue = std::numeric_limits::infinity(); + } + + virtual void appendValue(const double v) + { + if (v < pValue) + pValue = v; + } + + virtual double result() const + { + return pValue; + } + +private: + double pValue; + +}; // class Sum + +class Maximum final : public IOperator +{ +public: + Maximum() : pValue(-std::numeric_limits::infinity()) + { + } + + virtual const wxChar* caption() const + { + return wxT("Maximum"); + } + virtual void reset() + { + pValue = -std::numeric_limits::infinity(); + } + + virtual void appendValue(const double v) + { + if (v > pValue) + pValue = v; + } + + virtual double result() const + { + return pValue; + } + +private: + double pValue; + +}; // class Sum + +} // namespace Selection +} // namespace Datagrid +} // namespace Component +} // namespace Antares + +#endif // __ANTARES_TOOLBOX_COMPONENT_DATAGRID_SELECTION_OPERATION_H__ From 5d4c1689631521f39fae5eb59606a5ccd2498032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Thu, 19 Dec 2024 15:29:31 +0100 Subject: [PATCH 086/103] Modeler 2.5a: Add parameters and YAML parser (#2539) Co-authored-by: payetvin <113102157+payetvin@users.noreply.github.com> Co-authored-by: Vincent Payet --- src/CMakeLists.txt | 1 + src/libs/antares/io/CMakeLists.txt | 3 +- src/libs/antares/io/include/antares/io/file.h | 3 +- src/solver/modelParser/CMakeLists.txt | 4 +- src/solver/modeler/CMakeLists.txt | 1 + src/solver/modeler/parameters/CMakeLists.txt | 14 ++++ src/solver/modeler/parameters/encoder.hxx | 23 ++++++ .../modeler/parameters/modelerParameters.h | 18 +++++ .../parameters/parseModelerParameters.h | 11 +++ .../parameters/parseModelerParameters.cpp | 16 ++++ src/solver/systemParser/CMakeLists.txt | 2 - .../libs/antares/yaml-parser/CMakeLists.txt | 7 +- src/tests/src/solver/modeler/CMakeLists.txt | 1 + .../solver/modeler/parameters/CMakeLists.txt | 14 ++++ .../parameters/testParametersParsing.cpp | 74 +++++++++++++++++++ 15 files changed, 179 insertions(+), 13 deletions(-) create mode 100644 src/solver/modeler/parameters/CMakeLists.txt create mode 100644 src/solver/modeler/parameters/encoder.hxx create mode 100644 src/solver/modeler/parameters/include/antares/solver/modeler/parameters/modelerParameters.h create mode 100644 src/solver/modeler/parameters/include/antares/solver/modeler/parameters/parseModelerParameters.h create mode 100644 src/solver/modeler/parameters/parseModelerParameters.cpp create mode 100644 src/tests/src/solver/modeler/parameters/CMakeLists.txt create mode 100644 src/tests/src/solver/modeler/parameters/testParametersParsing.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 13c67fe7a0..32beee7a3a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -191,6 +191,7 @@ endif() find_package(Boost REQUIRED) find_package(antlr4-runtime REQUIRED) +find_package(yaml-cpp REQUIRED) #Sirius solver if(POLICY CMP0074) diff --git a/src/libs/antares/io/CMakeLists.txt b/src/libs/antares/io/CMakeLists.txt index 9e3211e14b..dc62a95aea 100644 --- a/src/libs/antares/io/CMakeLists.txt +++ b/src/libs/antares/io/CMakeLists.txt @@ -12,6 +12,7 @@ source_group("io" FILES ${SRC_IO}) add_library(io ${SRC_IO} ) +add_library(Antares::io ALIAS io) target_link_libraries(io PRIVATE @@ -26,4 +27,4 @@ target_include_directories(io install(DIRECTORY include/antares DESTINATION "include" -) \ No newline at end of file +) diff --git a/src/libs/antares/io/include/antares/io/file.h b/src/libs/antares/io/include/antares/io/file.h index b401b1cece..a9aed8c850 100644 --- a/src/libs/antares/io/include/antares/io/file.h +++ b/src/libs/antares/io/include/antares/io/file.h @@ -22,8 +22,7 @@ #define __LIBS_ANTARES_IO_FILE_H__ #include - -#include +#include namespace Antares::IO { diff --git a/src/solver/modelParser/CMakeLists.txt b/src/solver/modelParser/CMakeLists.txt index 1881ba78fa..8e5ac13726 100644 --- a/src/solver/modelParser/CMakeLists.txt +++ b/src/solver/modelParser/CMakeLists.txt @@ -1,5 +1,3 @@ -find_package(yaml-cpp REQUIRED) - set(SOURCES parser.cpp encoders.hxx @@ -24,4 +22,4 @@ target_link_libraries(modelParser install(DIRECTORY include/antares DESTINATION "include" -) \ No newline at end of file +) diff --git a/src/solver/modeler/CMakeLists.txt b/src/solver/modeler/CMakeLists.txt index 3c631240ac..74378f6f7f 100644 --- a/src/solver/modeler/CMakeLists.txt +++ b/src/solver/modeler/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(api) add_subdirectory(ortoolsImpl) +add_subdirectory(parameters) diff --git a/src/solver/modeler/parameters/CMakeLists.txt b/src/solver/modeler/parameters/CMakeLists.txt new file mode 100644 index 0000000000..33cfda091e --- /dev/null +++ b/src/solver/modeler/parameters/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(modeler-parameters + include/antares/solver/modeler/parameters/modelerParameters.h + include/antares/solver/modeler/parameters/parseModelerParameters.h + parseModelerParameters.cpp + encoder.hxx) + +target_link_libraries(modeler-parameters + PRIVATE + yaml-cpp + Antares::io) + +target_include_directories(modeler-parameters + PUBLIC + $) diff --git a/src/solver/modeler/parameters/encoder.hxx b/src/solver/modeler/parameters/encoder.hxx new file mode 100644 index 0000000000..32de3e0d83 --- /dev/null +++ b/src/solver/modeler/parameters/encoder.hxx @@ -0,0 +1,23 @@ +#include + +#include "yaml-cpp/yaml.h" + +namespace YAML +{ +template<> +struct convert +{ + static bool decode(const Node& node, Antares::Solver::ModelerParameters& rhs) + { + if (!node.IsMap()) + { + return false; + } + rhs.solver = node["solver"].as(); + rhs.solverLogs = node["solver-logs"].as(false); + rhs.solverParameters = node["solver-parameters"].as(); + rhs.noOutput = node["no-output"].as(false); + return true; + } +}; +} // namespace YAML diff --git a/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/modelerParameters.h b/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/modelerParameters.h new file mode 100644 index 0000000000..c6977a748b --- /dev/null +++ b/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/modelerParameters.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace Antares::Solver +{ +struct ModelerParameters +{ + // OR-Tools solver to be used for the simulation + std::string solver; + // Display solver logs ON/OFF + bool solverLogs = false; + // Specific solver parameters + std::string solverParameters; + // Write output results + bool noOutput = false; +}; +} // namespace Antares::Solver diff --git a/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/parseModelerParameters.h b/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/parseModelerParameters.h new file mode 100644 index 0000000000..2409fcddf1 --- /dev/null +++ b/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/parseModelerParameters.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include + +namespace Antares::Solver +{ + +ModelerParameters parseModelerParameters(const std::filesystem::path& path); +} // namespace Antares::Solver diff --git a/src/solver/modeler/parameters/parseModelerParameters.cpp b/src/solver/modeler/parameters/parseModelerParameters.cpp new file mode 100644 index 0000000000..39935db38c --- /dev/null +++ b/src/solver/modeler/parameters/parseModelerParameters.cpp @@ -0,0 +1,16 @@ +#include +#include + +#include + +#include "encoder.hxx" + +namespace Antares::Solver +{ +ModelerParameters parseModelerParameters(const std::filesystem::path& path) +{ + const auto contents = Antares::IO::readFile(path); + YAML::Node root = YAML::Load(contents); + return root.as(); +} +} // namespace Antares::Solver diff --git a/src/solver/systemParser/CMakeLists.txt b/src/solver/systemParser/CMakeLists.txt index 79e1262644..37e09a616a 100644 --- a/src/solver/systemParser/CMakeLists.txt +++ b/src/solver/systemParser/CMakeLists.txt @@ -1,5 +1,3 @@ -find_package(yaml-cpp REQUIRED) - set(SOURCES parser.cpp converter.cpp diff --git a/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt b/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt index 1633966826..dd9ef54891 100644 --- a/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt +++ b/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt @@ -1,6 +1,4 @@ - -find_package(yaml-cpp CONFIG REQUIRED) -Set(SRCS test_yaml_parser.cpp +set(SRCS test_yaml_parser.cpp ) set(execname "yaml-parser-test") @@ -8,8 +6,7 @@ add_executable(${execname} ${SRCS}) target_link_libraries(${execname} PRIVATE yaml-cpp - Boost::unit_test_framework - ) + Boost::unit_test_framework) add_test(NAME yaml-parser COMMAND ${execname}) diff --git a/src/tests/src/solver/modeler/CMakeLists.txt b/src/tests/src/solver/modeler/CMakeLists.txt index 53d257b04e..9a39b3b19b 100644 --- a/src/tests/src/solver/modeler/CMakeLists.txt +++ b/src/tests/src/solver/modeler/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(api) +add_subdirectory(parameters) diff --git a/src/tests/src/solver/modeler/parameters/CMakeLists.txt b/src/tests/src/solver/modeler/parameters/CMakeLists.txt new file mode 100644 index 0000000000..3e989c2b03 --- /dev/null +++ b/src/tests/src/solver/modeler/parameters/CMakeLists.txt @@ -0,0 +1,14 @@ +# Zip writer +add_executable(parse-parameters testParametersParsing.cpp) + +target_link_libraries(parse-parameters + PRIVATE + Boost::unit_test_framework + modeler-parameters + test_utils_unit +) + +set_target_properties(parse-parameters PROPERTIES FOLDER Unit-tests/test-writer) + +add_test(NAME parse-parameters COMMAND parse-parameters) +set_tests_properties(parse-parameters PROPERTIES LABELS unit) diff --git a/src/tests/src/solver/modeler/parameters/testParametersParsing.cpp b/src/tests/src/solver/modeler/parameters/testParametersParsing.cpp new file mode 100644 index 0000000000..aa2b14732b --- /dev/null +++ b/src/tests/src/solver/modeler/parameters/testParametersParsing.cpp @@ -0,0 +1,74 @@ +/* + * 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 . + */ +#define WIN32_LEAN_AND_MEAN + +#include +#define BOOST_TEST_MODULE parse modeler parameters + +#include + +#include + +#include "files-system.h" + +BOOST_AUTO_TEST_SUITE(read_modeler_parameters) + +BOOST_AUTO_TEST_CASE(all_properties_set) +{ + const auto working_tmp_dir = CREATE_TMP_DIR_BASED_ON_TEST_NAME(); + const auto fileP = working_tmp_dir / "parameters.yaml"; + { + std::ofstream param(fileP); + param << R"( +solver: sirius +solver-logs: false +solver-parameters: PRESOLVE 1 +no-output: true)"; + } + + auto params = Antares::Solver::parseModelerParameters(fileP); + BOOST_CHECK_EQUAL(params.solver, "sirius"); + BOOST_CHECK_EQUAL(params.solverLogs, false); + BOOST_CHECK_EQUAL(params.solverParameters, "PRESOLVE 1"); + BOOST_CHECK_EQUAL(params.noOutput, true); +} + +BOOST_AUTO_TEST_CASE(all_properties_set_out_of_order) +{ + const auto working_tmp_dir = CREATE_TMP_DIR_BASED_ON_TEST_NAME(); + const auto fileP = working_tmp_dir / "parameters.yaml"; + { + std::ofstream param(fileP); + param << R"( +solver-logs: false +solver: sirius +solver-parameters: PRESOLVE 1 +no-output: true)"; + } + + auto params = Antares::Solver::parseModelerParameters(fileP); + BOOST_CHECK_EQUAL(params.solver, "sirius"); + BOOST_CHECK_EQUAL(params.solverLogs, false); + BOOST_CHECK_EQUAL(params.solverParameters, "PRESOLVE 1"); + BOOST_CHECK_EQUAL(params.noOutput, true); +} + +BOOST_AUTO_TEST_SUITE_END() From 03508dec0fe5dec66ff432f1c98d390b7d3d4262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Thu, 19 Dec 2024 15:52:13 +0100 Subject: [PATCH 087/103] Fix segfault caused by invalid index [ANT-2582] (#2543) --- .../constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp b/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp index a1a73ef2fa..bb298a3f8d 100644 --- a/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp +++ b/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp @@ -54,7 +54,7 @@ void NbDispUnitsMinBoundSinceMinUpTime::add(int pays, int index, int pdt) builder.greaterThan(); if (builder.NumberOfVariables() > 1) { - data.CorrespondanceCntNativesCntOptim[pays] + data.CorrespondanceCntNativesCntOptim[pdt] .NumeroDeContrainteDesContraintesDeDureeMinDeMarche[cluster] = builder.data.nombreDeContraintes; From 212167b14aee8639b9bd99b89b57866f5a37e669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Fri, 20 Dec 2024 14:08:45 +0100 Subject: [PATCH 088/103] Add and use add_boost_test CMake helper function (#2545) Allow adding unit test in a single line, avoiding repetition of CMake targets. TODO - [x] Add optional argument for `target_include_directories` - [ ] Allow more labels / directories (IDE specific) ? - [x] Use `add_boost_test` in place of `add_executable` where needed This pull request includes significant changes to the CMake build system for various tests, primarily focusing on simplifying and standardizing the test definitions by introducing a new macro. The main changes involve replacing existing test setup code with a new `add_boost_test` function, which consolidates the test setup into a single line. --- .../binding_constraints/CMakeLists.txt | 40 ++--- .../end-to-end/simple_study/CMakeLists.txt | 46 ++---- src/tests/macros.cmake | 38 +++++ src/tests/src/api_internal/CMakeLists.txt | 39 ++--- src/tests/src/api_lib/CMakeLists.txt | 23 +-- src/tests/src/libs/antares/CMakeLists.txt | 143 ++++++------------ .../antares/antlr4-interface/CMakeLists.txt | 25 +-- .../libs/antares/benchmarking/CMakeLists.txt | 18 +-- .../libs/antares/concurrency/CMakeLists.txt | 17 +-- .../src/libs/antares/inifile/CMakeLists.txt | 18 +-- .../src/libs/antares/study/CMakeLists.txt | 16 +- .../libs/antares/study/area/CMakeLists.txt | 60 ++------ .../antares/study/constraint/CMakeLists.txt | 58 ++----- .../study/output-folder/CMakeLists.txt | 34 +---- .../antares/study/parameters/CMakeLists.txt | 22 +-- .../antares/study/parts/hydro/CMakeLists.txt | 53 ++----- .../study/scenario-builder/CMakeLists.txt | 68 ++------- .../libs/antares/study/series/CMakeLists.txt | 27 +--- .../short-term-storage-input/CMakeLists.txt | 37 +---- .../thermal-price-definition/CMakeLists.txt | 47 ++---- .../src/libs/antares/writer/CMakeLists.txt | 21 +-- .../libs/antares/yaml-parser/CMakeLists.txt | 17 +-- .../src/solver/expressions/CMakeLists.txt | 48 +++--- .../CMakeLists.txt | 23 +-- src/tests/src/solver/lps/CMakeLists.txt | 23 +-- .../src/solver/modelParser/CMakeLists.txt | 50 +++--- .../src/solver/modeler/api/CMakeLists.txt | 34 ++--- .../solver/modeler/parameters/CMakeLists.txt | 19 +-- .../solver/optim-model-filler/CMakeLists.txt | 43 ++---- .../adequacy_patch/CMakeLists.txt | 29 +--- .../name-translator/CMakeLists.txt | 23 +-- .../optimisation/translator/CMakeLists.txt | 23 +-- .../src/solver/simulation/CMakeLists.txt | 132 +++++----------- src/tests/src/solver/utils/CMakeLists.txt | 30 ++-- .../src/study/system-model/CMakeLists.txt | 30 ++-- 35 files changed, 398 insertions(+), 976 deletions(-) create mode 100644 src/tests/macros.cmake diff --git a/src/tests/end-to-end/binding_constraints/CMakeLists.txt b/src/tests/end-to-end/binding_constraints/CMakeLists.txt index 72e2e46f62..788899db61 100644 --- a/src/tests/end-to-end/binding_constraints/CMakeLists.txt +++ b/src/tests/end-to-end/binding_constraints/CMakeLists.txt @@ -1,30 +1,10 @@ -find_package(Boost COMPONENTS unit_test_framework REQUIRED) -enable_testing() - -#bigobj support needed for windows compilation -if(MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") -endif(MSVC) - -add_executable(tests-binding_constraints - test_binding_constraints.cpp - ) - -target_link_libraries(tests-binding_constraints - PRIVATE - Boost::unit_test_framework - model_antares - antares-solver-simulation - antares-solver-hydro - antares-solver-ts-generator - Antares::tests::in-memory-study - ) - -target_include_directories(tests-binding_constraints - PRIVATE - ${CMAKE_SOURCE_DIR}/solver - ) - -add_test(NAME end-to-end-binding_constraints COMMAND tests-binding_constraints) -set_property(TEST end-to-end-binding_constraints PROPERTY LABELS end-to-end) -set_target_properties(tests-binding_constraints PROPERTIES FOLDER Unit-tests/end_to_end) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + +add_boost_test(tests-binding_constraints + SRC test_binding_constraints.cpp + LIBS + model_antares + antares-solver-simulation + antares-solver-hydro + antares-solver-ts-generator + Antares::tests::in-memory-study) diff --git a/src/tests/end-to-end/simple_study/CMakeLists.txt b/src/tests/end-to-end/simple_study/CMakeLists.txt index cc5c93b410..e7dd6e2fa9 100644 --- a/src/tests/end-to-end/simple_study/CMakeLists.txt +++ b/src/tests/end-to-end/simple_study/CMakeLists.txt @@ -1,35 +1,11 @@ -find_package(Boost COMPONENTS unit_test_framework REQUIRED) -enable_testing() - -#bigobj support needed for windows compilation -if(MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") -endif(MSVC) - -add_executable(tests-simple-study - simple-study.cpp -) - -target_link_libraries(tests-simple-study - PRIVATE - antares-solver-hydro - antares-solver-variable - antares-solver-simulation - antares-solver-ts-generator - model_antares - ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} - Antares::tests::in-memory-study -) - -target_include_directories(tests-simple-study - PRIVATE - ${CMAKE_SOURCE_DIR}/solver -) - -add_test(NAME end-to-end-simple-study COMMAND tests-simple-study) -set_property(TEST end-to-end-simple-study PROPERTY LABELS end-to-end) -set_target_properties(tests-simple-study PROPERTIES FOLDER Unit-tests/end_to_end) - -# Storing tests-simple-study under the folder Unit-tests in the IDE - -#---------------------------------------------------------- +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + +add_boost_test(tests-simple-study + SRC simple-study.cpp + LIBS + antares-solver-hydro + antares-solver-variable + antares-solver-simulation + antares-solver-ts-generator + model_antares + Antares::tests::in-memory-study) diff --git a/src/tests/macros.cmake b/src/tests/macros.cmake new file mode 100644 index 0000000000..8d57ddf55b --- /dev/null +++ b/src/tests/macros.cmake @@ -0,0 +1,38 @@ +# The following function allows to add a test in a single line +# Arguments +# SRC path to the sources +# (optional) LIBS path to the libs to link +# (optional) INCLUDE include paths +# NOTE it's not necessary to add Boost::unit_test_framework + +function(add_boost_test) + set(options "") + set(oneValueArgs) + set(multiValueArgs SRC LIBS INCLUDE) + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" "${oneValueArgs}" "${multiValueArgs}") + # Bypass cmake_parse_arguments for the 1st argument + set(TEST_NAME ${ARGV0}) + add_executable(${TEST_NAME} ${arg_SRC}) + # All tests use boost + target_link_libraries(${TEST_NAME} PRIVATE ${arg_LIBS} Boost::unit_test_framework) + + # Optional: add private include directories + if (NOT "${arg_INCLUDE}" STREQUAL "") + target_include_directories(${TEST_NAME} PRIVATE ${arg_INCLUDE}) + endif() + + add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME}) + + # Adding labels allows ctest filter what tests to run + set_property(TEST ${TEST_NAME} PROPERTY LABELS unit) + + # Give the IDE some directions to display tests in a "Unit-tests" folder + set_target_properties(${TEST_NAME} PROPERTIES FOLDER Unit-tests) + + # Linux only. TODO remove ? + if(UNIX AND NOT APPLE) + target_link_libraries(${TEST_NAME} PRIVATE stdc++fs) + endif() + +endfunction() diff --git a/src/tests/src/api_internal/CMakeLists.txt b/src/tests/src/api_internal/CMakeLists.txt index 1c972cd4c6..e3bb61472e 100644 --- a/src/tests/src/api_internal/CMakeLists.txt +++ b/src/tests/src/api_internal/CMakeLists.txt @@ -1,28 +1,11 @@ -set(EXECUTABLE_NAME test-api) -add_executable(${EXECUTABLE_NAME}) - -target_sources(${EXECUTABLE_NAME} - PRIVATE - test_api.cpp -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - Antares::solver_api - Antares::tests::in-memory-study - test_utils_unit -) - -target_include_directories(${EXECUTABLE_NAME} - PRIVATE - #Allow to use the private headers - $ -) - -# Storing tests-ts-numbers under the folder Unit-tests in the IDE -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) - -add_test(NAME test-api COMMAND ${EXECUTABLE_NAME}) - -set_property(TEST test-api PROPERTY LABELS unit) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + +add_boost_test(test-api + SRC test_api.cpp + LIBS + Antares::solver_api + Antares::tests::in-memory-study + test_utils_unit + #Allow to use the private headers + INCLUDE + $) diff --git a/src/tests/src/api_lib/CMakeLists.txt b/src/tests/src/api_lib/CMakeLists.txt index b5ce633955..f45e9d65e4 100644 --- a/src/tests/src/api_lib/CMakeLists.txt +++ b/src/tests/src/api_lib/CMakeLists.txt @@ -1,20 +1,5 @@ -set(EXECUTABLE_NAME test-client-api) -add_executable(${EXECUTABLE_NAME}) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -target_sources(${EXECUTABLE_NAME} - PRIVATE - test_api.cpp -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - Antares::solver_api -) - -# Storing tests-ts-numbers under the folder Unit-tests in the IDE -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) - -add_test(NAME test-client-api COMMAND ${EXECUTABLE_NAME}) - -set_property(TEST test-client-api PROPERTY LABELS unit) +add_boost_test(test-client-api + SRC test_api.cpp + LIBS Antares::solver_api) diff --git a/src/tests/src/libs/antares/CMakeLists.txt b/src/tests/src/libs/antares/CMakeLists.txt index 97ef92fd0e..90def4d900 100644 --- a/src/tests/src/libs/antares/CMakeLists.txt +++ b/src/tests/src/libs/antares/CMakeLists.txt @@ -18,108 +18,63 @@ set(SRC_MATRIX_LIB # Necessary cpp files ${src_libs_antares}/jit/jit.cpp - logs/logs.cpp - ) + logs/logs.cpp) add_library(matrix ${SRC_MATRIX_LIB}) target_link_libraries(matrix PUBLIC - yuni-static-core -) + yuni-static-core) target_include_directories(matrix - PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/logs" - "${src_libs_antares}/jit/include" - ) - -# Storing lib-matrix under the folder Unit-tests in the IDE -set_target_properties(matrix PROPERTIES FOLDER Unit-tests) + PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/logs" + "${src_libs_antares}/jit/include") # Building tests on Matrix save operations -set(SRC_TEST_MATRIX_SAVE - logs/antares/logs/logs.h - array/fill-matrix.h - array/matrix-bypass-load.h - array/tests-matrix-save.h - array/tests-matrix-save.cpp - ) - -add_executable(tests-matrix-save ${SRC_TEST_MATRIX_SAVE}) - -target_include_directories(tests-matrix-save - PRIVATE - "${src_libs_antares}/array/include" - "${src_libs_antares}/io/include" - "${src_libs_antares}/jit/include" - "${src_libs_antares}/memory/include" - "${CMAKE_CURRENT_SOURCE_DIR}/logs" - "${CMAKE_CURRENT_SOURCE_DIR}/jit" - "${CMAKE_SOURCE_DIR}/tests/src/libs" - - ) - -target_link_libraries(tests-matrix-save - PRIVATE - matrix - yuni-static-core - Boost::unit_test_framework - antares-core -) - -# Storing tests-matrix-save under the folder Unit-tests in the IDE -set_target_properties(tests-matrix-save PROPERTIES FOLDER Unit-tests) - -add_test(NAME save-matrix COMMAND tests-matrix-save) - -set_property(TEST save-matrix PROPERTY LABELS unit) +add_boost_test(tests-matrix-save + SRC + logs/antares/logs/logs.h + array/fill-matrix.h + array/matrix-bypass-load.h + array/tests-matrix-save.h + array/tests-matrix-save.cpp + INCLUDE + "${src_libs_antares}/array/include" + "${src_libs_antares}/io/include" + "${src_libs_antares}/jit/include" + "${src_libs_antares}/memory/include" + "${CMAKE_CURRENT_SOURCE_DIR}/logs" + "${CMAKE_CURRENT_SOURCE_DIR}/jit" + "${CMAKE_SOURCE_DIR}/tests/src/libs" + LIBS + matrix + yuni-static-core + antares-core) # Building tests on Matrix load operations -set(SRC_TEST_MATRIX_LOAD - array/fill-matrix.h - array/matrix-bypass-load.h - array/tests-matrix-load.h - array/tests-matrix-load.cpp - ) - -add_executable(tests-matrix-load ${SRC_TEST_MATRIX_LOAD}) -target_include_directories(tests-matrix-load - PRIVATE - "${src_libs_antares}/array/include" - "${src_libs_antares}/io/include" - "${src_libs_antares}/jit/include" - "${src_libs_antares}/memory/include" - "${CMAKE_CURRENT_SOURCE_DIR}/logs" - "${CMAKE_CURRENT_SOURCE_DIR}/jit" - "${CMAKE_SOURCE_DIR}/tests/src/libs" -) - - -target_link_libraries(tests-matrix-load - PRIVATE - matrix - yuni-static-core - Boost::unit_test_framework - antares-core -) - -# Storing tests-matrix-load under the folder Unit-tests in the IDE -set_target_properties(tests-matrix-load PROPERTIES FOLDER Unit-tests) - -add_test(NAME load-matrix COMMAND tests-matrix-load) - -set_property(TEST load-matrix PROPERTY LABELS unit) - - -add_executable(test-utils test_utils.cpp) -target_link_libraries(test-utils - PRIVATE - Boost::unit_test_framework - Antares::utils - yuni-static-core -) -set_target_properties(test-utils PROPERTIES FOLDER Unit-tests/test-utils) - -add_test(NAME test-utils COMMAND test-utils) -set_property(TEST test-utils PROPERTY LABELS unit) +add_boost_test(tests-matrix-load + SRC + array/fill-matrix.h + array/matrix-bypass-load.h + array/tests-matrix-load.h + array/tests-matrix-load.cpp + INCLUDE + "${src_libs_antares}/array/include" + "${src_libs_antares}/io/include" + "${src_libs_antares}/jit/include" + "${src_libs_antares}/memory/include" + "${CMAKE_CURRENT_SOURCE_DIR}/logs" + "${CMAKE_CURRENT_SOURCE_DIR}/jit" + "${CMAKE_SOURCE_DIR}/tests/src/libs" + LIBS + matrix + yuni-static-core + antares-core) + +# Test utilities +add_boost_test(test-utils + SRC test_utils.cpp + LIBS + Antares::utils + yuni-static-core) diff --git a/src/tests/src/libs/antares/antlr4-interface/CMakeLists.txt b/src/tests/src/libs/antares/antlr4-interface/CMakeLists.txt index f74e12981c..508489e76a 100644 --- a/src/tests/src/libs/antares/antlr4-interface/CMakeLists.txt +++ b/src/tests/src/libs/antares/antlr4-interface/CMakeLists.txt @@ -1,20 +1,9 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) find_package(antlr4-runtime CONFIG REQUIRED) -Set(SRCS test_antlr_interface.cpp -) - -set(execname "antlr-interface-test") -add_executable(${execname} ${SRCS}) -target_link_libraries(${execname} - PRIVATE - antlr-interface - Boost::unit_test_framework - ) - - -target_include_directories(${execname} - PRIVATE - ${ANTLR4_INCLUDE_DIR}) -add_test(NAME antlr-interface COMMAND ${execname}) - -set_tests_properties(antlr-interface PROPERTIES LABELS unit) +add_boost_test(antlr-interface-test + SRC test_antlr_interface.cpp + LIBS + antlr-interface + INCLUDE + ${ANTLR4_INCLUDE_DIR}) diff --git a/src/tests/src/libs/antares/benchmarking/CMakeLists.txt b/src/tests/src/libs/antares/benchmarking/CMakeLists.txt index 911f6e12e4..4ad4a1b712 100644 --- a/src/tests/src/libs/antares/benchmarking/CMakeLists.txt +++ b/src/tests/src/libs/antares/benchmarking/CMakeLists.txt @@ -1,15 +1,5 @@ -set(PROJ test-duration-collector) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -add_executable(${PROJ}) -target_sources(${PROJ} PRIVATE test_duration_collector.cpp) -target_link_libraries(${PROJ} - PRIVATE - Antares::benchmarking - Boost::unit_test_framework -) - -set_target_properties(${PROJ} PROPERTIES FOLDER Unit-tests/${PROJ}) - -add_test(NAME ${PROJ} COMMAND ${PROJ}) - -set_property(TEST ${PROJ} PROPERTY LABELS unit) +add_boost_test(test-duration-collector + SRC test_duration_collector.cpp + LIBS Antares::benchmarking) diff --git a/src/tests/src/libs/antares/concurrency/CMakeLists.txt b/src/tests/src/libs/antares/concurrency/CMakeLists.txt index 563d89524f..07004c0290 100644 --- a/src/tests/src/libs/antares/concurrency/CMakeLists.txt +++ b/src/tests/src/libs/antares/concurrency/CMakeLists.txt @@ -1,14 +1,5 @@ -add_executable(test-concurrency) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -target_sources(test-concurrency PRIVATE test_concurrency.cpp) - -target_link_libraries(test-concurrency - PRIVATE - Boost::unit_test_framework - Antares::concurrency -) - -set_target_properties(test-concurrency PROPERTIES FOLDER Unit-tests/test-concurrency) - -add_test(NAME concurrency COMMAND test-concurrency) -set_property(TEST concurrency PROPERTY LABELS unit) +add_boost_test(test-concurrency + SRC test_concurrency.cpp + LIBS Antares::concurrency) diff --git a/src/tests/src/libs/antares/inifile/CMakeLists.txt b/src/tests/src/libs/antares/inifile/CMakeLists.txt index 1670c13084..e99ae8500d 100644 --- a/src/tests/src/libs/antares/inifile/CMakeLists.txt +++ b/src/tests/src/libs/antares/inifile/CMakeLists.txt @@ -1,15 +1,5 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -add_executable(test_inifile_io test_inifile_io.cpp) - -target_link_libraries(test_inifile_io - PRIVATE - inifile - Boost::unit_test_framework -) - -# Storing executable under the folder Unit-tests in the IDE -set_target_properties(test_inifile_io PROPERTIES FOLDER Unit-tests/test_inifile_io) - -add_test(NAME test_inifile_io COMMAND test_inifile_io) - -set_property(TEST test_inifile_io PROPERTY LABELS unit) +add_boost_test(test_inifile_io + SRC test_inifile_io.cpp + LIBS inifile) diff --git a/src/tests/src/libs/antares/study/CMakeLists.txt b/src/tests/src/libs/antares/study/CMakeLists.txt index c4edfc9dfa..b78478c050 100644 --- a/src/tests/src/libs/antares/study/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/CMakeLists.txt @@ -1,3 +1,5 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + set(src_tests_src_libs_antares_study "${CMAKE_CURRENT_SOURCE_DIR}") add_subdirectory(area) @@ -10,14 +12,6 @@ add_subdirectory(parts) add_subdirectory(series) add_subdirectory(parameters) -add_executable(test-study) -target_sources(test-study PRIVATE test_study.cpp) -target_link_libraries(test-study - PRIVATE - Antares::study - Boost::unit_test_framework -) - -add_test(NAME test-study COMMAND test-study) - -set_property(TEST test-study PROPERTY LABELS unit) +add_boost_test(test-study + SRC test_study.cpp + LIBS Antares::study) diff --git a/src/tests/src/libs/antares/study/area/CMakeLists.txt b/src/tests/src/libs/antares/study/area/CMakeLists.txt index fc726aa02c..947fbeed46 100644 --- a/src/tests/src/libs/antares/study/area/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/area/CMakeLists.txt @@ -1,3 +1,5 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + # Useful variables definitions set(src_libs_antares_study "${CMAKE_SOURCE_DIR}/libs/antares/study") @@ -9,29 +11,10 @@ set(SRC_LINK_PROPERTIES files-helper.cpp test-save-link-properties.cpp ) -add_executable(test-save-link-properties ${SRC_LINK_PROPERTIES}) - -target_include_directories(test-save-link-properties - PRIVATE - "${src_libs_antares_study}/include" -) -target_link_libraries(test-save-link-properties - PRIVATE - Boost::unit_test_framework - model_antares -) -# Linux -if(UNIX AND NOT APPLE) -target_link_libraries(test-save-link-properties PRIVATE stdc++fs) -endif() - - -# Storing test-save-link-properties under the folder Unit-tests in the IDE -set_target_properties(test-save-link-properties PROPERTIES FOLDER Unit-tests) - -add_test(NAME save-link-properties COMMAND test-save-link-properties) - -set_property(TEST save-link-properties PROPERTY LABELS unit) +add_boost_test(test-save-link-properties + SRC ${SRC_LINK_PROPERTIES} + INCLUDE "${src_libs_antares_study}/include" + LIBS model_antares) # =================================== # Tests on area's optimization.ini @@ -39,30 +22,9 @@ set_property(TEST save-link-properties PROPERTY LABELS unit) set(SRC_AREA_OPTIMIZATION files-helper.h files-helper.cpp - test-save-area-optimization-ini.cpp -) -add_executable(test-save-area-optimization-ini ${SRC_AREA_OPTIMIZATION}) - -target_include_directories(test-save-area-optimization-ini - PRIVATE - "${src_libs_antares_study}/include" -) -target_link_libraries(test-save-area-optimization-ini - PRIVATE - Boost::unit_test_framework - model_antares -) - -# Linux -if(UNIX AND NOT APPLE) -target_link_libraries(test-save-area-optimization-ini PRIVATE stdc++fs) -endif() - - -# Storing test-save-area-optimization-ini under the folder Unit-tests in the IDE -set_target_properties(test-save-area-optimization-ini PROPERTIES FOLDER Unit-tests) - -add_test(NAME save-area-optimization COMMAND test-save-area-optimization-ini) - -set_property(TEST save-area-optimization PROPERTY LABELS unit) + test-save-area-optimization-ini.cpp) +add_boost_test(test-save-area-optimization-ini + SRC ${SRC_AREA_OPTIMIZATION} + INCLUDE "${src_libs_antares_study}/include" + LIBS model_antares) diff --git a/src/tests/src/libs/antares/study/constraint/CMakeLists.txt b/src/tests/src/libs/antares/study/constraint/CMakeLists.txt index f9940d2247..c5295f5455 100644 --- a/src/tests/src/libs/antares/study/constraint/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/constraint/CMakeLists.txt @@ -1,45 +1,13 @@ -add_executable(test_constraint - test_constraint.cpp - ) - -target_link_libraries(test_constraint - PRIVATE - test_utils_unit - Boost::unit_test_framework - Antares::study - ) - -# Storing test_constraint under the folder Unit-tests in the IDE -set_target_properties(test_constraint PROPERTIES FOLDER Unit-tests) - -if(UNIX AND NOT APPLE) - target_link_libraries(test_constraint PRIVATE stdc++fs) -endif() - -add_test(NAME test_constraint COMMAND test_constraint) - -set_property(TEST test_constraint PROPERTY LABELS unit) - -################ - -add_executable(test_groups - test_group.cpp - ) - -target_link_libraries(test_groups - PRIVATE - test_utils_unit - Boost::unit_test_framework - Antares::study - ) - -# Storing test_constraint under the folder Unit-tests in the IDE -set_target_properties(test_groups PROPERTIES FOLDER Unit-tests) - -if(UNIX AND NOT APPLE) - target_link_libraries(test_groups PRIVATE stdc++fs) -endif() - -add_test(NAME test_groups COMMAND test_groups) - -set_property(TEST test_groups PROPERTY LABELS unit) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + +add_boost_test(test_constraint + SRC test_constraint.cpp + LIBS + test_utils_unit + Antares::study) + +add_boost_test(test_groups + SRC test_group.cpp + LIBS + test_utils_unit + Antares::study) diff --git a/src/tests/src/libs/antares/study/output-folder/CMakeLists.txt b/src/tests/src/libs/antares/study/output-folder/CMakeLists.txt index feca6f3bb8..06988e3e85 100644 --- a/src/tests/src/libs/antares/study/output-folder/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/output-folder/CMakeLists.txt @@ -1,31 +1,9 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + # Useful variables definitions set(src_libs_antares_study "${CMAKE_SOURCE_DIR}/libs/antares/study") -add_executable(test-folder-output study.cpp) - -target_include_directories(test-folder-output - PRIVATE - "${src_libs_antares_study}" -) - -target_link_libraries(test-folder-output - PRIVATE - Boost::unit_test_framework - Antares::study -) - -# Linux -if(UNIX AND NOT APPLE) -target_link_libraries(test-folder-output PRIVATE stdc++fs) -endif() - - -# Storing test-save-link-properties under the folder Unit-tests in the IDE -set_target_properties(test-folder-output PROPERTIES FOLDER Unit-tests) - -import_std_libs(test-folder-output) - -add_test(NAME folder-output COMMAND test-folder-output) -set_property(TEST folder-output PROPERTY LABELS unit) - - +add_boost_test(test-folder-output + SRC study.cpp + INCLUDE "${src_libs_antares_study}" + LIBS Antares::study) diff --git a/src/tests/src/libs/antares/study/parameters/CMakeLists.txt b/src/tests/src/libs/antares/study/parameters/CMakeLists.txt index 7e22aad5d1..39341e10ae 100644 --- a/src/tests/src/libs/antares/study/parameters/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/parameters/CMakeLists.txt @@ -1,20 +1,8 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + # ==================================== # Tests on Parameters class # ==================================== -set(SRC_PARAMETERS_TESTS - parameters-tests.cpp -) -add_executable(parameters-tests ${SRC_PARAMETERS_TESTS}) - -target_link_libraries(parameters-tests - PRIVATE - Boost::unit_test_framework - Antares::study -) - -# Storing parameters-tests under the folder Unit-tests in the IDE -set_target_properties(parameters-tests PROPERTIES FOLDER Unit-tests/parameters-tests) - -add_test(NAME parameters-tests COMMAND parameters-tests) - -set_property(TEST parameters-tests PROPERTY LABELS unit) +add_boost_test(parameters-tests + SRC parameters-tests.cpp + LIBS Antares::study) diff --git a/src/tests/src/libs/antares/study/parts/hydro/CMakeLists.txt b/src/tests/src/libs/antares/study/parts/hydro/CMakeLists.txt index 52937063c8..8b5dee7bc3 100644 --- a/src/tests/src/libs/antares/study/parts/hydro/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/parts/hydro/CMakeLists.txt @@ -1,44 +1,15 @@ -# Hydro data reader -set(SRC_HYDRO_READER - test-hydroreader-class.cpp) - -add_executable(test-hydro-reader ${SRC_HYDRO_READER}) - -target_link_libraries(test-hydro-reader - PRIVATE - Boost::unit_test_framework - Antares::study - test_utils_unit -) - -# Linux -if(UNIX AND NOT APPLE) - target_link_libraries(test-hydro-reader PRIVATE stdc++fs) -endif() - -set_target_properties(test-hydro-reader PROPERTIES FOLDER Unit-tests/hydro) -add_test(NAME hydro-reader COMMAND test-hydro-reader) -set_property(TEST hydro-reader PROPERTY LABELS unit) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) +# Hydro data reader +add_boost_test(test-hydro-reader + SRC test-hydroreader-class.cpp + LIBS + Antares::study + test_utils_unit) # Hydro series -set(SRC_HYDRO_SERIES - test-hydro-series.cpp) - -add_executable(test-hydro-series ${SRC_HYDRO_SERIES}) - -target_link_libraries(test-hydro-series - PRIVATE - Boost::unit_test_framework - Antares::study - test_utils_unit -) - -# Linux -if(UNIX AND NOT APPLE) - target_link_libraries(test-hydro-series PRIVATE stdc++fs) -endif() - -set_target_properties(test-hydro-series PROPERTIES FOLDER Unit-tests/hydro) -add_test(NAME hydro-series COMMAND test-hydro-series) -set_property(TEST hydro-series PROPERTY LABELS unit) \ No newline at end of file +add_boost_test(test-hydro-series + SRC test-hydro-series.cpp + LIBS + Antares::study + test_utils_unit) diff --git a/src/tests/src/libs/antares/study/scenario-builder/CMakeLists.txt b/src/tests/src/libs/antares/study/scenario-builder/CMakeLists.txt index 2f65c75b70..2444753e9c 100644 --- a/src/tests/src/libs/antares/study/scenario-builder/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/scenario-builder/CMakeLists.txt @@ -1,62 +1,26 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + # Useful variables definitions set(src_libs_antares_study "${CMAKE_SOURCE_DIR}/libs/antares/study") # ==================================== # Tests on reading scenario-builder # ==================================== -set(SRC_SC_BUILDER_READ - test-sc-builder-file-read-line.cpp -) -add_executable(test-sc-builder-file-read-line ${SRC_SC_BUILDER_READ}) - -target_include_directories(test-sc-builder-file-read-line - PRIVATE - "${src_libs_antares_study}/include" -) - -target_link_libraries(test-sc-builder-file-read-line - PRIVATE - Boost::unit_test_framework - model_antares -) -# Linux -if(UNIX AND NOT APPLE) -target_link_libraries(test-sc-builder-file-read-line PRIVATE stdc++fs) -endif() - - -# Storing test-sc-builder-file-read-line under the folder Unit-tests in the IDE -add_test(NAME sc-builder-file-read-line COMMAND test-sc-builder-file-read-line) -set_property(TEST sc-builder-file-read-line PROPERTY LABELS unit) -set_target_properties(test-sc-builder-file-read-line PROPERTIES FOLDER Unit-tests/sc-builder) - - +add_boost_test(test-sc-builder-file-read-line + SRC test-sc-builder-file-read-line.cpp + INCLUDE "${src_libs_antares_study}/include" + LIBS model_antares) # ==================================== # Tests on saving scenario-builder # ==================================== -set(SRC_SC_BUILDER_SAVE - test-sc-builder-file-save.cpp - "${src_tests_src_libs_antares_study}/area/files-helper.cpp" -) -add_executable(test-sc-builder-file-save ${SRC_SC_BUILDER_SAVE}) - -target_include_directories(test-sc-builder-file-save - PRIVATE - "${src_libs_antares_study}" - "${src_libs_antares_study}/scenario-builder" - "${src_tests_src_libs_antares_study}" -) - -target_link_libraries(test-sc-builder-file-save - PRIVATE - Boost::unit_test_framework - model_antares -) - -# Storing test-sc-builder-file-savee under the folder Unit-tests in the IDE -set_target_properties(test-sc-builder-file-save PROPERTIES FOLDER Unit-tests/sc-builder) - -add_test(NAME sc-builder-file-save COMMAND test-sc-builder-file-save) - -set_property(TEST sc-builder-file-save PROPERTY LABELS unit) +add_boost_test(test-sc-builder-file-save + SRC + test-sc-builder-file-save.cpp + "${src_tests_src_libs_antares_study}/area/files-helper.cpp" + INCLUDE + "${src_libs_antares_study}" + "${src_libs_antares_study}/scenario-builder" + "${src_tests_src_libs_antares_study}" + LIBS + model_antares) diff --git a/src/tests/src/libs/antares/study/series/CMakeLists.txt b/src/tests/src/libs/antares/study/series/CMakeLists.txt index 27c31d1728..7777264127 100644 --- a/src/tests/src/libs/antares/study/series/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/series/CMakeLists.txt @@ -1,22 +1,11 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + # ==================================== # Tests on TimeSeries class # ==================================== -set(SRC_TIMESERIES_TESTS - timeseries-tests.cpp -) -add_executable(timeseries-tests ${SRC_TIMESERIES_TESTS}) - -target_link_libraries(timeseries-tests - PRIVATE - Antares::array - Boost::unit_test_framework - Antares::series - antares-solver-simulation -) - -# Storing timeseries-tests under the folder Unit-tests in the IDE -set_target_properties(timeseries-tests PROPERTIES FOLDER Unit-tests/timeseries-tests) - -add_test(NAME timeseries-tests COMMAND timeseries-tests) - -set_property(TEST timeseries-tests PROPERTY LABELS unit) +add_boost_test(timeseries-tests + SRC timeseries-tests.cpp + LIBS + Antares::array + Antares::series + antares-solver-simulation) diff --git a/src/tests/src/libs/antares/study/short-term-storage-input/CMakeLists.txt b/src/tests/src/libs/antares/study/short-term-storage-input/CMakeLists.txt index 045e8ed944..afa269be4e 100644 --- a/src/tests/src/libs/antares/study/short-term-storage-input/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/short-term-storage-input/CMakeLists.txt @@ -1,33 +1,6 @@ -# Useful variables definitions -set(src_libs_antares_study "${CMAKE_SOURCE_DIR}/libs/antares/study") +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -# ==================================== -# Tests on reading scenario-builder -# ==================================== -set(SRC_SC_BUILDER_READ - short-term-storage-input-output.cpp -) -add_executable(short-term-storage-input ${SRC_SC_BUILDER_READ}) - -target_include_directories(short-term-storage-input - PRIVATE - "${src_libs_antares_study}/parts/short-term-storage" -) - -target_link_libraries(short-term-storage-input - PRIVATE - Boost::unit_test_framework - model_antares -) -# Linux -if(UNIX AND NOT APPLE) -target_link_libraries(short-term-storage-input PRIVATE stdc++fs) -endif() - - -# Storing short-term-storage-input under the folder Unit-tests in the IDE -set_target_properties(short-term-storage-input PROPERTIES FOLDER Unit-tests/short-term-storage-input) - -add_test(NAME short-term-storage-input COMMAND short-term-storage-input) - -set_property(TEST short-term-storage-input PROPERTY LABELS unit) +add_boost_test(short-term-storage-input + SRC short-term-storage-input-output.cpp + LIBS model_antares + INCLUDE "${src_libs_antares_study}/parts/short-term-storage") diff --git a/src/tests/src/libs/antares/study/thermal-price-definition/CMakeLists.txt b/src/tests/src/libs/antares/study/thermal-price-definition/CMakeLists.txt index 43c7aca74e..1b37de47a3 100644 --- a/src/tests/src/libs/antares/study/thermal-price-definition/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/thermal-price-definition/CMakeLists.txt @@ -1,3 +1,5 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + # Useful variables definitions set(src_libs_antares_study "${CMAKE_SOURCE_DIR}/libs/antares/study") set(src_libs_antares_checks "${CMAKE_SOURCE_DIR}/libs/antares/checks") @@ -5,36 +7,15 @@ set(src_libs_antares_checks "${CMAKE_SOURCE_DIR}/libs/antares/checks") # ==================================== # Tests on thermal price definition # ==================================== -set(SRC_THERM_PRICE_DEF - thermal-price-definition.cpp -) -add_executable(thermal-price-definition ${SRC_THERM_PRICE_DEF}) - -target_include_directories(thermal-price-definition - PRIVATE - "${src_libs_antares_study}/parts/thermal" - "${src_libs_antares_study}/area" - "${src_libs_antares_study}" - "${src_libs_antares_checks}" -) - -target_link_libraries(thermal-price-definition - PRIVATE - Boost::unit_test_framework - checks - Antares::study - Antares::exception - Antares::checks -) -# Linux -if(UNIX AND NOT APPLE) -target_link_libraries(thermal-price-definition PRIVATE stdc++fs) -endif() - - -# Storing thermal-price-definition under the folder Unit-tests in the IDE -set_target_properties(thermal-price-definition PROPERTIES FOLDER Unit-tests/thermal-price-definition) - -add_test(NAME thermal-price-definition COMMAND thermal-price-definition) - -set_property(TEST thermal-price-definition PROPERTY LABELS unit) +add_boost_test(thermal-price-definition + SRC thermal-price-definition.cpp + LIBS + checks + Antares::study + Antares::exception + Antares::checks + INCLUDE + "${src_libs_antares_study}/parts/thermal" + "${src_libs_antares_study}/area" + "${src_libs_antares_study}" + "${src_libs_antares_checks}") diff --git a/src/tests/src/libs/antares/writer/CMakeLists.txt b/src/tests/src/libs/antares/writer/CMakeLists.txt index b85bcce05c..36f5a678a0 100644 --- a/src/tests/src/libs/antares/writer/CMakeLists.txt +++ b/src/tests/src/libs/antares/writer/CMakeLists.txt @@ -1,15 +1,10 @@ -# Zip writer -add_executable(test-writer test_writer.cpp) - -target_link_libraries(test-writer - PRIVATE - Boost::unit_test_framework - Antares::result_writer - test_utils_unit - MINIZIP::minizip -) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -set_target_properties(test-writer PROPERTIES FOLDER Unit-tests/test-writer) +# Zip writer +add_boost_test(test-writer + SRC test_writer.cpp + LIBS + Antares::result_writer + test_utils_unit + MINIZIP::minizip) -add_test(NAME writer COMMAND test-writer) -set_tests_properties(writer PROPERTIES LABELS unit) diff --git a/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt b/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt index dd9ef54891..dbb1a0535a 100644 --- a/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt +++ b/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt @@ -1,14 +1,5 @@ -set(SRCS test_yaml_parser.cpp -) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -set(execname "yaml-parser-test") -add_executable(${execname} ${SRCS}) -target_link_libraries(${execname} - PRIVATE - yaml-cpp - Boost::unit_test_framework) - - -add_test(NAME yaml-parser COMMAND ${execname}) - -set_tests_properties(yaml-parser PROPERTIES LABELS unit) +add_boost_test(yaml-parser-test + SRC test_yaml_parser.cpp + LIBS yaml-cpp) diff --git a/src/tests/src/solver/expressions/CMakeLists.txt b/src/tests/src/solver/expressions/CMakeLists.txt index 4eeca6d0fe..c41dde6d3b 100644 --- a/src/tests/src/solver/expressions/CMakeLists.txt +++ b/src/tests/src/solver/expressions/CMakeLists.txt @@ -1,31 +1,17 @@ -set(EXECUTABLE_NAME test-expressions) -add_executable(${EXECUTABLE_NAME}) - -target_sources(${EXECUTABLE_NAME} - PRIVATE - test_main.cpp - test_nodes.cpp - test_PrintAndEvalNodes.cpp - test_TimeIndexVisitor.cpp - test_SubstitutionVisitor.cpp - test_LinearVisitor.cpp - test_CompareVisitor.cpp - test_CloneVisitor.cpp - test_DeepWideTrees.cpp - test_Iterators.cpp - test_AstDOTStyleVisitor.cpp -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - solver-expressions - solver-expressions-iterators -) - -# Storing tests-ts-numbers under the folder Unit-tests in the IDE -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) - -add_test(NAME test-expressions COMMAND ${EXECUTABLE_NAME}) - -set_property(TEST test-expressions PROPERTY LABELS unit) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) +add_boost_test(test-expressions + SRC + test_main.cpp + test_nodes.cpp + test_PrintAndEvalNodes.cpp + test_TimeIndexVisitor.cpp + test_SubstitutionVisitor.cpp + test_LinearVisitor.cpp + test_CompareVisitor.cpp + test_CloneVisitor.cpp + test_DeepWideTrees.cpp + test_Iterators.cpp + test_AstDOTStyleVisitor.cpp + LIBS + solver-expressions + solver-expressions-iterators) diff --git a/src/tests/src/solver/infeasible-problem-analysis/CMakeLists.txt b/src/tests/src/solver/infeasible-problem-analysis/CMakeLists.txt index 8a8a0e9544..845f1cd124 100644 --- a/src/tests/src/solver/infeasible-problem-analysis/CMakeLists.txt +++ b/src/tests/src/solver/infeasible-problem-analysis/CMakeLists.txt @@ -1,16 +1,7 @@ -add_executable(test-unfeasible-problem-analyzer) -target_sources(test-unfeasible-problem-analyzer - PRIVATE - test-unfeasible-problem-analyzer.cpp) -target_link_libraries(test-unfeasible-problem-analyzer - PRIVATE - Boost::unit_test_framework - infeasible_problem_analysis - ortools::ortools -) - -add_test(NAME test-unfeasible-problem-analyzer COMMAND test-unfeasible-problem-analyzer) - -# Storing the executable under the folder Unit-tests in Visual Studio -set_target_properties(test-unfeasible-problem-analyzer PROPERTIES FOLDER Unit-tests) -set_property(TEST test-unfeasible-problem-analyzer PROPERTY LABELS unit) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) +add_boost_test(test-unfeasible-problem-analyzer + SRC + test-unfeasible-problem-analyzer.cpp + LIBS + infeasible_problem_analysis + ortools::ortools) diff --git a/src/tests/src/solver/lps/CMakeLists.txt b/src/tests/src/solver/lps/CMakeLists.txt index 89121152ba..596dd71ff6 100644 --- a/src/tests/src/solver/lps/CMakeLists.txt +++ b/src/tests/src/solver/lps/CMakeLists.txt @@ -1,20 +1,5 @@ -set(EXECUTABLE_NAME test-lps) -add_executable(${EXECUTABLE_NAME}) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -target_sources(${EXECUTABLE_NAME} - PRIVATE - test_lps.cpp -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - antares-solver-simulation -) - -# Storing tests-ts-numbers under the folder Unit-tests in the IDE -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) - -add_test(NAME test-lps COMMAND ${EXECUTABLE_NAME}) - -set_property(TEST test-lps PROPERTY LABELS unit) +add_boost_test(test-lps + SRC test_lps.cpp + LIBS antares-solver-simulation) diff --git a/src/tests/src/solver/modelParser/CMakeLists.txt b/src/tests/src/solver/modelParser/CMakeLists.txt index 9c5fad1f82..5969d66c16 100644 --- a/src/tests/src/solver/modelParser/CMakeLists.txt +++ b/src/tests/src/solver/modelParser/CMakeLists.txt @@ -1,34 +1,18 @@ -# Add source files -set(SOURCE_FILES - testModelParser.cpp - testModelTranslator.cpp - testConvertorVisitor.cpp - test_full.cpp - enum_operators.h - testSystemParser.cpp - testSystemConverter.cpp -) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -# Add executable -add_executable(TestModelParser ${SOURCE_FILES}) - -# Link libraries -target_link_libraries(TestModelParser - PRIVATE - Boost::unit_test_framework - Antares::solver-expressions - Antares::modelConverter - Antares::modelParser - Antares::systemParser - Antares::antares-study-system-model - Antares::antlr-interface -) - -# Storing test-toybox under the folder Unit-tests in the IDE -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) - -# Add the test -add_test(NAME TestModelParser COMMAND TestModelParser) - -# Set test properties -set_property(TEST TestModelParser PROPERTY LABELS unit) +add_boost_test(TestModelParser + SRC + testModelParser.cpp + testModelTranslator.cpp + testConvertorVisitor.cpp + test_full.cpp + enum_operators.h + testSystemParser.cpp + testSystemConverter.cpp + LIBS + Antares::solver-expressions + Antares::modelConverter + Antares::modelParser + Antares::systemParser + Antares::antares-study-system-model + Antares::antlr-interface) diff --git a/src/tests/src/solver/modeler/api/CMakeLists.txt b/src/tests/src/solver/modeler/api/CMakeLists.txt index ae048140aa..76915ff504 100644 --- a/src/tests/src/solver/modeler/api/CMakeLists.txt +++ b/src/tests/src/solver/modeler/api/CMakeLists.txt @@ -1,24 +1,12 @@ -set(EXECUTABLE_NAME unit-tests-for-modeler-api) -add_executable(${EXECUTABLE_NAME}) - -target_sources(${EXECUTABLE_NAME} - PRIVATE - test_main.cpp - testModelerLinearProblemWithOrtools.cpp - testModelerLPbuilder.cpp -) -target_include_directories(${EXECUTABLE_NAME} - PRIVATE - "${src_solver_optimisation}" -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - Antares::modeler-ortools-impl -) - -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) -add_test(NAME ${EXECUTABLE_NAME} COMMAND ${EXECUTABLE_NAME}) -set_property(TEST ${EXECUTABLE_NAME} PROPERTY LABELS unit) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + +add_boost_test(unit-tests-for-modeler-api + SRC + test_main.cpp + testModelerLinearProblemWithOrtools.cpp + testModelerLPbuilder.cpp + INCLUDE + "${src_solver_optimisation}" + LIBS + Antares::modeler-ortools-impl) diff --git a/src/tests/src/solver/modeler/parameters/CMakeLists.txt b/src/tests/src/solver/modeler/parameters/CMakeLists.txt index 3e989c2b03..85c27e2969 100644 --- a/src/tests/src/solver/modeler/parameters/CMakeLists.txt +++ b/src/tests/src/solver/modeler/parameters/CMakeLists.txt @@ -1,14 +1,7 @@ -# Zip writer -add_executable(parse-parameters testParametersParsing.cpp) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -target_link_libraries(parse-parameters - PRIVATE - Boost::unit_test_framework - modeler-parameters - test_utils_unit -) - -set_target_properties(parse-parameters PROPERTIES FOLDER Unit-tests/test-writer) - -add_test(NAME parse-parameters COMMAND parse-parameters) -set_tests_properties(parse-parameters PROPERTIES LABELS unit) +add_boost_test(parse-parameters + SRC testParametersParsing.cpp + LIBS + modeler-parameters + test_utils_unit) diff --git a/src/tests/src/solver/optim-model-filler/CMakeLists.txt b/src/tests/src/solver/optim-model-filler/CMakeLists.txt index fa81c819b7..e6853bf8fc 100644 --- a/src/tests/src/solver/optim-model-filler/CMakeLists.txt +++ b/src/tests/src/solver/optim-model-filler/CMakeLists.txt @@ -1,29 +1,16 @@ -set(EXECUTABLE_NAME unit-tests-for-component-filler) -add_executable(${EXECUTABLE_NAME}) - -target_sources(${EXECUTABLE_NAME} - PRIVATE - test_main.cpp - test_componentFiller.cpp - test_linearExpression.cpp - test_readLinearExpressionVisitor.cpp - test_readLinearConstraintVisitor.cpp -) -target_include_directories(${EXECUTABLE_NAME} - PRIVATE - "${src_solver_optimisation}" -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - antares-study-system-model - Antares::modeler-ortools-impl - Antares::optim-model-filler - test_utils_unit -) - -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) -add_test(NAME ${EXECUTABLE_NAME} COMMAND ${EXECUTABLE_NAME}) -set_property(TEST ${EXECUTABLE_NAME} PROPERTY LABELS unit) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) +add_boost_test(unit-tests-for-component-filler + SRC + test_main.cpp + test_componentFiller.cpp + test_linearExpression.cpp + test_readLinearExpressionVisitor.cpp + test_readLinearConstraintVisitor.cpp + INCLUDE + "${src_solver_optimisation}" + LIBS + antares-study-system-model + Antares::modeler-ortools-impl + Antares::optim-model-filler + test_utils_unit) diff --git a/src/tests/src/solver/optimisation/adequacy_patch/CMakeLists.txt b/src/tests/src/solver/optimisation/adequacy_patch/CMakeLists.txt index bb28a99864..94aa87d377 100644 --- a/src/tests/src/solver/optimisation/adequacy_patch/CMakeLists.txt +++ b/src/tests/src/solver/optimisation/adequacy_patch/CMakeLists.txt @@ -1,24 +1,11 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + # Useful variables definitions set(src_solver_optimisation "${CMAKE_SOURCE_DIR}/solver/optimisation") -set(EXECUTABLE_NAME tests-adq-patch) -add_executable(${EXECUTABLE_NAME} adequacy_patch.cpp) - -target_include_directories(${EXECUTABLE_NAME} - PRIVATE - "${src_solver_optimisation}" -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - model_antares - array -) - -# Storing tests-ts-numbers under the folder Unit-tests in the IDE -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) - -add_test(NAME test-adq-patch COMMAND ${EXECUTABLE_NAME}) - -set_property(TEST test-adq-patch PROPERTY LABELS unit) +add_boost_test(tests-adq-patch + SRC adequacy_patch.cpp + INCLUDE "${src_solver_optimisation}" + LIBS + model_antares + array) diff --git a/src/tests/src/solver/optimisation/name-translator/CMakeLists.txt b/src/tests/src/solver/optimisation/name-translator/CMakeLists.txt index f5e1f0619d..81275e4af1 100644 --- a/src/tests/src/solver/optimisation/name-translator/CMakeLists.txt +++ b/src/tests/src/solver/optimisation/name-translator/CMakeLists.txt @@ -1,20 +1,5 @@ -set(EXECUTABLE_NAME test-name-translator) -add_executable(${EXECUTABLE_NAME}) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -target_sources(${EXECUTABLE_NAME} - PRIVATE - test_name_translator.cpp -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - model_antares -) - -# Storing tests-ts-numbers under the folder Unit-tests in the IDE -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) - -add_test(NAME test-name-translator COMMAND ${EXECUTABLE_NAME}) - -set_property(TEST test-name-translator PROPERTY LABELS unit) +add_boost_test(test-name-translator + SRC test_name_translator.cpp + LIBS model_antares) diff --git a/src/tests/src/solver/optimisation/translator/CMakeLists.txt b/src/tests/src/solver/optimisation/translator/CMakeLists.txt index 87f3d5a0cb..c211b7d32e 100644 --- a/src/tests/src/solver/optimisation/translator/CMakeLists.txt +++ b/src/tests/src/solver/optimisation/translator/CMakeLists.txt @@ -1,20 +1,5 @@ -set(EXECUTABLE_NAME test-translator) -add_executable(${EXECUTABLE_NAME}) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) -target_sources(${EXECUTABLE_NAME} - PRIVATE - test_translator.cpp -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - model_antares -) - -# Storing tests-ts-numbers under the folder Unit-tests in the IDE -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) - -add_test(NAME test-translator COMMAND ${EXECUTABLE_NAME}) - -set_property(TEST test-translator PROPERTY LABELS unit) +add_boost_test(test-translator + SRC test_translator.cpp + LIBS model_antares) diff --git a/src/tests/src/solver/simulation/CMakeLists.txt b/src/tests/src/solver/simulation/CMakeLists.txt index 294005454b..76d67765f7 100644 --- a/src/tests/src/solver/simulation/CMakeLists.txt +++ b/src/tests/src/solver/simulation/CMakeLists.txt @@ -1,3 +1,5 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + # Useful variables definitions set(src_solver_simulation "${CMAKE_SOURCE_DIR}/solver/simulation") set(src_solver_hydro "${CMAKE_SOURCE_DIR}/solver/hydro") @@ -11,112 +13,50 @@ set(SRC_TS_NUMBERS ${src_solver_simulation}/timeseries-numbers.cpp ${src_solver_simulation}/include/antares/solver/simulation/ITimeSeriesNumbersWriter.h) -add_executable(tests-ts-numbers tests-ts-numbers.cpp ${SRC_TS_NUMBERS}) - -target_include_directories(tests-ts-numbers - PRIVATE - "${src_solver_simulation}" - "${src_libs_antares_study}" -) -target_link_libraries(tests-ts-numbers - PRIVATE - Antares::utils - Boost::unit_test_framework - model_antares - antares-solver-simulation - antares-solver-ts-generator -) - -# Storing tests-ts-numbers under the folder Unit-tests in the IDE -set_target_properties(tests-ts-numbers PROPERTIES FOLDER Unit-tests) +add_boost_test(tests-ts-numbers + SRC tests-ts-numbers.cpp ${SRC_TS_NUMBERS} + INCLUDE + "${src_solver_simulation}" + "${src_libs_antares_study}" + LIBS + Antares::utils + model_antares + antares-solver-simulation + antares-solver-ts-generator) -add_test(NAME ts-numbers COMMAND tests-ts-numbers) - -set_property(TEST ts-numbers PROPERTY LABELS unit) # =================================== # Tests on area's store-timeseries-number # =================================== -set(SRC_STORE_TS - test-store-timeseries-number.cpp - ) -add_executable(test-store-timeseries-number ${SRC_STORE_TS}) - -target_link_libraries(test-store-timeseries-number - PRIVATE - Boost::unit_test_framework - test_utils_unit - antares-solver-simulation - Antares::study - Antares::result_writer - ) - -# Linux -if(UNIX AND NOT APPLE) - target_link_libraries(test-store-timeseries-number PRIVATE stdc++fs) -endif() - -set_target_properties(test-store-timeseries-number PROPERTIES FOLDER Unit-tests) - -add_test(NAME store-timeseries-number COMMAND test-store-timeseries-number) - -set_property(TEST store-timeseries-number PROPERTY LABELS unit) +add_boost_test(test-store-timeseries-number + SRC test-store-timeseries-number.cpp + LIBS + test_utils_unit + antares-solver-simulation + Antares::study + Antares::result_writer) # =================================== # Tests on time series # =================================== -set(SRC_STORE_TS - test-time_series.cpp - ) -add_executable(test-time_series ${SRC_STORE_TS}) - -target_link_libraries(test-time_series - PRIVATE - Boost::unit_test_framework - test_utils_unit - antares-solver-simulation - Antares::study - ) - -# Linux -if(UNIX AND NOT APPLE) - target_link_libraries(test-time_series PRIVATE stdc++fs) -endif() - - -set_target_properties(test-time_series PROPERTIES FOLDER Unit-tests) - -add_test(NAME time_series COMMAND test-time_series) - -set_property(TEST time_series PROPERTY LABELS unit) +add_boost_test(test-time_series + SRC test-time_series.cpp + LIBS + test_utils_unit + antares-solver-simulation + Antares::study) # =================================== # Tests on hydro final reservoir level functions # =================================== - -add_executable(test-hydro_final test-hydro-final-reservoir-level-functions.cpp) - -target_include_directories(test-hydro_final - PRIVATE - "${src_solver_simulation}" - "${src_libs_antares_study}" - "${src_solver_hydro}" -) -target_link_libraries(test-hydro_final - PRIVATE - Boost::unit_test_framework - Antares::study - antares-solver-simulation - Antares::array -) - -# Linux -if(UNIX AND NOT APPLE) - target_link_libraries(test-hydro_final PRIVATE stdc++fs) -endif() - -set_target_properties(test-hydro_final PROPERTIES FOLDER Unit-tests) - -add_test(NAME hydro_final COMMAND test-hydro_final) - -set_property(TEST hydro_final PROPERTY LABELS unit) \ No newline at end of file +add_boost_test(test-hydro_final + SRC + test-hydro-final-reservoir-level-functions.cpp + INCLUDE + "${src_solver_simulation}" + "${src_libs_antares_study}" + "${src_solver_hydro}" + LIBS + Antares::study + antares-solver-simulation + Antares::array) diff --git a/src/tests/src/solver/utils/CMakeLists.txt b/src/tests/src/solver/utils/CMakeLists.txt index b3331c6249..e93e01b496 100644 --- a/src/tests/src/solver/utils/CMakeLists.txt +++ b/src/tests/src/solver/utils/CMakeLists.txt @@ -1,20 +1,10 @@ -set(src_utils "${CMAKE_SOURCE_DIR}/solver/utils") - -set(EXECUTABLE_NAME tests-basis-status) -add_executable(${EXECUTABLE_NAME} basis_status.cpp) - - -target_include_directories(${EXECUTABLE_NAME} - PRIVATE - "${src_utils}" # basis_status_impl.h is private -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - ortools::ortools - Antares::solverUtils -) - -add_test(NAME test-basis-status COMMAND ${EXECUTABLE_NAME}) -set_property(TEST test-basis-status PROPERTY LABELS unit) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + +add_boost_test(tests-basis-status + SRC + basis_status.cpp + INCLUDE + "${CMAKE_SOURCE_DIR}/solver/utils" + LIBS + ortools::ortools + Antares::solverUtils) diff --git a/src/tests/src/study/system-model/CMakeLists.txt b/src/tests/src/study/system-model/CMakeLists.txt index 727635be3e..624da708a7 100644 --- a/src/tests/src/study/system-model/CMakeLists.txt +++ b/src/tests/src/study/system-model/CMakeLists.txt @@ -1,20 +1,10 @@ -set(EXECUTABLE_NAME test-system-model) -add_executable(${EXECUTABLE_NAME}) - -target_sources(${EXECUTABLE_NAME} - PRIVATE - test_main.cpp - test_component.cpp - test_system.cpp -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - antares-study-system-model - test_utils_unit -) - -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) -add_test(NAME test-system-model COMMAND ${EXECUTABLE_NAME}) -set_property(TEST test-system-model PROPERTY LABELS unit) +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) +add_boost_test(test-system-model + SRC + test_main.cpp + test_component.cpp + test_system.cpp + LIBS + Boost::unit_test_framework + antares-study-system-model + test_utils_unit) From f5f634c71cbcc0e91ca09c4febe4caab17e4356e Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Tue, 24 Dec 2024 11:24:22 +0100 Subject: [PATCH 089/103] rc 8 (#2547) --- .github/workflows/ubuntu.yml | 14 +++++++------- .github/workflows/windows-vcpkg.yml | 8 -------- simtest.json | 2 +- src/CMakeLists.txt | 2 +- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index daceabc0ff..226e8a01b0 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -170,7 +170,7 @@ jobs: run: | cd _build ctest -C Release --output-on-failure -L "unit|end-to-end" - + - name: Upload logs for failed tests if: ${{ failure() }} @@ -178,7 +178,7 @@ jobs: with: name: test-log path: ${{ github.workspace }}/_build/Testing/Temporary/LastTest.log - + - name: Run tests about infinity on BCs RHS if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} uses: ./.github/workflows/run-tests @@ -186,7 +186,7 @@ jobs: simtest-tag: ${{ env.SIMTEST }} batch-name: valid-v830 os: ${{ env.os }} - + - name: Run MILP with CBC if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} uses: ./.github/workflows/run-tests @@ -197,18 +197,18 @@ jobs: os: ${{ env.os }} - name: Run tests on adequacy patch (CSR) - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} uses: ./.github/workflows/run-tests with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} + simtest-tag: ${{ env.SIMTEST }} batch-name: adequacy-patch-CSR os: ${{ env.os }} - + - name: Run parallel tests if: ${{ env.RUN_EXTENDED_TESTS == 'true' }} uses: ./.github/workflows/run-tests with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} + simtest-tag: ${{ env.SIMTEST }} batch-name: valid-parallel os: ${{ env.os }} variant: "parallel" diff --git a/.github/workflows/windows-vcpkg.yml b/.github/workflows/windows-vcpkg.yml index 37d47eaadf..5fb4b19603 100644 --- a/.github/workflows/windows-vcpkg.yml +++ b/.github/workflows/windows-vcpkg.yml @@ -188,14 +188,6 @@ jobs: batch-name: adequacy-patch-CSR os: ${{ env.os }} - - name: Run tests about infinity on BCs RHS - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-v830 - os: ${{ env.test-platform }} - - name: Run tests about infinity on BCs RHS if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} uses: ./.github/workflows/run-tests diff --git a/simtest.json b/simtest.json index 11b8cee038..4f6f12a31e 100644 --- a/simtest.json +++ b/simtest.json @@ -1,3 +1,3 @@ { - "version": "v9.2.0g" + "version": "v9.2.0h" } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 32beee7a3a..1f0a6712b2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,7 @@ set(ANTARES_VERSION_REVISION 0) # Beta release set(ANTARES_BETA 0) -set(ANTARES_RC 7) +set(ANTARES_RC 8) set(ANTARES_VERSION_YEAR 2024) From 832e89b42a77d337f8c5b7de742fa2761d8536c1 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Tue, 31 Dec 2024 17:16:50 +0100 Subject: [PATCH 090/103] Modeler 2.5a: Read models and system yaml files [ANT-2306] (#2540) Add the main modeler as a new binary Directory loadFiles added, used to call previous work to read yaml files by handling I/O and errors related to yaml parsing --- src/solver/modeler/CMakeLists.txt | 39 ++++ src/solver/modeler/loadFiles/CMakeLists.txt | 34 +++ src/solver/modeler/loadFiles/handleErrors.cpp | 38 +++ .../solver/modeler/loadFiles/loadFiles.h | 54 +++++ .../modeler/loadFiles/readLibraries.cpp | 92 ++++++++ .../modeler/loadFiles/readParameters.cpp | 59 +++++ src/solver/modeler/loadFiles/readSystem.cpp | 73 ++++++ src/solver/modeler/main.cpp | 68 ++++++ src/solver/modeler/parameters/CMakeLists.txt | 18 +- src/solver/modeler/parameters/encoder.hxx | 21 ++ .../modeler/parameters/modelerParameters.h | 21 ++ .../parameters/parseModelerParameters.h | 28 ++- .../parameters/parseModelerParameters.cpp | 34 ++- src/tests/src/solver/modeler/CMakeLists.txt | 2 +- .../solver/modeler/loadFiles/CMakeLists.txt | 10 + .../loadFiles/testLoadModelerFiles.cpp | 220 ++++++++++++++++++ .../testParameters.cpp} | 70 +++--- .../solver/modeler/parameters/CMakeLists.txt | 7 - src/tests/src/utils/files-system.cpp | 4 +- src/tests/src/utils/files-system.h | 2 +- 20 files changed, 838 insertions(+), 56 deletions(-) create mode 100644 src/solver/modeler/loadFiles/CMakeLists.txt create mode 100644 src/solver/modeler/loadFiles/handleErrors.cpp create mode 100644 src/solver/modeler/loadFiles/include/antares/solver/modeler/loadFiles/loadFiles.h create mode 100644 src/solver/modeler/loadFiles/readLibraries.cpp create mode 100644 src/solver/modeler/loadFiles/readParameters.cpp create mode 100644 src/solver/modeler/loadFiles/readSystem.cpp create mode 100644 src/solver/modeler/main.cpp create mode 100644 src/tests/src/solver/modeler/loadFiles/CMakeLists.txt create mode 100644 src/tests/src/solver/modeler/loadFiles/testLoadModelerFiles.cpp rename src/tests/src/solver/modeler/{parameters/testParametersParsing.cpp => loadFiles/testParameters.cpp} (50%) delete mode 100644 src/tests/src/solver/modeler/parameters/CMakeLists.txt diff --git a/src/solver/modeler/CMakeLists.txt b/src/solver/modeler/CMakeLists.txt index 74378f6f7f..cb31b11fd4 100644 --- a/src/solver/modeler/CMakeLists.txt +++ b/src/solver/modeler/CMakeLists.txt @@ -1,3 +1,42 @@ add_subdirectory(api) add_subdirectory(ortoolsImpl) +add_subdirectory(loadFiles) add_subdirectory(parameters) + +OMESSAGE(" :: modeler") + +set(exec_name "antares-modeler") + +add_library(modeler-lib INTERFACE + ${SRCS} +) + +add_executable(antares-modeler + main.cpp + ${SRCS} +) + +set_target_properties(antares-modeler PROPERTIES OUTPUT_NAME ${exec_name}) + +target_link_libraries(modeler-lib + INTERFACE + Antares::loadModelerFiles + Antares::modelerParameters +) + +target_link_libraries(antares-modeler + PRIVATE + modeler-lib +) + +import_std_libs(antares-modeler) +executable_strip(antares-modeler) + +copy_dependency(sirius_solver antares-modeler) + +install(TARGETS antares-modeler EXPORT antares-modeler DESTINATION bin) + +INSTALL(EXPORT antares-modeler + FILE antares-modelerConfig.cmake + DESTINATION cmake +) diff --git a/src/solver/modeler/loadFiles/CMakeLists.txt b/src/solver/modeler/loadFiles/CMakeLists.txt new file mode 100644 index 0000000000..678aa9386c --- /dev/null +++ b/src/solver/modeler/loadFiles/CMakeLists.txt @@ -0,0 +1,34 @@ +set(SOURCES + readSystem.cpp + readLibraries.cpp + readParameters.cpp + handleErrors.cpp + + include/antares/solver/modeler/loadFiles/loadFiles.h +) + +# Create the library +add_library(loadModelerFiles STATIC ${SOURCES}) +add_library(Antares::loadModelerFiles ALIAS loadModelerFiles) + +# Specify include directories +target_include_directories(loadModelerFiles + PUBLIC + $ +) + +# Link dependencies (if any) +target_link_libraries(loadModelerFiles + PUBLIC + Antares::antares-study-system-model + PRIVATE + Antares::io + Antares::systemParser + Antares::modelParser + Antares::modelConverter + Antares::modelerParameters +) + +install(DIRECTORY include/antares + DESTINATION "include" +) diff --git a/src/solver/modeler/loadFiles/handleErrors.cpp b/src/solver/modeler/loadFiles/handleErrors.cpp new file mode 100644 index 0000000000..4ee2352970 --- /dev/null +++ b/src/solver/modeler/loadFiles/handleErrors.cpp @@ -0,0 +1,38 @@ +/* + * 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 +#include "antares/solver/modeler/loadFiles/loadFiles.h" + +namespace Antares::Solver::LoadFiles +{ + +void handleYamlError(const YAML::Exception& e, const std::string& context) +{ + logs.error() << "Error while parsing the yaml file: " << context; + if (!e.mark.is_null()) + { + logs.error() << "Line " << e.mark.line << " column " << e.mark.column; + } + logs.error() << e.what(); +} + +} // namespace Antares::Solver::LoadFiles diff --git a/src/solver/modeler/loadFiles/include/antares/solver/modeler/loadFiles/loadFiles.h b/src/solver/modeler/loadFiles/include/antares/solver/modeler/loadFiles/loadFiles.h new file mode 100644 index 0000000000..ff3882e554 --- /dev/null +++ b/src/solver/modeler/loadFiles/include/antares/solver/modeler/loadFiles/loadFiles.h @@ -0,0 +1,54 @@ +/* + * 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 +#include + +#include +#include +#include + +namespace Antares::Solver::LoadFiles +{ + +ModelerParameters loadParameters(const std::filesystem::path& studyPath); + +std::vector loadLibraries(const std::filesystem::path& studyPath); + +Study::SystemModel::System loadSystem(const std::filesystem::path& studyPath, + const std::vector& libraries); + +void handleYamlError(const YAML::Exception& e, const std::string& context); + +/// Generic error class for all loading errors to catch in the main +class ErrorLoadingYaml: public std::runtime_error +{ +public: + explicit ErrorLoadingYaml(const std::string& s): + runtime_error(s) + { + } +}; + +} // namespace Antares::Solver::LoadFiles diff --git a/src/solver/modeler/loadFiles/readLibraries.cpp b/src/solver/modeler/loadFiles/readLibraries.cpp new file mode 100644 index 0000000000..be6b8e15d8 --- /dev/null +++ b/src/solver/modeler/loadFiles/readLibraries.cpp @@ -0,0 +1,92 @@ +/* + * 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 + +#include +#include +#include +#include +#include "antares/solver/modeler/loadFiles/loadFiles.h" + +namespace fs = std::filesystem; + +namespace Antares::Solver::LoadFiles +{ + +static Study::SystemModel::Library loadSingleLibrary(const fs::path& filePath) +{ + std::string libraryStr; + try + { + libraryStr = IO::readFile(filePath); + } + catch (const std::runtime_error& e) + { + logs.error() << "Error while trying to read this library file: " << filePath; + throw ErrorLoadingYaml(e.what()); + } + + ModelParser::Parser parser; + ModelParser::Library libraryObj; + + try + { + libraryObj = parser.parse(libraryStr); + } + catch (const YAML::Exception& e) + { + handleYamlError(e, filePath.string()); + throw ErrorLoadingYaml(e.what()); + } + + try + { + return ModelConverter::convert(libraryObj); + } + catch (const std::runtime_error& e) + { + logs.error() << "Error while converting this library yaml: " << filePath; + throw ErrorLoadingYaml(e.what()); + } +} + +std::vector loadLibraries(const fs::path& studyPath) +{ + std::vector libraries; + + const fs::path directoryPath = studyPath / "input" / "model-libraries"; + for (const auto& entry: fs::directory_iterator(directoryPath)) + { + if (entry.path().extension() != ".yml") + { + logs.info() << entry.path() + << " ignored, only files having the `.yml` extension are loaded"; + continue; + } + + libraries.push_back(loadSingleLibrary(entry.path())); + logs.info() << "Library loaded: " << libraries.back().Id(); + } + + return libraries; +} +} // namespace Antares::Solver::LoadFiles diff --git a/src/solver/modeler/loadFiles/readParameters.cpp b/src/solver/modeler/loadFiles/readParameters.cpp new file mode 100644 index 0000000000..bab889cb7e --- /dev/null +++ b/src/solver/modeler/loadFiles/readParameters.cpp @@ -0,0 +1,59 @@ +/* + * 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 + +#include +#include +#include "antares/solver/modeler/loadFiles/loadFiles.h" +#include "antares/solver/modeler/parameters/parseModelerParameters.h" + +namespace fs = std::filesystem; + +namespace Antares::Solver::LoadFiles +{ + +ModelerParameters loadParameters(const fs::path& studyPath) +{ + std::string filename = "parameters.yml"; + std::string paramStr; + try + { + paramStr = IO::readFile(studyPath / filename); + } + catch (const std::runtime_error& e) + { + logs.error() << "Error while trying to read file parameters.yml"; + throw ErrorLoadingYaml(e.what()); + } + + try + { + return parseModelerParameters(paramStr); + } + catch (const YAML::Exception& e) + { + handleYamlError(e, filename); + throw ErrorLoadingYaml(e.what()); + } +} + +} // namespace Antares::Solver::LoadFiles diff --git a/src/solver/modeler/loadFiles/readSystem.cpp b/src/solver/modeler/loadFiles/readSystem.cpp new file mode 100644 index 0000000000..dac47889cc --- /dev/null +++ b/src/solver/modeler/loadFiles/readSystem.cpp @@ -0,0 +1,73 @@ +/* + * 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 + +#include +#include +#include +#include +#include "antares/solver/modeler/loadFiles/loadFiles.h" + +namespace fs = std::filesystem; + +namespace Antares::Solver::LoadFiles +{ + +Study::SystemModel::System loadSystem(const fs::path& studyPath, + const std::vector& libraries) +{ + std::string filename = "system.yml"; + std::string systemStr; + try + { + systemStr = IO::readFile(studyPath / "input" / filename); + } + catch (const std::runtime_error& e) + { + logs.error() << "Error while trying to read file system.yml"; + throw ErrorLoadingYaml(e.what()); + } + + SystemParser::Parser parser; + SystemParser::System systemObj; + try + { + systemObj = parser.parse(systemStr); + } + catch (const YAML::Exception& e) + { + handleYamlError(e, filename); + throw ErrorLoadingYaml(e.what()); + } + + try + { + return SystemConverter::convert(systemObj, libraries); + } + catch (const std::runtime_error& e) + { + logs.error() << "Error while converting the system yaml to components"; + throw ErrorLoadingYaml(e.what()); + } +} + +} // namespace Antares::Solver::LoadFiles diff --git a/src/solver/modeler/main.cpp b/src/solver/modeler/main.cpp new file mode 100644 index 0000000000..a4d071660b --- /dev/null +++ b/src/solver/modeler/main.cpp @@ -0,0 +1,68 @@ +/* + * 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 +#include +#include + +using namespace Antares; +using namespace Antares::Solver; + +int main(int argc, const char** argv) +{ + if (argc < 1) + { + logs.error() << "No study path provided, exiting."; + return EXIT_FAILURE; + } + + std::filesystem::path studyPath(argv[1]); + logs.info() << "Study path: " << studyPath; + + if (!std::filesystem::is_directory(studyPath)) + { + logs.error() << "The path provided isn't a valid directory, exiting"; + return EXIT_FAILURE; + } + + try + { + const auto parameters = LoadFiles::loadParameters(studyPath); + logs.info() << "Parameters loaded"; + const auto libraries = LoadFiles::loadLibraries(studyPath); + logs.info() << "Libraries loaded"; + const auto system = LoadFiles::loadSystem(studyPath, libraries); + logs.info() << "System loaded"; + } + catch (const LoadFiles::ErrorLoadingYaml&) + { + logs.error() << "Error while loading files, exiting"; + return EXIT_FAILURE; + } + catch (const std::exception& e) + { + logs.error() << e.what(); + logs.error() << "Error during the execution, exiting"; + return EXIT_FAILURE; + } + + return 0; +} diff --git a/src/solver/modeler/parameters/CMakeLists.txt b/src/solver/modeler/parameters/CMakeLists.txt index 33cfda091e..7ab35d5002 100644 --- a/src/solver/modeler/parameters/CMakeLists.txt +++ b/src/solver/modeler/parameters/CMakeLists.txt @@ -1,14 +1,16 @@ -add_library(modeler-parameters - include/antares/solver/modeler/parameters/modelerParameters.h - include/antares/solver/modeler/parameters/parseModelerParameters.h - parseModelerParameters.cpp - encoder.hxx) +add_library(modelerParameters + include/antares/solver/modeler/parameters/modelerParameters.h + include/antares/solver/modeler/parameters/parseModelerParameters.h + parseModelerParameters.cpp + encoder.hxx) -target_link_libraries(modeler-parameters +add_library(Antares::modelerParameters ALIAS modelerParameters) + +target_link_libraries(modelerParameters PRIVATE yaml-cpp - Antares::io) + Antares::io) -target_include_directories(modeler-parameters +target_include_directories(modelerParameters PUBLIC $) diff --git a/src/solver/modeler/parameters/encoder.hxx b/src/solver/modeler/parameters/encoder.hxx index 32de3e0d83..c43d195ccc 100644 --- a/src/solver/modeler/parameters/encoder.hxx +++ b/src/solver/modeler/parameters/encoder.hxx @@ -1,3 +1,24 @@ +/* + * 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 #include "yaml-cpp/yaml.h" diff --git a/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/modelerParameters.h b/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/modelerParameters.h index c6977a748b..6ea6e1072d 100644 --- a/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/modelerParameters.h +++ b/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/modelerParameters.h @@ -1,3 +1,24 @@ +/* + * 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 diff --git a/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/parseModelerParameters.h b/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/parseModelerParameters.h index 2409fcddf1..f0c9bd7238 100644 --- a/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/parseModelerParameters.h +++ b/src/solver/modeler/parameters/include/antares/solver/modeler/parameters/parseModelerParameters.h @@ -1,11 +1,33 @@ +/* + * 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::Solver +namespace Antares::Solver::LoadFiles { -ModelerParameters parseModelerParameters(const std::filesystem::path& path); -} // namespace Antares::Solver +ModelerParameters parseModelerParameters(const std::string& content); + +} // namespace Antares::Solver::LoadFiles diff --git a/src/solver/modeler/parameters/parseModelerParameters.cpp b/src/solver/modeler/parameters/parseModelerParameters.cpp index 39935db38c..470b7a66e4 100644 --- a/src/solver/modeler/parameters/parseModelerParameters.cpp +++ b/src/solver/modeler/parameters/parseModelerParameters.cpp @@ -1,16 +1,38 @@ +/* + * 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 -#include #include +#include #include "encoder.hxx" -namespace Antares::Solver +namespace Antares::Solver::LoadFiles { -ModelerParameters parseModelerParameters(const std::filesystem::path& path) + +ModelerParameters parseModelerParameters(const std::string& content) { - const auto contents = Antares::IO::readFile(path); - YAML::Node root = YAML::Load(contents); + YAML::Node root = YAML::Load(content); return root.as(); } -} // namespace Antares::Solver + +} // namespace Antares::Solver::LoadFiles diff --git a/src/tests/src/solver/modeler/CMakeLists.txt b/src/tests/src/solver/modeler/CMakeLists.txt index 9a39b3b19b..d532a0a77d 100644 --- a/src/tests/src/solver/modeler/CMakeLists.txt +++ b/src/tests/src/solver/modeler/CMakeLists.txt @@ -1,2 +1,2 @@ add_subdirectory(api) -add_subdirectory(parameters) +add_subdirectory(loadFiles) diff --git a/src/tests/src/solver/modeler/loadFiles/CMakeLists.txt b/src/tests/src/solver/modeler/loadFiles/CMakeLists.txt new file mode 100644 index 0000000000..896c759e06 --- /dev/null +++ b/src/tests/src/solver/modeler/loadFiles/CMakeLists.txt @@ -0,0 +1,10 @@ +include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) + +add_boost_test(loadFiles + SRC + testLoadModelerFiles.cpp + testParameters.cpp + LIBS + Antares::modelerParameters + Antares::loadModelerFiles + test_utils_unit) diff --git a/src/tests/src/solver/modeler/loadFiles/testLoadModelerFiles.cpp b/src/tests/src/solver/modeler/loadFiles/testLoadModelerFiles.cpp new file mode 100644 index 0000000000..61fe4decf1 --- /dev/null +++ b/src/tests/src/solver/modeler/loadFiles/testLoadModelerFiles.cpp @@ -0,0 +1,220 @@ +/* + * 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 . + */ +#define WIN32_LEAN_AND_MEAN + +#include +#define BOOST_TEST_MODULE load modeler files + +#include + +#include + +#include "files-system.h" + +BOOST_AUTO_TEST_SUITE(test_modeler_files_loading) + +namespace fs = std::filesystem; + +struct FixtureLoadFile +{ + fs::path studyPath; + fs::path inputPath; + fs::path libraryDirPath; + + FixtureLoadFile() + { + studyPath = CREATE_TMP_DIR_BASED_ON_TEST_NAME(); + inputPath = createFolder(studyPath.string(), "input"); + libraryDirPath = createFolder(inputPath.string(), "model-libraries"); + } + + ~FixtureLoadFile() + { + fs::remove_all(studyPath); + } +}; + +BOOST_AUTO_TEST_CASE(files_not_existing) +{ + fs::path studyPath = CREATE_TMP_DIR_BASED_ON_TEST_NAME(); + std::vector libraries; + + BOOST_CHECK_THROW(Antares::Solver::LoadFiles::loadLibraries(studyPath), std::runtime_error); + BOOST_CHECK_THROW(Antares::Solver::LoadFiles::loadSystem(studyPath, libraries), + std::runtime_error); +} + +BOOST_FIXTURE_TEST_CASE(read_one_lib_treile, FixtureLoadFile) +{ + std::ofstream libStream(libraryDirPath / "simple.yml"); + libStream << R"( + library: + id: lib_id + description: lib_description + port-types: [] + models: [] + )"; + libStream.close(); + + auto libraries = Antares::Solver::LoadFiles::loadLibraries(studyPath); + BOOST_CHECK_EQUAL(libraries[0].Id(), "lib_id"); +} + +BOOST_FIXTURE_TEST_CASE(dont_read_bad_extension, FixtureLoadFile) +{ + createFile(libraryDirPath.string(), "abc.txt"); + auto libraries = Antares::Solver::LoadFiles::loadLibraries(studyPath); + BOOST_CHECK(libraries.empty()); +} + +BOOST_FIXTURE_TEST_CASE(incorrect_library, FixtureLoadFile) +{ + std::ofstream libStream(libraryDirPath / "simple.yml"); + libStream << R"( + library: + port-types: [] + models: [] + )"; + libStream.close(); + + BOOST_CHECK_THROW(Antares::Solver::LoadFiles::loadLibraries(studyPath), std::runtime_error); +} + +BOOST_FIXTURE_TEST_CASE(incorrect_library2, FixtureLoadFile) +{ + std::ofstream libStream(libraryDirPath / "simple.yml"); + libStream << R"( + library: + id: std + port-types: [] + - id: generator + description: A basic generator model + + )"; + libStream.close(); + BOOST_CHECK_THROW(Antares::Solver::LoadFiles::loadLibraries(studyPath), std::runtime_error); +} + +BOOST_FIXTURE_TEST_CASE(read_several_lib_file, FixtureLoadFile) +{ + std::ofstream libStream(libraryDirPath / "simple.yml"); + libStream << R"( + library: + id: lib_id + description: lib_description + port-types: [] + models: [] + )"; + libStream.close(); + + std::ofstream libStream2(libraryDirPath / "2.yml"); + libStream2 << R"( + library: + id: lib_id2 + description: lib_description + port-types: [] + models: [] + )"; + libStream2.close(); + + std::ofstream libStream3(libraryDirPath / "3.yml"); + libStream3 << R"( + library: + id: lib_id3 + description: lib_description + port-types: [] + models: [] + )"; + libStream3.close(); + + auto libraries = Antares::Solver::LoadFiles::loadLibraries(studyPath); + + auto checkLibIdInVector = [&libraries](const std::string& libId) + { + return std::ranges::find_if(libraries, [&libId](const auto& l) { return l.Id() == libId; }) + != libraries.end(); + }; + + BOOST_CHECK(checkLibIdInVector("lib_id")); + BOOST_CHECK(checkLibIdInVector("lib_id2")); + BOOST_CHECK(checkLibIdInVector("lib_id3")); + + BOOST_CHECK(!checkLibIdInVector("id not in vector")); +} + +BOOST_FIXTURE_TEST_CASE(read_system_file, FixtureLoadFile) +{ + std::ofstream libStream(libraryDirPath / "simple.yml"); + libStream << R"( + library: + id: std + description: lib_description + port-types: [] + models: + - id: generator + description: A basic generator model + + )"; + libStream.close(); + + std::ofstream systemStream(inputPath / "system.yml"); + systemStream << R"( + system: + id: base_system + description: two components + components: + - id: N + model: std.generator + scenario-group: group-234 + )"; + systemStream.close(); + + auto libraries = Antares::Solver::LoadFiles::loadLibraries(studyPath); + auto system = Antares::Solver::LoadFiles::loadSystem(studyPath, libraries); +} + +BOOST_FIXTURE_TEST_CASE(read_invalid_system_file, FixtureLoadFile) +{ + std::ofstream libStream(libraryDirPath / "simple.yml"); + libStream << R"( + library: + id: std + description: lib_description + port-types: [] + models: + - id: generator + description: A basic generator model + + )"; + libStream.close(); + + std::ofstream systemStream(inputPath / "system.yml"); + systemStream << R"( + system: + )"; + systemStream.close(); + + auto libraries = Antares::Solver::LoadFiles::loadLibraries(studyPath); + BOOST_CHECK_THROW(Antares::Solver::LoadFiles::loadSystem(studyPath, libraries), + std::runtime_error); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/modeler/parameters/testParametersParsing.cpp b/src/tests/src/solver/modeler/loadFiles/testParameters.cpp similarity index 50% rename from src/tests/src/solver/modeler/parameters/testParametersParsing.cpp rename to src/tests/src/solver/modeler/loadFiles/testParameters.cpp index aa2b14732b..fb529f3111 100644 --- a/src/tests/src/solver/modeler/parameters/testParametersParsing.cpp +++ b/src/tests/src/solver/modeler/loadFiles/testParameters.cpp @@ -21,54 +21,66 @@ #define WIN32_LEAN_AND_MEAN #include -#define BOOST_TEST_MODULE parse modeler parameters #include -#include +#include #include "files-system.h" -BOOST_AUTO_TEST_SUITE(read_modeler_parameters) - -BOOST_AUTO_TEST_CASE(all_properties_set) +BOOST_AUTO_TEST_CASE(read_parameters) { - const auto working_tmp_dir = CREATE_TMP_DIR_BASED_ON_TEST_NAME(); - const auto fileP = working_tmp_dir / "parameters.yaml"; - { - std::ofstream param(fileP); - param << R"( -solver: sirius -solver-logs: false -solver-parameters: PRESOLVE 1 -no-output: true)"; - } + auto studyPath = CREATE_TMP_DIR_BASED_ON_TEST_NAME(); + std::ofstream paramStream(studyPath / "parameters.yml"); + paramStream << R"( + solver: sirius + solver-logs: false + solver-parameters: PRESOLVE 1 + no-output: true + )"; + paramStream.close(); - auto params = Antares::Solver::parseModelerParameters(fileP); + auto params = Antares::Solver::LoadFiles::loadParameters(studyPath); BOOST_CHECK_EQUAL(params.solver, "sirius"); BOOST_CHECK_EQUAL(params.solverLogs, false); BOOST_CHECK_EQUAL(params.solverParameters, "PRESOLVE 1"); BOOST_CHECK_EQUAL(params.noOutput, true); } -BOOST_AUTO_TEST_CASE(all_properties_set_out_of_order) +BOOST_AUTO_TEST_CASE(read_parameters_out_of_order) { - const auto working_tmp_dir = CREATE_TMP_DIR_BASED_ON_TEST_NAME(); - const auto fileP = working_tmp_dir / "parameters.yaml"; - { - std::ofstream param(fileP); - param << R"( -solver-logs: false -solver: sirius -solver-parameters: PRESOLVE 1 -no-output: true)"; - } + auto studyPath = CREATE_TMP_DIR_BASED_ON_TEST_NAME(); + std::ofstream paramStream(studyPath / "parameters.yml"); + paramStream << R"( + solver-logs: false + solver: sirius + solver-parameters: PRESOLVE 1 + no-output: true + )"; + paramStream.close(); - auto params = Antares::Solver::parseModelerParameters(fileP); + auto params = Antares::Solver::LoadFiles::loadParameters(studyPath); BOOST_CHECK_EQUAL(params.solver, "sirius"); BOOST_CHECK_EQUAL(params.solverLogs, false); BOOST_CHECK_EQUAL(params.solverParameters, "PRESOLVE 1"); BOOST_CHECK_EQUAL(params.noOutput, true); } -BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_CASE(parameters_missing) +{ + auto studyPath = CREATE_TMP_DIR_BASED_ON_TEST_NAME(); + std::ofstream paramStream(studyPath / "parameters.yml"); + paramStream << R"( + solver-logs: false + no-output: true + )"; + paramStream.close(); + + BOOST_CHECK_THROW(Antares::Solver::LoadFiles::loadParameters(studyPath), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(file_missing) +{ + auto studyPath = CREATE_TMP_DIR_BASED_ON_TEST_NAME(); + BOOST_CHECK_THROW(Antares::Solver::LoadFiles::loadParameters(studyPath), std::runtime_error); +} diff --git a/src/tests/src/solver/modeler/parameters/CMakeLists.txt b/src/tests/src/solver/modeler/parameters/CMakeLists.txt deleted file mode 100644 index 85c27e2969..0000000000 --- a/src/tests/src/solver/modeler/parameters/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) - -add_boost_test(parse-parameters - SRC testParametersParsing.cpp - LIBS - modeler-parameters - test_utils_unit) diff --git a/src/tests/src/utils/files-system.cpp b/src/tests/src/utils/files-system.cpp index f6097ee82b..e8d6163ea7 100644 --- a/src/tests/src/utils/files-system.cpp +++ b/src/tests/src/utils/files-system.cpp @@ -10,7 +10,7 @@ fs::path generateAndCreateDirName(const std::string& dirName) return working_dir; } -void createFolder(const std::string& path, const std::string& folder_name) +fs::path createFolder(const std::string& path, const std::string& folder_name) { fs::path folder_path = fs::path(path.c_str()) / folder_name.c_str(); @@ -22,6 +22,8 @@ void createFolder(const std::string& path, const std::string& folder_name) { std::cerr << "Exception creating folder '" + folder_name + "': " + e.what() + "\n"; } + + return folder_path; } void createFile(const std::string& folder_path, const std::string& file_name) diff --git a/src/tests/src/utils/files-system.h b/src/tests/src/utils/files-system.h index 092b498350..9ad4503e54 100644 --- a/src/tests/src/utils/files-system.h +++ b/src/tests/src/utils/files-system.h @@ -31,6 +31,6 @@ std::filesystem::path generateAndCreateDirName(const std::string&); -void createFolder(const std::string& path, const std::string& folder_name); +std::filesystem::path createFolder(const std::string& path, const std::string& folder_name); void createFile(const std::string& folder_path, const std::string& file_name); void removeFolder(std::string& path, std::string& folder_name); From 9a9715ebdba370b59bf8aa637071b68abf2f2733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Fri, 3 Jan 2025 09:43:05 +0100 Subject: [PATCH 091/103] High-level API: provide output path instead of returning it [ANT-2561] (#2548) TODO - [x] Fix build for api_client_test (missing argument) - [x] Fix extra output directory created by Simulator, for example 20241204-1554eco and 20241204-1554eco-2 --- src/api/API.cpp | 21 +++++++++++++------ .../include/antares/api/SimulationResults.h | 10 ++++----- src/api/include/antares/api/solver.h | 1 + src/api/private/API.h | 2 ++ src/api/solver.cpp | 5 +++-- src/api_client_example/src/API_client.cpp | 5 +++-- src/api_client_example/src/API_client.h | 5 +++-- src/api_client_example/tests/test.cpp | 8 ++++--- src/format-code.sh | 2 +- src/solver/application/application.cpp | 6 +++--- src/tests/src/api_internal/test_api.cpp | 21 +++++-------------- src/tests/src/api_lib/test_api.cpp | 2 +- 12 files changed, 46 insertions(+), 42 deletions(-) diff --git a/src/api/API.cpp b/src/api/API.cpp index 7bcda34502..63b4a9fda8 100644 --- a/src/api/API.cpp +++ b/src/api/API.cpp @@ -34,6 +34,7 @@ namespace Antares::API { SimulationResults APIInternal::run( const IStudyLoader& study_loader, + const std::filesystem::path& output, const Antares::Solver::Optimization::OptimizationOptions& optOptions) { try @@ -43,9 +44,9 @@ SimulationResults APIInternal::run( catch (const ::Antares::Error::StudyFolderDoesNotExist& e) { Antares::API::Error err{.reason = e.what()}; - return {.simulationPath = "", .antares_problems = {}, .error = err}; + return {.antares_problems = {}, .error = err}; } - return execute(optOptions); + return execute(output, optOptions); } /** @@ -56,6 +57,7 @@ SimulationResults APIInternal::run( * dupllication */ SimulationResults APIInternal::execute( + const std::filesystem::path& output, const Antares::Solver::Optimization::OptimizationOptions& optOptions) const { // study_ == nullptr e.g when the -h flag is given @@ -63,7 +65,7 @@ SimulationResults APIInternal::execute( { using namespace std::string_literals; Antares::API::Error err{.reason = "Couldn't create study"s}; - return {.simulationPath{}, .antares_problems{}, .error = err}; + return {.antares_problems{}, .error = err}; } Settings settings; @@ -75,10 +77,19 @@ SimulationResults APIInternal::execute( auto ioQueueService = std::make_shared(); ioQueueService->maximumThreadCount(1); ioQueueService->start(); + + study_->folderOutput = output; auto resultWriter = Solver::resultWriterFactory(parameters.resultFormat, study_->folderOutput, ioQueueService, durationCollector); + + // In some cases (e.g tests) we don't want to write anything + if (!output.empty()) + { + study_->saveAboutTheStudy(*resultWriter); + } + SimulationObserver simulationObserver; optimizationInfo = simulationRun(*study_, @@ -90,8 +101,6 @@ SimulationResults APIInternal::execute( // Importing Time-Series if asked study_->importTimeseriesIntoInput(); - return {.simulationPath = study_->folderOutput, - .antares_problems = simulationObserver.acquireLps(), - .error{}}; + return {.antares_problems = simulationObserver.acquireLps(), .error{}}; } } // namespace Antares::API diff --git a/src/api/include/antares/api/SimulationResults.h b/src/api/include/antares/api/SimulationResults.h index 5a5e93982a..31f0e9aec0 100644 --- a/src/api/include/antares/api/SimulationResults.h +++ b/src/api/include/antares/api/SimulationResults.h @@ -23,6 +23,7 @@ #include #include #include + #include "antares/solver/lps/LpsFromAntares.h" namespace Antares::API @@ -31,7 +32,8 @@ namespace Antares::API * @struct Error * @brief The Error structure is used to represent an error that occurred during the simulation. */ -struct Error { +struct Error +{ /** * @brief The reason for the error. */ @@ -45,10 +47,6 @@ struct Error { */ struct [[nodiscard("Contains results and potential error")]] SimulationResults { - /** - * @brief The path to the simulation (output). - */ - std::filesystem::path simulationPath; /** * @brief weekly problems */ @@ -59,4 +57,4 @@ struct [[nodiscard("Contains results and potential error")]] SimulationResults std::optional error; }; -} \ No newline at end of file +} // namespace Antares::API diff --git a/src/api/include/antares/api/solver.h b/src/api/include/antares/api/solver.h index a8279c00c8..64fa13ac55 100644 --- a/src/api/include/antares/api/solver.h +++ b/src/api/include/antares/api/solver.h @@ -36,5 +36,6 @@ namespace Antares::API */ SimulationResults PerformSimulation( const std::filesystem::path& study_path, + const std::filesystem::path& output, const Antares::Solver::Optimization::OptimizationOptions& optOptions) noexcept; } // namespace Antares::API diff --git a/src/api/private/API.h b/src/api/private/API.h index 3561f6d21b..c52c3304bf 100644 --- a/src/api/private/API.h +++ b/src/api/private/API.h @@ -48,11 +48,13 @@ class APIInternal * @return SimulationResults object which contains the results of the simulation. */ SimulationResults run(const IStudyLoader& study_loader, + const std::filesystem::path& output, const Antares::Solver::Optimization::OptimizationOptions& optOptions); private: std::shared_ptr study_; SimulationResults execute( + const std::filesystem::path& output, const Antares::Solver::Optimization::OptimizationOptions& optOptions) const; }; diff --git a/src/api/solver.cpp b/src/api/solver.cpp index 4e65696f8a..ac6810e7f1 100644 --- a/src/api/solver.cpp +++ b/src/api/solver.cpp @@ -30,18 +30,19 @@ namespace Antares::API SimulationResults PerformSimulation( const std::filesystem::path& study_path, + const std::filesystem::path& output, const Antares::Solver::Optimization::OptimizationOptions& optOptions) noexcept { try { APIInternal api; FileTreeStudyLoader study_loader(study_path); - return api.run(study_loader, optOptions); + return api.run(study_loader, output, optOptions); } catch (const std::exception& e) { Antares::API::Error err{.reason = e.what()}; - return SimulationResults{.simulationPath = study_path, .antares_problems{}, .error = err}; + return SimulationResults{.antares_problems{}, .error = err}; } } diff --git a/src/api_client_example/src/API_client.cpp b/src/api_client_example/src/API_client.cpp index 9cb19d8e59..8ebba07042 100644 --- a/src/api_client_example/src/API_client.cpp +++ b/src/api_client_example/src/API_client.cpp @@ -23,7 +23,8 @@ #include -Antares::API::SimulationResults solve(std::filesystem::path study_path) +Antares::API::SimulationResults solve(std::filesystem::path study_path, + std::filesystem::path output) { - return Antares::API::PerformSimulation(std::move(study_path), {}); + return Antares::API::PerformSimulation(std::move(study_path), std::move(output), {}); } diff --git a/src/api_client_example/src/API_client.h b/src/api_client_example/src/API_client.h index 5d8500649e..7f77a26e7f 100644 --- a/src/api_client_example/src/API_client.h +++ b/src/api_client_example/src/API_client.h @@ -22,7 +22,8 @@ #pragma once -#include #include +#include -Antares::API::SimulationResults solve(std::filesystem::path study_path); +Antares::API::SimulationResults solve(std::filesystem::path study_path, + std::filesystem::path output); diff --git a/src/api_client_example/tests/test.cpp b/src/api_client_example/tests/test.cpp index 4adee7bfd6..bd5b3d86a8 100644 --- a/src/api_client_example/tests/test.cpp +++ b/src/api_client_example/tests/test.cpp @@ -22,10 +22,12 @@ #define BOOST_TEST_MODULE test_client_api #include + #include "API_client.h" -BOOST_AUTO_TEST_CASE(test_run) { - auto results = solve("dummy_study_test_client_api"); +BOOST_AUTO_TEST_CASE(test_run) +{ + auto results = solve("dummy_study_test_client_api", {}); BOOST_CHECK(results.error); BOOST_CHECK(!results.error->reason.empty()); auto c = results.error->reason; @@ -34,4 +36,4 @@ BOOST_AUTO_TEST_CASE(test_run) { BOOST_CHECK(results.error->reason.find("folder") != std::string::npos); BOOST_CHECK(results.error->reason.find("not") != std::string::npos); BOOST_CHECK(results.error->reason.find("exist") != std::string::npos); -} \ No newline at end of file +} diff --git a/src/format-code.sh b/src/format-code.sh index abac85a423..752080ca58 100755 --- a/src/format-code.sh +++ b/src/format-code.sh @@ -3,7 +3,7 @@ if [ $# -eq 0 ] then # No arguments: format all - SOURCE_DIRS="analyzer/ libs/ solver/ tools/ config/ tests/ packaging/" + SOURCE_DIRS="analyzer/ libs/ solver/ tools/ config/ tests/ packaging/ api/" SOURCE_FILES=$(find $SOURCE_DIRS -regextype egrep -regex ".*/*\.(c|cxx|cpp|cc|h|hxx|hpp)$" ! -path '*/antlr-interface/*') else # Format files provided as arguments diff --git a/src/solver/application/application.cpp b/src/solver/application/application.cpp index 2d1695bcf0..43dfa3368d 100644 --- a/src/solver/application/application.cpp +++ b/src/solver/application/application.cpp @@ -161,9 +161,6 @@ void Application::readDataForTheStudy(Data::StudyLoadOptions& options) Antares::Solver::initializeSignalHandlers(resultWriter); - // Save about-the-study files (comments, notes, etc.) - study.saveAboutTheStudy(*resultWriter); - // Name of the simulation (again, if the value has been overwritten) if (!pSettings.simulationName.empty()) { @@ -375,6 +372,9 @@ void Application::execute() return; } + // Save about-the-study files (comments, notes, etc.) + pStudy->saveAboutTheStudy(*resultWriter); + SystemMemoryLogger memoryReport; memoryReport.interval(1000 * 60 * 5); // 5 minutes memoryReport.start(); diff --git a/src/tests/src/api_internal/test_api.cpp b/src/tests/src/api_internal/test_api.cpp index 5214aa8c10..47034cb19d 100644 --- a/src/tests/src/api_internal/test_api.cpp +++ b/src/tests/src/api_internal/test_api.cpp @@ -52,28 +52,17 @@ class InMemoryStudyLoader: public Antares::IStudyLoader builder.study->initializeRuntimeInfos(); builder.setNumberMCyears(1); builder.study->parameters.resultFormat = ResultFormat::inMemory; - builder.study->prepareOutput(); return std::move(builder.study); } bool success_ = true; }; -BOOST_AUTO_TEST_CASE(simulation_path_points_to_results) -{ - Antares::API::APIInternal api; - auto study_loader = std::make_unique(); - auto results = api.run(*study_loader.get(), {}); - BOOST_CHECK_EQUAL(results.simulationPath, std::filesystem::path{"no_output"}); - // Testing for "no_output" is a bit weird, but it's the only way to test this without actually - // running the simulation -} - BOOST_AUTO_TEST_CASE(api_run_contains_antares_problem) { Antares::API::APIInternal api; auto study_loader = std::make_unique(); - auto results = api.run(*study_loader.get(), {}); + auto results = api.run(*study_loader, {}, {}); BOOST_CHECK(!results.antares_problems.empty()); BOOST_CHECK(!results.error); @@ -83,7 +72,7 @@ BOOST_AUTO_TEST_CASE(result_failure_when_study_is_null) { Antares::API::APIInternal api; auto study_loader = std::make_unique(false); - auto results = api.run(*study_loader.get(), {}); + auto results = api.run(*study_loader, {}, {}); BOOST_CHECK(results.error); } @@ -93,7 +82,7 @@ BOOST_AUTO_TEST_CASE(result_contains_problems) { Antares::API::APIInternal api; auto study_loader = std::make_unique(); - auto results = api.run(*study_loader.get(), {}); + auto results = api.run(*study_loader, {}, {}); BOOST_CHECK(!results.antares_problems.empty()); BOOST_CHECK(!results.error); @@ -109,7 +98,7 @@ BOOST_AUTO_TEST_CASE(result_with_ortools_coin) .solverLogs = false, .solverParameters = ""}; - auto results = api.run(*study_loader.get(), opt); + auto results = api.run(*study_loader, {}, opt); BOOST_CHECK(!results.antares_problems.empty()); BOOST_CHECK(!results.error); @@ -126,7 +115,7 @@ BOOST_AUTO_TEST_CASE(invalid_ortools_solver) .solverLogs = true, .solverParameters = ""}; - auto shouldThrow = [&api, &study_loader, &opt] { return api.run(*study_loader.get(), opt); }; + auto shouldThrow = [&api, &study_loader, &opt] { return api.run(*study_loader, {}, opt); }; BOOST_CHECK_EXCEPTION(shouldThrow(), std::invalid_argument, checkMessage("Solver this-solver-does-not-exist not found")); diff --git a/src/tests/src/api_lib/test_api.cpp b/src/tests/src/api_lib/test_api.cpp index c1111b5c6a..8460c4533a 100644 --- a/src/tests/src/api_lib/test_api.cpp +++ b/src/tests/src/api_lib/test_api.cpp @@ -29,7 +29,7 @@ BOOST_AUTO_TEST_CASE(result_failure_when_study_path_invalid) { using namespace std::string_literals; - auto results = Antares::API::PerformSimulation("dummy"s, {}); + auto results = Antares::API::PerformSimulation("dummy"s, {}, {}); BOOST_CHECK(results.error); BOOST_CHECK(!results.error->reason.empty()); } From a71f438e28e832c8b8fa8767627d92a7e37b9e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 6 Jan 2025 10:31:39 +0100 Subject: [PATCH 092/103] Improve `add_boost_test` CMake function (#2552) - Start parsing argument from the 2nd one, ignore the 1st argument `${ARGV0}` since it's reserved to the test name - Remove the obsolete linking to `stdc++fs` (no longer necessary with modern compilers/linkers) --- src/tests/macros.cmake | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/tests/macros.cmake b/src/tests/macros.cmake index 8d57ddf55b..d68c7b4f2e 100644 --- a/src/tests/macros.cmake +++ b/src/tests/macros.cmake @@ -9,7 +9,7 @@ function(add_boost_test) set(options "") set(oneValueArgs) set(multiValueArgs SRC LIBS INCLUDE) - cmake_parse_arguments(PARSE_ARGV 0 arg + cmake_parse_arguments(PARSE_ARGV 1 arg "${options}" "${oneValueArgs}" "${multiValueArgs}") # Bypass cmake_parse_arguments for the 1st argument set(TEST_NAME ${ARGV0}) @@ -29,10 +29,4 @@ function(add_boost_test) # Give the IDE some directions to display tests in a "Unit-tests" folder set_target_properties(${TEST_NAME} PROPERTIES FOLDER Unit-tests) - - # Linux only. TODO remove ? - if(UNIX AND NOT APPLE) - target_link_libraries(${TEST_NAME} PRIVATE stdc++fs) - endif() - endfunction() From 361abdaefd58f0bd04a2b41c566a334640a29d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 6 Jan 2025 11:37:44 +0100 Subject: [PATCH 093/103] Update vcpkg@2023.07.21 -> vcpkg@2024.12.16, Boost@1.81.0 -> Boost@1.86.0 (#2553) The old tag seems to reference invalid URLs on Windows, e.g ``` Downloading https://mirror.msys2.org/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst Downloading https://repo.msys2.org/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst Downloading https://mirror.yandex.ru/mirrors/msys2/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst Downloading https://mirrors.tuna.tsinghua.edu.cn/msys2/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst Downloading https://mirrors.ustc.edu.cn/msys2/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst Downloading https://mirror.selfnet.de/msys2/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst error: Failed to download from mirror set error: https://mirror.msys2.org/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst: failed: status code 404 error: https://repo.msys2.org/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst: failed: status code 404 error: https://mirror.yandex.ru/mirrors/msys2/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst: failed: status code 404 error: https://mirrors.tuna.tsinghua.edu.cn/msys2/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst: failed: status code 404 error: https://mirrors.ustc.edu.cn/msys2/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst: failed: status code 404 error: https://mirror.selfnet.de/msys2/msys/x86_64/msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst: failed: status code 404 ``` [source](https://github.com/AntaresSimulatorTeam/Antares_Simulator/actions/runs/12580772537/job/35063320582?pr=2552) --- src/vcpkg.json | 6 +++--- vcpkg | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vcpkg.json b/src/vcpkg.json index 68a34fa53c..0a8e10c378 100644 --- a/src/vcpkg.json +++ b/src/vcpkg.json @@ -1,7 +1,7 @@ { "name": "antares-simulator", "version-string": "9.2.0", - "builtin-baseline": "9484a57dd560b89f0a583be08af6753611c57fd5", + "builtin-baseline": "b322364f06308bdd24823f9d8f03fe0cc86fd46f", "vcpkg-configuration": { "overlay-ports": [ "./ports" @@ -21,11 +21,11 @@ }, { "name": "boost-test", - "version>=": "1.81.0" + "version>=": "1.86.0" }, { "name": "boost-core", - "version>=": "1.81.0" + "version>=": "1.86.0" }, { "name": "minizip-ng", diff --git a/vcpkg b/vcpkg index 9d47b24eac..b322364f06 160000 --- a/vcpkg +++ b/vcpkg @@ -1 +1 @@ -Subproject commit 9d47b24eacbd1cd94f139457ef6cd35e5d92cc84 +Subproject commit b322364f06308bdd24823f9d8f03fe0cc86fd46f From 4a30c443cb821b482311095111bda33ffaf9cbba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Mon, 6 Jan 2025 14:54:50 +0100 Subject: [PATCH 094/103] Fix NonMovable class (#2555) --- src/ext/yuni/src/yuni/core/nonmovable.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ext/yuni/src/yuni/core/nonmovable.h b/src/ext/yuni/src/yuni/core/nonmovable.h index e9214e709f..c866e916ec 100644 --- a/src/ext/yuni/src/yuni/core/nonmovable.h +++ b/src/ext/yuni/src/yuni/core/nonmovable.h @@ -49,11 +49,12 @@ class YUNI_DECL NonMovable { protected: //! Default constructor - NonCopyable() + NonMovable() { } + //! Protected non-virtual destructor - ~NonCopyable() + ~NonMovable() { } }; From c6a693edeff70fb9b32c37f086c906f43dc03416 Mon Sep 17 00:00:00 2001 From: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> Date: Mon, 6 Jan 2025 17:17:57 +0100 Subject: [PATCH 095/103] Add optional additionnal constraints to short-term storage objects [ANT-1855] (#2546) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add week-dependent rhs New syntax to declare multiple contraints that shares same rhs vector and type --------- Co-authored-by: payetvin <113102157+payetvin@users.noreply.github.com> Co-authored-by: Vincent Payet Co-authored-by: Florian Omnès --- src/libs/antares/study/CMakeLists.txt | 4 +- src/libs/antares/study/area/list.cpp | 10 +- ...alConstraint.h => additionalConstraints.h} | 24 +- .../study/parts/short-term-storage/cluster.h | 4 +- .../parts/short-term-storage/container.h | 3 +- .../study/parts/short-term-storage/series.h | 2 +- ...nstraint.cpp => additionalConstraints.cpp} | 29 +- .../parts/short-term-storage/container.cpp | 149 ++++- .../study/parts/short-term-storage/series.cpp | 14 +- .../ShortTermStorageCumulation.cpp | 95 ++- .../opt_decompte_variables_et_contraintes.cpp | 8 +- ...opt_gestion_second_membre_cas_lineaire.cpp | 26 +- .../sim_structure_probleme_economique.h | 2 +- .../simulation/sim_calcul_economique.cpp | 18 +- .../short-term-storage-input-output.cpp | 579 ++++++++++++++++++ 15 files changed, 856 insertions(+), 111 deletions(-) rename src/libs/antares/study/include/antares/study/parts/short-term-storage/{AdditionalConstraint.h => additionalConstraints.h} (80%) rename src/libs/antares/study/parts/short-term-storage/{AdditionalConstraint.cpp => additionalConstraints.cpp} (68%) diff --git a/src/libs/antares/study/CMakeLists.txt b/src/libs/antares/study/CMakeLists.txt index e7336d020c..c3d23d9d80 100644 --- a/src/libs/antares/study/CMakeLists.txt +++ b/src/libs/antares/study/CMakeLists.txt @@ -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}) diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index 7af3a6a5a7..c91ecc1e38 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -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 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/additionalConstraints.h similarity index 80% rename from src/libs/antares/study/include/antares/study/parts/short-term-storage/AdditionalConstraint.h rename to src/libs/antares/study/include/antares/study/parts/short-term-storage/additionalConstraints.h index e16b991a05..5804261157 100644 --- 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/additionalConstraints.h @@ -22,20 +22,30 @@ #pragma once #include #include +#include namespace Antares::Data::ShortTermStorage { -struct AdditionalConstraint +class SingleAdditionalConstraint +{ +public: + std::set 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 hours; - double rhs; + bool enabled = true; + std::vector rhs; - unsigned int globalIndex = 0; + std::vector constraints; struct ValidateResult { @@ -43,11 +53,15 @@ struct AdditionalConstraint 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 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 df74a350b0..b7c901d6d1 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,7 +26,7 @@ #include -#include "AdditionalConstraint.h" +#include "additionalConstraints.h" #include "properties.h" #include "series.h" @@ -51,6 +51,6 @@ class STStorageCluster std::shared_ptr series = std::make_shared(); mutable Properties properties; - std::vector additional_constraints; + std::vector additionalConstraints; }; } // 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 d4e0233b5c..b53abc48f0 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 @@ -23,7 +23,6 @@ #include #include -#include "AdditionalConstraint.h" #include "cluster.h" namespace Antares::Data::ShortTermStorage @@ -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(); diff --git a/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h b/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h index 80f90b94f2..1f53a220fe 100644 --- a/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h +++ b/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h @@ -63,5 +63,5 @@ class Series bool loadFile(const std::filesystem::path& folder, std::vector& vect); bool writeVectorToFile(const std::string& path, const std::vector& vect); - +void fillIfEmpty(std::vector& v, double value); } // namespace Antares::Data::ShortTermStorage diff --git a/src/libs/antares/study/parts/short-term-storage/AdditionalConstraint.cpp b/src/libs/antares/study/parts/short-term-storage/additionalConstraints.cpp similarity index 68% rename from src/libs/antares/study/parts/short-term-storage/AdditionalConstraint.cpp rename to src/libs/antares/study/parts/short-term-storage/additionalConstraints.cpp index 2ca904041c..edc8d4d227 100644 --- a/src/libs/antares/study/parts/short-term-storage/AdditionalConstraint.cpp +++ b/src/libs/antares/study/parts/short-term-storage/additionalConstraints.cpp @@ -18,11 +18,14 @@ ** 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" + +#include "antares/study/parts/short-term-storage/additionalConstraints.h" + +#include namespace Antares::Data::ShortTermStorage { -AdditionalConstraint::ValidateResult AdditionalConstraint::validate() const +AdditionalConstraints::ValidateResult AdditionalConstraints::validate() const { if (cluster_id.empty()) { @@ -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 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 39a958c5c7..4c8e17ba3a 100644 --- a/src/libs/antares/study/parts/short-term-storage/container.cpp +++ b/src/libs/antares/study/parts/short-term-storage/container.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -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 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; @@ -87,8 +158,8 @@ 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; @@ -96,46 +167,51 @@ bool STStorageInput::LoadConstraintsFromIniFile(const fs::path& parent_path) 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); + additionalConstraints.cluster_id = transformNameIntoID(clusterName); } - else if (key == "variable") + else if (key == "enabled") { - value.to(constraint.variable); + value.to(additionalConstraints.enabled); } - else if (key == "operator") + else if (key == "variable") { - value.to(constraint.operatorType); + value.to(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(additionalConstraints.operatorType); } - else if (key == "rhs") + else if (key == "hours" && !loadHours(value.c_str(), additionalConstraints)) { - property->value.to(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; @@ -145,7 +221,7 @@ bool STStorageInput::LoadConstraintsFromIniFile(const fs::path& parent_path) } else { - it->additional_constraints.push_back(constraint); + it->additionalConstraints.push_back(additionalConstraints); } } @@ -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 diff --git a/src/libs/antares/study/parts/short-term-storage/series.cpp b/src/libs/antares/study/parts/short-term-storage/series.cpp index 6c341c948d..a8694e967b 100644 --- a/src/libs/antares/study/parts/short-term-storage/series.cpp +++ b/src/libs/antares/study/parts/short-term-storage/series.cpp @@ -107,16 +107,16 @@ bool loadFile(const fs::path& path, std::vector& vect) return true; } -void Series::fillDefaultSeriesIfEmpty() +void fillIfEmpty(std::vector& v, double value) { - auto fillIfEmpty = [](std::vector& v, double value) + if (v.empty()) { - if (v.empty()) - { - v.resize(HOURS_PER_YEAR, value); - } - }; + v.resize(HOURS_PER_YEAR, value); + } +} +void Series::fillDefaultSeriesIfEmpty() +{ fillIfEmpty(maxInjectionModulation, 1.0); fillIfEmpty(maxWithdrawalModulation, 1.0); fillIfEmpty(inflows, 0.0); diff --git a/src/solver/optimisation/constraints/ShortTermStorageCumulation.cpp b/src/solver/optimisation/constraints/ShortTermStorageCumulation.cpp index f6e684db83..3354ce29ce 100644 --- a/src/solver/optimisation/constraints/ShortTermStorageCumulation.cpp +++ b/src/solver/optimisation/constraints/ShortTermStorageCumulation.cpp @@ -27,10 +27,8 @@ class CumulationConstraint { public: - virtual void build(ConstraintBuilder& builder, - unsigned int index, - const ::ShortTermStorage::PROPERTIES& input) const - = 0; + virtual void build(unsigned int index) const = 0; + virtual std::string name() const = 0; virtual ~CumulationConstraint() = default; }; @@ -38,9 +36,12 @@ class CumulationConstraint class WithdrawalCumulationConstraint: public CumulationConstraint { public: - void build(ConstraintBuilder& builder, - unsigned int index, - const ::ShortTermStorage::PROPERTIES&) const override + WithdrawalCumulationConstraint(ConstraintBuilder& builder): + builder(builder) + { + } + + void build(unsigned int index) const override { builder.ShortTermStorageWithdrawal(index, 1.0); } @@ -51,14 +52,19 @@ class WithdrawalCumulationConstraint: public CumulationConstraint } ~WithdrawalCumulationConstraint() override = default; + + ConstraintBuilder& builder; }; class InjectionCumulationConstraint: public CumulationConstraint { public: - void build(ConstraintBuilder& builder, - unsigned int index, - const ::ShortTermStorage::PROPERTIES&) const override + InjectionCumulationConstraint(ConstraintBuilder& builder): + builder(builder) + { + } + + void build(unsigned int index) const override { builder.ShortTermStorageInjection(index, 1.0); } @@ -69,17 +75,25 @@ class InjectionCumulationConstraint: public CumulationConstraint } ~InjectionCumulationConstraint() override = default; + + ConstraintBuilder& builder; }; class NettingCumulationConstraint: public CumulationConstraint { public: - void build(ConstraintBuilder& builder, - unsigned int index, - const ::ShortTermStorage::PROPERTIES& input) const override + NettingCumulationConstraint( + ConstraintBuilder& builder, + const ::ShortTermStorage::PROPERTIES& short_term_storage_properties): + builder(builder), + short_term_storage_properties(short_term_storage_properties) + { + } + + void build(unsigned int index) const override { - builder.ShortTermStorageInjection(index, input.injectionEfficiency) - .ShortTermStorageWithdrawal(index, -input.withdrawalEfficiency); + builder.ShortTermStorageInjection(index, short_term_storage_properties.injectionEfficiency) + .ShortTermStorageWithdrawal(index, -short_term_storage_properties.withdrawalEfficiency); } std::string name() const override @@ -88,21 +102,28 @@ class NettingCumulationConstraint: public CumulationConstraint } ~NettingCumulationConstraint() override = default; + + ConstraintBuilder& builder; + const ShortTermStorage::PROPERTIES& short_term_storage_properties; }; -std::unique_ptr cumulationConstraintFromVariable(const std::string& variable) +std::unique_ptr cumulationConstraintFactory( + const std::string& variable, + ConstraintBuilder& builder, + const ShortTermStorage::PROPERTIES& short_term_storage_properties) { if (variable == "withdrawal") { - return std::make_unique(); + return std::make_unique(builder); } else if (variable == "injection") { - return std::make_unique(); + return std::make_unique(builder); } else if (variable == "netting") { - return std::make_unique(); + return std::make_unique(builder, + short_term_storage_properties); } throw std::invalid_argument("Invalid cumulation constraint type"); } @@ -130,28 +151,34 @@ void ShortTermStorageCumulation::add(int pays) for (const auto& storage: data.ShortTermStorage[pays]) { - for (const auto& constraint: storage.additional_constraints) + for (const auto& additionalConstraints: storage.additionalConstraints) { // 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) + auto cumulationConstraint = cumulationConstraintFactory(additionalConstraints.variable, + builder, + storage); + for (const auto& [hours, globalIndex, localIndex]: additionalConstraints.constraints) { - builder.updateHourWithinWeek(hour - 1); - constraintHelper->build(builder, index, storage); + namer.ShortTermStorageCumulation(cumulationConstraint->name(), + builder.data.nombreDeContraintes, + storage.name, + additionalConstraints.name + "_" + + std::to_string(localIndex)); + const auto index = storage.clusterGlobalIndex; + data.CorrespondanceCntNativesCntOptimHebdomadaires + .ShortTermStorageCumulation[globalIndex] + = builder.data.nombreDeContraintes; + + for (const auto& hour: hours) + { + builder.updateHourWithinWeek(hour - 1); + cumulationConstraint->build(index); + } + builder.SetOperator(ConvertSense(additionalConstraints.operatorType)).build(); } - builder.SetOperator(ConvertSense(constraint.operatorType)).build(); } } } diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp index 79c29c58ab..19f3f26ec9 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp @@ -245,9 +245,13 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* ProblemeAResoudre->NombreDeContraintes += 2 * nombreDePasDeTempsPourUneOptimisation; } - if (!storage.additional_constraints.empty()) + if (!storage.additionalConstraints.empty()) { - ProblemeAResoudre->NombreDeContraintes += storage.additional_constraints.size(); + for (const auto& additionalConstraints: storage.additionalConstraints) + { + ProblemeAResoudre->NombreDeContraintes += additionalConstraints + .enabledConstraints(); + } } } } 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 c04d416f00..d4065fd880 100644 --- a/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_second_membre_cas_lineaire.cpp @@ -19,6 +19,8 @@ ** along with Antares_Simulator. If not, see . */ +#include + #include "antares/solver/simulation/sim_structure_probleme_economique.h" double OPT_SommeDesPminThermiques(const PROBLEME_HEBDO*, int, uint); @@ -47,17 +49,27 @@ static void shortTermStorageCumulationRHS( const std::vector<::ShortTermStorage::AREA_INPUT>& shortTermStorageInput, int numberOfAreas, std::vector& SecondMembre, - const CORRESPONDANCES_DES_CONTRAINTES_HEBDOMADAIRES& CorrespondancesDesContraintesHebdomadaires) + const CORRESPONDANCES_DES_CONTRAINTES_HEBDOMADAIRES& CorrespondancesDesContraintesHebdomadaires, + int weekFirstHour) { for (int areaIndex = 0; areaIndex < numberOfAreas; areaIndex++) { for (auto& storage: shortTermStorageInput[areaIndex]) { - for (const auto& constraint: storage.additional_constraints) + for (const auto& additionalConstraints: storage.additionalConstraints) { - int cnt = CorrespondancesDesContraintesHebdomadaires - .ShortTermStorageCumulation[constraint.globalIndex]; - SecondMembre[cnt] = constraint.rhs; + for (const auto& constraint: additionalConstraints.constraints) + { + const int cnt = CorrespondancesDesContraintesHebdomadaires + .ShortTermStorageCumulation[constraint.globalIndex]; + + SecondMembre[cnt] = std::accumulate( + constraint.hours.begin(), + constraint.hours.end(), + 0.0, + [weekFirstHour, &additionalConstraints](const double sum, const int hour) + { return sum + additionalConstraints.rhs[weekFirstHour + hour - 1]; }); + } } } } @@ -395,11 +407,11 @@ void OPT_InitialiserLeSecondMembreDuProblemeLineaire(PROBLEME_HEBDO* problemeHeb } } } - shortTermStorageCumulationRHS(problemeHebdo->ShortTermStorage, problemeHebdo->NombreDePays, ProblemeAResoudre->SecondMembre, - problemeHebdo->CorrespondanceCntNativesCntOptimHebdomadaires); + problemeHebdo->CorrespondanceCntNativesCntOptimHebdomadaires, + weekFirstHour); if (problemeHebdo->OptimisationAvecCoutsDeDemarrage) { OPT_InitialiserLeSecondMembreDuProblemeLineaireCoutsDeDemarrage(problemeHebdo, 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 35051ba2d5..9356868766 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 @@ -183,7 +183,7 @@ struct PROPERTIES bool penalizeVariationInjection; std::shared_ptr series; - std::vector additional_constraints; + std::vector additionalConstraints; int clusterGlobalIndex; std::string name; }; diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 786b1b5aa6..d9166226f1 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -39,7 +39,7 @@ static void importShortTermStorages( std::vector<::ShortTermStorage::AREA_INPUT>& ShortTermStorageOut) { int clusterGlobalIndex = 0; - int clusterCumulativeConstraintGlobalIndex = 0; + int constraintGlobalIndex = 0; for (uint areaIndex = 0; areaIndex != areas.size(); areaIndex++) { ShortTermStorageOut[areaIndex].resize(areas[areaIndex]->shortTermStorage.count()); @@ -60,12 +60,20 @@ 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) + for (const auto& constraint: st.additionalConstraints) { - constraint.globalIndex = clusterCumulativeConstraintGlobalIndex; - ++clusterCumulativeConstraintGlobalIndex; + if (constraint.enabled) + { + auto newConstraint = constraint; + for (auto& c: newConstraint.constraints) + { + c.globalIndex = constraintGlobalIndex; + ++constraintGlobalIndex; + } + toInsert.additionalConstraints.push_back(std::move(newConstraint)); + } } + toInsert.series = st.series; // TODO add missing properties, or use the same struct diff --git a/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp b/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp index 265135c7d4..d4340dce12 100644 --- a/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp +++ b/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp @@ -25,10 +25,13 @@ #include #include +#include #include #include +#include "antares/antares/constants.h" +#include "antares/study/parts/short-term-storage/additionalConstraints.h" #include "antares/study/parts/short-term-storage/container.h" using namespace std; @@ -451,3 +454,579 @@ BOOST_FIXTURE_TEST_CASE(check_series_save, Fixture) } BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(AdditionalConstraintsTests) + +BOOST_AUTO_TEST_CASE(Validate_ClusterIdEmpty) +{ + ShortTermStorage::AdditionalConstraints constraints; + constraints.cluster_id = ""; // Cluster ID is empty + constraints.variable = "injection"; + constraints.operatorType = "less"; + + auto [ok, error_msg] = constraints.validate(); + BOOST_CHECK_EQUAL(ok, false); + BOOST_CHECK_EQUAL(error_msg, "Cluster ID is empty."); +} + +BOOST_AUTO_TEST_CASE(Validate_InvalidVariable) +{ + ShortTermStorage::AdditionalConstraints constraints; + constraints.cluster_id = "ClusterA"; + constraints.variable = "invalid"; // Invalid variable type + constraints.operatorType = "less"; + + auto [ok, error_msg] = constraints.validate(); + BOOST_CHECK_EQUAL(ok, false); + BOOST_CHECK_EQUAL(error_msg, + "Invalid variable type. Must be 'injection', 'withdrawal', or 'netting'."); +} + +BOOST_AUTO_TEST_CASE(Validate_InvalidOperatorType) +{ + ShortTermStorage::AdditionalConstraints constraints; + constraints.cluster_id = "ClusterA"; + constraints.variable = "injection"; + constraints.operatorType = "invalid"; // Invalid operator type + + auto [ok, error_msg] = constraints.validate(); + BOOST_CHECK_EQUAL(ok, false); + BOOST_CHECK_EQUAL(error_msg, "Invalid operator type. Must be 'less', 'equal', or 'greater'."); +} + +BOOST_AUTO_TEST_CASE(Validate_InvalidHours_Empty) +{ + ShortTermStorage::AdditionalConstraints constraints; + constraints.cluster_id = "ClusterA"; + constraints.variable = "injection"; + constraints.operatorType = "less"; + + // Case : Empty hours + ShortTermStorage::SingleAdditionalConstraint constraint; + constraint.hours = {}; // Invalid: empty + constraints.constraints.push_back(constraint); + + auto [ok, error_msg] = constraints.validate(); + BOOST_CHECK_EQUAL(ok, false); + BOOST_CHECK_EQUAL(error_msg, "Hours sets contains invalid values. Must be between 1 and 168."); +} + +BOOST_AUTO_TEST_CASE(Validate_InvalidHours_Out_of_range) +{ + ShortTermStorage::AdditionalConstraints constraints; + constraints.cluster_id = "ClusterA"; + constraints.variable = "injection"; + constraints.operatorType = "less"; + + // Case: Out of range + ShortTermStorage::SingleAdditionalConstraint constraint; + constraint.hours = {120, 169}; // Invalid: out of range + constraints.constraints.push_back(constraint); + + auto [ok, error_msg] = constraints.validate(); + BOOST_CHECK_EQUAL(ok, false); + BOOST_CHECK_EQUAL(error_msg, "Hours sets contains invalid values. Must be between 1 and 168."); +} + +BOOST_AUTO_TEST_CASE(Validate_InvalidHours_Below_minimum) +{ + ShortTermStorage::AdditionalConstraints constraints; + constraints.cluster_id = "ClusterA"; + constraints.variable = "injection"; + constraints.operatorType = "less"; + + // Case : Below minimum + ShortTermStorage::SingleAdditionalConstraint constraint; + constraint.hours = {0, 1}; // Invalid: below minimum + constraints.constraints.push_back(constraint); + + auto [ok, error_msg] = constraints.validate(); + BOOST_CHECK_EQUAL(ok, false); + BOOST_CHECK_EQUAL(error_msg, "Hours sets contains invalid values. Must be between 1 and 168."); +} + +BOOST_AUTO_TEST_CASE(Validate_ValidConstraints) +{ + ShortTermStorage::AdditionalConstraints constraints; + constraints.cluster_id = "ClusterA"; + constraints.variable = "injection"; + constraints.operatorType = "less"; + + ShortTermStorage::SingleAdditionalConstraint constraint1; + constraint1.hours = {1, 2, 3}; // Valid hours + + ShortTermStorage::SingleAdditionalConstraint constraint2; + constraint2.hours = {100, 150, 168}; // Valid hours + + constraints.constraints = {constraint1, constraint2}; + + auto [ok, error_msg] = constraints.validate(); + BOOST_CHECK_EQUAL(ok, true); + BOOST_CHECK(error_msg.empty()); +} + +BOOST_AUTO_TEST_CASE(loadAdditionalConstraints_ValidFile) +{ + std::filesystem::path testPath = getFolder() / "test_data"; + std::filesystem::create_directory(testPath); + + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << "[constraint1]\n"; + iniFile << "cluster=cluster1\n"; + iniFile << "variable=injection\n"; + iniFile << "operator=less\n"; + iniFile << "hours=[1,2,3]\n"; + iniFile.close(); + + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "cluster1"; + storageInput.storagesByIndex.push_back(cluster); + + bool result = storageInput.loadAdditionalConstraints(testPath); + + BOOST_CHECK_EQUAL(result, true); + BOOST_CHECK_EQUAL(storageInput.storagesByIndex[0].additionalConstraints.size(), 1); + BOOST_CHECK_EQUAL(storageInput.storagesByIndex[0].additionalConstraints[0].name, "constraint1"); + + std::filesystem::remove_all(testPath); +} + +BOOST_AUTO_TEST_CASE(loadAdditionalConstraints_InvalidHours) +{ + std::filesystem::path testPath = getFolder() / "test_data"; + std::filesystem::create_directory(testPath); + + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << "[constraint1]\n"; + iniFile << "cluster=ClusterA\n"; + iniFile << "variable=injection\n"; + iniFile << "operator=less\n"; + iniFile << "hours=[0,1]\n"; // Invalid hours + iniFile.close(); + + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "ClusterA"; + storageInput.storagesByIndex.push_back(cluster); + + bool result = storageInput.loadAdditionalConstraints(testPath); + BOOST_CHECK_EQUAL(result, false); + + std::filesystem::remove_all(testPath); +} + +BOOST_AUTO_TEST_CASE(loadAdditionalConstraints_MissingFile) +{ + ShortTermStorage::STStorageInput storageInput; + bool result = storageInput.loadAdditionalConstraints("nonexistent_path"); + BOOST_CHECK_EQUAL(result, true); +} + +BOOST_AUTO_TEST_CASE(loadAdditionalConstraints_InvalidConstraint) +{ + std::filesystem::path testPath = getFolder() / "test_data"; + std::filesystem::create_directory(testPath); + + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << "[constraint1]\n"; + iniFile << "cluster=cluster1\n"; + iniFile << "variable=invalid\n"; // Invalid variable + iniFile << "operator=less\n"; + iniFile << "hours=[1,2,3]\n"; + iniFile.close(); + + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "cluster1"; + storageInput.storagesByIndex.push_back(cluster); + + bool result = storageInput.loadAdditionalConstraints(testPath); + BOOST_CHECK_EQUAL(result, false); + + std::filesystem::remove_all(testPath); +} + +BOOST_AUTO_TEST_CASE(loadAdditionalConstraints_ValidRhs) +{ + std::filesystem::path testPath = getFolder() / "test_data"; + std::filesystem::create_directory(testPath); + + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << "[constraint1]\n"; + iniFile << "cluster=cluster1\n"; + iniFile << "variable=injection\n"; + iniFile << "operator=less\n"; + iniFile << "hours=[1,2,3]\n"; + iniFile.close(); + + std::ofstream rhsFile(testPath / "rhs_constraint1.txt"); + for (int i = 0; i < HOURS_PER_YEAR; ++i) + { + rhsFile << i * 1.0 << "\n"; + } + rhsFile.close(); + + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "cluster1"; + storageInput.storagesByIndex.push_back(cluster); + + bool result = storageInput.loadAdditionalConstraints(testPath); + + BOOST_CHECK_EQUAL(result, true); + BOOST_CHECK_EQUAL(storageInput.storagesByIndex[0].additionalConstraints[0].rhs.size(), + HOURS_PER_YEAR); + BOOST_CHECK_EQUAL(storageInput.storagesByIndex[0].additionalConstraints[0].rhs[0], 0.0); + BOOST_CHECK_EQUAL( + storageInput.storagesByIndex[0].additionalConstraints[0].rhs[HOURS_PER_YEAR - 1], + HOURS_PER_YEAR - 1); + + std::filesystem::remove_all(testPath); +} + +BOOST_AUTO_TEST_CASE(Load2ConstraintsFromIniFile) +{ + std::filesystem::path testPath = getFolder() / "test_data"; + std::filesystem::create_directory(testPath); + + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << R"([constraint1] + cluster=cluster1 + variable=injection + operator=less + hours=[1,2,3] + [constraint2] + cluster=cluster1 + variable=withdrawal + operator=greater + hours=[5,33])"; + iniFile.close(); + + std::ofstream rhsFile(testPath / "rhs_constraint1.txt"); + for (int i = 0; i < HOURS_PER_YEAR; ++i) + { + rhsFile << i * 1.0 << "\n"; + } + rhsFile.close(); + + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "cluster1"; + storageInput.storagesByIndex.push_back(cluster); + + bool result = storageInput.loadAdditionalConstraints(testPath); + + BOOST_CHECK_EQUAL(result, true); + BOOST_CHECK_EQUAL(storageInput.storagesByIndex[0].additionalConstraints.size(), 2); + + //------- constraint1 ---------- + const auto& constraint1 = storageInput.storagesByIndex[0].additionalConstraints[0]; + BOOST_CHECK_EQUAL(constraint1.name, "constraint1"); + BOOST_CHECK_EQUAL(constraint1.operatorType, "less"); + BOOST_CHECK_EQUAL(constraint1.variable, "injection"); + BOOST_CHECK_EQUAL(constraint1.cluster_id, cluster.id); + BOOST_CHECK_EQUAL(constraint1.rhs.size(), HOURS_PER_YEAR); + BOOST_CHECK_EQUAL(constraint1.rhs[0], 0.0); + BOOST_CHECK_EQUAL(constraint1.rhs[HOURS_PER_YEAR - 1], HOURS_PER_YEAR - 1); + + //------- constraint2 ---------- + + const auto& constraint2 = storageInput.storagesByIndex[0].additionalConstraints[1]; + BOOST_CHECK_EQUAL(constraint2.name, "constraint2"); + BOOST_CHECK_EQUAL(constraint2.operatorType, "greater"); + BOOST_CHECK_EQUAL(constraint2.variable, "withdrawal"); + BOOST_CHECK_EQUAL(constraint2.cluster_id, cluster.id); + + BOOST_CHECK_EQUAL(constraint2.rhs.size(), HOURS_PER_YEAR); + BOOST_CHECK_EQUAL(constraint2.rhs[0], 0.0); + BOOST_CHECK_EQUAL(constraint2.rhs[HOURS_PER_YEAR - 1], 0.0); + + std::filesystem::remove_all(testPath); +} + +BOOST_AUTO_TEST_CASE(loadAdditionalConstraints_MissingRhsFile) +{ + std::filesystem::path testPath = getFolder() / "test_data"; + std::filesystem::create_directory(testPath); + + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << "[constraint1]\n"; + iniFile << "cluster=cluster1\n"; + iniFile << "variable=injection\n"; + iniFile << "operator=less\n"; + iniFile << "hours=[1,2,3]\n"; + iniFile.close(); + + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "cluster1"; + storageInput.storagesByIndex.push_back(cluster); + + bool result = storageInput.loadAdditionalConstraints(testPath); + + BOOST_CHECK_EQUAL(result, true); + BOOST_CHECK_EQUAL(storageInput.storagesByIndex[0].additionalConstraints[0].rhs.size(), + HOURS_PER_YEAR); + BOOST_CHECK_EQUAL(storageInput.storagesByIndex[0].additionalConstraints[0].rhs[0], 0.0); + + std::filesystem::remove_all(testPath); +} + +BOOST_AUTO_TEST_CASE(loadAdditionalConstraints_MalformedRhsFile) +{ + std::filesystem::path testPath = getFolder() / "test_data"; + std::filesystem::create_directory(testPath); + + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << "[constraint1]\n"; + iniFile << "cluster=cluster1\n"; + iniFile << "variable=injection\n"; + iniFile << "operator=less\n"; + iniFile << "hours=[1,2,3]\n"; + iniFile.close(); + + std::ofstream rhsFile(testPath / "rhs_constraint1.txt"); + rhsFile << "1.0\n2.0\ninvalid\n4.0\n"; // Malformed line + rhsFile.close(); + + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "cluster1"; + storageInput.storagesByIndex.push_back(cluster); + + bool result = storageInput.loadAdditionalConstraints(testPath); + BOOST_CHECK_EQUAL(result, false); + /*"Error while reading rhs file: " << "rhs_" << additionalConstraints.name + << + ".txt";*/ + std::filesystem::remove_all(testPath); +} + +BOOST_AUTO_TEST_CASE(loadAdditionalConstraints_IncompleteRhsFile) +{ + std::filesystem::path testPath = getFolder() / "test_data"; + std::filesystem::create_directory(testPath); + + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << "[constraint1]\n"; + iniFile << "cluster=cluster1\n"; + iniFile << "variable=injection\n"; + iniFile << "operator=less\n"; + iniFile << "hours=[1,2,3]\n"; + iniFile.close(); + + std::ofstream rhsFile(testPath / "rhs_constraint1.txt"); + for (int i = 0; i < 10; ++i) + { + rhsFile << i * 1.0 << "\n"; + } + rhsFile.close(); + + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "cluster1"; + storageInput.storagesByIndex.push_back(cluster); + + bool result = storageInput.loadAdditionalConstraints(testPath); + BOOST_CHECK_EQUAL(result, false); + + std::filesystem::remove_all(testPath); +} + +// Test data for parameterization +namespace bdata = boost::unit_test::data; + +BOOST_DATA_TEST_CASE(Validate_AllVariableOperatorCombinations, + bdata::make({"injection", "withdrawal", "netting"}) + ^ bdata::make({"less", "equal", "greater"}), + variable, + op) +{ + ShortTermStorage::AdditionalConstraints constraints; + constraints.cluster_id = "ClusterA"; + constraints.variable = variable; + constraints.operatorType = op; + + // Create constraints with valid hours + constraints.constraints.push_back(ShortTermStorage::SingleAdditionalConstraint{{1, 2, 3}}); + constraints.constraints.push_back(ShortTermStorage::SingleAdditionalConstraint{{50, 100, 150}}); + constraints.constraints.push_back( + ShortTermStorage::SingleAdditionalConstraint{{120, 121, 122}}); + + // Validate the constraints + auto [ok, error_msg] = constraints.validate(); + BOOST_CHECK_EQUAL(ok, true); + BOOST_CHECK(error_msg.empty()); +} + +BOOST_DATA_TEST_CASE(Validate_AllVariableOperatorCombinationsFromFile, + bdata::make({"injection", "withdrawal", "netting"}) + * bdata::make({"less", "equal", "greater"}), + variable, + op) +{ + // Define the path for the test data + std::filesystem::path testPath = std::filesystem::temp_directory_path() / "test_data"; + std::filesystem::create_directory(testPath); + + // Write the `.ini` file for this test case + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << "[constraint1]\n"; + iniFile << "cluster=clustera\n"; + iniFile << "variable=" << variable << "\n"; + iniFile << "operator=" << op << "\n"; + iniFile << "enabled=true\n"; + iniFile << "hours=[1,2,3]\n"; + iniFile.close(); + + // Write the `rhs_constraint1.txt` file + std::ofstream rhsFile(testPath / "rhs_constraint1.txt"); + for (int i = 0; i < HOURS_PER_YEAR; ++i) + { + rhsFile << i * 1.0 << "\n"; + } + rhsFile.close(); + + // Setup storage input and cluster + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "clustera"; + storageInput.storagesByIndex.push_back(cluster); + + // Load constraints from the `.ini` file + bool result = storageInput.loadAdditionalConstraints(testPath); + BOOST_CHECK_EQUAL(storageInput.cumulativeConstraintCount(), 1); + + // Assertions + BOOST_CHECK_EQUAL(result, true); + // Validate loaded constraints + auto& built_cluster = storageInput.storagesByIndex[0]; + BOOST_REQUIRE_EQUAL(built_cluster.additionalConstraints.size(), 1); + + const auto& loadedConstraint = built_cluster.additionalConstraints[0]; + + // Check variable, operator type, and rhs values + BOOST_CHECK_EQUAL(loadedConstraint.variable, variable); + BOOST_CHECK_EQUAL(loadedConstraint.operatorType, op); + BOOST_REQUIRE_EQUAL(loadedConstraint.rhs.size(), HOURS_PER_YEAR); + + int i = 0; + do + { + BOOST_CHECK_CLOSE(loadedConstraint.rhs[i], i * 1.0, 0.001); + // Check rhs values within a tolerance + + i += HOURS_PER_YEAR / 5; + } while (i < HOURS_PER_YEAR); +} + +BOOST_AUTO_TEST_CASE(Load_disabled) +{ + // Define the path for the test data + std::filesystem::path testPath = std::filesystem::temp_directory_path() / "test_data"; + std::filesystem::create_directory(testPath); + + // Write the `.ini` file for this test case + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << "[constraint1]\n"; + iniFile << "cluster=clustera\n"; + iniFile << "variable=injection\n"; + iniFile << "operator=less\n"; + iniFile << "enabled=false\n"; + iniFile << "hours=[1,2,3]\n"; + iniFile.close(); + + // Setup storage input and cluster + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "clustera"; + storageInput.storagesByIndex.push_back(cluster); + + // Load constraints from the `.ini` file + bool result = storageInput.loadAdditionalConstraints(testPath); + BOOST_CHECK_EQUAL(storageInput.cumulativeConstraintCount(), 0); + + // Assertions + BOOST_CHECK_EQUAL(result, true); + // Validate loaded constraints + auto& built_cluster = storageInput.storagesByIndex[0]; + BOOST_REQUIRE_EQUAL(built_cluster.additionalConstraints.size(), 0); +} + +BOOST_DATA_TEST_CASE(loadAdditionalConstraints_InvalidHoursFormat, + bdata::make({"", + "[]", + "[ ]", + "[\t]", + "[\r]", + "[\f]", + "[\v]", + "[1, nol]", + "[; 3,2,1]", + "[1, 12345678901]", + "[1, 12345", + "1]", + "[1,]", + "[1,,2]", + "[a]", + "[1, 2], , [3]"}), + hours) +{ + std::filesystem::path testPath = getFolder() / "test_data"; + std::filesystem::create_directory(testPath); + + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << "[constraint1]\n"; + iniFile << "cluster=cluster1\n"; + iniFile << "variable=injection\n"; + iniFile << "operator=less\n"; + iniFile << "hours=" << hours << "\n"; // Invalid formats + iniFile.close(); + + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "cluster1"; + storageInput.storagesByIndex.push_back(cluster); + + bool result = storageInput.loadAdditionalConstraints(testPath); + BOOST_CHECK_EQUAL(result, false); + + std::filesystem::remove_all(testPath); +} + +BOOST_DATA_TEST_CASE( + loadAdditionalConstraints_ValidHoursFormats, + bdata::make( + {"[1],[1],[3,2,1]", + "[\r1,\t2]", + "[\v1\f,\t2],\f\v\t[4]", + "[\f\v1]\t\t", + "\t\v\t[1 ], [ 1, 2,3] ", + " [4,5 ]", + "[1 2 3 , 11 3]"}), + hours) +{ + std::filesystem::path testPath = getFolder() / "test_data"; + std::filesystem::create_directory(testPath); + + std::ofstream iniFile(testPath / "additional-constraints.ini"); + iniFile << "[constraint1]\n"; + iniFile << "cluster=cluster1\n"; + iniFile << "variable=injection\n"; + iniFile << "operator=less\n"; + iniFile << "hours=" << hours << "\n"; // Valid formats + iniFile.close(); + + ShortTermStorage::STStorageInput storageInput; + ShortTermStorage::STStorageCluster cluster; + cluster.id = "cluster1"; + storageInput.storagesByIndex.push_back(cluster); + + bool result = storageInput.loadAdditionalConstraints(testPath); + BOOST_CHECK_EQUAL(result, true); + + std::filesystem::remove_all(testPath); +} + +BOOST_AUTO_TEST_SUITE_END() From b48858164c3ca32927bb3a46d986b4a4713b1244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Wed, 8 Jan 2025 12:06:28 +0100 Subject: [PATCH 096/103] Set modeler name for logs (instead of [noname]) (#2561) --- src/solver/modeler/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/solver/modeler/main.cpp b/src/solver/modeler/main.cpp index a4d071660b..2af8f38e3f 100644 --- a/src/solver/modeler/main.cpp +++ b/src/solver/modeler/main.cpp @@ -28,6 +28,8 @@ using namespace Antares::Solver; int main(int argc, const char** argv) { + logs.applicationName("modeler"); + if (argc < 1) { logs.error() << "No study path provided, exiting."; From c6e46c812c735570538dfd8a0ecc752199d06745 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:24:56 +0100 Subject: [PATCH 097/103] Fix yaml-cpp target to avoid cmake warnings (#2564) --- src/solver/modelParser/CMakeLists.txt | 2 +- src/solver/modeler/parameters/CMakeLists.txt | 2 +- src/solver/systemParser/CMakeLists.txt | 2 +- src/tests/src/libs/antares/yaml-parser/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/solver/modelParser/CMakeLists.txt b/src/solver/modelParser/CMakeLists.txt index 8e5ac13726..55eae9b706 100644 --- a/src/solver/modelParser/CMakeLists.txt +++ b/src/solver/modelParser/CMakeLists.txt @@ -17,7 +17,7 @@ target_include_directories(modelParser # Link dependencies (if any) target_link_libraries(modelParser PRIVATE - yaml-cpp + yaml-cpp::yaml-cpp ) install(DIRECTORY include/antares diff --git a/src/solver/modeler/parameters/CMakeLists.txt b/src/solver/modeler/parameters/CMakeLists.txt index 7ab35d5002..308a15f148 100644 --- a/src/solver/modeler/parameters/CMakeLists.txt +++ b/src/solver/modeler/parameters/CMakeLists.txt @@ -8,7 +8,7 @@ add_library(Antares::modelerParameters ALIAS modelerParameters) target_link_libraries(modelerParameters PRIVATE - yaml-cpp + yaml-cpp::yaml-cpp Antares::io) target_include_directories(modelerParameters diff --git a/src/solver/systemParser/CMakeLists.txt b/src/solver/systemParser/CMakeLists.txt index 37e09a616a..e0c16fea65 100644 --- a/src/solver/systemParser/CMakeLists.txt +++ b/src/solver/systemParser/CMakeLists.txt @@ -22,7 +22,7 @@ target_link_libraries(systemParser PUBLIC Antares::antares-study-system-model PRIVATE - yaml-cpp + yaml-cpp::yaml-cpp ) install(DIRECTORY include/antares diff --git a/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt b/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt index dbb1a0535a..d6da0bec19 100644 --- a/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt +++ b/src/tests/src/libs/antares/yaml-parser/CMakeLists.txt @@ -2,4 +2,4 @@ include(${CMAKE_SOURCE_DIR}/tests/macros.cmake) add_boost_test(yaml-parser-test SRC test_yaml_parser.cpp - LIBS yaml-cpp) + LIBS yaml-cpp::yaml-cpp) From 4cb902daca2ab4b2769bd421d44c032a3b642e78 Mon Sep 17 00:00:00 2001 From: payetvin <113102157+payetvin@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:40:00 +0100 Subject: [PATCH 098/103] Add variable MRG PRICE CSR in 9.2 [ANT-2562] (#2559) --- .../study/parameters/adq-patch-params.cpp | 1 + .../adq_patch_post_process_list.cpp | 4 +- .../optimisation/post_process_commands.cpp | 12 + .../sim_structure_probleme_economique.h | 1 + .../simulation/sim_alloc_probleme_hebdo.cpp | 1 + src/solver/variable/CMakeLists.txt | 1 + .../antares/solver/variable/economy/all.h | 115 ++++---- .../solver/variable/economy/priceCSR.h | 273 ++++++++++++++++++ 8 files changed, 350 insertions(+), 58 deletions(-) create mode 100644 src/solver/variable/include/antares/solver/variable/economy/priceCSR.h diff --git a/src/libs/antares/study/parameters/adq-patch-params.cpp b/src/libs/antares/study/parameters/adq-patch-params.cpp index 800f2d19f8..ba075cc3a8 100644 --- a/src/libs/antares/study/parameters/adq-patch-params.cpp +++ b/src/libs/antares/study/parameters/adq-patch-params.cpp @@ -150,6 +150,7 @@ void AdqPatchParams::addExcludedVariables(std::vector& out) const out.emplace_back("LOLP CSR"); out.emplace_back("MAX MRG CSR"); out.emplace_back("OV. COST CSR"); + out.emplace_back("MRG. PRICE CSR"); } } diff --git a/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp b/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp index f9f8aa389b..fb21977bcd 100644 --- a/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp +++ b/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp @@ -48,10 +48,10 @@ AdqPatchPostProcessList::AdqPatchPostProcessList(const AdqPatchParams& adqPatchP problemeHebdo_, areas, numSpace_)); - post_process_list.push_back( - std::make_unique(problemeHebdo_, areas, numSpace)); post_process_list.push_back( std::make_unique(problemeHebdo_, areas, numSpace)); + post_process_list.push_back( + std::make_unique(problemeHebdo_, areas, numSpace)); post_process_list.push_back( std::make_unique(problemeHebdo_, areas, true, false)); post_process_list.push_back( diff --git a/src/solver/optimisation/post_process_commands.cpp b/src/solver/optimisation/post_process_commands.cpp index 3ddc06ddde..83446402a9 100644 --- a/src/solver/optimisation/post_process_commands.cpp +++ b/src/solver/optimisation/post_process_commands.cpp @@ -143,6 +143,18 @@ void UpdateMrgPriceAfterCSRcmd::execute(const optRuntimeData&) const bool isHourTriggeredByCsr = problemeHebdo_->adequacyPatchRuntimeData ->wasCSRTriggeredAtAreaHour(Area, hour); + // IF UNSP. ENR CSR == 0, MRG. PRICE CSR = MRG. PRICE + // ELSE, MRG. PRICE CSR = “Unsupplied Energy Cost” + if (hourlyResults.ValeursHorairesDeDefaillancePositiveCSR[hour] > 0.5 && areaInside) + { + hourlyResults.CoutsMarginauxHorairesCSR[hour] = -unsuppliedEnergyCost; + } + else + { + hourlyResults.CoutsMarginauxHorairesCSR[hour] = hourlyResults + .CoutsMarginauxHoraires[hour]; + } + if (isHourTriggeredByCsr && hourlyResults.ValeursHorairesDeDefaillancePositive[hour] > 0.5 && areaInside) { 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 9356868766..a37afcee55 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 @@ -436,6 +436,7 @@ struct RESULTATS_HORAIRES std::vector debordementsHoraires; std::vector CoutsMarginauxHoraires; + std::vector CoutsMarginauxHorairesCSR; std::vector ProductionThermique; // index is pdtHebdo std::vector<::ShortTermStorage::RESULTS> ShortTermStorage; diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index dd7480671c..d6386dc891 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -398,6 +398,7 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, problem.ResultatsHoraires[k].TurbinageHoraire.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].PompageHoraire.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].CoutsMarginauxHoraires.assign(NombreDePasDeTemps, 0.); + problem.ResultatsHoraires[k].CoutsMarginauxHorairesCSR.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].niveauxHoraires.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].valeurH2oHoraire.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].debordementsHoraires.assign(NombreDePasDeTemps, 0.); diff --git a/src/solver/variable/CMakeLists.txt b/src/solver/variable/CMakeLists.txt index ed7c017f5b..49105937c3 100644 --- a/src/solver/variable/CMakeLists.txt +++ b/src/solver/variable/CMakeLists.txt @@ -100,6 +100,7 @@ set(SRC_VARIABLE_ECONOMY include/antares/solver/variable/economy/STStorageCashFlowByCluster.h include/antares/solver/variable/economy/unsupliedEnergy.h include/antares/solver/variable/economy/unsupliedEnergyCsr.h + include/antares/solver/variable/economy/priceCSR.h include/antares/solver/variable/economy/domesticUnsuppliedEnergy.h include/antares/solver/variable/economy/localMatchingRuleViolations.h include/antares/solver/variable/economy/dtgMarginAfterCsr.h diff --git a/src/solver/variable/include/antares/solver/variable/economy/all.h b/src/solver/variable/include/antares/solver/variable/economy/all.h index 17207c22db..bd2e5c4cb2 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/all.h +++ b/src/solver/variable/include/antares/solver/variable/economy/all.h @@ -60,6 +60,7 @@ #include "overallCost.h" #include "overallCostCsr.h" #include "overflow.h" +#include "priceCSR.h" #include "pumping.h" #include "renewableGeneration.h" #include "reservoirlevel.h" @@ -95,62 +96,64 @@ namespace Antares::Solver::Variable::Economy /*! ** \brief All variables for a single area (economy) */ -typedef // Prices - OverallCost // Overall Cost (Op. Cost + Unsupplied Eng.) - >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +typedef // Prices + OverallCost // Overall Cost (Op. Cost + Unsupplied Eng.) + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VariablesPerArea; /*! diff --git a/src/solver/variable/include/antares/solver/variable/economy/priceCSR.h b/src/solver/variable/include/antares/solver/variable/economy/priceCSR.h new file mode 100644 index 0000000000..a3eac2966a --- /dev/null +++ b/src/solver/variable/include/antares/solver/variable/economy/priceCSR.h @@ -0,0 +1,273 @@ +/* +** 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 +*/ +#pragma once + +#include "yuni/yuni.h" + +#include "../variable.h" + +namespace Antares::Solver::Variable::Economy +{ +struct VCardPriceCSR +{ + //! Caption + static std::string Caption() + { + return "MRG. PRICE CSR"; + } + + //! Unit + static std::string Unit() + { + return "Euro"; + } + + //! The short description of the variable + static std::string Description() + { + return "Marginal Price CSR, throughout all MC years"; + } + + //! The expecte results + typedef Results>>>> + ResultsType; + + //! The VCard to look for for calculating spatial aggregates + typedef VCardPrice VCardForSpatialAggregate; + + enum + { + //! Data Level + categoryDataLevel = Category::DataLevel::area, + //! File level (provided by the type of the results) + categoryFileLevel = ResultsType::categoryFile + & (Category::FileLevel::id | Category::FileLevel::va), + //! Precision (views) + precision = Category::all, + //! Indentation (GUI) + nodeDepthForGUI = +0, + //! Decimal precision + decimal = 2, + //! Number of columns used by the variable (One ResultsType per column) + columnCount = 1, + //! The Spatial aggregation + spatialAggregate = Category::spatialAggregateAverage, + spatialAggregateMode = Category::spatialAggregateEachYear, + spatialAggregatePostProcessing = Category::spatialAggregatePostProcessingPrice, + //! 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 Marginal Price +*/ +template +class PriceCSR: public Variable::IVariable, NextT, VCardPriceCSR> +{ +public: + //! Type of the next static variable + typedef NextT NextType; + //! VCard + typedef VCardPriceCSR 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: + ~PriceCSR() + { + delete[] pValuesForTheCurrentYear; + } + + void initializeFromStudy(Data::Study& study) + { + pNbYearsParallel = study.maxNbYearsInParallel; + + // Average thoughout all years + InitializeResultsFromStudy(AncestorType::pResults, study); + + // Intermediate values + 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(uint year, unsigned int numSpace) + { + // Reset the values for the current year + pValuesForTheCurrentYear[numSpace].reset(); + // Next variable + NextType::yearBegin(year, numSpace); + } + + void yearEndBuild(State& state, unsigned int year) + { + // Next variable + NextType::yearEndBuild(state, year); + } + + void yearEnd(uint year, unsigned int numSpace) + { + // Compute all statistics for the current year (daily,weekly,monthly) + pValuesForTheCurrentYear[numSpace].computeAveragesForCurrentYearFromHourlyResults(); + + // 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(uint hourInTheYear) + { + // Next variable + NextType::hourBegin(hourInTheYear); + } + + void hourForEachArea(State& state, unsigned int numSpace) + { + pValuesForTheCurrentYear[numSpace][state.hourInTheYear] = -state.hourlyResults + ->CoutsMarginauxHorairesCSR + [state.hourInTheWeek]; + // Next variable + NextType::hourForEachArea(state, numSpace); + } + + Antares::Memory::Stored::ConstReturnType retrieveRawHourlyValuesForCurrentYear( + uint, + 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 PriceCSR + +} // namespace Antares::Solver::Variable::Economy From ad2140f78eed450877efafeccca8a4e15c19585f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Thu, 9 Jan 2025 17:29:58 +0100 Subject: [PATCH 099/103] Write raw optimization results [ANT-2302] (#2565) Allow the user to export solutions through new boolean option `include-export-solutions` (default=`false`). --------- Co-authored-by: sylvmara --- .../solver/static-modeler/04-parameters.md | 12 ++++++ .../study/include/antares/study/parameters.h | 1 + src/libs/antares/study/parameters.cpp | 12 ++++++ .../opt_optimisation_lineaire.cpp | 39 +++++++++++++++++++ .../sim_structure_probleme_economique.h | 1 + .../simulation/sim_calcul_economique.cpp | 1 + src/solver/utils/filename.cpp | 18 +++++++++ .../include/antares/solver/utils/filename.h | 10 +++++ 8 files changed, 94 insertions(+) diff --git a/docs/user-guide/solver/static-modeler/04-parameters.md b/docs/user-guide/solver/static-modeler/04-parameters.md index aad7e09794..a50f982135 100644 --- a/docs/user-guide/solver/static-modeler/04-parameters.md +++ b/docs/user-guide/solver/static-modeler/04-parameters.md @@ -433,6 +433,18 @@ _**This section is under construction**_ > _**Note:**_ You can find more information on this parameter [here](../03-appendix.md#details-on-the-include-exportmps-parameter). +--- +#### include-export-solutions +- **Expected value:** `true` or `false` +- **Required:** no +- **Default value:** `false` +- **Usage:** set to `true` to activate writing the raw optimization results, that is + - For each variable, optimal values (saved in output/output-name/optimal-values-y-w--optim-nb-z.txt) and reduced costs (saved in output/output-name/reduced-costs-y-w--optim-nb-z.txt) + - each constraint, the marginal cost is saved in output/output-name/marinal-costs-y-w--optim-nb-z.txt +where y is the year number (starting from 1), w is the week number (starting from 1) and z is the optimization index (1 or 2). + +This is an advanced option intended to help developers and advanced users better understand their simulation results. + --- #### include-split-exported-mps [//]: # (TODO: document this parameter, seems to belong to another category) diff --git a/src/libs/antares/study/include/antares/study/parameters.h b/src/libs/antares/study/include/antares/study/parameters.h index 38228bc23b..664d574b32 100644 --- a/src/libs/antares/study/include/antares/study/parameters.h +++ b/src/libs/antares/study/include/antares/study/parameters.h @@ -397,6 +397,7 @@ class Parameters final //! Enum to define unfeasible problem behavior \see UnfeasibleProblemBehavior UnfeasibleProblemBehavior unfeasibleProblemBehavior; + bool exportSolutions; } include; struct Compatibility diff --git a/src/libs/antares/study/parameters.cpp b/src/libs/antares/study/parameters.cpp index 54f5b6db74..60a3781bd2 100644 --- a/src/libs/antares/study/parameters.cpp +++ b/src/libs/antares/study/parameters.cpp @@ -368,6 +368,7 @@ void Parameters::reset() include.exportMPS = mpsExportStatus::NO_EXPORT; include.exportStructure = false; + include.exportSolutions = false; namedProblems = false; include.unfeasibleProblemBehavior = UnfeasibleProblemBehavior::ERROR_MPS; @@ -721,6 +722,11 @@ static bool SGDIntLoadFamily_Optimization(Parameters& d, return true; } + if (key == "include-export-solutions") + { + return value.to(d.include.exportSolutions); + } + if (key == "include-exportstructure") { return value.to(d.include.exportStructure); @@ -1769,6 +1775,10 @@ void Parameters::prepareForSimulation(const StudyLoadOptions& options) { logs.info() << " :: ignoring hurdle costs"; } + if (!include.exportSolutions) + { + logs.info() << " :: ignoring solution export"; + } logs.info() << " :: solver " << options.optOptions.ortoolsSolver << " is used for problem resolution"; @@ -1888,7 +1898,9 @@ void Parameters::saveToINI(IniFile& ini) const section->add("include-primaryreserve", include.reserve.primary); section->add("include-exportmps", mpsExportStatusToString(include.exportMPS)); + section->add("include-exportstructure", include.exportStructure); + section->add("include-export-solutions", include.exportSolutions); // Unfeasible problem behavior section->add("include-unfeasible-problem-behavior", diff --git a/src/solver/optimisation/opt_optimisation_lineaire.cpp b/src/solver/optimisation/opt_optimisation_lineaire.cpp index 99669ad1ea..ecb0231f11 100644 --- a/src/solver/optimisation/opt_optimisation_lineaire.cpp +++ b/src/solver/optimisation/opt_optimisation_lineaire.cpp @@ -62,6 +62,38 @@ void OPT_EcrireResultatFonctionObjectiveAuFormatTXT( writer.addEntryFromBuffer(filename, buffer); } +void OPT_WriteSolution(const PROBLEME_ANTARES_A_RESOUDRE& pb, + const OptPeriodStringGenerator& optPeriodStringGenerator, + int optimizationNumber, + Solver::IResultWriter& writer) +{ + Yuni::Clob buffer; + auto filename = createSolutionFilename(optPeriodStringGenerator, optimizationNumber); + for (int var = 0; var < pb.NombreDeVariables; var++) + { + buffer.appendFormat("%s\t%11.10e\n", pb.NomDesVariables[var].c_str(), pb.X[var]); + } + writer.addEntryFromBuffer(filename, buffer); + buffer.clear(); + + filename = createMarginalCostFilename(optPeriodStringGenerator, optimizationNumber); + for (unsigned int cont = 0; cont < pb.NombreDeContraintes; ++cont) + { + buffer.appendFormat("%s\t%11.10e\n", + pb.NomDesContraintes[cont].c_str(), + pb.CoutsMarginauxDesContraintes[cont]); + } + writer.addEntryFromBuffer(filename, buffer); + buffer.clear(); + + filename = createReducedCostFilename(optPeriodStringGenerator, optimizationNumber); + for (unsigned int var = 0; var < pb.NombreDeVariables; ++var) + { + buffer.appendFormat("%s\t%11.10e\n", pb.NomDesVariables[var].c_str(), pb.CoutsReduits[var]); + } + writer.addEntryFromBuffer(filename, buffer); +} + namespace { void notifyProblemHebdo(const PROBLEME_HEBDO* problemeHebdo, @@ -141,6 +173,13 @@ bool runWeeklyOptimization(const OptimizationOptions& options, optimizationNumber, writer); } + if (problemeHebdo->exportSolutions) + { + OPT_WriteSolution(*problemeHebdo->ProblemeAResoudre, + *optPeriodStringGenerator, + optimizationNumber, + writer); + } } return true; } 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 a37afcee55..dc7375c1f1 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 @@ -533,6 +533,7 @@ struct PROBLEME_HEBDO bool exportMPSOnError = false; bool ExportStructure = false; bool NamedProblems = false; + bool exportSolutions = false; uint32_t HeureDansLAnnee = 0; bool LeProblemeADejaEteInstancie = false; diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index d9166226f1..bfd33cc9f2 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -122,6 +122,7 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, problem.NombreDeContraintesCouplantes = activeConstraints.size(); problem.ExportMPS = study.parameters.include.exportMPS; + problem.exportSolutions = study.parameters.include.exportSolutions; problem.ExportStructure = study.parameters.include.exportStructure; problem.NamedProblems = study.parameters.namedProblems; problem.exportMPSOnError = Data::exportMPS(parameters.include.unfeasibleProblemBehavior); diff --git a/src/solver/utils/filename.cpp b/src/solver/utils/filename.cpp index cc71083350..2393e40c13 100644 --- a/src/solver/utils/filename.cpp +++ b/src/solver/utils/filename.cpp @@ -65,3 +65,21 @@ std::string createMPSfilename(const OptPeriodStringGenerator& optPeriodStringGen { return createOptimizationFilename("problem", optPeriodStringGenerator, optNumber, "mps"); } + +std::string createSolutionFilename(const OptPeriodStringGenerator& optPeriodStringGenerator, + const unsigned int optNumber) +{ + return createOptimizationFilename("optimal-values", optPeriodStringGenerator, optNumber, "txt"); +} + +std::string createMarginalCostFilename(const OptPeriodStringGenerator& optPeriodStringGenerator, + const unsigned int optNumber) +{ + return createOptimizationFilename("marginal-costs", optPeriodStringGenerator, optNumber, "txt"); +} + +std::string createReducedCostFilename(const OptPeriodStringGenerator& optPeriodStringGenerator, + const unsigned int optNumber) +{ + return createOptimizationFilename("reduced-costs", optPeriodStringGenerator, optNumber, "txt"); +} diff --git a/src/solver/utils/include/antares/solver/utils/filename.h b/src/solver/utils/include/antares/solver/utils/filename.h index 472d8f8477..7828fcc7a3 100644 --- a/src/solver/utils/include/antares/solver/utils/filename.h +++ b/src/solver/utils/include/antares/solver/utils/filename.h @@ -32,5 +32,15 @@ std::shared_ptr createOptPeriodAsString(bool isOptimiz std::string createCriterionFilename(const OptPeriodStringGenerator& optPeriodStringGenerator, const unsigned int optNumber); + std::string createMPSfilename(const OptPeriodStringGenerator& optPeriodStringGenerator, const unsigned int optNumber); + +std::string createSolutionFilename(const OptPeriodStringGenerator& optPeriodStringGenerator, + const unsigned int optNumber); + +std::string createMarginalCostFilename(const OptPeriodStringGenerator& optPeriodStringGenerator, + const unsigned int optNumber); + +std::string createReducedCostFilename(const OptPeriodStringGenerator& optPeriodStringGenerator, + const unsigned int optNumber); From c9cdfd1aca4fa335e1fb0f7805efd02acb13464c Mon Sep 17 00:00:00 2001 From: Abdoulbari Zaher <32519851+a-zakir@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:43:18 +0100 Subject: [PATCH 100/103] Move .clang-format at project root (#2568) This seems to be the usual practice for C/C++ code bases. --- src/.clang-format => .clang-format | 0 src/format-code.sh | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/.clang-format => .clang-format (100%) diff --git a/src/.clang-format b/.clang-format similarity index 100% rename from src/.clang-format rename to .clang-format diff --git a/src/format-code.sh b/src/format-code.sh index 752080ca58..aaededa940 100755 --- a/src/format-code.sh +++ b/src/format-code.sh @@ -20,5 +20,5 @@ fi if ! [ -x "$(command -v clang-format)" ]; then echo 'Warning: clang-format is not installed. Skipping' >&2 else - echo "$SOURCE_FILES" | xargs clang-format -i --verbose + echo "$SOURCE_FILES" | xargs clang-format -style=file:../.clang-format -i --verbose fi From eaf0373bb299e527063a6d5e00b73795bf45317f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Omn=C3=A8s?= Date: Fri, 10 Jan 2025 10:56:40 +0100 Subject: [PATCH 101/103] 2.5b build linear problem from components (#2558) - Build the problem from imported components - Write the MPS file to ${PWD}/problem.mps - Write the solution file to ${PWD}/solution.csv --------- Co-authored-by: Vincent Payet --- src/solver/modeler/CMakeLists.txt | 4 ++ .../solver/modeler/api/linearProblem.h | 2 + .../antares/solver/modeler/api/mipSolution.h | 3 + src/solver/modeler/main.cpp | 56 +++++++++++++++++++ .../modeler/ortoolsImpl/linearProblem.h | 1 + .../solver/modeler/ortoolsImpl/mipSolution.h | 1 + .../modeler/ortoolsImpl/linearProblem.cpp | 9 +++ .../modeler/ortoolsImpl/mipSolution.cpp | 5 ++ 8 files changed, 81 insertions(+) diff --git a/src/solver/modeler/CMakeLists.txt b/src/solver/modeler/CMakeLists.txt index cb31b11fd4..da059fbe1f 100644 --- a/src/solver/modeler/CMakeLists.txt +++ b/src/solver/modeler/CMakeLists.txt @@ -22,6 +22,10 @@ target_link_libraries(modeler-lib INTERFACE Antares::loadModelerFiles Antares::modelerParameters + Antares::optim-model-filler + Antares::modeler_api + # TODO FIXME don't depend on implementations + Antares::modeler-ortools-impl ) target_link_libraries(antares-modeler diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h index 6885d81ac1..dffc7f874c 100644 --- a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h @@ -72,6 +72,8 @@ class ILinearProblem /// Solve the problem, returns a IMipSolution virtual IMipSolution* solve(bool verboseSolver) = 0; + virtual void WriteLP(const std::string& filename) = 0; + // Definition of infinity virtual double infinity() const = 0; }; diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/mipSolution.h b/src/solver/modeler/api/include/antares/solver/modeler/api/mipSolution.h index 0018718de2..4a8b7237dc 100644 --- a/src/solver/modeler/api/include/antares/solver/modeler/api/mipSolution.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/mipSolution.h @@ -21,6 +21,8 @@ #pragma once +#include +#include #include #include "mipVariable.h" @@ -51,6 +53,7 @@ class IMipSolution virtual double getObjectiveValue() const = 0; virtual double getOptimalValue(const IMipVariable* var) const = 0; virtual std::vector getOptimalValues(const std::vector& vars) const = 0; + virtual const std::map& getOptimalValues() const = 0; }; } // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/main.cpp b/src/solver/modeler/main.cpp index 2af8f38e3f..559c1f980a 100644 --- a/src/solver/modeler/main.cpp +++ b/src/solver/modeler/main.cpp @@ -19,9 +19,14 @@ * along with Antares_Simulator. If not, see . */ +#include + #include +#include #include +#include #include +#include using namespace Antares; using namespace Antares::Solver; @@ -53,6 +58,57 @@ int main(int argc, const char** argv) logs.info() << "Libraries loaded"; const auto system = LoadFiles::loadSystem(studyPath, libraries); logs.info() << "System loaded"; + + // Fillers, etc. + std::vector fillers; + // TODO memory + for (auto& [_, component]: system.Components()) + { + fillers.push_back(new Antares::Optimization::ComponentFiller(component)); + } + + Antares::Solver::Modeler::Api::LinearProblemData LP_Data; + Antares::Solver::Modeler::Api::FillContext ctx = {0, 0}; + // We force the usage of MIP solvers to check that integer variables are properly handled + // TODO determine the nature of the problem based on system.Components() + const bool isMip = true; + Antares::Solver::Modeler::OrtoolsImpl::OrtoolsLinearProblem pb(isMip, parameters.solver); + Antares::Solver::Modeler::Api::LinearProblemBuilder linear_problem_builder(fillers); + linear_problem_builder.build(pb, LP_Data, ctx); + for (auto& filler: fillers) + { + delete filler; + } + + logs.info() << "Number of variables: " << pb.variableCount(); + logs.info() << "Number of constraints: " << pb.constraintCount(); + + if (!parameters.noOutput) + { + logs.info() << "Writing problem.lp..."; + auto mps_path = std::filesystem::current_path() / "problem.lp"; + pb.WriteLP(mps_path.string()); + } + + logs.info() << "Launching resolution..."; + auto* solution = pb.solve(parameters.solverLogs); + switch (solution->getStatus()) + { + case Antares::Solver::Modeler::Api::MipStatus::OPTIMAL: + case Antares::Solver::Modeler::Api::MipStatus::FEASIBLE: + if (!parameters.noOutput) + { + logs.info() << "Writing variables..."; + std::ofstream sol_out(std::filesystem::current_path() / "solution.csv"); + for (const auto& [name, value]: solution->getOptimalValues()) + { + sol_out << name << " " << value << std::endl; + } + } + break; + default: + logs.error() << "Problem during linear optimization"; + } } catch (const LoadFiles::ErrorLoadingYaml&) { diff --git a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h index 3d69ee98e9..f4a2fed61e 100644 --- a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h +++ b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h @@ -65,6 +65,7 @@ class OrtoolsLinearProblem: public Api::ILinearProblem bool isMaximization() const override; OrtoolsMipSolution* solve(bool verboseSolver) override; + void WriteLP(const std::string& filename) override; double infinity() const override; diff --git a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipSolution.h b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipSolution.h index 0cf452c11b..f536329e36 100644 --- a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipSolution.h +++ b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipSolution.h @@ -44,6 +44,7 @@ class OrtoolsMipSolution final: public Api::IMipSolution double getOptimalValue(const Api::IMipVariable* var) const override; std::vector getOptimalValues( const std::vector& vars) const override; + const std::map& getOptimalValues() const override; private: operations_research::MPSolver::ResultStatus status_; diff --git a/src/solver/modeler/ortoolsImpl/linearProblem.cpp b/src/solver/modeler/ortoolsImpl/linearProblem.cpp index feba47dda8..20c302c9fd 100644 --- a/src/solver/modeler/ortoolsImpl/linearProblem.cpp +++ b/src/solver/modeler/ortoolsImpl/linearProblem.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -165,6 +166,14 @@ bool OrtoolsLinearProblem::isMaximization() const return objective_->maximization(); } +void OrtoolsLinearProblem::WriteLP(const std::string& filename) +{ + std::string out; + mpSolver_->ExportModelAsLpFormat(false, &out); + std::ofstream of(filename); + of << out; +} + MPSolver* OrtoolsLinearProblem::MpSolver() const { return mpSolver_; diff --git a/src/solver/modeler/ortoolsImpl/mipSolution.cpp b/src/solver/modeler/ortoolsImpl/mipSolution.cpp index 8239f9893a..b10386a1a4 100644 --- a/src/solver/modeler/ortoolsImpl/mipSolution.cpp +++ b/src/solver/modeler/ortoolsImpl/mipSolution.cpp @@ -93,4 +93,9 @@ std::vector OrtoolsMipSolution::getOptimalValues( return solution; } +const std::map& OrtoolsMipSolution::getOptimalValues() const +{ + return solution_; +} + } // namespace Antares::Solver::Modeler::OrtoolsImpl From 874612dabbfd1734694cda77f2770f8f3e8ddc95 Mon Sep 17 00:00:00 2001 From: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Date: Fri, 10 Jan 2025 14:06:50 +0100 Subject: [PATCH 102/103] Introduce accurate shave peaks hydro algorithm + tests (#2532) For now it's not integrated into antares-solver, integration is done with #2566. Co-authored-by: Florian OMNES --- src/solver/simulation/CMakeLists.txt | 12 + .../simulation/shave-peaks-by-remix-hydro.h | 29 + .../simulation/shave-peaks-by-remix-hydro.cpp | 309 +++++++ .../src/solver/simulation/CMakeLists.txt | 81 +- .../solver/simulation/test-hydro-remix.cpp | 788 ++++++++++++++++++ 5 files changed, 1183 insertions(+), 36 deletions(-) create mode 100644 src/solver/simulation/include/antares/solver/simulation/shave-peaks-by-remix-hydro.h create mode 100644 src/solver/simulation/shave-peaks-by-remix-hydro.cpp create mode 100644 src/tests/src/solver/simulation/test-hydro-remix.cpp diff --git a/src/solver/simulation/CMakeLists.txt b/src/solver/simulation/CMakeLists.txt index 17e511fac5..a110adac4f 100644 --- a/src/solver/simulation/CMakeLists.txt +++ b/src/solver/simulation/CMakeLists.txt @@ -76,6 +76,18 @@ target_link_libraries(antares-solver-simulation antares-solver-ts-generator ) +# Remix hydro algorithm +add_library(shave-peaks-by-remix-hydro) + +target_sources(shave-peaks-by-remix-hydro + PRIVATE + shave-peaks-by-remix-hydro.cpp) + +target_include_directories(shave-peaks-by-remix-hydro + PUBLIC + $) + + install(DIRECTORY include/antares DESTINATION "include" ) diff --git a/src/solver/simulation/include/antares/solver/simulation/shave-peaks-by-remix-hydro.h b/src/solver/simulation/include/antares/solver/simulation/shave-peaks-by-remix-hydro.h new file mode 100644 index 0000000000..77ffbc67e8 --- /dev/null +++ b/src/solver/simulation/include/antares/solver/simulation/shave-peaks-by-remix-hydro.h @@ -0,0 +1,29 @@ + +#pragma once + +#include + +namespace Antares::Solver::Simulation +{ + +struct RemixHydroOutput +{ + std::vector HydroGen; + std::vector UnsupE; + std::vector levels; +}; + +RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGen, + const std::vector& HydroGen, + const std::vector& UnsupE, + const std::vector& HydroPmax, + const std::vector& HydroPmin, + double init_level, + double capacity, + const std::vector& inflow, + const std::vector& overflow, + const std::vector& pump, + const std::vector& Spillage, + const std::vector& DTG_MRG); + +} // namespace Antares::Solver::Simulation diff --git a/src/solver/simulation/shave-peaks-by-remix-hydro.cpp b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp new file mode 100644 index 0000000000..99a8f2aa55 --- /dev/null +++ b/src/solver/simulation/shave-peaks-by-remix-hydro.cpp @@ -0,0 +1,309 @@ +#include "include/antares/solver/simulation/shave-peaks-by-remix-hydro.h" + +#include +#include +#include +#include + +namespace Antares::Solver::Simulation +{ + +int find_min_index(const std::vector& TotalGen, + const std::vector& OutUnsupE, + const std::vector& OutHydroGen, + const std::vector& triedBottom, + const std::vector& HydroPmax, + const std::vector& enabledHours, + double top) +{ + double min_val = top; + int min_hour = -1; + for (unsigned int h = 0; h < TotalGen.size(); ++h) + { + if (OutUnsupE[h] > 0 && OutHydroGen[h] < HydroPmax[h] && !triedBottom[h] && enabledHours[h]) + { + if (TotalGen[h] < min_val) + { + min_val = TotalGen[h]; + min_hour = h; + } + } + } + return min_hour; +} + +int find_max_index(const std::vector& TotalGen, + const std::vector& OutHydroGen, + const std::vector& triedPeak, + const std::vector& HydroPmin, + const std::vector& enabledHours, + double ref_value, + double eps) +{ + double max_val = 0; + int max_hour = -1; + for (unsigned int h = 0; h < TotalGen.size(); ++h) + { + if (OutHydroGen[h] > HydroPmin[h] && TotalGen[h] >= ref_value + eps && !triedPeak[h] + && enabledHours[h]) + { + if (TotalGen[h] > max_val) + { + max_val = TotalGen[h]; + max_hour = h; + } + } + } + return max_hour; +} + +static bool operator<=(const std::vector& a, const std::vector& b) +{ + return a.size() == b.size() + && std::ranges::all_of(std::views::iota(size_t{0}, a.size()), + [&](size_t i) { return a[i] <= b[i]; }); +} + +static bool operator<=(const std::vector& v, const double c) +{ + return std::ranges::all_of(v, [&c](const double& e) { return e <= c; }); +} + +static bool operator>=(const std::vector& v, const double c) +{ + return std::ranges::all_of(v, [&c](const double& e) { return e >= c; }); +} + +static void checkInputCorrectness(const std::vector& DispatchGen, + const std::vector& HydroGen, + const std::vector& UnsupE, + const std::vector& levels, + const std::vector& HydroPmax, + const std::vector& HydroPmin, + double initial_level, + double capacity, + const std::vector& inflows, + const std::vector& overflow, + const std::vector& pump, + const std::vector& Spillage, + const std::vector& DTG_MRG) +{ + std::string msg_prefix = "Remix hydro input : "; + + // Initial level smaller than capacity + if (initial_level > capacity) + { + throw std::invalid_argument(msg_prefix + "initial level > reservoir capacity"); + } + // Arrays sizes must be identical + std::vector sizes = {DispatchGen.size(), + HydroGen.size(), + UnsupE.size(), + levels.size(), + HydroPmax.size(), + HydroPmin.size(), + inflows.size(), + overflow.size(), + pump.size(), + Spillage.size(), + DTG_MRG.size()}; + + if (!std::ranges::all_of(sizes, [&sizes](const size_t s) { return s == sizes.front(); })) + { + throw std::invalid_argument(msg_prefix + "arrays of different sizes"); + } + + // Arrays are of size 0 + if (!DispatchGen.size()) + { + throw std::invalid_argument(msg_prefix + "all arrays of sizes 0"); + } + + // Hydro production < Pmax + if (!(HydroGen <= HydroPmax)) + { + throw std::invalid_argument(msg_prefix + + "Hydro generation not smaller than Pmax everywhere"); + } + + // Hydro production > Pmin + if (!(HydroPmin <= HydroGen)) + { + throw std::invalid_argument(msg_prefix + + "Hydro generation not greater than Pmin everywhere"); + } + + if (!(levels <= capacity) || !(levels >= 0.)) + { + throw std::invalid_argument(msg_prefix + + "levels computed from input don't respect reservoir bounds"); + } +} + +RemixHydroOutput shavePeaksByRemixingHydro(const std::vector& DispatchGen, + const std::vector& HydroGen, + const std::vector& UnsupE, + const std::vector& HydroPmax, + const std::vector& HydroPmin, + double initial_level, + double capa, + const std::vector& inflows, + const std::vector& overflow, + const std::vector& pump, + const std::vector& Spillage, + const std::vector& DTG_MRG) +{ + std::vector levels(DispatchGen.size()); + if (!levels.empty()) + { + levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - HydroGen[0]; + for (size_t h = 1; h < levels.size(); ++h) + { + levels[h] = levels[h - 1] + inflows[h] - overflow[h] + pump[h] - HydroGen[h]; + } + } + + checkInputCorrectness(DispatchGen, + HydroGen, + UnsupE, + levels, + HydroPmax, + HydroPmin, + initial_level, + capa, + inflows, + overflow, + pump, + Spillage, + DTG_MRG); + + std::vector OutHydroGen = HydroGen; + std::vector OutUnsupE = UnsupE; + + int loop = 1000; + double eps = 1e-3; + double top = *std::max_element(DispatchGen.begin(), DispatchGen.end()) + + *std::max_element(HydroGen.begin(), HydroGen.end()) + + *std::max_element(UnsupE.begin(), UnsupE.end()) + 1; + + std::vector enabledHours(DispatchGen.size(), false); + for (unsigned int h = 0; h < enabledHours.size(); h++) + { + if (Spillage[h] + DTG_MRG[h] == 0. && HydroGen[h] + UnsupE[h] > 0.) + { + enabledHours[h] = true; + } + } + + std::vector TotalGen(DispatchGen.size()); + std::transform(DispatchGen.begin(), + DispatchGen.end(), + HydroGen.begin(), + TotalGen.begin(), + std::plus<>()); + + while (loop-- > 0) + { + std::vector triedBottom(DispatchGen.size(), false); + double delta = 0; + + while (true) + { + int hourBottom = find_min_index(TotalGen, + OutUnsupE, + OutHydroGen, + triedBottom, + HydroPmax, + enabledHours, + top); + if (hourBottom == -1) + { + break; + } + + std::vector triedPeak(DispatchGen.size(), false); + while (true) + { + int hourPeak = find_max_index(TotalGen, + OutHydroGen, + triedPeak, + HydroPmin, + enabledHours, + TotalGen[hourBottom], + eps); + if (hourPeak == -1) + { + break; + } + + std::vector intermediate_level(levels.begin() + + std::min(hourBottom, hourPeak), + levels.begin() + + std::max(hourBottom, hourPeak)); + double max_pic, max_creux; + if (hourBottom < hourPeak) + { + max_pic = capa; + max_creux = *std::min_element(intermediate_level.begin(), + intermediate_level.end()); + } + else + { + max_pic = capa + - *std::max_element(intermediate_level.begin(), + intermediate_level.end()); + max_creux = capa; + } + + max_pic = std::min(OutHydroGen[hourPeak] - HydroPmin[hourPeak], max_pic); + max_creux = std::min({HydroPmax[hourBottom] - OutHydroGen[hourBottom], + OutUnsupE[hourBottom], + max_creux}); + + double dif_pic_creux = std::max(TotalGen[hourPeak] - TotalGen[hourBottom], 0.); + + delta = std::max(std::min({max_pic, max_creux, dif_pic_creux / 2.}), 0.); + + if (delta > 0) + { + OutHydroGen[hourPeak] -= delta; + OutHydroGen[hourBottom] += delta; + OutUnsupE[hourPeak] = HydroGen[hourPeak] + UnsupE[hourPeak] + - OutHydroGen[hourPeak]; + OutUnsupE[hourBottom] = HydroGen[hourBottom] + UnsupE[hourBottom] + - OutHydroGen[hourBottom]; + break; + } + else + { + triedPeak[hourPeak] = true; + } + } + + if (delta > 0) + { + break; + } + triedBottom[hourBottom] = true; + } + + if (delta == 0) + { + break; + } + + std::transform(DispatchGen.begin(), + DispatchGen.end(), + OutHydroGen.begin(), + TotalGen.begin(), + std::plus<>()); + levels[0] = initial_level + inflows[0] - overflow[0] + pump[0] - OutHydroGen[0]; + for (size_t h = 1; h < levels.size(); ++h) + { + levels[h] = levels[h - 1] + inflows[h] - overflow[h] + pump[h] - OutHydroGen[h]; + } + } + return {OutHydroGen, OutUnsupE, levels}; +} + +} // End namespace Antares::Solver::Simulation diff --git a/src/tests/src/solver/simulation/CMakeLists.txt b/src/tests/src/solver/simulation/CMakeLists.txt index 76d67765f7..e6ca5e7900 100644 --- a/src/tests/src/solver/simulation/CMakeLists.txt +++ b/src/tests/src/solver/simulation/CMakeLists.txt @@ -6,57 +6,66 @@ set(src_solver_hydro "${CMAKE_SOURCE_DIR}/solver/hydro") set(src_libs_antares_study "${CMAKE_SOURCE_DIR}/libs/antares/study") set(SRC_TS_NUMBERS - # For confort in IDE, but not necessary - ${src_solver_simulation}/include/antares/solver/simulation/timeseries-numbers.h - - # Necessary cpp files - ${src_solver_simulation}/timeseries-numbers.cpp - ${src_solver_simulation}/include/antares/solver/simulation/ITimeSeriesNumbersWriter.h) + # For confort in IDE, but not necessary + ${src_solver_simulation}/include/antares/solver/simulation/timeseries-numbers.h + # Necessary cpp files + ${src_solver_simulation}/timeseries-numbers.cpp + ${src_solver_simulation}/include/antares/solver/simulation/ITimeSeriesNumbersWriter.h) add_boost_test(tests-ts-numbers - SRC tests-ts-numbers.cpp ${SRC_TS_NUMBERS} - INCLUDE - "${src_solver_simulation}" - "${src_libs_antares_study}" - LIBS - Antares::utils - model_antares - antares-solver-simulation - antares-solver-ts-generator) + SRC tests-ts-numbers.cpp ${SRC_TS_NUMBERS} + INCLUDE + "${src_solver_simulation}" + "${src_libs_antares_study}" + LIBS + Antares::utils + model_antares + antares-solver-simulation + antares-solver-ts-generator) # =================================== # Tests on area's store-timeseries-number # =================================== add_boost_test(test-store-timeseries-number - SRC test-store-timeseries-number.cpp - LIBS - test_utils_unit - antares-solver-simulation - Antares::study - Antares::result_writer) + SRC test-store-timeseries-number.cpp + LIBS + test_utils_unit + antares-solver-simulation + Antares::study + Antares::result_writer) # =================================== # Tests on time series # =================================== add_boost_test(test-time_series - SRC test-time_series.cpp - LIBS - test_utils_unit - antares-solver-simulation - Antares::study) + SRC test-time_series.cpp + LIBS + test_utils_unit + antares-solver-simulation + Antares::study) # =================================== # Tests on hydro final reservoir level functions # =================================== add_boost_test(test-hydro_final - SRC - test-hydro-final-reservoir-level-functions.cpp - INCLUDE - "${src_solver_simulation}" - "${src_libs_antares_study}" - "${src_solver_hydro}" - LIBS - Antares::study - antares-solver-simulation - Antares::array) + SRC + test-hydro-final-reservoir-level-functions.cpp + INCLUDE + "${src_solver_simulation}" + "${src_libs_antares_study}" + "${src_solver_hydro}" + LIBS + Antares::study + antares-solver-simulation + Antares::array) + +# =================================== +# Tests on hydro remix algorithm +# =================================== +add_boost_test(tests-on-hydro-remix + SRC + test-hydro-remix.cpp + LIBS + shave-peaks-by-remix-hydro + test_utils_unit) \ No newline at end of file diff --git a/src/tests/src/solver/simulation/test-hydro-remix.cpp b/src/tests/src/solver/simulation/test-hydro-remix.cpp new file mode 100644 index 0000000000..ffcef67007 --- /dev/null +++ b/src/tests/src/solver/simulation/test-hydro-remix.cpp @@ -0,0 +1,788 @@ +#define BOOST_TEST_MODULE hydro remix + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include + +#include + +#include "antares/solver/simulation/shave-peaks-by-remix-hydro.h" + +using namespace Antares::Solver::Simulation; + +template +struct InputFixture +{ + InputFixture() + { + TotalGenNoHydro.assign(size, 0.); + HydroGen.assign(size, 0.); + UnsupE.assign(size, 0.); + HydroPmax.assign(size, std::numeric_limits::max()); + HydroPmin.assign(size, 0.); + inflows.assign(size, 0.); + ovf.assign(size, 0.); + pump.assign(size, 0.); + Spillage.assign(size, 0.); + DTG_MRG.assign(size, 0.); + } + + std::vector TotalGenNoHydro, HydroGen, UnsupE, HydroPmax, HydroPmin, inflows, ovf, pump, + Spillage, DTG_MRG; + double init_level = 0.; + double capacity = std::numeric_limits::max(); +}; + +BOOST_FIXTURE_TEST_CASE(input_vectors_of_different_sizes__exception_raised, InputFixture<0>) +{ + HydroGen = {0., 0.}; + + BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : arrays of different sizes")); +} + +BOOST_FIXTURE_TEST_CASE(input_init_level_exceeds_capacity__exception_raised, InputFixture<0>) +{ + HydroGen = {0., 0.}; + init_level = 2.; + capacity = 1.; + + BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : initial level > reservoir capacity")); +} + +BOOST_FIXTURE_TEST_CASE(all_input_arrays_of_size_0__exception_raised, InputFixture<0>) +{ + init_level = 0.; + capacity = 1.; + + BOOST_CHECK_EXCEPTION(shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : all arrays of sizes 0")); +} + +BOOST_FIXTURE_TEST_CASE(Hydro_gen_not_smaller_than_pmax__exception_raised, InputFixture<5>) +{ + HydroGen = {1., 2., 3., 4., 5.}; + HydroPmax = {2., 2., 2., 4., 5.}; + init_level = 0.; + capacity = 1.; + + BOOST_CHECK_EXCEPTION( + shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : Hydro generation not smaller than Pmax everywhere")); +} + +BOOST_FIXTURE_TEST_CASE(Hydro_gen_not_greater_than_pmin__exception_raised, InputFixture<5>) +{ + HydroGen = {1., 2., 3., 4., 5.}; + HydroPmin = {0., 0., 4., 0., 0.}; + init_level = 0.; + capacity = 1.; + + BOOST_CHECK_EXCEPTION( + shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), + std::invalid_argument, + checkMessage("Remix hydro input : Hydro generation not greater than Pmin everywhere")); +} + +BOOST_FIXTURE_TEST_CASE(input_is_acceptable__no_exception_raised, InputFixture<1>) +{ + init_level = 0.; + capacity = 1.; + + BOOST_CHECK_NO_THROW(shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG)); +} + +BOOST_FIXTURE_TEST_CASE( + hydro_increases_and_pmax_40mwh___Hydro_gen_is_flattened_to_mean_Hydro_gen_20mwh, + InputFixture<5>) +{ + std::ranges::fill(HydroPmax, 40.); + std::ranges::fill(TotalGenNoHydro, 100.); + HydroGen = {0., 10., 20., 30., 40.}; // we have Pmin <= HydroGen <= Pmax + UnsupE = {80.0, 60., 40., 20., 0.}; + init_level = 500.; + capacity = 1000.; + + auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; + // UnsupE such as TotalGenNoHydro + HydroGen + UnsupE remains flat + std::vector expected_UnsupE = {60., 50., 40., 30., 20.}; + BOOST_CHECK(OutHydroGen == expected_HydroGen); + BOOST_CHECK(OutUnsupE == expected_UnsupE); +} + +BOOST_FIXTURE_TEST_CASE(Pmax_does_not_impact_results_when_greater_than_40mwh, InputFixture<5>) +{ + std::ranges::fill(HydroPmax, 50.); + std::ranges::fill(TotalGenNoHydro, 100.); + HydroGen = {0., 10., 20., 30., 40.}; + UnsupE = {80.0, 60., 40., 20., 0.}; + init_level = 500.; + capacity = 1000.; + + auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; + // UnsupE such as TotalGenNoHydro + HydroGen + UnsupE remains constant at each hour + std::vector expected_UnsupE = {60., 50., 40., 30., 20.}; + BOOST_CHECK(OutHydroGen == expected_HydroGen); + BOOST_CHECK(OutUnsupE == expected_UnsupE); +} + +BOOST_FIXTURE_TEST_CASE( + hydro_decreases_and_pmax_40mwh___Hydro_gen_is_flattened_to_mean_Hydro_gen_20mwh, + InputFixture<5>) +{ + std::ranges::fill(HydroPmax, 40.); + std::ranges::fill(TotalGenNoHydro, 100.); + HydroGen = {40., 30., 20., 10., 0.}; + UnsupE = {0., 20., 40., 60., 80.}; + init_level = 500.; + capacity = 1000.; + + auto [OutHydroGen, OutUnsupE, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen = {20., 20., 20., 20., 20.}; + // UnsupE such as TotalGenNoHydro + HydroGen + UnsupE remains constant at each hour + std::vector expected_UnsupE = {20., 30., 40., 50., 60.}; + BOOST_CHECK(OutHydroGen == expected_HydroGen); + BOOST_CHECK(OutUnsupE == expected_UnsupE); +} + +BOOST_FIXTURE_TEST_CASE(influence_of_pmax, InputFixture<5>, *boost::unit_test::tolerance(0.01)) +{ + // TotalGenNoHydro decreases + TotalGenNoHydro = {100., 80., 60., 40., 20.}; + + // HydroGen is flat and must respect HydroGen <= Pmax everywhere + HydroGen = {20., 20., 20., 20., 20.}; + UnsupE = {50., 50., 50., 50., 50.}; + init_level = 500.; + capacity = 1000.; + + // 1. Algorithm tends to flatten TotalGenNoHydro + HydroGen, so it would require HydroGen to + // increase. Proof : + auto [OutHydroGen_1, new_D1, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen_1 = {0., 0., 13.33, 33.33, 53.33}; + BOOST_TEST(OutHydroGen_1 == expected_HydroGen_1, boost::test_tools::per_element()); + + // 2. But HydroGen is limited by HydroPmax. So Algo does nothing in the end. + // Proof : + HydroPmax = {20., 20., 20., 20., 20.}; + auto [OutHydroGen_2, OutUnsupE_2, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen_2 = {20., 20., 20., 20., 20.}; + std::vector expected_UnsupE_2 = {50., 50., 50., 50., 50.}; + BOOST_CHECK(OutHydroGen_2 == expected_HydroGen_2); + BOOST_CHECK(OutUnsupE_2 == expected_UnsupE_2); +} + +BOOST_FIXTURE_TEST_CASE(influence_of_pmin, InputFixture<5>, *boost::unit_test::tolerance(0.01)) +{ + // TotalGenNoHydro decreases + TotalGenNoHydro = {100., 80., 60., 40., 20.}; + + // HydroGen is flat and must respect Pmin <= HydroGen <= Pmax everywhere + HydroGen = {20., 20., 20., 20., 20.}; + UnsupE = {50., 50., 50., 50., 50.}; + init_level = 500.; + capacity = 1000.; + + // 1. Algorithm tends to flatten TotalGenNoHydro + HydroGen, so it would require HydroGen to + // increase. + auto [OutHydroGen_1, new_D1, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + std::vector expected_HydroGen_1 = {0., 0., 13.33, 33.33, 53.33}; + BOOST_TEST(OutHydroGen_1 == expected_HydroGen_1, boost::test_tools::per_element()); + + // 2. But HydroGen is low bounded by HydroPmin. So Algo does nothing in the end. + HydroPmin = {20., 20., 20., 20., 20.}; + auto [OutHydroGen_2, OutUnsupE_2, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen_2 = {20., 20., 20., 20., 20.}; + std::vector expected_UnsupE_2 = {50., 50., 50., 50., 50.}; + BOOST_CHECK(OutHydroGen_2 == expected_HydroGen_2); + BOOST_CHECK(OutUnsupE_2 == expected_UnsupE_2); +} + +BOOST_FIXTURE_TEST_CASE(Hydro_gen_is_already_flat___remix_is_useless__level_easily_computed, + InputFixture<5>) +{ + init_level = 500.; + std::ranges::fill(ovf, 25.); // Cause levels to decrease + std::ranges::fill(HydroGen, 20.); // Cause levels to decrease + std::ranges::fill(inflows, 15.); // Cause levels to increase + std::ranges::fill(pump, 10.); // Cause levels to increase + + auto [OutHydroGen, OutUnsupE, levels] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_levels = {480., 460., 440., 420., 400.}; + BOOST_TEST(levels == expected_levels, boost::test_tools::per_element()); +} + +BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_over_capacity___exception_raised, InputFixture<5>) +{ + init_level = 500.; + capacity = 550.; + std::ranges::fill(ovf, 15); // Cause levels to decrease + std::ranges::fill(HydroGen, 10); // Cause levels to decrease + std::ranges::fill(inflows, 25); // Cause levels to increase + std::ranges::fill(pump, 20); // Cause levels to increase + + BOOST_CHECK_EXCEPTION( + shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), + std::invalid_argument, + checkMessage( + "Remix hydro input : levels computed from input don't respect reservoir bounds")); +} + +BOOST_FIXTURE_TEST_CASE(input_leads_to_levels_less_than_zero___exception_raised, InputFixture<5>) +{ + init_level = 50.; + std::ranges::fill(ovf, 30); // Cause levels to decrease + std::ranges::fill(HydroGen, 10); // Cause levels to decrease + std::ranges::fill(inflows, 5); // Cause levels to increase + std::ranges::fill(pump, 10); // Cause levels to increase + + BOOST_CHECK_EXCEPTION( + shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG), + std::invalid_argument, + checkMessage( + "Remix hydro input : levels computed from input don't respect reservoir bounds")); +} + +BOOST_FIXTURE_TEST_CASE(influence_of_capacity_on_algorithm___case_where_no_influence, + InputFixture<10>, + *boost::unit_test::tolerance(0.001)) +{ + std::ranges::fill(UnsupE, 20); // Not important for this test + + // HydroGen oscillates between 10 and 20 (new HydroGen will be flattened to 15 everywhere) + HydroGen = {10., 20., 10., 20., 10., 20., 10., 20., 10., 20.}; + // First inflows > HydroGen, then inflows < HydroGen. Consequence : levels first increase, then + // decrease. + inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; + init_level = 100.; + // HydroGen and inflows result in : input_levels = {115, 120, 135, 140, 155, 140, 135, 120, 115, + // 100} + // Note that : sup(input_levels) = 155 + + // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is + // flat) + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // HydroGen is flat and is 15. (means of initial HydroGen) + std::vector expected_HydroGen(10, 15.); + // Levels associated to new HydroGen are such as sup(L) = 150. < sup(input_levels) = 155 + std::vector expected_L = {110., 120., 130., 140., 150., 140., 130., 120., 110., 100.}; + BOOST_TEST(OutHydroGen == expected_HydroGen, boost::test_tools::per_element()); + BOOST_TEST(L == expected_L, boost::test_tools::per_element()); + + // Case 2 : now, if we lower capacity to sup(input_levels) = 155, we should + // have HydroGen and L identical to previously : this value of capacity should + // not have an influence on HydroGen and levels as results of the algorithm. + capacity = 155.; + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + BOOST_TEST(OutHydroGen_2 == expected_HydroGen, boost::test_tools::per_element()); + BOOST_TEST(L2 == expected_L, boost::test_tools::per_element()); +} + +BOOST_FIXTURE_TEST_CASE(lowering_capacity_too_low_leads_to_suboptimal_solution_for_GplusH, + InputFixture<10>, + *boost::unit_test::tolerance(0.001)) +{ + std::ranges::fill(UnsupE, 20); // Not important for this test + + // HydroGen oscillates between 10 and 20 (new HydroGen will be flattened to 15 everywhere) + HydroGen = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; + // First inflows > HydroGen, then inflows < HydroGen. Consequence : levels first increase, then + // decrease. + inflows = {25., 25., 25., 25., 25., 5., 5., 5., 5., 5.}; + init_level = 100.; + // HydroGen and inflows lead to have : + // input_levels = {105, 120, 125, 140, 145, 140, 125, 120, 105,100} + // Note sup(input_levels) = 145 + + // Case 1 : capacity relaxed (infinite by default) ==> leads to optimal solution (HydroGen is + // flat) + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // HydroGen is flat and is 15. (means of initial HydroGen) + std::vector expected_HydroGen(10, 15.); + // Levels associated to new HydroGen are such as sup(L) = 150. > sup(input_levels) = 145 + std::vector expected_L = {110., 120., 130., 140., 150., 140., 130., 120., 110., 100.}; + BOOST_TEST(OutHydroGen == expected_HydroGen, boost::test_tools::per_element()); + BOOST_TEST(L == expected_L, boost::test_tools::per_element()); + + // Case 2 : we lower capacity to sup(input_levels) = 145. + // This makes input acceptable for algo : levels computed from input have an + // up bound <= capacity + // But this time levels can not increase up to sup(L) = 150., as it would if capacity + // was infinite. Therefore, solution found is suboptimal : we expect to get an + // output HydroGen flat by interval, not flat on the whole domain. + capacity = 145.; + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // OutHydroGen_2 is flat by interval + std::vector expected_HydroGen_2 = {16., 16., 16., 16., 16., 14., 14., 14., 14., 14.}; + BOOST_TEST(OutHydroGen_2 == expected_HydroGen_2, boost::test_tools::per_element()); +} + +BOOST_FIXTURE_TEST_CASE(lowering_initial_level_too_low_leads_to_suboptimal_solution_for_GplusH, + InputFixture<10>, + *boost::unit_test::tolerance(0.001)) +{ + std::ranges::fill(UnsupE, 20); // Not important for this test + + // HydroGen oscillates between 20 and 30 (new HydroGen will be flattened to 25 everywhere) + HydroGen = {20., 30., 20., 30., 20., 30., 20., 30., 20., 30.}; + // First inflows < HydroGen, then inflows > HydroGen. Consequence : levels first decrease, then + // increase. + inflows = {5., 5., 5., 5., 5., 45., 45., 45., 45., 45.}; + capacity = std::numeric_limits::max(); + init_level = 100.; + // HydroGen and inflows result in : input_levels = {85, 60, 45, 20, 5, 20, 45, 60, 85, 100} + // Note : inf(input_levels) = 5 + + // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) + // are acceptable for algorithm (input levels >= 0.), and running algorithm leads to optimal + // solution (OutHydroGen is flat) + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // HydroGen is flat and is 25. (means of initial HydroGen) + std::vector expected_HydroGen(10, 25.); + // Levels associated to new HydroGen are such as inf(L) = 0. > inf(input_levels) = 5 + std::vector expected_L = {80., 60., 40., 20., 0., 20., 40., 60., 80., 100.}; + BOOST_TEST(OutHydroGen == expected_HydroGen, boost::test_tools::per_element()); + BOOST_TEST(L == expected_L, boost::test_tools::per_element()); + + // Case 2 : we lower initial level. Input data are still acceptable + // for algorithm (despite the new init level), algorithm will have to take the levels lower + // bound (0.) into account. As the levels change, the solution OutHydroGen will be suboptimal, + // that is flat by interval (not flat on the whole domain). + init_level = 95.; + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // OutHydroGen_2 is flat by interval + std::vector expected_HydroGen_2 = {24., 24., 24., 24., 24., 26., 26., 26., 26., 26.}; + BOOST_TEST(OutHydroGen_2 == expected_HydroGen_2, boost::test_tools::per_element()); +} + +BOOST_FIXTURE_TEST_CASE(influence_of_initial_level_on_algorithm___case_where_no_influence, + InputFixture<10>, + *boost::unit_test::tolerance(0.001)) +{ + std::ranges::fill(UnsupE, 20); // Not important for this test + + // HydroGen oscillates between 10 and 20 (new HydroGen will be flattened to 15 everywhere) + HydroGen = {20., 10., 20., 10., 20., 10., 20., 10., 20., 10.}; + // First inflows < HydroGen, then inflows > HydroGen. Consequence : levels first decrease, then + // increase. + inflows = {5., 5., 5., 5., 5., 25., 25., 25., 25., 25.}; + init_level = 100.; + // HydroGen and inflows are such as inf(input_levels) = 45 + + // Case 1 : init level (== 100) is high enough so that input levels (computed from input data) + // are acceptable by algorithm, and levels computed by algorithm (output) are optimal, that + // is computed from a optimal (that is flat) OutHydroGen. + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // HydroGen is flat and is 15. (means of initial HydroGen) + std::vector expected_HydroGen(10, 15.); + // Levels associated to new HydroGen are such as inf(L) = 50 > inf(input_levels) = 45 + std::vector expected_L = {90., 80., 70., 60., 50., 60., 70., 80., 90., 100.}; + BOOST_TEST(OutHydroGen == expected_HydroGen, boost::test_tools::per_element()); + BOOST_TEST(L == expected_L, boost::test_tools::per_element()); + + // Case 2 : now we lower initial level down to 55. + // In this way, input data is still acceptable for algorithm + // and algorithm won't have to take the levels lower bound (0.) into account. + // The solution OutHydroGen will be optimal, that is flat by interval. + init_level = 55.; + auto [OutHydroGen_2, OutUnsupE_2, L2] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + // OutHydroGen_2 is flat (and optimal) + std::vector expected_HydroGen_2(10, 15.); + BOOST_TEST(OutHydroGen_2 == expected_HydroGen_2, boost::test_tools::per_element()); +} + +BOOST_FIXTURE_TEST_CASE(spillage_positive_at_hour_0___no_change_at_this_hour, InputFixture<5>) +{ + std::ranges::fill(TotalGenNoHydro, 100.); + HydroGen = {40., 30., 20., 10., 0.}; + UnsupE = {0., 20., 40., 60., 80.}; + init_level = 500.; + capacity = 1000.; + // At this stage, DTG_MRG is filled with zeros. Running the algorithm would flatten + // HydroGen to 20 everywhere : HydroGen = {20, 20, 20, 20, 20} + // But : + Spillage[0] = 1.; + // Now, we expect no change for HydroGen at hour 0 + auto [OutHydroGen, __, _] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen = {40., 15., 15., 15., 15.}; + BOOST_CHECK(OutHydroGen == expected_HydroGen); +} + +BOOST_FIXTURE_TEST_CASE(DTG_MRG_positive_on_hour_4___no_change_at_this_hour, InputFixture<5>) +{ + std::ranges::fill(TotalGenNoHydro, 100.); + HydroGen = {40., 30., 20., 10., 0.}; + UnsupE = {0., 20., 40., 60., 80.}; + init_level = 500.; + capacity = 1000.; + // At this stage, DTG_MRG is filled with zeros. Running the algorithm would flatten + // HydroGen to 20 everywhere : HydroGen = {20, 20, 20, 20, 20} + // But : + DTG_MRG[4] = 1.; + // Now, we expect no change for HydroGen at hour 4 + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + + std::vector expected_HydroGen = {25., 25., 25., 25., 0.}; + BOOST_CHECK(OutHydroGen == expected_HydroGen); +} + +BOOST_FIXTURE_TEST_CASE(comparison_of_results_with_python_algo, + InputFixture<20>, + *boost::unit_test::tolerance(0.01)) +{ + std::vector load = {46, 81, 89, 42, 69, 55, 88, 46, 84, 94, + 66, 93, 68, 39, 91, 89, 94, 93, 91, 38}; + HydroGen = {10, 40, 36, 8, 13, 33, 9, 0, 24, 18, 5, 47, 29, 6, 7, 54, 49, 11, 63, 21}; + UnsupE = {34, 32, 33, 23, 9, 8, 20, 40, 30, 3, 50, 27, 12, 1, 35, 31, 2, 58, 20, 4}; + // Computing total generation without hydro generation + TotalGenNoHydro = load; + std::ranges::transform(TotalGenNoHydro, + HydroGen, + TotalGenNoHydro.begin(), + std::minus()); + std::ranges::transform(TotalGenNoHydro, UnsupE, TotalGenNoHydro.begin(), std::minus()); + + HydroPmax = {43, 48, 36, 43, 13, 44, 13, 31, 49, 35, 47, 47, 37, 41, 21, 54, 49, 28, 63, 49}; + HydroPmin = {10, 22, 17, 8, 7, 15, 8, 0, 9, 2, 5, 18, 22, 6, 4, 11, 1, 0, 23, 6}; + init_level = 13.6; + capacity = 126.; + inflows = {37, 27, 41, 36, 7, 14, 38, 23, 17, 35, 20, 24, 17, 46, 1, 10, 10, 12, 46, 30}; + + auto [OutHydroGen, OutUnsupE, L] = shavePeaksByRemixingHydro(TotalGenNoHydro, + HydroGen, + UnsupE, + HydroPmax, + HydroPmin, + init_level, + capacity, + inflows, + ovf, + pump, + Spillage, + DTG_MRG); + std::vector expected_HydroGen = {42.3, 35.3, 27., 31., 7., 33., 8., + 31., 19.55, 2., 38.55, 30.55, 22.55, 7., + 4., 45.55, 6.55, 25.55, 41.55, 25.}; + + BOOST_TEST(OutHydroGen == expected_HydroGen, boost::test_tools::per_element()); +} + +// Possible simplifications / clarifications of the algorithm itself : +// - the algo is flat, it's C (not C++), it should be divided in a small number of steps +// - max_pic is an up hydro production margin (Hydro_gen_up_mrg) +// - max_creux is a down hydro production margin (Hydro_gen_down_mrg) +// - an iteration updates OutHydroGen : it's its main job. +// So OutUnsupE could be updated from OutHydroGen at the end of an iteration, separately. +// - they are 3 while loops. 2 loops should be enough (the iteration loop and +// another one simply updating OutHydroGen and OutUnsupE) From bd4968d2923951e6389f4f77aeba822b6de6403d Mon Sep 17 00:00:00 2001 From: guilpier-code <62292552+guilpier-code@users.noreply.github.com> Date: Mon, 13 Jan 2025 17:52:12 +0100 Subject: [PATCH 103/103] Accurate shave peaks algorithm integration (#2566) Co-authored-by: Florian OMNES --- src/libs/antares/study/fwd.cpp | 6 + .../antares/study/include/antares/study/fwd.h | 1 + src/packaging/CMakeLists.txt | 1 + src/solver/simulation/CMakeLists.txt | 24 ++-- src/solver/simulation/common-hydro-remix.cpp | 118 ++++++++++++++++-- 5 files changed, 130 insertions(+), 20 deletions(-) diff --git a/src/libs/antares/study/fwd.cpp b/src/libs/antares/study/fwd.cpp index 100a4b127e..0b5f8c07d6 100644 --- a/src/libs/antares/study/fwd.cpp +++ b/src/libs/antares/study/fwd.cpp @@ -221,6 +221,10 @@ SheddingPolicy StringToSheddingPolicy(const AnyString& text) { return shpShavePeaks; } + if (s == "accurate shave peaks") + { + return shpAccurateShavePeaks; + } if (s == "minimize duration") { return shpMinimizeDuration; @@ -235,6 +239,8 @@ const char* SheddingPolicyToCString(SheddingPolicy strategy) { case shpShavePeaks: return "shave peaks"; + case shpAccurateShavePeaks: + return "accurate shave peaks"; case shpMinimizeDuration: return "minimize duration"; case shpUnknown: diff --git a/src/libs/antares/study/include/antares/study/fwd.h b/src/libs/antares/study/include/antares/study/fwd.h index 6fa2819aca..b615e821b6 100644 --- a/src/libs/antares/study/include/antares/study/fwd.h +++ b/src/libs/antares/study/include/antares/study/fwd.h @@ -434,6 +434,7 @@ PowerFluctuations StringToPowerFluctuations(const AnyString& text); enum SheddingPolicy { shpShavePeaks = 0, + shpAccurateShavePeaks, shpMinimizeDuration, shpUnknown, }; diff --git a/src/packaging/CMakeLists.txt b/src/packaging/CMakeLists.txt index ea0e5c1836..28889b6b10 100644 --- a/src/packaging/CMakeLists.txt +++ b/src/packaging/CMakeLists.txt @@ -50,6 +50,7 @@ set(TARGET_LIBS #No alias misc model_antares antares-solver-ts-generator + shave-peaks-by-remix-hydro # lps : nothing diff --git a/src/solver/simulation/CMakeLists.txt b/src/solver/simulation/CMakeLists.txt index a110adac4f..e097bece6a 100644 --- a/src/solver/simulation/CMakeLists.txt +++ b/src/solver/simulation/CMakeLists.txt @@ -1,3 +1,14 @@ +# Remix hydro algorithm +add_library(shave-peaks-by-remix-hydro) + +target_sources(shave-peaks-by-remix-hydro + PRIVATE + shave-peaks-by-remix-hydro.cpp) + +target_include_directories(shave-peaks-by-remix-hydro + PUBLIC + $) + # # Simulation # @@ -74,20 +85,9 @@ target_link_libraries(antares-solver-simulation antares-solver-hydro antares-solver-variable antares-solver-ts-generator + shave-peaks-by-remix-hydro ) -# Remix hydro algorithm -add_library(shave-peaks-by-remix-hydro) - -target_sources(shave-peaks-by-remix-hydro - PRIVATE - shave-peaks-by-remix-hydro.cpp) - -target_include_directories(shave-peaks-by-remix-hydro - PUBLIC - $) - - install(DIRECTORY include/antares DESTINATION "include" ) diff --git a/src/solver/simulation/common-hydro-remix.cpp b/src/solver/simulation/common-hydro-remix.cpp index be94eba549..13f8e5d49d 100644 --- a/src/solver/simulation/common-hydro-remix.cpp +++ b/src/solver/simulation/common-hydro-remix.cpp @@ -24,29 +24,33 @@ #include #include -#include #include #include #include "antares/solver/simulation/common-eco-adq.h" +#include "antares/solver/simulation/shave-peaks-by-remix-hydro.h" #include "antares/study/simulation.h" #define EPSILON 1e-6 namespace Antares::Solver::Simulation { + +const unsigned int HOURS_IN_WEEK = 168; +const unsigned int HOURS_IN_DAY = 24; + template static bool Remix(const Data::AreaList& areas, PROBLEME_HEBDO& problem, uint numSpace, uint hourInYear) { - double HE[168]; + double HE[HOURS_IN_WEEK]; - double DE[168]; + double DE[HOURS_IN_WEEK]; - bool remix[168]; + bool remix[HOURS_IN_WEEK]; - double G[168]; + double G[HOURS_IN_WEEK]; bool status = true; @@ -68,7 +72,7 @@ static bool Remix(const Data::AreaList& areas, uint endHour = step; uint offset = 0; - for (; offset < 168; offset += step, endHour += step) + for (; offset < HOURS_IN_WEEK; offset += step, endHour += step) { { double WD = 0.; @@ -220,6 +224,92 @@ static bool Remix(const Data::AreaList& areas, return status; } +std::vector computeTotalGenWithoutHydro(const std::vector& load, + const std::vector& unsupE, + const std::vector& hydroGen) +{ + // Can be computed (for any hour) as : load - unsupplied energy - hydro + std::vector to_return = load; + for (size_t i = 0; i < to_return.size(); ++i) + { + to_return[i] -= unsupE[i] + hydroGen[i]; + } + return to_return; +} + +std::vector extractLoadForCurrentWeek(const Data::Area& area, + const unsigned int year, + const unsigned int firstHourOfWeek) +{ + std::vector load_to_return(HOURS_IN_WEEK, 0.); + for (int h = 0; h < HOURS_IN_WEEK; h++) + { + load_to_return[h] = area.load.series.getColumn(year)[h + firstHourOfWeek]; + } + return load_to_return; +} + +std::vector extractHydroPmin(const Data::Area& area, + const unsigned int year, + const unsigned int firstHourOfWeek) +{ + // area->hydro.series->mingen.timeSeries + std::vector hydroPmin(HOURS_IN_WEEK, 0.); + for (int h = 0; h < HOURS_IN_WEEK; h++) + { + hydroPmin[h] = area.hydro.series->mingen.getColumn(year)[h + firstHourOfWeek]; + } + return hydroPmin; +} + +static void RunAccurateShavePeaks(const Data::AreaList& areas, + PROBLEME_HEBDO& problem, + uint numSpace, + uint firstHourOfWeek) +{ + areas.each( + [&](const Data::Area& area) + { + auto& weeklyResults = problem.ResultatsHoraires[area.index]; + + const auto load = extractLoadForCurrentWeek(area, problem.year, firstHourOfWeek); + auto& unsupE = weeklyResults.ValeursHorairesDeDefaillancePositive; + auto& hydroGen = weeklyResults.TurbinageHoraire; + auto& levels = weeklyResults.niveauxHoraires; + const auto DispatchGen = computeTotalGenWithoutHydro(load, unsupE, hydroGen); + const auto& hydroPmax = problem.CaracteristiquesHydrauliques[area.index] + .ContrainteDePmaxHydrauliqueHoraire; + const auto hydroPmin = extractHydroPmin(area, problem.year, firstHourOfWeek); + const double initLevel = problem.CaracteristiquesHydrauliques[area.index] + .NiveauInitialReservoir; + const double capacity = area.hydro.reservoirCapacity; + const auto& inflows = problem.CaracteristiquesHydrauliques[area.index] + .ApportNaturelHoraire; + const auto& ovf = weeklyResults.debordementsHoraires; + const auto& pump = weeklyResults.PompageHoraire; + const auto& spillage = weeklyResults.ValeursHorairesDeDefaillanceNegative; + + const auto& dtgMrgArray = area.scratchpad[numSpace].dispatchableGenerationMargin; + const std::vector dtgMrg(dtgMrgArray, dtgMrgArray + HOURS_IN_WEEK); + + auto [H, U, L] = shavePeaksByRemixingHydro(DispatchGen, + hydroGen, + unsupE, + hydroPmax, + hydroPmin, + initLevel, + capacity, + inflows, + ovf, + pump, + spillage, + dtgMrg); + hydroGen = H; + unsupE = U; + levels = L; + }); +} + void RemixHydroForAllAreas(const Data::AreaList& areas, PROBLEME_HEBDO& problem, Data::SheddingPolicy sheddingPolicy, @@ -234,10 +324,10 @@ void RemixHydroForAllAreas(const Data::AreaList& areas, switch (simplexOptimizationRange) { case Data::sorWeek: - result = Remix<168>(areas, problem, numSpace, hourInYear); + result = Remix(areas, problem, numSpace, hourInYear); break; case Data::sorDay: - result = Remix<24>(areas, problem, numSpace, hourInYear); + result = Remix(areas, problem, numSpace, hourInYear); break; case Data::sorUnknown: logs.fatal() << "invalid simplex optimization range"; @@ -250,5 +340,17 @@ void RemixHydroForAllAreas(const Data::AreaList& areas, "Error in simplex optimisation. Check logs for more details."); } } + else if (sheddingPolicy == Data::shpAccurateShavePeaks) + { + try + { + RunAccurateShavePeaks(areas, problem, numSpace, hourInYear); + } + catch (std::invalid_argument& invalidArgExc) + { + Data::AssertionError assertErrException(invalidArgExc.what()); + throw assertErrException; + } + } } } // namespace Antares::Solver::Simulation