Skip to content

Commit

Permalink
Enable overridable master algorithm selection for SSP (#373)
Browse files Browse the repository at this point in the history
* Allow custom master algorithms when loading from SSP
  • Loading branch information
markaren authored Sep 18, 2019
1 parent 485778b commit ce550a8
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 14 deletions.
30 changes: 30 additions & 0 deletions include/cse.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,46 @@ cse_execution* cse_execution_create(
*
* \param [in] sspDir
* Path to the directory holding SystemStructure.ssd
* \param [in] startTimeDefined
* Defines whether or not the following startTime variable should be ignored or not.
* \param [in] startTime
* The (logical) time point at which the simulation should start.
* If startTimeDefined=false, this variable will be ignored and a default value will be used.
* \returns
* A pointer to an object which holds the execution state,
* or NULL on error.
*/
cse_execution* cse_ssp_execution_create(
const char* sspDir,
bool startTimeDefined,
cse_time_point startTime);

/**
* Creates a new execution based on a SystemStructure.ssd file.
*
* \param [in] sspDir
* Path to the directory holding SystemStructure.ssd
* \param [in] startTimeDefined
* Defines whether or not the following startTime variable should be ignored or not.
* \param [in] startTime
* The (logical) time point at which the simulation should start.
* If startTimeDefined=false, this variable will be ignored and a default value will be used.
* \param [in] stepSizeDefined
* Defines whether or not the following stepSize variable should be ignored or not.
* Must evaluate to `true` when loaded SSP does not contain a osp:FixedStepMaster annotation providing a default step size.
* \param [in] stepSize
* If stepSizeDefined=true, this value will be used by the (fixed-step) co-simulation algorithm.
* \returns
* A pointer to an object which holds the execution state,
* or NULL on error.
*/
cse_execution* cse_ssp_fixed_step_execution_create(
const char* sspDir,
bool startTimeDefined,
cse_time_point startTime,
bool stepSizeDefined,
cse_duration stepSize);

/**
* Destroys an execution.
*
Expand Down
12 changes: 11 additions & 1 deletion include/cse/ssp_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,17 @@ struct simulator_map_entry

using simulator_map = std::map<std::string, simulator_map_entry>;

std::pair<execution, simulator_map> load_ssp(cse::model_uri_resolver&, const boost::filesystem::path& sspDir, std::optional<cse::time_point> overrideStartTime = {});
std::pair<execution, simulator_map> load_ssp(
cse::model_uri_resolver&,
const boost::filesystem::path& sspDir,
std::optional<cse::time_point> overrideStartTime = std::nullopt);


std::pair<execution, simulator_map> load_ssp(
cse::model_uri_resolver&,
const boost::filesystem::path& sspDir,
std::shared_ptr<cse::algorithm> overrideAlgorithm = nullptr,
std::optional<cse::time_point> overrideStartTime = std::nullopt);

} // namespace cse

Expand Down
21 changes: 19 additions & 2 deletions src/c/cse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,30 @@ cse_execution* cse_execution_create(cse_time_point startTime, cse_duration stepS
}
}

cse_execution* cse_ssp_execution_create(const char* sspDir, cse_time_point startTime)
cse_execution* cse_ssp_execution_create(
const char* sspDir,
bool startTimeDefined,
cse_time_point startTime)
{
return cse_ssp_fixed_step_execution_create(sspDir, startTimeDefined, startTime, false, 0);
}

cse_execution* cse_ssp_fixed_step_execution_create(
const char* sspDir,
bool startTimeDefined,
cse_time_point startTime,
bool stepSizeDefined,
cse_duration stepSize)
{
try {
auto execution = std::make_unique<cse_execution>();

auto resolver = cse::default_model_uri_resolver();
auto sim = cse::load_ssp(*resolver, sspDir, to_time_point(startTime));
auto sim = cse::load_ssp(
*resolver,
sspDir,
stepSizeDefined ? std::make_unique<cse::fixed_step_algorithm>(to_duration(stepSize)) : nullptr,
startTimeDefined ? std::optional<cse::time_point>(to_time_point(startTime)) : std::nullopt);

execution->cpp_execution = std::make_unique<cse::execution>(std::move(sim.first));
execution->simulators = std::move(sim.second);
Expand Down
46 changes: 37 additions & 9 deletions src/cpp/ssp_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class ssp_parser
double stepSize;
};

bool has_simulation_information() const;
const SimulationInformation& get_simulation_information() const;

struct SystemDescription
Expand Down Expand Up @@ -97,6 +98,8 @@ class ssp_parser
const std::vector<Connection>& get_connections() const;

private:
bool hasSimulationInformation_;

boost::filesystem::path xmlPath_;
boost::property_tree::ptree pt_;

Expand All @@ -108,7 +111,7 @@ class ssp_parser
};

ssp_parser::ssp_parser(const boost::filesystem::path& xmlPath)
: xmlPath_(xmlPath)
: hasSimulationInformation_(false), xmlPath_(xmlPath)
{
// Root node
std::string path = "ssd:SystemStructureDescription";
Expand Down Expand Up @@ -136,6 +139,7 @@ ssp_parser::ssp_parser(const boost::filesystem::path& xmlPath)
const auto& annotationType = get_attribute<std::string>(annotation.second, "type");
if (annotationType == "org.open-simulation-platform") {
for (const auto& infos : annotation.second.get_child("osp:SimulationInformation")) {
hasSimulationInformation_ = true;
if (infos.first == "osp:FixedStepMaster") {
simulationInformation_.description = get_attribute<std::string>(infos.second, "description");
simulationInformation_.stepSize = get_attribute<double>(infos.second, "stepSize");
Expand Down Expand Up @@ -203,6 +207,11 @@ ssp_parser::ssp_parser(const boost::filesystem::path& xmlPath)

ssp_parser::~ssp_parser() noexcept = default;

bool ssp_parser::has_simulation_information() const
{
return hasSimulationInformation_;
}

const ssp_parser::SimulationInformation& ssp_parser::get_simulation_information() const
{
return simulationInformation_;
Expand Down Expand Up @@ -252,6 +261,11 @@ std::ostream& operator<<(std::ostream& os, streamer<std::variant<Ts...>> sv)
return os;
}

cse::time_point get_default_start_time(const ssp_parser& parser)
{
return cse::to_time_point(parser.get_default_experiment().startTime);
}

cse::variable_id get_variable(
const std::map<std::string, slave_info>& slaves,
const std::string& element,
Expand Down Expand Up @@ -281,22 +295,36 @@ std::pair<execution, simulator_map> load_ssp(
cse::model_uri_resolver& resolver,
const boost::filesystem::path& sspDir,
std::optional<cse::time_point> overrideStartTime)
{
return load_ssp(resolver, sspDir, nullptr, overrideStartTime);
}

std::pair<execution, simulator_map> load_ssp(
cse::model_uri_resolver& resolver,
const boost::filesystem::path& sspDir,
std::shared_ptr<cse::algorithm> overrideAlgorithm,
std::optional<cse::time_point> overrideStartTime)
{
simulator_map simulatorMap;
const auto ssdPath = boost::filesystem::absolute(sspDir) / "SystemStructure.ssd";
const auto baseURI = path_to_file_uri(ssdPath);
const auto parser = ssp_parser(ssdPath);

const auto& simInfo = parser.get_simulation_information();
const cse::duration stepSize = cse::to_duration(simInfo.stepSize);

auto elements = parser.get_elements();
std::shared_ptr<cse::algorithm> algorithm;
if (overrideAlgorithm != nullptr) {
algorithm = overrideAlgorithm;
} else if (parser.has_simulation_information()) {
const auto& simInfo = parser.get_simulation_information();
const cse::duration stepSize = cse::to_duration(simInfo.stepSize);
algorithm = std::move(std::make_unique<cse::fixed_step_algorithm>(stepSize));
} else {
CSE_PANIC_M("No co-simulation algorithm specified!");
}

const auto startTime = overrideStartTime ? *overrideStartTime : cse::to_time_point(parser.get_default_experiment().startTime);
const auto startTime = overrideStartTime ? *overrideStartTime : get_default_start_time(parser);
auto execution = cse::execution(startTime, algorithm);

auto execution = cse::execution(
startTime,
std::make_unique<cse::fixed_step_algorithm>(stepSize));
auto elements = parser.get_elements();

std::map<std::string, slave_info> slaves;
for (const auto& component : elements) {
Expand Down
1 change: 1 addition & 0 deletions test/c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ set(tests
"real_time_test"
"connections_test"
"execution_from_ssp_test"
"execution_from_ssp_custom_algo_test"
"time_series_observer_test"
"variable_metadata_test"
)
Expand Down
102 changes: 102 additions & 0 deletions test/c/execution_from_ssp_custom_algo_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include <cse.h>

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef _WINDOWS
# include <windows.h>
#else
# include <unistd.h>
# define Sleep(x) usleep((x)*1000)
#endif

void print_last_error()
{
fprintf(
stderr,
"Error code %d: %s\n",
cse_last_error_code(), cse_last_error_message());
}

int main()
{
cse_log_setup_simple_console_logging();
cse_log_set_output_level(CSE_LOG_SEVERITY_INFO);

int exitCode = 0;
cse_execution* execution = NULL;
cse_observer* observer = NULL;

const char* dataDir = getenv("TEST_DATA_DIR");
if (!dataDir) {
fprintf(stderr, "Environment variable TEST_DATA_DIR not set\n");
goto Lfailure;
}

char sspDir[1024];
int rc = snprintf(sspDir, sizeof sspDir, "%s/ssp/demo/no_algorithm_element", dataDir);
if (rc < 0) {
perror(NULL);
goto Lfailure;
}

int64_t nanoStepSize = (int64_t)(0.1 * 1.0e9);
execution = cse_ssp_fixed_step_execution_create(sspDir, true, 0, true, nanoStepSize); // override ssp startTime
if (!execution) { goto Lerror; }

cse_execution_status status;
cse_execution_get_status(execution, &status);

if (status.current_time != 0.0) {
fprintf(stderr, "Expected value 0.0, got %f\n", (double)(status.current_time / 1.0e9));
goto Lfailure;
}

observer = cse_last_value_observer_create();
if (!observer) { goto Lerror; }
cse_execution_add_observer(execution, observer);

rc = cse_execution_step(execution, 3);
if (rc < 0) { goto Lerror; }

size_t numSlaves = cse_execution_get_num_slaves(execution);

cse_slave_info infos[2];
rc = cse_execution_get_slave_infos(execution, &infos[0], numSlaves);
if (rc < 0) { goto Lerror; }

for (size_t i = 0; i < numSlaves; i++) {
if (0 == strncmp(infos[i].name, "KnuckleBoomCrane", SLAVE_NAME_MAX_SIZE)) {
double value = -1;
cse_slave_index slaveIndex = infos[i].index;
cse_value_reference varIndex = 2;
rc = cse_observer_slave_get_real(observer, slaveIndex, &varIndex, 1, &value);
if (rc < 0) {
goto Lerror;
}
if (value != 0.05) {
fprintf(stderr, "Expected value 0.05, got %f\n", value);
goto Lfailure;
}
}
}

cse_execution_start(execution);
Sleep(100);
cse_execution_stop(execution);

goto Lcleanup;

Lerror:
print_last_error();

Lfailure:
exitCode = 1;

Lcleanup:
cse_observer_destroy(observer);
cse_execution_destroy(execution);
return exitCode;
}
2 changes: 1 addition & 1 deletion test/c/execution_from_ssp_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ int main()
goto Lfailure;
}

execution = cse_ssp_execution_create(sspDir, 0);
execution = cse_ssp_execution_create(sspDir, false, 0);
if (!execution) { goto Lerror; }

observer = cse_last_value_observer_create();
Expand Down
2 changes: 1 addition & 1 deletion test/c/load_config_and_teardown_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ int main()
return 1;
}

cse_execution* execution = cse_ssp_execution_create(sspDir, 0);
cse_execution* execution = cse_ssp_execution_create(sspDir, false, 0);
if (!execution) {
print_last_error();
return 1;
Expand Down
1 change: 1 addition & 0 deletions test/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(tests
"multi_connections_test"
"multi_fixed_step_algorithm_test"
"ssp_parser_test"
"ssp_parser_no_algorithm_elem_test"
"time_series_observer_test"
"trend_buffer_test"
"monitor_modified_variables_test"
Expand Down
Loading

0 comments on commit ce550a8

Please sign in to comment.