numerical[1].mws

Approximation Methods

MA 507

October 25, 2000

Richard Hitt

Introduction

We look at methods of numerically approximating solutions to IVPs of the form diff(y(t),t) = f(t,y) , y(t[0]) = y[0] . For a concrete example we will use the exponential decay differential equation diff(y(t),t) = y with initial condition y(0) = 1 .

Euler's Method

> restart;

> f:=(x,y)->y;

f := proc (x, y) options operator, arrow; y end pro...

>

> y||0:=1;

y0 := 1

>

If we want to approximate the solution of this IVP when t=2, we can partition the interval [0,1] into N equal subintervals and use the linear shooting method to move in steps out to a t-value of 2. Using N=10 we first calculate the t-values

> N:=10; a:=0; b:=2; h:=evalf((b-a)/N);
t||0:=a;
for i from 1 to N do
t||i:=h + t||(i-1);
od;

N := 10

a := 0

b := 2

h := .2000000000

t0 := 0

t1 := .2000000000

t2 := .4000000000

t3 := .6000000000

t4 := .8000000000

t5 := 1.000000000

t6 := 1.200000000

t7 := 1.400000000

t8 := 1.600000000

t9 := 1.800000000

t10 := 2.000000000

>

We can now successively approximate the value of y[i] that correspond to the value of t[i] using the tangent line approximation based at the point ( t[n-1], y[n-1] ).

> y||0:=1;
for i from 1 to N do
y||i:= y||(i-1)+h*f(t||(i-1),y||(i-1));
od;

y0 := 1

y1 := 1.200000000

y2 := 1.440000000

y3 := 1.728000000

y4 := 2.073600000

y5 := 2.488320000

y6 := 2.985984000

y7 := 3.583180800

y8 := 4.299816960

y9 := 5.159780352

y10 := 6.191736422

>

To get a visualization for this approximation, we plot the points.

> points:=[seq([t||i,y||i],i=0..N)];

