@@ -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