Skip to content

Commit 8d89d77

Browse files
small bug in initial step size calculation & some formatting issues (#14194)
1 parent 219c923 commit 8d89d77

File tree

1 file changed

+47
-38
lines changed
  • OMCompiler/SimulationRuntime/c/simulation/solver

1 file changed

+47
-38
lines changed

OMCompiler/SimulationRuntime/c/simulation/solver/gbode_ctrl.c

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -264,82 +264,91 @@ void getInitStepSize(DATA* data, threadData_t* threadData, DATA_GBODE* gbData)
264264
modelica_real* fODE = &sData->realVars[nStates];
265265

266266
int i;
267-
268-
double sc;
269-
double d, d0 = 0.0, d1 = 0.0, d2 = 0.0;
267+
double sc, safety = 0.01;
268+
double d0 = 0.0; // norm of y0 weighted
269+
double d1 = 0.0; // norm of f0 weighted
270+
double d2 = 0.0; // norm of slope difference weighted
271+
270272
double h0, h1;
271273
double absTol = data->simulationInfo->tolerance;
272274
double relTol = absTol;
273275

274-
// This flag will be used in order to reduce the step size for the first Euler step below
275-
// Only used for subsequent calls, if an assert happens during the Euler step
276+
// Increase initialFailures counter on repeated failures (for adaptive reduction)
276277
gbData->initialFailures++;
277278

278-
/* store values of the states and state derivatives at initial or event time */
279+
// Store current time and state
279280
gbData->time = sData->timeValue;
280-
memcpy(gbData->yOld, sData->realVars, nStates*sizeof(double));
281+
memcpy(gbData->yOld, sData->realVars, nStates * sizeof(double));
282+
283+
// Compute f(t0, y0)
281284
gbode_fODE(data, threadData, &(gbData->stats.nCallsODE));
282285

283286
if (gbData->initialStepSize < 0) {
284-
memcpy(gbData->f, fODE, nStates*sizeof(double));
285-
for (i=0; i<nStates; i++) {
286-
sc = absTol + fabs(sDataOld->realVars[i])*relTol;
287-
d0 += ((sDataOld->realVars[i] * sDataOld->realVars[i])/(sc*sc));
288-
d1 += ((fODE[i] * fODE[i]) / (sc*sc));
289-
}
290-
d0 /= nStates;
291-
d1 /= nStates;
287+
memcpy(gbData->f, fODE, nStates * sizeof(double));
292288

293-
d0 = sqrt(d0);
294-
d1 = sqrt(d1);
289+
// Compute weighted norms of y0 and f0
290+
for (i = 0; i < nStates; i++) {
291+
sc = absTol + fabs(gbData->yOld[i]) * relTol;
292+
d0 += (gbData->yOld[i] * gbData->yOld[i]) / (sc * sc);
293+
d1 += (fODE[i] * fODE[i]) / (sc * sc);
294+
}
295+
d0 = sqrt(d0 / nStates);
296+
d1 = sqrt(d1 / nStates);
295297

296-
/* calculate first guess of the initial step size */
297-
if (d0 < 1e-5 || d1 < 1e-5) {
298+
// Initial guess for h0 based on ratio
299+
if (d0 < 1e-10 || d1 < 1e-10) {
298300
h0 = 1e-6;
299301
} else {
300-
h0 = 0.01 * d0/d1;
302+
h0 = safety * d0 / d1;
301303
}
302-
if (gbData->initialFailures>0)
303-
h0 /= pow(10,gbData->initialFailures);
304304

305-
for (i=0; i<nStates; i++) {
305+
// If repeated failures happened, reduce h0 accordingly
306+
if (gbData->initialFailures > 0) {
307+
h0 /= pow(10, gbData->initialFailures);
308+
}
309+
310+
// Trial explicit Euler step: y1 = y0 + h0 * f0
311+
for (i = 0; i < nStates; i++) {
306312
sData->realVars[i] = gbData->yOld[i] + fODE[i] * h0;
307313
}
308-
sData->timeValue += h0;
314+
sData->timeValue = gbData->time + h0;
309315

316+
// Compute f(t0+h0, y1)
310317
gbode_fODE(data, threadData, &(gbData->stats.nCallsODE));
311318

312-
for (i=0; i<nStates; i++) {
313-
sc = absTol + fabs(gbData->yOld[i])*relTol;
314-
d2 += ((fODE[i]-gbData->f[i])*(fODE[i]-gbData->f[i])/(sc*sc));
319+
// Compute weighted norm of slope difference
320+
for (i = 0; i < nStates; i++) {
321+
sc = absTol + fabs(gbData->yOld[i]) * relTol;
322+
double diff = fODE[i] - gbData->f[i];
323+
d2 += (diff * diff) / (sc * sc);
315324
}
325+
d2 = sqrt(d2 / nStates) / h0;
316326

317-
d2 /= h0;
318-
d2 = sqrt(d2);
319-
320-
321-
d = fmax(d1,d2);
327+
// Combine the slopes to refine step size estimate
328+
double d = fmax(d1, d2);
322329

323330
if (d > 1e-15) {
324-
h1 = sqrt(0.01/d);
331+
h1 = sqrt(safety / d);
325332
} else {
326-
h1 = fmax(1e-6, h0*1e-3);
333+
h1 = fmax(1e-6, h0 * 1e-3);
327334
}
328335

329-
gbData->stepSize = 0.5*fmin(100*h0,h1);
336+
// Final step size: blend h0 and h1 with some limits
337+
gbData->stepSize = 0.5 * fmin(100.0 * h0, h1);
330338
gbData->optStepSize = gbData->stepSize;
331339
gbData->lastStepSize = 0.0;
332340

341+
// Restore original state and time
333342
sData->timeValue = gbData->time;
334-
memcpy(sData->realVars, gbData->yOld, nStates*sizeof(double));
335-
memcpy(fODE, gbData->f, nStates*sizeof(double));
343+
memcpy(sData->realVars, gbData->yOld, nStates * sizeof(double));
344+
memcpy(fODE, gbData->f, nStates * sizeof(double));
336345
} else {
337346
gbData->stepSize = gbData->initialStepSize;
338347
gbData->lastStepSize = 0.0;
339348
}
340349

341350
infoStreamPrint(OMC_LOG_SOLVER, 0, "Initial step size = %e at time %g", gbData->stepSize, gbData->time);
342351

343-
// Set number of initialization failures back to -1 (intial step size determination was succesfull)
352+
// Reset failure count on success
344353
gbData->initialFailures = -1;
345354
}

0 commit comments

Comments
 (0)