Skip to content

Commit 78063ff

Browse files
Fixing bug with result storing of bool and enums (#356)
1 parent c1972d7 commit 78063ff

File tree

6 files changed

+91
-5
lines changed

6 files changed

+91
-5
lines changed

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
--- CHANGELOG ---
22
--- PyFMI-FUTURE ---
33

4+
--- PyFMI-2.18.3 ---
5+
* Fixed a bug introduced in PyFMI 2.18.0 causing incorrect result storing for `boolean` and `enum` variables
6+
with `result_handling = "binary"` (default).
7+
48
--- PyFMI-2.18.2 ---
59
* Fixed an issue with `ResultDymolaBinary` result retrieval if `dynamic_diagnostics = True` and
610
there is only a single solution point.

doc/sphinx/source/changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
==========
33
Changelog
44
==========
5+
--- PyFMI-2.18.3 ---
6+
* Fixed a bug introduced in PyFMI 2.18.0 causing incorrect result storage for `boolean` and `enum` variables
7+
with `result_handling = "binary"` (default).
8+
59
--- PyFMI-2.18.2 ---
610
* Fixed an issue with `ResultDymolaBinary` result retrieval if `dynamic_diagnostics = True` and
711
there is only a single solution point.

doc/sphinx/source/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@
5151
# built documents.
5252
#
5353
# The short X.Y version.
54-
version = '2.18.2'
54+
version = '2.18.3'
5555
# The full version, including alpha/beta/rc tags.
56-
release = '2.18.2'
56+
release = '2.18.3'
5757

5858
# The language for content autogenerated by Sphinx. Refer to documentation
5959
# for a list of supported languages.

src/common/io.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2896,8 +2896,8 @@ def _get_sorted_vars(self):
28962896
data_types = [
28972897
fmi.FMI_REAL,
28982898
fmi.FMI_INTEGER,
2899+
fmi.FMI_ENUMERATION,
28992900
fmi.FMI_BOOLEAN,
2900-
fmi.FMI_ENUMERATION
29012901
]
29022902

29032903
for data_type in data_types:

tests/conftest.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,30 @@ def download_url(url, save_file_to):
4848

4949
with ZipFile(zip_path, 'r') as zf:
5050
for fobj in zf.filelist:
51-
# For now, only unpack FMI 3.0 FMUs
52-
if (fobj.filename.startswith('3.0') or fobj.filename.startswith('2.0')) and fobj.filename.endswith('.fmu'):
51+
if fobj.filename.startswith('3.0') and fobj.filename.endswith('.fmu'):
52+
zf.extract(fobj, zip_unzip_to)
53+
with open(md5_file, 'w') as f:
54+
f.write(md5)
55+
# NOTE: FMI2 Feedthrough.fmu is broken in v0.0.39; use v0.0.38 for FMI2 instead
56+
# Remove the code below with new reference FMU version
57+
zip_file_url = "https://github.com/modelica/Reference-FMUs/releases/download/v0.0.38/Reference-FMUs-0.0.38.zip"
58+
zip_file_name = 'reference_fmus.zip'
59+
zip_unzip_to = files_directory / 'reference_fmus'
60+
md5 = hashlib.md5(zip_file_url.encode("utf-8")).hexdigest()
61+
md5_file = Path(zip_unzip_to) / 'metadata_0_0_38' # Expected file
62+
use_already_existing = False
63+
if md5_file.exists():
64+
with open(md5_file, 'r') as f:
65+
use_already_existing = md5 == f.read()
66+
67+
if not use_already_existing:
68+
with TemporaryDirectory() as tmpdirname:
69+
zip_path = Path(tmpdirname) / zip_file_name
70+
download_url(zip_file_url, zip_path)
71+
72+
with ZipFile(zip_path, 'r') as zf:
73+
for fobj in zf.filelist:
74+
if fobj.filename.startswith('2.0') and fobj.filename.endswith('.fmu'):
5375
zf.extract(fobj, zip_unzip_to)
5476
with open(md5_file, 'w') as f:
5577
f.write(md5)

tests/test_io.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
from io import StringIO, BytesIO
2525
from collections import OrderedDict
2626

27+
from pyfmi import load_fmu
28+
2729
from pyfmi.fmi import (
2830
FMUException,
2931
FMUModelME2,
@@ -63,6 +65,7 @@
6365

6466
this_dir = Path(__file__).parent.absolute()
6567
FMI3_REF_FMU_PATH = Path(this_dir) / 'files' / 'reference_fmus' / '3.0'
68+
FMI2_REF_FMU_PATH = Path(this_dir) / 'files' / 'reference_fmus' / '2.0'
6669
file_path = os.path.dirname(os.path.abspath(__file__))
6770

6871
def _run_negated_alias(model, result_type, result_file_name=""):
@@ -2299,3 +2302,56 @@ def test_basic_class_functions(get_fmu, result_handling, expected_result_class):
22992302
assert isinstance(trajs, dict)
23002303
traj = trajs.get("time")
23012304
assert isinstance(traj, Trajectory)
2305+
2306+
@pytest.mark.parametrize("fmu_path, result_handling",
2307+
[
2308+
(FMI2_REF_FMU_PATH / "Feedthrough.fmu", "file"),
2309+
(FMI2_REF_FMU_PATH / "Feedthrough.fmu", "binary"),
2310+
(FMI2_REF_FMU_PATH / "Feedthrough.fmu", "memory"),
2311+
(FMI2_REF_FMU_PATH / "Feedthrough.fmu", "csv"),
2312+
2313+
(FMI3_REF_FMU_PATH / "Feedthrough.fmu", "binary"),
2314+
]
2315+
)
2316+
def test_basic_variable_get_set_result_correctness(fmu_path, result_handling):
2317+
"""Test that basic get/set and result values align for the different variable types."""
2318+
fmu = load_fmu(fmu_path)
2319+
fmu.initialize()
2320+
# non-default values
2321+
bool_val = True
2322+
int32_val = 15
2323+
float64_val = 3.14
2324+
enum_val = 2
2325+
2326+
# verify values are not the defaults
2327+
assert fmu.get("Boolean_input")[0] != bool_val
2328+
assert fmu.get("Int32_input")[0] != int32_val
2329+
assert fmu.get("Float64_continuous_input")[0] != float64_val
2330+
assert fmu.get("Enumeration_input")[0] != enum_val
2331+
2332+
fmu.set("Boolean_input", bool_val)
2333+
fmu.set("Int32_input", int32_val)
2334+
fmu.set("Float64_continuous_input", float64_val)
2335+
fmu.set("Enumeration_input", enum_val)
2336+
2337+
# verify get/set
2338+
assert fmu.get("Boolean_input")[0] == bool_val
2339+
assert fmu.get("Int32_input")[0] == int32_val
2340+
assert fmu.get("Float64_continuous_input")[0] == float64_val
2341+
assert fmu.get("Enumeration_input")[0] == enum_val
2342+
2343+
fmu.event_update()
2344+
fmu.enter_continuous_time_mode()
2345+
opts = {"ncp": 2, "initialize": False, "result_handling": result_handling}
2346+
res = fmu.simulate(options = opts)
2347+
2348+
# verify simulation didn't change value
2349+
assert fmu.get("Boolean_input")[0] == bool_val
2350+
assert fmu.get("Int32_input")[0] == int32_val
2351+
assert fmu.get("Float64_continuous_input")[0] == float64_val
2352+
assert fmu.get("Enumeration_input")[0] == enum_val
2353+
2354+
assert res["Boolean_input"][-1] == bool_val
2355+
assert res["Int32_input"][-1] == int32_val
2356+
assert res["Float64_continuous_input"][-1] == float64_val
2357+
assert res["Enumeration_input"][-1] == enum_val

0 commit comments

Comments
 (0)