Skip to content

Add simulation support to oms3 api #1462

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

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ project(OMSimulator)

# Options to enable/disable specific components
option(OMS_ENABLE_OMSimulator "Enable OMSimulator component" ON)
option(OMS_ENABLE_OMSimulatorGui "Enable OMSimulator GUI component" ON)
option(OMS_ENABLE_PIP "Enable pip component" ON)
option(OMS_ENABLE_OMSimulatorGui "Enable OMSimulator GUI component" OFF)
option(OMS_ENABLE_PIP "Enable pip component" OFF)
option(OMS_ENABLE_TESTSUITE "Enable the OMSimulator testsuite" OFF)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/config.cmake/")
Expand Down
6 changes: 6 additions & 0 deletions include/OMSimulator/OMSimulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ OMSAPI oms_status_enu_t OMSCALL oms_simulate(const char* cref);
OMSAPI oms_status_enu_t OMSCALL oms_stepUntil(const char* cref, double stopTime);
OMSAPI oms_status_enu_t OMSCALL oms_terminate(const char* cref);

OMSAPI oms_status_enu_t OMSCALL oms3_instantiateFromJson(char* model_json_desc, void** out_model_ptr);
OMSAPI oms_status_enu_t OMSCALL oms3_initialize(void* model);
OMSAPI oms_status_enu_t OMSCALL oms3_simulate(void* model);
OMSAPI oms_status_enu_t OMSCALL oms3_stepUntil(void* model, double stopTime);
OMSAPI oms_status_enu_t OMSCALL oms3_terminate(void* model);

#ifdef __cplusplus
}
#endif
Expand Down
28 changes: 28 additions & 0 deletions src/OMSimulatorLib/OMSimulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1691,3 +1691,31 @@ oms_status_enu_t oms_setTolerance(const char* cref, double relativeTolerance)

return logError_SystemNotInModel(model->getCref(), front);
}


oms_status_enu_t oms3_instantiateFromJson(char* model_json_desc, void** out_model_ptr)
{
*out_model_ptr = nullptr;
logDebug(model_json_desc);
return oms_status_ok;
}

oms_status_enu_t oms3_initialize(void* model)
{
return oms_status_error;
}

oms_status_enu_t oms3_simulate(void* model)
{
return oms_status_error;
}

oms_status_enu_t oms3_stepUntil(void* model, double stopTime)
{
return oms_status_error;
}

