From affe46d525e970278bd0e9b7d86a25f2306fb02f Mon Sep 17 00:00:00 2001 From: Julien Schueller Date: Mon, 20 Jul 2026 16:44:58 +0200 Subject: [PATCH] fmi3_xml_parser: Allow INF values Closes #207 --- Test/FMI3/fmi3_import_variable_types_test.cpp | 53 +++++++++++++++++++ .../inf_start/modelDescription.xml | 13 +++++ src/XML/src/FMI3/fmi3_xml_parser.c | 19 +++++++ 3 files changed, 85 insertions(+) create mode 100644 Test/FMI3/parser_test_xmls/variable_types/inf_start/modelDescription.xml diff --git a/Test/FMI3/fmi3_import_variable_types_test.cpp b/Test/FMI3/fmi3_import_variable_types_test.cpp index a77cd26d..0389fb69 100644 --- a/Test/FMI3/fmi3_import_variable_types_test.cpp +++ b/Test/FMI3/fmi3_import_variable_types_test.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "fmilib.h" #include "config_test.h" @@ -129,3 +130,55 @@ TEST_CASE("Varibles types testing") { REQUIRE(fmi3_testutil_get_num_problems(tfmu) == 0); fmi3_testutil_import_free(tfmu); } + +/* Parse INF start values */ +static void test_inf_float64_positive(fmi3_import_t* xml) { + fmi3_import_variable_t* v = fmi3_import_get_variable_by_name(xml, "var1"); + REQUIRE(v != nullptr); + fmi3_import_float64_variable_t* var = fmi3_import_get_variable_as_float64(v); + REQUIRE(var != nullptr); + REQUIRE(std::isinf(fmi3_import_get_float64_variable_start(var))); + REQUIRE(fmi3_import_get_float64_variable_start(var) > 0); +} + +static void test_inf_float64_negative(fmi3_import_t* xml) { + fmi3_import_variable_t* v = fmi3_import_get_variable_by_name(xml, "var2"); + REQUIRE(v != nullptr); + fmi3_import_float64_variable_t* var = fmi3_import_get_variable_as_float64(v); + REQUIRE(var != nullptr); + REQUIRE(std::isinf(fmi3_import_get_float64_variable_start(var))); + REQUIRE(fmi3_import_get_float64_variable_start(var) < 0); +} + +static void test_inf_float32_positive(fmi3_import_t* xml) { + fmi3_import_variable_t* v = fmi3_import_get_variable_by_name(xml, "var3"); + REQUIRE(v != nullptr); + fmi3_import_float32_variable_t* var = fmi3_import_get_variable_as_float32(v); + REQUIRE(var != nullptr); + REQUIRE(std::isinf(fmi3_import_get_float32_variable_start(var))); + REQUIRE(fmi3_import_get_float32_variable_start(var) > 0); +} + +static void test_inf_float32_negative(fmi3_import_t* xml) { + fmi3_import_variable_t* v = fmi3_import_get_variable_by_name(xml, "var4"); + REQUIRE(v != nullptr); + fmi3_import_float32_variable_t* var = fmi3_import_get_variable_as_float32(v); + REQUIRE(var != nullptr); + REQUIRE(std::isinf(fmi3_import_get_float32_variable_start(var))); + REQUIRE(fmi3_import_get_float32_variable_start(var) < 0); +} + +TEST_CASE("INF start values") { + const char* xmldir = FMI3_TEST_XML_DIR "/variable_types/inf_start"; + fmi3_testutil_import_t* tfmu = fmi3_testutil_parse_xml_with_log(xmldir); + fmi3_import_t* fmu = tfmu->fmu; + REQUIRE(fmu != nullptr); + + test_inf_float64_positive(fmu); + test_inf_float64_negative(fmu); + test_inf_float32_positive(fmu); + test_inf_float32_negative(fmu); + + REQUIRE(fmi3_testutil_get_num_problems(tfmu) == 0); + fmi3_testutil_import_free(tfmu); +} diff --git a/Test/FMI3/parser_test_xmls/variable_types/inf_start/modelDescription.xml b/Test/FMI3/parser_test_xmls/variable_types/inf_start/modelDescription.xml new file mode 100644 index 00000000..39644c69 --- /dev/null +++ b/Test/FMI3/parser_test_xmls/variable_types/inf_start/modelDescription.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/XML/src/FMI3/fmi3_xml_parser.c b/src/XML/src/FMI3/fmi3_xml_parser.c index 73dcb26d..59ba4a00 100644 --- a/src/XML/src/FMI3/fmi3_xml_parser.c +++ b/src/XML/src/FMI3/fmi3_xml_parser.c @@ -623,6 +623,12 @@ static int fmi3_xml_str_to_floatXX(fmi3_xml_parser_context_t* context, int requi void* value = NULL; /* points to the buffer that holds the value: default or read */ int status = 0; /* status flag for value boundary check */ + /* detect INF values - allow them to skip the boundary check */ + int isInf = 0; + if (strVal) { + isInf = (strcmp(strVal, "INF") == 0 || strcmp(strVal, "+INF") == 0 || strcmp(strVal, "-INF") == 0); + } + /* get the value */ if (!strVal && !required) { value = defaultVal; @@ -634,6 +640,19 @@ static int fmi3_xml_str_to_floatXX(fmi3_xml_parser_context_t* context, int requi value = &valReadBuff; } + if (isInf) { + /* INF values are valid per FMI spec; assign directly without boundary check */ + switch(primType->bitness) { + case fmi3_bitness_64: + *(fmi3_float64_t*)field = (fmi3_float64_t)valReadBuff; break; + case fmi3_bitness_32: + *(fmi3_float32_t*)field = (fmi3_float32_t)valReadBuff; break; + default: + assert(0); /* impl. error */ + } + return 0; + } + /* downcast */ switch(primType->bitness) { case fmi3_bitness_64: