-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
uploading with functional co-simulation setting
- Loading branch information
Showing
58 changed files
with
9,151 additions
and
3,346 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file added
BIN
+3.46 MB
co-simulation/controllerFMU/controllerFMU/binaries/darwin64/unifmu.dylib
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
42 changes: 42 additions & 0 deletions
42
co-simulation/controllerFMU/controllerFMU/modelDescription.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?xml version='1.0' encoding='utf-8'?> | ||
<fmiModelDescription fmiVersion="2.0" modelName="unifmu" guid="77236337-210e-4e9c-8f2c-c1a0677db21b" author="Santiago Gil" generationDateAndTime="2020-10-23T19:51:25Z" variableNamingConvention="flat" generationTool="unifmu"> | ||
<CoSimulation modelIdentifier="unifmu" needsExecutionTool="true" canNotUseMemoryManagementFunctions="false" canHandleVariableCommunicationStepSize="true" /> | ||
<LogCategories> | ||
<Category name="logStatusWarning" /> | ||
<Category name="logStatusDiscard" /> | ||
<Category name="logStatusError" /> | ||
<Category name="logStatusFatal" /> | ||
<Category name="logStatusPending" /> | ||
<Category name="logAll" /> | ||
</LogCategories> | ||
<ModelVariables> | ||
<!--Index of variable = "1"--> | ||
<ScalarVariable name="controller_event" valueReference="0" variability="discrete" causality="output"> | ||
<String /> | ||
</ScalarVariable> | ||
<ScalarVariable name="controller_event_args_0" valueReference="1" causality="output" variability="continuous"> | ||
<Real /> | ||
</ScalarVariable> | ||
<ScalarVariable name="controller_event_args_1" valueReference="2" causality="output" variability="continuous"> | ||
<Real /> | ||
</ScalarVariable> | ||
<ScalarVariable name="controller_event_args_2" valueReference="3" causality="output" variability="continuous"> | ||
<Real /> | ||
</ScalarVariable> | ||
|
||
</ModelVariables> | ||
<ModelStructure> | ||
<Outputs> | ||
<Unknown index="1" dependencies="" /> | ||
<Unknown index="2" dependencies="" /> | ||
<Unknown index="3" dependencies="" /> | ||
<Unknown index="4" dependencies="" /> | ||
</Outputs> | ||
<InitialUnknowns> | ||
<Unknown index="1" dependencies="" /> | ||
<Unknown index="2" dependencies="" /> | ||
<Unknown index="3" dependencies="" /> | ||
<Unknown index="4" dependencies="" /> | ||
</InitialUnknowns> | ||
</ModelStructure> | ||
</fmiModelDescription> |
115 changes: 115 additions & 0 deletions
115
co-simulation/controllerFMU/controllerFMU/resources/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
**This FMU was generated using UniFMU. | ||
For general instructions on how to use the tool access the repository https://github.com/INTO-CPS-Association/unifmu** | ||
|
||
# Implementing the model | ||
|
||
The `resources/model.py` file defines the functional relationship between inputs and outputs of the FMU. | ||
|
||
## Declaring inputs and outputs | ||
|
||
By default, each input, output or parameter declared in the `modelDescription.xml` file is represented as attributes on the instance of the `Model` class. | ||
For instance if a variable `a` is declared in the `modelDescription.xml` file, it an attribute of the same name should be declared in the `Model` class: | ||
|
||
```xml | ||
<ScalarVariable name="a" valueReference="0" variability="continuous" causality="input"> | ||
<Real start="0.0" /> | ||
</ScalarVariable> | ||
``` | ||
|
||
```python | ||
def __init__(self) -> None: | ||
self.a = 0.0 | ||
|
||
self.reference_to_attribute = { | ||
0: "a", | ||
} | ||
``` | ||
|
||
The FMI C-API uses numerical indices rather than names to which variables to read or write to. | ||
As such a mapping between the indices declared by the `valueReference` attribute of the xml and the attributes must be defined. | ||
By default the mapping between a value reference and its corresponding Python attribute is defined by adding an entry to the `reference_to_attributes` variable of the `Model` class. | ||
|
||
## Defining the behavior | ||
|
||
The `Model` class declares several methods that can be used to define the behavior of the FMU. | ||
Methods prefixed with `fmi2` mirror the methods declared in the C-API defined by the FMI specification. | ||
|
||
For instance, to update an output `b` to be twice the value of `a` the `fmi2DoStep` method could be defined as: | ||
|
||
```python | ||
def fmi2DoStep(self, current_time, step_size, no_step_prior): | ||
self.b = self.a * 2 | ||
return Fmi2Status.ok | ||
``` | ||
|
||
# Testing and debugging the model | ||
|
||
The `model.py` is _plain_ Python code, which means we can test the model using test cases and debugging tools. | ||
A small test program can be written and placed in the `model.py` the slave as seen below: | ||
|
||
```python | ||
if __name__ == "__main__": | ||
m = Model() | ||
|
||
assert m.a == 0.0 | ||
assert m.b == 0.0 | ||
|
||
m.a = 1.0 | ||
m.fmiDoStep(0.0, 1.0, False) | ||
|
||
assert m.b == 2.0 | ||
``` | ||
|
||
The program can be executed in your IDE with or from the command line by running the `resources/model.py` script. | ||
|
||
# Runtime dependencies | ||
|
||
The environment that invokes the Python code must provide all the dependencies, otherwise the simulation will fail when instantiating or simulation the model. | ||
For instance, if the `resources/model.py` imports a third-party package such as `numpy` | ||
|
||
```python | ||
import numpy as np | ||
``` | ||
|
||
this must also be available to the Python interpreter specified by the `launch.toml` file, in this case the system's `python3` interpreter: | ||
|
||
```toml | ||
linux = ["python3", "backend.py"] | ||
``` | ||
|
||
One way to address a missing dependency is to install using package manager such as `pip` | ||
|
||
``` | ||
python3 -m pip install numpy | ||
``` | ||
|
||
**Any Python FMU generated UniFMU requires the `protobuf` package. | ||
The easiest way to install this is using pip:** | ||
|
||
``` | ||
python3 -m pip install protobuf | ||
``` | ||
|
||
# File structure | ||
|
||
An overview of the role of each file is provided in the tree below: | ||
|
||
```python | ||
📦model | ||
┣ 📂binaries | ||
┃ ┣ 📂darwin64 | ||
┃ ┃ ┗ 📜unifmu.dylib # binary for macOS | ||
┃ ┣ 📂linux64 | ||
┃ ┃ ┗ 📜unifmu.so # binary for Linux | ||
┃ ┗ 📂win64 | ||
┃ ┃ ┗ 📜unifmu.dll # binary For Windows | ||
┣ 📂resources | ||
┃ ┣ 📂schemas | ||
┃ ┃ ┗ 📜unifmu_fmi2_pb2.py # schema defining structure of messages sent over RPC | ||
┃ ┣ 📜backend.py # receives messages and dispatched function calls to "model.py" | ||
┃ ┣ 📜launch.toml* # specifies command used to start FMU | ||
┃ ┗ 📜model.py* # implementation of FMU | ||
┗ 📜modelDescription.xml* # definition of inputs and outputs | ||
``` | ||
|
||
\* denotes files that would typically be modified by the implementor of the FMU |
142 changes: 142 additions & 0 deletions
142
co-simulation/controllerFMU/controllerFMU/resources/backend.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import logging | ||
import os | ||
import sys | ||
from schemas.unifmu_fmi2_pb2 import ( | ||
Fmi2Command, | ||
Fmi2ExtHandshakeReturn, | ||
Fmi2ExtSerializeSlaveReturn, | ||
Fmi2StatusReturn, | ||
Fmi2GetRealReturn, | ||
Fmi2GetIntegerReturn, | ||
Fmi2GetBooleanReturn, | ||
Fmi2GetStringReturn, | ||
Fmi2FreeInstanceReturn, | ||
) | ||
|
||
logging.basicConfig(level=logging.DEBUG) | ||
logger = logging.getLogger(__file__) | ||
|
||
try: | ||
import zmq | ||
except ImportError: | ||
logger.fatal( | ||
"unable to import the python library 'zmq' required by the schemaless backend. " | ||
"please ensure that the library is present in the python environment launching the script. " | ||
"the missing dependencies can be installed using 'python -m pip install unifmu[python-backend]'" | ||
) | ||
sys.exit(-1) | ||
|
||
from model import Model | ||
|
||
if __name__ == "__main__": | ||
|
||
slave = Model() | ||
|
||
# initializing message queue | ||
context = zmq.Context() | ||
socket = context.socket(zmq.REQ) | ||
dispatcher_endpoint = os.environ["UNIFMU_DISPATCHER_ENDPOINT"] | ||
logger.info(f"dispatcher endpoint received: {dispatcher_endpoint}") | ||
socket.connect(dispatcher_endpoint) | ||
|
||
state = Fmi2ExtHandshakeReturn().SerializeToString() | ||
socket.send(state) | ||
|
||
command = Fmi2Command() | ||
|
||
while True: | ||
|
||
msg = socket.recv() | ||
command.ParseFromString(msg) | ||
|
||
group = command.WhichOneof("command") | ||
|
||
data = getattr(command, command.WhichOneof("command")) | ||
if group == "Fmi2SetupExperiment": | ||
result = Fmi2StatusReturn() | ||
result.status = slave.fmi2SetupExperiment( | ||
data.start_time, data.stop_time, data.tolerance | ||
) | ||
|
||
elif group == "Fmi2SetDebugLogging": | ||
result = Fmi2StatusReturn() | ||
result.status = slave.fmiSetDebugLogging( | ||
data.categores, data.logging_on | ||
) | ||
|
||
elif group == "Fmi2DoStep": | ||
result = Fmi2StatusReturn() | ||
result.status = slave.fmi2DoStep( | ||
data.current_time, data.step_size, data.no_step_prior | ||
) | ||
elif group == "Fmi2EnterInitializationMode": | ||
result = Fmi2StatusReturn() | ||
result.status = slave.fmi2EnterInitializationMode() | ||
elif group == "Fmi2ExitInitializationMode": | ||
result = Fmi2StatusReturn() | ||
result.status = slave.fmi2ExitInitializationMode() | ||
elif group == "Fmi2ExtSerializeSlave": | ||
result = Fmi2ExtSerializeSlaveReturn() | ||
(result.status, result.state) = slave.fmi2ExtSerialize() | ||
elif group == "Fmi2ExtDeserializeSlave": | ||
result = Fmi2StatusReturn() | ||
result.status = slave.fmi2ExtDeserialize(data.state) | ||
elif group == "Fmi2GetReal": | ||
result = Fmi2GetRealReturn() | ||
result.status, result.values[:] = slave.fmi2GetReal( | ||
command.Fmi2GetReal.references | ||
) | ||
elif group == "Fmi2GetInteger": | ||
result = Fmi2GetIntegerReturn() | ||
result.status, result.values[:] = slave.fmi2GetInteger( | ||
command.Fmi2GetInteger.references | ||
) | ||
elif group == "Fmi2GetBoolean": | ||
result = Fmi2GetBooleanReturn() | ||
result.status, result.values[:] = slave.fmi2GetBoolean( | ||
command.Fmi2GetBoolean.references | ||
) | ||
elif group == "Fmi2GetString": | ||
result = Fmi2GetStringReturn() | ||
result.status, result.values[:] = slave.fmi2GetString( | ||
command.Fmi2GetString.references | ||
) | ||
elif group == "Fmi2SetReal": | ||
result = Fmi2StatusReturn() | ||
result.status = slave.fmi2SetReal( | ||
command.Fmi2SetReal.references, command.Fmi2SetReal.values | ||
) | ||
|
||
elif group == "Fmi2SetInteger": | ||
result = Fmi2StatusReturn() | ||
|
||
result.status = slave.fmi2SetInteger( | ||
command.Fmi2SetInteger.references, command.Fmi2SetInteger.values | ||
) | ||
|
||
elif group == "Fmi2SetBoolean": | ||
result = Fmi2StatusReturn() | ||
result.status = slave.fmi2SetBoolean( | ||
command.Fmi2SetBoolean.references, command.Fmi2SetBoolean.values | ||
) | ||
elif group == "Fmi2SetString": | ||
result = Fmi2StatusReturn() | ||
result.status = slave.fmi2SetString( | ||
command.Fmi2SetString.references, command.Fmi2SetString.values | ||
) | ||
elif group == "Fmi2Terminate": | ||
result = Fmi2StatusReturn() | ||
result.status = slave.fmi2Terminate() | ||
elif group == "Fmi2Reset": | ||
result = Fmi2StatusReturn() | ||
result.status = slave.fmi2Reset() | ||
elif group == "Fmi2FreeInstance": | ||
result = Fmi2FreeInstanceReturn() | ||
logger.info(f"Fmi2FreeInstance received, shutting down") | ||
sys.exit(0) | ||
else: | ||
logger.error(f"unrecognized command '{group}' received, shutting down") | ||
sys.exit(-1) | ||
|
||
state = result.SerializeToString() | ||
socket.send(state) |
3 changes: 3 additions & 0 deletions
3
co-simulation/controllerFMU/controllerFMU/resources/launch.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
linux = ["python3", "backend.py"] | ||
macos = ["python3", "backend.py"] | ||
windows = ["python", "backend.py"] |
Oops, something went wrong.