Skip to content

Commit 468b3c3

Browse files
committed
Fix numerical issues in int/runge_kutta.c
int/runge_kutta.c - Initialize Hacc, ErrOld, NewtonIncrementOld - Add error checks to prevent div-by-zero errors - Now set *IERR = Code in Rk_ErrorMsg (was Code = *IERR) - Fixed missing decimal point for rkb[2] Radau2A coefficient - Added missing rkT[0][0] and rkt[0][1] coefficients CHANGELOG.md - Updated accordingly Signed-off-by: Bob Yantosca <[email protected]>
1 parent 232610a commit 468b3c3

File tree

2 files changed

+53
-6
lines changed

2 files changed

+53
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2626
- Updated rules to ignore files in `.gitignore` and updated comments accordingly
2727
- Fixed a bug that prevented `.ci-pipelines/ci-cleanup-script.sh` from removing KPP-generated files for MCM mechanisms
2828
- Fixed typo in error message in `int/rosenbrock_autoreduce.f90`
29+
- Fixed several issues in `int/runge_kutta.c` that were causing numerical instability or non-deterministic results
2930

3031
### Removed
3132
- Removed C-I tests on Microsoft Azure Dev Pipelines

int/runge_kutta.c

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,9 @@ void RK_Integrator( int N,
670670
SkipJac,
671671
NewtonDone,
672672
SkipLU;
673+
/* Initialize variables to prevent use of uninitialized values */
674+
Hacc = ZERO;
675+
ErrOld = ZERO;
673676

674677
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
675678

@@ -769,6 +772,7 @@ Tloop: while ( (Tend-*T)*Tdirection - Roundoff > ZERO ) {
769772
/*~~~> Initializations for Newton iteration */
770773
NewtonDone = 0;
771774
Fac = (KPP_REAL)0.5; /* Step reduction if too many iterations */
775+
NewtonIncrementOld = Roundoff; /* Initialize to prevent division by zero */
772776

773777
/* for NewtonLoop */
774778
for (NewtonIter = 1; NewtonIter <= NewtonMaxit; NewtonIter++)
@@ -791,8 +795,12 @@ Tloop: while ( (Tend-*T)*Tdirection - Roundoff > ZERO ) {
791795
Theta = ABS(ThetaMin);
792796
NewtonRate = (KPP_REAL)2.0;
793797
}
794-
else {
798+
else {
795799
/*printf("Entering else from NewtonIter=%d == 1\n", NewtonIter);*/
800+
/* Safety check: prevent division by zero */
801+
if (NewtonIncrementOld <= Roundoff) {
802+
NewtonIncrementOld = MAX(NewtonIncrement, Roundoff);
803+
}
796804
Theta = NewtonIncrement / NewtonIncrementOld;
797805
/*printf("Theta=%f\n", Theta);*/
798806
if (Theta < (KPP_REAL)0.99) {
@@ -874,6 +882,7 @@ Tloop: while ( (Tend-*T)*Tdirection - Roundoff > ZERO ) {
874882
/*~~~> Initializations for Newton iteration */
875883
NewtonDone = 0;
876884
Fac = (KPP_REAL)0.5; /* Step reduction factor if too many iterations */
885+
NewtonIncrementOld = Roundoff; /* Initialize to prevent division by zero */
877886

878887
/* for SDNewtonLoop */
879888
for (NewtonIter = 1; NewtonIter <= NewtonMaxit; NewtonIter++)
@@ -884,6 +893,11 @@ Tloop: while ( (Tend-*T)*Tdirection - Roundoff > ZERO ) {
884893
FUN_CHEM(*T+H,TMP,DZ4); /* DZ4 <- Fun(Y+Z4) */
885894
ISTATUS[Nfun]++;
886895
/* DZ4[1,N] = (D[1, N]-Z4[1,N])*(rkGamma/H) + DZ4[1,N]; */
896+
/* Safety check: H should not be zero here, but add protection */
897+
if (ABS(H) <= Roundoff) {
898+
*IERR = -10;
899+
return;
900+
}
887901
WAXPY(N,-ONE*rkGamma/H,Z4,1,DZ4,1);
888902
WAXPY(N,rkGamma/H,G,1,DZ4,1);
889903

@@ -902,6 +916,10 @@ Tloop: while ( (Tend-*T)*Tdirection - Roundoff > ZERO ) {
902916
}
903917
else {
904918
/*printf("Entering else from NewtonIter=%d == 1\n", NewtonIter);*/
919+
/* Safety check: prevent division by zero */
920+
if (NewtonIncrementOld <= Roundoff) {
921+
NewtonIncrementOld = MAX(NewtonIncrement, Roundoff);
922+
}
905923
ThetaSD = NewtonIncrement / NewtonIncrementOld;
906924
if (ThetaSD < (KPP_REAL)0.99) {
907925
/*printf( "Entering if Theta=%g < 0.99\n", Theta );*/
@@ -1001,7 +1019,13 @@ Tloop: while ( (Tend-*T)*Tdirection - Roundoff > ZERO ) {
10011019
if (Gustafsson == 1) {
10021020
/*~~~> Predictive controller of Gustafsson */
10031021
if (ISTATUS[Nacc] > 1) {
1004-
FacGus = FacSafe*(H/Hacc)*pow(Err*Err/ErrOld,(KPP_REAL)(-0.25));
1022+
/* Safety check: prevent division by zero or near-zero values */
1023+
if (ABS(Hacc) > ((KPP_REAL)10.0)*WLAMCH('E') &&
1024+
ABS(ErrOld) > ((KPP_REAL)10.0)*WLAMCH('E')) {
1025+
FacGus = FacSafe*(H/Hacc)*pow(Err*Err/ErrOld,(KPP_REAL)(-0.25));
1026+
} else {
1027+
FacGus = Fac;
1028+
}
10051029
FacGus = MIN(FacMax,MAX(FacMin,FacGus));
10061030
Fac = MIN(Fac,FacGus);
10071031
Hnew = Fac*H;
@@ -1067,7 +1091,7 @@ Tloop: while ( (Tend-*T)*Tdirection - Roundoff > ZERO ) {
10671091
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
10681092
void RK_ErrorMsg(int Code, KPP_REAL T, KPP_REAL H, int* IERR)
10691093
{
1070-
Code = *IERR;
1094+
*IERR = Code;
10711095
printf("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
10721096
printf("\nForced exit from RungeKutta due to the following error:\n");
10731097

@@ -1177,6 +1201,10 @@ void RK_Interpolate(char action[], int N, KPP_REAL H, KPP_REAL Hold, KPP_REAL Z1
11771201
/* Construct the solution quadratic interpolant Q(c_i) = Z_i, i=1:3 */
11781202
if ( strncmp(action, "make", 4 ) ) {
11791203
den = (rkC[2]-rkC[1])*(rkC[1]-rkC[0])*(rkC[0]-rkC[2]);
1204+
/* Safety check: prevent division by zero or near-zero denominator */
1205+
if (ABS(den) <= ((KPP_REAL)10.0)*WLAMCH('E')) {
1206+
return; /* Denominator is too small, cannot interpolate */
1207+
}
11801208
for (i = 0; i < N; i++)
11811209
{
11821210
CONT[i][0] = (-rkC[2]*rkC[2]*rkC[1]*Z1[i]
@@ -1195,6 +1223,10 @@ void RK_Interpolate(char action[], int N, KPP_REAL H, KPP_REAL Hold, KPP_REAL Z1
11951223
}
11961224
/* Evaluate quadratic polynomial */
11971225
else if ( strncmp( action, "eval", 4 ) ) {
1226+
/* Safety check: prevent division by zero or near-zero Hold */
1227+
if (ABS(Hold) <= ((KPP_REAL)10.0)*WLAMCH('E')) {
1228+
return; /* Hold is too small, cannot interpolate */
1229+
}
11981230
r = H / Hold;
11991231
x1 = ONE + rkC[0]*r;
12001232
x2 = ONE + rkC[1]*r;
@@ -1258,6 +1290,11 @@ void RK_Decomp(int N, KPP_REAL H, KPP_REAL FJAC[], KPP_REAL E1[],
12581290
KPP_REAL Alpha, Beta, Gamma;
12591291
int i,j;
12601292

1293+
/* Safety check: prevent division by zero or near-zero H */
1294+
if (ABS(H) <= ((KPP_REAL)10.0)*WLAMCH('E')) {
1295+
*ISING = 1;
1296+
return;
1297+
}
12611298
Gamma = rkGamma / H;
12621299
Alpha = rkAlpha / H;
12631300
Beta = rkBeta / H;
@@ -1318,6 +1355,10 @@ void RK_Solve(int N, KPP_REAL H, KPP_REAL E1[], int IP1[], KPP_REAL E2R[],
13181355
int i;
13191356

13201357
/* Z <- h^{-1) T^{-1) A^{-1) x Z */
1358+
/* Safety check: prevent division by zero or near-zero H */
1359+
if (ABS(H) <= ((KPP_REAL)10.0)*WLAMCH('E')) {
1360+
return; /* H is too small, skip this operation */
1361+
}
13211362
for (i = 0; i < N; i++)
13221363
{
13231364
x1 = R1[i]/H;
@@ -1368,6 +1409,11 @@ void RK_ErrorEstimate(int N, KPP_REAL H, KPP_REAL T, KPP_REAL Y[],
13681409
KPP_REAL HrkE1,HrkE2,HrkE3;
13691410
int i;
13701411

1412+
/* Safety check: prevent division by zero or near-zero H */
1413+
if (ABS(H) <= ((KPP_REAL)10.0)*WLAMCH('E')) {
1414+
*Err = (KPP_REAL)1.0e10; /* Large error if H is too small */
1415+
return;
1416+
}
13711417
HrkE1 = rkE[0]/H;
13721418
HrkE2 = rkE[1]/H;
13731419
HrkE3 = rkE[2]/H;
@@ -1458,7 +1504,7 @@ void Radau2A_Coefficients()
14581504

14591505
rkB[0] = (KPP_REAL)(3.764030627004672750500754423692808e-01);
14601506
rkB[1] = (KPP_REAL)(5.124858261884216138388134465196080e-01);
1461-
rkB[2] = (KPP_REAL)(1111111111111111111111111111111111e-01);
1507+
rkB[2] = (KPP_REAL)(1.111111111111111111111111111111111e-01);
14621508

14631509
rkC[0] = (KPP_REAL)(1.550510257216821901802715925294109e-01);
14641510
rkC[1] = (KPP_REAL)(6.449489742783178098197284074705891e-01);
@@ -1636,8 +1682,8 @@ void Lobatto3C_Coefficients ()
16361682
rkAlpha = (KPP_REAL)1.687091590520766641994055533117359;
16371683
rkBeta = (KPP_REAL)2.508731754924880510838743672432351;
16381684

1639-
rkT[0][1] = ONE;
1640-
rkT[0][1] = ONE;
1685+
rkT[0][0] = (KPP_REAL).4554100411010284672111720348287483;
1686+
rkT[0][1] = (KPP_REAL)(-.6027050205505142336055860174143743);
16411687
rkT[0][2] = ZERO;
16421688
rkT[1][0] = (KPP_REAL).4554100411010284672111720348287483;
16431689
rkT[1][1] = (KPP_REAL)(-.6027050205505142336055860174143743);

0 commit comments

Comments
 (0)