Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reset overrides from outside #206

Merged
merged 5 commits into from
Mar 15, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 47 additions & 3 deletions include/cse.h
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,28 @@ int cse_manipulator_slave_set_real(
size_t nv,
const double values[]);

/**
* Resets any previously overridden values of real variables for one slave.
*
* \param [in] manipulator
* The manipulator.
* \param [in] slaveIndex
* The slave.
* \param [in] variables
* A pointer to an array of length `nv` that contains the (slave-specific)
* indices of variables to reset.
* \param [in] nv
* The length of the `variables` array.
*
* \returns
* 0 on success and -1 on error.
*/
int cse_manipulator_slave_reset_real(
cse_manipulator* manipulator,
cse_slave_index slaveIndex,
const cse_variable_index variables[],
size_t nv);

/**
* Retrieves the values of real variables for one slave.
*
Expand Down Expand Up @@ -438,6 +460,28 @@ int cse_manipulator_slave_set_integer(
size_t nv,
const int values[]);

/**
* Resets the values of any previously overridden integer variables for one slave.
*
* \param [in] manipulator
* The manipulator.
* \param [in] slaveIndex
* The slave.
* \param [in] variables
* A pointer to an array of length `nv` that contains the (slave-specific)
* indices of variables to reset.
* \param [in] nv
* The length of the `variables` array.
*
* \returns
* 0 on success and -1 on error.
*/
int cse_manipulator_slave_reset_integer(
cse_manipulator* manipulator,
cse_slave_index slaveIndex,
const cse_variable_index variables[],
size_t nv);

