diff --git a/.gitignore b/.gitignore
index aadaf1b1..9541e1f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,4 +10,5 @@ cmake-build-*/
# Visual Studio Code
.vscode/
-CMakeUserPresets.json
\ No newline at end of file
+
+CMakeUserPresets.json
diff --git a/data/xsd/OspSystemStructure.xsd b/data/xsd/OspSystemStructure.xsd
index df4b864b..e3004db0 100644
--- a/data/xsd/OspSystemStructure.xsd
+++ b/data/xsd/OspSystemStructure.xsd
@@ -46,6 +46,7 @@
+
diff --git a/src/cosim/osp_config_parser.cpp b/src/cosim/osp_config_parser.cpp
index 674def3c..1bd118d8 100644
--- a/src/cosim/osp_config_parser.cpp
+++ b/src/cosim/osp_config_parser.cpp
@@ -120,20 +120,6 @@ class osp_config_parser
const cosim::filesystem::path& configPath);
~osp_config_parser() noexcept;
- struct EccoConfiguration
- {
- double safetyFactor = 0.99;
- double stepSize = 1e-3;
- double minimumStepSize = 1e-5;
- double maximumStepSize = 1e-2;
- double minimumChangeRate = 0.2;
- double maximumChangeRate = 1.5;
- double proportionalGain = 0.2;
- double integralGain = 0.15;
- double relativeTolerance = 1e-6;
- double absoluteTolerance = 1e-6;
- };
-
struct SimulationInformation
{
std::string description;
@@ -141,7 +127,7 @@ class osp_config_parser
double stepSize = 0.1;
double startTime = 0.0;
std::optional endTime;
- std::optional eccoConfiguration;
+ std::optional eccoConfiguration;
};
const SimulationInformation& get_simulation_information() const;
@@ -260,21 +246,6 @@ class osp_config_parser
static bool parse_boolean_value(const std::string& s);
};
-[[maybe_unused]] std::ostream& operator<<(std::ostream& os, const osp_config_parser::EccoConfiguration& cfg)
-{
- return os << "Safety Factor: " << cfg.safetyFactor << std::endl
- << "Step Size: " << cfg.stepSize << std::endl
- << "Minimum Step Size: " << cfg.minimumStepSize << std::endl
- << "Maximum Step Size: " << cfg.maximumStepSize << std::endl
- << "Minimum Change Rate: " << cfg.minimumChangeRate << std::endl
- << "Maximum Change Rate: " << cfg.maximumChangeRate << std::endl
- << "Proportional Gain: " << cfg.proportionalGain << std::endl
- << "Integral Gain: " << cfg.integralGain << std::endl
- << "Relative Tolerance: " << cfg.relativeTolerance << std::endl
- << "Absolute Tolerance: " << cfg.absoluteTolerance << std::endl;
-}
-
-
namespace
{
@@ -501,21 +472,20 @@ osp_config_parser::osp_config_parser(
const auto relativeTolerance = eccoConfigurationElement->getElementsByTagName(tc("RelativeTolerance").get())->item(0)->getTextContent();
const auto absoluteTolerance = eccoConfigurationElement->getElementsByTagName(tc("AbsoluteTolerance").get())->item(0)->getTextContent();
- EccoConfiguration eccoConfig{};
-
- eccoConfig.safetyFactor = boost::lexical_cast(tc(safetyFactor));
- eccoConfig.stepSize = boost::lexical_cast(tc(stepSize));
- eccoConfig.minimumStepSize = boost::lexical_cast(tc(minimumStepSize));
- eccoConfig.maximumStepSize = boost::lexical_cast(tc(maximumStepSize));
- eccoConfig.minimumChangeRate = boost::lexical_cast(tc(minimumChangeRate));
- eccoConfig.maximumChangeRate = boost::lexical_cast(tc(maximumChangeRate));
- eccoConfig.proportionalGain = boost::lexical_cast(tc(proportionalGain));
- eccoConfig.integralGain = boost::lexical_cast(tc(integralGain));
- eccoConfig.relativeTolerance = boost::lexical_cast(tc(relativeTolerance));
- eccoConfig.absoluteTolerance = boost::lexical_cast(tc(absoluteTolerance));
-
- simulationInformation_.eccoConfiguration = eccoConfig;
- std::cout << simulationInformation_.algorithm;
+ cosim::ecco_parameters eccoConfig{};
+
+ eccoConfig.safety_factor = boost::lexical_cast(tc(safetyFactor));
+ eccoConfig.step_size = cosim::to_duration(boost::lexical_cast(tc(stepSize)));
+ eccoConfig.min_step_size = cosim::to_duration(boost::lexical_cast(tc(minimumStepSize)));
+ eccoConfig.max_step_size = cosim::to_duration(boost::lexical_cast(tc(maximumStepSize)));
+ eccoConfig.min_change_rate = boost::lexical_cast(tc(minimumChangeRate));
+ eccoConfig.max_change_rate = boost::lexical_cast(tc(maximumChangeRate));
+ eccoConfig.p_gain = boost::lexical_cast(tc(proportionalGain));
+ eccoConfig.i_gain = boost::lexical_cast(tc(integralGain));
+ eccoConfig.rel_tolerance = boost::lexical_cast(tc(relativeTolerance));
+ eccoConfig.abs_tolerance = boost::lexical_cast(tc(absoluteTolerance));
+
+ simulationInformation_.eccoConfiguration = eccoConfig;
}
auto connectionsElement = static_cast(rootElement->getElementsByTagName(tc("Connections").get())->item(0));
@@ -1037,6 +1007,22 @@ osp_config load_osp_config(
config.end_time = to_time_point(simInfo.endTime.value());
}
+ auto algorithm = simInfo.algorithm;
+ std::transform(algorithm.begin(), algorithm.end(), algorithm.begin(),
+ [](unsigned char c) { return std::tolower(c); });
+
+ if (simInfo.algorithm == "ecco") {
+ if (simInfo.eccoConfiguration.has_value()) {
+ config.algorithm_configuration = simInfo.eccoConfiguration.value();
+ } else {
+ throw std::invalid_argument("No configuration parameters found for ecco algorithm.");
+ }
+ } else if (simInfo.algorithm == "fixedstep") {
+ config.algorithm_configuration = cosim::fixed_step_configuration{simInfo.stepSize};
+ } else {
+ throw std::invalid_argument("Invalid algorithm choice. Allowed values are fixedStep, ecco.");
+ }
+
auto simulators = parser.get_elements();
std::unordered_map emds;
diff --git a/tests/data/ecco/quarter_truck/OspSystemStructure.xml b/tests/data/ecco/quarter_truck/OspSystemStructure.xml
index e246e8db..22005133 100644
--- a/tests/data/ecco/quarter_truck/OspSystemStructure.xml
+++ b/tests/data/ecco/quarter_truck/OspSystemStructure.xml
@@ -34,13 +34,13 @@
-
+
-
+
-
+
@@ -51,6 +51,7 @@
0.00001
0.01
0.2
+
1.5
0.2
0.15
diff --git a/tests/ecco_algorithm_from_system_structure_test.cpp b/tests/ecco_algorithm_from_system_structure_test.cpp
index 879e34ca..118a7e41 100644
--- a/tests/ecco_algorithm_from_system_structure_test.cpp
+++ b/tests/ecco_algorithm_from_system_structure_test.cpp
@@ -1,16 +1,17 @@
#include
+#include
#include
+#include
#include
#include
-#include
-#include
#include
#include
+#include
+#include
#include
#include
#include
-#include
// A helper macro to test various assertions
#define REQUIRE(test) \
@@ -24,11 +25,43 @@ int main()
cosim::log::setup_simple_console_logging();
cosim::log::set_global_output_level(cosim::log::debug);
+ constexpr cosim::time_point endTime = cosim::to_time_point(10.0);
+
auto resolver = cosim::default_model_uri_resolver();
auto configPath = cosim::filesystem::path(testDataDir) / "ecco" / "quarter_truck";
- std::cout << "Config path is " << configPath << std::endl;
-
+ const auto logXmlPath = cosim::filesystem::path(testDataDir) / "ecco" / "quarter_truck" / "LogConfig.xml";
const auto config = cosim::load_osp_config(configPath, *resolver);
+
+ auto ecco_params = std::get(config.algorithm_configuration);
+ auto ecco_algo = std::make_shared(ecco_params);
+
+ auto execution = cosim::execution(config.start_time, ecco_algo);
+
+ const auto entityMaps = cosim::inject_system_structure(execution, config.system_structure, config.initial_values);
+ const auto realTimeConfig = execution.get_real_time_config();
+
+ REQUIRE(entityMaps.simulators.size() == 2);
+ REQUIRE(!realTimeConfig->real_time_simulation);
+
+ auto chassisIndex = entityMaps.simulators.at("chassis");
+ auto wheelIndex = entityMaps.simulators.at("wheel");
+
+ auto chassisForce = cosim::variable_id{chassisIndex, cosim::variable_type::real, 19};
+ auto chassisVel = cosim::variable_id{chassisIndex, cosim::variable_type::real, 22};
+ auto wheelCForce = cosim::variable_id{wheelIndex, cosim::variable_type::real, 26};
+ auto wheelCVel = cosim::variable_id{wheelIndex, cosim::variable_type::real, 24};
+
+ ecco_algo->add_power_bond(chassisVel, chassisForce, wheelCForce, wheelCVel);
+
+ const auto logPath = cosim::filesystem::current_path() / "logs";
+ std::cout << "Log path:" << logPath.c_str();
+ auto file_obs = std::make_unique(logPath, logXmlPath);
+ execution.add_observer(std::move(file_obs));
+
+ auto simResult = execution.simulate_until(endTime);
+ REQUIRE(simResult);
+
+
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
diff --git a/tests/ecco_algorithm_multi_bond_test.cpp b/tests/ecco_algorithm_multi_bond_test.cpp
index d0679a30..a7d01b7f 100644
--- a/tests/ecco_algorithm_multi_bond_test.cpp
+++ b/tests/ecco_algorithm_multi_bond_test.cpp
@@ -2,9 +2,9 @@
#include
#include
+#include
#include
#include
-#include
#include
#include
@@ -23,7 +23,8 @@ int main()
cosim::log::setup_simple_console_logging();
cosim::log::set_global_output_level(cosim::log::info);
- constexpr cosim::time_point startTime = cosim::to_time_point(0.0);;
+ constexpr cosim::time_point startTime = cosim::to_time_point(0.0);
+ ;
constexpr cosim::time_point midTime = cosim::to_time_point(4.0);
auto ecco_params = cosim::ecco_parameters{
@@ -38,12 +39,8 @@ int main()
0.2,
0.15};
- // Set up an ecco algo
auto ecco_algo = std::make_shared(ecco_params);
-// auto fs_algo = std::make_shared(cosim::to_duration(1e-4));
-
const auto testDataDir = std::getenv("TEST_DATA_DIR");
- //const auto configPath = cosim::filesystem::path("C:/dev/osp/demo-cases/quarter-truck/OspSystemStructure.xml");
const auto configPath = cosim::filesystem::path(testDataDir) / "ecco" / "quarter_truck" / "OspSystemStructure.xml";
const auto logXmlPath = cosim::filesystem::path(testDataDir) / "ecco" / "quarter_truck" / "LogConfig.xml";
@@ -52,50 +49,47 @@ int main()
auto execution = cosim::execution(
config.start_time,
ecco_algo);
-// fs_algo);
- const auto entityMaps = cosim::inject_system_structure(
- execution, config.system_structure, config.initial_values);
+ const auto entityMaps = cosim::inject_system_structure(execution, config.system_structure, config.initial_values);
REQUIRE(entityMaps.simulators.size() == 2);
-// REQUIRE(boost::size(config.system_structure.connections()) == expectedNumConnections);
// Default should not be real time
const auto realTimeConfig = execution.get_real_time_config();
REQUIRE(!realTimeConfig->real_time_simulation);
- //auto chassisIndex = entityMaps.simulators.at("chassis");
- //auto wheelIndex = entityMaps.simulators.at("wheel");
- //auto groundIndex = entityMaps.simulators.at("ground");
+ // auto chassisIndex = entityMaps.simulators.at("chassis");
+ // auto wheelIndex = entityMaps.simulators.at("wheel");
+ // auto groundIndex = entityMaps.simulators.at("ground");
auto chassisIndex = entityMaps.simulators.at("chassis");
auto wheelIndex = entityMaps.simulators.at("wheel");
- //auto gravity = cosim::variable_id{chassisIndex, cosim::variable_type::real, 2};
+ // auto gravity = cosim::variable_id{chassisIndex, cosim::variable_type::real, 2};
auto chassisForce = cosim::variable_id{chassisIndex, cosim::variable_type::real, 19};
auto chassisVel = cosim::variable_id{chassisIndex, cosim::variable_type::real, 22};
auto wheelCForce = cosim::variable_id{wheelIndex, cosim::variable_type::real, 26};
auto wheelCVel = cosim::variable_id{wheelIndex, cosim::variable_type::real, 24};
- //auto wheelGForce = cosim::variable_id{wheelIndex, cosim::variable_type::real, 17};
- //auto wheelGVel = cosim::variable_id{wheelIndex, cosim::variable_type::real, 18};
- //auto groundForce = cosim::variable_id{groundIndex, cosim::variable_type::real, 11};
- //auto groundVel = cosim::variable_id{groundIndex, cosim::variable_type::real, 12};
+ // auto wheelGForce = cosim::variable_id{wheelIndex, cosim::variable_type::real, 17};
+ // auto wheelGVel = cosim::variable_id{wheelIndex, cosim::variable_type::real, 18};
+ // auto groundForce = cosim::variable_id{groundIndex, cosim::variable_type::real, 11};
+ // auto groundVel = cosim::variable_id{groundIndex, cosim::variable_type::real, 12};
// a = chassis b = wheel
// a = wheel b = ground
// u_a = y_b --- u_b = y_a
// u_a y_a u_b y_b
ecco_algo->add_power_bond(chassisVel, chassisForce, wheelCForce, wheelCVel); // chassis -> wheel (chassis port)
- //ecco_algo->add_power_bond(wheelGVel, wheelGForce, groundForce, groundVel); // wheel -> ground (ground port)
+ // ecco_algo->add_power_bond(wheelGVel, wheelGForce, groundForce, groundVel); // wheel -> ground (ground port)
- auto file_obs = std::make_unique("./logDir", logXmlPath);
- execution.add_observer(std::move(file_obs));
+ auto file_obs = std::make_unique("./logDir", logXmlPath);
+ execution.add_observer(std::move(file_obs));
- // auto simResult = execution.simulate_until(midTime);
- // REQUIRE(simResult);
+ // auto simResult = execution.simulate_until(midTime);
+ // REQUIRE(simResult);
- // Add an observer that watches the last slave
+ // Add an observer that watches the last slave
auto t_observer = std::make_shared(50000);
execution.add_observer(t_observer);
t_observer->start_observing(chassisVel);