Skip to content

Support serialization of state #55

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

Merged
merged 9 commits into from
Feb 17, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
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
13 changes: 11 additions & 2 deletions pythonfmu/fmi2slave.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Define the abstract facade class."""
import json
import datetime
from abc import ABC, abstractmethod
from collections import OrderedDict, namedtuple
Expand Down Expand Up @@ -250,12 +251,20 @@ def set_string(self, vrs: List[int], values: List[str]):
f"Variable with valueReference={vr} is not of type String!"
)

def _get_fmu_state(self) -> Dict[str, Any]:
def _get_fmu_state(self) -> Dict[str, any]:
state = dict()
for var in self.vars.values():
state[var.name] = self.get_value(var.name)
return state

def _set_fmu_state(self, state: Dict[str, Any]):
def _set_fmu_state(self, state: Dict[str, any]):
for name, value in state.items():
self.set_value(name, value)

@staticmethod
def _fmu_state_to_bytes(state: Dict[str, Any]) -> bytes:
return json.dumps(state).encode("utf-8")

@staticmethod
def _fmu_state_from_bytes(state: bytes) -> Dict[str, Any]:
return json.loads(state.decode("utf-8"))
44 changes: 43 additions & 1 deletion pythonfmu/pythonfmu-export/cpp/PySlaveInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,13 +307,55 @@ void PySlaveInstance::FreeFMUstate(fmi2FMUstate& state)
Py_XDECREF(f);
}

size_t PySlaveInstance::SerializedFMUstateSize(const fmi2FMUstate& state)
{
auto pyState = reinterpret_cast<PyObject*>(state);
PyObject* pyStateBytes = PyObject_CallMethod(pClass_, "_fmu_state_to_bytes", "(O)", pyState);
if (pyStateBytes == nullptr) {
handle_py_exception("[SerializedFMUstateSize] PyObject_CallMethod");
}
auto size = PyBytes_Size(pyStateBytes);
Py_DECREF(pyStateBytes);
return size;
}

void PySlaveInstance::SerializeFMUstate(const fmi2FMUstate& state, fmi2Byte* bytes, size_t size)
{
auto pyState = reinterpret_cast<PyObject*>(state);
PyObject* pyStateBytes = PyObject_CallMethod(pClass_, "_fmu_state_to_bytes", "(O)", pyState);
if (pyStateBytes == nullptr) {
handle_py_exception("[SerializeFMUstate] PyObject_CallMethod");
}
char* c = PyBytes_AsString(pyStateBytes);
if (c == nullptr) {
handle_py_exception("[SerializeFMUstate] PyBytes_AsString");
}
for (int i = 0; i < size; i++) {
bytes[i] = c[i];
}
Py_DECREF(pyStateBytes);
}

void PySlaveInstance::DeSerializeFMUstate(const fmi2Byte bytes[], size_t size, fmi2FMUstate& state)
{
PyObject* pyStateBytes = PyBytes_FromStringAndSize(bytes, size);
if (pyStateBytes == nullptr) {
handle_py_exception("[DeSerializeFMUstate] PyBytes_FromStringAndSize");
}
PyObject* pyState = PyObject_CallMethod(pClass_, "_fmu_state_from_bytes", "(O)", pyStateBytes);
if (pyState == nullptr) {
handle_py_exception("[DeSerializeFMUstate] PyObject_CallMethod");
}
state = reinterpret_cast<fmi2FMUstate*>(pyState);
Py_DECREF(pyStateBytes);
}

PySlaveInstance::~PySlaveInstance()
{
Py_XDECREF(pClass_);
Py_XDECREF(pInstance_);
}


} // namespace pythonfmu

std::unique_ptr<pythonfmu::PyState> pyState = nullptr;
Expand Down
64 changes: 41 additions & 23 deletions pythonfmu/pythonfmu-export/cpp/fmi_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,40 +424,58 @@ fmi2Status fmi2FreeFMUstate(

fmi2Status fmi2SerializedFMUstateSize(
fmi2Component c,
fmi2FMUstate,
size_t*)
fmi2FMUstate state,
size_t* size)
{
reinterpret_cast<Component*>(c)->logger.Log(
fmi2Error,
"cppfmu",
"FMI function not supported: fmi2SerializedFMUstateSize");
return fmi2Error;
const auto component = reinterpret_cast<Component*>(c);
try {
*size = component->slave->SerializedFMUstateSize(state);
return fmi2OK;
} catch (const cppfmu::FatalError& e) {
component->logger.Log(fmi2Fatal, "", e.what());
return fmi2Fatal;
} catch (const std::exception& e) {
component->logger.Log(fmi2Error, "", e.what());
return fmi2Error;
}
}

fmi2Status fmi2SerializeFMUstate(
fmi2Component c,
fmi2FMUstate,
fmi2Byte[],
size_t)
fmi2FMUstate state,
fmi2Byte bytes[],
size_t size)
{
reinterpret_cast<Component*>(c)->logger.Log(
fmi2Error,
"cppfmu",
"FMI function not supported: fmi2SerializeFMUstate");
return fmi2Error;
const auto component = reinterpret_cast<Component*>(c);
try {
component->slave->SerializeFMUstate(state, bytes, size);
return fmi2OK;
} catch (const cppfmu::FatalError& e) {
component->logger.Log(fmi2Fatal, "", e.what());
return fmi2Fatal;
} catch (const std::exception& e) {
component->logger.Log(fmi2Error, "", e.what());
return fmi2Error;
}
}

fmi2Status fmi2DeSerializeFMUstate(
fmi2Component c,
const fmi2Byte[],
size_t,
fmi2FMUstate*)
const fmi2Byte bytes[],
size_t size,
fmi2FMUstate* state)
{
reinterpret_cast<Component*>(c)->logger.Log(
fmi2Error,
"cppfmu",
"FMI function not supported: fmi2DeSerializeFMUstate");
return fmi2Error;
const auto component = reinterpret_cast<Component*>(c);
try {
component->slave->DeSerializeFMUstate(bytes, size, *state);
return fmi2OK;
} catch (const cppfmu::FatalError& e) {
component->logger.Log(fmi2Fatal, "", e.what());
return fmi2Fatal;
} catch (const std::exception& e) {
component->logger.Log(fmi2Error, "", e.what());
return fmi2Error;
}
}


Expand Down
6 changes: 4 additions & 2 deletions pythonfmu/pythonfmu-export/headers/cppfmu/cppfmu_cs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,13 @@ class SlaveInstance
FMIReal& endOfStep) = 0;

virtual void GetFMUstate(fmi2FMUstate& state) = 0;

virtual void SetFMUstate(const fmi2FMUstate& state) = 0;

virtual void FreeFMUstate(fmi2FMUstate& state) = 0;

virtual size_t SerializedFMUstateSize(const fmi2FMUstate& state) = 0;
virtual void SerializeFMUstate(const fmi2FMUstate& state, fmi2Byte bytes[], size_t size) = 0;
virtual void DeSerializeFMUstate(const fmi2Byte bytes[], size_t size, fmi2FMUstate& state) = 0;

// The instance is destroyed in fmi2FreeInstance()/fmiFreeSlaveInstance().
virtual ~SlaveInstance() CPPFMU_NOEXCEPT;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ class PySlaveInstance : public cppfmu::SlaveInstance
void SetFMUstate(const fmi2FMUstate& state) override;
void FreeFMUstate(fmi2FMUstate& state) override;

size_t SerializedFMUstateSize(const fmi2FMUstate& state) override;
void SerializeFMUstate(const fmi2FMUstate& state, fmi2Byte bytes[], size_t size) override;
void DeSerializeFMUstate(const fmi2Byte bytes[], size_t size, fmi2FMUstate& state) override;

~PySlaveInstance() override;

private:
Expand Down