points := [[0, 1], [.2000000000, 1.200000000], [.40...
points := [[0, 1], [.2000000000, 1.200000000], [.40...
points := [[0, 1], [.2000000000, 1.200000000], [.40...

> plot(points,style=point,symbol=cross,view=[0..b,0..7.4]);

[Maple Plot]

>

We can compare the approximations to the actual solutions in this case since we can solve the IVP explicitly.

> dsolve({diff(y(t),t)=f(t,y(t)), y(0)=y||0},y(t));

y(t) = exp(t)

> exactsol:=unapply(rhs(%),t);

exactsol := exp

> J:=plot(points,style=POINT,symbol=CROSS,view=[0..b,0..exactsol(b)]):
K:=plot(exactsol(t),t=0..b,color=blue):
plots[display]({J,K});

[Maple Plot]

>

Runge-Kutta Method

The Runge-Kutta method provides us with much more accuracy to the point where we can use a much smaller value of N and still be a better result than with the Euler method.

> N:=4; a:=0; b:=2; h:=evalf((b-a)/N); t||0:=a;
for i from 1 to N do
t||i:=h + t||(i-1);
od;

N := 4

a := 0

b := 2

h := .5000000000

t0 := 0

t1 := .5000000000

t2 := 1.000000000

t3 := 1.500000000

t4 := 2.000000000

> y||0:=1:
for i from 1 to N do
k1 := f(t||(i-1),y||(i-1)):
k2 := f(t||(i-1)+h/2,y||(i-1)+h/2*k1):
k3 := f(t||(i-1)+h/2,y||(i-1)+h/2*k2):
k4 := f(t||i,y||(i-1)+h*k3):
y||i:= y||(i-1) + h/6*( k1 + 2*k2 + 2*k3 + k4);
od;

k1 := 1

k2 := 1.250000000

k3 := 1.312500000

k4 := 1.656250000

y1 := 1.648437500

k1 := 1.648437500

k2 := 2.060546875

k3 := 2.163574219

k4 := 2.730224610

y2 := 2.717346192

k1 := 2.717346192

k2 := 3.396682740

k3 := 3.566516877

k4 := 4.500604630

y3 := 4.479375364

k1 := 4.479375364

k2 := 5.599219205

k3 := 5.879180165

k4 := 7.418965446

y4 := 7.383970327

> rkpoints :=[seq([t||i,y||i],i=0..N)];

rkpoints := [[0, 1], [.5000000000, 1.648437500], [1...

We can plot the exact solution together with the Euler and Runge-Kutta approximations together. Note how the Runge-Kutta does a much better job in this case even though we are using fewer points.

> L:=plot(rkpoints,style=POINT,symbol=DIAMOND,
view=[0..b,0..exactsol(b)],color=red):
plots[display]({J,K,L});

[Maple Plot]

>

>

Maple has numerical methods built-in

Rather than doing the numerical methods by hand (well almost) as above, we can take advantage of Maple's built-in ability to handle this.

> restart:
with( DEtools ):
with( plots ):

Warning, the name changecoords has been redefined

Let's work on the IVP

diff(y(t),t) = t+sqrt(y(t)) , y(0) = 1

We can use the Euler method, the improved Euler method (Heun method), and the Runge-Kutta method and compare the results.

> eul :=dsolve(
{diff(y(t),t) = t + y(t), y(0)=1}, y(t),
type=numeric, method=classical[foreuler], stepsize=.33
);

eul := proc (x_classical) local i, _s, st, en, outp...

> heun :=dsolve(
{diff(y(t),t)=t+y(t), y(0)=1}, y(t),
type=numeric, method=classical[heunform], stepsize=.33
);

heun := proc (x_classical) local i, _s, st, en, out...

> rk :=dsolve(
{diff(y(t),t)=t+y(t), y(0)=1}, y(t),
type=numeric, method=classical[rk4], stepsize=.33
);

rk := proc (x_classical) local i, _s, st, en, outpo...

> plot1 := odeplot(eul,[t,y(t)],color=red):
plot2 := odeplot(heun,[t,y(t)],color=green):

> plot3 := odeplot(rk,[t,y(t)],color=blue):

> display(plot1,plot2,plot3,view=[0..3,0..30]);

[Maple Plot]

You can experiment with the stepsize on the Euler method to see how small you have to make it to get an approximation to the solution that is as good as the Runge-Kutta method. Note that the Heun method gives much better results in this case that the regular Euler method.

The "method=classical" option used in the dsolve command instructs Maple to use a static (fixed) step size. Left to its defaults, Maple would employ an adaptive stepsize making is smaller as needed to gain accuracy.

When Things Go Wrong

An Example

Here is a simple example that illustrates the possible pathology in numerical solutions.

We solve the IVP 2*diff(y(t),t)*y(t) = -1 , y(0) = 1 . We can get an exact solution using dsolve.

> sol:=dsolve({2*diff(y(t),t)*y(t)=-1, y(0)=1},y(t));

sol := y(t) = sqrt(-t+1)

> plot(rhs(sol),t=0..2);

[Maple Plot]

If we use DEplot to get a plot of a numerical solution, the default method Maple uses is classical[rk4]. This method is not sensitive to vertical tangents on the solution, so it blindly computes right across them producing potentially rediculous results.

> DEplot(2*diff(y(t),t)*y(t)=-1, y(t), t=0..2, [[0,1]]);

[Maple Plot]

We can get slightly less rediculous results by reducing the stepsize.

> DEplot(2*diff(y(t),t)*y(t)=-1, y(t), t=0..2, [[0,1]], stepsize=0.01);

[Maple Plot]

But for better results, we need to let Maple use an adaptive stepsize.

> DEplot(2*diff(y(t),t)*y(t)=-1, y(t), t=0..2, [[0,1]], method=rkf45);

Error, (in DEtools/DEplot/drawlines) Stopping integration due to rkf45 is unable to achieve requested accuracy

The numerical method recognizes that it cannot subdivide the stepsize enough to achieve its default accuracy and simply reports that rather than drawing an erroneous graph.

>

>

Another Example

> DEplot(diff(y(x),x) = x^2/(1-y(x)^2),y(x),x=-2..2,y=-2..2,[[0,2]]);

[Maple Plot]

>

Another Example

> ode:=diff(y(t),t$2)+y(t)=0;

ode := diff(y(t),`$`(t,2))+y(t) = 0

> plot1:=DEplot(ode,y(t),t=0..100,[[y(0)=1,D(y)(0)=0]],stepsize=.6,color=red):

> plot2:=plot(rhs(dsolve({ode,y(0)=1,D(y)(0)=0},y(t))),t=0..100,color=blue):

> display({plot1,plot2});

[Maple Plot]

>