10  L10: Improved Euler’s Method and Runge-Kutta Methods (3.2)

10.1 Recall Euler’s method

# Our differential equation
diff <- function(x,y)
{
    return(x+y) #Try also x/y
}

# Line function
TheLine <- function(x1,y1,slp,d)
{
    z = slope*(d-x1)+y1
    return(z)
}

# Domains
x = seq(-20,20,0.5)
y = seq(-20,20,0.5)

# Points to draw our graph
f = c(-5,5) 
h = c(-5,5)
plot(f,h,main="Slope field, dy/dx= x+y")
lines(c(-2,-1.5,-1,-.5,0),c(2.2,2.2,2.6,3.2,4.5),type ="p",pch=19,cex=.7,col="red")

# Let's generate the slope field
for(j in x)
{
    for(k in y)
    {
        slope = diff(j,k)
        domain = seq(j-0.07,j+0.07,0.14)
        z = TheLine(j,k,slope,domain)
        arrows(domain[1],z[1],domain[2],z[2],length = 0.05, angle = 10,code=2)
    }
}

10.2 Recall Euler’s method (Zoom)

\[\frac{dy}{dx}=g(x,y),\qquad y(x_0)=y_0\] \[\boxed{y_1 = y_0+g(x_0,y_0)\cdot(x_1-x_0)}\]

How can we improve the method?

?

10.3 Improved linear approx.

Conceptual Idea: use the slope at \((x_0,y_0)\) and the slope at \((x_1,y_1)\)

Concept: Average of the slopes to improve linear approximation.

Improved Linear approximation(1-step Euler)

Calculate \(m_1\) by evaluating \(g(x_0,y_0\)), no problem!

Improved Linear approximation(1-step Euler)

Calculate \(m_2\) by evaluating \(g(x_1,y_1)\) \(\cdots\)

but I dont know \(y_1\), because that is what I want to find!

so what to do?

I can estimated \(y_1\)

\[y_1 \approx y_0+g(x_0,y_0)(x_1-x_0)\] \[= y_{1s}\]

Improved Linear approximation(1-step Euler)

Now I use the average of \(m_1\) and \(m_2\) to get a better estimation of the function between \(x_0\) and \(x_1\):

Improved Linear approximation(1-step Euler)
Improved linear approx.

10.4 1-step improved Euler

Idea: use slope at \((x_0,y_0)\) and \((x_1,y_1)\)

\[y_1^* = y_0+g(x_0,y_0)(x_1-x_0)\qquad\text{(1-step Euler)}\]

\[m=\frac{g(x_0,y_0)+g(x_1,y_1^*)}{2}\] \[\boxed{y_1=y_0+m(x_1-x_0)}\qquad\text{(Improved 1-step Euler)}\]

10.5 n-steps improved Euler1

\[\begin{align} y_1&=y_0+m_1(x_1-x_0)\\ y_2&=y_1+m_2(x_2-x_1)\\ \cdots \end{align}\]

\[\boxed{y_n=y_{n-1}+m_n(x_n-x_{n-1})}\] where \[m_n=\frac{g(x_{n-1},y_{n-1})+g(x_{n},y_n^*)}{2}\] and \(y_n^*\) is obtained with Euler method.

10.6 Runge-Kutta Methods

Second order method (weighted Improved Euler)

While Euler’s method is useful, it does quite poorly in cases where the solution is changing rapidly. A way to circumvent this is to adjust the value of \(\Delta x\) to be smaller, which comes at the expense of more computational time. A second way is to use a higher order solver than euler, and one such method is called the Runge-Kutta method.

\[\boxed{\boxed{y_1=y_0+aK_1+bK_2}}\] \[\boxed{K_1=g(x_0,y_0)\Delta x}\] \(K_1\), is defined as how much I rise when I only consider the rate at \(x_0\).

and

\[\boxed{K_2=g(x_0+\alpha\Delta x, y_0+\beta K_1)\Delta x}\] is defined as the rise due to the change of \(K_1\) and other parameters, \(\alpha\) and \(\beta\), which related how fast I am advancing on my immediate space.

The conditions for this parameters are:

\[\boxed{a+b=1,\qquad b\alpha=\frac{1}{2},\qquad b\beta =\frac{1}{2}}\] In most cases: \(\alpha=\beta=\frac{1}{2b}\)

10.7 Recovering Improved Euler from RK

\[\boxed{y_1=y_0+aK_1+bK_2}\]

But, if \[\alpha=1=\beta,\quad a=b=1/2\] then:

\[y_1=y_0+ag(x_0,y_0)\Delta x+bg(x_0+\alpha\Delta x, y_0+\beta K_1)\] \[y_1=y_0+\frac{1}{2}g(x_0,y_0)\Delta x+\frac{1}{2}g(x_0+\Delta x, y_0+K_1)\] \[y_1=y_0+\frac{1}{2}g(x_0,y_0)\Delta x+\frac{1}{2}g(x_0+\Delta x, y_0+\frac{1}{2}g(x_0,y_0)\Delta x)\] \[ \boxed{y_1 = y_0+\frac{g(x_0,y_0)+g(x_1,y_1)}{2}\Delta x} \]

10.9 Example using demodelr

10.10 Using Runge-Kutta-4 function from R

rm(rk4) # First I need to remove my rk4 function
library(demodelr) # This library load a rk4, and more

infection_eq <- c(dpdt ~ .023 * p * (1 - p))
prop_init <- c(p = 250/13600)
deltaT <- 1
n_steps <- 600
out_solution <- rk4(system_eq = infection_eq,
                      initial_condition = prop_init,
                      parameters = c(beta=0.2, alpha=0.2),
                      deltaT = deltaT, 
                      n_steps = n_steps
                      )
str(out_solution)
tibble [600 × 2] (S3: tbl_df/tbl/data.frame)
 $ t: num [1:600] 0 1 2 3 4 5 6 7 8 9 ...
 $ p: num [1:600] 0.0184 0.0188 0.0192 0.0197 0.0201 ...

library(ggplot2)
ggplot(data = out_solution) +
  geom_line(aes(x = t, y = p), color = "blue",linetype='dashed', lwd=2) +
  labs(
    x = "Time",
    y = "Solution"
  )

10.11 References

  1. LibreTexts, 3.3: The Runge-Kutta Method from William F. Trench.
  2. slope field code for R and python
  3. Modelling with R

  1. please put attention, for n-steps \(m_1\) is not the same of 1-step Euler. \(m_1\) correspond to the mean of the slope at \(x_0\) and \(x_1\).↩︎