Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix outputs in generated modelDescription.xml #87

Merged
merged 6 commits into from
Dec 19, 2024
Merged
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
All notable changes to the [mlfmu] project will be documented in this file.<br>
The changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## Unreleased

### Changed

* Generation of modelDescription.xml file to correctly generate tags for each output with 1-indexed indexes and InitialUnknowns tags
* Generation of modelDescription.xml adds the variables (inputs, parameters and outputs) in the orderer of their valueReference. This is for the indexing to work correctly

## [1.0.2]

### Changed
Expand Down
18 changes: 15 additions & 3 deletions src/mlfmu/utils/fmi_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,16 @@ def generate_model_description(fmu_model: FmiModel) -> ElementTree:
# <ModelStructure> tag with <Outputs> tab inside --> Append all outputs
model_structure = SubElement(root, "ModelStructure")
outputs = SubElement(model_structure, "Outputs")
initial_unknowns = SubElement(model_structure, "InitialUnknowns")

for var in fmu_model.get_fmi_model_variables():
# Get all variables to add them inside the <ModelVariables> tag
model_variables = fmu_model.get_fmi_model_variables()

# The variables needs to be added in the order of their valueReference
sorted_model_variables = sorted(model_variables, key=lambda x: x.variable_reference)

# Add each variable inside the <ModelVariables> tag
for var in sorted_model_variables:
# XML variable attributes
var_attrs = {
"name": var.name,
Expand All @@ -95,9 +103,13 @@ def generate_model_description(fmu_model: FmiModel) -> ElementTree:
# FMI variable type element
_ = SubElement(var_elem, var.type.value.capitalize(), var_type_attrs)

# Appending output to <Outputs> inside <ModelStructure>
# Adding outputs inside <ModelStructure>
if var.causality == FmiCausality.OUTPUT:
_ = SubElement(outputs, "Unknown", {"index": str(var.variable_reference)})
# Index is 1-indexed for <Unknown> tag
unknown_attributes = {"index": str(var.variable_reference + 1)}
# For each output create an <Unknown> tag inside both <Outputs> and <InitialUnknowns>
_ = SubElement(outputs, "Unknown", unknown_attributes)
_ = SubElement(initial_unknowns, "Unknown", unknown_attributes)

# Create XML tree containing root element and pretty format its contents
xml_tree = ElementTree(root)
Expand Down
18 changes: 10 additions & 8 deletions tests/utils/test_modelDescription_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ def test_generate_model_description_with_internal_state_params():
variables = xml_structure.findall(".//ScalarVariable")

assert xml_structure.getroot().tag == "fmiModelDescription"
assert variables[0].attrib["name"] == "state1"
assert variables[0].attrib["causality"] == "parameter"
assert variables[0][0].tag == "Real"
assert variables[0][0].attrib["start"] == "0.0"

assert variables[1].attrib["name"] == "output1"
assert variables[1].attrib["causality"] == "output"
assert variables[0].attrib["name"] == "output1"
assert variables[0].attrib["causality"] == "output"

assert variables[1].attrib["name"] == "state1"
assert variables[1].attrib["causality"] == "parameter"
assert variables[1][0].tag == "Real"
assert variables[1][0].attrib["start"] == "0.0"


def test_generate_vector_ports():
Expand Down Expand Up @@ -193,5 +194,6 @@ def test_generate_model_description_output():
output_variables = [var for var in variables if var.attrib.get("causality") == "output"]
outputs_registered = xml_structure.findall(".//Outputs/Unknown")

assert output_variables[0].attrib["valueReference"] == outputs_registered[0].attrib["index"]
assert output_variables[1].attrib["valueReference"] == outputs_registered[1].attrib["index"]
# The index should be the valueReference + 1
assert int(output_variables[0].attrib["valueReference"]) + 1 == int(outputs_registered[0].attrib["index"])
assert int(output_variables[1].attrib["valueReference"]) + 1 == int(outputs_registered[1].attrib["index"])
Loading