Skip to content
Merged
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: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
--- CHANGELOG ---
--- PyFMI-FUTURE ---

--- PyFMI-2.18.3 ---
* Fixed a bug introduced in PyFMI 2.18.0 causing incorrect result storing for `boolean` and `enum` variables
with `result_handling = "binary"` (default).

--- PyFMI-2.18.2 ---
* Fixed an issue with `ResultDymolaBinary` result retrieval if `dynamic_diagnostics = True` and
there is only a single solution point.
Expand Down
4 changes: 4 additions & 0 deletions doc/sphinx/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
==========
Changelog
==========
--- PyFMI-2.18.3 ---
* Fixed a bug introduced in PyFMI 2.18.0 causing incorrect result storage for `boolean` and `enum` variables
with `result_handling = "binary"` (default).

--- PyFMI-2.18.2 ---
* Fixed an issue with `ResultDymolaBinary` result retrieval if `dynamic_diagnostics = True` and
there is only a single solution point.
Expand Down
4 changes: 2 additions & 2 deletions doc/sphinx/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@
# built documents.
#
# The short X.Y version.
version = '2.18.2'
version = '2.18.3'
# The full version, including alpha/beta/rc tags.
release = '2.18.2'
release = '2.18.3'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
2 changes: 1 addition & 1 deletion src/common/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -2896,8 +2896,8 @@ def _get_sorted_vars(self):
data_types = [
fmi.FMI_REAL,
fmi.FMI_INTEGER,
fmi.FMI_ENUMERATION,
fmi.FMI_BOOLEAN,
fmi.FMI_ENUMERATION
]

for data_type in data_types:
Expand Down
26 changes: 24 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,30 @@ def download_url(url, save_file_to):

with ZipFile(zip_path, 'r') as zf:
for fobj in zf.filelist:
# For now, only unpack FMI 3.0 FMUs
if (fobj.filename.startswith('3.0') or fobj.filename.startswith('2.0')) and fobj.filename.endswith('.fmu'):
if fobj.filename.startswith('3.0') and fobj.filename.endswith('.fmu'):
zf.extract(fobj, zip_unzip_to)
with open(md5_file, 'w') as f:
f.write(md5)
# NOTE: FMI2 Feedthrough.fmu is broken in v0.0.39; use v0.0.38 for FMI2 instead
# Remove the code below with new reference FMU version
zip_file_url = "https://github.com/modelica/Reference-FMUs/releases/download/v0.0.38/Reference-FMUs-0.0.38.zip"
zip_file_name = 'reference_fmus.zip'
zip_unzip_to = files_directory / 'reference_fmus'
md5 = hashlib.md5(zip_file_url.encode("utf-8")).hexdigest()
md5_file = Path(zip_unzip_to) / 'metadata_0_0_38' # Expected file
use_already_existing = False
if md5_file.exists():
with open(md5_file, 'r') as f:
use_already_existing = md5 == f.read()

if not use_already_existing:
with TemporaryDirectory() as tmpdirname:
zip_path = Path(tmpdirname) / zip_file_name
download_url(zip_file_url, zip_path)

with ZipFile(zip_path, 'r') as zf:
for fobj in zf.filelist:
if fobj.filename.startswith('2.0') and fobj.filename.endswith('.fmu'):
zf.extract(fobj, zip_unzip_to)
with open(md5_file, 'w') as f:
f.write(md5)
56 changes: 56 additions & 0 deletions tests/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
from io import StringIO, BytesIO
from collections import OrderedDict

from pyfmi import load_fmu

from pyfmi.fmi import (
FMUException,
FMUModelME2,
Expand Down Expand Up @@ -63,6 +65,7 @@

this_dir = Path(__file__).parent.absolute()
FMI3_REF_FMU_PATH = Path(this_dir) / 'files' / 'reference_fmus' / '3.0'
FMI2_REF_FMU_PATH = Path(this_dir) / 'files' / 'reference_fmus' / '2.0'
file_path = os.path.dirname(os.path.abspath(__file__))

def _run_negated_alias(model, result_type, result_file_name=""):
Expand Down Expand Up @@ -2299,3 +2302,56 @@ def test_basic_class_functions(get_fmu, result_handling, expected_result_class):
assert isinstance(trajs, dict)
traj = trajs.get("time")
assert isinstance(traj, Trajectory)

@pytest.mark.parametrize("fmu_path, result_handling",
[
(FMI2_REF_FMU_PATH / "Feedthrough.fmu", "file"),
(FMI2_REF_FMU_PATH / "Feedthrough.fmu", "binary"),
(FMI2_REF_FMU_PATH / "Feedthrough.fmu", "memory"),
(FMI2_REF_FMU_PATH / "Feedthrough.fmu", "csv"),

(FMI3_REF_FMU_PATH / "Feedthrough.fmu", "binary"),
]
)
def test_basic_variable_get_set_result_correctness(fmu_path, result_handling):
"""Test that basic get/set and result values align for the different variable types."""
fmu = load_fmu(fmu_path)
fmu.initialize()
# non-default values
bool_val = True
int32_val = 15
float64_val = 3.14
enum_val = 2

# verify values are not the defaults
assert fmu.get("Boolean_input")[0] != bool_val
assert fmu.get("Int32_input")[0] != int32_val
assert fmu.get("Float64_continuous_input")[0] != float64_val
assert fmu.get("Enumeration_input")[0] != enum_val

fmu.set("Boolean_input", bool_val)
fmu.set("Int32_input", int32_val)
fmu.set("Float64_continuous_input", float64_val)
fmu.set("Enumeration_input", enum_val)

# verify get/set
assert fmu.get("Boolean_input")[0] == bool_val
assert fmu.get("Int32_input")[0] == int32_val
assert fmu.get("Float64_continuous_input")[0] == float64_val
assert fmu.get("Enumeration_input")[0] == enum_val

fmu.event_update()
fmu.enter_continuous_time_mode()
opts = {"ncp": 2, "initialize": False, "result_handling": result_handling}
res = fmu.simulate(options = opts)

# verify simulation didn't change value
assert fmu.get("Boolean_input")[0] == bool_val
assert fmu.get("Int32_input")[0] == int32_val
assert fmu.get("Float64_continuous_input")[0] == float64_val
assert fmu.get("Enumeration_input")[0] == enum_val

assert res["Boolean_input"][-1] == bool_val
assert res["Int32_input"][-1] == int32_val
assert res["Float64_continuous_input"][-1] == float64_val
assert res["Enumeration_input"][-1] == enum_val