4th Order Runge-Kutta

2025-12-12

A 4th order Runga-Kutta integrator for solving ODEs. This intended to be loaded into the library and used that way (e.g. LOAD "rk4.bas" <enter> LIBRARY SAVE). The subroutine works in-place, filling an output array(n,m) with the answer for an n dimensional problem with m timesteps. The screenshot is from an example, solving the ode f(t,y) = -y with three different initial conditions.


/* Runge-Kutta 4th Order ODE Integrator

rk4 fname$,y0(),t0,dt,o()

Integrates the ODE system using RK-4
with a fixed step size.

Arguments:
fname$ - function name of rhs of ode
         fname(t,y(),o())
         where the result is returned
         in-place in the array o
         function returns 1 for success
         and 0 to terminate integration
y0(n)  - array of initial conditions
t0     - initial value of t
dt     - fixed time step
o(n,m) - pre-allocated output array
         n variables
         m timesteps
*/
Function rk4step(fname$,yt(),t,dt) as integer
 'initialize bounds on arrays
 Static integer l = Bound(yt(),0)
 Static integer n = Bound(yt(),1)

 'rk arrays
 Static float dts(3+l) = (0.0,0.5*dt,0.5*dt,dt)
 Static float rks(3+l) = (dt/6,dt/3,dt/3,dt/6)
 Static float s(n),a(n),k(n)
 Array Set 0,s()
 Array Set 0,k()

 'integration step
 Local integer i
 For i=l To 3+l
  'y_{t} + dts_i * k_{i-1}
  Math scale k(),dts(i),k()
  Math c_add yt(),k(),k()
  t = t + dts(i)

  'k_{i} = f(t+dts_i,y_{t}+dts_i*k_{i-1})
  flag = Call(fname$,t,k(),k())
  If flag=0 Then
   rk4step=0
   Exit Function
  End If

  '\sum_{i=1}^4 rks_i*k_i
  Math scale k(),rks(i),a()
  Math c_add s(),a(),s()
 Next i

 'y_{t+dt} = y_{t} + \sum
 Math c_add yt(),s(),yt()
 rkstep=1
End Function

Sub rk4 fname$,y0(),t0,dt,o()
 'check bounds of arrays
 Local integer l = Bound(o(),0)
 Local integer n = Bound(o(),1)
 Local integer m = Bound(o(),2)

 If Bound(y0(),0) <> l Then
'I don't know if this is even possible
  Error "y0 and o must start at the same index"
 End If

 If Bound(y0(),1) <> n Then
  Error "array size mismatch"
 End If

 'initialize loop variables
 Local integer i,flag
 Local float yi(n)
 Local float ti = t0
 Array Add y0(),0,yi()
 Array Insert o(),,l,y0()

 'main loop
 For i=l+1 To m
  flag = rk4step(fname$,yi(),ti,dt)
  If flag=1 Then
   Print Format$(ti,"Integration terminated at t=%g")
   Exit For
  End If
  Array Insert o(),,i,yi()
  ti = ti + dt
 Next i
End Sub