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] 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 "