Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
d438209
Base to ckecl expression
Nov 26, 2025
0c70ad6
reduced cost
Nov 26, 2025
e6317b8
dual handling
Nov 26, 2025
c20bf08
add loop on lib and models
Nov 26, 2025
9242a94
continue
Nov 26, 2025
78f22ae
move code related to functions node in another functiong
Nov 26, 2025
6e5b2f0
fix segfault when reduced cost with parameter
Nov 26, 2025
4273f3f
quality
Nov 26, 2025
fb73142
Construct var node
Nov 27, 2025
d76ed93
format
Nov 27, 2025
8d91f61
better name for exception
Nov 27, 2025
67297cd
rm lambda
Nov 27, 2025
c517057
handle portfieldsum
Nov 27, 2025
54ad5fc
rm lambda
Nov 27, 2025
80efcc3
add checklocation cpp
Nov 28, 2025
adc0b57
Move code to checkLocation.cpp
Nov 28, 2025
8a94e32
improve exception message
Nov 28, 2025
65383ea
improve exception message
Nov 28, 2025
e12d570
specialize exceptions, handle pfsum
Nov 28, 2025
c76d4d0
create the error msg once
Nov 28, 2025
df66c1d
use correct port id
Dec 1, 2025
388522f
const AST and function
Dec 1, 2025
1a5aa3c
move check for hybrid
Dec 1, 2025
a3be6a2
add a separated header
Dec 1, 2025
4f49a07
add unit test file
Dec 1, 2025
b76c467
test for dual and reduced cost
Dec 1, 2025
28cce06
base to test portfield
Dec 1, 2025
c64b181
portfield test
Dec 1, 2025
8c0e03d
location to str and compatible
Dec 1, 2025
b868d4b
stricter location
Dec 1, 2025
988ca55
test location compatible for expressions
Dec 1, 2025
34890df
format
Dec 1, 2025
db6d39d
move function to cpp file
Dec 2, 2025
8d9a982
Add a test with valid portfield
Dec 2, 2025
29f88c8
Add test for portfield sum
Dec 2, 2025
59960dd
check for port id
Dec 2, 2025
f528667
comments 1
Dec 3, 2025
59ec64f
comments 2 fmt
Dec 3, 2025
2d89de1
create a separated check folder
Dec 3, 2025
badd38a
format
Dec 3, 2025
ba60c37
Update src/io/inputs/model-converter/convertorVisitor.cpp
flomnes Dec 9, 2025
806901f
mege conflicts
Dec 9, 2025
f389db3
Merge branch 'feature/valid-location' of https://github.com/AntaresSi…
Dec 9, 2025
d06de83
add const to checks
Dec 9, 2025
99686f4
loop on components
Dec 9, 2025
f3fbc9d
unit tests
Dec 9, 2025
316ef0e
Merge remote-tracking branch 'origin' into feature/valid-location
Dec 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions src/io/inputs/model-converter/convertorVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/

#include <ExprVisitor.h>
#include <any>

#include <antares/expressions/nodes/ExpressionsNodes.h>
#include <antares/io/inputs/model-converter/convertorVisitor.h>
Expand Down Expand Up @@ -422,7 +423,7 @@
return node;
}

throw NoConstraintWithThisName(model_.id, constraint_id);
throw DualNoConstraintWithThisName(model_.id, constraint_id);
}

std::any ConvertorVisitor::handleReducedCost(ExprParser::ArgListContext* context)
Expand All @@ -444,18 +445,18 @@
+ params);
}

