From 3228d2941933d26d844ccd4d9f5cfb9bc2ff5db7 Mon Sep 17 00:00:00 2001 From: Torsten Sommer Date: Tue, 5 May 2026 09:49:00 +0200 Subject: [PATCH] Fix handling of relative quantities fixes #865 --- src/fmpy/model_description.py | 25 +++++++++++++++++-------- src/fmpy/simulation.py | 21 ++++++++++++++++----- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/fmpy/model_description.py b/src/fmpy/model_description.py index 744270f2..121a245f 100644 --- a/src/fmpy/model_description.py +++ b/src/fmpy/model_description.py @@ -136,7 +136,7 @@ class SimpleType: quantity: str | None = field(default=None, repr=False) unit: str | None = None displayUnit: str | None = field(default=None, repr=False) - relativeQuantity: str | None = field(default=None, repr=False) + relativeQuantity: bool = field(default=False, repr=False) min: str | None = field(default=None, repr=False) max: str | None = field(default=None, repr=False) nominal: str | None = field(default=None, repr=False) @@ -253,7 +253,7 @@ class ModelVariable: displayUnit: str | None = field(default=None, repr=False) "Default display unit" - relativeQuantity: bool = field(default=False, repr=False) + relativeQuantity: bool | None = field(default=None, repr=False) "Relative quantity" min: str | None = field(default=None, repr=False) @@ -738,10 +738,14 @@ def get_fmu_state_attributes(element, object): first = t[0] # first element + attrib = dict(first.attrib) + + attrib["relativeQuantity"] = attrib.get("relativeQuantity") in {"true", "1"} + simple_type = SimpleType( name=t.get('name'), type=first.tag[:-len('Type')] if is_fmi1 else first.tag, - **dict(first.attrib) + **attrib ) # add enumeration items @@ -762,7 +766,11 @@ def get_fmu_state_attributes(element, object): 'EnumerationType'}: continue - simple_type = SimpleType(type=t.tag[:-4], **dict(t.attrib)) + attrib = dict(t.attrib) + + attrib["relativeQuantity"] = attrib.get("relativeQuantity") in {"true", "1"} + + simple_type = SimpleType(type=t.tag[:-4], **attrib) # add enumeration items for item in t.findall('Item'): @@ -850,7 +858,8 @@ def get_fmu_state_attributes(element, object): if sv.type in ['Real', 'Float32', 'Float64']: sv.unit = value.get('unit') sv.displayUnit = value.get('displayUnit') - sv.relativeQuantity = value.get('relativeQuantity') in {'true', '1'} + if "relativeQuantity" in value: + sv.relativeQuantity = value.get('relativeQuantity') in {'true', '1'} sv.derivative = value.get('derivative') sv.nominal = value.get('nominal') sv.unbounded = value.get('unbounded') in {'true', '1'} @@ -1147,7 +1156,7 @@ def set_attributes(element, object, attributes): ("quantity", None), ("unit", None), ("displayUnit", None), - ("relativeQuantity", None), + ("relativeQuantity", False), ("min", None), ("max", None), ("nominal", None), @@ -1208,7 +1217,7 @@ def set_attributes(element, object, attributes): ("quantity", None), ("unit", None), ("displayUnit", None), - ("relativeQuantity", False), + ("relativeQuantity", None), ("min", None), ("max", None), ("nominal", None), @@ -1387,7 +1396,7 @@ def set_attributes(element, object, attributes): ("quantity", None), ("unit", None), ("displayUnit", None), - ("relativeQuantity", None), + ("relativeQuantity", False), ("min", None), ("max", None), ("nominal", None), diff --git a/src/fmpy/simulation.py b/src/fmpy/simulation.py index e4be7058..686ced21 100644 --- a/src/fmpy/simulation.py +++ b/src/fmpy/simulation.py @@ -500,9 +500,9 @@ def apply_start_values(fmu, model_description, start_values, settable=None): unit = None if unit is None or unit == variable.unit: - pass + ... elif variable.declaredType is not None and unit == variable.declaredType.unit: - pass + ... else: if variable.unit is not None: base_unit = variable.unit @@ -516,7 +516,18 @@ def apply_start_values(fmu, model_description, start_values, settable=None): raise Exception(f'The unit "{unit}" of the start value for variable {variable.name} is not defined.') display_unit = unit_definitions[base_unit][unit] - value = (value - display_unit.offset) / display_unit.factor + + is_relative_quantity = False + + if variable.relativeQuantity is not None: + is_relative_quantity = variable.relativeQuantity + elif variable.declaredType and variable.declaredType.relativeQuantity is not None: + is_relative_quantity = True + + if is_relative_quantity: + value = value / display_unit.factor + else: + value = (value - display_unit.offset) / display_unit.factor vr = variable.valueReference @@ -544,8 +555,8 @@ def apply_start_values(fmu, model_description, start_values, settable=None): value = value.split() value = list(map(lambda e: variable._python_type(e), value)) if len(value) != np.prod(variable.shape): - raise ArgumentError(f'The start value for variable "{variable.name}" must have' - f' {np.prod(variable.shape)} elements but has {len(value)}.') + raise Exception(f'The start value for variable "{variable.name}" must have' + f' {np.prod(variable.shape)} elements but has {len(value)}.') else: value = [variable._python_type(value)]