Skip to content

Commit

Permalink
Fixed stiffness detection bug for non-FSAL methods
Browse files Browse the repository at this point in the history
  • Loading branch information
princemahajan committed Jan 22, 2024
1 parent a35629a commit b632203
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 126 deletions.
Binary file modified media/wp_sp_fr.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions src/ERK.f90
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,14 @@ end subroutine erk_destroy



module subroutine erk_stepint(me, X0, Y0, F0, h, Y1, Yint12, FCalls, EstimateErr, Err, params)
module subroutine erk_stepint(me, X0, Y0, F0, h, Y1, Ysint_pre, Ysint, &
FCalls, EstimateErr, Err, params)
class(ERK_class), intent(inout) :: me
real(WP), intent(in) :: X0
real(WP), dimension(me%pDiffEqSys%n), intent(in) :: Y0
real(WP), dimension(me%pDiffEqSys%n), intent(inout) :: F0
real(WP), intent(in) :: h
real(WP), dimension(size(Y0)), intent(out) :: Y1, Yint12
real(WP), dimension(size(Y0)), intent(out) :: Y1, Ysint_pre, Ysint
integer, intent(out) :: FCalls
logical, intent(in) :: EstimateErr
real(WP), intent(out) :: Err
Expand Down
6 changes: 3 additions & 3 deletions src/ERKIntegrate.f90
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ module subroutine erk_int(me, X0, Y0, Xf, Yf, StepSz, UseConstStepSz, StepAdvanc
real(WP), dimension(6) :: StepSzParams

real(WP) :: h, hSign, hnew, hmax, X, Err, LastStepSzFac
real(WP), dimension(me%pDiffEqSys%n) :: Y, Y1, F0, Sc0, Yint12
real(WP), dimension(me%pDiffEqSys%n) :: Y, Y1, F0, Sc0, Ysint_pre, Ysint

integer :: FCalls, nInterpStates
integer :: StiffnessTest, StiffThreshold, NonStiffThreshold, StiffTestSteps
Expand Down Expand Up @@ -271,7 +271,7 @@ module subroutine erk_int(me, X0, Y0, Xf, Yf, StepSz, UseConstStepSz, StepAdvanc
end if

! Advance one step using the chosen method
call me%StepInt(X, Y, F0, h, Y1, Yint12, FCalls, (.NOT. ConstStepSz), Err, params)
call me%StepInt(X, Y, F0, h, Y1, Ysint_pre, Ysint, FCalls, (.NOT. ConstStepSz), Err, params)

! update steps taken and function calls made
me%TotalSteps = me%TotalSteps + 1
Expand Down Expand Up @@ -776,7 +776,7 @@ subroutine CheckStiffness(IsProblemStiff)

if (mod(me%AcceptedSteps, StiffTestSteps) == 0 .OR. StiffThreshold > 0) then
StiffN = norm2(me%k(:,me%sint) - me%k(:,me%sint-1))
StiffD = norm2(Y1 - Yint12)
StiffD = norm2(Ysint - Ysint_pre)

if (StiffD > 0.0_WP) hLamb = abs(h)*StiffN/StiffD

Expand Down
101 changes: 55 additions & 46 deletions src/ERKStepInt.f90
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@

contains

module subroutine erk_stepint(me, X0, Y0, F0, h, Y1, Yint12, FCalls, &
EstimateErr, Err, params)
module subroutine erk_stepint(me, X0, Y0, F0, h, Y1, Ysint_pre, Ysint, &
FCalls, EstimateErr, Err, params)
class(ERK_class), intent(inout) :: me
real(WP), intent(in) :: X0
real(WP), dimension(me%pDiffEqSys%n), intent(in) :: Y0
real(WP), dimension(me%pDiffEqSys%n), intent(inout) :: F0
real(WP), intent(in) :: h
real(WP), dimension(size(Y0)), intent(out) :: Y1, Yint12
real(WP), dimension(size(Y0)), intent(out) :: Y1, Ysint_pre, Ysint
integer, intent(out) :: FCalls
logical, intent(in) :: EstimateErr
real(WP), intent(out) :: Err
Expand All @@ -41,38 +41,38 @@ module subroutine erk_stepint(me, X0, Y0, F0, h, Y1, Yint12, FCalls, &
select case (me%method)
case (ERK_DOP853)
if (EstimateErr) then
call DOP853_stepint(me%pDiffEqSys, X0, Y0, F0, h, me%k, Y1, Yint12, FCalls, Err, &
me%IsScalarTol, me%RTol, me%ATol, params)
call DOP853_stepint(me%pDiffEqSys, X0, Y0, F0, h, me%k, Y1, Ysint_pre, Ysint, &
FCalls, Err, me%IsScalarTol, me%RTol, me%ATol, params)
else
call DOP853_stepint(me%pDiffEqSys, X0, Y0, F0, h, me%k, Y1, Yint12, FCalls, Err, &
params=params)
call DOP853_stepint(me%pDiffEqSys, X0, Y0, F0, h, me%k, Y1, Ysint_pre, Ysint, &
FCalls, Err, params=params)
end if
case (ERK_DOP54)
if (EstimateErr) then
call DOP54_stepint(me%pDiffEqSys, X0, Y0, F0, h, me%k, Y1, Yint12, FCalls, Err, &
me%IsScalarTol, me%RTol, me%ATol, params)
call DOP54_stepint(me%pDiffEqSys, X0, Y0, F0, h, me%k, Y1, Ysint_pre, Ysint, &
FCalls, Err, me%IsScalarTol, me%RTol, me%ATol, params)
else
call DOP54_stepint(me%pDiffEqSys, X0, Y0, F0, h, me%k, Y1, Yint12, FCalls, Err, &
params=params)
call DOP54_stepint(me%pDiffEqSys, X0, Y0, F0, h, me%k, Y1, Ysint_pre, Ysint, &
FCalls, Err, params=params)
end if
case (ERK_VERNER65E)
if (EstimateErr) then
call stepint(me%pDiffEqSys, X0, Y0, F0, h, Verner65E_FSAL, Verner65E_sint, me%k, &
Verner65E_a, Verner65E_b, Verner65E_c, Y1, Yint12, FCalls, &
Verner65E_a, Verner65E_b, Verner65E_c, Y1, Ysint_pre, Ysint, FCalls, &
Err, me%IsScalarTol, me%RTol, me%ATol, Verner65E_e, params)
else
call stepint(me%pDiffEqSys, X0, Y0, F0, h, Verner65E_FSAL, Verner65E_sint, me%k, &
Verner65E_a, Verner65E_b, Verner65E_c, Y1, Yint12, FCalls, &
Verner65E_a, Verner65E_b, Verner65E_c, Y1, Ysint_pre, Ysint, FCalls, &
Err, params=params)
end if
case (ERK_VERNER98R)
if (EstimateErr) then
call stepint(me%pDiffEqSys, X0, Y0, F0, h, Verner98R_FSAL, Verner98R_sint, me%k, &
Verner98R_a, Verner98R_b, Verner98R_c, Y1, Yint12, FCalls, &
Verner98R_a, Verner98R_b, Verner98R_c, Y1, Ysint_pre, Ysint, FCalls, &
Err, me%IsScalarTol, me%RTol, me%ATol, Verner98R_e, params)
else
call stepint(me%pDiffEqSys, X0, Y0, F0, h, Verner98R_FSAL, Verner98R_sint, me%k, &
Verner98R_a, Verner98R_b, Verner98R_c, Y1, Yint12, FCalls, &
Verner98R_a, Verner98R_b, Verner98R_c, Y1, Ysint_pre, Ysint, FCalls, &
Err, params=params)
end if
case default
Expand Down Expand Up @@ -118,7 +118,7 @@ end subroutine erk_intpcoeff

!> It advances integrator by 1 step by computing intermediate stages
subroutine stepint(pDiffEqSys, X0, Y0, F0, h, IsFSALMethod, sint, k, a, b, c, Y1, &
Yint12, FCalls, Err, IsScalarTol, RTol, ATol, e, params)
Ysint_pre, Ysint, FCalls, Err, IsScalarTol, RTol, ATol, e, params)
class(DiffEqSys), intent(inout) :: pDiffEqSys
real(WP), intent(in) :: X0
real(WP), dimension(pDiffEqSys%n), intent(in) :: Y0
Expand All @@ -130,7 +130,7 @@ subroutine stepint(pDiffEqSys, X0, Y0, F0, h, IsFSALMethod, sint, k, a, b, c, Y1
real(WP), dimension(:), contiguous, intent(in) :: a
real(WP), dimension(1:sint), intent(in) :: b
real(WP), dimension(2:sint), intent(in) :: c
real(WP), dimension(size(Y0)), intent(out) :: Y1, Yint12
real(WP), dimension(size(Y0)), intent(out) :: Y1, Ysint_pre, Ysint
integer, intent(out) :: FCalls
real(WP), intent(out) :: Err
logical, intent(in), optional :: IsScalarTol
Expand All @@ -153,7 +153,7 @@ subroutine stepint(pDiffEqSys, X0, Y0, F0, h, IsFSALMethod, sint, k, a, b, c, Y1

! compute rest of the stages
! This compact and beautiful code is slower than ugly hardcoded one!
do i = 2,sint
do i = 2, (sint-1)
block
integer :: astart, j
real(WP), dimension(n) :: aijkj
Expand All @@ -170,28 +170,32 @@ subroutine stepint(pDiffEqSys, X0, Y0, F0, h, IsFSALMethod, sint, k, a, b, c, Y1
aijkj = aijkj + k(:,j)*a(astart + j)
end do

Yint = Y0 + h*aijkj
k(:,i) = pDiffEqSys%F(X0 + h*c(i), Yint, params)

! Yint for the last non-FSAL stage is needed for stiffness detection
! This is from Hairer's DOP853, so not sure its correct for other solvers
! TBD: I dont like this, need a way to avoid this condition in this loop
if (i == (sint-1)) Yint12 = Yint
Ysint_pre = Y0 + h*aijkj
k(:,i) = pDiffEqSys%F(X0 + h*c(i), Ysint_pre, params)
end block
end do

! Yint for the second last stage is needed for stiffness detection
! TBD: Confirm this is correct method for stiffness detection for non-FSAL methods

! the last stage
block
integer :: astart, j
real(WP), dimension(n) :: aijkj
astart = int((sint-1)/2.0*(sint-2))
aijkj = 0.0_WP
do j = 1,(sint-1)
aijkj = aijkj + k(:,j)*a(astart + j)
end do
Yint = Y0 + h*aijkj
k(:,sint) = pDiffEqSys%F(X0 + h*c(sint), Yint, params)
end block

! propagate the solution to the next step for error computation
! For FSAL methods, Yint already has the new solution

! For non-FSAL methods, compute the solution at the next step
if (IsFSALMethod .EQV. .FALSE.) then
! for stiffness detection, we need last non-FSAL stage solution
! TBD: this needs correction for stifness detection in case of
! non-FSAL methods as stiffness test needs Yint12 and F(Yint12)
! and we replaced Yint12 with Yint but still have old F(Yint12)
Yint12 = Yint
Yint = Y0 + h*matmul(k(:,1:sint), b(1:sint))
end if
if (IsFSALMethod .EQV. .FALSE.) Yint = Y0 + h*matmul(k(:,1:sint), b(1:sint))

if (EstimateErr) then
! Estimate the error. We assume that the error coeffcients are precomputed,
Expand Down Expand Up @@ -223,6 +227,7 @@ subroutine stepint(pDiffEqSys, X0, Y0, F0, h, IsFSALMethod, sint, k, a, b, c, Y1
! Evaluate F0 for the next step
F0 = pDiffEqSys%F(X0 + h, Y1, params)
! Number of function calls made so far
Ysint = Yint ! for stiffness detection
FCalls = sint
else
! In FSAL methods, the integration last stage is F0 for the next step
Expand Down Expand Up @@ -319,15 +324,15 @@ end subroutine IntpCoeff


!> It advances integrator by 1 step by computing stages
subroutine DOP853_stepint(pDiffEqSys, X0, Y0, F0, h, k, Y1, Yint12, FCalls, Err, &
IsScalarTol, RTol, ATol, params)
subroutine DOP853_stepint(pDiffEqSys, X0, Y0, F0, h, k, Y1, Ysint_pre, Ysint, &
FCalls, Err, IsScalarTol, RTol, ATol, params)
class(DiffEqSys), intent(inout) :: pDiffEqSys
real(WP), intent(in) :: X0
real(WP), dimension(pDiffEqSys%n), intent(in) :: Y0
real(WP), dimension(pDiffEqSys%n), intent(inout) :: F0
real(WP), intent(in) :: h
real(WP), dimension(size(Y0),1:DOP853_sint), intent(inout) :: k
real(WP), dimension(size(Y0)), intent(out) :: Y1, Yint12
real(WP), dimension(size(Y0)), intent(out) :: Y1, Ysint_pre, Ysint
integer, intent(out) :: FCalls
real(WP), intent(out) :: Err
logical, intent(in), optional :: IsScalarTol
Expand Down Expand Up @@ -408,9 +413,9 @@ subroutine DOP853_stepint(pDiffEqSys, X0, Y0, F0, h, k, Y1, Yint12, FCalls, Err,
aijkj = k(:,1)*DOP853_a(56) + k(:,4)*DOP853_a(59) &
+ k(:,5)*DOP853_a(60) + k(:,6)*DOP853_a(61) + k(:,7)*DOP853_a(62) + k(:,8)*DOP853_a(63) &
+ k(:,9)*DOP853_a(64) + k(:,10)*DOP853_a(65) + k(:,11)*DOP853_a(66)
Yint12 = Y0 + h*aijkj
k(:,12) = pDiffEqSys%F(X0 + h*DOP853_c(12), Yint12, params)
Ysint_pre = Y0 + h*aijkj
k(:,12) = pDiffEqSys%F(X0 + h*DOP853_c(12), Ysint_pre, params)

! 13th stage
aijkj = k(:,1)*DOP853_a(67) &
+ k(:,6)*DOP853_a(72) + k(:,7)*DOP853_a(73) + k(:,8)*DOP853_a(74) &
Expand Down Expand Up @@ -453,6 +458,8 @@ subroutine DOP853_stepint(pDiffEqSys, X0, Y0, F0, h, k, Y1, Yint12, FCalls, Err,
! In FSAL methods, the intgeration last stage is F0 for the next step
k(:,13) = pDiffEqSys%F(X0 + h, Yint, params)
F0 = k(:,13)
! this for stiffness detection
Ysint = Yint
! Function calls made if the step is accepted
FCalls = DOP853_sint - 1
else
Expand Down Expand Up @@ -558,15 +565,15 @@ end subroutine DOP853_IntpCoeff


!> It advances integrator by 1 step by computing stages
subroutine DOP54_stepint(pDiffEqSys, X0, Y0, F0, h, k, Y1, Yint12, FCalls, Err, &
IsScalarTol, RTol, ATol, params)
subroutine DOP54_stepint(pDiffEqSys, X0, Y0, F0, h, k, Y1, Ysint_pre, Ysint, &
FCalls, Err, IsScalarTol, RTol, ATol, params)
class(DiffEqSys), intent(inout) :: pDiffEqSys
real(WP), intent(in) :: X0
real(WP), dimension(pDiffEqSys%n), intent(in) :: Y0
real(WP), dimension(pDiffEqSys%n), intent(inout) :: F0
real(WP), intent(in) :: h
real(WP), dimension(size(Y0),1:DOP54_sint), intent(inout) :: k
real(WP), dimension(size(Y0)), intent(out) :: Y1, Yint12
real(WP), dimension(size(Y0)), intent(out) :: Y1, Ysint_pre, Ysint
integer, intent(out) :: FCalls
real(WP), intent(out) :: Err
logical, intent(in), optional :: IsScalarTol
Expand Down Expand Up @@ -600,13 +607,13 @@ subroutine DOP54_stepint(pDiffEqSys, X0, Y0, F0, h, k, Y1, Yint12, FCalls, Err,
k(:,5) = pDiffEqSys%F(X0 + h*DOP54_c(5), Yint, params)

! 6th stage
Yint12 = Y0 + h*(k(:,1)*DOP54_a(11) + k(:,2)*DOP54_a(12) + k(:,3)*DOP54_a(13) &
+ k(:,4)*DOP54_a(14) + k(:,5)*DOP54_a(15))
k(:,6) = pDiffEqSys%F(X0 + h*DOP54_c(6), Yint12, params)
Ysint_pre = Y0 + h*(k(:,1)*DOP54_a(11) + k(:,2)*DOP54_a(12) + k(:,3)*DOP54_a(13) &
+ k(:,4)*DOP54_a(14) + k(:,5)*DOP54_a(15))
k(:,6) = pDiffEqSys%F(X0 + h*DOP54_c(6), Ysint_pre, params)

! 7th stage
Yint = Y0 + h*(k(:,1)*DOP54_a(16) + k(:,2)*DOP54_a(17) + k(:,3)*DOP54_a(18) &
+ k(:,4)*DOP54_a(19) + k(:,5)*DOP54_a(20) + k(:,6)*DOP54_a(21))
+ k(:,4)*DOP54_a(19) + k(:,5)*DOP54_a(20) + k(:,6)*DOP54_a(21))
k(:,7) = pDiffEqSys%F(X0 + h, Yint, params)

! propagate the solution to the next step for error computation
Expand Down Expand Up @@ -637,6 +644,8 @@ subroutine DOP54_stepint(pDiffEqSys, X0, Y0, F0, h, k, Y1, Yint12, FCalls, Err,
Y1 = Yint
! In FSAL methods, the intgeration first stage is same as the last stage
F0 = k(:,7)
! this for stiffness detection
Ysint = Yint
! Function calls made if the step is accepted
FCalls = DOP54_sint - 1
else
Expand Down
2 changes: 1 addition & 1 deletion tests/perf_TBP.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
DOP54 0.062 0.128E-03 0.295E-09 47527 7851 84
DOP853 0.016 0.144E-03 -0.332E-09 13253 976 139
Verner65E 0.062 0.392E-03 0.908E-09 30885 3822 44
Verner98R 0.016 0.332E-04 -0.769E-10 13427 676 174
Verner98R 0.031 0.332E-04 -0.769E-10 13427 676 174
22 changes: 11 additions & 11 deletions tests/results_CR3BP.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@

A. Internal Step Size
Method Time(s) Closing Err Jacobi Err FCalls Accepted Rejected
DOP54 3.203 0.224E+01 -0.587E-10 26587 4390 49
DOP853 1.156 0.224E+01 0.285E-10 11893 680 154
Verner65E 3.547 0.224E+01 -0.684E-11 22005 2417 36
Verner98R 2.047 0.224E+01 -0.125E-11 12010 503 97
DOP54 2.188 0.222E+01 -0.573E-10 26496 4379 44
DOP853 0.781 0.222E+01 0.287E-10 11782 677 148
Verner65E 2.500 0.222E+01 -0.588E-11 21898 2409 31
Verner98R 1.422 0.222E+01 -0.126E-11 11974 502 96
X-axis (Y1) and Y-axis (Y2) crossing events
Event Index X Y1 Y2 Y3
2 0.399136E+00 0.748352E+00-0.694312E-15 0.000000E+00
2 0.399136E+00 0.748351E+00-0.557943E-14 0.000000E+00
B. Interpolated Grid
Method Time(s) Closing Err Jacobi Err FCalls Accepted Rejected
DOP54 4.547 0.224E+01 -0.587E-10 26587 4390 49
DOP853 1.875 0.224E+01 0.285E-10 11896 680 154
Verner65E 4.547 0.224E+01 -0.684E-11 22007 2417 36
Verner98R 2.906 0.224E+01 -0.125E-11 12020 503 97
DOP54 3.516 0.219E+01 -0.565E-10 26522 4380 48
DOP853 1.500 0.216E+01 0.371E-10 11818 677 151
Verner65E 3.516 0.212E+01 -0.674E-11 22156 2432 38
Verner98R 2.172 0.208E+01 -0.114E-11 11954 502 94
X-axis (Y1) and Y-axis (Y2) crossing events
Event Index X Y1 Y2 Y3
2 0.399136E+00 0.748352E+00-0.694312E-15 0.000000E+00
2 0.399137E+00 0.748351E+00-0.477519E-14 0.000000E+00

10000000 Func calls: 281.25 ms
10000000 Func calls: 156.25 ms
18 changes: 9 additions & 9 deletions tests/results_Lorenz.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

A. Internal Step-size
Method Time(s) FCalls Accepted Rejected Total Steps
DOP54 1.047 256647 42655 143 42798
DOP853 0.266 74888 5839 438 6277
Verner65E 1.062 177861 22123 125 22248
Verner98R 0.453 73507 4385 223 4608
DOP54 0.781 247190 41088 132 41220
DOP853 0.203 75141 5861 437 6298
Verner65E 0.750 175388 21813 126 21939
Verner98R 0.359 74172 4420 230 4650
B. Interpolated Grid
Method Time(s) FCalls Accepted Rejected Total Steps
DOP54 2.094 256647 42655 143 42798
DOP853 0.609 92405 5839 438 6277
Verner65E 2.250 199984 22123 125 22248
Verner98R 1.047 95432 4385 223 4608
DOP54 1.578 250130 41583 126 41709
DOP853 0.516 92128 5822 436 6258
Verner65E 1.781 196422 21735 115 21850
Verner98R 0.781 96020 4413 223 4636

100000000 Func calls: 187.50 ms
100000000 Func calls: 125.00 ms
2 changes: 1 addition & 1 deletion tests/test_CR3BP.f90
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ program TestFLINT_CR3BP
logical, parameter :: CONST_STEPSZ = .FALSE.

! random dispersion of IC: this multiplies the random number
real(WP), parameter :: randon = 0.000000000000_WP
real(WP), parameter :: randon = 0.000000000001_WP

! Interpolation points
integer, parameter :: nIp = int(1000.0*norb)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_Lorenz.f90
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ program LorenzTest
logical, parameter :: CONST_STEPSZ = .FALSE.

! random dispersion of IC: this multiplies the random number
real(WP), parameter :: randon = 0.000000000000_WP
real(WP), parameter :: randon = 0.000000000001_WP

! Interpolation points
integer, parameter :: nIp = int(1000.0)
Expand Down
Loading

0 comments on commit b632203

Please sign in to comment.