Skip to content

Commit 2c23b70

Browse files
Copilotivan-pi
andauthored
feat: add non-autonomous stiff3 overload with dFdx callback and test
Agent-Logs-Url: https://github.com/ivan-pi/stiff3/sessions/67f692d9-43f0-4337-94d3-193b5edcdf71 Co-authored-by: ivan-pi <21085643+ivan-pi@users.noreply.github.com>
1 parent 5c4f6cb commit 2c23b70

3 files changed

Lines changed: 162 additions & 4 deletions

File tree

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# stiff3
22

3-
`stiff3` is a Fortran subprogram for solving stiff autonomous systems of ordinary differential equations (ODE's) using a semi-implicit Runge-Kutta method with three steps (SIRK3). The `stiff3` source code was originally published in the work:
3+
`stiff3` is a Fortran subprogram for solving stiff systems of ordinary differential equations (ODE's) using a semi-implicit Runge-Kutta method with three steps (SIRK3). Both autonomous and non-autonomous systems are supported through overloaded `stiff3` interfaces. The `stiff3` source code was originally published in the work:
44

55
> Villadsen, J., & Michelsen, M. L. (1978). *Solution of differential equation models by polynomial approximation*. Prentice-Hall, Inc.
66
@@ -111,6 +111,5 @@ For students interested in CSE, here are some contribution ideas:
111111
- Support for banded or sparse Jacobian matrices
112112
- Use BLAS kernels for vector operations
113113
- Continuous (dense) output of variables
114-
- Extend `stiff3` to non-autonomous systems of ODE's
115114
- Advanced stepsize control settings
116-
- Write a tutorial on how to use `stiff3`
115+
- Write a tutorial on how to use `stiff3`

src/stiff3_solver.f90

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,19 @@ module stiff3_solver
1818

1919
public :: stiff3, stiff3_wp
2020
public :: rhs_sub, jacobian_sub, output_sub
21+
public :: rhs_nonaut_sub, jacobian_nonaut_sub, rhs_time_derivative_sub
2122

2223
!> Kind parameter for working precision of stiff3 reals
2324
integer, parameter :: stiff3_wp = kind(1.0d0)
2425

2526
!> Working precision with short name for internal use
2627
integer, parameter :: wp = stiff3_wp
2728

29+
interface stiff3
30+
module procedure stiff3_autonomous
31+
module procedure stiff3_nonautonomous
32+
end interface
33+
2834
abstract interface
2935
!> Function to evaluate the right-hand side of a system of ODEs.
3036
!> It is assumed the system of ODEs is autonomous, meaning that
@@ -58,6 +64,33 @@ subroutine output_sub(x,y,iha,qa)
5864
!! Step-length acceleration factor
5965
end subroutine
6066

67+
!> User supplied subprogram for non-autonomous rhs evaluation.
68+
subroutine rhs_nonaut_sub(n,x,y,f)
69+
import wp
70+
integer, intent(in) :: n
71+
real(wp), intent(in) :: x
72+
real(wp), intent(in) :: y(n)
73+
real(wp), intent(inout) :: f(n)
74+
end subroutine
75+
76+
!> User supplied subprogram for non-autonomous Jacobian evaluation.
77+
subroutine jacobian_nonaut_sub(n,x,y,df)
78+
import wp
79+
integer, intent(in) :: n
80+
real(wp), intent(in) :: x
81+
real(wp), intent(in) :: y(n)
82+
real(wp), intent(inout) :: df(n,n)
83+
end subroutine
84+
85+
!> User supplied subprogram for evaluation of dF/dx.
86+
subroutine rhs_time_derivative_sub(n,x,y,fx)
87+
import wp
88+
integer, intent(in) :: n
89+
real(wp), intent(in) :: x
90+
real(wp), intent(in) :: y(n)
91+
real(wp), intent(inout) :: fx(n)
92+
end subroutine
93+
6194
end interface
6295

6396

@@ -68,7 +101,7 @@ subroutine output_sub(x,y,iha,qa)
68101

69102
!> Semi-implicit Runge-Kutta integrator routine
70103
!
71-
subroutine stiff3(n,fun,dfun,out,nprint,x0,x1,h0,eps,w,y)
104+
subroutine stiff3_autonomous(n,fun,dfun,out,nprint,x0,x1,h0,eps,w,y)
72105
integer, intent(in) :: n
73106
!! Number of equations to be integrated.
74107
procedure(rhs_sub) :: fun
@@ -228,6 +261,74 @@ subroutine stiff3(n,fun,dfun,out,nprint,x0,x1,h0,eps,w,y)
228261

229262
end subroutine
230263

264+
!> Semi-implicit Runge-Kutta integrator routine for non-autonomous systems
265+
!
266+
subroutine stiff3_nonautonomous(n,fun,dfun,dfdx,out,nprint,x0,x1,h0,eps,w,y)
267+
integer, intent(in) :: n
268+
!! Number of equations to be integrated.
269+
procedure(rhs_nonaut_sub) :: fun
270+
!! User supplied subprogram for function evaluation.
271+
procedure(jacobian_nonaut_sub) :: dfun
272+
!! User supplied subprogram for evaluation of the Jacobian wrt y.
273+
procedure(rhs_time_derivative_sub) :: dfdx
274+
!! User supplied subprogram for evaluation of dF/dx.
275+
procedure(output_sub) :: out
276+
!! User supplied subprogram for output.
277+
integer, intent(in) :: nprint
278+
!! Printing interval. For `nprint = k` the solution is only printed.
279+
!! at every kth step.
280+
real(wp), intent(in) :: x0, x1
281+
!! Limits of the independent variable between which the differential
282+
!! equation is solved.
283+
real(wp), intent(inout) :: h0
284+
!! Suggested initial half-step length. On exit `h0` contains suggested
285+
!! value of half-step length for continued integration beyond `x1`.
286+
real(wp), intent(in) :: eps, w(n)
287+
!! Tolerance parameters.
288+
real(wp), intent(inout) :: y(n)
289+
!! Vector of dependent variables at `x0`. On exit `y` is the vector of
290+
!! dependent variables at `x1`.
291+
292+
real(wp) :: yaug(n+1), waug(n+1)
293+
294+
yaug(1) = x0
295+
yaug(2:) = y
296+
297+
waug(1) = 0.0_wp
298+
waug(2:) = w
299+
300+
call stiff3_autonomous(n+1,fun_aug,jac_aug,out_aug,nprint,x0,x1,h0,eps,waug,yaug)
301+
y = yaug(2:)
302+
303+
contains
304+
305+
subroutine fun_aug(naug,yi,fi)
306+
integer, intent(in) :: naug
307+
real(wp), intent(in) :: yi(naug)
308+
real(wp), intent(inout) :: fi(naug)
309+
call fun(n,yi(1),yi(2:),fi(2:))
310+
fi(1) = 1.0_wp
311+
end subroutine
312+
313+
subroutine jac_aug(naug,yi,dfi)
314+
integer, intent(in) :: naug
315+
real(wp), intent(in) :: yi(naug)
316+
real(wp), intent(inout) :: dfi(naug,naug)
317+
dfi = 0.0_wp
318+
call dfdx(n,yi(1),yi(2:),dfi(2:,1))
319+
call dfun(n,yi(1),yi(2:),dfi(2:,2:))
320+
end subroutine
321+
322+
subroutine out_aug(x,yi,iha,qa)
323+
real(wp), intent(in) :: x
324+
real(wp), intent(in) :: yi(:)
325+
integer, intent(in) :: iha
326+
real(wp), intent(in) :: qa
327+
call out(x,yi(2:),iha,qa)
328+
end subroutine
329+
330+
end subroutine
331+
231332

232333
!> Single-step semi-implicit integration
233334
!

test/nonautonomous.f90

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
program nonautonomous
2+
3+
use stiff3_solver, only: stiff3, wp => stiff3_wp
4+
5+
implicit none
6+
7+
integer, parameter :: n = 1, nout = 1000000
8+
real(wp), parameter :: atol = 5.0e-6_wp
9+
real(wp) :: y(n), w(n), x0, x1, h0, eps, y_exact
10+
11+
y = [0.0_wp]
12+
w = [1.0_wp]
13+
x0 = 0.0_wp
14+
x1 = 1.0_wp
15+
h0 = 1.0e-3_wp
16+
eps = 1.0e-8_wp
17+
18+
call stiff3(n,fun,jac,dfdx,out,nout,x0,x1,h0,eps,w,y)
19+
20+
y_exact = 0.5_wp*(sin(x1) - cos(x1) + exp(-x1))
21+
if (abs(y(1)-y_exact) > atol) then
22+
error stop 1
23+
end if
24+
25+
contains
26+
27+
subroutine fun(n,t,y,f)
28+
integer, intent(in) :: n
29+
real(wp), intent(in) :: t
30+
real(wp), intent(in) :: y(n)
31+
real(wp), intent(inout) :: f(n)
32+
f(1) = -y(1) + sin(t)
33+
end subroutine
34+
35+
subroutine jac(n,t,y,df)
36+
integer, intent(in) :: n
37+
real(wp), intent(in) :: t
38+
real(wp), intent(in) :: y(n)
39+
real(wp), intent(inout) :: df(n,n)
40+
df(1,1) = -1.0_wp
41+
end subroutine
42+
43+
subroutine dfdx(n,t,y,fx)
44+
integer, intent(in) :: n
45+
real(wp), intent(in) :: t
46+
real(wp), intent(in) :: y(n)
47+
real(wp), intent(inout) :: fx(n)
48+
fx(1) = cos(t)
49+
end subroutine
50+
51+
subroutine out(t,y,ih,qa)
52+
real(wp), intent(in) :: t
53+
real(wp), intent(in) :: y(:)
54+
integer, intent(in) :: ih
55+
real(wp), intent(in) :: qa
56+
end subroutine
57+
58+
end program

0 commit comments

Comments
 (0)