Skip to content

Commit d630523

Browse files
Copilotivan-pi
andauthored
Add stiff3 workspace overloads with shared core implementation (#25)
* Add stiff3 workspace overload and core routine Agent-Logs-Url: https://github.com/ivan-pi/stiff3/sessions/a3bd8265-d95a-447c-96ff-c8de05acbfbd Co-authored-by: ivan-pi <21085643+ivan-pi@users.noreply.github.com> * Improve ode_workspace mismatch diagnostics Agent-Logs-Url: https://github.com/ivan-pi/stiff3/sessions/a3bd8265-d95a-447c-96ff-c8de05acbfbd Co-authored-by: ivan-pi <21085643+ivan-pi@users.noreply.github.com> * Apply review feedback for workspace argument mapping Agent-Logs-Url: https://github.com/ivan-pi/stiff3/sessions/0bfd1f1c-6066-4bb0-9df3-d8078e1d0164 Co-authored-by: ivan-pi <21085643+ivan-pi@users.noreply.github.com> * Polish workspace argument indexing in stiff3_work Agent-Logs-Url: https://github.com/ivan-pi/stiff3/sessions/0bfd1f1c-6066-4bb0-9df3-d8078e1d0164 Co-authored-by: ivan-pi <21085643+ivan-pi@users.noreply.github.com> * Simplify workspace offset expressions in stiff3_work Agent-Logs-Url: https://github.com/ivan-pi/stiff3/sessions/0bfd1f1c-6066-4bb0-9df3-d8078e1d0164 Co-authored-by: ivan-pi <21085643+ivan-pi@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ivan-pi <21085643+ivan-pi@users.noreply.github.com>
1 parent 7249f65 commit d630523

4 files changed

Lines changed: 148 additions & 3 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ This repository provides a refactored version with a simplified procedural inter
1212
- Adaptive stepsize control with error tolerance per component
1313
- Optional maximum absolute half-step size (`hmax`) to cap step growth
1414
- Optional runtime statistics output: rhs evaluations (`nfev`), Jacobian evaluations (`njev`), and LU decompositions (`nlu`)
15+
- Optional explicit workspace interface via `stiff3(..., rwork, iwork, ...)` for caller-managed memory
1516
- Requires an exact user-supplied Jacobian
1617
- Depends on BLAS and LAPACK for linear algebra operations
1718
- Supports two build systems: [CMake](https://cmake.org/) and [Fortran Package Manager (fpm)](https://github.com/fortran-lang/fpm)
@@ -151,6 +152,8 @@ The two tolerance parameters `eps` and `w` together control how accurately the s
151152

152153
A reasonable first choice is `eps = 1.0e-4` with all `w(i) = 1.0`, which requests roughly four significant digits from every component.
153154

155+
For interoperability scenarios where the caller manages memory allocation (e.g. language bindings), `stiff3` also provides an overload with explicit work arrays: `rwork` of size `n*(7 + 2*n)` and `iwork` of size `n`.
156+
154157
You can also optionally pass `hmax` to limit the absolute half-step size used by the adaptive controller. If `hmax` is omitted or set to `0`, the default is `abs(x1-x0)`. If provided and positive, the solver uses `min(hmax, abs(x1-x0))`. Negative values are rejected.
155158

156159
**How the tolerance is applied:** after each step the solver estimates the local error in each component and checks:

src/stiff3_solver.f90

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module stiff3_solver
1616
implicit none
1717
private
1818

19-
public :: stiff3, stiff3_wp
19+
public :: stiff3, stiff3_auto, stiff3_work, stiff3_wp
2020
public :: rhs_sub, jacobian_sub, output_sub
2121

2222
!> Kind parameter for working precision of stiff3 reals
@@ -66,6 +66,11 @@ subroutine output_sub(nr,xold,x,y,iha,qa,irtrn)
6666

6767
end interface
6868

69+
interface stiff3
70+
module procedure stiff3_auto
71+
module procedure stiff3_work
72+
end interface
73+
6974

7075
contains
7176

@@ -74,7 +79,7 @@ subroutine output_sub(nr,xold,x,y,iha,qa,irtrn)
7479

7580
!> Semi-implicit Runge-Kutta integrator routine
7681
!
77-
subroutine stiff3(n,fun,dfun,x0,x1,h0,eps,w,y,solout,stats,hmax)
82+
subroutine stiff3_auto(n,fun,dfun,x0,x1,h0,eps,w,y,solout,stats,hmax)
7883
integer, intent(in) :: n
7984
!! Number of equations to be integrated.
8085
procedure(rhs_sub) :: fun
@@ -108,6 +113,81 @@ subroutine stiff3(n,fun,dfun,x0,x1,h0,eps,w,y,solout,stats,hmax)
108113
integer :: ip(n)
109114
!! Workspace for the pivot array
110115

116+
call stiff3_core(n,fun,dfun,x0,x1,h0,eps,w,y, &
117+
yk1,yk2,ya,yold,yold1,f,fold,df,dfold,ip, &
118+
solout,stats,hmax)
119+
120+
end subroutine
121+
122+
123+
!> Semi-implicit Runge-Kutta integrator routine with explicit workspace
124+
!
125+
subroutine stiff3_work(n,fun,dfun,x0,x1,h0,eps,w,y,rwork,iwork,solout,stats,hmax)
126+
integer, intent(in) :: n
127+
!! Number of equations to be integrated.
128+
procedure(rhs_sub) :: fun
129+
!! User supplied subprogram for function evaluation.
130+
procedure(jacobian_sub) :: dfun
131+
!! User supplied subprogram for evaluation of the Jacobian.
132+
real(wp), intent(in) :: x0, x1
133+
!! Limits of the independent variable between which the differential
134+
!! equation is solved.
135+
real(wp), intent(inout) :: h0
136+
!! Suggested initial half-step length. On exit `h0` contains suggested
137+
!! value of half-step length for continued integration beyond `x1`,
138+
!! or the suggested step size at an interrupted callback return.
139+
real(wp), intent(in) :: eps, w(n)
140+
!! Tolerance parameters.
141+
real(wp), intent(inout) :: y(n)
142+
!! Vector of dependent variables at `x0`. On exit `y` is the vector of
143+
!! dependent variables at `x1`.
144+
real(wp), intent(inout) :: rwork(n*(7 + 2*n))
145+
!! Real workspace of size `n*(7 + 2*n)`.
146+
integer, intent(inout) :: iwork(n)
147+
!! Integer workspace of size `n`.
148+
procedure(output_sub), optional :: solout
149+
!! User supplied subprogram for output.
150+
integer, intent(out), optional :: stats(3)
151+
!! Statistics array with `[nfev, njev, nlu]`.
152+
real(wp), intent(in), optional :: hmax
153+
!! Maximum absolute half-step size. If absent or zero, defaults to
154+
!! `abs(x1 - x0)`.
155+
156+
call stiff3_core(n,fun,dfun,x0,x1,h0,eps,w,y, &
157+
yk1 = rwork(1), &
158+
yk2 = rwork(n+1), &
159+
ya = rwork(2*n+1), &
160+
yold = rwork(3*n+1), &
161+
yold1 = rwork(4*n+1), &
162+
f = rwork(5*n+1), &
163+
fold = rwork(6*n+1), &
164+
df = rwork(7*n+1), &
165+
dfold = rwork(7*n+n*n+1), &
166+
ip = iwork(1), &
167+
solout=solout,stats=stats,hmax=hmax)
168+
169+
end subroutine
170+
171+
172+
!> Semi-implicit Runge-Kutta integrator routine core implementation
173+
!
174+
subroutine stiff3_core(n,fun,dfun,x0,x1,h0,eps,w,y, &
175+
yk1,yk2,ya,yold,yold1,f,fold,df,dfold,ip, &
176+
solout,stats,hmax)
177+
integer, intent(in) :: n
178+
procedure(rhs_sub) :: fun
179+
procedure(jacobian_sub) :: dfun
180+
real(wp), intent(in) :: x0, x1
181+
real(wp), intent(inout) :: h0
182+
real(wp), intent(in) :: eps, w(n)
183+
real(wp), intent(inout) :: y(n)
184+
real(wp), intent(inout) :: yk1(n), yk2(n), ya(n), yold(n), yold1(n), f(n), fold(n)
185+
real(wp), intent(inout) :: df(n,n), dfold(n,n)
186+
integer, intent(inout) :: ip(n)
187+
procedure(output_sub), optional :: solout
188+
integer, intent(out), optional :: stats(3)
189+
real(wp), intent(in), optional :: hmax
190+
111191
integer :: icon, iha, i, j, nr, irtrn
112192
integer :: nfev, njev, nlu
113193
real(wp) :: x, xold, h, e, es, q, qa, hmax_used

test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
foreach(test_program ode_linear_decay ode_order ode_logistic ode_stiff_linear ode_robertson_invariants ode_stats ode_hmax)
1+
foreach(test_program ode_linear_decay ode_order ode_logistic ode_stiff_linear ode_robertson_invariants ode_stats ode_hmax ode_workspace)
22
add_executable(${test_program} ${test_program}.f90)
33
target_link_libraries(${test_program} PRIVATE stiff3)
44
add_test(NAME ${test_program} COMMAND ${test_program})

test/ode_workspace.f90

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
program ode_workspace
2+
3+
use stiff3_solver, only: stiff3, wp => stiff3_wp
4+
5+
implicit none
6+
7+
integer, parameter :: n = 2
8+
real(wp) :: y_auto(n), y_work(n), w(n), x0, x1, h0, eps
9+
real(wp), allocatable :: rwork(:)
10+
integer, allocatable :: iwork(:)
11+
integer :: stats_auto(3), stats_work(3)
12+
13+
y_auto = [1.0_wp, -0.5_wp]
14+
y_work = y_auto
15+
w = 1.0_wp
16+
x0 = 0.0_wp
17+
x1 = 1.0_wp
18+
h0 = 0.02_wp
19+
eps = 1.0e-8_wp
20+
21+
allocate(rwork(n*(7 + 2*n)))
22+
allocate(iwork(n))
23+
24+
call stiff3(n,fun,jac,x0,x1,h0,eps,w,y_auto,stats=stats_auto)
25+
26+
h0 = 0.02_wp
27+
call stiff3(n,fun,jac,x0,x1,h0,eps,w,y_work,rwork,iwork,stats=stats_work)
28+
29+
if (any(y_auto /= y_work)) then
30+
print '(A,2(1X,ES12.4),A,2(1X,ES12.4))', &
31+
'solutions differ. auto=', y_auto, ' work=', y_work
32+
error stop 1
33+
end if
34+
35+
if (any(stats_auto /= stats_work)) then
36+
print '(A,3(I0,1X),A,3(I0,1X))', &
37+
'stats mismatch auto [nfev njev nlu]: ', stats_auto, &
38+
' work: ', stats_work
39+
error stop 1
40+
end if
41+
42+
contains
43+
44+
subroutine fun(n,y,f)
45+
integer, intent(in) :: n
46+
real(wp), intent(in) :: y(n)
47+
real(wp), intent(inout) :: f(n)
48+
f(1) = -2.0_wp*y(1) + y(2)
49+
f(2) = -3.0_wp*y(2)
50+
end subroutine
51+
52+
subroutine jac(n,y,df)
53+
integer, intent(in) :: n
54+
real(wp), intent(in) :: y(n)
55+
real(wp), intent(inout) :: df(n,n)
56+
df(1,1) = -2.0_wp
57+
df(1,2) = 1.0_wp
58+
df(2,1) = 0.0_wp
59+
df(2,2) = -3.0_wp
60+
end subroutine
61+
62+
end program

0 commit comments

Comments
 (0)