/**
* Retrieves the values of integer variables for one slave.
*
Expand Down Expand Up @@ -660,9 +704,9 @@ cse_manipulator* cse_scenario_manager_create();

/// Loads and executes a scenario from file.
int cse_execution_load_scenario(
cse_execution* execution,
cse_manipulator* manipulator,
const char* scenarioFile);
cse_execution* execution,
cse_manipulator* manipulator,
const char* scenarioFile);

/// Checks if a scenario is running
int cse_scenario_is_running(cse_manipulator* manipulator);
Expand Down
11 changes: 10 additions & 1 deletion include/cse/manipulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,21 @@ class override_manipulator : public manipulator
void override_real_variable(simulator_index, variable_index, double value);
void override_integer_variable(simulator_index, variable_index, int value);
void override_boolean_variable(simulator_index, variable_index, bool value);
void override_string_variable(simulator_index, variable_index, std::string value);
void override_string_variable(simulator_index, variable_index, const std::string& value);
void reset_real_variable(simulator_index, variable_index);
void reset_integer_variable(simulator_index, variable_index);
void reset_boolean_variable(simulator_index, variable_index);
void reset_string_variable(simulator_index, variable_index);

~override_manipulator() noexcept override;

private:
template<typename I, typename O, typename M, typename N>
void add_action(simulator_index index, variable_index variable, variable_type type, std::function<O(I)> f);

std::unordered_map<simulator_index, simulator*> simulators_;
std::vector<scenario::variable_action> actions_;
std::mutex lock_;
};

} // namespace cse
Expand Down
46 changes: 44 additions & 2 deletions src/c/cse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ int cse_observer_start_observing(cse_observer* observer, cse_slave_index slave,
if (!timeSeriesObserver) {
throw std::invalid_argument("Invalid observer! The provided observer must be a time_series_observer.");
}
const auto variableId = cse::variable_id {slave, to_variable_type(type), index};
const auto variableId = cse::variable_id{slave, to_variable_type(type), index};
timeSeriesObserver->start_observing(variableId);
return success;
} catch (...) {
Expand All @@ -603,7 +603,7 @@ int cse_observer_stop_observing(cse_observer* observer, cse_slave_index slave, c
if (!timeSeriesObserver) {
throw std::invalid_argument("Invalid observer! The provided observer must be a time_series_observer.");
}
const auto variableId = cse::variable_id {slave, to_variable_type(type), index};
const auto variableId = cse::variable_id{slave, to_variable_type(type), index};
timeSeriesObserver->stop_observing(variableId);
return success;
} catch (...) {
Expand Down Expand Up @@ -706,6 +706,48 @@ int cse_manipulator_slave_set_integer(
}
}

int cse_manipulator_slave_reset_real(
cse_manipulator* manipulator,
cse_slave_index slaveIndex,
const cse_variable_index variables[],
size_t nv)
{
try {
const auto man = std::dynamic_pointer_cast<cse::override_manipulator>(manipulator->cpp_manipulator);
if (!man) {
throw std::invalid_argument("Invalid manipulator!");
}
for (size_t i = 0; i < nv; i++) {
man->reset_real_variable(slaveIndex, variables[i]);
}
return success;
} catch (...) {
handle_current_exception();
return failure;
}
}

int cse_manipulator_slave_reset_integer(
cse_manipulator* manipulator,
cse_slave_index slaveIndex,
const cse_variable_index variables[],
size_t nv)
{
try {
const auto man = std::dynamic_pointer_cast<cse::override_manipulator>(manipulator->cpp_manipulator);
if (!man) {
throw std::invalid_argument("Invalid manipulator!");
}
for (size_t i = 0; i < nv; i++) {
man->reset_integer_variable(slaveIndex, variables[i]);
}
return success;
} catch (...) {
handle_current_exception();
return failure;
}
}

cse_manipulator* cse_scenario_manager_create()
{
auto manipulator = std::make_unique<cse_manipulator>();
Expand Down
152 changes: 95 additions & 57 deletions src/cpp/override_manipulator.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include "../../include/cse/scenario.hpp"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not #include "cse/scenario.hpp"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLion works in mysterious ways, but I should have caught it! I'll remove it, as scenario.hpp is already included in manipulator.hpp.


#include "cse/manipulator.hpp"

namespace cse
Expand All @@ -6,6 +8,17 @@ namespace cse
namespace
{

template<typename... Functors>
struct visitor : Functors...
{
visitor(const Functors&... functors)
: Functors(functors)...
{
}

using Functors::operator()...;
};

cse::variable_causality find_variable_causality(const std::vector<variable_description>& variables,
const cse::variable_type type,
const cse::variable_index index)
Expand All @@ -32,90 +45,115 @@ void override_manipulator::simulator_removed(simulator_index index, time_point)

void override_manipulator::step_commencing(time_point /*currentTime*/)
{
std::lock_guard<std::mutex> lock(lock_);
if (!actions_.empty()) {
for (const auto& action : actions_) {
auto sim = simulators_.at(action.simulator);
std::visit(
visitor(
[=](scenario::real_input_manipulator m) {
sim->expose_for_setting(variable_type::real, action.variable);
sim->set_real_input_manipulator(action.variable, m.f);
},
[=](scenario::real_output_manipulator m) {
sim->expose_for_getting(variable_type::real, action.variable);
sim->set_real_output_manipulator(action.variable, m.f);
},
[=](scenario::integer_input_manipulator m) {
sim->expose_for_setting(variable_type::integer, action.variable);
sim->set_integer_input_manipulator(action.variable, m.f);
},
[=](scenario::integer_output_manipulator m) {
sim->expose_for_getting(variable_type::integer, action.variable);
sim->set_integer_output_manipulator(action.variable, m.f);
},
[=](scenario::boolean_input_manipulator m) {
sim->expose_for_setting(variable_type::boolean, action.variable);
sim->set_boolean_input_manipulator(action.variable, m.f);
},
[=](scenario::boolean_output_manipulator m) {
sim->expose_for_getting(variable_type::boolean, action.variable);
sim->set_boolean_output_manipulator(action.variable, m.f);
},
[=](scenario::string_input_manipulator m) {
sim->expose_for_setting(variable_type::string, action.variable);
sim->set_string_input_manipulator(action.variable, m.f);
},
[=](scenario::string_output_manipulator m) {
sim->expose_for_getting(variable_type::string, action.variable);
sim->set_string_output_manipulator(action.variable, m.f);
}),
action.manipulator);
}
actions_.clear();
}
}

void override_manipulator::override_real_variable(simulator_index index, variable_index variable, double value)

template<typename I, typename O, typename M, typename N>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With so many template parameters it is no longer obvious what they mean. I suggest some more descriptive names, or at least an explanatory comment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree! I also don't really like how this turned out, so I'm working on a cleaner way to do it.

