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()); + } +}