Skip to content

Commit

Permalink
update xsd, tests
Browse files Browse the repository at this point in the history
  • Loading branch information
restenb committed Jan 27, 2025
1 parent 860c4dd commit 6bc87c6
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 78 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ cmake-build-*/
# Visual Studio Code
.vscode/

CMakeUserPresets.json

CMakeUserPresets.json
1 change: 1 addition & 0 deletions data/xsd/OspSystemStructure.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<xs:sequence>
<xs:element name="Variable" type="osp:variableEndpoint" minOccurs="2" maxOccurs="2"/>
</xs:sequence>
<xs:attribute name="powerbond" use="optional" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="SignalConnection" minOccurs="0" maxOccurs="unbounded">
Expand Down
76 changes: 31 additions & 45 deletions src/cosim/osp_config_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,28 +120,14 @@ 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;
std::string algorithm;
double stepSize = 0.1;
double startTime = 0.0;
std::optional<double> endTime;
std::optional<EccoConfiguration> eccoConfiguration;
std::optional<cosim::ecco_parameters> eccoConfiguration;
};

const SimulationInformation& get_simulation_information() const;
Expand Down Expand Up @@ -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
{

Expand Down Expand Up @@ -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<double>(tc(safetyFactor));
eccoConfig.stepSize = boost::lexical_cast<double>(tc(stepSize));
eccoConfig.minimumStepSize = boost::lexical_cast<double>(tc(minimumStepSize));
eccoConfig.maximumStepSize = boost::lexical_cast<double>(tc(maximumStepSize));
eccoConfig.minimumChangeRate = boost::lexical_cast<double>(tc(minimumChangeRate));
eccoConfig.maximumChangeRate = boost::lexical_cast<double>(tc(maximumChangeRate));
eccoConfig.proportionalGain = boost::lexical_cast<double>(tc(proportionalGain));
eccoConfig.integralGain = boost::lexical_cast<double>(tc(integralGain));
eccoConfig.relativeTolerance = boost::lexical_cast<double>(tc(relativeTolerance));
eccoConfig.absoluteTolerance = boost::lexical_cast<double>(tc(absoluteTolerance));

simulationInformation_.eccoConfiguration = eccoConfig;
std::cout << simulationInformation_.algorithm;
cosim::ecco_parameters eccoConfig{};

eccoConfig.safety_factor = boost::lexical_cast<double>(tc(safetyFactor));
eccoConfig.step_size = cosim::to_duration(boost::lexical_cast<double>(tc(stepSize)));
eccoConfig.min_step_size = cosim::to_duration(boost::lexical_cast<double>(tc(minimumStepSize)));
eccoConfig.max_step_size = cosim::to_duration(boost::lexical_cast<double>(tc(maximumStepSize)));
eccoConfig.min_change_rate = boost::lexical_cast<double>(tc(minimumChangeRate));
eccoConfig.max_change_rate = boost::lexical_cast<double>(tc(maximumChangeRate));
eccoConfig.p_gain = boost::lexical_cast<double>(tc(proportionalGain));
eccoConfig.i_gain = boost::lexical_cast<double>(tc(integralGain));
eccoConfig.rel_tolerance = boost::lexical_cast<double>(tc(relativeTolerance));
eccoConfig.abs_tolerance = boost::lexical_cast<double>(tc(absoluteTolerance));

simulationInformation_.eccoConfiguration = eccoConfig;
}

auto connectionsElement = static_cast<xercesc::DOMElement*>(rootElement->getElementsByTagName(tc("Connections").get())->item(0));
Expand Down Expand Up @@ -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<std::string, extended_model_description> emds;
Expand Down
7 changes: 4 additions & 3 deletions tests/data/ecco/quarter_truck/OspSystemStructure.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@
</InitialValue>
</InitialValues>
</Simulator>
</Simulators>
</Simulators>
<Connections>
<VariableConnection>
<VariableConnection powerbond='wheelchassis'>
<Variable simulator="chassis" name="velocity"/>
<Variable simulator="wheel" name="in_vel"/>
</VariableConnection>
<VariableConnection>
<VariableConnection powerbond='wheelchassis'>
<Variable simulator="wheel" name="out_spring_damper_f"/>
<Variable simulator="chassis" name="force"/>
</VariableConnection>
Expand All @@ -51,6 +51,7 @@
<MinimumStepSize>0.00001</MinimumStepSize>
<MaximumStepSize>0.01</MaximumStepSize>
<MinimumChangeRate>0.2</MinimumChangeRate>

<MaximumChangeRate>1.5</MaximumChangeRate>
<ProportionalGain>0.2</ProportionalGain>
<IntegralGain>0.15</IntegralGain>
Expand Down
43 changes: 38 additions & 5 deletions tests/ecco_algorithm_from_system_structure_test.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
#include <cosim/algorithm.hpp>
#include <cosim/fs_portability.hpp>
#include <cosim/log/simple.hpp>
#include <cosim/observer/file_observer.hpp>
#include <cosim/observer/last_value_observer.hpp>
#include <cosim/observer/time_series_observer.hpp>
#include <cosim/time.hpp>
#include <cosim/fs_portability.hpp>
#include <cosim/orchestration.hpp>
#include <cosim/osp_config_parser.hpp>
#include <cosim/time.hpp>

#include <cstdlib>
#include <exception>
#include <memory>
#include <stdexcept>
#include <cstdlib>

// A helper macro to test various assertions
#define REQUIRE(test) \
Expand All @@ -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<cosim::ecco_parameters>(config.algorithm_configuration);
auto ecco_algo = std::make_shared<cosim::ecco_algorithm>(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<cosim::file_observer>(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;
Expand Down
42 changes: 18 additions & 24 deletions tests/ecco_algorithm_multi_bond_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

#include <cosim/algorithm.hpp>
#include <cosim/log/simple.hpp>
#include <cosim/observer/file_observer.hpp>
#include <cosim/observer/last_value_observer.hpp>
#include <cosim/observer/time_series_observer.hpp>
#include <cosim/observer/file_observer.hpp>
#include <cosim/osp_config_parser.hpp>
#include <cosim/time.hpp>

Expand All @@ -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{
Expand All @@ -38,12 +39,8 @@ int main()
0.2,
0.15};

// Set up an ecco algo
auto ecco_algo = std::make_shared<cosim::ecco_algorithm>(ecco_params);
// auto fs_algo = std::make_shared<cosim::fixed_step_algorithm>(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";

Expand All @@ -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<cosim::file_observer>("./logDir", logXmlPath);
execution.add_observer(std::move(file_obs));
auto file_obs = std::make_unique<cosim::file_observer>("./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<cosim::time_series_observer>(50000);
execution.add_observer(t_observer);
t_observer->start_observing(chassisVel);
Expand Down

0 comments on commit 6bc87c6

Please sign in to comment.