Skip to content

Commit

Permalink
Check rational arithmetic for overflow (#8504)
Browse files Browse the repository at this point in the history
* Check rational arithmetic for overflow

Also refactor clocked calculations

* Add comparison for rational with integer

* Use floor to compare rational with integer

The previous lessRatInt function could overflow
  • Loading branch information
phannebohm committed Feb 8, 2022
1 parent 9489298 commit 851ba5e
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 148 deletions.
2 changes: 1 addition & 1 deletion OMCompiler/Compiler/Template/CodegenC.tpl
Expand Up @@ -421,7 +421,7 @@ template makeCRational(Rational rational)
match rational
case RATIONAL(__) then
<<
(RATIONAL){<%nom%>, <%denom%>}
makeRATIONAL(<%nom%>, <%denom%>)
>>
end makeCRational;

Expand Down
61 changes: 26 additions & 35 deletions OMCompiler/SimulationRuntime/c/simulation/solver/synchronous.c
Expand Up @@ -60,7 +60,7 @@ void initSynchronous(DATA* data, threadData_t *threadData, modelica_real startTi
for(i=0; i<data->modelData->nBaseClocks; i++) {
for(j=0; j<data->simulationInfo->baseClocks[i].nSubClocks; j++) {
assertStreamPrint(threadData, data->simulationInfo->baseClocks[i].subClocks[j].solverMethod != NULL, "Continuous clocked systems aren't supported yet.");
assertStreamPrint(threadData, rat2Real(data->simulationInfo->baseClocks[i].subClocks[j].shift) >= 0, "Shift of sub-clock is negative. Sub-clocks aren't allowed to fire before base-clock.");
assertStreamPrint(threadData, floorRat(data->simulationInfo->baseClocks[i].subClocks[j].shift) >= 0, "Shift of sub-clock is negative. Sub-clocks aren't allowed to fire before base-clock.");
}
}

Expand Down Expand Up @@ -162,7 +162,7 @@ void checkForSynchronous(DATA *data, SOLVER_INFO* solverInfo)
modelica_boolean handleBaseClock(DATA* data, threadData_t *threadData, long idx, double curTime)
{
TRACE_PUSH
modelica_boolean frstSubClockIsBaseClock = 0 /* false */;
modelica_boolean frstSubClockIsBaseClock = 0 /* false */;

/* Special case for event-clocks activated at initialization */
if (data->simulationInfo->initial) {
Expand All @@ -179,13 +179,9 @@ modelica_boolean handleBaseClock(DATA* data, threadData_t *threadData, long idx,
SUBCLOCK_DATA* subClock;
SYNC_TIMER nextTimer, firstSubTimer;
SYNC_TIMER* nextSubTimer;
double nextBaseTime, nextSubTime, absoluteSubTime;
double subTimer, activationTime;
int i, k;

if (baseClock->subClocks[0].shift.m == 0 && baseClock->subClocks[0].factor.m == 1 && baseClock->subClocks[0].factor.n == 1) {
frstSubClockIsBaseClock = 1 /* true */;
}
double nextBaseTime, nextSubTime, absoluteSubTime, activationTime;
RATIONAL subTimer;
int i;

/* Update base clock */
baseClock->stats.count++;
Expand All @@ -198,14 +194,17 @@ modelica_boolean handleBaseClock(DATA* data, threadData_t *threadData, long idx,
baseClock->stats.previousInterval = baseClock->interval;
}
baseClock->stats.lastActivationTime = curTime;
if (frstSubClockIsBaseClock) {

subClock = &baseClock->subClocks[0];
if (subClock->shift.num == 0 && subClock->factor.num == 1 && subClock->factor.den == 1) {
frstSubClockIsBaseClock = 1 /* true */;
#if !defined(OMC_MINIMAL_RUNTIME)
// Save result before clock tick, then evaluate equations
sim_result.emit(&sim_result, data, threadData);
#endif /* #if !defined(OMC_MINIMAL_RUNTIME) */
baseClock->subClocks[0].stats.count++;
baseClock->subClocks[0].stats.previousInterval = baseClock->stats.previousInterval;
baseClock->subClocks[0].stats.lastActivationTime = baseClock->stats.lastActivationTime;
subClock->stats.count++;
subClock->stats.previousInterval = baseClock->stats.previousInterval;
subClock->stats.lastActivationTime = baseClock->stats.lastActivationTime;
data->callback->function_equationsSynchronous(data, threadData, idx, 0);
}
if (!baseClock->isEventClock) {
Expand All @@ -225,32 +224,24 @@ modelica_boolean handleBaseClock(DATA* data, threadData_t *threadData, long idx,
}

// Add sub-clocks to timer that will fire during this base-clock interval.
// k = subClock->stats.count
// s = subClock->shift + k*subClock->factor;
// timer = base.prevTick + (s-baseClock->stats.count-1) * baserClock->interval
// s = subClock->shift + subClock->stats.count * subClock->factor - (baseClock->stats.count-1);
// timer = base.prevTick + s * baseClock->interval

// Skipp first subClock if is equivalent to the baseClock
if (frstSubClockIsBaseClock) {
i=1;
} else {
i=0;
}
while (i<baseClock->nSubClocks) {
// Skip first subClock if is equivalent to the baseClock
i = frstSubClockIsBaseClock ? 1 : 0;
for (/* init above */; i < baseClock->nSubClocks; ++i) {
subClock = &baseClock->subClocks[i];
k = subClock->stats.count;
subTimer = rat2Real(addRat2Rat(subClock->shift, multInt2Rat(k, subClock->factor)));
while (subTimer < baseClock->stats.count) {
activationTime = curTime + (subTimer-(baseClock->stats.count-1))*baseClock->interval;
subTimer = addRat(subRat(subClock->shift, int2Rat(baseClock->stats.count-1)), mulRat(int2Rat(subClock->stats.count), subClock->factor));
while (floorRat(subTimer) == 0) {
activationTime = curTime + rat2Real(subTimer)*baseClock->interval;
nextTimer = (SYNC_TIMER){
.base_idx = idx,
.sub_idx = i,
.type = SYNC_SUB_CLOCK,
.activationTime = activationTime};
insertTimer(data->simulationInfo->intvlTimers, &nextTimer);
k++;
subTimer = rat2Real(addRat2Rat(subClock->shift, multInt2Rat(k, subClock->factor)));
subTimer = addRat(subTimer, subClock->factor);
}
i++;
}

TRACE_POP
Expand Down Expand Up @@ -425,8 +416,8 @@ int handleTimersFMI(DATA* data, threadData_t *threadData, double currentTime, in
* @param baseClocks Pointer to array of size nClocks with base clock data.
* @param nBaseClocks Number of base clocks.
*/
void printClocks(BASECLOCK_DATA* baseClocks, int nBaseClocks) {
/* Variables */
void printClocks(BASECLOCK_DATA* baseClocks, int nBaseClocks)
{
int i,j;
BASECLOCK_DATA* baseClock;
SUBCLOCK_DATA* subClock;
Expand All @@ -438,7 +429,7 @@ void printClocks(BASECLOCK_DATA* baseClocks, int nBaseClocks) {
baseClock = &baseClocks[i];
infoStreamPrint(LOG_SYNCHRONOUS, 1, "Base clock %i", i+1);
if (baseClock->isEventClock) {
infoStreamPrint(LOG_SYNCHRONOUS, 0, "is event clock");
infoStreamPrint(LOG_SYNCHRONOUS, 0, "is event clock");
} else if (baseClock->intervalCounter==-1) {
infoStreamPrint(LOG_SYNCHRONOUS, 0, "interval: %e", baseClock->interval);
} else {
Expand All @@ -449,8 +440,8 @@ void printClocks(BASECLOCK_DATA* baseClocks, int nBaseClocks) {
for(j=0; j<baseClock->nSubClocks; j++) {
subClock = &baseClock->subClocks[j];
infoStreamPrint(LOG_SYNCHRONOUS, 1, "Sub-clock %i of base clock %i", j+1, i+1);
infoStreamPrint(LOG_SYNCHRONOUS, 0, "shift: %li/%li", subClock->shift.m, subClock->shift.n);
infoStreamPrint(LOG_SYNCHRONOUS, 0, "factor: %li/%li", subClock->factor.m, subClock->factor.n);
infoStreamPrint(LOG_SYNCHRONOUS, 0, "shift: "RAT_FMT"/"RAT_FMT, subClock->shift.num, subClock->shift.den);
infoStreamPrint(LOG_SYNCHRONOUS, 0, "factor: "RAT_FMT"/"RAT_FMT, subClock->factor.num, subClock->factor.den);
infoStreamPrint(LOG_SYNCHRONOUS, 0, "solverMethod: %s", strlen(subClock->solverMethod)>0?subClock->solverMethod:"none");
infoStreamPrint(LOG_SYNCHRONOUS, 0, "holdEvents: %s", subClock->holdEvents?"true":"false");
messageClose(LOG_SYNCHRONOUS);
Expand Down

0 comments on commit 851ba5e

Please sign in to comment.