1111
1212import numpy as np
1313
14- from sim_explorer .json5 import Json5
14+ from sim_explorer .utils . json5 import json5_read
1515from sim_explorer .utils .misc import from_xml , match_with_wildcard
1616from sim_explorer .utils .osp import read_system_structure_xml
1717from 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 } " ,
0 commit comments