Skip to content

Commit e449e0f

Browse files
committed
Part 1
1 parent 1dbba8e commit e449e0f

16 files changed

Lines changed: 450 additions & 900 deletions

pyproject.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ dependencies = [
7373
"plotly>=6.5",
7474
"pydantic>=2.12",
7575
"rich>=13.9.4",
76+
"pyjson5>=1.6.8",
7677
]
7778

7879
[project.optional-dependencies]
@@ -83,9 +84,6 @@ test = [
8384
rest = [
8485
"docutils>=0.22.4",
8586
]
86-
editor = [
87-
"thonny>=4.1",
88-
]
8987

9088
[project.urls]
9189
Homepage = "https://github.com/dnv-opensource/sim-explorer"

src/sim_explorer/case.py

Lines changed: 89 additions & 169 deletions
Large diffs are not rendered by default.

src/sim_explorer/json5.py

Lines changed: 0 additions & 664 deletions
This file was deleted.

src/sim_explorer/system_interface.py

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import numpy as np
1313

14-
from sim_explorer.json5 import Json5
14+
from sim_explorer.utils.json5 import json5_read
1515
from sim_explorer.utils.misc import from_xml, match_with_wildcard
1616
from sim_explorer.utils.osp import read_system_structure_xml
1717
from sim_explorer.utils.types import TActionArgs, TGetActionArgs, TSetActionArgs, TValue
@@ -92,7 +92,7 @@ def read_system_structure(
9292
if file.suffix == ".xml": # assume the standard OspSystemStructure.xml file
9393
system_structure = read_system_structure_xml(file)
9494
elif file.suffix in (".js5", ".json"): # assume the js5 variant of the OspSystemStructure
95-
system_structure = Json5(file).js_py
95+
system_structure = json5_read(file)
9696
elif file.suffix == ".ssp":
9797
# see https://ssp-standard.org/publications/SSP10/SystemStructureAndParameterization10.pdf
9898
raise NotImplementedError("The SSP file variant is not yet implemented") from None
@@ -313,15 +313,14 @@ def pytype(fmu_type: str, val: TValue | None = None) -> type | bool:
313313
return typ(val)
314314

315315
@staticmethod
316-
def default_initial(
316+
def valid_initial(
317317
causality: str,
318318
variability: str,
319-
*,
320-
only_default: bool = True,
321-
) -> str | int | tuple[int] | tuple[str, ...]:
322-
"""Return default initial setting as str. See p.50 FMI2.
323-
With only_default, the single allowed value, or '' is returned.
324-
Otherwise a tuple of possible values is returned where the default value is always listed first.
319+
) -> tuple[str, ...]:
320+
"""Return valid initial setting as tuple of str. See p.50 FMI2.
321+
The default value is always listed first in the tuple.
322+
The empty string denotes 'no initial setting'.
323+
'ERROR' denotes that the combination causality/variability is invalid.
325324
"""
326325
col: int = {
327326
"parameter": 0,
@@ -347,16 +346,20 @@ def default_initial(
347346
(-2, -2, 5, 8, 13, -3),
348347
(-2, -2, 6, 9, 14, 15),
349348
)[row][col]
350-
349+
res: tuple[str, ...]
351350
if init < 0: # "Unallowed combination {variability}, {causality}. See '{chr(96-init)}' in FMI standard"
352-
return init if only_default else (init,)
353-
if init in {1, 2, 7, 10}:
354-
return "exact" if only_default else ("exact",)
355-
if init in {3, 4, 11, 12}:
356-
return "calculated" if only_default else ("calculated", "approx")
357-
if init in {8, 9, 13, 14}:
358-
return "calculated" if only_default else ("calculated", "exact", "approx")
359-
return init if only_default else (init,)
351+
res = (f"ERROR_{chr(96 - init)}",)
352+
elif init in (1, 2, 7, 10):
353+
res = ("exact",)
354+
elif init in (3, 4, 11, 12):
355+
res = ("calculated", "approx")
356+
elif init in (8, 9, 13, 14):
357+
res = ("calculated", "exact", "approx")
358+
elif init in (5, 6, 15): # combination valid, but initial shall not be provided
359+
res = ("",)
360+
else:
361+
raise ValueError(f"Unknown init index {init}") from None
362+
return res
360363

361364
def allowed_action( # noqa: C901
362365
self,
@@ -397,15 +400,20 @@ def _check(*, cond: bool, msg: str) -> bool:
397400
return False
398401
return True
399402

400-
_type, _causality, _variability = ("", "", "") # unknown
403+
_type, _causality, _variability, _initial = ("", "", "", "") # unknown
401404

402405
variables = self.variables(comp)
403406
for name, var_info in self.variable_iter(variables=variables, flt=var):
407+
assert isinstance(name, str), "str expected. Found {name}"
408+
assert isinstance(var_info, dict), f"Dict expected as var_info. Found {var_info}"
404409
if _type == "" or _causality == "" or _variability == "": # define the properties and check whether allowed
405410
_type = var_info["type"]
406411
_causality = var_info["causality"]
407412
_variability = var_info["variability"]
408-
_initial = var_info.get("initial", SystemInterface.default_initial(_causality, _variability))
413+
_initial = var_info.get("initial", SystemInterface.valid_initial(_causality, _variability)[0])
414+
assert not _initial.startswith("ERROR"), (
415+
f"Invalid combination of causality {_causality}-variability {_variability}: {_initial}"
416+
)
409417
if action in {"get", "step"}: # no restrictions on get
410418
pass
411419
elif action == "set" and (
@@ -434,7 +442,7 @@ def _check(*, cond: bool, msg: str) -> bool:
434442
return False
435443
# additional rule for ModelExchange, not listed here
436444
else: # check whether the properties are equal
437-
_initial = var_info.get("initial", SystemInterface.default_initial(_causality, _variability))
445+
_initial = var_info.get("initial", SystemInterface.valid_initial(_causality, _variability))
438446
if not _check(
439447
cond=_type == var_info["type"],
440448
msg=f"{_description(name=name, info=var_info, initial=_initial)} != type {_type}",

src/sim_explorer/system_interface_osp.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
from collections.abc import Callable
23
from functools import partial
34
from pathlib import Path
@@ -11,6 +12,8 @@
1112
from sim_explorer.system_interface import SystemInterface
1213
from sim_explorer.utils.types import TActionArgs
1314

15+
logger = logging.getLogger(__name__)
16+
1417

1518
class SystemInterfaceOSP(SystemInterface):
1619
"""Implements the SystemInterface as a OSP.

0 commit comments

Comments
 (0)