UP | HOME

Step Size & Order Vs Accuracy
A MRKISS Library Example Program

Author: Mitch Richling
Updated: 2025-08-18 15:22:34
Generated: 2025-08-18 15:22:39

Copyright © 2025 Mitch Richling. All rights reserved.

Table of Contents

1. Results

The code for this example is found in examples/step_order_vs_error.f90. Additionally the code may be found at the end of this document in the section Full Code Listing.

In this example we solve the same equation with two different Runge-Kutta methods – the classical \(\mathcal{O}(4)\) method and a newer \(\mathcal{O}(0)\) method. For each method we use 10 different step sizes.

The system we solve: \[ y'=t\cos(t^2) \,\,\,\mathrm{with}\,\,\, y(0)=0 \]

We can solve this equation symbolically: \[ y'\frac{\sin(t^2)}{2} \]

Here are a copule plots

step_order_vs_error_soly.png

step_order_vs_error_sold.png

The system is solved at 10 points, using order 4 and 9 methods with between 1 and 10 steps per point. The impact on accuracy is summarized in the following plot:

step_order_vs_error_err.png

2. Full Code Listing

2.1. Fortran Code

program step_order_vs_error

  use :: mrkiss_config,          only: rk, istats_size
  use :: mrkiss_solvers_wt,      only: steps_fixed_stab, steps_points_stab
  use :: mrkiss_utils,           only: print_solution, seq
  use :: mrkiss_erk_kutta_4,     only: a4=>a, b4=>b, c4=>c
  use :: mrkiss_eerk_verner_9_8, only: a9=>a, b9=>b1, c9=>c

  implicit none

  integer,        parameter :: deq_dim       = 1
  integer,        parameter :: num_points    = 10
  real(kind=rk),  parameter :: y_iv(deq_dim) = [0.0_rk]
  real(kind=rk),  parameter :: param(2)      = [1.0_rk, 1.0_rk]
  real(kind=rk),  parameter :: pi            = 4.0_rk * atan(1.0_rk)
  real(kind=rk),  parameter :: t_start       = 0.0_rk
  real(kind=rk),  parameter :: t_end         = 2.0_rk * pi

  real(kind=rk)             :: solution(1+2*deq_dim, num_points)
  integer                   :: status, istats(istats_size), spp
  character(len=512)        :: filename

  call seq(status, solution(1,:), from_o=t_start, to_o=t_end)

  do spp = 1,10
     call steps_points_stab(status, istats, solution, eq, y_iv, param, a4, b4, c4, spp)
     write (filename, '("step_order_vs_error_04_",i2.2,".csv")') spp
     call print_solution(status, solution, filename_o=trim(filename))

     call steps_points_stab(status, istats, solution, eq, y_iv, param, a9, b9, c9, spp)
     write (filename, '("step_order_vs_error_09_",i2.2,".csv")') spp
     call print_solution(status, solution, filename_o=trim(filename))
  end do

contains

  subroutine eq(status, dydt, t, y, param)
    integer,          intent(out) :: status
    real(kind=rk),    intent(out) :: dydt(:)
    real(kind=rk),    intent(in)  :: t
    real(kind=rk),    intent(in)  :: y(:)
    real(kind=rk),    intent(in)  :: param(:)
    dydt = [ t * param(1)*cos(param(2) * t * t) ]
    status = 0
  end subroutine eq

end program step_order_vs_error

2.2. R Code

The images were produced with R.

crvDat <- data.table(t=seq(0,2*pi, length.out=500)) %>% mutate(truy1=sin(t*t)/2)
drvDat <- data.table(t=seq(0,2*pi, length.out=500)) %>% mutate(trudy1=t*cos(t*t))

truDat <- data.table(t=seq(0,2*pi, length.out=10)) %>% transmute(truy1=sin(t*t)/2)

solDat <- do.call(rbind, lapply(list.files(pattern = "^step_order_vs_error_[0-9][0-9]_[0-9][0-9]\\.csv$"), 
                                function(f) { 
                                  rko=first(strsplit(f, "[_.]"))[5];
                                  spp=first(strsplit(f, "[_.]"))[6];
                                  cbind(fread(f), truDat) %>% 
                                    mutate(err=abs(y1-truy1), order=rko, steps_per_point=spp); })) %>% 
  filter(i>1 & steps_per_point!='01')

gp <- ggplot(crvDat) +
  geom_line(aes(x=t, y=truy1)) +
  labs(title='Solution', x='t', y='y') 
ggsave(filename='step_order_vs_error_soly.png', plot=gp, width=1024, height=800, units='px', dpi=150)

gp <- ggplot(drvDat) +
  geom_line(aes(x=t, y=trudy1)) +
  labs(title='Solution Derivative', x='t', y='y') 
ggsave(filename='step_order_vs_error_sold.png', plot=gp, width=1024, height=800, units='px', dpi=150)

gp <- ggplot(solDat) +
  geom_line( aes(x=t, y=err, shape=order, col=steps_per_point)) +
  geom_point(aes(x=t, y=err, shape=order, col=steps_per_point)) +
  annotate("text", x = 2, y = 1e-8, label = "4th Order\n\n9th Order", color = "black", size = 6) +
  annotate("segment", 
           x    = min(solDat$t), 
           xend = max(solDat$t), 
           y    = 1e-9,
           yend = 1e-5,
           linewidth=3) +
  scale_y_log10() +
  labs(title='Accuracy: Step Size & Order', x='t', y='Absolute Error') +
  guides(shape = "none")
print(gp)
ggsave(filename='step_order_vs_error_err.png', plot=gp, width=1024, height=1024, units='px', dpi=150)