oms_status_enu_t oms3_terminate(void* model)
{
return oms_status_error;
}
3 changes: 2 additions & 1 deletion src/OMSimulatorPython/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OMSimulatorPython3.in" "${CMAKE_CURR

install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py"
"${CMAKE_CURRENT_BINARY_DIR}/capi.py"
"${CMAKE_CURRENT_SOURCE_DIR}/component.py"
"${CMAKE_CURRENT_SOURCE_DIR}/connection.py"
"${CMAKE_CURRENT_SOURCE_DIR}/connector.py"
"${CMAKE_CURRENT_SOURCE_DIR}/component.py"
"${CMAKE_CURRENT_SOURCE_DIR}/cref.py"
"${CMAKE_CURRENT_SOURCE_DIR}/elementgeometry.py"
"${CMAKE_CURRENT_SOURCE_DIR}/fmu.py"
"${CMAKE_CURRENT_SOURCE_DIR}/instantiated_model.py"
"${CMAKE_CURRENT_SOURCE_DIR}/namespace.py"
"${CMAKE_CURRENT_SOURCE_DIR}/settings.py"
"${CMAKE_CURRENT_SOURCE_DIR}/ssd.py"
Expand Down
23 changes: 19 additions & 4 deletions src/OMSimulatorPython/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
OpenModelica FMI & SSP based simulator.
'''

from OMSimulator.capi import Capi
from OMSimulator.connection import Connection
from OMSimulator.connector import Connector
from OMSimulator.cref import CRef
Expand All @@ -14,11 +15,25 @@
from OMSimulator.ssv import SSV
from OMSimulator.system import System
from OMSimulator.variable import Causality, SignalType, Variable

from OMSimulator import capi
from OMSimulator.instantiated_model import InstantiatedModel

# Define public API
__all__ = ['Connection', 'Connector', 'CRef', 'FMU', 'Settings', 'SSD', 'SSP', 'SSV', 'System', 'Causality', 'SignalType', 'Variable']
__all__ = [
'Capi',
'Causality',
'Connection',
'Connector',
'CRef',
'FMU',
'InstantiatedModel',
'Settings',
'SignalType',
'SSD',
'SSP',
'SSV',
'System',
'Variable',
]

__version__ = '@OMS_SHORT_VERSION_STRING@'
__author__ = 'Open Source Modelica Consortium (OSMC)'
Expand All @@ -28,4 +43,4 @@
c/o Linköpings universitet, Department of Computer and Information Science,
SE-58183 Linköping, Sweden.'''

version = capi.capi().getVersion()
version = Capi.getVersion()
425 changes: 54 additions & 371 deletions src/OMSimulatorPython/capi.py

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions src/OMSimulatorPython/instantiated_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from OMSimulator.capi import Capi, Status

class InstantiatedModel:
def __init__(self, json_description):
print(json_description)
self.model, status = Capi.instantiateFromJson(json_description)
if status != Status.ok:
raise RuntimeError(f"Failed to instantiate model: {status}")

def setValues(self):
pass

def getValues(self):
pass

def initialize(self):
status = Capi.initialize(self.model)
if status != Status.ok:
raise RuntimeError(f"Failed to initialize model: {status}")

def simulate(self):
status = Capi.simulate(self.model)
if status != Status.ok:
raise RuntimeError(f"Failed to simulate model: {status}")

def stepUntil(self, stopTime):
status = Capi.stepUntil(self.model, stopTime)
if status != Status.ok:
raise RuntimeError(f"Failed to step until {stopTime}: {status}")

def terminate(self):
status = Capi.terminate(self.model)
if status != Status.ok:
raise RuntimeError(f"Failed to terminate model: {status}")
19 changes: 9 additions & 10 deletions src/OMSimulatorPython/system.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import json
import logging
from collections import defaultdict

from lxml import etree as ET
from OMSimulator.component import Component
from OMSimulator.connector import Connector
from OMSimulator.connection import Connection
from OMSimulator.connector import Connector
from OMSimulator.elementgeometry import ElementGeometry
from OMSimulator.fmu import FMU
from OMSimulator.values import Values
from OMSimulator.instantiated_model import InstantiatedModel
from OMSimulator.ssv import SSV
from OMSimulator.elementgeometry import ElementGeometry

from OMSimulator import CRef, namespace, utils
from OMSimulator.values import Values

from collections import defaultdict
import json
from OMSimulator import Capi, CRef, namespace, utils

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -268,7 +268,7 @@ def setSolver(self, cref: CRef, name: str):
raise ValueError(f"Component '{first}' not found in {self.name}")
self.elements[first].setSolver(name)

def instantiate(self):
def instantiate(self) -> InstantiatedModel:
"""Instantiates the system and its components."""
data = {
"simulation units": []
Expand Down Expand Up @@ -304,8 +304,7 @@ def instantiate(self):

# Dump JSON
json_string = json.dumps(data, indent=2)
print(json_string)

return InstantiatedModel(json_string)

def processElements(self, elements_dict: dict, connections: list, data: dict, solver_groups : defaultdict, componentSolver : dict, solver_connections : defaultdict, systemName = None):
"""Processes the elements and connections in the system."""
Expand Down
8 changes: 6 additions & 2 deletions testsuite/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

all: difftool resources test

test: api.log parker.log dcmotor.log
test: api.log parker.log dcmotor.log simulation.log

partest: difftool resources
cd partest && time ./runtests.pl -nocolour -with-xml
Expand All @@ -23,4 +23,8 @@ parker.log: difftool

dcmotor.log: difftool
@$(MAKE) -C dcmotor -f Makefile test > $@
@grep == dcmotor.log
@grep == dcmotor.log

simulation.log: difftool
@$(MAKE) -C simulation -f Makefile test > $@
@grep == simulation.log
3 changes: 0 additions & 3 deletions testsuite/api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ TEST = ../rtest -v
TESTFILES = \
create_ssp_file.py \
cref.py \
exportJson1.py \
exportJson2.py \
exportJson4.py \
fmuinfo.py \
invalidSSD.py \
invalidSSV.py \
Expand Down
67 changes: 67 additions & 0 deletions testsuite/resources/sim.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"simulation units": [
{
"components": [
{
"name": "Controller",
"type": "FMI 2 CS",
"path": "resources/Controller.fmu",
"variables": ["output"]
}
],
"solver": {
"type": "co-simulation"
},
"connections": []
},
{
"components": [
{
"name": "Plant",
"type": "model exchange",
"path": "resources/Plant.fmu",
"variables": ["input", "output"]
},
{
"name": "Sensor",
"type": "model exchange",
"path": "resources/Sensor.fmu",
"variables": ["output"]
}
],
"solver": {
"type": "CVODE",
"stepSize": 0.01,
"tolerance": 1e-5
},
"connections": [
{
"start element": "Sensor",
"start connector": "output",
"end element": "Plant",
"end connector": "input"
}
]
}
],
"connections": [
{
"start element": "Controller",
"start connector": "output",
"end element": "Plant",
"end connector": "input"
},
{
"start element": "Sensor",
"start connector": "output",
"end element": "Controller",
"end connector": "input"
}
],
"result file": "simulation_result.csv",
"simulation settings": {
"start time": 0.0,
"stop time": 10.0,
"tolerance": 1e-6
}
}
33 changes: 33 additions & 0 deletions testsuite/resources/sim_singleFMU.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"temp dir": "temp",
"working dir": "working",
"simulation units": [
{
"components": [
{
"name": "",
"type": "FMI 2 ME",
"path": "resources/Controller.fmu",
"variables": {
"output": 15,
"state1": 0
}
}
],
"solver": {
"type": "model exchange",
"solver": "CVODE",
"stepSize": 0.01,
"tolerance": 1e-5
},
"connections": []
}
],
"connections": [],
"result file": "simulation_result.csv",
"simulation settings": {
"start time": 0.0,
"stop time": 10.0,
"tolerance": 1e-6
}
}
55 changes: 55 additions & 0 deletions testsuite/simulation/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
TEST = ../rtest -v

