Description
The while loops used to wrap the input u for periodic extrapolation in several functions like ModelicaTableAdditions_CombiTable1D_getValue() can cause severe performance issues and, in extreme cases, infinite loops.
Code Reference
In ModelicaTableAdditions_CombiTable1D_getValue():
/* Periodic extrapolation */
if (tableID->extrapolation == PERIODIC) {
const double T = uMax - uMin;
if (u < uMin) {
do {
u += T;
} while (u < uMin);
}
else if (u > uMax) {
do {
u -= T;
} while (u > uMax);
}
last = findRowIndex(table, nRow, nCol, tableID->last, u);
tableID->last = last;
}
Impact & Root Cause
- Performance Bottleneck: With a large value for
u, the loop can take a significant amount of time. This can happen during step-size adjustments even in well-behaved models.
- Infinite Loop: As
u and T are double-precision floats, they are limited by a 53-bit mantissa. If the absolute value of u is larger than T * 2^53, adding or subtracting T has no effect on the value of u, resulting in an endless loop that will freeze the whole simulation.
Proposed Solution
This O(n) logic can be replaced with an O(1) modulo operation using fmod. This eliminates both the performance penalty and the floating-point infinite loop risk.
For example:
/* Periodic extrapolation */
if (tableID->extrapolation == PERIODIC) {
const double T = uMax - uMin;
if (u < uMin || u > uMax) {
double rem = fmod(u - uMin, T);
/* fmod can return negative values, so adjust to strictly positive modulo */
if (rem < 0.0) {
rem += T;
}
u = uMin + rem;
}
last = findRowIndex(table, nRow, nCol, tableID->last, u);
tableID->last = last;
}
Mitigation
This loop can be avoided in Modelica by adding the modulus operation to the assignment of the table input u directly.
From:
table.u = <equation for u>;
To:;
table.u = table.u_min + mod(<equation_for_u>, table.u_max - table.u_min);
If the table is continuously periodic, a noEvent(...) can be added around the modulus to avoid triggering of unnecessary events.
Description
The
whileloops used to wrap the inputufor periodic extrapolation in several functions likeModelicaTableAdditions_CombiTable1D_getValue()can cause severe performance issues and, in extreme cases, infinite loops.Code Reference
In
ModelicaTableAdditions_CombiTable1D_getValue():Impact & Root Cause
u, the loop can take a significant amount of time. This can happen during step-size adjustments even in well-behaved models.uandTare double-precision floats, they are limited by a 53-bit mantissa. If the absolute value ofuis larger thanT * 2^53, adding or subtractingThas no effect on the value ofu, resulting in an endless loop that will freeze the whole simulation.Proposed Solution
This O(n) logic can be replaced with an O(1) modulo operation using
fmod. This eliminates both the performance penalty and the floating-point infinite loop risk.For example:
Mitigation
This loop can be avoided in Modelica by adding the modulus operation to the assignment of the table input
udirectly.From:
To:;
If the table is continuously periodic, a
noEvent(...)can be added around the modulus to avoid triggering of unnecessary events.