std::vector<Node*> nodes;
try
{
nodes = std::any_cast<std::vector<Node*>>(context->accept(this));
}
catch (const NoParameterOrVariableWithThisName&) // to print accurate message
unsigned index = 0;
for (const auto& var: model_.variables)
{
throw NoVariableWithThisName(model_.id, context->expr(0)->getText());
if (var.id == variableId.at(0)->getText())
{
auto varNode = registry_.create<VariableNode>(var.id, index);

Check warning on line 453 in src/io/inputs/model-converter/convertorVisitor.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Change this declaration specifying the "pointer" part outside of auto.

See more on https://sonarcloud.io/project/issues?id=AntaresSimulatorTeam_Antares_Simulator&issues=AZrE4Hqq0tQ8QuKR3ny2&open=AZrE4Hqq0tQ8QuKR3ny2&pullRequest=3258
return static_cast<Node*>(
registry_.create<FunctionNode>(FunctionNodeType::reduced_cost, varNode));
}
++index;
}

return static_cast<Node*>(
registry_.create<FunctionNode>(FunctionNodeType::reduced_cost, nodes.at(0)));
throw ReducedCostNoVariableWithThisName(model_.id, variableId.at(0)->getText());
}

template<class T>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,22 @@ class NoParameterOrVariableWithThisName final: public std::runtime_error
}
};

class NoVariableWithThisName final: public std::runtime_error
class ReducedCostNoVariableWithThisName final: public std::runtime_error
{
public:
explicit NoVariableWithThisName(const std::string& modelName, const std::string& varName):
explicit ReducedCostNoVariableWithThisName(const std::string& modelName,
const std::string& varName):
runtime_error("reduced_cost called with unknown variable '" + varName + "' in model '"
+ modelName + "'")
{
}
};