void override_manipulator::add_action(simulator_index index, variable_index variable, variable_type type, std::function<O(I)> f)
{
auto f = [value](double /*original*/) { return value; };
auto sim = simulators_.at(index);
auto causality = find_variable_causality(sim->model_description().variables, variable_type::real, variable);
auto causality = find_variable_causality(sim->model_description().variables, type, variable);
std::lock_guard<std::mutex> lock(lock_);
switch (causality) {
case input:
case parameter:
sim->expose_for_setting(variable_type::real, variable);
sim->set_real_input_manipulator(variable, f);
actions_.emplace_back(scenario::variable_action{index, variable, M{f}});
break;
case calculated_parameter:
case output:
sim->expose_for_getting(variable_type::real, variable);
sim->set_real_output_manipulator(variable, f);
actions_.emplace_back(scenario::variable_action{index, variable, N{f}});
break;
default:
throw std::invalid_argument("No support for manipulating a variable with this causality");
}
}

void override_manipulator::override_real_variable(simulator_index index, variable_index variable, double value)
{
auto f = [value](double /*original*/) { return value; };
add_action<double, double, scenario::real_input_manipulator, scenario::real_output_manipulator>(index, variable, cse::variable_type::real, f);
}

void override_manipulator::override_integer_variable(simulator_index index, variable_index variable, int value)
{
auto f = [value](int /*original*/) { return value; };
auto sim = simulators_.at(index);
auto causality = find_variable_causality(sim->model_description().variables, variable_type::integer, variable);
switch (causality) {
case input:
case parameter:
sim->expose_for_setting(variable_type::integer, variable);
sim->set_integer_input_manipulator(variable, f);
break;
case calculated_parameter:
case output:
sim->expose_for_getting(variable_type::integer, variable);
sim->set_integer_output_manipulator(variable, f);
break;
default:
throw std::invalid_argument("No support for manipulating a variable with this causality");
}
add_action<int, int, scenario::integer_input_manipulator, scenario::integer_output_manipulator>(index, variable, cse::variable_type::integer, f);
}

void override_manipulator::override_boolean_variable(simulator_index index, variable_index variable, bool value)
{
auto f = [value](bool /*original*/) { return value; };
auto sim = simulators_.at(index);
auto causality = find_variable_causality(sim->model_description().variables, variable_type::boolean, variable);
switch (causality) {
case input:
case parameter:
sim->expose_for_setting(variable_type::boolean, variable);
sim->set_boolean_input_manipulator(variable, f);
break;
case calculated_parameter:
case output:
sim->expose_for_getting(variable_type::boolean, variable);
sim->set_boolean_output_manipulator(variable, f);
break;
default:
throw std::invalid_argument("No support for manipulating a variable with this causality");
}
add_action<bool, bool, scenario::boolean_input_manipulator, scenario::boolean_output_manipulator>(index, variable, cse::variable_type::boolean, f);
}
void override_manipulator::override_string_variable(simulator_index index, variable_index variable, std::string value)

void override_manipulator::override_string_variable(simulator_index index, variable_index variable, const std::string& value)
{
auto f = [value](std::string_view /*original*/) { return value; };
auto sim = simulators_.at(index);
auto causality = find_variable_causality(sim->model_description().variables, variable_type::string, variable);
switch (causality) {
case input:
case parameter:
sim->expose_for_setting(variable_type::string, variable);
sim->set_string_input_manipulator(variable, f);
break;
case calculated_parameter:
case output:
sim->expose_for_getting(variable_type::string, variable);
sim->set_string_output_manipulator(variable, f);
break;
default:
throw std::invalid_argument("No support for manipulating a variable with this causality");
}
add_action<std::string_view, std::string, scenario::string_input_manipulator, scenario::string_output_manipulator>(index, variable, cse::variable_type::string, f);
}

void override_manipulator::reset_real_variable(simulator_index index, variable_index variable)
{
add_action<double, double, scenario::real_input_manipulator, scenario::real_output_manipulator>(index, variable, cse::variable_type::real, nullptr);
}

void override_manipulator::reset_integer_variable(simulator_index index, variable_index variable)
{
add_action<int, int, scenario::integer_input_manipulator, scenario::integer_output_manipulator>(index, variable, cse::variable_type::integer, nullptr);
}

void override_manipulator::reset_boolean_variable(simulator_index index, variable_index variable)
{
add_action<bool, bool, scenario::boolean_input_manipulator, scenario::boolean_output_manipulator>(index, variable, cse::variable_type::boolean, nullptr);
}

void override_manipulator::reset_string_variable(simulator_index index, variable_index variable)
{
add_action<std::string_view, std::string, scenario::string_input_manipulator, scenario::string_output_manipulator>(index, variable, cse::variable_type::string, nullptr);
}

override_manipulator::~override_manipulator() = default;

} // namespace cse
} // namespace cse