TESTFILES = \
exportJson1.py \
exportJson2.py \
exportJson3.py \
exportJson4.py \
SimpleSimulation.py \

# Run make failingtest
FAILINGTESTFILES = \

# Dependency files that are not .lua or Makefile
# Add them here or they will be cleaned.
DEPENDENCIES = \
*.lua \
*.py \
Makefile \

CLEAN = `ls | grep -w -v -f deps.tmp`

.PHONY : test clean getdeps failingtest

test:
@echo
@echo Running tests...
@$(TEST) $(TESTFILES)

baseline:
@echo
@echo Updating badelines...
@$(TEST) -b $(TESTFILES)

# Cleans all files that are not listed as dependencies
clean:
@echo $(DEPENDENCIES) | sed 's/ /\\\|/g' > deps.tmp
@rm -rf $(CLEAN)

# Run this if you want to list out the files (dependencies).
# do it after cleaning and updating the folder
# then you can get a list of file names (which must be dependencies
# since you got them from repository + your own new files)
# then add them to the DEPENDENCIES. You can find the
# list in deps.txt
getdeps:
@echo $(DEPENDENCIES) | sed 's/ /\\\|/g' > deps.tmp
@echo $(CLEAN) | sed -r 's/deps.txt|deps.tmp//g' | sed 's/ / \\\n/g' > deps.txt
@echo Dependency list saved in deps.txt.
@echo Copy the list from deps.txt and add it to the Makefile @DEPENDENCIES

failingtest:
@echo
@echo Running failing tests...
@echo
@$(TEST) $(FAILINGTESTFILES)
Loading