class NoConstraintWithThisName final: public std::runtime_error
class DualNoConstraintWithThisName final: public std::runtime_error
{
public:
explicit NoConstraintWithThisName(const std::string& modelName,
const std::string& constraintName):
explicit DualNoConstraintWithThisName(const std::string& modelName,
const std::string& constraintName):
runtime_error("dual called with unknown constraint '" + constraintName + "' in model '"
+ modelName + "'")
{
Expand Down
1 change: 1 addition & 0 deletions src/modeler/loadFiles/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(SOURCES
readScenarioGroup.cpp
readSystem.cpp
readOptimConfig.cpp
checkLocation.cpp

include/antares/solver/modeler/loadFiles/loadFiles.h
include/antares/solver/modeler/loadFiles/Fileloader.h
Expand Down
143 changes: 143 additions & 0 deletions src/modeler/loadFiles/checkLocation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* Copyright 2007-2025, RTE (https://www.rte-france.com)
* See AUTHORS.txt
* SPDX-License-Identifier: MPL-2.0
* This file is part of Antares-Simulator,
* Adequacy and Performance assessment for interconnected energy networks.
*
* Antares_Simulator is free software: you can redistribute it and/or modify
* it under the terms of the Mozilla Public Licence 2.0 as published by
* the Mozilla Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* Antares_Simulator is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Mozilla Public Licence 2.0 for more details.
*
* You should have received a copy of the Mozilla Public Licence 2.0
* along with Antares_Simulator. If not, see <https://opensource.org/license/mpl-2-0/>.
*/

#include <antares/expressions/iterators/pre-order.h>
#include <antares/expressions/nodes/ExpressionsNodes.h>
#include <antares/solver/modeler/data.h>
#include <antares/solver/modeler/loadFiles/loadFiles.h>

using namespace Antares::Expressions::Nodes;
using namespace Antares::ModelerStudy::SystemModel;
using namespace Antares::Modeler::Config;

namespace Antares::Solver::LoadFiles
{

void checkFunctionNode(Node& node, Model& model)
{
// dual and reduced_cost can only be used in subproblems
if (auto* functionNode = dynamic_cast<FunctionNode*>(&node); functionNode)
{
if (functionNode->type() == FunctionNodeType::reduced_cost)
{
const auto* varNode = dynamic_cast<VariableNode*>(functionNode->getOperands().at(0));
for (const auto& variable: model.Variables())
{
if (variable.Id() == varNode->value()
&& variable.location() != Location::SUBPROBLEMS)
{
throw std::runtime_error("Reduced costs can only be used in subproblems");

Check warning on line 47 in src/modeler/loadFiles/checkLocation.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define and throw a dedicated exception instead of using a generic one.

See more on https://sonarcloud.io/project/issues?id=AntaresSimulatorTeam_Antares_Simulator&issues=AZrKHEsOwuKIVMWKmNuX&open=AZrKHEsOwuKIVMWKmNuX&pullRequest=3258
}
}
}

if (functionNode->type() == FunctionNodeType::dual)
{
// This node contains the constraint name
const auto* n = dynamic_cast<LiteralNode*>(functionNode->getOperands().at(0));
for (const auto& constraint: model.Constraints())
{
if (constraint.Id() == n->name())
{
if (constraint.location() != Location::SUBPROBLEMS)

Check warning on line 60 in src/modeler/loadFiles/checkLocation.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Merge this "if" statement with the enclosing one.

See more on https://sonarcloud.io/project/issues?id=AntaresSimulatorTeam_Antares_Simulator&issues=AZrKHEsOwuKIVMWKmNuY&open=AZrKHEsOwuKIVMWKmNuY&pullRequest=3258
{
throw std::runtime_error("Duals can only be used in subproblems");

Check warning on line 62 in src/modeler/loadFiles/checkLocation.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define and throw a dedicated exception instead of using a generic one.

See more on https://sonarcloud.io/project/issues?id=AntaresSimulatorTeam_Antares_Simulator&issues=AZrKHEsOwuKIVMWKmNuZ&open=AZrKHEsOwuKIVMWKmNuZ&pullRequest=3258
}
}
}
}
}
}

void checkExpression(Node* expression, const Location& location, Model& model)
{
for (auto& node: AST(expression))
{
// base variable
if (const auto* varNode = dynamic_cast<VariableNode*>(&node); varNode)
{
for (const auto& variable: model.Variables())
{
if (variable.Id() == varNode->value()
&& !AreLocationsCompatible(variable.location(), location))
{
throw std::runtime_error("Variable mismatch locations"); // TODO Better ex

Check warning on line 82 in src/modeler/loadFiles/checkLocation.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this "TODO" comment.

See more on https://sonarcloud.io/project/issues?id=AntaresSimulatorTeam_Antares_Simulator&issues=AZrKHEsOwuKIVMWKmNuW&open=AZrKHEsOwuKIVMWKmNuW&pullRequest=3258

Check warning on line 82 in src/modeler/loadFiles/checkLocation.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define and throw a dedicated exception instead of using a generic one.

See more on https://sonarcloud.io/project/issues?id=AntaresSimulatorTeam_Antares_Simulator&issues=AZrKHEsOwuKIVMWKmNua&open=AZrKHEsOwuKIVMWKmNua&pullRequest=3258
}
}
continue;
}

// Portfields can contains variables, we recursively check their expressions
if (const auto* n = dynamic_cast<PortFieldNode*>(&node); n)
{
PortFieldKey key(n->getPortName(), n->getFieldName());
checkExpression(model.PortFieldDefinitions().at(key).Definition().RootNode(),
location,
model);
continue;
}

if (const auto* portFieldSumNode = dynamic_cast<PortFieldSumNode*>(&node); portFieldSumNode)
{
for (const auto& connection: model.ComponentConnections())
{
auto* n = connection.component()->nodeAtPortField(portFieldSumNode->getPortName(),
portFieldSumNode->getFieldName());
checkExpression(n, location, *connection.component()->getModel());
}
continue;
}

checkFunctionNode(node, model);
}
}

void checkModel(Model& model)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const

{
for (const auto& constraint: model.Constraints())
{
checkExpression(constraint.expression().RootNode(), constraint.location(), model);
}

for (const auto& objective: model.Objectives())
{
checkExpression(objective.expression().RootNode(), objective.location(), model);
}

// Extra outputs must be evaluated, they need to contain only subproblem objects
for (const auto& [_, extraOutput]: model.ExtraOutputs())
{
checkExpression(extraOutput.expression().RootNode(), Location::SUBPROBLEMS, model);
}
}

void checkLocations(Modeler::Data& data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const

{
for (auto& lib: data.libraries)
{
for (auto& [modelName, model]: lib.Models())
{
checkModel(model);
}
}
}

} // namespace Antares::Solver::LoadFiles
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ void loadOptimConfig(const std::filesystem::path& studyPath,

void handleYamlError(const YAML::Exception& e, const std::string& filename);

void checkLocations(Antares::Modeler::Data& data);

/// Generic error class for all loading errors to catch in the main
class ErrorLoadingYaml final: public std::runtime_error
{
Expand Down
6 changes: 3 additions & 3 deletions src/modeler/modeler/Modeler.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/*
* Copyright 2007-2025, RTE (https://www.rte-france.com)
* See AUTHORS.txt
Expand All @@ -22,7 +21,6 @@

#include "antares/solver/modeler/Modeler.h"

#include <chrono>
#include <fstream>

#include <antares/logs/logs.h>
Expand All @@ -36,11 +34,12 @@
#include "antares/solver/modeler/IWriter.h"
#include "antares/utils/utils.h"

#include "include/antares/solver/modeler/data.h"

using namespace Antares::Optimisation::LinearProblemMpsolverImpl;
using namespace Antares;
using namespace Antares::Optimization;
using namespace Antares::Optimisation;
using namespace Antares::Solver;
using namespace Antares::Optimisation::LinearProblemApi;

namespace Antares::Solver
Expand Down Expand Up @@ -113,6 +112,7 @@ void Modeler::run() const
parameters = loader_.loadParameters();
logs.info() << "Parameters loaded";
data = loader_.loadAll();
LoadFiles::checkLocations(data);
}
catch (const LoadFiles::ErrorLoadingYaml&)
{
Expand Down
3 changes: 2 additions & 1 deletion src/study/system-model/component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Component::Component(const ComponentData& component_data)

void Component::addComponentConnection(const std::string localPortId, ConnectionEnd&& connexionEnd)
{
getModel()->addComponentConnection(connexionEnd); // used to check location later
componentConnectionEnds_[localPortId].push_back(std::move(connexionEnd));
}

Expand All @@ -76,7 +77,7 @@ std::vector<ConnectionEnd> Component::componentConnectionsViaPort(const std::str
return {};
}

const Node* Component::nodeAtPortField(const std::string& portId, const std::string& fieldId) const
Node* Component::nodeAtPortField(const std::string& portId, const std::string& fieldId) const
{
try
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ class Component final
void addComponentConnection(const std::string localPortId, ConnectionEnd&& connection);
std::vector<ConnectionEnd> componentConnectionsViaPort(const std::string& portId) const;

const Expressions::Nodes::Node* nodeAtPortField(const std::string& portId,
const std::string& fieldId) const;
Expressions::Nodes::Node* nodeAtPortField(const std::string& portId,
const std::string& fieldId) const;

void addAreaConnection(const std::string& localPortId, const std::string& areaId);

Expand Down
12 changes: 12 additions & 0 deletions src/study/system-model/include/antares/study/system-model/model.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <antares/expressions/expression.h>

#include "connection.h"
#include "constraint.h"
#include "extraOutput.h"
#include "objective.h"
Expand Down Expand Up @@ -107,6 +108,16 @@ class Model final
return extraOutputs_;
}

void addComponentConnection(ConnectionEnd connection)
{
componentsConnections_.push_back(connection);
}

const std::vector<ConnectionEnd>& ComponentConnections() const
{
return componentsConnections_;
}

private:
friend class ModelBuilder;
std::string id_;
Expand All @@ -119,6 +130,7 @@ class Model final
std::vector<Objective> objectives_;

PortFieldMap portFieldDefinitions_;
std::vector<ConnectionEnd> componentsConnections_; // used to check location for portFieldSum
};

// List of IDs used internally to check for uniqueness of IDs at component level
Expand Down
Loading