Skip to content

Commit fa6a63b

Browse files
committed
State saving support with proxyfmu
1 parent b65ce6f commit fa6a63b

File tree

5 files changed

+77
-30
lines changed

5 files changed

+77
-30
lines changed

conanfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def requirements(self):
4343
self.requires("libzip/[>=1.7 <1.10]") # 1.10 deprecates some functions we use
4444
self.requires("ms-gsl/[>=3 <5]", transitive_headers=True)
4545
if self.options.proxyfmu:
46-
self.requires("proxyfmu/0.3.2@osp/stable")
46+
self.requires("proxyfmu/0.3.3@osp/testing-feature_779-state-serialization")
4747
self.requires("boost/[~1.81]", transitive_headers=True, transitive_libs=True) # Required by Thrift
4848
else:
4949
self.requires("boost/[>=1.71]", transitive_headers=True, transitive_libs=True)

src/cosim/proxy/remote_fmu.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ std::unique_ptr<cosim::model_description> parse_model_description(const proxyfmu
7171
_md->author = md.author;
7272
_md->name = md.modelName;
7373
_md->description = md.description;
74+
_md->capabilities.can_get_and_set_fmu_state = md.canGetAndSetFMUstate;
75+
_md->capabilities.can_serialize_fmu_state = md.canSerializeFMUstate;
7476

7577
for (auto& var : md.modelVariables) {
7678
cosim::variable_description vd;

src/cosim/proxy/remote_slave.cpp

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <cosim/error.hpp>
77
#include <cosim/exception.hpp>
88
#include <cosim/proxy/remote_slave.hpp>
9+
#include <proxyfmu/thrift/defs_types.h>
910

1011
#include <utility>
1112

@@ -204,45 +205,60 @@ void cosim::proxy::remote_slave::set_string_variables(gsl::span<const cosim::val
204205

205206
cosim::slave::state_index cosim::proxy::remote_slave::save_state()
206207
{
207-
throw error(
208-
make_error_code(errc::unsupported_feature),
209-
"Proxyfmu does not support state saving");
208+
return slave_->save_state();
210209
}
211210

212-
void cosim::proxy::remote_slave::save_state(state_index)
211+
void cosim::proxy::remote_slave::save_state(state_index idx)
213212
{
214-
throw error(
215-
make_error_code(errc::unsupported_feature),
216-
"Proxyfmu does not support state saving");
213+
slave_->save_state(idx);
217214
}
218215

219-
void cosim::proxy::remote_slave::restore_state(state_index)
216+
void cosim::proxy::remote_slave::restore_state(state_index idx)
220217
{
221-
throw error(
222-
make_error_code(errc::unsupported_feature),
223-
"Proxyfmu does not support state saving");
218+
slave_->restore_state(idx);
224219
}
225220

226-
void cosim::proxy::remote_slave::release_state(state_index)
221+
void cosim::proxy::remote_slave::release_state(state_index idx)
227222
{
228-
throw error(
229-
make_error_code(errc::unsupported_feature),
230-
"Proxyfmu does not support state saving");
223+
slave_->release_state(idx);
231224
}
232225

233-
cosim::serialization::node cosim::proxy::remote_slave::export_state(state_index) const
226+
cosim::serialization::node cosim::proxy::remote_slave::export_state(state_index idx) const
234227
{
235-
throw error(
236-
make_error_code(errc::unsupported_feature),
237-
"Proxyfmu does not support state serialization");
228+
proxyfmu::thrift::ExportedState state;
229+
slave_->export_state(idx, state);
230+
231+
// Create the exported state
232+
serialization::node exportedState;
233+
exportedState.put("scheme_version", state.schemeVersion);
234+
exportedState.put("fmu_uuid", state.uuid);
235+
236+
std::vector<std::byte> vec;
237+
std::transform(state.fmuState.begin(), state.fmuState.end(), std::back_inserter(vec),
238+
[](unsigned char c) { return std::byte(c); });
239+
240+
exportedState.put("serialized_fmu_state", vec);
241+
exportedState.put("setup_complete", state.setupComplete);
242+
exportedState.put("simulation_started", state.simStarted);
243+
return exportedState;
238244
}
239245

240246
cosim::slave::state_index cosim::proxy::remote_slave::import_state(
241-
const cosim::serialization::node&)
247+
const cosim::serialization::node& node)
242248
{
243-
throw error(
244-
make_error_code(errc::unsupported_feature),
245-
"Proxyfmu does not support state serialization");
249+
proxyfmu::thrift::ExportedState state;
250+
state.schemeVersion = node.get<std::int32_t>("scheme_version");
251+
state.uuid = node.get<std::string>("fmu_uuid");
252+
253+
const auto& serializedFMUState = std::get<std::vector<std::byte>>(
254+
node.get_child("serialized_fmu_state").data());
255+
state.fmuState.reserve(serializedFMUState.size());
256+
std::transform(serializedFMUState.begin(), serializedFMUState.end(), std::back_inserter(state.fmuState),
257+
[](std::byte b) { return static_cast<unsigned char>(b); });
258+
259+
state.setupComplete = node.get<bool>("setup_complete");
260+
state.simStarted = node.get<bool>("simulation_started");
261+
return slave_->import_state(state);
246262
}
247263

248264
cosim::proxy::remote_slave::~remote_slave()
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<OspSystemStructure
3+
xmlns="http://opensimulationplatform.com/MSMI/OSPSystemStructure"
4+
version="0.1">
5+
<StartTime>0.0</StartTime>
6+
<BaseStepSize>0.01</BaseStepSize>
7+
<Algorithm>fixedStep</Algorithm>
8+
<Simulators>
9+
<Simulator name="bouncingball" source="proxyfmu://localhost?file=../fmi2/BouncingBall.fmu">
10+
</Simulator>
11+
</Simulators>
12+
<Connections>
13+
</Connections>
14+
</OspSystemStructure>

tests/save_state_test.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ std::vector<double> get_reals(
3838
return values;
3939
}
4040

41-
int main()
41+
int run(const cosim::filesystem::path& configPath)
4242
{
4343
try {
4444
cosim::log::setup_simple_console_logging();
@@ -49,10 +49,6 @@ int main()
4949
// ================================================================
5050
constexpr cosim::duration stepSize = cosim::to_duration(0.05);
5151

52-
const auto testDataDir = std::getenv("TEST_DATA_DIR");
53-
REQUIRE(testDataDir);
54-
auto configPath = cosim::filesystem::path(testDataDir) / "msmi" / "OspSystemStructure_BouncingBall.xml";
55-
5652
auto resolver = cosim::default_model_uri_resolver();
5753
const auto config = cosim::load_osp_config(configPath, *resolver);
5854
auto execution = cosim::execution(
@@ -212,7 +208,26 @@ int main()
212208
REQUIRE(state2ValuesAgain == state2Values);
213209
} catch (const std::exception& e) {
214210
std::cerr << "Error: " << e.what() << std::endl;
215-
return 1;
211+
return 0;
216212
}
213+
return 1;
214+
}
215+
216+
int main()
217+
{
218+
const auto testDataDir = std::getenv("TEST_DATA_DIR");
219+
REQUIRE(testDataDir);
220+
221+
auto configPath1 = cosim::filesystem::path(testDataDir) / "msmi" / "OspSystemStructure_BouncingBall.xml";
222+
auto result1 = run(configPath1);
223+
224+
std::cout << "Result 1: " << result1 << std::endl;
225+
226+
auto configPath2 = cosim::filesystem::path(testDataDir) / "msmi" / "OspSystemStructure_BouncingBall_proxyfmu.xml";
227+
auto result2 = run(configPath2);
228+
229+
std::cout << "Result 2: " << result2 << std::endl;
230+
231+
REQUIRE(result1 && result2);
217232
return 0;
218233
}

0 commit comments

Comments
 (0)