0% found this document useful (0 votes)
788 views342 pages

Main

This document provides an overview of numerical methods for solving differential equations. It begins with an introduction and then covers various methods for solving initial value problems for ordinary differential equations (ODEs), including Taylor's method, Euler's method, and Runge-Kutta methods. It also discusses shooting methods for boundary value problems, finite difference methods for ODEs, properties of partial differential equations (PDEs), methods for elliptic and parabolic PDEs, and diffusion problems. The document contains examples throughout to illustrate the application of these numerical methods.

Uploaded by

chipulino
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
788 views342 pages

Main

This document provides an overview of numerical methods for solving differential equations. It begins with an introduction and then covers various methods for solving initial value problems for ordinary differential equations (ODEs), including Taylor's method, Euler's method, and Runge-Kutta methods. It also discusses shooting methods for boundary value problems, finite difference methods for ODEs, properties of partial differential equations (PDEs), methods for elliptic and parabolic PDEs, and diffusion problems. The document contains examples throughout to illustrate the application of these numerical methods.

Uploaded by

chipulino
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 342

Numerical Methods for Engineers

A digital compendium

Leif Rune Hellevik

Department of Structural Engineering, NTNU

Jan 16, 2017


Contents

1 Introduction 7
1.1 Check Python and LiClipse plugin . . . . . . . . . . . . . . . . . 7
1.2 Scientific computing with Python . . . . . . . . . . . . . . . . . . 8

2 Initial value problems for ODEs 9


2.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.1 Example: A mathematical pendulum . . . . . . . . . . . . 10
2.1.2 n-th order linear ordinary differential equations . . . . . . 11
2.2 Taylor’s method . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.1 Example: Taylor’s method for the non-linear mathematical
pendulum . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.2 Example: Newton’s first differential equation . . . . . . . 14
2.3 Reduction of Higher order Equations . . . . . . . . . . . . . . . . 14
2.3.1 Example: Reduction of higher order systems . . . . . . . 16
2.4 Differences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.4.1 Example: Discretization of a diffusion term . . . . . . . . 23
2.5 Euler’s method . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.5.1 Example: Eulers method on a simple ODE . . . . . . . . 25
2.5.2 Example: Eulers method on the mathematical pendulum 26
2.5.3 Example: Generic euler implementation on the mathemat-
ical pendulum . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.5.4 Example: Sphere in free fall . . . . . . . . . . . . . . . . . 29
2.5.5 Example: Falling sphere with constant and varying drag . 32
2.6 Python functions with vector arguments and modules . . . . . . 39
2.7 How to make a Python-module and some useful programming
features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.7.1 Example: Numerical error as a function of ∆t . . . . . . . 47
2.8 Heun’s method . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.8.1 Example: Newton’s equation . . . . . . . . . . . . . . . . 51
2.8.2 Example: Falling sphere with Heun’s method . . . . . . . 53
2.9 Generic second order Runge-Kutta method . . . . . . . . . . . . 56
2.10 Runge-Kutta of 4th order . . . . . . . . . . . . . . . . . . . . . . 57
2.10.1 Example: Falling sphere using RK4 . . . . . . . . . . . . 59
2.10.2 Example: Particle motion in two dimensions . . . . . . . 61

2
CONTENTS 3

2.10.3 Example: Numerical error as a function of ∆t for ODE-


schemes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.11 Stability of explicit RK-methods . . . . . . . . . . . . . . . . . . 83
2.11.1 Example: Stability of Euler’s method . . . . . . . . . . . 84
2.11.2 Example: Stability of Heun’s method . . . . . . . . . . . 86
2.11.3 Stability of higher order RK-methods . . . . . . . . . . . 87
2.12 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

3 Shooting Methods 96
3.1 Linear equations . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
3.1.1 Example: Couette-Poiseuille flow . . . . . . . . . . . . . . 100
3.1.2 Example: Simply supported beam with constant cross-
sectional area . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.1.3 Example: Simply supported beam with varying cross-
sectional area . . . . . . . . . . . . . . . . . . . . . . . . . 107
3.2 Non-linear boundary value problems of ODEs . . . . . . . . . . . 111
3.2.1 Example: Large deflection of a cantilever . . . . . . . . . 117
3.3 Notes on similarity solutions . . . . . . . . . . . . . . . . . . . . . 122
3.3.1 Example: Freezing of a waterpipe . . . . . . . . . . . . . . 126
3.3.2 Example: Stokes 1. problem . . . . . . . . . . . . . . . . . 127
3.3.3 Example: Blasius-ligningen . . . . . . . . . . . . . . . . . 129
3.3.4 Example:Falkner-Skan ligningen . . . . . . . . . . . . . . 135
3.4 Skyting med to startbetingelser . . . . . . . . . . . . . . . . . . . 140
3.4.1 Lineære ligninger . . . . . . . . . . . . . . . . . . . . . . . 140
3.4.2 Example: Sylindrisk tank med væske . . . . . . . . . . . . 141
3.4.3 Eksempel på ikke-lineære ligninger . . . . . . . . . . . . . 146
3.5 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

4 Finite differences for ODEs 154


4.1 Tridiagonal systems of algebraic equations . . . . . . . . . . . . . 154
4.1.1 Example: Heat conduction. Heat exchanger with constant
cross-section . . . . . . . . . . . . . . . . . . . . . . . . . 158
4.1.2 Ribbe med variabelt tverrsnitt . . . . . . . . . . . . . . . 168
4.1.3 Example: Talleksempel for trapesprofilet . . . . . . . . . . 170
4.2 To-punktsmetode. Varmeveksler. . . . . . . . . . . . . . . . . . . 175
4.2.1 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
4.2.2 Example: Varmeveksler . . . . . . . . . . . . . . . . . . . 177
4.2.3 Example: Talleksempel . . . . . . . . . . . . . . . . . . . 184
4.3 Linearinsering av ikke-linære algebraiske ligninger . . . . . . . . . 187
4.3.1 Metoden med etterslep . . . . . . . . . . . . . . . . . . . . 188
4.3.2 Newton-linearisering . . . . . . . . . . . . . . . . . . . . . 190
4.3.3 Example: . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
4.3.4 Example: . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
4.3.5 Example: . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
4.3.6 Eksempler på stoppkriterier . . . . . . . . . . . . . . . . . 194
4.3.7 Ligninger på delta-form . . . . . . . . . . . . . . . . . . . 196
CONTENTS 4

4.3.8 Kvasilinearisering . . . . . . . . . . . . . . . . . . . . . . . 197


4.3.9 Example: . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
4.4 Løsning av Blasius ligning ved bruk av differansemetode . . . . . 199
4.5 Differential boundary conditions/von Neumann boundary conditions199
4.6 Iterative solution of ODEs . . . . . . . . . . . . . . . . . . . . . . 199
4.7 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200

5 Mathematical properties of PDEs 204


5.1 Model equations . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
5.1.1 Liste over noen modell-ligninger . . . . . . . . . . . . . . 204
5.2 First order partial differential equations . . . . . . . . . . . . . . 205
5.3 Second order partial differenatial equations . . . . . . . . . . . . 209
5.4 RANDBETINGELSER FOR 2. ORDENS PDL . . . . . . . . . . 212
5.4.1 Hyberbolsk ligning . . . . . . . . . . . . . . . . . . . . . . 213
5.4.2 Elliptisk ligning . . . . . . . . . . . . . . . . . . . . . . . . 213
5.4.3 Parabolsk ligning . . . . . . . . . . . . . . . . . . . . . . . 214
5.5 VELFORMULERT PROBLEM. OPPSUMMERING . . . . . . . 215
5.6 PARTIKULÆRLØSNINGER AV LINEÆRE PDL . . . . . . . . 217

6 Elliptic PDEs 220


6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
6.2 Differanser. Notasjon . . . . . . . . . . . . . . . . . . . . . . . . . 222
6.2.1 Example: Discretization of the Laplace equation . . . . . 224
6.3 Direct numerical solution . . . . . . . . . . . . . . . . . . . . . . 224
6.3.1 von Neumann boundary conditions . . . . . . . . . . . . . 232
6.4 Iterative methods for linear algebraic equation systems . . . . . . 238
6.4.1 Stop criteria . . . . . . . . . . . . . . . . . . . . . . . . . 243
6.4.2 Optimal relaksasjonsparameter . . . . . . . . . . . . . . . 245
6.4.3 Eksempel på bruk av SOR . . . . . . . . . . . . . . . . . 246
6.4.4 Startverdier og randbetingelser . . . . . . . . . . . . . . . 248
6.4.5 Example: A non-linear elliptic PDE . . . . . . . . . . . . 248
6.4.6 Convergence criteria . . . . . . . . . . . . . . . . . . . . . 254
6.4.7 UTNYTTELSE AV SYMMETRI . . . . . . . . . . . . . . 261

7 Diffusjonsproblemer 266
7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
7.2 Confined, unsteady Couette flow . . . . . . . . . . . . . . . . . . 267
7.3 Stability: Criterion for positive coefficients. PC-criterion . . . . . 272
7.4 Stability analysis with von Neumann’s method . . . . . . . . . . 273
7.4.1 Example: Practical usage of the von Neumann condition . 276
7.5 Flere skjema for parabolske ligninger . . . . . . . . . . . . . . . . 278
7.5.1 Richardson-skjemaet (1910) . . . . . . . . . . . . . . . . . 278
7.5.2 Dufort-Frankel skjemaet (1953) . . . . . . . . . . . . . . . 280
7.5.3 Crank-Nicolson skjemaet. θ-skjemaet . . . . . . . . . . . . 281
7.5.4 Von Neumanns generelle stabilitetsbetingelse . . . . . . . 286
7.6 Trunkeringsfeil, konsistens og konvergens . . . . . . . . . . . . . . 287
CONTENTS 5

7.6.1 Trunkeringsfeil . . . . . . . . . . . . . . . . . . . . . . . . 287


7.6.2 Konsistens . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
7.6.3 Example: Consistency of the FTCS-scheme . . . . . . . . 288
7.6.4 Example: Consistency of the DuFort-Frankel scheme . . . 289
7.6.5 Konvergens . . . . . . . . . . . . . . . . . . . . . . . . . . 289
7.7 Eksempler med radiell symmetri . . . . . . . . . . . . . . . . . . 290
7.7.1 Example: Oppstart av rørstrømning . . . . . . . . . . . . 292
7.7.2 Example: Avkjøling av kule . . . . . . . . . . . . . . . . . 297

8 hyperbolic PDEs 301


8.1 The advection equation . . . . . . . . . . . . . . . . . . . . . . . 301
8.1.1 Forward in time central in space discretization . . . . . . 301
8.1.2 Upwind schemes . . . . . . . . . . . . . . . . . . . . . . . 304
8.2 The modified differential equation . . . . . . . . . . . . . . . . . 307
8.3 Errors due to diffusion and dispersion . . . . . . . . . . . . . . . 309
8.3.1 Example: Advection equation . . . . . . . . . . . . . . . . 309
8.3.2 Example: Diffusion and dispersion errors for the upwinding
schemes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
8.3.3 Example: Diffusion and disperision errors for Lax-Wendroff
schemes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
8.4 The Lax-Friedrich Scheme . . . . . . . . . . . . . . . . . . . . . . 313
8.5 Lax-Wendroff Schemes . . . . . . . . . . . . . . . . . . . . . . . . 313
8.5.1 Lax-Wendroff for non-linear systems of hyperbolic PDEs . 314
8.5.2 Code example for various schemes for the advection equation316
8.6 Order analysis on various schemes for the advection equation . . 319
8.6.1 Separating spatial and temporal discretization error . . . 321
8.7 Flux limiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
8.8 Example: Burgers equation . . . . . . . . . . . . . . . . . . . . . 330
8.8.1 Upwind Scheme . . . . . . . . . . . . . . . . . . . . . . . . 331
8.8.2 Lax-Friedrich . . . . . . . . . . . . . . . . . . . . . . . . . 331
8.8.3 Lax-Wendroff . . . . . . . . . . . . . . . . . . . . . . . . . 331
8.8.4 MacCormack . . . . . . . . . . . . . . . . . . . . . . . . . 332
8.8.5 Method of Manufactured solution . . . . . . . . . . . . . . 332

9 Python Style Guide 335


9.1 The conventions we use . . . . . . . . . . . . . . . . . . . . . . . 335
9.2 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335
9.3 The code is the documentation... i.e. the docs always lie! . . . . . 336
9.4 Docstring Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . 336

10 Sympolic computation with SymPy 337


10.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
10.2 Basic features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337

Bibliography 340
CONTENTS 6

Index 342
Chapter 1

Introduction

This digital compendium is based on the first chapter of the compendium


Numeriske Beregninger by J.B. Aarseth. It’s intended to be used in the course
TKT4140 Numerical Methods with Computer Laboratory at NTNU.
The development of the technical solutions for this digital compendium
results from collaborations with professor Hans Petter Langtangen at UiO
([email protected]), who has developed Doconce for flexible typesetting, and asso-
ciate professor Hallvard Trætteberg at IDI, NTNU ([email protected]), who has
developed the webpage-parser which identifies Python-code for integration in
Eclipse IDEs (such as LiClipse). The latter part of the development has been
funded by the project IKTiSU.
Johan Kolstø was instrumental in the initial phase and the develompent of
the first version of the Digital Compendium consisting of only chapter1 and for
programming examples and development of exercises.
Marie Kjeldsen Bergvoll made important contributions during her summerjob
with the translation of chapters 2-7 from LATEX to Doconce.
Finally, during the fall 2015 Fredrik Eikeland Fossan have contributed enor-
mously by implementing python code for most chapters. In particular his
contributions to the test procedures for MMS and to algorithms for testing of
the order of numerical PDE schemes are highly appreciated.

1.1 Check Python and LiClipse plugin


This page is ment as a check that you have Python and the necessary Python
Packages installed, and also that the Eclipse/LiClipse IDE plugin is working.
Download and run the code systemCheck.py in your Eclipse/LiClipse IDE.
For an illustration on how to download the Eclipse/LiClipse plugin and how to
use it see this video LiClipsePlugin.mp4 LiClipsePlugin.ogg
# src-ch0/systemCheck.py

def systemCheck():
’’’

7
CHAPTER 1. INTRODUCTION 8

Check for necessary moduls needed in the course tkt4140:


matplotlib
numpy
scipy
sympy

’’’
installed = " ... installed!"
print ""
print "Check for necessary modules needed for the course tkt4140"
print ""

print "check for matplotlib ",


try:
import matplotlib.pyplot
print installed
except:
print " IMPORT ERROR; no version of matplotlib.pyplot found"

print "check for numpy ",


try:
import numpy
print installed

except:
print " IMPORT ERROR; no version of numpy found"

print "check for scipy ",


try:
import scipy
print installed
except:
print " IMPORT ERROR; no version of scipy found"

print "check for sympy ",


try:
import sympy
print installed
except:
print " IMPORT ERROR; no version of sympy found"

if __name__ == ’__main__’:
systemCheck()

1.2 Scientific computing with Python


In this course we will use the programming language Python to solve numerical
problems. Students not familiar with Python are strongly recommended to work
through the example Intro to scientific computing with Python before proceeding.
If you are familiar with Matlab the transfer to Python should not be a problem.
Chapter 2

Initial value problems for


Ordinary Differential
Equations

2.1 Introduction
With an initial value problem for an ordinary differential equation (ODE) we
mean a problem where all boundary conditions are given for one and the same
value of the independent variable. For a first order ODE we get e.g.
y 0 (x) = f (x, y) (2.1)
y(x0 ) = a (2.2)
while for a second order ODE we get

y 00 (x) = f (x, y, y 0 ) (2.3)


y(x0 ) = a, y 0 (x0 ) = b (2.4)
A first order ODE, as shown in Equation (2.1), will always be an initial value
problem. For Equation (2.3), on the other hand, we can for instance specify the
boundary conditions as follows,
y(x0 ) = a, y(x1 ) = b
With these boundary conditions Equation (2.3) presents a boundary value problem.
In many applications boundary value problems are more common than initial
value problems. But the solution technique for initial value problems may often
be applied to solve boundary value problems.
Both from an analytical and numerical viewpoint initial value problems are
easier to solve than boundary value problems, and methods for solution of initial
value problems are more developed than for boundary value problems.

9
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 10

If we are to solve an initial value problem of the type in Equation (2.1), we


must first be sure that it has a solution. In addition we will demand that this
solution is unique, together the two criteria above lead to the following criteria:

The criteria for existence and uniqueness


A sufficient criteria for existence and uniqueness of a solution of the
problem in Equation (2.1) is that both f (x, y) and ∂f
∂y are continuous in
and around x0 .

For (2.3) this conditions becomes that f (x, y), ∂f


∂y and
∂f
∂y 0 are continuous in
and around x0 . Similarly for higher order equations.

Violation of the criteria for existence and uniqueness


1
y 0 = y 3 , y(0) = 0
1 ∂f 1
Here f = y 3 and ∂y = 2 . f is continuous in x = 0, but that’s not the
3y 3
∂f
case for ∂y . It may be shown that this ODE has two solutions: y = 0 and
2
y = ( 23 x) 3 . Hopefully this equation doesn’t present a physical problem.

2.1.1 Example: A mathematical pendulum


A problem of more interest is the mathematical pendulum (see Figure 2.1). By
using Newton’s second law in the θ-direction one can show that the following
equation must be satisfied:

∂2θ g
2
+ sin(θ) = 0 (2.5)
∂τ l

θ(0) = θ0 , (0) = 0 (2.6)

To present the governing equation (2.6) on
p a more convenient form, we
introduce a dimensionless time t given by t = gl · τ such that (2.5) and (2.6)
may be written as:

θ̈(t) + sin(θ(t)) = 0 (2.7)


θ(0) = θ0 , θ̇(0) = 0 (2.8)
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 11

g
θ
θ0

Figure 2.1: An illustration of the mathematical pendulum.

The dot denotes derivation with respect to the dimensionless time t. For small
displacements we can set sin(θ) ≈ θ, such that (2.7) and (2.8) becomes

θ̈(t) + θ(t) = 0 (2.9)


θ(0) = θ0 , θ̇(0) = 0 (2.10)

The difference between (2.7) and (2.9) is that the latter is linear, while the
first is non-linear. The analytical solution of Equations (2.7) and (2.8) is given
in Appendix G.2. in the Numeriske Beregninger.

2.1.2 n-th order linear ordinary differential equations


An n-th order linear ODE may be written on the generic form:

an (x)y (n) (x) + an−1 (x)y (n−1) (x) + · · · + a1 (x)y 0 (x) + a0 (x)y(x) = b(x) (2.11)

where y (k) , k = 0, 1, . . . n is referring to the k’th derivative and y (0) (x) = y(x).
If one or more of the coefficients ak also are functions of at least one y (k) , k =
0, 1, . . . n, the ODE is non-linear. From (2.11) it follows that (2.7) is non-linear
and (2.9) is linear.
Analytical solutions of non-linear ODEs are rare, and except from some
special types, there are no general ways of finding such solutions. Therefore
non-linear equations must usually be solved numerically. In many cases this is
also the case for linear equations. For instance it doesn’t exist a method to solve
the general second order linear ODE given by

a2 (x) · y 00 (x) + a1 (x) · y 0 (x) + a0 (x) · y(x) = b(x)

From a numerical point of view the main difference between linear and
non-linear equations is the multitude of solutions that may arise when solving
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 12

non-linear equations. In a linear ODE it will be evident from the equation if


there are special critical points where the solution change character, while this
is often not the case for non-linear equations.
For instance the equation y 0 (x) = y 2 (x), y(0) = 1 has the solution y(x) = 1−x
1

such that y(x) → ∞ for x → 1, which isn’t evident from the equation itself.

2.2 Taylor’s method


Taylor’s formula for series expansion of a function f (x) around x0 is given by

(x − x0 )2 00 (x − x0 )n (n)
f (x) = f (x0 )+(x−x0 )·f 0 (x0 )+ f (x0 )+· · ·+ f (x0 )+higher order terms
2 n!
(2.12)
Let’s use this formula to find the first terms in the series expansion for θ(t)
around t = 0 from the differential equation given in (2.9):

θ̈(t) + θ(t) = 0 (2.13)


θ(0) = θ0 , θ̇(0) = 0 (2.14)

First we observe that the solution to the ODE in (2.14) may be expressed as
an Taylor expansion around the initial point:

t2 t3 ... t4
θ(t) ≈ θ(0) + t · θ̇(0) + θ̈(0) + θ (0) + θ(4) (0) (2.15)
2 6 24
By use of the initial conditions of the ODE in (2.14) θ(0) = θ0 , θ̇(0) = 0 we
get
t2 t3 ... t4
θ(t) ≈ θ0 + θ̈ + θ (0) + θ(4) (0) (2.16)
2 6 24
From the ODE in (2.14) we obtain expressions for the differentials at the initial
point:
θ̈(t) = −θ(t) → θ̈(0) = −θ(0) = −θ0 (2.17)
Expressions for higher order differentials evaluated at the initial point may
be obtained by further differentiation of the ODE (2.14)
...
θ (t) = −θ̇(t) → θ̈(0) = −θ(0) = −θ0 (2.18)

and

θ(4) (t) = −θ̈(t) → θ(4) (0) = −θ̈(0) = θ0


Substitution of these differentials into (2.16) yields

t2 t4 t2 t4
   
θ(t) ≈ θ0 1 − + = θ0 1 − + (2.19)
2 24 2! 4!
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 13

If we include n terms, we get


t2 t4 t6 2n
 
n t
θ(t) ≈ θ0 · 1 − + − + · · · + (−1)
2! 4! 6! (2n)!
If we let n → ∞ we see that the parentheses give the series for cos(t). In this
case we have found the exact solution θ(t) = θ0 cos(t) of the differential equation.
Since this equation is linear we manage in this case to find a connection between
the coefficients such that we recognize the series expansion of cos(t).

Taylor’s Method for solution of initial value ODE..


1. Use the ODE (e.g. (2.2) or (2.4)) to evaluate the differentials at the
initial value.

2. Obtain an approximate solution of the ODE by substitution of the


differentials in the Taylor expansion (2.12).
3. Differentiate the ODE as many times needed to obtain the wanted
accuracy.

2.2.1 Example: Taylor’s method for the non-linear math-


ematical pendulum
Let’s try the same procedure on the non-linear version (2.7)

θ̈(t) + sin (θ(t)) = 0


θ(0) = θ0 , θ̇(0) = 0
2 3 ...
t4 (4)
We start in the same manner: θ(t) ≈ θ(0) + t2 θ̈(0) + t6 θ (0) + 24 θ (0). From
the differential equation we have θ̈ = − sin(θ) → θ̈(0) = − sin(θ0 ), which by
consecutive differentiation gives
... ...
θ = − cos(θ) · θ̇ → θ (0) = 0
θ(4) = sin(θ) · θ̇2 − cos(θ) · θ̈ → θ(4) (0) = −θ̈(0) cos(θ(0)) = sin(θ0 ) cos(θ0 )
2 4
Inserted above: θ(t) ≈ θ0 − t2 sin(θ0 ) + 24t
sin(θ0 ) cos(θ0 ).
We may include more terms, but this complicates the differentiation and it
is hard to find any connection between the coefficients. When we have found an
approximation for θ(t) we can get an approximation for θ̇(t) by differentiation:
3
θ̇(t) ≈ −t sin(θ0 ) + t8 sin(θ0 ) cos(θ0 ).
Series expansions are often useful around the starting point when we solve
initial value problems. The technique may also be used on non-linear equations.
Symbolic mathematical programs like Maple and Mathematica do this
easily.
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 14

2.2.2 Example: Newton’s first differential equation


We will end with one of the earliest known differential equations, which Newton
solved with series expansion in 1671.

y 0 (x) = 1 − 3x + y + x2 + xy, y(0) = 0

Series expansion around x = 0 gives

x2 00 x3 x4
y(x) ≈ x · y 0 (0) + y (0) + y 000 (0) + y (4) (0)
2 6 24
From the differential equation we get y 0 (0) = 1. By consecutive differentiation
we get

y 00 (x) = −3 + y 0 + 2x + xy 0 + y → y 00 (0) = −2
y (x) = y 00 + 2 + xy 00 + 2y 0
000
→ y 000 (0) = 2
y (4) (x) = y 000 + xy 000 + 3y 00 → y (4) (0) = −4
3 4
Inserting above gives y(x) ≈ x − x2 + x3 − x6 .
3 4 5 6
Newton gave the following solution: y(x) ≈ x − x2 + x3 − x6 + x30 − x45 .
Now you can check if Newton calculated correctly. Today it is possible to
give the solution on closed form with known functions as follows,
 √  √ 


h  x i 2 2
y(x) =3 2πe · exp x 1 + · erf (1 + x) − erf
2 2 2
h  x i
+4 · 1 − exp[x 1 + −x
2

Note the combination 2πe. See Hairer et al. [10] section 1.2 for more details
on classical differential equations.

2.3 Reduction of Higher order Equations


When we are solving initial value problems, we usually need to write these as
sets of first order equations, because most of the program packages require this.
Example: y 00 (x) + y(x) = 0, y(0) = a0 , y 0 (0) = b0
We may for instance write this equation in a system as follows,

y 0 (x) =g(x)
g 0 (x) = − y(x)
y(0) =a0 , g(0) = b0

Another example:

y 000 (x) + 2y 00 (x) − (y 0 (x))2 + 2y(x) = x2 (2.20)


0 00
y(0) = a0 , y (0) = b0 , y (0) = c0
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 15

We set y 0 (x) = g(x) and y 00 (x) = g 0 (x) = f (x), and the system may be written
as

y 0 (x) =g(x)
g 0 (x) =f (x)
f 0 (x) = − 2f (x) + (g(x))2 − 2y(x) + x2

with initial values y(0) = a0 , g(0) = b0 , f (0) = c0 .


This is fair enough for hand calculations, men when we use program packages
a more systematic procedure is needed. Let’s use the equation above as an
example.
We start by renaming y to y0 . We then get the following procedure:

y 0 = y00 = y1
y 00 = y000 = y10 = y2

Finally, the third order ODE in (2.20) may be represented as a system of first
order ODEs:

y00 (x) =y1 (x)


y10 (x) =y2 (x)
y20 (x) = − 2y2 (x) + (y1 (x))2 − 2y0 (x) + x2

with initial conditions y0 (0) = a0 , y1 (0) = b0 , y2 (0) = c0 .

General procedure to reduce a higher order ODE to a system of


first order ODEs.
The general procedure to reduce a higher order ODE to a system of
first order ODEs becomes the following:
Given the equation

y (m) = f (x, y, y 0 , y 00 , . . . , y (m−1) ) (2.21)


0 (m−1)
y(x0 ) = a0 , y (x0 ) = a1 , . . . , y (x0 ) = am−1

where
dm y
y (m) ≡
dxm
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 16

with y = y0 , we get the following system of ODEs:

y00 = y1
y10 = y2
.
.
0
ym−2 = ym−1
0
ym−1 = f (x, y0 , y1 , y2 , . . . , ym−1 )

with the following boundary conditions:

y0 (x0 ) = a0 , y1 (x0 ) = a1 , . . . , ym−1 (x0 ) = am−1

2.3.1 Example: Reduction of higher order systems


Write the following ODE as a system of first order ODEs:
y 000 − y 0 y 00 − (y 0 )2 + 2y = x3
y(0) = a, y 0 (0) = b, y 00 (0) = c
First we write y 000 = y 0 y 00 + (y 0 )2 − 2y + x3 .
By use of (??) we get
y00 = y1
y10 = y2
y20 = y1 y2 + (y1 )2 − 2y0 + x3
y0 (0) = a, y1 (0) = b, y2 = c

2.4 Differences
We will study some simple methods to solve initial value problems. Later we
shall see that these methods also may be used to solve boundary value problems
for ODEs.
For this purpose we need to introduce a suitable notation to enable us to
formulate the methods in a convenient manner. In Figure 2.2) an arbitrary
function y is illustrated as a continuous function of x, ie y = y(x). Later y will
be used to represent the solution of an ODE, which only may be represented
and obtained for discrete values of x. We represent these discrete, equidistant
values of x by:

xj = x0 + jh
where h = ∆x is assumed constant unless otherwise stated and j is an integer
counter referring to the discrete values xj for which the corresponding discrete
value
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 17

y
y(xj)
y(xj-1)
y(xj-2)
y(x1)
y(x0)

h h h

x0 x1 xj-2 xj-1 xj x

Figure 2.2: A generic function y(x) sampled at equidistant values of x. .

yj = y(xj )
may be found (see Figure 2.3).

y yj+1½ yj+2
yj+1
yj+½
yj
yj-½
yj-1

½h ½h ½h ½h

xj-1 xj-½ xj xj+½ xj+1 xj+1½ xj+2 x

Figure 2.3: Illustration of how to obtain difference equations.

Having introduced this notation we may the develop useful expressions and
notations for forward differences, backward differences, and central differences,
which will be used frequently later:
Forward differences:
∆yj = yj+1 − yj
Backward differences:

∇yj = yj − yj−1 (2.22)


CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 18

Central differences:
δyj+ 21 = yj+1 − yj
The linear difference operators ∆, ∇ and δ are useful when we are deriving
more complicated expressions. An example of usage is as follows,

δ 2 yj = δ(δyj ) = δ(y1+ 12 − y1− 12 ) = yj+1 − yj − (yj − yj−1 ) = yj+1 − 2yj + yj−1

However, for clarity we will mainly write out the formulas entirely rather
than using operators.
We shall find difference formulas and need again:

Taylor’s theorem:
1
y(x) =y(x0 ) + y 0 (x0 ) · (x − x0 ) + y 00 (x0 ) · (x − x0 )2 + (2.23)
2
1 (n) n
· · · + y (x0 ) · (x − x0 ) + Rn
n!
The remainder Rn is given by
1
Rn = y (n+1) (ξ) · (x − x0 )n+1 (2.24)
(n + 1)!
where ξ ∈ (x0 , x)

Now, Taylor’s theorem (2.23) may be used to approximate the value of y(xj+1 ),
i.e. the forward value of y(xj ), by assuming that y(xj ) and it’s derivatives are
known:

h2 00
y(xj+1 ) ≡y(xj + h) = y(xj ) + hy 0 (xj ) + y (xj )+ (2.25)
2
hn y (n) (xj )
··· + + Rn
n!
where the remainder Rn = O(hn+1 ), h → 0.
From (2.25) we also get

h2 00 hk (−1)k y (k) (xj )


y(xj−1 ) ≡ y(xj − h) = y(xj ) − hy 0 (xj ) + y (xj ) + · · · + +...
2 k!
(2.26)
In the following we will assume that h is positive. By solving (2.25) with
respect to y 0 we may obtain a discrete forward difference approximation of y 0 at
xj :

y(xj+1 ) − y(xj )
y 0 (xj ) = + O(h) (2.27)
h
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 19

By solving (2.26) with respect to y 0 we obtain a discrete approximation at xi :

y(xj ) − y(xj−1 )
y 0 (xj ) = + O(h) (2.28)
h
By adding (2.26) and (2.25) together we get an approximation of the second
derivative at the location xj :

y(xj+1 ) − 2y(xj ) + y(xj−1 )


y 00 (xj ) = + O(h2 ) (2.29)
h2
By subtraction of (2.26) from (2.25) we get a backward difference approxi-
mation of the first order derivative at the location xj :

y(xj+1 ) − y(xj−1 )
y 0 (xj ) = + O(h2 ) (2.30)
2h
Notation:
We let y(xj ) always denote the function y(x) with x = xj . We use yj both
for the numerical and analytical value, the intended meaning is hopfullye clear
from the context.
Equations (2.27), (2.28), (2.29) and (2.30) then may be used to deduce the
following difference expressions:

yj+1 − yj
yj0 = ; truncation error O(h) (2.31)
h
yj − yj−1
yj0 = ; truncation error O(h) (2.32)
h
yj+1 − 2yj + yj−1
yj00 = ; truncation error O(h2 ) (2.33)
h2
yj+1 − yj−1
yj0 = ; truncation error O(h2 ) (2.34)
2h
In summary, equation (2.31) is a forward difference, (2.32) is a backward
difference while (2.33) and (2.34) are central differences.
The expressions in (2.31), (2.32), (2.33) and (2.34) may also conveniently be
established from Figure 2.4.
Whereas, (2.31) follows directly from the definition of the derivative, whereas
the second order derivative (2.33) may be obtained as a derivative of the derivative
by:
 
00 yj+1 − yj yj − yj−1 1 yj+1 − 2yj + yj−1
yj (xj ) = − · =
h h h h2
and an improved expression for the derivative (2.34) may be obtained by
averaging the forward and the backward derivatives:
 
0 yj+1 − yj yj − yj−1 1 yj+1 − yj−1
yj = + · =
h h 2 2h
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 20

y yj+1

yj
yj-1

½h ½h ½h ½h

xj-1 xj xj+1 x

Figure 2.4: Illustration of how the discrete values may be used to estimate
various orders of derivatives at location xi .

To find the truncation error we proceed in a systematical manner by:


y 0 (xj ) = a · y(xj−1 ) + b · y(xj ) + c · y(xj+1 ) + O(hm ) (2.35)
where we shall determine the constants a, b and c together with the error
term. For simplicity we use the notation yj ≡ y(xj ), yj0 ≡ y 0 (xj ) and so on.
From the Taylor series expansion in (2.25) and (2.26) we get

a · yj−1 + b · yj + c · yj+1 =
h2 h3
 
a · yj − hyj0 + yj00 − yj000 (ξ) + b · yj + (2.36)
2 6
2
h 00 h3 000
 
0
c · yj + hyj + yj + yj (ξ)
2 6
By collecting terms in Eq. (2.36) we get:

a · yj−1 + b · yj + c · yj+1 =
(a + b + c) yj + (c − a) h yj0 + (2.37)
2 3
h 00 h 000
(a + c) y + (c − a) y (ξ)
2 j 6
From Eq.(2.37) we may then find a, b and c such that yj0 gets as high accuracy
as possible by :
a+b+c=0
(c − a) · h = 1 (2.38)
a+c=0
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 21

The solution to (2.38) is


1 1
a=− , b = 0 and c =
2h 2h
which when inserted in (2.35) gives
yj+1 − yj−1 h2
yj0 = − y 000 (ξ) (2.39)
2h 6
By comparison of (2.39) with (2.35) we see that the error term is O(hm ) =
2
− h6 y 000 (ξ),
which means that m = 2. As expected, (2.39) is identical to (2.30).
Let’s use this method to find a forward difference expression for y 0 (xj ) with
accuracy of O(h2 ). Second order accuracy requires at least three unknown
coefficients. Thus,

y 0 (xj ) = a · yj + b · yj+1 + c · yj+2 + O(hm ) (2.40)


The procedure goes as in the previous example as follows,
a · yj + b · yj+1 + c · yj+2 =
h2 h3
 
a · yj + b · yj + hyj0 + yj00 + y 000 (ξ) +
2 6
3
 
8h 000
c · yj + 2hyj0 + 2h2 yj00 + yj (ξ)
6
=(a + b + c) · yj + (b + 2c) · hyj0
h3
 
b
+h2 + 2c · yj00 + (b + 8c) · y 000 (ξ)
2 6
We determine a, b and c such that yj0 becomes as accurate as possible. Then we
get,
a+b+c=0
(b + 2c) · h = 1 (2.41)
b
+ 2c = 0
2
The solution of (2.41) is
3 2 1
a=− , b= , c=−
2h h 2h
which inserted in (2.40) gives
−3yj + 4yj+1 − yj+2 h2
yj0 = + y 000 (ξ) (2.42)
2h 3
2
The error term O(hm ) = h3 y 000 (ξ) shows that m = 2.
Here follows some difference formulas derived with the procedure above:
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 22

Forward differences:
dyi yi+1 − yi 1
= + y 00 (ξ)∆x
dx ∆x 2
dyi −3yi + 4yi+1 − yi+2 1
= + y 000 (ξ) · (∆x)2
dx 2∆x 3
dyi −11yi + 18yi+1 − 9yi+2 + yi+3 1
= + y (4) (ξ) · (∆x)3
dx 6∆x 4
d2 yi yi − 2yi+1 + yi+2
= + y 000 (ξ) · ∆x
dx2 (∆x)2
d2 yi 2yi − 5yi+1 + 4yi+2 − yi+3 11
= + y (4) (ξ) · (∆x)2
dx2 (∆x)2 12

Backward differences:
dyi yi − yi−1 1
= + y 00 (ξ)∆x
dx ∆x 2
dyi 3yi − 4yi−1 + yi−2 1
= + y 000 (ξ) · (∆x)2
dx 2∆x 3
dyi 11yi − 18yi−1 + 9yi−2 − yi−3 1
= + y (4) (ξ) · (∆x)3
dx 6∆x 4
d2 yi yi − 2yi−1 + yi−2 000
= + y (ξ) · ∆x
dx2 (∆x)2
d2 yi 2yi − 5yi−1 + 4yi−2 − yi−3 11
= + y (4) (ξ) · (∆x)2
dx2 (∆x)2 12

Central differences:
dyi yi+1 − yi−1 1
= − y 000 (ξ)(∆x)2
dx 2∆x 6
dyi −yi+2 + 8yi+1 − 8yi−1 + yi−2 1
= + y (5) (ξ) · (∆x)4
dx 12∆x 30
d2 yi yi+1 − 2yi + yi−1 1
= − y (4) (ξ) · (∆x)2
dx2 (∆x) 2 12
d2 yi −yi+2 + 16yi+1 − 30yi + 16yi−1 − yi−2 1
= + y (6) (ξ) · (∆x)4
dx2 12(∆x)2 90
d3 yi yi+2 − 2yi+1 + 2yi−1 − yi−2 1
= + y (5) (ξ) · (∆x)2
dx3 2(∆x)3 4
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 23

2.4.1 Example: Discretization of a diffusion term


d d

This diffusion term dx p(x) dx u(x) often appears in difference equations, and
it may be beneficial to treat the term as it is instead of first execute the
differentiation. Below we will illustrate how the diffusion term may be discretized
with the three various difference approaches: forward, backward and central
differences.

Central differences: We use central differences (recall Figure 2.3) as follows,

[p(x) · u0 (x)]|i+ 21 − [p(x) · u0 (x)]|i− 21


 
d d
p(x) · u(x) ≈
dx dx i h
p(xi+ 12 ) · u (xi+ 21 ) − p(xi− 21 ) · u0 (xi− 21 )
0
=
h
Using central differences again, we get
ui+1 − ui ui − ui−1
u0 (xi+ 12 ) ≈ , u0 (xi− 21 ) ≈ ,
h h
which inserted in the previous equation gives the final expression

pi− 12 · ui−1 − (pi+ 12 + pi− 21 ) · ui + pi+ 12 · ui+1


 
d d
p(x) · u(x) ≈ +error term
dx dx i h2
(2.43)
where
h2 d
 
000 0 00
error term = − · p(x) · u (x) + [p(x) · u (x)] + O(h3 )
24 dx

If p(x1+ 21 ) and p(x1− 21 ) cannot be found directly, we use

1 1
p(x1+ 12 ) ≈ (pi+1 + pi ), p(x1− 12 ) ≈ (pi + pi−1 ) (2.44)
2 2
Note that for p(x) = 1 = constant we get the usual expression

d2 u

ui+1 − 2ui + ui−1
= + O(h2 )
dx2 i h2

Forward differences: We start with


p(xi+ 21 ) · u0 (xi+ 12 ) − p(xi ) · u0 (xi )
 
d du
p(x) · ≈ h
dx dx i 2
 
ui+1 −ui
p(xi+ 12 ) · h − p(xi ) · u0 (xi )
≈ h
2
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 24

which gives

2 · [p(xi+ 21 ) · (ui+1 − ui ) − h · p(xi ) · u0 (xi )]


 
d du
p(x) · = + error term
dx dx
i h2
(2.45)
where
h
error term = − [3p00 (xi ) · u0 (xi ) + 6p0 (xi ) · u00 (xi ) + 4p(xi ) · u000 (xi )] + O(h2 )
12
(2.46)
We have kept the term u0 (xi ) since (2.45) usually is used at the boundary, and
u0 (xi ) may be prescribed there. For p(x) = 1 = constant we get the expression

2 · [ui+1 − ui − h · u0 (xi )] h 000


u00i = − u (xi ) + O(h2 ) (2.47)
h2 3

Backward Differences: We start with


p(xi ) · u0 (xi ) − p(xi ) · u0 (xi− 21 ) · u0 (xi− 21 )
 
d du
p(x) ≈ h
dx dx i 2
 
p(xi ) · u (xi ) − p(xi− 21 ) ui −u
0
h
i−1

≈ h
2

which gives

2 · [h · p(xi )u0 (xi ) − p(xi− 21 ) · (ui − ui−1 )]


 
d du
p(x) = + error term
dx dx
i h2
(2.48)
where
h
error term = [3p00 (xi )·u0 (xi )+6p0 (xi )·u00 (xi )+4p(xi )·u000 (xi )]+O(h2 ) (2.49)
12
This is the same error term as in (2.46) except from the sign. Also here we have
kept the term u0 (xi ) since (2.49) usually is used at the boundary where u0 (xi )
may be prescribed. For p(x) = 1 = constant we get the expression

2 · [h · u0 (xi ) − (ui − ui−1 )] h 000


u00i = + u (xi ) + O(h2 ) (2.50)
h2 3

2.5 Euler’s method


The ODE is given as
dy
= y 0 (x) = f (x, y) (2.51)
dx
y(x0 ) =y0 (2.52)
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 25

By using a first order forward approximation (2.27) of the derivative in (2.51)


we obtain:
y(xn+1 ) = y(xn ) + h · f (xn , y(xn )) + O(h2 )
or
yn+1 = yn + h · f (xn , yn ) (2.53)
(2.53) is a difference equation and the scheme is called Euler’s method (1768).
The scheme is illustrated graphically in Figure 2.5. Euler’s method is a first
order method, since the expression for y 0 (x) is first order of h. The method has
a global error of order h, and a local of order h2 .

y
y(xn+2)

y(x) numerical
solution
yn+2
y(xn+1)
yn+1
yn h∙f(xn,yn)

xn xn+1 xn+2 x

Figure 2.5: Graphical illustration of Euler’s method.

2.5.1 Example: Eulers method on a simple ODE


# src-ch1/euler_simple.py

import numpy as np
import matplotlib.pylab as plt

""" example using eulers method for solving the ODE


y’(x) = f(x, y) = y
y(0) = 1

Eulers method:
y^(n + 1) = y^(n) + h*f(x, y^(n)), h = dx
"""

N = 100
x = np.linspace(0, 1, N + 1)
h = x[1] - x[0] # steplength
y_0 = 1 # initial condition
Y = np.zeros_like(x) # vector for storing y values
Y[0] = y_0 # first element of y = y(0)

for n in range(N):
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 26

f = Y[n]
Y[n + 1] = Y[n] + h*f

Y_analytic = np.exp(x)

# change default values of plot to make it more readable


LNWDT=2; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT
plt.rcParams[’font.size’] = FNT
plt.figure()
plt.plot(x, Y_analytic, ’b’, linewidth=2.0)
plt.plot(x, Y, ’r--’, linewidth=2.0)
plt.legend([’$e^x$’, ’euler’], loc=’best’, frameon=False)
plt.xlabel(’x’)
plt.ylabel(’y’)
#plt.savefig(’../fig-ch1/euler_simple.png’, transparent=True)
plt.show()

2.8
ex
2.6
euler
2.4

2.2

2.0
y

1.8

1.6

1.4

1.2

1.0
0.0 0.2 0.4 0.6 0.8 1.0
x

Figure 2.6: result from the code above

2.5.2 Example: Eulers method on the mathematical pen-


dulum
# src-ch1/euler_pendulum.py

import numpy as np
import matplotlib.pylab as plt
from math import pi

""" example using eulers method for solving the ODE:


theta’’(t) + thetha(t) = 0
thetha(0) = theta_0
thetha’(0) = dtheta_0
Reduction of higher order ODE:
theta = y0
theta’ = y1
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 27

theta’’ = - theta = -y0


y0’ = y1
y1’ = -y0
eulers method:
y0^(n + 1) = y0^(n) + h*y1, h = dt
y1^(n + 1) = y1^(n) + h*(-y0), h = dt
"""
N = 100
t = np.linspace(0, 2*pi, N + 1)
h = t[1] - t[0] # steplength
thetha_0 = 0.1
y0_0 = thetha_0 # initial condition
y1_0 = 0
Y = np.zeros((2, N + 1)) # 2D array for storing y values
Y[0, 0] = y0_0 # apply initial conditions
Y[1, 0] = y1_0
for n in range(N):
y0_n = Y[0, n]
y1_n = Y[1, n]

Y[0, n + 1] = y0_n + h*y1_n


Y[1, n + 1] = y1_n - h*y0_n

thetha = Y[0, :]
thetha_analytic = thetha_0*np.cos(t)

# change default values of plot to make it more readable


LNWDT=2; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT
plt.rcParams[’font.size’] = FNT

plt.figure()
plt.plot(t, thetha_analytic, ’b’)
plt.plot(t, thetha, ’r--’)

plt.legend([r’$\theta_0 \cdot cos(t)$’, ’euler’], loc=’best’, frameon=False)


plt.xlabel(’t’)
plt.ylabel(r’$\theta$’)
#plt.savefig(’../fig-ch1/euler_pendulum.png’, transparent=True)
plt.show()

2.5.3 Example: Generic euler implementation on the math-


ematical pendulum
# src-ch1/euler_pendulum_generic.py

import numpy as np
import matplotlib.pylab as plt
from math import pi
# define Euler solver
def euler(func, y_0, time):
""" Generic implementation of the euler scheme for solution of systems of ODEs:
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 28

0.15

0.10

0.05

0.00

−0.05

−0.10
0 cos(t)
euler
−0.15
0 1 2 3 4 5 6 7
t

Figure 2.7: result from the code above

y0’ = y1
y1’ = y2
.
.
yN’ = f(yN-1,..., y1, y0, t)

method:
y0^(n+1) = y0^(n) + h*y1
y1^(n+1) = y1^(n) + h*y2
.
.
yN^(n + 1) = yN^(n) + h*f(yN-1, .. y1, y0, t)

Args:
func(function): func(y, t) that returns y’ at time t; [y1, y2,...,f(yn-1, .. y1, y0, t)]
y_0(array): initial conditions
time(array): array containing the time to be solved for

Returns:
y(array): array/matrix containing solution for y0 -> yN for all timesteps"""

y = np.zeros((np.size(time), np.size(y_0)))
y[0,:] = y_0
for i in range(len(time)-1):
dt = time[i+1] - time[i]
y[i+1,:]=y[i,:] + np.asarray(func(y[i,:], time[i]))*dt

return y

def pendulum_func(y, t):


""" function that returns the RHS of the mathematcal pendulum ODE:
Reduction of higher order ODE:
theta = y0
theta’ = y1
theta’’ = - theta = -y0

y0’ = y1
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 29

y1’ = -y0
Args:
y(array): array [y0, y1] at time t
t(float): current time

Returns:
dy(array): [y0’, y1’] = [y1, -y0]
"""
dy = np.zeros_like(y)
dy[:] = [y[1], -y[0]]
return dy

N = 100
time = np.linspace(0, 2*pi, N + 1)
thetha_0 = [0.1, 0]
theta = euler(pendulum_func, thetha_0, time)
thetha = theta[:, 0]
thetha_analytic = thetha_0[0]*np.cos(time)

# change default values of plot to make it more readable


LNWDT=2; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT
plt.rcParams[’font.size’] = FNT

plt.figure()
plt.plot(time, thetha_analytic, ’b’)
plt.plot(time, thetha, ’r--’)

plt.legend([r’$\theta_0 \cdot cos(t)$’, ’euler’], loc=’best’, frameon=False)


plt.xlabel(’t’)
plt.ylabel(r’$\theta$’)
#plt.savefig(’../fig-ch1/euler_pendulum.png’, transparent=True)
plt.show()

2.5.4 Example: Sphere in free fall


Figure 2.8 illustrates a falling sphere in a gravitational field with a diameter
d and mass m that falls vertically in a fluid. Use of Newton’s 2nd law in the
z-direction gives
dv 1 dv 1
m = mg − mf g − mf − ρf v |v| Ak CD , (2.54)
dt 2 dt 2
where the different terms are interpreted as follows: m = ρk V , where ρk is the
density of the sphere and V is the sphere volume. The mass of the displaced fluid
is given by mf = ρf V , where ρf is the density of the fluid, whereas buoyancy and
the drag coefficient are expressed by mf g and CD , respectively. The projected
area of the sphere is given by Ak = π4 d2 and 12 mf is the hydro-dynamical mass
(added mass). The expression for the hydro-dynamical mass is derived in White
[25], page 539-540. To write Equation (2.54) on a more convenient form we
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 30

dz
z v=
dt

mg

Figure 2.8: Falling sphere due to gravity.

introduce the following abbreviations:


ρf ρ 3ρ
ρ= , A = 1 + , B = (1 − ρ)g, C = . (2.55)
ρk 2 4d
in addition to the drag coefficient CD which is a function of the Reynolds number
vd
Re = , where ν is the kinematical viscosity. Equation (2.54) may then be
ν
written as
dv 1
= (B − C · v |v| Cd ). (2.56)
dt A
In air we may often neglect the buoyancy term and the hydro-dynamical mass,
whereas this is not the case for a liquid. Introducing v = dz dt in Equation (2.56),
we get a 2nd order ODE as follows

d2 z
 
1 dz dz
= B − C · Cd (2.57)
dt2 A dt dt

For Equation (2.57) two initial conditions must be specified, e.g. v = v0 and
z = z0 for t = 0.
Figure 2.9 illustrates CD as a function of Re. The values in the plot are not
as accurate as the number of digits in the program might indicate. For example
is the location and the size of the "valley" in the diagram strongly dependent of
the degree of turbulence in the free stream and the roughness of the sphere. As
the drag coefficient CD is a function of the Reynolds number, it is also a function
of the solution v (i.e. the velocity) of the ODE in Equation (2.56). We will use
the function CD (Re) as an example of how functions may be implemented in
Python.
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 31

3
10

2
10

1
10

CD 10
0

-1
10

-2
10 -1 0 1 2 3 4 5 6 7
10 10 10 10 10 10 10 10 10
Re

Figure 2.9: Drag coefficient CD as function of the Reynold’s number Re .

Euler’s method for a system. Euler’s method may of course also be used
for a system. Let’s look at a simultaneous system of p equations

y10 = f1 (x, y1 , y2 , . . . yp )
y20 = f2 (x, y1 , y2 , . . . yp )
. (2.58)
.
yp0 = fp (x, y1 , y2 , . . . yp )

with initial values

y1 (x0 ) = a1 , y2 (x0 ) = a2 , . . . , yp (x0 ) = ap (2.59)

Or, in vectorial format as follows,

y0 = f (x, y) (2.60)
y(x0 ) = a

where y0 , f , y and a are column vectors with p components.


The Euler scheme (2.53) used on (2.60) gives

yn+1 = yn + h · f (xn , yn ) (2.61)

For a system of three equations we get

y10 =y2
y20 =y3 (2.62)
y30 = − y1 y3
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 32

In this case (2.61) gives

(y1 )n+1 = (y1 )n + h · (y2 )n


(y2 )n+1 = (y2 )n + h · (y3 )n (2.63)
(y3 )n+1 = (y3 )n − h · (y1 )n · (y3 )n
(2.64)

with y1 (x0 ) = a1 , y2 (x0 ) = a2 , and y3 (x0 ) = a3


In section 2.3 we have seen how we can reduce a higher order ODE to a set of
2 2
first order ODEs. In (2.65) and (2.66) we have the equation ddt2z = g − α · dz
dt
which we have reduced to a system as
dz
=v
dt
dv
= g − α · v2
dt
which gives an Euler scheme as follows,

zn+1 = zn + ∆t · vn
vn+1 = nn + ∆t · [g − α(vn )2 ]
med z0 = 0, v0 = 0

2.5.5 Example: Falling sphere with constant and varying


drag
We write (2.56) and (2.57) as a system as follows,

dz
=v (2.65)
dt
dv
= g − αv 2 (2.66)
dt
where
3ρf
α= · CD
4ρk · d
The analytical solution with z(0) = 0 and v(0) = 0 is given by

ln(cosh( αg · t))
z(t) = (2.67)
r α
g √
v(t) = · tanh( αg · t) (2.68)
α
r
dv g
The terminal velocity vt is found by = 0 which gives vt = .
dt α
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 33

3 3
We use data from a golf ball: d = 41 mm, ρk = 1275 kg/m , ρk = 1.22 kg/m ,
and choose CD = 0.4 which gives α = 7 · 10−3 . The terminal velocity then
becomes r
g
vt = = 37.44
α
If we use Taylor’s method from section 2.2 we get the following expression
by using four terms in the series expansion:
1 1
z(t) = gt2 · (1 − αgt2 ) (2.69)
2 6
1
v(t) =gt · (1 − αgt2 ) (2.70)
3
By applying the Euler scheme (2.53) on (2.65) and (2.66)

zn+1 = zn + ∆t · vn (2.71)
vn+1 = vn + ∆t · (g − α · vn2 ), n = 0, 1, . . . (2.72)

with z(0) = 0 and v(0) = 0.


By adopting the conventions proposed in (??) and substituting z0 for z and
z1 for v and we may render the system of equations in (2.65) and (2.66) as:

dz0
= z1
dt
dz1
= g − αz12
dt
One way of implementing the integration scheme is given in the following
function euler():
def euler(func,z0, time):
"""The Euler scheme for solution of systems of ODEs.
z0 is a vector for the initial conditions,
the right hand side of the system is represented by func which returns
a vector with the same size as z0 ."""

z = np.zeros((np.size(time),np.size(z0)))
z[0,:] = z0

for i in range(len(time)-1):
dt = time[i+1]-time[i]
z[i+1,:]=z[i,:] + np.asarray(func(z[i,:],time[i]))*dt

return z

The program FallingSphereEuler.py computes the solution for the first 10


seconds, using a time step of ∆t = 0.5 s, and generates the plot in Figure 2.10.
In addition to the case of constant drag coefficient, a solution for the case of
varying CD is included. To find CD as function of velocity we use the function
cd_sphere() that we implemented in (2.5.4). The complete program is as
follows,
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 34

# src-ch1/FallingSphereEuler.py;DragCoefficientGeneric.py @ git@lrhgit/tkt4140/src/src-ch1/DragCoeffi
from DragCoefficientGeneric import cd_sphere
from matplotlib.pyplot import *
import numpy as np
# change some default values to make plots more readable
LNWDT=2; FNT=11
rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT

g = 9.81 # Gravity m/s^2


d = 41.0e-3 # Diameter of the sphere
rho_f = 1.22 # Density of fluid [kg/m^3]
rho_s = 1275 # Density of sphere [kg/m^3]
nu = 1.5e-5 # Kinematical viscosity [m^2/s]
CD = 0.4 # Constant drag coefficient

def f(z, t):


"""2x2 system for sphere with constant drag."""
zout = np.zeros_like(z)
alpha = 3.0*rho_f/(4.0*rho_s*d)*CD
zout[:] = [z[1], g - alpha*z[1]**2]
return zout

def f2(z, t):


"""2x2 system for sphere with Re-dependent drag."""
zout = np.zeros_like(z)
v = abs(z[1])
Re = v*d/nu
CD = cd_sphere(Re)
alpha = 3.0*rho_f/(4.0*rho_s*d)*CD
zout[:] = [z[1], g - alpha*z[1]**2]
return zout
# define euler scheme
def euler(func,z0, time):
"""The Euler scheme for solution of systems of ODEs.
z0 is a vector for the initial conditions,
the right hand side of the system is represented by func which returns
a vector with the same size as z0 ."""

z = np.zeros((np.size(time),np.size(z0)))
z[0,:] = z0

for i in range(len(time)-1):
dt = time[i+1]-time[i]
z[i+1,:]=z[i,:] + np.asarray(func(z[i,:],time[i]))*dt
return z

def v_taylor(t):
# z = np.zeros_like(t)
v = np.zeros_like(t)

alpha = 3.0*rho_f/(4.0*rho_s*d)*CD
v=g*t*(1-alpha*g*t**2)
return v

# main program starts here

T = 10 # end of simulation
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 35

N = 20 # no of time steps
time = np.linspace(0, T, N+1)

z0=np.zeros(2)
z0[0] = 2.0

ze = euler(f, z0, time) # compute response with constant CD using Euler’s method
ze2 = euler(f2, z0, time) # compute response with varying CD using Euler’s method

k1 = np.sqrt(g*4*rho_s*d/(3*rho_f*CD))
k2 = np.sqrt(3*rho_f*g*CD/(4*rho_s*d))
v_a = k1*np.tanh(k2*time) # compute response with constant CD using analytical solution
# plotting

legends=[]
line_type=[’-’,’:’,’.’,’-.’,’--’]
plot(time, v_a, line_type[0])
legends.append(’Analytical (constant CD)’)
plot(time, ze[:,1], line_type[1])
legends.append(’Euler (constant CD)’)

plot(time, ze2[:,1], line_type[3])


legends.append(’Euler (varying CD)’)

time_taylor = np.linspace(0, 4, N+1)


plot(time_taylor, v_taylor(time_taylor))
legends.append(’Taylor (constant CD)’)

legend(legends, loc=’best’, frameon=False)


font = {’size’ : 16}
rc(’font’, **font)
xlabel(’Time [s]’)
ylabel(’Velocity [m/s]’)
#savefig(’example_sphere_falling_euler.png’, transparent=True)
show()

Python implementation of the drag coefficient function and how to


plot it. The complete Python program CDsphere.py used to plot the drag
coefficient in the example above is listed below. The program uses a function
cd_sphere which results from a curve fit to the data of Evett and Liu [6]. In
our setting we will use this function for two purposes, namely to demonstrate
how functions and modules are implemented in Python and finally use these
functions in the solution of the ODE in Equations (2.56) and (2.57).
# src-ch1/CDsphere.py

from numpy import logspace, zeros

# Define the function cd_sphere


def cd_sphere(Re):
"This function computes the drag coefficient of a sphere as a function of the Reynolds number Re.
# Curve fitted after fig . A -56 in Evett and Liu: "Fluid Mechanics and Hydraulics"
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 36

40

35

30

25

Velocity [m/s]
Analytical (constant CD)
20 Euler (constant CD)
15 Euler (varying CD)
Taylor (constant CD)
10

−5
0 2 4 6 8 10
Time [s]

Figure 2.10: Euler’s method with ∆t = 0.5 s.

from numpy import log10, array, polyval

if Re <= 0.0:
CD = 0.0
elif Re > 8.0e6:
CD = 0.2
elif Re > 0.0 and Re <= 0.5:
CD = 24.0/Re
elif Re > 0.5 and Re <= 100.0:
p = array([4.22, -14.05, 34.87, 0.658])
CD = polyval(p, 1.0/Re)
elif Re > 100.0 and Re <= 1.0e4:
p = array([-30.41, 43.72, -17.08, 2.41])
CD = polyval(p, 1.0/log10(Re))
elif Re > 1.0e4 and Re <= 3.35e5:
p = array([-0.1584, 2.031, -8.472, 11.932])
CD = polyval(p, log10(Re))
elif Re > 3.35e5 and Re <= 5.0e5:
x1 = log10(Re/4.5e5)
CD = 91.08*x1**4 + 0.0764
else:
p = array([-0.06338, 1.1905, -7.332, 14.93])
CD = polyval(p, log10(Re))
return CD

# Calculate drag coefficient


Npts = 500
Re = logspace(-1, 7, Npts, True, 10)
CD = zeros(Npts)
i_list = range(0, Npts-1)
for i in i_list:
CD[i] = cd_sphere(Re[i])

# Make plot
from matplotlib import pyplot
# change some default values to make plots more readable
LNWDT=2; FNT=11
pyplot.rcParams[’lines.linewidth’] = LNWDT; pyplot.rcParams[’font.size’] = FNT
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 37

pyplot.plot(Re, CD, ’-b’)


pyplot.yscale(’log’)
pyplot.xscale(’log’)
pyplot.xlabel(’$Re$’)
pyplot.ylabel(’$C_D$’)
pyplot.grid(’on’, ’both’, ’both’)
#pyplot.savefig(’example_sphere.png’, transparent=True)
pyplot.show()

In the following, we will break up the program and explain the different parts.
In the first code line,
from numpy import logspace, zeros

the functions logspace and zeros are imported from the package numpy.
The numpy package (NumPy is an abbreviation for Numerical Python) enables
the use of array objects. Using numpy a wide range of mathematical operations
can be done directly on complete arrays, thereby removing the need for loops
over array elements. This is commonly called vectorization and may cause a
dramatic increase in computational speed of Python programs. The function
logspace works on a logarithmic scale just as the function linspace works on
a regular scale. The function zeros creates arrays of a certain size filled with
zeros. Several comprehensive guides to the numpy package may be found at
http://www.numpy.org.
In CDsphere.py a function cd_sphere was defined as follows:
def cd_sphere(Re):
"This function computes the drag coefficient of a sphere as a function of the Reynolds number Re.
# Curve fitted after fig . A -56 in Evett and Liu: "Fluid Mechanics and Hydraulics"

from numpy import log10, array, polyval

if Re <= 0.0:
CD = 0.0
elif Re > 8.0e6:
CD = 0.2
elif Re > 0.0 and Re <= 0.5:
CD = 24.0/Re
elif Re > 0.5 and Re <= 100.0:
p = array([4.22, -14.05, 34.87, 0.658])
CD = polyval(p, 1.0/Re)
elif Re > 100.0 and Re <= 1.0e4:
p = array([-30.41, 43.72, -17.08, 2.41])
CD = polyval(p, 1.0/log10(Re))
elif Re > 1.0e4 and Re <= 3.35e5:
p = array([-0.1584, 2.031, -8.472, 11.932])
CD = polyval(p, log10(Re))
elif Re > 3.35e5 and Re <= 5.0e5:
x1 = log10(Re/4.5e5)
CD = 91.08*x1**4 + 0.0764
else:
p = array([-0.06338, 1.1905, -7.332, 14.93])
CD = polyval(p, log10(Re))
return CD
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 38

The function takes Re as an argument and returns the value CD. All Python func-
tions begin with def, followed by the function name, and then inside parentheses
a comma-separated list of function arguments, ended with a colon. Here we have
only one argument, Re. This argument acts as a standard variable inside the
function. The statements to perform inside the function must be indented. At
the end of a function it is common to use the return statement to return the
value of the function.
Variables defined inside a function, such as p and x1 above, are local variables
that cannot be accessed outside the function. Variables defined outside functions,
in the "main program", are global variables and may be accessed anywhere, also
inside functions.
Three more functions from the numpy package are imported in the func-
tion. They are not used outside the function and are therefore chosen to be
imported only if the function is called from the main program. We refer to the
documentation of NumPy for details about the different functions.
The function above contains an example of the use of the if-elif-else
block. The block begins with if and a boolean expression. If the boolean
expression evaluates to true the indented statements following the if statement
are carried out. If not, the boolean expression following the elif is evaluated. If
none of the conditions are evaluated to true the statements following the else
are carried out.
In the code block
Npts = 500
Re = logspace(-1, 7, Npts, True, 10)
CD = zeros(Npts)
i_list = range(0, Npts-1)
for i in i_list:
CD[i] = cd_sphere(Re[i])

the function cd_sphere is called. First, the number of data points to be


calculated are stored in the integer variable Npts. Using the logspace function
imported earlier, Re is assigned an array object which has float elements with
values ranging from 10−1 to 107 . The values are uniformly distributed along
a 10-logarithmic scale. CD is first defined as an array with Npts zero elements,
using the zero function. Then, for each element in Re, the drag coefficient is
calculated using our own defined function cd_sphere, in a for loop, which is
explained in the following.
The function range is a built-in function that generates a list containing
arithmetic progressions. The for i in i_list construct creates a loop over all
elements in i_list. In each pass of the loop, the variable i refers to an element
in the list, starting with i_list[0] (0 in this case) and ending with the last
element i_list[Npts-1] (499 in this case). Note that element indices start at
0 in Python. After the colon comes a block of statements which does something
useful with the current element; in this case, the return of the function call
cd_sphere(Re[i]) is assigned to CD[i]. Each statement in the block must be
indented.
Lastly, the drag coefficient is plotted and the figure generated:
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 39

from matplotlib import pyplot


# change some default values to make plots more readable
LNWDT=2; FNT=11
pyplot.rcParams[’lines.linewidth’] = LNWDT; pyplot.rcParams[’font.size’] = FNT
pyplot.plot(Re, CD, ’-b’)
pyplot.yscale(’log’)
pyplot.xscale(’log’)
pyplot.xlabel(’$Re$’)
pyplot.ylabel(’$C_D$’)
pyplot.grid(’on’, ’both’, ’both’)
#pyplot.savefig(’example_sphere.png’, transparent=True)
pyplot.show()

To generate the plot, the package matplotlib is used. matplotlib is


the standard package for curve plotting in Python. For simple plotting the
matplotlib.pyplot interface provides a Matlab-like interface, which has been
used here. For documentation and explanation of this package, we refer to
http://www.matplotlib.org.
First, the curve is generated using the function plot, which takes the x-values
and y-values as arguments (Re and CD in this case), as well as a string specifying
the line style, like in Matlab. Then changes are made to the figure in order to
make it more readable, very similarly to how it is done in Matlab. For instance,
in this case it makes sense to use logarithmic scales. A png version of the figure
is saved using the savefig function. Lastly, the figure is showed on the screen
with the show function.
To change the font size the function rc is used. This function takes in the
object font, which is a dictionary object. Roughly speaking, a dictionary is a
list where the index can be a text (in lists the index must be an integer). It is
best to think of a dictionary as an unordered set of key:value pairs, with the
requirement that the keys are unique (within one dictionary). A pair of braces
creates an empty dictionary: {}. Placing a comma-separated list of key:value
pairs within the braces adds initial key:value pairs to the dictionary. In this
case the dictionary font contains one key:value pair, namely ’size’ : 16.
Descriptions and explanations of all functions available in pyplot may be
found here.

2.6 Python functions with vector arguments and


modules
For many numerical problems variables are most conveniently expressed by arrays
containing many numbers (i.e. vectors) rather than single numbers (i.e. scalars).
The function cd_sphere above takes a scalar as an argument and returns a scalar
value too. For computationally intensive algorithms where variables are stored
in arrays this is inconvenient and time consuming, as each of the array elements
must be sent to the function independently. In the following, we will therefore
show how to implement functions with vector arguments that also return vectors.
This may be done in various ways. Some possibilities are presented in the
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 40

following, and, as we shall see, some are more time consuming than others. We
will also demonstrate how the time consumption (or efficiency) may be tested.
A simple extension of the single-valued function cd_sphere is as follows:
def cd_sphere_py_vector(ReNrs):
CD = zeros_like(ReNrs)
counter = 0

for Re in ReNrs:
CD[counter] = cd_sphere(Re)
counter += 1
return CD

The new function cd_sphere_py_vector takes in an array ReNrs and calcu-


lates the drag coefficient for each element using the previous function cd_sphere.
This does the job, but is not very efficient.
A second version is implemented in the function cd_sphere_vector. This
function takes in the array Re and calculates the drag coefficient of all elements by
multiple calls of the function numpy.where; one call for each condition, similarly
as each if statement in the function cd_sphere. The function is shown here:
def cd_sphere_vector(Re):
"Computes the drag coefficient of a sphere as a function of the Reynolds number Re."
# Curve fitted after fig . A -56 in Evett and Liu: "Fluid Mechanics and Hydraulics"

from numpy import log10, array, polyval, where, zeros_like


CD = zeros_like(Re)

CD = where(Re < 0, 0.0, CD) # condition 1

CD = where((Re > 0.0) & (Re <=0.5), 24/Re, CD) # condition 2

p = array([4.22, -14.05, 34.87, 0.658])


CD = where((Re > 0.5) & (Re <=100.0), polyval(p, 1.0/Re), CD) #condition 3

p = array([-30.41, 43.72, -17.08, 2.41])


CD = where((Re > 100.0) & (Re <= 1.0e4), polyval(p, 1.0/log10(Re)), CD) #condition 4

p = array([-0.1584, 2.031, -8.472, 11.932])


CD = where((Re > 1.0e4) & (Re <= 3.35e5), polyval(p, log10(Re)), CD) #condition 5

CD = where((Re > 3.35e5) & (Re <= 5.0e5), 91.08*(log10(Re/4.5e5))**4 + 0.0764, CD) #condition 6

p = array([-0.06338, 1.1905, -7.332, 14.93])


CD = where((Re > 5.05e5) & (Re <= 8.0e6), polyval(p, log10(Re)), CD) #condition 7

CD = where(Re > 8.0e6, 0.2, CD) # condition 8


return CD

A third approach we will try is using boolean type variables. The 8 variables
condition1 through condition8 in the function cd_sphere_vector_bool are
boolean variables of the same size and shape as Re. The elements of the boolean
variables evaluate to either True or False, depending on if the corresponding
element in Re satisfy the condition the variable is assigned.
def cd_sphere_vector_bool(Re):
"Computes the drag coefficient of a sphere as a function of the Reynolds number Re."
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 41

# Curve fitted after fig . A -56 in Evett and Liu: "Fluid Mechanics and Hydraulics"
from numpy import log10, array, polyval, zeros_like

condition1 = Re < 0
condition2 = logical_and(0 < Re, Re <= 0.5)
condition3 = logical_and(0.5 < Re, Re <= 100.0)
condition4 = logical_and(100.0 < Re, Re <= 1.0e4)
condition5 = logical_and(1.0e4 < Re, Re <= 3.35e5)
condition6 = logical_and(3.35e5 < Re, Re <= 5.0e5)
condition7 = logical_and(5.0e5 < Re, Re <= 8.0e6)
condition8 = Re > 8.0e6
CD = zeros_like(Re)
CD[condition1] = 0.0

CD[condition2] = 24/Re[condition2]
p = array([4.22,-14.05,34.87,0.658])
CD[condition3] = polyval(p,1.0/Re[condition3])
p = array([-30.41,43.72,-17.08,2.41])
CD[condition4] = polyval(p,1.0/log10(Re[condition4]))

p = array([-0.1584,2.031,-8.472,11.932])
CD[condition5] = polyval(p,log10(Re[condition5]))

CD[condition6] = 91.08*(log10(Re[condition6]/4.5e5))**4 + 0.0764


p = array([-0.06338,1.1905,-7.332,14.93])
CD[condition7] = polyval(p,log10(Re[condition7]))

CD[condition8] = 0.2
return CD

Lastly, the built-in function vectorize is used to automatically generate a


vector-version of the function cd_sphere, as follows:
cd_sphere_auto_vector = vectorize(cd_sphere)

To provide a convenient and practical means to compare the various imple-


mentations of the drag function, we have collected them all in a file DragCoef-
ficientGeneric.py. This file constitutes a Python module which is a concept
we will discuss in section 2.7.

2.7 How to make a Python-module and some


useful programming features
Python modules A module is a file containing Python definitions and state-
ments and represents a convenient way of collecting useful and related functions,
classes or Python code in a single file. A motivation to implement the drag
coefficient function was that we should be able to import it in other programs to
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 42

solve e.g. the problems outlined in (2.5.4). In general, a file containing Python-
code may be executed either as a main program (script), typically with python
filename.py or imported in another script/module with import filename.
A module file should not execute a main program, but rather just define
functions, import other modules, and define global variables. Inside modules,
the standard practice is to only have functions and not any statements outside
functions. The reason is that all statements in the module file are executed from
top to bottom during import in another module/script [16], and thus a desirable
behavior is no output to avoid confusion. However, in many situations it is also
desirable to allow for tests or demonstration of usage inside the module file, and
for such situations the need for a main program arises. To meet these demands
Python allows for a fortunate construction to let a file act both as a module with
function definitions only (i.e. no main program) and as an ordinary program we
can run, with functions and a main program. The latter is possible by letting
the main program follow an if test of the form:
if __name__ ==’__main__’:
<main program statements>

The __name__ variable is automatically defined in any module and equals the
module name if the module is imported in another program/script, but when the
module file is executed as a program, __name__ equals the string ’__main__’.
Consequently, the if test above will only be true whenever the module file
is executed as a program and allow for the execution of the <main program
statements>. The <main program statements> is normally referred to as the
test block of a module.
The module name is the file name without the suffix .py [16], i.e. the module
contained in the module file filename.py has the module name filename. Note
that a module can contain executable statements as well as function definitions.
These statements are intended to initialize the module and are executed only
the first time the module name is encountered in an import statement. They
are also run if the file is executed as a script.
Below we have listed the content of the file DragCoefficientGeneric.py
to illustrate a specific implementation of the module DragCoefficientGeneric
and some other useful programming features in Python. The functions in the
module are the various implementations of the drag coefficient functions from
the previous section.
Python lists and dictionaries
• Lists hold a list of values and are initialized with empty brackets, e.g.
fncnames = []. The values of the list are accessed with an index, start-
ing from zero. The first value of fncnames is fncnames[0], the second
value of fncnames is fncnames[1] and so on. You can remove values
from the list, and add new values to the end by fncnames. Example:
fncnames.append(name) will append name as the last value of the list
fncnames. In case it was empty prior to the append-operation, name will
be the only element in the list.
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 43

• Dictionaries are similar to what their name suggests - a dictionary - and


an empty dictionary is initialized with empty braces, e.g. CD = {}. In a
dictionary, you have an ’index’ of words or keys and the values accessed by
their ’key’. Thus, the values in a dictionary aren’t numbered or ordered,
they are only accessed by the key. You can add, remove, and modify
the values in dictionaries. For example with the statement CD[name] =
func(ReNrs) the results of func(ReNrs) are stored in the list CD with key
name.
To illustrate a very powerful feature of Python data structures allowing for lists
of e.g. function objects we put all the function names in a list with the statement:
funcs = [cd_sphere_py_vector, cd_sphere_vector, cd_sphere_vector_bool, \
cd_sphere_auto_vector] # list of functions to test

which allows for convenient looping over all of the functions with the following
construction:
for func in funcs:

Exception handling Python has a very convenient construction for testing


of potential errors with try-except blocks:
try:
<statements>
except ExceptionType1:
<remedy for ExceptionType1 errors>
except ExceptionType2:
<remedy for ExceptionType1 errors>
except:
<remedy for any other errors>

In the DragCoefficientGeneric module, this feature is used to handle the


function name for a function which has been vectorized automatically. For such
a function func.func_name has no value and will return an error, and the name
may be found by the statements in the exception block.
Efficiency and benchmarking The function clock in the module time,
return a time expressed in seconds for the current statement and is frequently
used for benchmarking in Python or timing of functions. By subtracting the time
t0 recored immediately before a function call from the time immediately after
the function call, an estimate of the elapsed cpu-time is obtained. In our module
DragCoefficientGeneric the efficiency is implemented with the codelines:
t0 = time.clock()
CD[name] = func(ReNrs)
exec_times[name] = time.clock() - t0

Sorting of dictionaries The computed execution times are for convenience


stored in the dictionary exec_time to allow for pairing of the names of the
functions and their execution time. The dictionary may be sorted on the values
and the corresponding keys sorted are returned by:
exec_keys_sorted = sorted(exec_times, key=exec_times.get)
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 44

Afterwards the results may be printed with name and execution time, ordered
by the latter, with the most efficient function at the top:
for name_key in exec_keys_sorted:
print name_key, ’\t execution time = ’, ’%6.6f’ % exec_times[name_key]

By running the module DragCoefficientGeneric as a script, and with 500


elements in the ReNrs array we got the following output:
cd_sphere_vector_bool execution time = 0.000312
cd_sphere_vector execution time = 0.000641
cd_sphere_auto_vector execution time = 0.009497
cd_sphere_py_vector execution time = 0.010144

Clearly, the function with the boolean variables was fastest, the straight forward
vectorized version cd_sphere_py_vector was slowest and the built-in function
vectorize was nearly as inefficient.
The complete module DragCoefficientGeneric is listed below.
# src-ch1/DragCoefficientGeneric.py
from numpy import linspace,array,append,logspace,zeros_like,where,vectorize,\
logical_and
import numpy as np
from matplotlib.pyplot import loglog,xlabel,ylabel,grid,savefig,show,rc,hold,\
legend, setp
from numpy.core.multiarray import scalar

# single-valued function
def cd_sphere(Re):
"Computes the drag coefficient of a sphere as a function of the Reynolds number Re."
# Curve fitted after fig . A -56 in Evett and Liu: "Fluid Mechanics and Hydraulics"

from numpy import log10,array,polyval

if Re <= 0.0:
CD = 0.0
elif Re > 8.0e6:
CD = 0.2
elif Re > 0.0 and Re <= 0.5:
CD = 24.0/Re
elif Re > 0.5 and Re <= 100.0:
p = array([4.22,-14.05,34.87,0.658])
CD = polyval(p,1.0/Re)
elif Re > 100.0 and Re <= 1.0e4:
p = array([-30.41,43.72,-17.08,2.41])
CD = polyval(p,1.0/log10(Re))
elif Re > 1.0e4 and Re <= 3.35e5:
p = array([-0.1584,2.031,-8.472,11.932])
CD = polyval(p,log10(Re))
elif Re > 3.35e5 and Re <= 5.0e5:
x1 = log10(Re/4.5e5)
CD = 91.08*x1**4 + 0.0764
else:
p = array([-0.06338,1.1905,-7.332,14.93])
CD = polyval(p,log10(Re))
return CD
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 45

# simple extension cd_sphere


def cd_sphere_py_vector(ReNrs):
CD = zeros_like(ReNrs)
counter = 0
for Re in ReNrs:
CD[counter] = cd_sphere(Re)
counter += 1
return CD
# vectorized function
def cd_sphere_vector(Re):
"Computes the drag coefficient of a sphere as a function of the Reynolds number Re."
# Curve fitted after fig . A -56 in Evett and Liu: "Fluid Mechanics and Hydraulics"

from numpy import log10, array, polyval, where, zeros_like


CD = zeros_like(Re)
CD = where(Re < 0, 0.0, CD) # condition 1

CD = where((Re > 0.0) & (Re <=0.5), 24/Re, CD) # condition 2

p = array([4.22, -14.05, 34.87, 0.658])


CD = where((Re > 0.5) & (Re <=100.0), polyval(p, 1.0/Re), CD) #condition 3

p = array([-30.41, 43.72, -17.08, 2.41])


CD = where((Re > 100.0) & (Re <= 1.0e4), polyval(p, 1.0/log10(Re)), CD) #condition 4

p = array([-0.1584, 2.031, -8.472, 11.932])


CD = where((Re > 1.0e4) & (Re <= 3.35e5), polyval(p, log10(Re)), CD) #condition 5

CD = where((Re > 3.35e5) & (Re <= 5.0e5), 91.08*(log10(Re/4.5e5))**4 + 0.0764, CD) #condition 6

p = array([-0.06338, 1.1905, -7.332, 14.93])


CD = where((Re > 5.05e5) & (Re <= 8.0e6), polyval(p, log10(Re)), CD) #condition 7

CD = where(Re > 8.0e6, 0.2, CD) # condition 8


return CD

# vectorized boolean
def cd_sphere_vector_bool(Re):
"Computes the drag coefficient of a sphere as a function of the Reynolds number Re."
# Curve fitted after fig . A -56 in Evett and Liu: "Fluid Mechanics and Hydraulics"

from numpy import log10, array, polyval, zeros_like

condition1 = Re < 0
condition2 = logical_and(0 < Re, Re <= 0.5)
condition3 = logical_and(0.5 < Re, Re <= 100.0)
condition4 = logical_and(100.0 < Re, Re <= 1.0e4)
condition5 = logical_and(1.0e4 < Re, Re <= 3.35e5)
condition6 = logical_and(3.35e5 < Re, Re <= 5.0e5)
condition7 = logical_and(5.0e5 < Re, Re <= 8.0e6)
condition8 = Re > 8.0e6

CD = zeros_like(Re)
CD[condition1] = 0.0

CD[condition2] = 24/Re[condition2]

p = array([4.22,-14.05,34.87,0.658])
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 46

CD[condition3] = polyval(p,1.0/Re[condition3])
p = array([-30.41,43.72,-17.08,2.41])
CD[condition4] = polyval(p,1.0/log10(Re[condition4]))
p = array([-0.1584,2.031,-8.472,11.932])
CD[condition5] = polyval(p,log10(Re[condition5]))

CD[condition6] = 91.08*(log10(Re[condition6]/4.5e5))**4 + 0.0764


p = array([-0.06338,1.1905,-7.332,14.93])
CD[condition7] = polyval(p,log10(Re[condition7]))
CD[condition8] = 0.2

return CD

if __name__ == ’__main__’:
#Check whether this file is executed (name==main) or imported as a module
import time
from numpy import mean

CD = {} # Empty list for all CD computations

ReNrs = logspace(-2,7,num=500)
# make a vectorized version of the function automatically
cd_sphere_auto_vector = vectorize(cd_sphere)

# make a list of all function objects


funcs = [cd_sphere_py_vector, cd_sphere_vector, cd_sphere_vector_bool, \
cd_sphere_auto_vector] # list of functions to test

# Put all exec_times in a dictionary and fncnames in a list


exec_times = {}
fncnames = []
for func in funcs:
try:
name = func.func_name
except:
scalarname = func.__getattribute__(’pyfunc’)
name = scalarname.__name__+’_auto_vector’

fncnames.append(name)

# benchmark
t0 = time.clock()
CD[name] = func(ReNrs)
exec_times[name] = time.clock() - t0

# sort the dictionary exec_times on values and return a list of the corresponding keys
exec_keys_sorted = sorted(exec_times, key=exec_times.get)

# print the exec_times by ascending values


for name_key in exec_keys_sorted:
print name_key, ’\t execution time = ’, ’%6.6f’ % exec_times[name_key]
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 47

# set fontsize prms


fnSz = 16; font = {’size’ : fnSz}; rc(’font’,**font)

# set line styles


style = [’v-’, ’8-’, ’*-’, ’o-’]
mrkevry = [30, 35, 40, 45]

# plot the result for all functions


i=0
for name in fncnames:
loglog(ReNrs, CD[name], style[i], markersize=10, markevery=mrkevry[i])
hold(’on’)
i+=1

# use fncnames as plot legend


leg = legend(fncnames)
leg.get_frame().set_alpha(0.)
xlabel(’$Re$’)
ylabel(’$C_D$’)
grid(’on’, ’both’, ’both’)
# # savefig(’example_sphere_generic.png’, transparent=True) # save plot if needed
show()

2.7.1 Example: Numerical error as a function of ∆t


In this example we will assess how the error of our implementation of the Euler
method depends on the time step ∆t in a systematic manner. We will solve a
problem with an analytical solution in a loop, and for each new solution we do
the following:
• Divide the time step by two (or double the number of time steps)

• Compute the error


• Plot the error
Euler’s method is a first order method and we expect the error to be O(h) =
O(∆t). Consequently if the time-step is divided by two, the error should also
be divided by two. As errors normally are small values and are expected to be
smaller and smaller for decreasing time steps, we normally do not plot the error
itself, but rather the logarithm of the absolute value of the error. The latter we
do due to the fact that we are only interested in the order of magnitude of the
error, whereas errors may be both positive and negative. As the initial value is
always correct we discard the first error at time zero to avoid problems with the
logarithm of zero in log_error = np.log2(abs_error[1:]).
# coding: utf-8
# src-ch1/Euler_timestep_ctrl.py;DragCoefficientGeneric.py @ git@lrhgit/tkt4140/src/src-ch1/DragCoeff
from DragCoefficientGeneric import cd_sphere
from matplotlib.pyplot import *
import numpy as np

# change some default values to make plots more readable


LNWDT=2; FNT=11
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 48

rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT

g = 9.81 # Gravity m/s^2


d = 41.0e-3 # Diameter of the sphere
rho_f = 1.22 # Density of fluid [kg/m^3]
rho_s = 1275 # Density of sphere [kg/m^3]
nu = 1.5e-5 # Kinematical viscosity [m^2/s]
CD = 0.4 # Constant drag coefficient

def f(z, t):


"""2x2 system for sphere with constant drag."""
zout = np.zeros_like(z)
alpha = 3.0*rho_f/(4.0*rho_s*d)*CD
zout[:] = [z[1], g - alpha*z[1]**2]
return zout
# define euler scheme
def euler(func,z0, time):
"""The Euler scheme for solution of systems of ODEs.
z0 is a vector for the initial conditions,
the right hand side of the system is represented by func which returns
a vector with the same size as z0 ."""

z = np.zeros((np.size(time),np.size(z0)))
z[0,:] = z0

for i in range(len(time)-1):
dt = time[i+1]-time[i]
z[i+1,:]=z[i,:] + np.asarray(func(z[i,:],time[i]))*dt
return z

def v_taylor(t):
# z = np.zeros_like(t)
v = np.zeros_like(t)
alpha = 3.0*rho_f/(4.0*rho_s*d)*CD
v=g*t*(1-alpha*g*t**2)
return v

# main program starts here


T = 10 # end of simulation
N = 10 # no of time steps

z0=np.zeros(2)
z0[0] = 2.0

# Prms for the analytical solution


k1 = np.sqrt(g*4*rho_s*d/(3*rho_f*CD))
k2 = np.sqrt(3*rho_f*g*CD/(4*rho_s*d))
Ndts = 4 # Number of times to divide the dt by 2
legends=[]
error_diff = []

for i in range(Ndts+1):
time = np.linspace(0, T, N+1)
ze = euler(f, z0, time) # compute response with constant CD using Euler’s method
v_a = k1*np.tanh(k2*time) # compute response with constant CD using analytical solution
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 49

abs_error=np.abs(ze[:,1] - v_a)
log_error = np.log2(abs_error[1:])
max_log_error = np.max(log_error)

plot(time[1:], log_error)
legends.append(’Euler scheme: N ’ + str(N) + ’ timesteps’ )
N*=2
if i > 0:
error_diff.append(previous_max_log_err-max_log_error)
previous_max_log_err = max_log_error

print ’Approximate order of scheme n =’, np.mean(error_diff)


print ’Approximate error reuduction by dt=dt/2:’, 1/2**(np.mean(error_diff))

# plot analytical solution


# plot(time,v_a)
# legends.append(’analytical’)

# fix plot
legend(legends, loc=’best’, frameon=False)
xlabel(’Time [s]’)
#ylabel(’Velocity [m/s]’)
ylabel(’log2-error’)
#savefig(’example_euler_timestep_study.png’, transparent=True)
show()

The plot resulting from the code above is shown in Figure (2.11). The
difference or distance between the curves seems to be rather constant after an
initial transient. As we have plotted the logarithm of the absolute value of the
error i , the difference di+1 between two curves is di+1 = log2 i − log2 i+1 =
i
log2 . A rough visual inspection of Figure (2.11) yields di+1 ≈ 1.0, from
i+1
which we may deduce the apparent order of the scheme:
i
n = log2 ≈ 1 ⇒ i+1 ≈ 0.488483620 i (2.73)
i+1

The print statement returns ’n=1.0336179048’ and ’0.488483620794’, thus we


see that the error is reduced even slightly more than the theoretically expected
value for a first order scheme, i.e. ∆ti+1 = ∆ti /2 yields i+1 ≈ i /2.
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 50

−2

−4

log2 -error
−6

−8
Euler scheme: N 10 timesteps
−10
Euler scheme: N 20 timesteps
−12 Euler scheme: N 40 timesteps
Euler scheme: N 80 timesteps
−14
Euler scheme: N 160 timesteps
−16
0 2 4 6 8 10
Time [s]

Figure 2.11: Plots for the logarithmic errors for a falling sphere with constant
drag. The timestep ∆t is reduced by a factor two from one curve to the one
immediately below.

2.8 Heun’s method


From (2.27) or (2.31) we have

f (xn + h) − f (xn )
y 00 (xn , yn ) = f 0 (xn , y(xn , yn )) ≈ (2.74)
h
The Taylor series expansion (2.25) gives

h2 00
y(xn + h) = y(xn ) + hy 0 [xn , y(xn )] + y [xn , y(xn )] + O(h3 )
2
which, inserting (2.74), gives

h
yn+1 = yn + · [f (xn , yn ) + f (xn+1 , y(xn+1 ))] (2.75)
2
This formula is called the trapezoidal formula, since it reduces to computing
an integral with the trapezoidal rule if f (x, y) is only a function of x. Since yn+1
appears on both sides of the equation, this is an implicit formula which means
that we need to solve a system of non-linear algebraic equations if the function
f (x, y) is non-linear. One way of making the scheme explicit is to use the Euler
scheme (2.53) to calculate y(xn+1 ) on the right side of (2.75). The resulting
scheme is often denoted Heun’s method.
The scheme for Heun’s method becomes
p
yn+1 = yn + h · f (xn , yn ) (2.76)
h p
yn+1 = yn + · [f (xn , yn ) + f (xn+1 , yn+1 )] (2.77)
2
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 51

Index p stands for "predicted". (2.76) is then the predictor and (2.77) is the
corrector. This is a second order method. For more details, see [4]. Figure 2.12
is a graphical illustration of the method.

y
corrected
yn+1 slope
slope
f(xn+1,yn+1)
y(x)
ypn+1

slope
yn
f(xn,yn)

xn xn+1 x

Figure 2.12: Illustration of Heun’s method.

In principle we could make an iteration procedure where we after using the


corrector use the corrected values to correct the corrected values to make a
new predictor and so on. This will likely lead to a more accurate solution of
the difference scheme, but not necessarily of the differential equation. We are
therefore satisfied by using the corrector once. For a system, we get
p
yn+1 = yn + h · f (xn , yn ) (2.78)
h p
yn+1 = yn + · [f (xn , yn ) + f (xn+1 , yn+1 )] (2.79)
2
p
Note that yn+1 is a temporary variable that is not necessary to store.
If we use (2.78) and (2.79) on the example in (2.62) we get
Predictor:
(y1 )pn+1 = (y1 )n + h · (y2 )n
(y2 )pn+1 = (y2 )n + h · (y3 )n
(y3 )pn+1 = (y3 )n − h · (y1 )n · (y3 )n
Corrector:
(y1 )n+1 = (y1 )n + 0.5h · [(y2 )n + (y2 )pn+1 ]
(y2 )n+1 = (y2 )n + 0.5h · [(y3 )n + (y3 )pn+1 ]
(y3 )n+1 = (y3 )n − 0.5h · [(y1 )n · (y3 )n + (y1 )pn+1 · (y3 )pn+1 ]

2.8.1 Example: Newton’s equation


Let’s use Heun’s method to solve Newton’s equation from section 2.1,
y 0 (x) = 1 − 3x + y + x2 + xy, y(0) = 0 (2.80)
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 52

with analytical solution

 √  √ 


  x  2 2
y(x) =3 2πe · exp x 1 + · erf (1 + x) − erf
2 2 2
h   x i
+4 · 1 − exp x 1 + −x (2.81)
2
Here we have f (x, y) = 1 − 3x + y + x2 + xy = 1 + x(x − 3) + (1 + x)y
The following program NewtonHeun.py solves this problem using Heun’s
method, and the resulting figure is shown in Figure 2.13.
# src-ch1/NewtonHeun.py
# Program Newton
# Computes the solution of Newton’s 1st order equation (1671):
# dy/dx = 1-3*x + y + x^2 +x*y , y(0) = 0
# using Heun’s method.

import numpy as np

xend = 2
dx = 0.1
steps = np.int(np.round(xend/dx, 0)) + 1
y, x = np.zeros((steps,1), float), np.zeros((steps,1), float)
y[0], x[0] = 0.0, 0.0

for n in range(0,steps-1):
x[n+1] = (n+1)*dx
xn = x[n]
fn = 1 + xn*(xn-3) + y[n]*(1+xn)
yp = y[n] + dx*fn
xnp1 = x[n+1]
fnp1 = 1 + xnp1*(xnp1-3) + yp*(1+xnp1)
y[n+1] = y[n] + 0.5*dx*(fn+fnp1)
# Analytical solution
from scipy.special import erf
a = np.sqrt(2)/2
t1 = np.exp(x*(1+ x/2))
t2 = erf((1+x)*a)-erf(a)
ya = 3*np.sqrt(2*np.pi*np.exp(1))*t1*t2 + 4*(1-t1)-x

# plotting
import matplotlib.pylab as plt

# change some default values to make plots more readable


LNWDT=2; FNT=11
plt.rcParams[’lines.linewidth’] = LNWDT; plt.rcParams[’font.size’] = FNT

plt.plot(x, y, ’-b.’, x, ya, ’-g.’)


plt.xlabel(’x’)
plt.ylabel(’y’)

plt.title(’Solution to Newton\’s equation’)


plt.legend([’Heun’, ’Analytical’], loc=’best’, frameon=False)
plt.grid()
#plt.savefig(’newton_heun.png’, transparent=True)
plt.show()
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 53

0.5

0.0

−0.5

−1.0

−1.5

y
−2.0

−2.5

−3.0 Heun
Analytical
−3.5
0.0 0.5 1.0 1.5 2.0
x

Figure 2.13: Velocity of falling sphere using Euler’s and Heun’s methods.

2.8.2 Example: Falling sphere with Heun’s method


Let’s go back to (2.5.5), and implement a new function heun() in the program
FallingSphereEuler.py.
We recall the system of equations as
dz
=v
dt
dv
= g − αv 2
dt
which by use of Heun’s method in (2.78) and (2.79) becomes
Predictor:
p
zn+1 = zn + ∆tvn (2.82)
p
vn+1 = vn + ∆t · (g − αvn2 )

Corrector:
p
zn+1 = zn + 0.5∆t · (vn + vn+1 ) (2.83)
2 p
)2
 
vn+1 = vn + 0.5∆t · 2g − α[vn + (vn+1

with initial values z0 = z(0) = 0, v0 = v(0) = 0. Note that we don’t use the
p
predictor zn+1 since it doesn’t appear on the right hand side of the equation
system.
One possible way of implementing this scheme is given in the following
function named heun(), in the program ODEschemes.py:
def heun(func, z0, time):
"""The Heun scheme for solution of systems of ODEs.
z0 is a vector for the initial conditions,
the right hand side of the system is represented by func which returns
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 54

a vector with the same size as z0 ."""


z = np.zeros((np.size(time), np.size(z0)))
z[0,:] = z0
zp = np.zeros_like(z0)

for i, t in enumerate(time[0:-1]):
dt = time[i+1] - time[i]
zp = z[i,:] + np.asarray(func(z[i,:],t))*dt # Predictor step
z[i+1,:] = z[i,:] + (np.asarray(func(z[i,:],t)) + np.asarray(func(zp,t+dt)))*dt/2.0 # Correct

Using the same time steps as in (2.5.5), we get the response plotted in
Figure 2.14.

40

35

30

25
Velocity [m/s]

20

15 Analytical (constant CD)


Euler (constant CD)
10
Heun (constant CD)
5 Euler (varying CD)
Heun (varying CD)
0
0 2 4 6 8 10
Time [s]

Figure 2.14: Velocity of falling sphere using Euler’s and Heun’s methods.

The complete program FallingSphereEulerHeun.py is listed below. Note


that the solver functions euler and heun are imported from the script ODE-
schemes.py.
# src-ch1/FallingSphereEulerHeun.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch1/ODEschemes.py;
from DragCoefficientGeneric import cd_sphere
from ODEschemes import euler, heun
from matplotlib.pyplot import *
import numpy as np
# change some default values to make plots more readable
LNWDT=5; FNT=11
rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT

g = 9.81 # Gravity m/s^2


d = 41.0e-3 # Diameter of the sphere
rho_f = 1.22 # Density of fluid [kg/m^3]
rho_s = 1275 # Density of sphere [kg/m^3]
nu = 1.5e-5 # Kinematical viscosity [m^2/s]
CD = 0.4 # Constant drag coefficient
def f(z, t):
"""2x2 system for sphere with constant drag."""
zout = np.zeros_like(z)
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 55

alpha = 3.0*rho_f/(4.0*rho_s*d)*CD
zout[:] = [z[1], g - alpha*z[1]**2]
return zout

def f2(z, t):


"""2x2 system for sphere with Re-dependent drag."""
zout = np.zeros_like(z)
v = abs(z[1])
Re = v*d/nu
CD = cd_sphere(Re)
alpha = 3.0*rho_f/(4.0*rho_s*d)*CD
zout[:] = [z[1], g - alpha*z[1]**2]
return zout

# main program starts here

T = 10 # end of simulation
N = 20 # no of time steps
time = np.linspace(0, T, N+1)

z0=np.zeros(2)
z0[0] = 2.0

ze = euler(f, z0, time) # compute response with constant CD using Euler’s method
ze2 = euler(f2, z0, time) # compute response with varying CD using Euler’s method
zh = heun(f, z0, time) # compute response with constant CD using Heun’s method
zh2 = heun(f2, z0, time) # compute response with varying CD using Heun’s method
k1 = np.sqrt(g*4*rho_s*d/(3*rho_f*CD))
k2 = np.sqrt(3*rho_f*g*CD/(4*rho_s*d))
v_a = k1*np.tanh(k2*time) # compute response with constant CD using analytical solution

# plotting

legends=[]
line_type=[’-’,’:’,’.’,’-.’,’--’]

plot(time, v_a, line_type[0])


legends.append(’Analytical (constant CD)’)

plot(time, ze[:,1], line_type[1])


legends.append(’Euler (constant CD)’)

plot(time, zh[:,1], line_type[2])


legends.append(’Heun (constant CD)’)

plot(time, ze2[:,1], line_type[3])


legends.append(’Euler (varying CD)’)
plot(time, zh2[:,1], line_type[4])
legends.append(’Heun (varying CD)’)
legend(legends, loc=’best’, frameon=False)

xlabel(’Time [s]’)
ylabel(’Velocity [m/s]’)
#savefig(’example_sphere_falling_euler_heun.png’, transparent=True)
show()
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 56

2.9 Generic second order Runge-Kutta method


We seek to derive a generic second order Runge-Kutta method for the solution
of a generic ODE (2.1) on the form:

yn+1 = yn + (a1 K1 + a2 K2 ) (2.84)

where a1 and a2 are some weights to be determined and K1 and K2 are


derivatives on the form:

K1 = f (xn , yn ) and K1 = f (xn + p1 h, yn + p2 K1 h) (2.85)

By substitution of (2.85) in (2.85) we get:

yn+1 = yn + a1 h f (xn , yn ) + a2 h f (xn + p1 h, yn + p2 K1 h) (2.86)

Now, we may find a Taylor-expansion of f (xn + p1 h, yn + p2 K1 h):

f (xn + p1 h, yn + p2 K1 h) = f + p1 h fx + p2 K1 h fy + h.o.t.
= f + p1 h fx + p2 h f fy + h.o.t. (2.87)

where we for convenience have adopted the common notation for partial deriva-
tives
∂f ∂f
fx ≡ and fy ≡ (2.88)
∂x ∂y

By substitution of (2.87) in (2.86) we eliminate the implicit dependency of


yn+1

yn+1 = yn + a1 h f (xn , yn ) + a2 h (f + p1 h fx + p2 h f fy )
= yn + (a1 + a2 ) hf + (a2 p1 fx + a2 p2 f fy ) h2 (2.89)

Further, a second order derivative of the solution to (2.1) may be obtained


by differentiation:

d2 y df dx dy
y 00 = 2
= = ∂f x + ∂f y = fx + f fy (2.90)
dx dx dx dx
which may be used in a second order Taylor expansion of the solution of (2.1):

h2 00
y(xn + h) = yn + hy 0 + y + O(h3 ) (2.91)
2
Substitution of (2.90) and (2.1) into (2.91) yields:

h2
y(xn + h) = yn + hf + (fx + f fy ) + O(h3 ) (2.92)
2
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 57

Now the idea of the generic second order Runge-Kutta method is to select
a1 , a2 , K1 , and K2 in such a way that (2.89) approximates (2.92), which will be
true if:

a1 + a2 = 1
1
a2 p1 = (2.93)
2
1
a2 p2 =
2
Note, that since we have 4 unknowns (a1 , a2 , K1 , and K2 ) and only 3
equations in (2.93), several methods of the kind proposed in (2.84) are possible. 2.8
is retrieved by selecting a2 = 1/2, from which we get a1 = 1/2 and p1 = p2 = 1
from (2.93).

2.10 Runge-Kutta of 4th order


Euler’s method and Heun’s method belong to the Runge-Kutta family of explicit
methods, and is respectively Runge-Kutta of 1st and 2nd order, the latter with
one time use of corrector. Explicit Runge-Kutta schemes are single step schemes
that try to copy the Taylor series expansion of the differential equation to a
given order.
The classical Runge-Kutta scheme of 4th order (RK4) is given by
k1 = f (xn , yn )
h h
k2 = f (xn + , yn + k1 )
2 2
h h
k3 = f (xn + , yn + k2 ) (2.94)
2 2
k4 = f (xn + h, yn + hk3 )
h
yn+1 = yn + (k1 + 2k2 + 2k3 + k4 )
6
We see that we are actually using Euler’s method four times and find a
weighted gradient. The local error is of order O(h5 ), while the global is of O(h4 ).
We refer to [4].
Figure 2.15 shows a graphical illustration of the RK4 scheme.
In detail we have
1. In point (xn , yn ) we know the gradient k1 and use this when we go forward
a step h/2 where the gradient k2 is calculated.
2. With this gradient we start again in point (xn , yn ), go forward a step h/2
and find a new gradient k3 .
3. With this gradient we start again in point (xn , yn ), but go forward a
complete step h and find a new gradient k4 .
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 58

4. The four gradients are averaged with weights 1/6, 2/6, 2/6 and 1/6. Using
the averaged gradient we calculate the final value yn+1 .
Each of the steps above are Euler steps.

y
y(x)

yn+1 4
3

2
yn 1

xn xn+½ xn+1 x

Figure 2.15: Illustration of the RK4 scheme.

Using (2.94) on the equation system in (2.62) we get

h
(y1 )n+1 = (y1 )n + (k1 + 2k2 + 2k3 + k4 )
6
h
(y2 )n+1 = (y2 )n + (l1 + 2l2 + 2l3 + l4 ) (2.95)
6
h
(y3 )n+1 = (y3 )n + (m1 + 2m2 + 2m3 + m4 )
6
(2.96)
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 59

where
k1 = y2
l1 = y3
m1 = −y1 y3

k2 = (y2 + hll /2)


l2 = (y3 + hm1 /2)
m2 = −[(y1 + hk1 /2)(y3 + hm1 /2)]

k3 = (y2 + hl2 /2)


l3 = (y3 + hm2 /2)
m3 = −[(y1 + hk2 /2)(y3 + hm2 /2)]

k4 = (y2 + hl3 )
l4 = (y3 + hm3 )
m4 = −[(y1 + hk3 )(y3 + hm3 )

2.10.1 Example: Falling sphere using RK4


Let’s implement the RK4 scheme and add it to the falling sphere example. The
scheme has been implemented in the function rk4(), and is given below
def rk4(func, z0, time):
"""The Runge-Kutta 4 scheme for solution of systems of ODEs.
z0 is a vector for the initial conditions,
the right hand side of the system is represented by func which returns
a vector with the same size as z0 ."""
z = np.zeros((np.size(time),np.size(z0)))
z[0,:] = z0
zp = np.zeros_like(z0)

for i, t in enumerate(time[0:-1]):
dt = time[i+1] - time[i]
dt2 = dt/2.0
k1 = np.asarray(func(z[i,:], t)) # predictor step 1
k2 = np.asarray(func(z[i,:] + k1*dt2, t + dt2)) # predictor step 2
k3 = np.asarray(func(z[i,:] + k2*dt2, t + dt2)) # predictor step 3
k4 = np.asarray(func(z[i,:] + k3*dt, t + dt)) # predictor step 4
z[i+1,:] = z[i,:] + dt/6.0*(k1 + 2.0*k2 + 2.0*k3 + k4) # Corrector step

Figure 2.16 shows the results using Euler, Heun and RK4. AS seen, RK4
and Heun are more accurate than Euler. The complete program Falling-
SphereEulerHeunRK4.py is listed below. The functions euler, heun and
rk4 are imported from the program ODEschemes.py.
# src-ch1/FallingSphereEulerHeunRK4.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch1/ODEschemes.py;
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 60

40

35

30

25

Velocity [m/s]
20
Analytical (constant CD)
Euler (constant CD)
15 Heun (constant CD)
RK4 (constant CD)
10
Euler (varying CD)
5 Heun (varying CD)
RK4 (varying CD)
0
0 2 4 6 8 10
Time [s]

Figure 2.16: Velocity of falling sphere using Euler, Heun and RK4.

from DragCoefficientGeneric import cd_sphere


from ODEschemes import euler, heun, rk4
from matplotlib.pyplot import *
import numpy as np

# change some default values to make plots more readable


LNWDT=5; FNT=11
rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT

g = 9.81 # Gravity m/s^2


d = 41.0e-3 # Diameter of the sphere
rho_f = 1.22 # Density of fluid [kg/m^3]
rho_s = 1275 # Density of sphere [kg/m^3]
nu = 1.5e-5 # Kinematical viscosity [m^2/s]
CD = 0.4 # Constant drag coefficient
def f(z, t):
"""2x2 system for sphere with constant drag."""
zout = np.zeros_like(z)
alpha = 3.0*rho_f/(4.0*rho_s*d)*CD
zout[:] = [z[1], g - alpha*z[1]**2]
return zout

def f2(z, t):


"""2x2 system for sphere with Re-dependent drag."""
zout = np.zeros_like(z)
v = abs(z[1])
Re = v*d/nu
CD = cd_sphere(Re)
alpha = 3.0*rho_f/(4.0*rho_s*d)*CD
zout[:] = [z[1], g - alpha*z[1]**2]
return zout

# main program starts here


T = 10 # end of simulation
N = 20 # no of time steps
time = np.linspace(0, T, N+1)
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 61

z0=np.zeros(2)
z0[0] = 2.0

ze = euler(f, z0, time) # compute response with constant CD using Euler’s method
ze2 = euler(f2, z0, time) # compute response with varying CD using Euler’s method

zh = heun(f, z0, time) # compute response with constant CD using Heun’s method
zh2 = heun(f2, z0, time) # compute response with varying CD using Heun’s method
zrk4 = rk4(f, z0, time) # compute response with constant CD using RK4
zrk4_2 = rk4(f2, z0, time) # compute response with varying CD using RK4
k1 = np.sqrt(g*4*rho_s*d/(3*rho_f*CD))
k2 = np.sqrt(3*rho_f*g*CD/(4*rho_s*d))
v_a = k1*np.tanh(k2*time) # compute response with constant CD using analytical solution

# plotting

legends=[]
line_type=[’-’,’:’,’.’,’-.’,’:’,’.’,’-.’]

plot(time, v_a, line_type[0])


legends.append(’Analytical (constant CD)’)

plot(time, ze[:,1], line_type[1])


legends.append(’Euler (constant CD)’)

plot(time, zh[:,1], line_type[2])


legends.append(’Heun (constant CD)’)

plot(time, zrk4[:,1], line_type[3])


legends.append(’RK4 (constant CD)’)
plot(time, ze2[:,1], line_type[4])
legends.append(’Euler (varying CD)’)
plot(time, zh2[:,1], line_type[5])
legends.append(’Heun (varying CD)’)

plot(time, zrk4_2[:,1], line_type[6])


legends.append(’RK4 (varying CD)’)

legend(legends, loc=’best’, frameon=False)

xlabel(’Time [s]’)
ylabel(’Velocity [m/s]’)
#savefig(’example_sphere_falling_euler_heun_rk4.png’, transparent=True)
show()

2.10.2 Example: Particle motion in two dimensions


In this example we will calculate the motion of a particle in two dimensions.
First we will calculate the motion of a smooth ball with drag coefficient given
by the previously defined function cd_sphere() (see (2.5.4)), and then of a golf
ball with drag and lift. The problem is illustrated in the following figure:
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 62

y
vf


vr
ϕ
Fd
v0 m
g

Figure 2.17: An illustration of a particle subjected to both gravity and drag in


two dimensions.

where v is the absolute velocity, vf = is the velocity of the fluid, vr = v − vf


is the relative velocity between the fluid and the ball, α is the elevation angle,
v0 is the initial velocity and φ is the angle between the x-axis and vr .
Fl is the lift force stemming from the rotation of the ball (the Magnus-effect)
and is normal to vr . With the given direction the ball rotates counter-clockwise
(backspin). Fd is the fluids resistance against the motion and is parallel to vr .
These forces are given by
1
Fd = ρf ACD vr2 (2.97)
2
1
Fl = ρf ACL vr2 (2.98)
2
CD is the drag coefficient, CL is the lift coefficient, A is the area projected
in the velocity direction and ρF is the density of the fluid.
Newton’s law in x- and y-directions gives
dvx A 2
= −ρf v (CD · cos(φ) + CL sin(φ)) (2.99)
dt 2m r
dvy A 2
= ρf v (CL · cos(φ) − CD sin(φ)) − g (2.100)
dt 2m r
From the figure we have
vrx
cos(φ) =
vr
vry
sin(φ) =
vr
A 3ρ
We assume that the particle is a sphere, such that C = ρf 2m = 4ρkfd as in
(2.5.4). Here d is the diameter of the sphere and ρk the density of the sphere.
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 63

Now (2.99) and (2.100) become


dvx
= −C · vr (CD · vrx + CL · vry ) (2.101)
dt
dvy
= C · vr (CL · vrx − CD · vry ) − g (2.102)
dt
dx dy
With dt = vx and dt = vy we get a system of 1st order equations as follows,
dx
= vx
dt
dy
= vy
dt
dvx
= −C · vr (CD · vrx + CL · vry ) (2.103)
dt
dvy
= C · vr (CL · vrx − CD · vry ) − g
dt
Introducing the notation x = y1 , y = y2 , vx = y3 , vy = y4 , we get
dy1
= y3
dt
dy2
= y4
dt
dy3
= −C · vr (CD · vrx + CL · vry ) (2.104)
dt
dy4
= C · vr (CL · vrx − CD · vry ) − g
dt

q we have vrx = vx − vf x = y3 − vf x , vry = vy − vf y = y4 − vf y ,


Here
vr = vrx 2 + v2
ry
Initial conditions for t = 0 are

y1 = y2 = 0
y3 = v0 cos(α)
y4 = v0 sin(α)

—–
Let’s first look at the case of a smooth ball. We use the following data (which
are the data for a golf ball):
6m 3
Diameter d = 41mm, mass m = 46g which gives ρk = = 1275kg/m
πd3
We use the initial velocity v0 = 50 m/s and solve (2.104) using the Runge-Kutta
4 scheme. In this example we have used the Python package Odespy (ODE
Software in Python), which offers a large collection of functions for solving
ODE’s. The RK4 scheme available in Odespy is used herein.
The right hand side in (2.104) is implemented as the following function:
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 64

def f(z, t):


"""4x4 system for smooth sphere with drag in two directions."""
zout = np.zeros_like(z)
C = 3.0*rho_f/(4.0*rho_s*d)
vrx = z[2] - vfx
vry = z[3] - vfy
vr = np.sqrt(vrx**2 + vry**2)
Re = vr*d/nu
CD = cd_sphere(Re) # using the already defined function
zout[:] = [z[2], z[3], -C*vr*(CD*vrx), C*vr*(-CD*vry) - g]

Note that we have used the function cd_sphere() defined in (2.5.4) to


calculate the drag coefficient of the smooth sphere.
The results are shown for some initial angles in Figure 2.18.

25
angle=30.0, smooth ball
angle=25.0, smooth ball
angle=20.0, smooth ball
20 angle=15.0, smooth ball

15
y [m]

10

00 20 40 60 80 100
x [m]

Figure 2.18: Motion of smooth ball with drag.

—–
Now let’s look at the same case for a golf ball. The dimension and weight
are the same as for the sphere. Now we need to account for the lift force from
the spin of the ball. In addition, the drag data for a golf ball are completely
different from the smooth sphere. We use the data from Bearman and Harvey
[1] who measured the drag and lift of a golf ball for different spin velocities in
a vindtunnel. We choose as an example 3500 rpm, and an initial velocity of
v0 = 50 m/s.
The right hand side in (2.104) is now implemented as the following function:
def f3(z, t):
"""4x4 system for golf ball with drag and lift in two directions."""
zout = np.zeros_like(z)
C = 3.0*rho_f/(4.0*rho_s*d)
vrx = z[2] - vfx
vry = z[3] - vfy
vr = np.sqrt(vrx**2 + vry**2)
Re = vr*d/nu
CD, CL = cdcl(vr, nrpm)
zout[:] = [z[2], z[3], -C*vr*(CD*vrx + CL*vry), C*vr*(CL*vrx - CD*vry) - g]

The function cdcl() (may be downloaded here) gives the drag and lift data
for a given velocity and spin.
The results are shown in Figure 2.19. The motion of a golf ball with drag
but without lift is also included. We see that the golf ball goes much farther
than the smooth sphere, due to less drag and the lift.
The complete program ParticleMotion2D.py is listed below.
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 65

50
angle=30.0, smooth ball
angle=25.0, smooth ball
angle=20.0, smooth ball
40 angle=15.0, smooth ball
angle=30.0, golf ball
angle=25.0, golf ball
30 angle=20.0, golf ball
angle=15.0, golf ball

y [m]
angle=30.0, golf ball (with lift)
angle=25.0, golf ball (with lift)
20 angle=20.0, golf ball (with lift)
angle=15.0, golf ball (with lift)

10

00 50 100 150 200 250


x [m]

Figure 2.19: Motion of golf ball with drag and lift.

# src-ch1/ParticleMotion2D.py;DragCoefficientGeneric.py @ git@lrhgit/tkt4140/src/src-ch1/DragCoeffici

from DragCoefficientGeneric import cd_sphere


from cdclgolfball import cdcl
from matplotlib.pyplot import *
import numpy as np
import odespy

g = 9.81 # Gravity [m/s^2]


nu = 1.5e-5 # Kinematical viscosity [m^2/s]
rho_f = 1.20 # Density of fluid [kg/m^3]
rho_s = 1275 # Density of sphere [kg/m^3]
d = 41.0e-3 # Diameter of the sphere [m]
v0 = 50.0 # Initial velocity [m/s]
vfx = 0.0 # x-component of fluid’s velocity
vfy = 0.0 # y-component of fluid’s velocity
nrpm = 3500 # no of rpm of golf ball

# smooth ball
def f(z, t):
"""4x4 system for smooth sphere with drag in two directions."""
zout = np.zeros_like(z)
C = 3.0*rho_f/(4.0*rho_s*d)
vrx = z[2] - vfx
vry = z[3] - vfy
vr = np.sqrt(vrx**2 + vry**2)
Re = vr*d/nu
CD = cd_sphere(Re) # using the already defined function
zout[:] = [z[2], z[3], -C*vr*(CD*vrx), C*vr*(-CD*vry) - g]
return zout

# golf ball without lift


def f2(z, t):
"""4x4 system for golf ball with drag in two directions."""
zout = np.zeros_like(z)
C = 3.0*rho_f/(4.0*rho_s*d)
vrx = z[2] - vfx
vry = z[3] - vfy
vr = np.sqrt(vrx**2 + vry**2)
Re = vr*d/nu
CD, CL = cdcl(vr, nrpm)
zout[:] = [z[2], z[3], -C*vr*(CD*vrx), C*vr*(-CD*vry) - g]
return zout

# golf ball with lift


CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 66

def f3(z, t):


"""4x4 system for golf ball with drag and lift in two directions."""
zout = np.zeros_like(z)
C = 3.0*rho_f/(4.0*rho_s*d)
vrx = z[2] - vfx
vry = z[3] - vfy
vr = np.sqrt(vrx**2 + vry**2)
Re = vr*d/nu
CD, CL = cdcl(vr, nrpm)
zout[:] = [z[2], z[3], -C*vr*(CD*vrx + CL*vry), C*vr*(CL*vrx - CD*vry) - g]
return zout

# main program starts here

T = 7 # end of simulation
N = 60 # no of time steps
time = np.linspace(0, T, N+1)

N2 = 4
alfa = np.linspace(30, 15, N2) # Angle of elevation [degrees]
angle = alfa*np.pi/180.0 # convert to radians

legends=[]
line_color=[’k’,’m’,’b’,’r’]
figure(figsize=(20, 8))
hold(’on’)
LNWDT=4; FNT=18
rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT

# computing and plotting

# smooth ball with drag


for i in range(0,N2):
z0 = np.zeros(4)
z0[2] = v0*np.cos(angle[i])
z0[3] = v0*np.sin(angle[i])
solver = odespy.RK4(f)
solver.set_initial_condition(z0)
z, t = solver.solve(time)
plot(z[:,0], z[:,1], ’:’, color=line_color[i])
legends.append(’angle=’+str(alfa[i])+’, smooth ball’)

# golf ball with drag


for i in range(0,N2):
z0 = np.zeros(4)
z0[2] = v0*np.cos(angle[i])
z0[3] = v0*np.sin(angle[i])
solver = odespy.RK4(f2)
solver.set_initial_condition(z0)
z, t = solver.solve(time)
plot(z[:,0], z[:,1], ’-.’, color=line_color[i])
legends.append(’angle=’+str(alfa[i])+’, golf ball’)

# golf ball with drag and lift


for i in range(0,N2):
z0 = np.zeros(4)
z0[2] = v0*np.cos(angle[i])
z0[3] = v0*np.sin(angle[i])
solver = odespy.RK4(f3)
solver.set_initial_condition(z0)
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 67

z, t = solver.solve(time)
plot(z[:,0], z[:,1], ’.’, color=line_color[i])
legends.append(’angle=’+str(alfa[i])+’, golf ball (with lift)’)

legend(legends, loc=’best’, frameon=False)


xlabel(’x [m]’)
ylabel(’y [m]’)
axis([0, 250, 0, 50])
#savefig(’example_particle_motion_2d_2.png’, transparent=True)
show()

2.10.3 Example: Numerical error as a function of ∆t for


ODE-schemes
To investigate whether the various ODE-schemes in our module ’ODEschemes.py’
have the expected, theoretical order, we proceed in the same manner as outlined
in (2.7.1). The complete code is listed at the end of this section but we will
highlight and explain some details in the following.
To test the numerical order for the schemes we solve a somewhat general
linear ODE:

u0 (t) = a u + b (2.105)
u(t0 ) = u0

which has the analytical solutions:


(
u0 + ab ea t − ab ,

a 6= 0
u= (2.106)
u0 + b t, a=0

The right hand side defining the differential equation has been implemented in
function f3 and the corresponding analytical solution is computed by u_nonlin_analytical:

—– The basic idea for the convergence test in the function convergence_test is
that we start out by solving numerically an ODE with an analytical solution on
a relatively coarse grid, allowing for direct computations of the error. We then
reduce the timestep by a factor two (or double the grid size), repeatedly, and
compute the error for each grid and compare it with the error of previous grid.
The Euler scheme (2.53) is O(h), whereas the Heun scheme (2.76) is O(h2 ),
and Runge-Kutta (2.94) is O(h4 ), where the h denote a generic step size which
for the current example is the timestep ∆t. The order of a particular scheme is
given exponent n in the error term O(hn ). Consequently, the Euler scheme is a
first oder scheme, Heun is second order, whereas Runge-Kutta is fourth order.
By letting i+1 and i denote the errors on two consecutive grids with
∆ti
corresponding timesteps ∆ti+1 = . The errors i+1 and i for a scheme of
2
order n are then related by:
1
i+1 = n i (2.107)
2
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 68

Consequently, whenever i+1 and i are known from consecutive simulations an


estimate of the order of the scheme may be obtained by:
i
n ≈ log2 (2.108)
i+1

The theoretical value of n is thus n = 1 for Euler’s method, n = 2 for Heun’s


method and n = 4 for RK4.
In the function convergence_test the schemes we will subject to a conver-
gence test is ordered in a list scheme_list. This allows for a convenient loop
over all schemes with the clause: for scheme in scheme_list:. Subsequently,
for each scheme we refine the initial grid (N=30) Ndts times in the loop for i in
range(Ndts+1): and solve and compute the order estimate given by (2.108) with
the clause order_approx.append(previous_max_log_err - max_log_err). Note
that we can not compute this for the first iteration (i=0), and that we use a an
initial empty list order_approx to store the approximation of the order n for
each grid refinement. For each grid we plot log2 () as a function of time with:
plot(time[1:], log_error, linestyles[i]+colors[iclr], markevery=N/5)
and for each plot we construct the corresponding legend by appending a new ele-
ment to the legends-list legends.append(scheme.func_name +’: N = ’ + str(N)).
This construct produces a string with both the scheme name and the number of
elements N . The plot is not reproduced below, but you may see the result by
downloading and running the module yourself.
Having completed the given number of refinements Ndts for a specific scheme
we store the order_approx for the scheme in a dictionary using the name of
the scheme as a key by schemes_orders[scheme.func_name] = order_approx.
This allows for an illustrative plot of the order estimate for each scheme with
the clause:
for key in schemes_orders:
plot(N_list, (np.asarray(schemes_orders[key])))

and the resulting plot is shown in Figure 2.20, and we see that our numerical
approximations for the orders of our schemes approach the theoretical values as
the number of timesteps increase (or as the timestep is reduced by a factor two
consecutively).
The complete function convergence_test is a part of the module ODEschemes
and is isolated below:
def convergence_test():
""" Test convergence rate of the methods """
from numpy import linspace, size, abs, log10, mean, log2
figure()
tol = 1E-15
T = 8.0 # end of simulation
Ndts = 5 # Number of times to refine timestep in convergence test

z0 = 2

schemes =[euler, heun, rk4]


legends=[]
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 69

5
rk4
heun
4
euler

Scheme order approximation


theoretical
3

0
120
240

480

960

192
0
Number of unknowns

Figure 2.20: The convergence rate for the various ODE-solvers a function of
the number of timesteps.

schemes_order={}
colors = [’r’, ’g’, ’b’, ’m’, ’k’, ’y’, ’c’]
linestyles = [’-’, ’--’, ’-.’, ’:’, ’v--’, ’*-.’]
iclr = 0
for scheme in schemes:
N = 30 # no of time steps
time = linspace(0, T, N+1)

order_approx = []

for i in range(Ndts+1):
z = scheme(f3, z0, time)
abs_error = abs(u_nonlin_analytical(z0, time)-z[:,0])
log_error = log2(abs_error[1:]) # Drop 1st elt to avoid log2-problems (1st elt is zer
max_log_err = max(log_error)
plot(time[1:], log_error, linestyles[i]+colors[iclr], markevery=N/5)
legends.append(scheme.func_name +’: N = ’ + str(N))
hold(’on’)

if i > 0: # Compute the log2 error difference


order_approx.append(previous_max_log_err - max_log_err)
previous_max_log_err = max_log_err
N *=2
time = linspace(0, T, N+1)

schemes_order[scheme.func_name] = order_approx
iclr += 1

legend(legends, loc=’best’)
xlabel(’Time’)
ylabel(’log(error)’)
grid()

N = N/2**Ndts
N_list = [N*2**i for i in range(1, Ndts+1)]
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 70

N_list = np.asarray(N_list)
figure()
for key in schemes_order:
plot(N_list, (np.asarray(schemes_order[key])))

# Plot theoretical n for 1st, 2nd and 4th order schemes


axhline(1.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
axhline(2.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
axhline(4.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
xticks(N_list, rotation=-70)
legends = schemes_order.keys()
legends.append(’theoretical’)
legend(legends, loc=’best’, frameon=False)
xlabel(’Number of unknowns’)
ylabel(’Scheme order approximation’)
axis([0, max(N_list), 0, 5])
# savefig(’ConvergenceODEschemes.png’, transparent=True)

def manufactured_solution():
""" Test convergence rate of the methods, by using the Method of Manufactured solutions.
The coefficient function f is chosen to be the normal distribution
f = (1/(sigma*sqrt(2*pi)))*exp(-((t-mu)**2)/(2*sigma**2)).
The ODE to be solved is than chosen to be: f’’’ + f’’*f + f’ = RHS,
leading to to f’’’ = RHS - f’’*f - f
"""
from numpy import linspace, size, abs, log10, mean, log2
from sympy import exp, symbols, diff, lambdify
from math import sqrt, pi

print "solving equation f’’’ + f’’*f + f’ = RHS"


print "which lead to f’’’ = RHS - f’’*f - f"
t = symbols(’t’)
sigma=0.5 # standard deviation
mu=0.5 # mean value
Domain=[-1.5, 2.5]
t0 = Domain[0]
tend = Domain[1]

f = (1/(sigma*sqrt(2*pi)))*exp(-((t-mu)**2)/(2*sigma**2))
dfdt = diff(f, t)
d2fdt = diff(dfdt, t)
d3fdt = diff(d2fdt, t)
RHS = d3fdt + dfdt*d2fdt + f
f = lambdify([t], f)
dfdt = lambdify([t], dfdt)
d2fdt = lambdify([t], d2fdt)
RHS = lambdify([t], RHS)

def func(y,t):
yout = np.zeros_like(y)
yout[:] = [y[1], y[2], RHS(t) -y[0]- y[1]*y[2]]

return yout
z0 = np.array([f(t0), dfdt(t0), d2fdt(t0)])

figure()
tol = 1E-15
Ndts = 5 # Number of times to refine timestep in convergence test
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 71

schemes =[euler, heun, rk4]


legends=[]
schemes_order={}

colors = [’r’, ’g’, ’b’, ’m’, ’k’, ’y’, ’c’]


linestyles = [’-’, ’--’, ’-.’, ’:’, ’v--’, ’*-.’]
iclr = 0
for scheme in schemes:
N = 100 # no of time steps
time = linspace(t0, tend, N+1)
fanalytic = np.zeros_like(time)
k = 0
for tau in time:
fanalytic[k] = f(tau)
k = k + 1

order_approx = []
for i in range(Ndts+1):
z = scheme(func, z0, time)
abs_error = abs(fanalytic-z[:,0])
log_error = log2(abs_error[1:]) # Drop 1st elt to avoid log2-problems (1st elt is zer
max_log_err = max(log_error)
plot(time[1:], log_error, linestyles[i]+colors[iclr], markevery=N/5)
legends.append(scheme.func_name +’: N = ’ + str(N))
hold(’on’)

if i > 0: # Compute the log2 error difference


order_approx.append(previous_max_log_err - max_log_err)
previous_max_log_err = max_log_err

N *=2
time = linspace(t0, tend, N+1)
fanalytic = np.zeros_like(time)
k = 0
for tau in time:
fanalytic[k] = f(tau)
k = k + 1

schemes_order[scheme.func_name] = order_approx
iclr += 1

legend(legends, loc=’best’)
xlabel(’Time’)
ylabel(’log(error)’)
grid()

N = N/2**Ndts
N_list = [N*2**i for i in range(1, Ndts+1)]
N_list = np.asarray(N_list)

figure()
for key in schemes_order:
plot(N_list, (np.asarray(schemes_order[key])))

# Plot theoretical n for 1st, 2nd and 4th order schemes


axhline(1.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
axhline(2.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
axhline(4.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
xticks(N_list, rotation=-70)
legends = schemes_order.keys()
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 72

legends.append(’theoretical’)
legend(legends, loc=’best’, frameon=False)
title(’Method of Manufactured Solution’)
xlabel(’Number of unknowns’)
ylabel(’Scheme order approximation’)
axis([0, max(N_list), 0, 5])
# savefig(’MMSODEschemes.png’, transparent=True)
# test using MMS and solving a set of two nonlinear equations to find estimate of order
def manufactured_solution_Nonlinear():
""" Test convergence rate of the methods, by using the Method of Manufactured solutions.
The coefficient function f is chosen to be the normal distribution
f = (1/(sigma*sqrt(2*pi)))*exp(-((t-mu)**2)/(2*sigma**2)).
The ODE to be solved is than chosen to be: f’’’ + f’’*f + f’ = RHS,
leading to f’’’ = RHS - f’’*f - f
"""
from numpy import linspace, abs
from sympy import exp, symbols, diff, lambdify
from math import sqrt, pi
from numpy import log, log2

t = symbols(’t’)
sigma= 0.5 # standard deviation
mu = 0.5 # mean value
#### Perform needed differentiations based on the differential equation ####
f = (1/(sigma*sqrt(2*pi)))*exp(-((t-mu)**2)/(2*sigma**2))
dfdt = diff(f, t)
d2fdt = diff(dfdt, t)
d3fdt = diff(d2fdt, t)
RHS = d3fdt + dfdt*d2fdt + f
#### Create Python functions of f, RHS and needed differentiations of f ####
f = lambdify([t], f, np)
dfdt = lambdify([t], dfdt, np)
d2fdt = lambdify([t], d2fdt)
RHS = lambdify([t], RHS)

def func(y,t):
""" Function that returns the dfn/dt of the differential equation f + f’’*f + f’’’ = RHS
as a system of 1st order equations; f = f1
f1’ = f2
f2’ = f3
f3’ = RHS - f1 - f2*f3

Args:
y(array): solutian array [f1, f2, f3] at time t
t(float): current time

Returns:
yout(array): differantiation array [f1’, f2’, f3’] at time t
"""
yout = np.zeros_like(y)
yout[:] = [y[1], y[2], RHS(t) -y[0]- y[1]*y[2]]

return yout

t0, tend = -1.5, 2.5


z0 = np.array([f(t0), dfdt(t0), d2fdt(t0)]) # initial values

schemes = [euler, heun, rk4] # list of schemes; each of which is a function


schemes_error = {} # empty dictionary. to be filled in with lists of error-norms for all sche
h = [] # empty list of time step
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 73

Ntds = 4 # number of times to refine dt


fig, ax = subplots(1, len(schemes), sharey = True, squeeze=False)

for k, scheme in enumerate(schemes):


N = 20 # initial number of time steps
error = [] # start of with empty list of errors for all schemes
legendList = []

for i in range(Ntds + 1):


time = linspace(t0, tend, N+1)

if k==0:
h.append(time[1] - time[0]) # add this iteration’s dt to list h
z = scheme(func, z0, time) # Solve the ODE by calling the scheme with arguments. e.g:
fanalytic = f(time) # call analytic function f to compute analytical solutions at tim

abs_error = abs(z[:,0]- fanalytic) # calculate infinity norm of the error


error.append(max(abs_error))

ax[0][k].plot(time, z[:,0])
legendList.append(’$h$ = ’ + str(h[i]))

N *=2 # refine dt

schemes_error[scheme.func_name] = error # Add a key:value pair to the dictionary. e.g: "e

ax[0][k].plot(time, fanalytic, ’k:’)


legendList.append(’$u_m$’)
ax[0][k].set_title(scheme.func_name)
ax[0][k].set_xlabel(’time’)

ax[0][2].legend(legendList, loc = ’best’, frameon=False)


ax[0][0].set_ylabel(’u’)
setp(ax, xticks=[-1.5, 0.5, 2.5], yticks=[0.0, 0.4 , 0.8, 1.2])
# #savefig(’../figs/normal_distribution_refinement.png’)
def Newton_solver_sympy(error, h, x0):
""" Function that solves for the nonlinear set of equations
error1 = C*h1^p --> f1 = C*h1^p - error1 = 0
error2 = C*h2^p --> f2 = C h2^p - error 2 = 0
where C is a constant h is the step length and p is the order,
with use of a newton rhapson solver. In this case C and p are
the unknowns, whereas h and error are knowns. The newton rhapson
method is an iterative solver which take the form:
xnew = xold - (J^-1)*F, where J is the Jacobi matrix and F is the
residual funcion.
x = [C, p]^T
J = [[df1/dx1 df2/dx2],
[df2/dx1 df2/dx2]]
F = [f1, f2]
This is very neatly done with use of the sympy module

Args:
error(list): list of calculated errors [error(h1), error(h2)]
h(list): list of steplengths corresponding to the list of errors
x0(list): list of starting (guessed) values for x

Returns:
x(array): iterated solution of x = [C, p]
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 74

"""
from sympy import Matrix
#### Symbolic computiations: ####
C, p = symbols(’C p’)
f1 = C*h[-2]**p - error[-2]
f2 = C*h[-1]**p - error[-1]
F = [f1, f2]
x = [C, p]
def jacobiElement(i,j):
return diff(F[i], x[j])
Jacobi = Matrix(2, 2, jacobiElement) # neat way of computing the Jacobi Matrix
JacobiInv = Jacobi.inv()
#### Numerical computations: ####
JacobiInvfunc = lambdify([x], JacobiInv)
Ffunc = lambdify([x], F)
x = x0

for n in range(8): #perform 8 iterations


F = np.asarray(Ffunc(x))
Jinv = np.asarray(JacobiInvfunc(x))
xnew = x - np.dot(Jinv, F)
x = xnew
#print "n, x: ", n, x
x[0] = round(x[0], 2)
x[1] = round(x[1], 3)
return x

ht = np.asarray(h)
eulerError = np.asarray(schemes_error["euler"])
heunError = np.asarray(schemes_error["heun"])
rk4Error = np.asarray(schemes_error["rk4"])

[C_euler, p_euler] = Newton_solver_sympy(eulerError, ht, [1,1])


[C_heun, p_heun] = Newton_solver_sympy(heunError, ht, [1,2])
[C_rk4, p_rk4] = Newton_solver_sympy(rk4Error, ht, [1,4])

from sympy import latex


h = symbols(’h’)
epsilon_euler = C_euler*h**p_euler
epsilon_euler_latex = ’$’ + latex(epsilon_euler) + ’$’
epsilon_heun = C_heun*h**p_heun
epsilon_heun_latex = ’$’ + latex(epsilon_heun) + ’$’
epsilon_rk4 = C_rk4*h**p_rk4
epsilon_rk4_latex = ’$’ + latex(epsilon_rk4) + ’$’

print epsilon_euler_latex
print epsilon_heun_latex
print epsilon_rk4_latex
epsilon_euler = lambdify(h, epsilon_euler, np)
epsilon_heun = lambdify(h, epsilon_heun, np)
epsilon_rk4 = lambdify(h, epsilon_rk4, np)

N = N/2**(Ntds + 2)
N_list = [N*2**i for i in range(1, Ntds + 2)]
N_list = np.asarray(N_list)
print len(N_list)
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 75

print len(eulerError)
figure()
plot(N_list, log2(eulerError), ’b’)
plot(N_list, log2(epsilon_euler(ht)), ’b--’)
plot(N_list, log2(heunError), ’g’)
plot(N_list, log2(epsilon_heun(ht)), ’g--’)
plot(N_list, log2(rk4Error), ’r’)
plot(N_list, log2(epsilon_rk4(ht)), ’r--’)
LegendList = [’${\epsilon}_{euler}$’, epsilon_euler_latex, ’${\epsilon}_{heun}$’, epsilon_heu
legend(LegendList, loc=’best’, frameon=False)
xlabel(’-log(h)’)
ylabel(’-log($\epsilon$)’)
# #savefig(’../figs/MMS_example2.png’)

The complete module ODEschemes is listed below and may easily be down-
loaded in your Eclipse/LiClipse IDE:
# src-ch1/ODEschemes.py

import numpy as np
from matplotlib.pyplot import plot, show, legend, hold,rcParams,rc, figure, axhline, close,\
xticks, title, xlabel, ylabel, savefig, axis, grid, subplots, setp

# change some default values to make plots more readable


LNWDT=3; FNT=10
rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT

# define Euler solver


def euler(func, z0, time):
"""The Euler scheme for solution of systems of ODEs.
z0 is a vector for the initial conditions,
the right hand side of the system is represented by func which returns
a vector with the same size as z0 ."""

z = np.zeros((np.size(time), np.size(z0)))
z[0,:] = z0

for i in range(len(time)-1):
dt = time[i+1] - time[i]
z[i+1,:]=z[i,:] + np.asarray(func(z[i,:], time[i]))*dt
return z

# define Heun solver


def heun(func, z0, time):
"""The Heun scheme for solution of systems of ODEs.
z0 is a vector for the initial conditions,
the right hand side of the system is represented by func which returns
a vector with the same size as z0 ."""

z = np.zeros((np.size(time), np.size(z0)))
z[0,:] = z0
zp = np.zeros_like(z0)

for i, t in enumerate(time[0:-1]):
dt = time[i+1] - time[i]
zp = z[i,:] + np.asarray(func(z[i,:],t))*dt # Predictor step
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 76

z[i+1,:] = z[i,:] + (np.asarray(func(z[i,:],t)) + np.asarray(func(zp,t+dt)))*dt/2.0 # Correct


return z

# define rk4 scheme


def rk4(func, z0, time):
"""The Runge-Kutta 4 scheme for solution of systems of ODEs.
z0 is a vector for the initial conditions,
the right hand side of the system is represented by func which returns
a vector with the same size as z0 ."""

z = np.zeros((np.size(time),np.size(z0)))
z[0,:] = z0
zp = np.zeros_like(z0)

for i, t in enumerate(time[0:-1]):
dt = time[i+1] - time[i]
dt2 = dt/2.0
k1 = np.asarray(func(z[i,:], t)) # predictor step 1
k2 = np.asarray(func(z[i,:] + k1*dt2, t + dt2)) # predictor step 2
k3 = np.asarray(func(z[i,:] + k2*dt2, t + dt2)) # predictor step 3
k4 = np.asarray(func(z[i,:] + k3*dt, t + dt)) # predictor step 4
z[i+1,:] = z[i,:] + dt/6.0*(k1 + 2.0*k2 + 2.0*k3 + k4) # Corrector step

return z

if __name__ == ’__main__’:
a = 0.2
b = 3.0
u_exact = lambda t: a*t + b

def f_local(u,t):
"""A function which returns an np.array but less easy to read
than f(z,t) below. """
return np.asarray([a + (u - u_exact(t))**5])

def f(z, t):


"""Simple to read function implementation """
return [a + (z - u_exact(t))**5]

def test_ODEschemes():
"""Use knowledge of an exact numerical solution for testing."""
from numpy import linspace, size

tol = 1E-15
T = 2.0 # end of simulation
N = 20 # no of time steps
time = linspace(0, T, N+1)

z0 = np.zeros(1)
z0[0] = u_exact(0.0)

schemes = [euler, heun, rk4]


for scheme in schemes:
z = scheme(f, z0, time)
max_error = np.max(u_exact(time) - z[:,0])
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 77

msg = ’%s failed with error = %g’ % (scheme.func_name, max_error)


assert max_error < tol, msg

# f3 defines an ODE with ananlytical solution in u_nonlin_analytical


def f3(z, t, a=2.0, b=-1.0):
""" """
return a*z + b

def u_nonlin_analytical(u0, t, a=2.0, b=-1.0):


from numpy import exp
TOL = 1E-14
if (abs(a)>TOL):
return (u0 + b/a)*exp(a*t)-b/a
else:
return u0 + b*t

# Function for convergence test


def convergence_test():
""" Test convergence rate of the methods """
from numpy import linspace, size, abs, log10, mean, log2
figure()
tol = 1E-15
T = 8.0 # end of simulation
Ndts = 5 # Number of times to refine timestep in convergence test
z0 = 2

schemes =[euler, heun, rk4]


legends=[]
schemes_order={}

colors = [’r’, ’g’, ’b’, ’m’, ’k’, ’y’, ’c’]


linestyles = [’-’, ’--’, ’-.’, ’:’, ’v--’, ’*-.’]
iclr = 0
for scheme in schemes:
N = 30 # no of time steps
time = linspace(0, T, N+1)

order_approx = []

for i in range(Ndts+1):
z = scheme(f3, z0, time)
abs_error = abs(u_nonlin_analytical(z0, time)-z[:,0])
log_error = log2(abs_error[1:]) # Drop 1st elt to avoid log2-problems (1st elt is zer
max_log_err = max(log_error)
plot(time[1:], log_error, linestyles[i]+colors[iclr], markevery=N/5)
legends.append(scheme.func_name +’: N = ’ + str(N))
hold(’on’)

if i > 0: # Compute the log2 error difference


order_approx.append(previous_max_log_err - max_log_err)
previous_max_log_err = max_log_err

N *=2
time = linspace(0, T, N+1)

schemes_order[scheme.func_name] = order_approx
iclr += 1

legend(legends, loc=’best’)
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 78

xlabel(’Time’)
ylabel(’log(error)’)
grid()

N = N/2**Ndts
N_list = [N*2**i for i in range(1, Ndts+1)]
N_list = np.asarray(N_list)

figure()
for key in schemes_order:
plot(N_list, (np.asarray(schemes_order[key])))

# Plot theoretical n for 1st, 2nd and 4th order schemes


axhline(1.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
axhline(2.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
axhline(4.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
xticks(N_list, rotation=-70)
legends = schemes_order.keys()
legends.append(’theoretical’)
legend(legends, loc=’best’, frameon=False)
xlabel(’Number of unknowns’)
ylabel(’Scheme order approximation’)
axis([0, max(N_list), 0, 5])
# savefig(’ConvergenceODEschemes.png’, transparent=True)

def manufactured_solution():
""" Test convergence rate of the methods, by using the Method of Manufactured solutions.
The coefficient function f is chosen to be the normal distribution
f = (1/(sigma*sqrt(2*pi)))*exp(-((t-mu)**2)/(2*sigma**2)).
The ODE to be solved is than chosen to be: f’’’ + f’’*f + f’ = RHS,
leading to to f’’’ = RHS - f’’*f - f
"""
from numpy import linspace, size, abs, log10, mean, log2
from sympy import exp, symbols, diff, lambdify
from math import sqrt, pi

print "solving equation f’’’ + f’’*f + f’ = RHS"


print "which lead to f’’’ = RHS - f’’*f - f"
t = symbols(’t’)
sigma=0.5 # standard deviation
mu=0.5 # mean value
Domain=[-1.5, 2.5]
t0 = Domain[0]
tend = Domain[1]
f = (1/(sigma*sqrt(2*pi)))*exp(-((t-mu)**2)/(2*sigma**2))
dfdt = diff(f, t)
d2fdt = diff(dfdt, t)
d3fdt = diff(d2fdt, t)
RHS = d3fdt + dfdt*d2fdt + f

f = lambdify([t], f)
dfdt = lambdify([t], dfdt)
d2fdt = lambdify([t], d2fdt)
RHS = lambdify([t], RHS)
def func(y,t):
yout = np.zeros_like(y)
yout[:] = [y[1], y[2], RHS(t) -y[0]- y[1]*y[2]]

return yout
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 79

z0 = np.array([f(t0), dfdt(t0), d2fdt(t0)])

figure()
tol = 1E-15
Ndts = 5 # Number of times to refine timestep in convergence test
schemes =[euler, heun, rk4]
legends=[]
schemes_order={}
colors = [’r’, ’g’, ’b’, ’m’, ’k’, ’y’, ’c’]
linestyles = [’-’, ’--’, ’-.’, ’:’, ’v--’, ’*-.’]
iclr = 0
for scheme in schemes:
N = 100 # no of time steps
time = linspace(t0, tend, N+1)
fanalytic = np.zeros_like(time)
k = 0
for tau in time:
fanalytic[k] = f(tau)
k = k + 1

order_approx = []

for i in range(Ndts+1):
z = scheme(func, z0, time)
abs_error = abs(fanalytic-z[:,0])
log_error = log2(abs_error[1:]) # Drop 1st elt to avoid log2-problems (1st elt is zer
max_log_err = max(log_error)
plot(time[1:], log_error, linestyles[i]+colors[iclr], markevery=N/5)
legends.append(scheme.func_name +’: N = ’ + str(N))
hold(’on’)

if i > 0: # Compute the log2 error difference


order_approx.append(previous_max_log_err - max_log_err)
previous_max_log_err = max_log_err
N *=2
time = linspace(t0, tend, N+1)
fanalytic = np.zeros_like(time)
k = 0
for tau in time:
fanalytic[k] = f(tau)
k = k + 1
schemes_order[scheme.func_name] = order_approx
iclr += 1

legend(legends, loc=’best’)
xlabel(’Time’)
ylabel(’log(error)’)
grid()
N = N/2**Ndts
N_list = [N*2**i for i in range(1, Ndts+1)]
N_list = np.asarray(N_list)

figure()
for key in schemes_order:
plot(N_list, (np.asarray(schemes_order[key])))
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 80

# Plot theoretical n for 1st, 2nd and 4th order schemes


axhline(1.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
axhline(2.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
axhline(4.0, xmin=0, xmax=N, linestyle=’:’, color=’k’)
xticks(N_list, rotation=-70)
legends = schemes_order.keys()
legends.append(’theoretical’)
legend(legends, loc=’best’, frameon=False)
title(’Method of Manufactured Solution’)
xlabel(’Number of unknowns’)
ylabel(’Scheme order approximation’)
axis([0, max(N_list), 0, 5])
# savefig(’MMSODEschemes.png’, transparent=True)
# test using MMS and solving a set of two nonlinear equations to find estimate of order
def manufactured_solution_Nonlinear():
""" Test convergence rate of the methods, by using the Method of Manufactured solutions.
The coefficient function f is chosen to be the normal distribution
f = (1/(sigma*sqrt(2*pi)))*exp(-((t-mu)**2)/(2*sigma**2)).
The ODE to be solved is than chosen to be: f’’’ + f’’*f + f’ = RHS,
leading to f’’’ = RHS - f’’*f - f
"""
from numpy import linspace, abs
from sympy import exp, symbols, diff, lambdify
from math import sqrt, pi
from numpy import log, log2
t = symbols(’t’)
sigma= 0.5 # standard deviation
mu = 0.5 # mean value
#### Perform needed differentiations based on the differential equation ####
f = (1/(sigma*sqrt(2*pi)))*exp(-((t-mu)**2)/(2*sigma**2))
dfdt = diff(f, t)
d2fdt = diff(dfdt, t)
d3fdt = diff(d2fdt, t)
RHS = d3fdt + dfdt*d2fdt + f
#### Create Python functions of f, RHS and needed differentiations of f ####
f = lambdify([t], f, np)
dfdt = lambdify([t], dfdt, np)
d2fdt = lambdify([t], d2fdt)
RHS = lambdify([t], RHS)

def func(y,t):
""" Function that returns the dfn/dt of the differential equation f + f’’*f + f’’’ = RHS
as a system of 1st order equations; f = f1
f1’ = f2
f2’ = f3
f3’ = RHS - f1 - f2*f3
Args:
y(array): solutian array [f1, f2, f3] at time t
t(float): current time

Returns:
yout(array): differantiation array [f1’, f2’, f3’] at time t
"""
yout = np.zeros_like(y)
yout[:] = [y[1], y[2], RHS(t) -y[0]- y[1]*y[2]]

return yout

t0, tend = -1.5, 2.5


CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 81

z0 = np.array([f(t0), dfdt(t0), d2fdt(t0)]) # initial values


schemes = [euler, heun, rk4] # list of schemes; each of which is a function
schemes_error = {} # empty dictionary. to be filled in with lists of error-norms for all sche
h = [] # empty list of time step

Ntds = 4 # number of times to refine dt

fig, ax = subplots(1, len(schemes), sharey = True, squeeze=False)


for k, scheme in enumerate(schemes):
N = 20 # initial number of time steps
error = [] # start of with empty list of errors for all schemes
legendList = []

for i in range(Ntds + 1):


time = linspace(t0, tend, N+1)
if k==0:
h.append(time[1] - time[0]) # add this iteration’s dt to list h
z = scheme(func, z0, time) # Solve the ODE by calling the scheme with arguments. e.g:
fanalytic = f(time) # call analytic function f to compute analytical solutions at tim

abs_error = abs(z[:,0]- fanalytic) # calculate infinity norm of the error


error.append(max(abs_error))
ax[0][k].plot(time, z[:,0])
legendList.append(’$h$ = ’ + str(h[i]))
N *=2 # refine dt

schemes_error[scheme.func_name] = error # Add a key:value pair to the dictionary. e.g: "e

ax[0][k].plot(time, fanalytic, ’k:’)


legendList.append(’$u_m$’)
ax[0][k].set_title(scheme.func_name)
ax[0][k].set_xlabel(’time’)

ax[0][2].legend(legendList, loc = ’best’, frameon=False)


ax[0][0].set_ylabel(’u’)
setp(ax, xticks=[-1.5, 0.5, 2.5], yticks=[0.0, 0.4 , 0.8, 1.2])

# #savefig(’../figs/normal_distribution_refinement.png’)
def Newton_solver_sympy(error, h, x0):
""" Function that solves for the nonlinear set of equations
error1 = C*h1^p --> f1 = C*h1^p - error1 = 0
error2 = C*h2^p --> f2 = C h2^p - error 2 = 0
where C is a constant h is the step length and p is the order,
with use of a newton rhapson solver. In this case C and p are
the unknowns, whereas h and error are knowns. The newton rhapson
method is an iterative solver which take the form:
xnew = xold - (J^-1)*F, where J is the Jacobi matrix and F is the
residual funcion.
x = [C, p]^T
J = [[df1/dx1 df2/dx2],
[df2/dx1 df2/dx2]]
F = [f1, f2]
This is very neatly done with use of the sympy module

Args:
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 82

error(list): list of calculated errors [error(h1), error(h2)]


h(list): list of steplengths corresponding to the list of errors
x0(list): list of starting (guessed) values for x

Returns:
x(array): iterated solution of x = [C, p]

"""
from sympy import Matrix
#### Symbolic computiations: ####
C, p = symbols(’C p’)
f1 = C*h[-2]**p - error[-2]
f2 = C*h[-1]**p - error[-1]
F = [f1, f2]
x = [C, p]

def jacobiElement(i,j):
return diff(F[i], x[j])

Jacobi = Matrix(2, 2, jacobiElement) # neat way of computing the Jacobi Matrix


JacobiInv = Jacobi.inv()
#### Numerical computations: ####
JacobiInvfunc = lambdify([x], JacobiInv)
Ffunc = lambdify([x], F)
x = x0
for n in range(8): #perform 8 iterations
F = np.asarray(Ffunc(x))
Jinv = np.asarray(JacobiInvfunc(x))
xnew = x - np.dot(Jinv, F)
x = xnew
#print "n, x: ", n, x
x[0] = round(x[0], 2)
x[1] = round(x[1], 3)
return x

ht = np.asarray(h)
eulerError = np.asarray(schemes_error["euler"])
heunError = np.asarray(schemes_error["heun"])
rk4Error = np.asarray(schemes_error["rk4"])

[C_euler, p_euler] = Newton_solver_sympy(eulerError, ht, [1,1])


[C_heun, p_heun] = Newton_solver_sympy(heunError, ht, [1,2])
[C_rk4, p_rk4] = Newton_solver_sympy(rk4Error, ht, [1,4])

from sympy import latex


h = symbols(’h’)
epsilon_euler = C_euler*h**p_euler
epsilon_euler_latex = ’$’ + latex(epsilon_euler) + ’$’
epsilon_heun = C_heun*h**p_heun
epsilon_heun_latex = ’$’ + latex(epsilon_heun) + ’$’
epsilon_rk4 = C_rk4*h**p_rk4
epsilon_rk4_latex = ’$’ + latex(epsilon_rk4) + ’$’

print epsilon_euler_latex
print epsilon_heun_latex
print epsilon_rk4_latex

epsilon_euler = lambdify(h, epsilon_euler, np)


epsilon_heun = lambdify(h, epsilon_heun, np)
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 83

epsilon_rk4 = lambdify(h, epsilon_rk4, np)


N = N/2**(Ntds + 2)
N_list = [N*2**i for i in range(1, Ntds + 2)]
N_list = np.asarray(N_list)
print len(N_list)
print len(eulerError)
figure()
plot(N_list, log2(eulerError), ’b’)
plot(N_list, log2(epsilon_euler(ht)), ’b--’)
plot(N_list, log2(heunError), ’g’)
plot(N_list, log2(epsilon_heun(ht)), ’g--’)
plot(N_list, log2(rk4Error), ’r’)
plot(N_list, log2(epsilon_rk4(ht)), ’r--’)
LegendList = [’${\epsilon}_{euler}$’, epsilon_euler_latex, ’${\epsilon}_{heun}$’, epsilon_heu
legend(LegendList, loc=’best’, frameon=False)
xlabel(’-log(h)’)
ylabel(’-log($\epsilon$)’)

# #savefig(’../figs/MMS_example2.png’)

def plot_ODEschemes_solutions():
"""Plot the solutions for the test schemes in schemes"""
from numpy import linspace
figure()
T = 1.5 # end of simulation
N = 50 # no of time steps
time = linspace(0, T, N+1)

z0 = 2.0

schemes = [euler, heun, rk4]


legends = []

for scheme in schemes:


z = scheme(f3, z0, time)
plot(time, z[:,-1])
legends.append(scheme.func_name)

plot(time, u_nonlin_analytical(z0, time))


legends.append(’analytical’)
legend(legends, loc=’best’, frameon=False)

manufactured_solution_Nonlinear()
#test_ODEschemes()
#convergence_test()
#plot_ODEschemes_solutions()
#manufactured_solution()
show()

2.11 Stability of explicit RK-methods


To investigate stability for explicity RK-methods for the solution of intital value
ODEs on the generic form (2.1), let us consider the following model problem:
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 84

y 0 (x) = λ · y(x) (2.109)


y(0) = 1 (2.110)
which has the analytical solution:

y(x) = eλx , λ er en konstant (2.111)


The solution y(x) of (2.109) is illustrated in Figure 2.21 for positive (λ = 1)
and negative (λ = −2) growth factors.

3.0
=1
2.5 = -2

2.0
x

1.5
e

1.0

0.5

0.0
0.0 0.2 0.4 0.6 0.8 1.0
x

Figure 2.21: Solution of ODE for exponential growth with positive and negative
growth factor λ.

We illustrate the stability concept for the numerical solution of ODEs by two
examples below, namely, the Euler scheme and the Heun scheme. In the latter
example we will also allude to how the analysis may be applied for higher order
RK-methods.

2.11.1 Example: Stability of Euler’s method


By applying the generic 2.5 On our particular model problem given by (2.109)
we obtain the following generic scheme:

yn+1 = (1 + λh) yn , h = ∆x, n = 0, 1, 2, . . . (2.112)


The numerical soltion yn at the n-th iteration may be related with the initial
solution y0 by applying the scheme (2.112) iteratively:
y1 = (1 + λh) y0
y2 = (1 + λh) y1 = (1 + λh)2 y0
..
.
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 85

which yields:
yn = (1 + λh)n y0 , n = 1, 2, 3, . . . (2.113)
To investigate stability we first introduce the analytic amplification factor
Ga as
y(xn+1 )
Ga = (2.114)
y(xn )
Note that y(xn ) represents the analytical solution of (2.109) at xn , whereas
yn denotes the numerical approximation. For the model problem at hand we see
that Ga reduces to:

y(xn+1 )
Ga = = exp[λ(xn+1 − xn )] = eλh = 1 + λh + (λh)2 /2 . . . (2.115)
y(xn )
Exponential growth λ > 0.
Consider first the case of a positive λ > 0, corresponding to an exponential
growth, as given by (2.111). We observe that our scheme will also exhibit
exponential growth (2.114), and will thus have no concerns in terms of stability.
Naturally, the choice of h will affect the accuracy and numerical error of the
solution.
Exponential decay λ < 0.
In case of exponential decay with a negative λ < 0, we adopt the following
convention for convenience:
λ = −α, α>0 (2.116)
and (2.113) may be recasted to:
yn = (1 − αh)n y0 (2.117)
If yn is to decrease as n increases we must have
|1 − αh| < 1 ⇒ −1 < 1 − αh < 1 (2.118)
which yields the following criterion for selection of h:
0 < αh < 2, α > 0 (2.119)
The criterion may also be formulated by introducing the numerical amplifica-
tion factor G as:

yn+1
G= (2.120)
yn
which for the current example (2.112) reduces to:

yn+1
G= = 1 + λh = 1 − αh (2.121)
yn
For the current example G > 1 for λ > 0 and G < 1 for λ < 0. Compare with
the expression for the analytical amplification factor Ga (2.115).
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 86

A-stable The numerical scheme is absolutely stable (A-stable) when:

|G| < 1 (2.122)

For example when α = 100 we must choose h < 0.02 to produce an A-stable
numerical solution.
By the introduction of the G in (2.121) we may rewrite (2.113) as:

yn = Gn y0 , n = 0, 1, 2, . . . (2.123)

From (2.123) we observe that an A-stable, exponantially decaying solution


(λ < 0 ) the solution will oscillate if G < 0, as Gn < 0 when n is odd and Gn > 0
when n is even. As this behavior is qualitatively different from the behaviour of
the analytical solution, we will seek to avoid such behavior.
The Euler scheme is A-stable for our model equation when

0 < αh < 2, α > 0 (2.124)

but oscillations will occur when

1 < αh < 2, α > 0 (2.125)

Consequently, the Euler scheme will be A-stable and free of spurious oscilla-
tions when

0 < αh < 1, α>0 (2.126)

For example the numerical solution with α = 10 will be stable in the intervall
0 < h < 0.2, but exhibit oscillations in the interval 0.1 < h < 0.2. Note, however,
that the latter restriction on avoiding spurious oscillations will not be of major
concerns in pratice, as the demand for descent accuracy will dictate a far smaller
h.

2.11.2 Example: Stability of Heun’s method


In this example we will analyze the stability of 2.8 when applied on our model
ODE (2.109) with λ = −α, α > 0.
The predictor step reduces to:
p
yn+1 = yn + h · fn = (1 − αh) · yn (2.127)
p
for convenience the predictor yn+1 may be eliminated in the corrector step:

h p 1
yn+1 = yn + · (f + fn+1 ) = 1 − αh + (αh)2 (2.128)
2 2
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 87

which shows that Heun’s method may be represented as a one-step method


for this particular and simple model problem. From (2.128) we find the numerical
amplification factor G (ref<eq:1618a);
yn+1 1
G= = 1 − αh + (αh)2 (2.129)
yn 2
Our taks is now to investigate for which values of αh the condition of for
A-stability (2.122) may be satisfied.
First, we may realize that (2.129) is a second order polynomial in αh and
that G = 1 for αh = 0 and αh = 2. The numerical amplification factor has an
extremum where:
dG
= αh − 1 = 0 ⇒ αh = 1
dαh
and since
d2 G
>0
d(αh)2
this extremum is a minimum and Gmin = G(αh = 1) = 1/2. Consequently we
may conclude that 2.8 will be A-stable for (2.109) in the following αh-range
(stability range):

0 < αh < 2 (2.130)


Note that this condition is the same as for the 2.11.1 above, but as G > 0
always, the scheme will not produce spurious oscillations.
The 2.5 and 2.8 are RK-methods of first and second order, respectively. Even
though the αh-range was not expanded by using a RK-method of 2 order, the
quality of the numerical predictions were improved as spurios oscillations will
vanish.

2.11.3 Stability of higher order RK-methods


A natural questions to raise is whether the stability range may be expanded for
higher order RK-methods, so let us now investigate their the stability range.
The analytical solution of our model ODE (2.109) is:

(λx)2 (λx)3 (λx)n


y(x) = eλx = 1 + λx + + + ··· + + ··· (2.131)
2! 3! n!
By substitution of λx with λh, we get the solution of the difference equation
corresponding to Euler’s method (RK1) with the two first terms, Heun’s method
(RK2) the three first terms RK3 the four first terms, and finally RK4 with the
first five terms:

(λh)2 (λh)3 (λh)n


G = 1 + λh + + + ··· + , n = 1, 2, . . . , (2.132)
2! 3! n!
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 88

We focus on decaying solutions with λ < 0 and we have previously show from
(2.119) that 0 < αh < 2, α > 2 or:

−2 < λh < 0 (2.133)


for RK1 and RK3, but what about RK3? In this case:

(λh)2 (λh)3
G = 1 + λh + + (2.134)
2! 3!
The limiting values for the G-polynomial are found for G = ±1 which for
real roots are:
−2.5127 < λh < 0 (2.135)
For RK4 we get correspondingly

(λh)2 (λh)3 (λh)4


G = 1 + λh + + + (2.136)
2! 3! 4!
which for G = 1 has the real roots:

−2.7853 < λh < 0 (2.137)


In conclusion, we may argue that with respect to stability there is not much
to gain by increasing the order for RK-methods. We have assumed λ to be real
in the above analysis. However, λ may me complex for higer order ODEs and
for systems of first order ODEs. If complex roots are included the regions of
stability for RK-methods become as illstrated in figure 2.22.
Naturally, we want numerical schemes which are stable in the whole left
half-plane. Such a scheme would be denoted strictly absolutely stable or simply
L-stable (where L alludes to left half-plane). Regretfully, there are no existing,
explicit methods which are L-stable. For L-stable methods one has to restort to
implicit methods which are to be discussed in 2.11.3.

Stiff equations.
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 89

3 RK4

RK3
2
RK2
imaginary part of h

1 RK1

−1

−2

−3
−3 −2 −1 0 1 2 3
real part of h

Figure 2.22: Regions of stability for RK-methods order 1-4 for complex roots.

2.12 Exercises
Exercise 1: Solving Newton’s first differential equation us-
ing euler’s method
One of the earliest known differential equations, which Newton solved with series
expansion in 1671 is:

y 0 (x) = 1 − 3x + y + x2 + xy, y(0) = 0 (2.138)

Newton gave the following solution:


x3 x4 x5 x6
y(x) ≈ x − x2 + − + − (2.139)
3 6 30 45
Today it is possible to give the solution on closed form with known functions
as follows,
 √  √ 


h  x i 2 2 h  x i
y(x) =3 2πe · exp x 1 + · erf (1 + x) − erf + 4 · 1 − exp[x 1 + −x
2 2 2 2
(2.140)

Note the combination 2πe.
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 90

a) Solve Eq. (2.138) using Euler’s method. Plot and compare with Newton’s
solution Eq. (2.139) and the analytical solution Eq. (2.140). Plot between x = 0
and x = 1.5

Hint 1. The function scipy.special.erf will be needed. See http://docs.


scipy.org/doc/scipy-0.15.1/reference/generated/scipy.special.erf.html.

Hint 2. Figure should look something like this:

0.4

0.2

0.0
y

−0.2

−0.4 analytical
euler
Newton
−0.6
0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6
x

Figure 2.23: Problem 1 with 101 samplepoints between x = 0 and x = 1.5 .

Exercise 2: Solitary wave

A
Y

O X

Figure 2.24: Solitary wave.

This exercise focuses on a solitary wave propagating on water.


CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 91

The differential equation for a solitary wave can be written as:

d2 Y
 
3Y A 3
= 2 − Y (2.141)
dX 2 D D 2D

where D is the middle depth, Y (X) is the wave height above middle depth
and A is the wave height at X = 0. The wave is symmetric with respect to
X = 0. See Figure 2.24. The coordinate system follows the wave.
By using dimensionless variables: x = X A Y
D , a = D , y = A , Eq. (2.141) can be
written as:

 
00 3
y (x) = a 3 y(x) 1 − y(x) (2.142)
2

initial conditions: y(0) = 1, y 0 (0) = 0. Use a = 32


Pen and paper
The following problems should be done using pen and paper:
a) Calculate y(0.6), and y’(0.6) using euler’s method with ∆x = 0.2
b) Solve a) using Heuns’s method.
c) Perform a taylor expansion series around x = 0 (include 3 parts) on Eq.
(2.142), and compare results with a) and b).
d) Solve Eq. (2.142) analytically for a = 23 , given:

Z
dy p 
√ = −2 arctanh 1−y
y 1−y

Compare with solutions in a), b) and c).


Programing: Write a program that solve a), b) and c) numerically, and
compare with the analytical solution found in d). Solve first with ∆x = 0.2, and
experiment with different values.

Hint 1. Solutions:
a) y(0.6) = 0.88, y 0 (0.6) = −0.569.
b) y(0.6) = 0.8337, y 0 (0.6) = −0.4858.
2 4
c) y ≈ 1 − x2 + x6 , y 0 ≈ −x + 23 x3
d y = cosh2 1x /√2 = 1+cosh1 √2·x
( ) ( )

Hint 2. If you want you can use this template and fill in the lines where it’s
indicated.
#import matplotlib; matplotlib.use(’Qt4Agg’)
import matplotlib.pylab as plt
#plt.get_current_fig_manager().window.raise_()
import numpy as np
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 92

1.00

0.98

0.96

0.94

0.92

0.90

0.88
euler, y(0.6)=0.88
0.86 heun, y(0.6)=0.8336
taylor, y(0.6)=0.8416
0.84
analytic, y(0.6)=0.8396
0.82
0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7

Figure 2.25: Plot should look something like this.

#### set default plot values: ####


LNWDT=3; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT; plt.rcParams[’font.size’] = FNT

""" This script solves the problem with the solitary wave:

y’’ = a*3*y*(1-y*3/2)
y(0) = 1, y’(0) = 0

or as a system of first order differential equations (y0 = y, y1 = y’):

y0’ = y’
y1’ = a*3*y0*(1-y0*3/2)

y0(0) = 1, y1(0) = 0

"""
a = 2./3
h = 0.2 # steplength dx
x_0, x_end = 0, 0.6

x = np.arange(x_0, x_end + h, h) # allocate x values


#### solution vectors: ####
Y0_euler = np.zeros_like(x) # array to store y values
Y1_euler = np.zeros_like(x) # array to store y’ values

Y0_heun = np.zeros_like(x)
Y1_heun = np.zeros_like(x)

#### initial conditions: ####


Y0_euler[0] = 1 # y(0) = 1
Y1_euler[0] = 0 # y’(0) = 0
Y0_heun[0] = 1
Y1_heun[0] = 0
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 93

#### solve with euler’s method ####

for n in range(len(x) - 1):


y0_n = Y0_euler[n] # y at this timestep
y1_n = Y1_euler[n] # y’ at this timestep

"Fill in lines below"


f0 =
f1 =
"Fill in lines above"

Y0_euler[n + 1] = y0_n + h*f0


Y1_euler[n + 1] = y1_n + h*f1

#### solve with heun’s method: ####

for n in range(len(x) - 1):


y0_n = Y0_heun[n] # y0 at this timestep (y_n)
y1_n = Y1_heun[n] # y1 at this timestep (y’_n)
"Fill in lines below"
f0 =
f1 =

y0_p =
y1_p =

f0_p =
f1_p =
"Fill in lines above"

Y0_heun[n + 1] = y0_n + 0.5*h*(f0 + f0_p)


Y1_heun[n + 1] = y1_n + 0.5*h*(f1 + f1_p)

Y0_taylor = 1 - x**2/2 + x**4/6


Y1_taylor = -x + (2./3)*x**3

Y0_analytic = 1./(np.cosh(x/np.sqrt(2))**2)

Exercise 3: Mathematical pendulum


Figure 2.26 shows a mathematical pendulum where the motion is described by
the following ODE:

d2 θ g
+ sin θ = 0 (2.143)
dτ 2 l
with initial conditions

θ(0) = θ0 (2.144)

(0) = θ̇0 (2.145)

CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 94

g
θ
θ0

Figure 2.26: Mathematical pendulum.

pg
We introduce a dimensionless time t = lt such that (2.143) may be written
as

θ̈(t) + sin θ(t) = 0 (2.146)

with initial conditions

θ(0) = θ0 (2.147)
θ̇(0) = θ̇0 (2.148)

Assume that the pendulum wire is a massless rod, such that −π ≤ θ0 ≤ π.


The total energy (potential + kinetic), which is constant, may be written in
dimensionless form as
1 2 1
(θ̇) − cos θ = (θ̇0 )2 − cos θ0 (2.149)
2 2
We define an energy function E(θ) from (2.149) as
1
E(θ) = [(θ̇)2 − (θ̇0 )2 ] + cos θ0 − cos θ (2.150)
2
We see that this function should be identically equal to zero at all times. But,
when it is computed numerically, it will deviate from zero due to numerical
errors.

Movie 1: mov-ch1/pendulum.mp4

a) Write a Python program that solves the ODE in (2.146) with the specified
initial conditions using Heun’s method, for given values of θ0 and θ̇0 . Set for
instance θ0 = 85o and θ̇0 = 0. (remember to convert use rad in ODE) Experiment
CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 95

with different time steps ∆t, and carry out the computation for at least a whole
period. Plot both the amplitude and the energy function in (2.150) as functions
of t. Plot in separate figures.
b) Solve a) using Euler’s method.
c) Solve the linearized version of the ODE in (2.146):

θ̈(t) + θ(t) = 0 (2.151)


θ(0) = θ0 , θ̇(0) = 0 (2.152)

using both euler and Heuns method. Plot all four solutions (Problem 2, 3a
and b) in the same figure. Experiment with different timesteps and values of θ0 .

Hint 1. Euler implementations of the linearized version of this problem may be


found in the digital compendium. See http://folk.ntnu.no/leifh/teaching/
tkt4140/._main007.html.

Hint 2. Figure should look something like this:

2.0
EulerLin
1.5
HeunLin
EulerNonlin
1.0
HeunNonlin
Amplitude [rad]

0.5

0.0

−0.5

−1.0

−1.5

−2.0
0 2 4 6 8 10 12 14 16
Dimensionless time [-]

Figure 2.27: Problem 3 with 2500 samplepoints and θ0 = 85o .

Exercise 4: Comparison of 2nd order RK-methods


In this exercise we seek to compare several 2nd order RK-methods as outlined
in 2.9.
a) Derive the Midpoint method a2 = 1 and Ralston’s method a2 = 2/3 from
the generic second order RK-method in (2.84).
b) Implement the Midpoint method a2 = 1 and Ralston’s method a2 = 2/3
and compare their numerical predictions with the predictions of Heun’s method
for a model problem.
Chapter 3

Shooting Methods for


Boundary Value Problems

3.1 Linear equations


Shooting methods are developed to transform boundary value probelms (BVPs)
for ordinary differential equations to an equivalent initial value problem (IVP).
The term "shooting method" is inspired by the problem illustrated in Figure 3.1,
where the problem is to "shoot" a ballistic object in the field of gravity, aming hit
a target at a given length L. The initial angle α is then changed in an repeated
fasion, based on observed lengths, until the target at L is hit.

y
v0
m

v
α
mg

x
L

Figure 3.1: The trajectory of a ballistic object launched with an inital angle α.

The problem is a boundary value problem with one condition given at x = 0


and another at x = L. It might seems obvious that the problem of varying α
until the condition at x = L is satisfied has a solution. We will use this approach
on problems which has nothing to do with ballistic trajectories.
Let us consider the following example:

y 00 = y(x) (3.1)

96
CHAPTER 3. SHOOTING METHODS 97

which is a second order, linear ODE with initial conditions:

y(0) = 0, y 0 (0) = s (3.2)

and consequently an initial value problem which can be shown to have the
following analytical solution:

y(x) = s · sinh(x) (3.3)


0
For each choice of the initial value y (0) = s we will get a new solution y(x),
and in Figure 3.2 we see the solutions for s = 0.2 og 0.7.
The problem we really is (3.1) with the following boundary conditions:

y(0) = 0, y(1) = 1 (3.4)

which is what we call a boundary value problem.


From (3.3) we realize that the boundary problem may be solve by selecting
s = s∗ such that y(1) = s∗ · sinh(1) or
1
s∗ = (3.5)
sinh(1)
For this particular case we are able to find the analytical solution of both
the initial problem and the boundary value problem. When this is not the case
our method of approach is a shooting method where we select values of s until
the condition y(1) = 1 is fulfilled. For arbitrary values of s the boundary value
y(1) becomes a function of s, which is linear if the ODE is linear and nonlinear
if the ODE is nonlinear.
To illustrate the shooting method, consider a somewhat general boundary
problem for a second order linear ODE:

y 00 (x) = p(x) · y 0 (x) + q(x) · y(x) + r(x) (3.6)


where p(x), q(x) are arbritary functions and r(x) may be considered as a
source term. The boundary values may be prescribed as:

y(a) = α, y(b) = β (3.7)


The second order ODE (3.6) may be reduced to a system of two ODEs
(see 2.3):

y 0 (x) = g(x)
g 0 (x) = p(x) · g(x) + q(x) · y(x) + r(x) (3.8)

with the boundary conditions given in (3.7).


We start the shooting method by chosing the given boundary value y(a) = α
as an initial condition. As we need an initial condition for y 0 (α) ≡ g(α) to solve
(3.8) as an initial value problem, we have to guess and initial value in a way
CHAPTER 3. SHOOTING METHODS 98

such that the boundary value y(b) = β is satisfied. As (3.6) is a linear ODE it
suffices to guess two values of s = g(α) ≡ y 0 (a). The correct value for the initial
value of s which gives the correct value of the solution y(b) = β, may then be
found by linear interpolation. Note that y(x) is always proportional to s when
the ODE is linear.
To quantify the goodness of how well the boundary value resulting from our
initial guess s = g(a) ≡ y 0 (a), we introduce a boundary value error function φ:

φ(s) = y(b; s) − β (3.9)



The correct initial guess s = s is found when the boundary value error
function is zero:

φ(s∗ ) = 0 (3.10)
The procedure may be outlined as follows:

The shooting method for linear boundary value problems.

1. Guess two initial values s0 og s1


2. Compute the corresponding values for the error function φ0 og φ1 by
solving the initial value problem in (3.8)
3. Find the correct initial value s∗ by linear interpolation.

4. Compute the solution to the boundary value problem by solving the


initial value problem in (3.8) with g(a) = y 0 (a) = s∗ .

To see how we find s∗ from lineariztion, consider first φ as a linear fuction of


s:
φ = ka · s + kb (3.11)
where ka is the slope and kb is the offset when s = 0. We easily see from
kb
(3.11) that φ = 0 for s∗ = − . When we have two samples φ0 og φ1 of φ at s0
ka
og s1 , both ka and kb may be found from (3.11) to be:

φ1 − φ0 s1 · φ0 − φ1 · s0
ka = , k b = (3.12)
s1 − s0 s1 − s0

and concequently we may find s as:

φ1 s0 − φ0 s1
s∗ = (3.13)
φ1 − φ0
CHAPTER 3. SHOOTING METHODS 99

which also may be presented on an incremental form as:


 1
s − s0

∗ 1 1
s = s + ∆s, ∆s = −φ · (3.14)
φ1 − φ0
Let us go back to our model boundary value example (3.1) with boundary
values as prescribed in (3.4) which may be presented as reduced system of first
order ODEs:

y 0 (x) = g(x)
(3.15)
g 0 (x) = y(x)
For the given values of b and β and s = y 0 (0) = g(0) the boundary value
error function in (3.9) takes the form:

φ(s) = y(1; s) − 1 (3.16)

In accordance with the shooting method we choose two initial values s0 = 0.2
og s1 = 0.7 and solve (3.15) as an initial value problem with e.g. and RK4-solver
with ∆x = 0.1 and obtain the following results:.

m sm φ(sm )
0 0.2 -0.7650
1 0.7 -0.1774

Note that we use m as a superindex for iterations, which will be used in case of
nonlinear equations. Substitution into (3.13) gives the s∗ = 0.8510. Subsequent
use of the s∗ -value in the RK4-solver yields φ(0.8510) = 0.0001. We observe a
good approximation to the correct value for the initial value may be found from
1
the analytical solution as: y 0 (0) = = 0.8509
sinh(1)
The presentation above with the shooting method is chosen as it can easily
be generalized to the solution of nonlinear ODEs.

Alternative approach for linear second order ODEs. For linear second
order ODEs the solution may be found in somewhat simpler fashion, by solving
the following sub-problems:
Sub-problem 1

y000 (x) = p(x) · y00 (x) + q(x) · y0 (x) + r(x), y0 (a) = α, y00 (a) = 0 (3.17)

and
Sub-problem 2

y100 (x) = p(x) · y10 (x) + q(x) · y1 (x), y1 (a) = 0, y10 (a) = 1 (3.18)

That is, the two sub-problems differ only by the source term r(x) and the
boundary conditions. Notice that the condition y 0 (α) = 0 in (3.17) corresponds
to s0 = 0 and the condition y 0 (α) = 1 i (3.18) corresponds to s1 = 1.
CHAPTER 3. SHOOTING METHODS 100

1.0
y(x)
y(x,s1 )
0.8
y(x,s0 )

0.6

y 0.4

0.2

0.0
0.0 0.2 0.4 0.6 0.8 1.0
x

Figure 3.2: The solution y(x) of a boundary value problem resulting from two
initial guesses y(x; s0 ) and y(x; s1 ).

Let y0 (x) represent the solution to (3.17) and y1 (x) be the solution to (3.18).
The complete solution of the boundary value problem in (3.6) with the boundary
conditions (3.7) may then be shown to be:

φ0
   
β − y0 (b)
y(x) = y0 (x) + · y1 (x) = y0 (x) − 1 · y1 (x) (3.19)
y1 (b) φ +β

with s0 = 0 og s1 = 1. Note that the solution of (3.17) corresponds to a


particular solution of (3.1) and (3.4), and that the solution of (3.18) corresponds
to the homogenous solution of (3.1) and (3.4) as the source term is missing.
From general theory on ODEs we know that the full solution may be found by
the sum of a particular solution and the homogenous solution, given that the
boundary conditions are satisfied.

3.1.1 Example: Couette-Poiseuille flow


In a Couette-Poiseuille flow, we consider fluid flow constrained between two walls,
where the upper wall is moving at a prescribed velocity U0 and at a distance
Y = L from the bottom wall. Additionally, the flow is subjected to a prescribed
∂p
pressure gradient ∂x .
We assume that the vertical velocity component V = 0 and concequently we
∂U
get from continuity: ∂X = 0 which implies that U = U (Y ), i.e. the velocity in
the streamwise X-direction depends on the cross-wise Y-direction only.
∂p
The equation of motion in the Y-direction simplifies to ∂Y = −ρg, whereas
the equation of motion in the X-direction has the form:
 2
∂2U

∂U ∂p ∂ U
ρU · =− +µ +
∂X ∂X ∂X 2 ∂Y 2
CHAPTER 3. SHOOTING METHODS 101

y
U0

p(x) U

Figure 3.3: An illustration of Couette flow driven by a pressure gradient and a


moving upper wall.

which due to the above assumptions and ramifications reduces to


d2 U 1 dp
2
= (3.20)
dY µ dX
with no-slip boundary conditions: U (0) = 0, U (L) = U0 . To render equation
(3.20) on a more appropriate and generic form we introduce dimesionless variables:
dp L2
u = UU0 , y = YL , P = − U10 ( dX ) µ , which yields:

d2 u
= −P (3.21)
dy 2
with corresponding boundary conditions:

u = 0 for y = 0, u = 1 for y = 1 (3.22)

An analytical solution of equation (3.21) with the corresponding boundary


conditions (3.22) may be found to be:
 
P
u = y · 1 + (1 − y) (3.23)
2
Observe that for P ≤ −2 we will get negative velocities for some values of
y. In Figure 3.4 velocity profiles are illustrated for a range of non-dimensional
pressure gradients P.
To solve (3.21) numerically, we represent is as a system of equations:

u0 (y) = u1 (y)
(3.24)
u01 (y) = −P
with corresponding boundary conditions:

u(0) = 0, u(1) = 1 (3.25)


To solve this boundary value problem with a shooting method, we must find
s = u0 (0) = u1 (0) such that the boundary condition u(1) = 1 is satisfied. We
can express this condition in Dette kan uttrykkes på følgende måte:
CHAPTER 3. SHOOTING METHODS 102

1.0
P = -8
P = -4
0.8 P = -2
P=0
P=4
0.6
P=8

y 0.4

0.2

0.01.0 0.5 0.0 0.5 1.0 1.5 2.0


u

Figure 3.4: Velocity profiles for Couette-Poiseuille flow with various pressure
gradients.

φ(s) = u(1; s) − 1, such that φ(s) = 0 when s = s∗

We guess two values s0 og s1 and compute the correct s by linear interpolation


due to the linearity of system of ODEs (3.24). For the linear interpolation see
equation (3.14).
The shooting method is implemented in the python-code Poiseuille_shoot.py
and results are computed and plotted for a range of non-dimensional pressure
gradients and along with the analytical solution.
# src-ch2/Couette_Poiseuille_shoot.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch2/ODEschemes.py;
from ODEschemes import euler, heun, rk4
import numpy as np
from matplotlib.pyplot import *

# change some default values to make plots more readable


LNWDT=5; FNT=11
rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT

N=200
L = 1.0
y = np.linspace(0,L,N+1)

def f(z, t):


"""RHS for Couette-Posieulle flow"""
zout = np.zeros_like(z)
zout[:] = [z[1], -dpdx]
return zout
def u_a(y,dpdx):
return y*(1.0 + dpdx*(1.0-y)/2.0);
CHAPTER 3. SHOOTING METHODS 103

beta=1.0 # Boundary value at y = L

# Guessed values
s=[1.0, 1.5]

z0=np.zeros(2)

dpdx_list=[-5.0, -2.5, -1.0, 0.0, 1.0,2.5, 5.0]


legends=[]

for dpdx in dpdx_list:


phi = []
for svalue in s:
z0[1] = svalue
z = rk4(f, z0, y)
phi.append(z[-1,0] - beta)
# Compute correct initial guess
s_star = (s[0]*phi[1]-s[1]*phi[0])/(phi[1]-phi[0])
z0[1] = s_star

# Solve the initial value problem which is a solution to the boundary value problem
z = rk4(f, z0, y)

plot(z[:,0],y,’-.’)
legends.append(’rk4: dp=’+str(dpdx))

# Plot the analytical solution


plot(u_a(y, dpdx),y,’:’)
legends.append(’exa: dp=’+str(dpdx))

# Add the labels


legend(legends,loc=’best’,frameon=False) # Add the legends
xlabel(’u/U0’)
ylabel(’y/L’)
show()

3.1.2 Example: Simply supported beam with constant cross-


sectional area
Figure 3.5 illustrates a simply supported beam subjected to an evenly distributed
load q per length unit and a horizontal force P .
The differential equation for the deflection U (X) is given by:

d2 U P q
+ U =− (L2 − X 2 ), P > 0 (3.26)
dX 2 EI 2EI
with the following boundary conditions:

U (−L) = U (L) = 0 (3.27)


where EI denotes the flexural rigidity. The equation (3.26) was linearized by
dU
assuming small deflections. Alternatively we may assume dX (0) = 0 due to the
symmetry.
CHAPTER 3. SHOOTING METHODS 104

q
A B P
U(X)
X

L L

Figure 3.5: Simply supported beam with an evenly distributed load q per length
unit.

For convenience we introduce dimensionless variables:

x P P L2
x= , u= 2
· U, θ2 = (3.28)
L qL EI
which by substitution in (3.26) and (3.27) yield:

d2 u 2
2
2 (1 − x )
+ θ · u = θ , −1 < x < 1 (3.29)
dx2 2
with the corresponding boundary conditions:

u(−1) = 0, u(1) = 0 (3.30)


Equation (3.29) with boundary conditions (3.30) have the analytixcal solution:

(1 − x2 )
 
1 cos(θx)
u(x) = 2 · −1 − (3.31)
θ cos(θ) 2
πEI
The buckling load for this case is given by Pk = such that
4L2
π
0≤θ≤ (3.32)
2

Numerical solution. We wish to solve the second order linear ODE in (3.29)
by means of shooting methods and choose the alternative approach as outlined
in equation (3.19).
Two similar sub-problems are then two be solved; they differ only with the
source term and the boundary conditions.
Sub-problem 1

(1 − x2 )
u000 (x) = −θ2 u0 (x) + θ2 , u0 (−1) = 0, u00 (−1) = 0 (3.33)
2
(3.34)
CHAPTER 3. SHOOTING METHODS 105

Sub-problem 2

u001 (x) = −θ2 · u1 (x) u1 (−1) = 0, u01 (−1) = 1 (3.35)


(3.36)

From the superposition principle for linear equation given in equation n (3.19)
a complete solution is obtained as a combination of the solutions to the two
sub-problems:

u0 (1)
u(x) = u0 (x) − · u1 (x) (3.37)
u1 (1)
Now, to solve the equation numerically we write (3.33) and (3.35) as a system
of first order ODEs:
Sub-problem 1 as a system of first order ODEs
For convenience we introduce the notation u0 = y1 and u0o = y2 :

y10 =y2 (3.38)


(1 − x2 )
 
y20 = − θ2 · y1 +
2

with the corresponding initial conditions

y1 (−1) = 0, y2 (−1) = 0 (3.39)


Sub-problem 2 as a system of first order ODEs
With u1 = y1 og u01 = y2 :

y10 =y2 (3.40)


y20 2
= − θ y1

and initial conditions

y1 (−1) = 0, y2 (−1) = 1 (3.41)


Both sub-problems must be integrated from x = −1 to x = 1 such that u0 (1)
and u1 (1) may be found and the solution to the original problem in equation (3.29)
may be constructed according to (3.37). A python-code beam_deflect_shoot_constant.py
for the problem is listed below. Here the resluting solution is compared with the
analytical solution too.
# src-ch2/beam_deflect_shoot_constant.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch2/ODEschemes.py
from ODEschemes import euler, heun, rk4
from numpy import cos, sin
import numpy as np
from matplotlib.pyplot import *

# change some default values to make plots more readable


CHAPTER 3. SHOOTING METHODS 106

LNWDT=2; FNT=15; FMLY=’helvetica’;


rcParams[’lines.linewidth’] = LNWDT
rcParams[’font.size’] = FNT
rcParams[’font.family’] = FMLY

def SubProblem1(y, x):


""" system 1 of Governing differential equation on beam bending with constant cross section
Args:
y(array): an array containg y and its derivatives up to second order. (RHS)
x(array): an array
Returns:
yout(array): dydx RHS of reduced system of 1st order equations
"""
yout = np.zeros_like(y)
yout[:] = [y[1],-theta2*(y[0]+0.5*(1-x**2))]

return yout

def SubProblem2(y, x):


""" system 2 of Governing differential equation on beam bending with constant cross section
Args:
y(array): an array containg y and its derivatives up to second order. (RHS)
x(array): an array
Returns:
yout(array): dydx RHS of reduced system of 1st order equations
"""
yout = np.zeros_like(y)
yout[:] = [y[1], -theta2*y[0]]
return yout

# === main program starts here ===

N = 20 # number of elements
L = 1.0 # half the length of the beam
x = np.linspace(-L, L, N + 1) # allocate space
theta = 1 # PL**2/EI
theta2 = theta**2

solverList = [euler, heun, rk4]


solver = solverList[2]
s = [0, 1] # guessed values
# === shoot ===
y0Sys1 = [0, s[0]] # initial values of u and u’
y0Sys2 = [0, s[1]]

u0 = solver(SubProblem1, y0Sys1,x)
u1 = solver(SubProblem2, y0Sys2,x)

u0 = u0[:,0] # extract deflection from solution data


u1 = u1[:,0]
u = u0 -(u0[-1]/u1[-1])*u1 # interpolate to find correct solution
ua = (1/theta2)*(cos(theta*x)/cos(theta) - 1)-(1 - x**2)/2 # analytical solution
legendList=[] # empty list to append legends as plots are generated

plot(x,u,’y’,)
plot(x,ua,’r:’)
legendList.append(’shooting technique’)
CHAPTER 3. SHOOTING METHODS 107

legendList.append(’analytical solution’)
## Add the labels
legend(legendList,loc=’best’,frameon=False)
ylabel(’u’)
xlabel(’x’)
grid(b=True, which=’both’, color=’0.65’,linestyle=’-’)
#savefig(’../fig-ch2/beam_deflect_shoot_constant.png’, transparent=True)
#savefig(’../fig-ch2/beam_deflect_shoot_constant.pdf’, transparent=True)
#sh
show()

The output of beam_deflect_shoot_constant.py is shown in Figure 3.6.

0.40
0.35
0.30
0.25
0.20
u

0.15
0.10
0.05 shooting technique
analytical solution
0.001.0 0.5 0.0 0.5 1.0
x

Figure 3.6: The anyalytical and numerical solutions for simply supported beam
with an evenly distributed load q per length unit. The results are produced with
a shooting method implemented in beam_deflect_shoot_constant.py.

3.1.3 Example: Simply supported beam with varying cross-


sectional area
In this example we will study a simply supported beam with varying cross-
sectional area and refer to the figure in our previous example (3.1.2). The
difference with the previous example is that the second area momentis a function
of X due to the varying cross-sectional area.
We denote the second area moment at X = 0 as I0 , and let the second area
moment I vary in the following manner:
I0
I(X) = , n = 2, 4, 6, . . . (3.42)
1 + (X/L)n
Consider a rectangular cross-sectional area with a constant width b and a
varying height h:
h0
h(X) = (3.43)
[1 + (X/L)n ]1/3
CHAPTER 3. SHOOTING METHODS 108

where h0 denotes h at X = 0. From equation (3.26) in example (3.1.2) we


have:

d2 U P q
+ U =− (L2 − X 2 ) (3.44)
dX 2 EI 2EI
dU (0)
U (−L) = U (L) = 0, =0 (3.45)
dX
We start by computing the moment distribution M (X) in the beam, which
is related with the displaceent by the following expression:

d2 U M
2
=− (3.46)
dX EI
By substitution of equation (3.46) in (3.44) and two esubsequent differentia-
tions we get:

d2 M P
2
+ @, M = −q (3.47)
dX EI
To represent the resulting second order ODE on a more convenient and
generic form we introduce the dimensionless variables:
X M
x= , m= (3.48)
L qL2
and let
EI0
P = (3.49)
L2
such that equation (3.47) becomes:

m00 (x) + (1 + xn ) · m(x) = −1 (3.50)


with the boundary conditions:

m(−1) = m(1) = 0, m0 (0) = 0 (3.51)


To our knowledge, no analytical solution exists for equation (3.50), even if it
is linear and analytical solutions exists for the previous example in (3.1.2).
Once the moment distribution has been computed, the dimensionless dis-
placement u(x) may retrieved from:
1
u(x) = m(x) − (1 − x2 ) (3.52)
2
The displacement in physical dimensions U may subsequently computed from
the dimensionless u:

qL4
U= u (3.53)
EI0
CHAPTER 3. SHOOTING METHODS 109

Further, the differential equaiton for u(x) may be found by substitution of


equation (3.52) into (3.50):
1
u00 (x) + (1 + xn ) · u(x) = − (1 − x2 ) · (1 + xn ) (3.54)
2
By expoliting the symmetry in the problem, we solve equation (3.50) numeri-
cally with a shooting method. The boundary conditions are:

m(1) = 0, m0 (0) = 0 (3.55)

The dimensionless displacement u(x) is subsequently computed from equation


(3.52). We have implemented the outlined approach in beam_deflect_shoot_varying.py
in such a way that one easily may choose between various RK-solvers (euler,
heun, og rk4) from the module ODEschemes.
We represent the second order ODE (3.50) as a system of first order ODEs
by introducing the following conventions m(x) = y1 (x) og m0 (x) = y2 (x):

y10 = y2 (3.56)
y20 = − (1 + (1 + xn ) · y1 )

and the boundary conditions become:

y2 (0) = y1 (1) = 0 (3.57)

In this case y2 (0) ≡ m0 (0) is given, which leaves m(0) ≡ y1 (0) to be guessed
such that the boundary condition at the other end m(1) ≡ y1 (1) = 0 is fulfilled.
To express the approach algorithmically as previously, we let s = y1 (0) and let
the bondary value error function be φ(s) = y1 (1; s).

Simplified shooting method for linear ODEs


1. Let the two initial values s0 = 0 og s1 = 1 for simplicity

2. Compute the corresponding values for the error function φ0 og φ1 by


solving the initial value problem (in the current example (3.56)).
3. Find the correct initial value s∗ by linear interpolation:

φ0
s∗ = (3.58)
φ0 − φ1

The simplfied expression for s in equation (3.58) may be found from (3.14)
by setting s0 = 0 og s1 = 1.
One should be aware of that the choice in (3.58) is not necessarily always a
good choice even though the ODE is linear. If the solution is of the kind eαx
CHAPTER 3. SHOOTING METHODS 110

when both α and x are large, we may end up outside the allowable range even
for double precision which is approximately 10308 . In our example above this is
not a problem and we may use (3.58) and we have implemented the approach
in beam_deflect_shoot_varying.py as shown below where both the moment
and deflection is computed for n = 2.
# src-ch2/beam_deflect_shoot_varying.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch2/ODEschemes.py;

from ODEschemes import euler, heun, rk4


from numpy import cos, sin
import numpy as np
from matplotlib.pyplot import *

# change some default values to make plots more readable


LNWDT=3; FNT=11
rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT
def f(y, x):
"""Governing differential equation on beam bending as a system of 1. order equations.
Args:
y(array): an array containg y and its derivatives up to second order. (RHS)
x(array): space array
Returns:
dydx(array): dydx. RHS of reduced system of 1st order equations
"""
yout = np.zeros_like(y)
yout[:] = [y[1],-(1+(1+x**n)*y[0])]
return yout

# === main program starts here ===


N = 10 # number of elements
L = 1.0 # half the length of the beam
x = np.linspace(0,L,N+1) # vector of
theta = 1 # PL**2/EI
theta2 = theta**2
h0=1 # height of beam at x = 0
n=2 # polynomial order to go into h(x)
h=h0/(1+(x/L)**n)**(1/3.) # height of beam assuming constant width

solvers = [euler, heun, rk4]


solver = solvers[2]

s = [0, 1] # guessed values


# === shoot ===
y01 = [s[0], 0] # initial values
y02 = [s[1], 0]

m0 = solver(f, y01, x)
m1 = solver(f, y02, x)

phi0 = m0[-1,0]
phi1 = m1[-1,0]

sfinal = phi0/(phi0 - phi1) # find correct initial value of moment m(x=0) using secant method

y03 = [sfinal, 0]
CHAPTER 3. SHOOTING METHODS 111

mfinal = solver(f,y03,x)
m = mfinal[:, 0] # extract moment from solution data

u = m -0.5*(1 - x**2) # final solution of dimensionless deflection


ua = (1/theta2)*(cos(theta*x)/cos(theta)-1)-(1-x**2)/2 #analytical solution with constant stifness

legendList=[] # empty list to append legends as plots are generated

plot(x, m, ’b’,)
legendList.append(’m’)
plot(x, u, ’r’,)
legendList.append(’u’)
## Add the labels
legend(legendList,loc=’best’,frameon=False)
ylabel(’m, u’)
xlabel(’x’)
grid(b=True, which=’both’, axis=’both’,linestyle=’-’)
show()

1.0
m
0.8 u

0.6
m, u

0.4

0.2

0.0

−0.2
0.0 0.2 0.4 0.6 0.8 1.0
x

Figure 3.7: Moment m and deflection u .

3.2 Non-linear boundary value problems of ODEs


As model examaple for a non-linear boundary value problems we will investigate:

y 00 (x) = 32 y 2
(3.59)
y(0) = 4, y(1) = 1
Our model problem (3.59) may be proven to have two solutions.

Solution I:

4
yI = (3.60)
(1 + x)2
CHAPTER 3. SHOOTING METHODS 112

Solution II: Can be expressed by elliptic Jacobi-functions ( see G.3 in Nu-


meriske Beregninger)

Both solutions are illustrated in Figure 3.8 .

−2

−4
y

−6

−8

−10 yI
yII
−12
0.0 0.2 0.4 0.6 0.8 1.0
x

Figure 3.8: The two solutions yI og yII of the non-linear ODE (3.59).

Our model equation (3.59) may be reduced to a system of ODEs in by


introducing the common notation y → y0 og y 0 = y00 = y1 and following the
procedure in 2.3:

y00 (x) = y1 (x)


0 (3.61)
y1 (x) = 32 [y0 (x)]2
with the corresponding boundary conditions:

y0 (0) = 4, y0 (1) = 1 (3.62)


We will use the shooting method to find s = y 0 (0) = y1 (0) such that the
boundary condition y0 (1) = 1 is satisfied. Our boundary value error function
becomes:

φ(sm ) = y0 (1; sm ) − 1, m = 0, 1, . . . such that y0 (1) → 1 for φ(sm ) → 0, m → ∞


(3.63)

As our model equation is non-linear our error function φ(s) will also be
non-linear, and we will have to conduct an iteration process as outlined in (3.63).
Our task will then be to find the values s∗ so that our boundary value error
function φ(s) becomes zero φ(s∗ ) = 0. For this purpose we choose the secant
method (See [3], section 3.3).
Two initial guesses s0 and s1 are needed to start the iteration process. Eq.
(3.61) is then solved twice (using s0 and s1 ). From these solutions two values
for the error function (3.63) may be calculated, namely φ0 and φ1 . The next
CHAPTER 3. SHOOTING METHODS 113

value of s (s2 ) is then found at the intersection of the gradient (calculated by


the secant method) with the s − axis.
For an arbitrary iteration, illustrated in Figure 3.9 we find it more convenient
to introduce the ∆s:

sm+1 = sm + ∆s (3.64)
where

sm − sm−1
 
m+1 m m
∆s = s −s = −φ(s ) · , m = 1, 2, . . .
φ(sm ) − φ(sm−1 )

ϕ
ϕ(sm-1)

ϕ(sm)
ϕ(sm+1)

sm-1 sm sm+1 s* s

Figure 3.9: An illustration of the usage of the secant method label to find the
zero for a non-linear boundary value error function.

Given that sm−1 og sm may be taken as known quantities the iteration


process process may be outlined as follows:

Iteration process

1. Compute φ(sm−1 ) og φ(sm ) from numerical solution of (3.61) and


(3.63).
2. Compute ∆s and sm+1 from (3.64)

3. Update
• sm−1 ← sm
• sm ← sm+1
• φ(sm−1 ) ← φ(sm )
CHAPTER 3. SHOOTING METHODS 114

4. Repeat 1-3until convergence

Examples on convergence criteria:

Control of absolute error:

|∆s| < ε1 (3.65)

Control of relative error:


∆s
sm+1 < ε2 (3.66)

The crietria (3.65) and (3.66) are frequently used in combination with:

|φ(sm+1 )| < ε3 (3.67)


We will now use this iteration process to solve (3.61). However, a frequent
problem is to find appropriate initial guesses, in particular in when φ is a non-
linear function and may have multiple solutions. A simple way to assess φ is to
make implement a program which plots φ for a wide range of s-values and then
vary this range until the zeros are in the range. An example for such a code is
given below for our specific model problem:
# src-ch2/phi_plot_non_lin_ode.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch2/ODEschemes.py;

from ODEschemes import euler, heun, rk4


from numpy import cos, sin
import numpy as np
from matplotlib.pyplot import *

# change some default values to make plots more readable


LNWDT=2; FNT=11
rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT
font = {’size’ : 16}; rc(’font’, **font)

N=20
L = 1.0
x = np.linspace(0,L,N+1)

def f(z, t):


zout = np.zeros_like(z)
zout[:] = [z[1],3.0*z[0]**2/2.0]
return zout

beta=1.0 # Boundary value at x = L


solvers = [euler, heun, rk4] #list of solvers
solver=solvers[2] # select specific solver
CHAPTER 3. SHOOTING METHODS 115

smin=-45.0
smax=1.0
s_guesses = np.linspace(smin,smax,20)

# Guessed values
#s=[-5.0, 5.0]

z0=np.zeros(2)
z0[0] = 4.0
z = solver(f,z0,x)
phi0 = z[-1,0] - beta
nmax=10
eps = 1.0e-3
phi = []
for s in s_guesses:
z0[1] = s
z = solver(f,z0,x)
phi.append(z[-1,0] - beta)

legends=[] # empty list to append legends as plots are generated

plot(s_guesses,phi)
ylabel(’phi’)
xlabel(’s’)
grid(b=True, which=’both’, color=’0.65’,linestyle=’-’)
show()
close()

Based on our plots of φ we may now provided qualified inital guesses for
and choose s0 = −3.0 og s1 = −6.0. The complete shooting method for the our
boundary value problem may be found here:
# src-ch2/non_lin_ode.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch2/ODEschemes.py;
from ODEschemes import euler, heun, rk4
from numpy import cos, sin
import numpy as np
from matplotlib.pyplot import *

# change some default values to make plots more readable


LNWDT=3; FNT=16
rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT

N=40
L = 1.0
x = np.linspace(0,L,N+1)

def dsfunction(phi0,phi1,s0,s1):
if (abs(phi1-phi0)>0.0):
return -phi1 *(s1 - s0)/float(phi1 - phi0)
else:
return 0.0
CHAPTER 3. SHOOTING METHODS 116

def f(z, t):


zout = np.zeros_like(z)
zout[:] = [z[1],3.0*z[0]**2/2.0]
return zout

def y_analytical(x):
return 4.0/(1.0+x)**2

beta=1.0 # Boundary value at x = L

solvers = [euler, heun, rk4] #list of solvers


solver=solvers[2] # select specific solver

# Guessed values
# s=[-3.0,-9]
s=[-40.0,-10.0]

z0=np.zeros(2)
z0[0] = 4.0
z0[1] = s[0]

z = solver(f,z0,x)
phi0 = z[-1,0] - beta
nmax=10
eps = 1.0e-3
for n in range(nmax):
z0[1] = s[1]
z = solver(f,z0,x)
phi1 = z[-1,0] - beta
ds = dsfunction(phi0,phi1,s[0],s[1])
s[0] = s[1]
s[1] += ds
phi0 = phi1
print ’n = {} s1 = {} and ds = {}’.format(n,s[1],ds)

if (abs(ds)<=eps):
print ’Solution converged for eps = {} and s1 ={} and ds = {}. \n’.format(eps,s[1],ds)
break
legends=[] # empty list to append legends as plots are generated

plot(x,z[:,0])
legends.append(’y’)

plot(x,y_analytical(x),’:^’)
legends.append(’y analytical’)

# Add the labels


legend(legends,loc=’best’,frameon=False) # Add the legends
ylabel(’y’)
xlabel(’x/L’)
show()

After selection ∆x = 0.1 and using the RK4-solver, the following iteration
output may be obtained:
CHAPTER 3. SHOOTING METHODS 117

m sm−1 φ(sm−1 ) sm φ(sm ) sm+1 φ(sm+1 )


1 -3.0 26.8131 -6.0 6.2161 -6.9054 2.9395
2 -6.0 6.2161 -6.9054 2.9395 -7.7177 0.6697
3 -6.9054 2.9395 -7.7177 0.6697 -7.9574 0.09875
4 -7.7177 0.6697 -7.9574 0.09875 -7.9989 0.0004

After four iterations s = y 0 (0) = −7.9989 , while the analytical value is −8.0. The
code non_lin_ode.py illustrates how our non-linear boundary value problem
may be solve with a shooting method and offer graphical comparison of the
numerical and analytical solution.
The secant method is simple and efficient and does not require any knowledge
of the analytical expressions for the derivatives for the function for which the
zeros are sought, like e.g. for Newton-Raphsons method. Clearly a drawback is
that two initial guesses are mandatory to start the itertion process. However, by
using some physical insight for the problemn and ploting the φ-function for a
wide range of s-values, the problem is normally possible to deal with.

3.2.1 Example: Large deflection of a cantilever

A
θ y
P δ
ɭ
C B
ɭh

Figure 3.10: Large deflection of a beam subjected to a vertical load.

Consider a cantilever (see figure 3.10) which is anchored at one end A to a


vertical support from which it is protruding. The cantilever is subjected to a
structural load P at the other end B. When subjected to a structural load, the
cantilever carries the load to the support where it is forced against by a moment
and shear stress [12]. In this example we will allow for large deflections and
for that reason we introduce the arc length l and the angle of inclination θ as
variables.
All lengths are rendered dimensionless by division with the cantilever length
L. The arch length l ranges consequently from l = 0 in A to l = 1 in B. Without
further ado we present the differential equation for the elastic cantilever as:
dθ M
κ= = (3.68)
L · dl EI
CHAPTER 3. SHOOTING METHODS 118

where κ denotes the curvature, M the moment and EI flexural rigidity. The
balance of moments in C may by computed as C: M = P · L(lh − x) which by
substitution in (3.68) results in:

dθ P L2
= (lh − x) (3.69)
dl EI
From figure 3.10 we may deduce the following geometrical relations:
dx dy
= cos θ, = sin θ (3.70)
dl dl
Further, differentiation of (3.69) with respect to the arch length l and substi-
tution of (3.70) yields:

d2 θ P L2
+ cos θ = 0 (3.71)
dl2 EI
For convenience we introduce the parameter α which is defined as:

P L2
α2 = (3.72)
EI
As a result we must solve the following differential equations:

d2 θ
+ α2 cos θ = 0 (3.73)
dl2
dy
= sin θ (3.74)
dl
with the following boundary conditions:

y(0) = 0, θ(0) = 0, (1) = 0 (3.75)
dl
The first two boundary conditions are due the anchoring in A, whereas the
latter is due to a vanishing moment in B. The analytical solution of this problem
may be found in appendix G, section G.3 in Numeriske Beregninger.
Numerical solution
First, we need to represent (3.73) and (3.74) as a system of first order
differntial equations. By introducing the conventions θ = z0 , θ0 = z1 and y = z2
we get:

z00 = z1
z10 = −α2 cos z0 (3.76)
z20 = sin z0

with the boundary conditions

z0 (0) = 0, z1 (1) = 0, z2 (0) = 0 (3.77)


CHAPTER 3. SHOOTING METHODS 119

We have to guess the initial value θ0 (0) such that the condition dθ
dl (1) = 0 is
satisfied.
To do so, we let s = θ0 (0) = z1 (0) and φ(s) = θ0 (1; s) − 0 = z1 (1). Conse-
quently, we have to find s = s∗ such that φ(s∗ ) = 0, which with z-variables takes
the form: s = z1 (0).

With the introduction of these convendtions the task at hand becomes to


find s = s∗ such that:

φ(s∗ ) = z1 (1; s∗ ) = 0 (3.78)

Additionally we find:
s∗
lh = (3.79)
α2
Due to the nonlinear nature of (3.76) the function (3.78) will be nonlinear
too and we will use the secant method to find s∗ . To start the secant iterations
we need two intial guesses s0 og s1 . Suitable initial guesses may be found by
first looking at φ(s) graphically. The python-code phi_plot_beam_shoot.py
produces Figure 3.11.
# src-ch2/phi_plot_beam_shoot.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch2/ODEschemes.py;

from ODEschemes import euler, heun, rk4


from numpy import cos, sin
import numpy as np
from matplotlib.pyplot import *

# change some default values to make plots more readable


LNWDT=3; FNT=11
rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT

N=20
L = 1.0
y = np.linspace(0,L,N+1)
def f(z, t):
"""RHS for deflection of beam"""
zout = np.zeros_like(z)
zout[:] = [z[1],-alpha2*cos(z[0]),sin(z[0])]
return zout

solvers = [euler, heun, rk4] #list of solvers


solver=solvers[2] # select specific solver

alpha2 = 5.0
beta=0.0 # Boundary value at y = L

N_guess = 30
s_guesses=np.linspace(1,5,N_guess)

z0=np.zeros(3)
CHAPTER 3. SHOOTING METHODS 120

phi = []
for s_guess in s_guesses:
z0[1] = s_guess
z = solver(f,z0,y)
phi.append(z[-1,1] - beta)

legends=[] # empty list to append legends as plots are generated


plot(s_guesses,phi)
# Add the labels
legend(legends,loc=’best’,frameon=False) # Add the legends
title(’alpha2 = ’ + str(alpha2))
ylabel(’phi’)
xlabel(’s’)
grid(b=True, which=’both’)
show()

0
(s)

−1

−2

−3

−4
1.0 1.5 2.0 2.5 3.0 3.5
s

Figure 3.11: A plot of φ(s) for α2 = 5 for identification of zeros.

From visual inspection of Figure 3.11 we find that φ as a zero at approximately


s∗ ≈ 3.05. Note, that the zeros depend on the values of α.
Given this approximation of the zero we may provide two initial guesses
s0 = 2.5 and s1 = 5.0 which are ’close enough’ for the secant method to
converge. An example for how the solution may be found and presented is given
in beam_deflect_shoot.py.
# src-ch2/beam_deflect_shoot.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch2/ODEschemes.py;

from ODEschemes import euler, heun, rk4


from numpy import cos, sin
import numpy as np
from matplotlib.pyplot import *

# change some default values to make plots more readable


LNWDT=3; FNT=11
rcParams[’lines.linewidth’] = LNWDT; rcParams[’font.size’] = FNT
CHAPTER 3. SHOOTING METHODS 121

N=20
L = 1.0
y = np.linspace(0,L,N+1)

def dsfunction(phi0,phi1,s0,s1):
if (abs(phi1-phi0)>0.0):
return -phi1 *(s1 - s0)/float(phi1 - phi0)
else:
return 0.0

def f(z, t):


"""RHS for deflection of beam"""
zout = np.zeros_like(z)
zout[:] = [z[1],-alpha2*cos(z[0]),sin(z[0])]
return zout

alpha2 = 5.0
beta=0.0 # Boundary value at y = L

solvers = [euler, heun, rk4] #list of solvers


solver=solvers[2] # select specific solver

# Guessed values
s=[2.5, 5.0]

z0=np.zeros(3)

z0[1] = s[0]
z = solver(f,z0,y)
phi0 = z[-1,1] - beta
nmax=10
eps = 1.0e-10
for n in range(nmax):
z0[1] = s[1]
z = solver(f,z0,y)
phi1 = z[-1,1] - beta
ds = dsfunction(phi0,phi1,s[0],s[1])
s[0] = s[1]
s[1] += ds
phi0 = phi1
print ’n = {} s1 = {} and ds = {}’.format(n,s[1],ds)

if (abs(ds)<=eps):
print ’Solution converged for eps = {} and s1 ={} and ds = {}. \n’.format(eps,s[1],ds)
break
legends=[] # empty list to append legends as plots are generated

plot(y,z[:,0])
legends.append(r’$\theta$’)

plot(y,z[:,1])
legends.append(r’$d\theta/dl$’)

plot(y,z[:,2])
legends.append(r’$y$’)
CHAPTER 3. SHOOTING METHODS 122

# Add the labels


legend(legends,loc=’best’,frameon=False) # Add the legends
ylabel(r’$\theta, d\theta/dl, y$’)
xlabel(’y/L’)
#grid(b=True, which=’both’, axis=’both’,linestyle=’-’)
grid(b=True, which=’both’, color=’0.65’,linestyle=’-’)

show()

And the resulting output of solutions is illustrated in Figure 3.12

3.5
3.0 d /dl
2.5 y
=5.0

2.0
2

1.5
,d /dl,y for

1.0
0.5
0.0
0.50.0 0.2 0.4 0.6 0.8 1.0
y/L

Figure 3.12: Solutions generated with a shooting method for large deflections
of a cantilever subjected to a point load.

3.3 Notes on similarity solutions


The transient one dimensional heat equation may be represented:

∂T ∂2T
=α (3.80)
∂τ ∂X 2
where τ and X denote time and spatial coordinates, respectively. The
temperature T is a function of time and space T = T (X, τ ), and α is the thermal
diffusivity. (See appendix B in Numeriske Beregninger for a derivation)
In Figure 3.13 a one-dimensional beam in the right half-space (0 ≤ X < ∞)
is illustrated. The beam has initially a temperature Ts , but at time τ = 0, the
temperature at the left end X = 0 is abrubtly set to T0 , and kept constant
thereafter.
We wish to compute the temperaturedistribution in the beam as a function
of time τ . The partial differential equation describing this problem is given by
CHAPTER 3. SHOOTING METHODS 123

X
Ts

T0

Figure 3.13: Beam in the right half-space in one-dimension.

equation (3.80), and to model the time evolution of the temperature we provide
the following initial condition:

T (X, τ ) = Ts , τ < 0 (3.81)


along with the boundary conditions which do not change in time:

T (0, τ ) = T0 , T (∞, τ ) = Ts (3.82)


Before we solve the problem numerically, we scale equation (3.80) by the
introduction of the following dimensionless variables:
T − T0 X τ ·α
u= , x= , t= (3.83)
Ts − T0 L L2
where L is a characteristic length. By substitution of the dimensonless
variables in equation (3.83) in (3.80), we get the following:

∂u ∂2u
= , 0<x<∞ (3.84)
∂t ∂x2
accompanied by the dimensionless intitial condition:

u(x, t) = 1, t<0 (3.85)


and dimensionless boundary conditions:

u(0, t) = 0, u(∞, t) = 1 (3.86)


The particular choice of the time scale in t (3.83) has been made to make the
thermal diffusivity vanish and to present the governing partial on a canonical
form (3.84) which has many analytical solutions and a wide range of applications.
The dimensionless time in (3.83) is a dimensjonsløs number, which is commonly
referred to as the Fourier-number.
CHAPTER 3. SHOOTING METHODS 124

We will now try to transform the partial differential equation (3.84) with
boundary conditions (3.85) to a simpler ordinary differential equaitons. We will
do so by introducing som apropriate scales for the time and space coordinates:

x̄ = a x and t̄ = b t (3.87)
where a and b are some positive constants. Substitution of equation (3.87)
into equation (3.84) yields the following equation:

∂u a2 ∂ 2 u
= (3.88)
∂ t̄ b ∂ x̄2
We chose b = a2 to bring the scaled eqution (3.88) on the canonical, dimen-
sionless for of equation (3.84) with the boundary conditions:

u(x, t) = u(x̄, t̄) = u(ax, a2 t), with b = a2 (3.89)


For (3.89) to be independent of a > 0, the solution u(x, t) has to be on the
form:
   2
x x
u(x, t) = f √ , g , etc. (3.90)
t t
and for convenience we choose the first alternative:
 
x
u(x, t) = f √ = f (η) (3.91)
t
where we have introduced a new similarity variable η defined as:
x
η= √ (3.92)
2 t
and the factor 2 has been introduced to obtain a simpler end result only. By
introducing the similariy variable η in equation (3.91), we transfor the solution
(and the differential equation) from being a function of x and t, to only depend
on one variable, namely η. A concequence of this transformation is that one
profile u(η), will define the solution for all x and t, i.e. the solutions will be
similar and is denoted a similarity solution for that reason and (3.92) a similarity
transformation.
The Transformation in equation (3.92) is often referred to as the Boltzmann-
transformation.
The original PDE in equation (3.84) has been transformed to an ODE,
which will become clearer from the following. We have introduced the following
variables:
τ ·α x X
t= , η= √ = √ (3.93)
L2 2 t 2 τα
Let us now solve equation (3.84) analytically and introduce:

u = f (η) (3.94)
CHAPTER 3. SHOOTING METHODS 125

with the boundary conditions:

f (0) = 0, f (∞) = 1 (3.95)


Based on the mathematical representation of the solution in equation (3.94)
we may express the partial derivatives occuring in equation (3.84) as:
   
∂u ∂u ∂n y η
= = f 0 (η) · − √ = −f 0 (η)
∂t ∂η ∂t 4t t 2t
∂2u
   
∂u ∂u ∂η 1 ∂ 1 1
= = f 0 (η) √ , = f 0
(η) √ = f 00 (η)
∂x ∂η ∂x 2 t ∂x2 ∂x 2 t 4t

∂u ∂2u
By substituting the expressions for and in equation (3.84) we
∂t ∂x2
transform the original PDE in equation (3.84) to an ODE in equation (3.96) as
stated above:

1 η
f 00 (η) + f 0 (η) = 0
4t 2t
or equivalently:

f 00 (η) + 2ηf 0 (η) = 0 (3.96)


The ODE in equation (3.96) may be solved directely by integration. First,
we rewrite equation (3.96) as:

f 00 (η)
= −2η
f 0 (η)
which may be integrated to yield:

ln f 0 (η) = −η 2 + ln C1 (3.97)

which may be simplified by and exponential transformation on both sides:


2
f 0 (η) = C1 e−η

and integrated once again to yield:


Z η
2
f (η) = C1 e−t dt (3.98)
0

where we have used the boundary condition f (0) = 0 from (3.95).


The integral in (3.98) is related with the error function:
Z x √
2 π
e−t dt = erf(x)
0 2
CHAPTER 3. SHOOTING METHODS 126

where the error function erf (x) is defined as:


Z x
2 2
√ e−t dt (3.99)
π 0
Substitution of equation (3.99) in equation (3.98) yields:

π
f (η) = C1 erf(η) (3.100)
2
As the error function has the property erf(η) → 1 for η → ∞ we get:
2
C1 = √ , and subsequent substitution of equation (3.100) yields:
π

A similarity solution for the one-dimensional heat equation


 
x
u(x, t) = erf(η) = erf √ (3.101)
2 t

If we wish to express u(x, t) by means of the original variables we have from


equation (3.83):
 
T (X, τ ) − T0 X
= erf √ (3.102)
Ts − T0 2 τ ·α
In Figure 3.14 the error function erf(η), which is a solution of the one-
dimensional heat equation (3.84), is plotted along with the complementary error
function erfc(η) defined as:
Z ∞
2 2
erfc(η) = 1 − erf(η) = √ e−t dt (3.103)
π η

3.3.1 Example: Freezing of a waterpipe


A dry layer of soil at initial temperature 20◦ C, is in a cold periode exposed to a
suface temperature of −15◦ C in 30 days and nigths. The question of concern is
how deep the waterpipe must be located in order to avoid that the water in the
pipe starts freezing?
The thermal diffusivity is termiske diffusiviteten α = 5 · 10−4 m2 /hour. With
reference to (3.81) we have T0 = −15◦ C and Ts = 20◦ C, and τ = 30 days and
nigths = 720 hours, and water freezes at 0◦ C.
From (3.83):

T − T0 0 − (−15) 3
u= = = = 0.4286
Ts − T0 20 − (−15) 7
Some values for erf(η) are tabulated below :
CHAPTER 3. SHOOTING METHODS 127

1.0

0.8

0.6
erf
erf , erfc
erfc
0.4

0.2

0.00.0 0.5 1.0 1.5 2.0

Figure 3.14: The error function is a similarity solution of the one-dimensional


heat equation expressed by the similarity variable η.

x erf(η) η erf(η)
0.00 0.00000 1.00 0.84270
0.20 0.22270 1.20 0.91031
0.40 0.42839 1.40 0.95229
0.60 0.60386 1.60 0.97635
0.80 0.74210 1.80 0.98909

From tabular values for Fra tabellverdi for erf(x) og (3.101) finner vi erf(η) =
0.4286 → η ≈ 0.4 som med (3.93) gir:
√ √
X = 0.4 · 2 τ · α = 0.8 · 720 · 5 · 10−4 = 0.48m
Vi har regnet med konstant diffusivitet α, mens den kan variere i intervallet
α ∈ [3 · 10−4 , 10−3 ]m2 /time. Dessuten vil jorda normalt ikke være tørr.

3.3.2 Example: Stokes 1. problem

Y U=0

U(Y,τ)
U = U0

Figure 3.15: Marit 1: description


CHAPTER 3. SHOOTING METHODS 128

Vi har en stillestående fluid ved τ < 0 . Ved tiden τ = 0 får plata som er
parallell med X-aksen, en konstant hastighet U = U0 parallelt med X-aksen.
Plata må betraktes som uendelig tynn med uendelig utstrekning i X-retning
for en korrekt matematisk beskrivelse i dette tilfellet. Navier-Stokes ligning i
X-retning for inkompressibel strømning:
 2
∂2U

∂U ∂U ∂U 1 ∂p ∂ U
+U +V =− +ν +
∂τ ∂X ∂Y ρ ∂X ∂X 2 ∂Y 2
(Se utledning i appendiks B i Numeriske Beregninger)
Antar at løsningen av dette problemet er uavhengig av X, samt at V = 0
som betyr at U = U (Y, τ ):

∂U ∂2U
=ν , 0<Y <∞ (3.104)
∂τ ∂Y 2
Initialbetingelse:

U (U, 0) = 0 (3.105)
Randbetingelser:

U (0, τ ) = U0 (heftbet.)
(3.106)
U (∞, τ ) = 0
Innfører følgende dimensjonsløse variable:
U Y τ ·ν
u= , y= , t= 2 (3.107)
U0 L L
der U0 og L er henholdsvis en karakteristisk hastighet og lengde. (3.107)
innsatt i (3.104) gir følgende ligning:

∂u ∂2u
= , 0<y<∞ (3.108)
∂t ∂y 2
Initialbetingelse:

u(y, 0) = 0 (3.109)
Randbetingelser:

u(0, t) = 1
(3.110)
u(∞, t) = 0
Vi ser at vi har fått samme ligning og problem som i (3.84) og (3.85), bare
med en ombytting av 0 og 1 i randbetingelsene. Løsningen av (3.108) og (3.109)
med randbetingelser (3.110) blir:
 
y
u(y, t) = 1 − erf(η) = erfc(η) = erfc √ (3.111)
2 t
CHAPTER 3. SHOOTING METHODS 129

eller uttrykt ved dimensjonelle variable:


 
Y
U (Y, τ ) = U0 erfc √ (3.112)
2 τ ·ν

3.3.3 Example: Blasius-ligningen

U = constant
y

v δ

Figure 3.16: Marit 1: description

En detaljert utledning er gitt i appendiks C, del C.2 i Numeriske Beregninger.


Gjengir noe av utledningen her for oversiktens skyld. For en stasjonær og
inkompressibel grensesjikt-strømning, får vi fra lign. (C.1.10) i appendiks C i
Numeriske Beregninger:
∂u ∂v
+ =0 (3.113)
∂x ∂y
∂u ∂u 1 dp ∂2u
u +v =− +ν 2 (3.114)
∂x ∂y ρ dx ∂y
Ser på det tilfellet at fristrømshastigheten U er konstant = U0 . Bernoullis
ligning (C.1.8) i appendiks C i Numeriske Beregninger gir for dette tilfellet
dp
dx = 0.
(3.114) forenkler seg til:

∂u ∂u ∂2u
u +v =ν 2 (3.115)
∂x ∂y ∂y
Randbetingelser:

u(0) = 0 (3.116)
u → U0 for y → δ (3.117)

For å oppfylle kontinuitetsligningen (3.113), innfører vi strømfunksjonen


ψ(x, y) definert ved:
∂ψ ∂ψ
u= , v=− (3.118)
∂y ∂x
CHAPTER 3. SHOOTING METHODS 130

Vi definerer et Reynoldstall:
U0 x
Rex = (3.119)
ν
Innfører følgende likedannhetsvariable for koordinat og strømfunksjon:
r
U0 ψ
η= · y og f (η) = √ (3.120)
2νx 2Uo νx
Transformasjonen (3.120) gir Blasius-ligningen for strømfunksjonen f :

f 000 (η) + f (η) · f 00 (η) = 0 (3.121)


df
Notasjon: ≡ f 0 (η) og tilsvarende for høyere deriverte. De fysikalske

hastighetskomponentene er gitt ved:

u v η · f 0 (η) − f (η)
= f 0 (η), = √ (3.122)
U0 U0 2Rex
Heftbetingelsen u = 0 for y = 0 blir nå f 0 (0) = 0 da f 0 (η) = Uu0 fra (3.122).
Uten suging eller blåsing gjennom randen η = 0, blir den andre heftbetingelsen
v = 0 for η = 0. Fra (3.122) blir denne betingelsen f (0) = 0. Betingelsen
u → U0 fra (3.117), blir nå f 0 (η) → 1 for η → ∞. Randbetingelsene for
ugjennomstrømmelig sjikt blir da:

f (0) = f 0 (0) = 0, f 0 (η∞ ) = 1 (3.123)


Skjærspenningen:
r
00 U0
τxy = µU0 · f (η) (3.124)
2νx

Numerisk løsning
Vi ønsker å løse (3.121) sammen med randbetingelsene i (3.123) ved bruk av
skyteteknikk og skriver derfor ligningen som et sett av tre 1. ordens differensial-
ligninger:

f 0 = f1 (3.125)
f10 = f2 (3.126)
f20 = −f · f2 (3.127)

Randbetingelser:

f (0) = f1 (0) = 0
(3.128)
f1 (η∞ ) = 1
Setter f 00 (0) = f2 (0) = s
CHAPTER 3. SHOOTING METHODS 131

s, som i dette tilfellet er skjærspenningen ved veggen, må bestemmes slik at


randbetingelsen f1 (η∞ ) = 1 blir oppfylt. Dette siste kravet kan formuleres på
følgende måte:

φ(s) = f1 (η∞ ; s) − 1 (3.129)


∗ ∗
med rett verdi s = s når φ(s ) = 0 Vi velger å bruke sekantmetoden til
nullpunktsbestemmelsen i (3.129).

Iterasjonsprosess
Iterasjonsprosessen ved bruk av sekantmetoden, er gitt ved:

sm − sm−1
 
m+1 m m
s = s + δs, δs = −φ(s ) · , m = 1, 2. . . . (3.130)
φ(sm ) − φ(sm−1 )

Antar at sm−1 og sm er kjent.

1. Beregn φ(sm−1 ) og φ(sm ) ved å løse(3.126).


2. Beregn δs og sm+1 fra (3.130)
3. Sett
• sm−1 ← sm
• sm ← sm+1
• φ(sm−1 ) ← φ(sm )

Gjenta skritt 1–3 inntil konvergens er oppnådd.


I dette tilfellet er korrekt verdi s∗ = 0.46960... slik at konvergenskriteriet
tilslutt blir δs < ε, dvs. en absolutt test. Under prosessen kan vi ha s > 1 og da
δs
testes , altså en relativ test.
s
La oss se litt nærmere på hvordan vi finner passende startverdier s0 og s1
for å komme igang med iterasjonsprosessen. Den vanligvis enkleste måten å
få oversikt over nullpunktene for en funksjon på, er å framstille funksjonen
grafisk. Figure 3.17 visreer φ(s) der s ∈ [0.05, 0.8]. Beregningen er gjort
med Pythonprogrammet phi_plot_blasius_shoot_v2 . Av figuren ser vi at
nullpunktet ligger i intervallet [0.45, 0.5]. Vi ser også at vi har et stort spillerom
ved valg av s0 og s1 .
# src-ch2/phi_plot_blasius_shoot_v2.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch2/ODEschemes.py;

from ODEschemes import euler, heun, rk4


from matplotlib.pyplot import *
# Change some default values to make plots more readable on the screen
LNWDT=3; FNT=20
matplotlib.rcParams[’lines.linewidth’] = LNWDT; matplotlib.rcParams[’font.size’] = FNT
CHAPTER 3. SHOOTING METHODS 132

def fblasius(y, x):


"""ODE-system for the Blasius-equation"""
return [y[1],y[2], -y[0]*y[2]]

solvers = [euler, heun, rk4] #list of solvers


solver=solvers[2] # select specific solver

from numpy import linspace, exp, abs


xmin = 0
xmax = 5.75

N = 50 # no x-values
x = linspace(xmin, xmax, N+1)

# Guessed values
#s=[0.1,0.8]
s_guesses=np.linspace(0.01,5.0)

z0=np.zeros(3)
beta=1.0 #Boundary value for eta=infty

phi = []
for s_guess in s_guesses:
z0[2] = s_guess
u = solver(fblasius, z0, x)
phi.append(u[-1,1] - beta)
plot(s_guesses,phi)

title(’Phi-function for the Blasius equation’)


ylabel(’phi’)
xlabel(’s’)
grid(b=True, which=’both’)
show()

Figure 3.17: Marit 1: description


CHAPTER 3. SHOOTING METHODS 133

6
f'( ) - velocity
5 f''( ) - wall shear stress

0
0.0 0.2 0.4 0.6 0.8 1.0 1.2

Figure 3.18: Marit 1: description

Figure 3.18 viser den dimensjonsløse u-hastigheten f 0 (η) og den dimen-


sjonsløse skjærspenningen f 00 (η) som beregnet i tabellen på neste side. Den
maksimale verdien av f 00 (η) inntreffer for η = 0 , som igjen betyr at skjærspen-
ningen er størst ved veggen. Legg merke til at f 000 (0) = 0 som betyr at f 00 (η)
har vertikal tangent på veggen. Tabellen nedenfor er beregnet med programmet
blasius_shoot_v2:
# src-ch2/blasius_shoot_v2.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch2/ODEschemes.py;

from ODEschemes import euler, heun, rk4


from matplotlib.pyplot import *
# Change some default values to make plots more readable on the screen
LNWDT=3; FNT=20
matplotlib.rcParams[’lines.linewidth’] = LNWDT; matplotlib.rcParams[’font.size’] = FNT

def fblasius(y, x):


"""ODE-system for the Blasius-equation"""
return [y[1],y[2], -y[0]*y[2]]

def dsfunction(phi0,phi1,s0,s1):
if (abs(phi1-phi0)>0.0):
return -phi1 *(s1 - s0)/float(phi1 - phi0)
else:
return 0.0
solvers = [euler, heun, rk4] #list of solvers
solver=solvers[0] # select specific solver

from numpy import linspace, exp, abs


xmin = 0
xmax = 5.750
N = 400 # no x-values
x = linspace(xmin, xmax, N+1)
CHAPTER 3. SHOOTING METHODS 134

# Guessed values
s=[0.1,0.8]

z0=np.zeros(3)
z0[2] = s[0]

beta=1.0 #Boundary value for eta=infty


## Compute phi0

u = solver(fblasius, z0, x)
phi0 = u[-1,1] - beta

nmax=10
eps = 1.0e-3
for n in range(nmax):
z0[2] = s[1]
u = solver(fblasius, z0, x)
phi1 = u[-1,1] - beta
ds = dsfunction(phi0,phi1,s[0],s[1])
s[0] = s[1]
s[1] += ds
phi0 = phi1
print ’n = {} s1 = {} and ds = {}’.format(n,s[1],ds)

if (abs(ds)<=eps):
print ’Solution converged for eps = {} and s1 ={} and ds = {}. \n’.format(eps,s[1],ds)
break

plot(u[:,1],x,u[:,2],x)
xlabel(’u og u\’’)
ylabel(’eta’)

legends=[]
legends.append(’velocity’)
legends.append(’wall shear stress’)
legend(legends,loc=’best’,frameon=False)
title(’Solution of the Blaisus eqn with ’+str(solver.func_name)+’-shoot’)
show()
close() #Close the window opened by show()

itr. s ds
1 0.471625 - 2.837e-002
2 0.469580 - 2.046e-003
3 0.469601 2.146e-005
4 0.469601 - 1.540e-008
CHAPTER 3. SHOOTING METHODS 135

η f f’ f"
0.00 0.000000 0.000000 4.69601e-001
0.25 0.014673 0.117364 4.69027e-001
0.50 0.058643 0.234228 4.65032e-001
0.75 0.131642 0.349324 4.54373e-001
1.00 0.232991 0.460634 4.34380e-001
1.25 0.361431 0.565601 4.03495e-001
1.50 0.515032 0.661476 3.61805e-001
1.75 0.691201 0.745765 3.11302e-001
2.00 0.886798 0.816697 2.55671e-001
2.25 1.098374 0.873559 1.99544e-001
2.50 1.322442 0.916810 1.47476e-001
2.75 1.555766 0.947928 1.02930e-001
3.00 1.795573 0.969057 6.77108e-002
3.25 2.039661 0.982573 4.19262e-002
3.50 2.286412 0.990711 2.44148e-002
3.75 2.534723 0.995319 1.33643e-002
4.00 2.783894 0.997773 6.87412e-003
4.25 3.033509 0.999000 3.32201e-003
4.50 3.283340 0.999577 1.50841e-003
4.75 3.533271 0.999832 6.43473e-004
5.00 3.783244 0.999938 2.57831e-004
5.25 4.033235 0.999980 9.70546e-005
5.50 4.283232 0.999995 3.43646e-005
5.75 4.533231 1.000000 1.15317e-005

3.3.4 Example:Falkner-Skan ligningen


Blasius ligning er egentlig et spesialtilfelle av en mer generell ligning som kalles
Falkner-Skan ligningen. Falkner-Skan tranformasjonen (1930) overfører grens-
esjiktligningen til en likedannhetsform gitt ved:

f 000 + f f 00 + β · [1 − (f 0 )2 ] = 0 (3.131)
når fristrømshastigheten U (x) er gitt ved:

U (x) = U0 xm , m = konstant (3.132)


(3.131) kalles også kilestrømsligningen fordi parameteren β har den ge-
ometriske betydningen som vist i Figure 3.19:
Vi ser at halve kilevinkelen er β · π2 . For β = 0, får vi følgelig en flat plate,
og (3.131) blir da Blasius ligning.
En detaljert utledning er gitt i appendiks C, del C.3 i Numeriske Beregninger.
Vi gjengir noe av utledningen for oversiktens skyld.
2m β
Sammenheng mellom m og β: β = m+1 og m = 2−β Vi ser at β = 0 gir
U (x) = U0 .
CHAPTER 3. SHOOTING METHODS 136

U0
η

π
β
2
π
β
2

Figure 3.19: Marit 1: description

Falkner-Skan transformasjonen er gitt ved:


s
U ψ
η= · y, f (η) = p (3.133)
(2 − β)νx (2 − β)U νx
Dersom vi velger de samme randbetingelsene som i eksempel (3.3.3), får vi:
F-S - ligningen:

f 000 + f f 00 + β · [1 − (f 0 )2 ] = 0 (3.134)
Randbetingelser:

f (0) = f 0 (0) = 0
(3.135)
f 0 (η∞ ) = 1
Vi løser ligningen på samme måte som Blasius ligning ved å skrive (3.134)
som et sett av 1. ordens differensialligninger:

f 0 = f1 (3.136)
f10 = f2 (3.137)
f20 = −[f f2 + β(1 − f12 )] (3.138)

Randbetingelser:

f (0) = f1 (0) = 0
(3.139)
f1 (η∞ ) = 1
Med f 00 (0) = f2 (0) = s, får vi:

φ(s) = f1 (η∞ ; s) − 1 (3.140)


∗ ∗
med korrekt verdi s når φ(s ) = 0
Flere detaljer om løsningsprosessen er gitt i appendiks C, del C.3 i Numeriske
Beregninger.
Bestemmelse av startverdier.
CHAPTER 3. SHOOTING METHODS 137

Vi bruker sekantmetoden for å finne nullpunktet i (3.140) og trenger derfor to


startverdier s0 og s1 for å starte iterasjonsprosessen. Velger tilfellet med β = 1
som er strømning mot en flat plate, dvs.: en stagnasjonsstrøm, se Figure 3.20.
Dette tilfellet kalles også en Hiemenz-strømning.

U = U0∙x

Figure 3.20: Marit 1: description

−1

=4
−2 =5
=6
−3
0.8 0.9 1.0 1.1 1.2 1.3
s

Figure 3.21: Marit 1: description

φ(s) er tegnet i Figure 3.21. Beregningen er utført med bruk av ode45.


Marie 8: Matlab-funksjon
Det korrekte nullpunktet er s∗ = 1.23259 som er den entydige løsningen av
F-S-ligningen for η → ∞ med β = 1. Dersom vi ser på kurven for η∞ = 5.0,
finner vi et nullpunkt rundt s = 0.85 og et rundt s = 1.23 der det siste er det
korrekte. Årsaken er at F-S-ligningen har to løsninger for endelige verdier av η∞
der det venstre nullpunktet beveger seg mens det andre som er det korrekte for
η → ∞, ligger fast. Begge nullpunktene gir korrekte løsninger av diff.ligningen,
men det venstre nullpunktet gir en løsning som fører til avløsning og tilbake-
strømning, noe som er ufysikalsk i dette tilfellet. Legg merke til at avstanden
mellom nullpunktene minsker med økende verdi av η∞ , og med η → ∞ vil de to
grenene falle sammen.
CHAPTER 3. SHOOTING METHODS 138

Dersom vi bruker en løser med konstant skrittlengde, f.eks RK4, og samtidig


velger en forholdsvis stor skrittlengde, f. eks. ∆η = 0.2, vil vi få en rekke
andre nullpunkt. Disse nullpunktene gir løsning av differanseligningen, men er
ikke løsning av differensialligningen. Ved å la ∆η → 0, vil disse nullpunktene
forsvinne også for store η∞ -verdier.
Figure 3.22 og Figure 3.23 viser noen resultater fra Matlab-programmet
fsksec. Marie 9: Matlab-program for ulike verdier av β. marit 10: viser
nå resultatet fra python programmene fig22.py og fig23.py

6
= -0.198837
5 = -0.15
=0
= 0.3
4
=1

0
0.0 0.2 0.4 0.6 0.8 1.0
f'

Figure 3.22: Marit 1: description

6
= -0.198837
5 = -0.15
=0
= 0.3
4
=1

0
0.0 0.2 0.4 0.6 0.8 1.0 1.2
f''

Figure 3.23: Marit 1: description

For β = βsep = −0.19883768 . . . forsvinner skjærspenningen ved veggen.


Dette indikerer begynnende tilbakestrømning og separasjon, se Figure 3.24.
CHAPTER 3. SHOOTING METHODS 139

separation

-17.9°
β = -0.1988... ≈ -17.9°

Figure 3.24: Marit 1: description

Det finnes løsninger av F-S-ligningen for β-verdier som ligger utenfor det
området vi fysisk kan knytte til en kilestrøm. For mer informasjon om disse
løsningene, henvises til Evans [5], White [24], og Schlichting [21].
Tilslutt bør det nevnes at det finnes en analytisk løsning av F-S-ligningen.
Vi tenker oss at det er plassert et sluk i x = 0 med r styrke K parallelt med
K y K
platekanten. I dette tilfellet blir U (x) = − og η = .
x x ν
Ligningen blir nå:
2
f 000 (η) − (f 0 (η)) + 1 = 0 (3.141)
med de vanlige randbetingelsene

f (0) = f 0 (0) = 0 (3.142)


0
f (η∞ ) = 1 (3.143)

Løsningen kan da skrives:

√ √
f (η) = η + 2 3 − 3 2 · tanh(z) (3.144)
0 2
f (η) = 3 tanh (z) − 2 (3.145)

f 00 (η) = 3 2 · tanh(z) · [1 − tanh2 (z)] (3.146)

Spesielt har vi:


2
f 00 (0) = √ = 1.1547 . . .
3
√ √
Merk at en funksjon f (η) = η + a − 3 2 · tanh(η/ 2 + b) tilfredstiller (3.141)
for vilkårlige verdier av a og b med f 0 (∞) = 1.
CHAPTER 3. SHOOTING METHODS 140

ϕ,Ψ

ϕ = A∙s + B∙r + C

Ψ = D∙s + E∙r + F

r
Ψ=0
(s*,r*)
ϕ=0
s

Figure 3.25: Marit 1: description

3.4 Skyting med to startbetingelser


3.4.1 Lineære ligninger
Vi vil nå utvide teknikken som vi brukte i avsnitt (3.1) til to ukjente start-
betingelser. I dette tilfellet må vi tippe to startbetingelser r og s med tilhørende
funksjoner φ og ψ. Dette er vist grafisk i Figure 3.25. Da ligningen som skal
løses er lineær, danner φ ogψ to plan og kan derfor skrives på formen:

φ=A·s+B·r+C
(3.147)
ψ =D·s+E·r+F
der A, B, C, · · · , F er konstanter som må bestemmes. De rette verdiene r∗ og
s finnes fra φ(r∗ , s∗ ) = 0 og ψ(r∗ , s∗ ) = 0. (Se figuren) Vi har seks konstanter

som bestemmes fra ligningene:

φ0 = A · s0 + B · r0 + C (3.148)
1 1 1
φ =A·s +B·r +C (3.149)
(2) (2) (2)
φ =A·s +B·r +C (3.150)
(3.151)
CHAPTER 3. SHOOTING METHODS 141

ψ 0 = D · s0 + E · r0 + F (3.152)
1 1 1
ψ =D·s +E·r +F (3.153)
(2) (2) (2)
ψ =D·s +E·r +F (3.154)
(3.155)

der s0 , s1 , s(2) , r0 , r1 og r(2) er verdier som vi har tippet for initial-


betingelsene.For å forenkle slutt-resultatet, velger vi følgende verdier:

1) s0 = 0, r0 = 0 (3.156)
1 1
2) s = 0, r = 1 (3.157)
(2) (2)
3) s = 1, r =0 (3.158)

Vi får da følgende uttrykk for konstantene:

C = φ0 , B = φ1 − φ0 , A = φ(2) − φ0
(3.159)
F = ψ 0 , E = ψ 1 − ψ 0 , D = ψ (2) − ψ 0

De korrekte verdiene r∗ og s∗ finnes fra φ(r∗ , s∗ ) = 0 og ψ(r∗ , s∗ ) = 0 som


her blir A · s∗ + B · r∗ + C = D · s∗ + E · r∗ + C = 0 med følgende løsning:
E·C −B·F A·F −D·C
s∗ = , r∗ =
D·B−A·E D·B−A·E
som innsatt for A, B, C, . . . , F gir:
ψ 1 ·φ0 −φ1 ·ψ 0
s∗ = (ψ (2) −ψ 0 )·(φ1 −φ0 )−(φ(2) −φ0 )·(ψ 1 −ψ 0 )
(3.160)
∗ φ(2) ·ψ 0 −ψ (2) ·φ0
r = (ψ (2) −ψ 0 )·(φ1 −φ0 )−(φ(2) −φ0 )·(ψ 1 −ψ 0 )

Fremgangsmåten blir da som følger:


Vi løser ligningsystemet for de tre settene av verdier for r og s gitt i (3.157)
og finner derved de tilhørende verdiene av φ og ψ. De korrekte verdiene r∗ og
s∗ finnes da fra (3.160)). Vi skal bruke denne prosedyren i eksempel (3.4.2)

3.4.2 Example: Sylindrisk tank med væske


DEL 1: Konstant veggtykkelse
Figure 3.26 viser en sylindrisk tank fylt med en væske til en høyde H. W er
radiell forskyvning. På detaljen til venstre er V skjærkraft pr. lengdeenhet og
M moment pr. lengdeenhet. Pilene angir positiv retning.
Differensialligningen for forskyvningen W er gitt ved:

d4 W H −X
4
+ B · W = −γ (3.161)
dX D
CHAPTER 3. SHOOTING METHODS 142

R
g
t

M X
V W
V H
M

Figure 3.26: Marit 1: description

12(1 − ν 2 ) Et3
der B = , D = , γ = ρg
R2 t2 12(1 − ν 2 )
Her er ν Poissons tall, E elastisitetsmodelen og ρ væskas tetthet.
Innfører dimensjonsløse størrelser:
 2
X E t
x= og w = · ·W (3.162)
H γHt R
som innsatt i (3.161) gir følgende differensialligning:

d4 w
+ 4β 4 · w = −4β 4 (1 − x) (3.163)
dx4
der

3(1 − ν 2 )H 4
β4 = (3.164)
R2 t2
Randverdier.
For x = 0:
dW
W = 0,= 0 (Fast innspent)
dX
Skjærkraft og moment = 0 for X = H som gir:

d2 W d3 W
M = −D 2
= 0, V = −D =0
dX dX 3
Randverdiene uttrykt ved dimensjonsløse størrelser blir da:
dw
For x = 0 : w = 0, dx3 = 0
2 (3.165)
For x = 1 : ddxw2 = 0, d w
dx3 = 0
CHAPTER 3. SHOOTING METHODS 143

d2 w
Dimensjonsløst moment m(x) = − og dimensjonsløs skjærkraft v(x) =
dx2
d3 w
− . Se appendiks D for flere detaljer.
dx3
Velger en en tank av betong med følgende dimensjoner:

R = 8.5m, H = 7.95m, t = 0.35m


(3.166)
γ = 9810N/m3 (vann), ν = 0.2, E = 2 · 104 MPa
Med disse data blir β = 6.0044.

Numerisk beregning
Setter w = y1 , w0 = y10 = y2 , w00 = y20 = y3 , w000 = y30 = y4 og skriver (3.161)
som et system av fire 1. ordens differensialligninger:

y10 = y2
y20 = y3
(3.167)
y30 = y4
0
y4 = −4β 4 (y + 1 − x)
med følgende randbetingelser:

y1 (0) = 0, y2 (0) = 0, y3 (1) = 0, y4 (1) = 0 (3.168)


Skal bestemme s = w00 (0) = y3 (0) og r = w000 (0) = y4 (0) slik at y3 (1) og
y4 (1) = 0. Setter følgelig φ(r, s) = y3 (1; r, s) og ψ(r, s) = y4 (1; r, s). De korrekte
verdiene r∗ og s∗ gir da φ(r∗ , s∗ ) = 0. Løser følgelig (3.167) tre ganger med y1 (0)
og y2 (0) = 0 mens verdiene for r og s velges fra (3.157). De korrekte verdiene r∗
og s∗ beregnes deretter fra (3.160).
Utsnitt av programmet tank1 samt utskrift er vist nedenfor. Marie 9:
Matlab-program
x w dw/dx m(x) v(x)
0.000 0.00000e+000 0.00000e+000 6.00946e+001 -7.93776e+002
0.100 -1.89049e-001 -2.86464e+000 4.85241e+000 -3.36907e+002
0.200 -4.57346e-001 -2.19767e+000 -1.36887e+001 -6.60901e+001
0.300 -6.03796e-001 -7.32255e-001 -1.38468e+001 4.15724e+001
0.400 -6.16145e-001 3.93069e-001 -8.41051e+000 5.74987e+001
0.500 -5.43811e-001 9.70524e-001 -3.44813e+000 3.94237e+001
0.600 -4.35148e-001 1.15559e+000 -6.10973e-001 1.81108e+001
0.700 -3.18861e-001 1.15307e+000 4.27833e-001 4.09131e+000
0.800 -2.06030e-001 1.10306e+000 4.68862e-001 -2.15847e+000
0.900 -9.76194e-002 1.07014e+000 1.76515e-001 -2.96401e+000
1.000 8.92555e-003 1.06379e+000 1.20446e-004 6.10070e-004

Vi ser at vi har god overenstemmelse når vi sammenligner med den analytiske


løsningen i tabell 1 i appendiks D i Numeriske Beregninger. Figure ?? nedenfor
viser forløpet av det dimensjonsløse momentet samt skjærkrafta.
(3.163) er av typen der den høyeste deriverte er multiplisert med et lite tall
ε der ε = 4β1 4 i vårt tilfelle. Kalles gjerne en singulær ligning dersom vi tillater
CHAPTER 3. SHOOTING METHODS 144

at β → ∞. Dette gjenspeiler seg i den analytiske løsningen i lign. (D.1.6) og


(D.1.8), del D.1, i appendiks D i Numeriske Beregninger der vi har ledd av typen
eβx sin βx og eβx cos βx.
Dette betyr at skytelengden i praksis er lik β. Det vil da bli mer og mer
vanskelig å treffe randen x = 1 med økende β-verdier. For store β-verdier vil
deformasjonen konsentrere seg rundt x = 0 slik at det kanskje ikke er nødvendig
å skyte helt til x = 1, men kan greie oss med en mindre verdi.
∂2m
Nedenfor har vi beregnet innspenningsmomentet m0 = − 2 og skjærkrafta
∂x x=0
∂2v

v0 = − 2 som funksjon av skytelengden. Merk at m0 = −s∗ og v0 = −r∗ .
∂x x=0

Skytelengde m0 −v0
1.0 60.098 793.809
0.9 60.093 793.715
0.8 60.099 793.670
0.7 60.079 793.598
0.6 59.816 791.835
0.5 58.879 781.541

DEL 2: Lineært variabel veggtykkelse

R
g t1

M X W
H
V
V
M

t0

Figure 3.27: Marit 1: description

Her varierer veggtykkelsen lineært fra t0 nederst til t1 øverst.


t0 − t1
Med α = kan veggtykkelsen t skrives:
t0
 
X
t= 1−α · t0 , 0 ≤ X ≤ H (3.169)
H
CHAPTER 3. SHOOTING METHODS 145

Differensialligningen for forskyvningen W er nå gitt ved:

d2
 2 
d W tW
2
D 2
+ E 2 = −γ(H − X) (3.170)
dX dX R
Et3
der D = , γ = ρg
12(1 − ν 2 )
Konstantene har samme betydning som i del 1. (Se appendiks D i Numeriske
Beregninger for flere detaljer).

Dimensjonsløs form
2
3(1 − ν 2 )

X E t0
x= , w= · W, β 4 = · H4 (3.171)
H γHt0 R R2 t20
(3.171) innsatt i (3.170):

d2 2
 
3d w
(1 − αx) + 4β 4 (1 − αx) · w = −4β 4 (1 − x) (3.172)
dx2 dx2
Utderivert:

d4 w(x) 6α d5 w(x) 6α2 d2 w(x) 4β 4 4β 4 (1 − x)


− + + w(x) = −
dx4 (1 − αx) dx5 (1 − αx)2 dx2 (1 − αx)2 (1 − αx)5
(3.173)
Dette systemet kan også løses analytisk, se appendiks D, del D.2 i Numeriske
Beregninger, men matematikken er mer komplisert fordi løsningen blir uttrykt
meden spesiell type Besselfunksjoner som kalles Kelvinfunksjoner. Den numeriske
fremgangsmåten er derimot uforandret.
Velger samme tank som i del 1 med tillegg for varierende veggtykkelse:

R = 8.5m, H = 7.95m, t0 = 0.35m, t1 = 0.1m


(3.174)
γ = 9810N/m3 (vann), ν = 0.2, E = 2 · 104 MPa
t0 −t1 5
Her blir α = t0 = 7 og som tidligere blir β = 6.0044.

Numerisk beregning
Setter w = y1 , w0 = y10 = y2 , w00 = y20 = y3 , w000 = y30 = y4 , z = 1 − αx og
skriver (3.169) som et system av fire 1. ordens differensialligninger:

y10 = y2
y20 = y3
y30 = y4 (3.175)
6α2
4
4β 4 (1−x)
y4 = z y4 − z2 y3 − 4β
0 6α
z 2 y1 − z3

med følgende randbetingelser:

y1 (0) = 0, y2 (0) = 0, y3 (1) = 0, y4 (1) = 0 (3.176)


CHAPTER 3. SHOOTING METHODS 146

Fremgangsmåten blir som for del 1, bortsett fra at vi nå har parameteren


α i tillegg til β. Programmet tank2 blir derfor nesten identisk med tank1.
Hovedforskjellen er funksjonen fcntank2 for diff. ligningen. Marie 18: Matlab

x w dw/dx m(x) v(x)

0.000 0.00000e+000 0.00000e+000 6.23338e+001 -7.73773e+002


0.100 -2.15376e-001 -3.45545e+000 9.04151e+000 -3.18887e+002
0.200 -5.66553e-001 -3.16644e+000 -8.14798e+000 -5.86193e+001
0.300 -8.05113e-001 -1.53673e+000 -8.34542e+000 3.32725e+001
0.400 -8.79417e-001 -3.87614e-002 -4.36688e+000 3.81223e+001
0.500 -8.34707e-001 8.24809e-001 -1.47715e+000 1.90313e+001
0.600 -7.31823e-001 1.17417e+000 -3.81333e-001 4.52213e+000
0.700 -6.05528e-001 1.35136e+000 -2.49403e-001 -5.41818e-001
0.800 -4.57651e-001 1.63752e+000 -3.00683e-001 8.66313e-002
0.900 -2.72819e-001 2.06404e+000 -1.83081e-001 2.16427e+000
1.000 -5.26758e-002 2.26301e+000 3.87892e-005 -1.76069e-006

Vi finner god overenstemmelse ved å sammenligne med den analytiske løs-


ningen i tabell 7, del D.2 i appendiks D i Numeriske Beregninger.

3.4.3 Eksempel på ikke-lineære ligninger


Figure ?? viser et fluidsjikt med initiell hastighet U1 som strømmer over et
annet sjikt med initiell hastighet U2 . Da sjiktene må ha samme hastighet og
skjærspenning langs den felles grenseflata, oppstår det et skjærsjikt som vist
på figuren. For enkelhets skyld antar vi samme fluid i begge sjiktene. Antar
dessuten at Blasius ligning beskriver skjærsjiktet.
For begge sjiktene:

f 000 (η) + f (η) · f 00 (η) = 0 (3.177)


med randbetingelser:

f (0) = 0 (3.178)
f 0 (η∞ ) = 1 (3.179)
U2
f 0 (−η∞ ) = (3.180)
U1
Merk her at η ≥ 0 for det øvre sjiktet og η ≤ 0 for det nedre sjiktet. Vi har
definert koordinaten η og strømfunksjonen f (η) på følgende måte:
q
U1
η = 2νx ·y
(3.181)
f 0 (η) = U (x,y)
U1

(Sammenlign med lign. (C.2.7), appendiks C, del C.2 i Numeriske Bereg-


ninger)
CHAPTER 3. SHOOTING METHODS 147

I dette tilfellet er både hastigheten f 0 (0) og skjærspenningen f 00 (0) ukjente,


slik at vi må tippe to initialbetingelser når vi skal bruke skyteteknikk.
Får totalt følgende tre initialbetingelser:

f (0) = 0, f 0 (0) = r, f 00 (0) = s (3.182)


De to ukjente initialbetingelsene må velges slik at randbetingelsene (3.179)
og (3.180) blir oppfylt. Vi skriver dette på følgende måte:

φ(η∞ ; r, s) = f 0 (η∞ ; r, s) − 1 = 0 for s = s∗ , r = r∗ (3.183)

U2
ψ(−η∞ ; r, s) = f 0 (−η∞ ; r, s) − = 0 for s = s∗ , r = r∗ (3.184)
U1
Istedenfor å bruke negative verdier for η for det nedre sjiktet, velger vi å
innføre koordinaten ζ der ζ = −η. Får da følgende system:

I. For det øvre sjiktet:

f 000 (η) + f (η) · f 00 (η) = 0 (3.185)


med rand - og initialbetingelser:

f 0 (η∞ ) = 1 (3.186)
f (0) = 0, f 0 (0) = r, f 00 (0) = s (3.187)
0
φ(η∞ ; r, s) = f (η∞ ; r, s) − 1 = 0 (3.188)

II. For det nedre sjiktet:

f 000 (ζ) − f (ζ) · f 00 (ζ) = 0 (3.189)


med rand - og initialbetingelser:

U2
f 0 (ζ∞ ) = − (3.190)
U1
f (0) = 0, f 0 (0) = −r, f 00 (0) = s (3.191)
U2
ψ(ζ∞ ; r, s) = f 0 (ζ∞ ; r, s) + =0 (3.192)
U1
Merk at derivasjon er m. h. p. koordinaten ζ i det nedre sjiktet.
Da ζ = −η, får vi for eksempel:

df (ζ) df (η) dη df (η) df (η)


= · = · (−1) = −
dζ dη dζ dη dη
CHAPTER 3. SHOOTING METHODS 148

Oppgava blir da å løse (3.185), (3.187) og (3.188) simultant med (3.189),


(3.191) og (3.192). Dette betyr at vi må finne verdier av r og s slik at (3.188)
U2
og (3.192) er tilfredstilt. Dette må gjøres for alle aktuelle verdier av der
U1
U2
∈ [0, 1].
U1
Vi har da det gamle problemet med å finne gode nok startverdier for r og s
når vi skal beregne nullpunktene av (3.188) og (3.192). Vi går fram som tidligere
ved å beregne φ(η∞ ; r, s) og ψ(ζ∞ ; r, s) for passende verdier av η∞ , ζ∞ , r og s
og deretter tegne funksjonene. La oss se nærmere på framgangsmåten.
Vi skal finne de verdiene av r og s som er nullpunkter både i (3.188) og
(3.192). Fra Figure ?? ser vi at dette er punktet (r∗ , s∗ ). Velger verdier for η∞
og ζ∞ slik at φ og ψ bare er funksjoner av r og s:

φ(r∗ , s∗ ) = 0
(3.193)
ψ(r∗ , s∗ ) = 0
Velger så en verdi s = s0 , se Figure ??. Setter deretter r = r0 og beregner
verdiene av φ og ψ langs linja s = s0 med varierende r. Med henvisning til
figuren ovenfor, får vi fortløpende:

ψ(r0 , s0 ) · ψ(r1 , s0 ) > 0, ψ(r1 , s0 ) · ψ(r2 , s0 ) > 0, ψ(r2 , s0 ) · ψ(r3 , s0 ) < 0

Den negative verdien av ψ(r2 , s0 ) · ψ(r3 , s0 ) betyr at vi har en rot av ψ(r, s0 )


mellom r2 og r3 . Denne rota som er merket med 1 på figuren, kan finnes med en
endimensjonal nullpunktsløser siden ψ nå bare er funksjon av r. Ved å gå videre
langs s = s0 , finner vi nullpunktet 2 av φ på samme måten. Deretter begynner
vi på ny s-verdi med s1 = s0 + ∆s og finner nullpunktene langs s1 - linja. Tilslutt
har vi beregnet alle nullpunktene merket med en ring på figuren. Dermed kan
vi finne en god tilnærmelse (r̄, s̄) til det korrekte nullpunktet (r∗ , s∗ ) . Med
disse tilnæringsverdiene for nullpunktene, kan vi nå løse (3.193) ved for eks. å
bruke en todimensjonal versjon av Newton-Raphsons metode, se avsnitt 14.2 i
[3]. Figure ?? gjelder for en bestemt verdi av α = U U1 slik at vi i prinsippet må
2

gjenta søkeprosedyren for hver verdi av α. I praksis er dette sjelden nødvendig,


da verdien av (r̄, s̄) for en α–verdi vanligvis kan brukes til å finne (r∗ , s∗ ) for en
nærliggende verdi av α. Prosedyren ovenfor gir følgende tabell for (r∗ , s∗ ) som
funksjon av U U1 :
2
CHAPTER 3. SHOOTING METHODS 149

U2
U1 r∗ s∗
0.0 0.583776 0.284447
0.1 0.613568 0.267522
0.2 0.646947 0.247879
0.3 0.683594 0.225504
0.4 0.723101 0.200460
0.5 0.765049 0.172847
0.6 0.809060 0.142779
0.7 0.854807 0.110363
0.8 0.902021 0.075701
0.9 0.950480 0.038886
1.0 1.000000 0.000000
U2
Med α = U1 finner vi følgende kurvetilpasninger for r∗ og s∗ fra tabellen:

r∗ ≈ r̄ = 0.1076 · α2 + 0.3086 · α + 0.5838


(3.194)
s∗ ≈ s̄ = −0.1224 · α2 − 0.1620 · α + 0.2844
Istedenfor denne litt omstendelige fremgangsmåten, kan du forsøke program-
met fsolve fra Matlabs Optimization Toolbox. Marie 19: Henviser til Matlab

3.5 Exercises
Problem 5: Stokes first problem for a non-Newtonian fluid

y
u = U0

u(y,t)

Figure 3.28: Marit 1: description

A non-Newtonian fluid flows in the plane with constant velocity U0 , paralell


with the x-axis. At time t = 0 we insert a thin plate into the flow, paralell to
the x-axis. See Fig. 3.28 (The plate must be concidered as infinitesimal thin,
with infinite extent in th x-directions.) We are interested in finding the velocity
field u(y, t) which developes because of the adherence between the fluid and the
plate. The equation of motion for the problem may be stated as:
CHAPTER 3. SHOOTING METHODS 150

∂u ∂τxy
ρ = (3.195)
∂t ∂y
∂u
The relation between the shear stress τxy and the velocitygradient ∂y is given
by:

21
∂u ∂u
τxy = K · (3.196)
∂y ∂y
where K is a positive constant.
We introduce the following transformation which reduces the system to an
ordinary differential equation:

y u
η=C· 2 , f (η) = (3.197)
t5 U0
where C is a positive constant, y ≥ 0 and t ≥ 0. By inserting Eq. (3.196)
into Eq. (3.195) and using (3.197), we get:

p
f 00 (η) + 2 η f 0 (η) = 0 (3.198)
With boundaryconditions:

f (0) = 0, f (δ) = 1 (3.199)


where δ is the boundary-layer thickness.
Movie 2: mov-ch2/stokes.mp4
Pen and paper: The following problems should be done using pen and
paper:

a) We are first gonna solve Eq. (3.198) as an initial-value problem. In this


problem we thus set f 0 (0) = 1.25. Calculate f , and f 0 for η = 0.6 using Euler’s
method. Use ∆η = 0.2
b) Write Eq (3.198) as a system of equations. Explain how you could solve the
problem using shooting technique, when f (0) = 0, f (δ) = 1, and δ is considered
known.
c) During the solution of the system above we find that f 0 (δ) = 0. This
information makes it possible to determine δ as a part of the solution of the
system in b). Explain how.
d) Solve Eq. (3.198) when f1 (0) = f 0 (0) is given. Show that the boundary
condition f (δ) = 1 give f1 (0) = 225
128 = 1.25311 . . .
Programming:
Write a python program that solves the problem defined in b. Use the
information about δ obtained in c.
CHAPTER 3. SHOOTING METHODS 151

Hint 1. Pen and paper:


a) Solutions: f (0.6) = 0.732, f 0 (0.6)
hp= 0.988. i
d
c) Perform the differentiation dη f 0 (η) , and integrate Eq. (3.198) once.
q p
Solution: δ = 2 f 0 (0)

Hint 2. Programming:
You may use the template script below:
# src-ch2/stokes.py;ODEschemes.py @ git@lrhgit/tkt4140/src/src-ch2/ODEschemes.py;

#import matplotlib; matplotlib.use(’Qt4Agg’)


import matplotlib.pylab as plt
#plt.get_current_fig_manager().window.raise_()
import numpy as np

from ODEschemes import euler, heun, rk4


from math import sqrt
from scipy.interpolate import splev, splrep

#### set default plot values: ####


LNWDT=2; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT; plt.rcParams[’font.size’] = FNT

#### a: ####
def func(f, eta):

f0 = f[0]
f1 = f[1]
if f1<0:
# f1 should not be negative
f1=0
df0 = ?
df1 = ?

dF = np.array([df0, df1])

return dF

N = 5

Eta = np.linspace(0, 1, N + 1)
d_eta = Eta[1] - Eta[0]

f_0 = ?
df_0 = ?
F_0 = [f_0, df_0]

F = euler(func, F_0, Eta)

print "f(0.6) = {0}, f’(0.6) = {1}".format(F[N*3/5, 0], F[N*3/5, 1])

#### b/c: ####


N = 100 # using more gridpoints
CHAPTER 3. SHOOTING METHODS 152

d_eta = Eta[1] - Eta[0]


f_0 = 0

s0, s1 = 1., 1.1


delta = ?

Eta = np.linspace(0, delta, N + 1)


F_0 = [?, ?]
F = euler(func, F_0, Eta)

phi0 = ?

# Solve using shooting technique:


for n in range(4):
F_0 = [?, ?]
delta = ?
Eta = np.linspace(0, delta, N + 1)
F = euler(func, F_0, Eta)

phi1 = ?

s = ?

s1, s0 = s, s1
print "n = {0}, s = {1}, ds = {2}, delta = {3} ".format(n, s0, s1 - s0, delta)

# Transform to time-space variables:

C = 1.
U0 = 1
dt = 0.05
t0, tend = dt, 2.

dy = 0.01
y0, yend = 0, 2.

time = np.arange(dt, tend + dt, dt)

Y = np.arange(y0, yend + dy, dy)


Usolutions = np.zeros((len(time), len(Y)))

f = F[:, 0]*U0
tck = splrep(Eta, f) # create interpolation splines

for n, t in enumerate(time):
Eta_n = C*Y/(t**(2./5))

Eta_n = np.where(Eta_n>delta, delta, Eta_n) # if eta>delta set eta to delta

Usolutions[n, :] = splev(Eta_n, tck)


from Visualization import myAnimation
myAnimation(Y, Usolutions, time)
CHAPTER 3. SHOOTING METHODS 153

You also need this file in order to run simulation:


# src-ch2/Visualization.py

import matplotlib.pylab as plt


import numpy as np
from matplotlib import animation
def myAnimation(Y, Usolutions, time):
fig = plt.figure()
ax = plt.axes(xlim=(0, 1.1), ylim=(0, Y[-1]))

lines=[] # list for plot lines for solvers and analytical solutions
legends=[] # list for legends for solvers and analytical solutions

line, = ax.plot([], [])


time_text = ax.text(0.1, 0.95, ’’, transform=ax.transAxes)
dt = time[1]-time[0]
plt.xlabel(’u’)
plt.ylabel(’y’)

# initialization function: plot the background of each frame


def init():
time_text.set_text(’’)
line.set_data([], [])
return lines,

# animation function. This is called sequentially


def animate(i):
time = i*dt
time_text.set_text(’time = %.4f’ % time)
U = Usolutions[i, :]
line.set_data(U, Y)
return lines,

# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, frames=len(time), init_func=init, blit=False)
# Writer = animation.writers[’ffmpeg’]
# writer = Writer(fps=15, metadata=dict(artist=’Me’), bitrate=1800)
# anim.save(’../mov/stokes.mov’, writer=writer)

plt.show()
Chapter 4

Finite difference methods


for ordinary differenatial
equtions

4.1 Tridiagonal systems of algebraic equations


When finite difference discretization methods are applied on ordinary of partial
differential equations, the resulting equation systems will normally have a distinct
band structure. In particular, a tridiagonal coefficient matrix will normally be the
result when a second order ODE is solved. The tridiagonal matrix has only three
diagonals with non-zero elements (hence the name); one main diagonal with the
two other on each side of this. Such a tridiagonal system may be represented
mathematically as:

b1 x1 + c1 x2 = d1
···
ai xi−1 + bi xi + ci xi+1 = di
(4.1)
···
aN xN −1 + bN xN = dN
i = 1, 2, ...N , a1 = cN = 0
or more convenient in a matrix representation:

     
b1 c1 x1 d1
a2 b2 c2   x2
   d2
     

 · · ·  
  ·
 
 

 ·

 · · · ·
  ·
=
 

 · (4.2)

 · · ·  
  ·
 
 

 ·
 aN −1 bN −1 cN −1  xN −1  dN −1 
aN bN xN dN

154
CHAPTER 4. FINITE DIFFERENCES FOR ODES 155

The linear algebraic equation system (4.1) may be solved by Gauss-elimination,


which has a particular simple form for tridiagonal matrices and is often referred
to as the Thomas-algorithm. More details on the derivation may be found in
appendix I of Numeriske beregninger (in Norwegian).
The Thomas-algorithm has two steps; an elimination step and a substitution
step. In the elimination step, sub-diagonal elements are eliminated by summation
of two consecutive appropriate scaled rows in the matrix, starting at the first
row at the top. By completion of the elimination step, the last unknown xN
may the be computed as xN := dbN N
.
In the equation for xN −1 immediately above the last, there are only two
unknows, namely xN and xN −1 . But since we already have calculated xN in
the elimination step, we substitute its value in this equation and may thereby
find xN −1 . By moving on to the equation for xN −2 , there will be only two
unknowns as well, xN −2 and xN −1 , and since we have already calculated xN −1 ,
it may be substituted into this equation such that xN −2 may be found. This
procedure of back-substitution may be repeated until all the unknows for the
tridiagolnal equation system is known. This step of the procedure is known as
back substitution or simply substitution.
The algorithms for the two steps are listed outlined below in mathematical
terms:

Elimination:

aj
qj := for j = 2, 3 · · · , N
bj−1
bj := bj − qj · cj−1 (4.3)
dj := dj − qj · dj−1

Back substitution:

dN
xN :=
bN
dj − cj · xj+1
xj := for j = N − 1, N − 2, · · · , 1 (4.4)
bj
(4.5)

The Python-code for (4.3) and (4.4) is implemented in tdma, which corre-
sponds to tri in [3] , section 6.3 (see below).
def tdma(a, b, c, d):
"""Solution of a linear system of algebraic equations with a
tri-diagonal matrix of coefficients using the Thomas-algorithm.

Args:
a(array): an array containing lower diagonal (a[0] is not used)
b(array): an array containing main diagonal
c(array): an array containing lower diagonal (c[-1] is not used)
CHAPTER 4. FINITE DIFFERENCES FOR ODES 156

d(array): right hand side of the system


Returns:
x(array): solution array of the system

"""

n = len(b)
x = np.zeros(n)

# elimination:

for k in range(1,n):
q = a[k]/b[k-1]
b[k] = b[k] - c[k-1]*q
d[k] = d[k] - d[k-1]*q

# backsubstitution:
q = d[n-1]/b[n-1]
x[n-1] = q
for k in range(n-2,-1,-1):
q = (d[k]-c[k]*q)/b[k]
x[k] = q

return x

Stability of (4.3) and (4.4) is satisfied subject to the following conditions:

| b1 |>| c1 |> 0
| bi |≥| ai | + | ci |, ai · ci 6= 0 , i = 2, 3, · · · , N − 1 (4.6)
| bn |>| aN |> 0
Matrices satisfying (4.6) are called diagonally dominant for obvious reasons,
and strictly diagonally in case ≥ may be substitued with > in (4.6). Pivoting
during Gauss-elimination is not necessary for diagonally dominant matrices,
and thus the band structure is preserved and the algorithm becomes less CPU-
intensive. See appendix I in Numeriske beregninger for a proof of (4.6).
Notice that all coefficients in each row of (4.2) has the same index. However,
the linear algebraic equation system (4.1) may also be presented:

b1 x1 + c2 x2 = d1
···
ai−1 xi−1 + bi xi + ci+1 xi+1 = di
··· (4.7)
aN −1 xN −1 + bN xN = dN

i = 1, 2, ...N , a1 = cN = 0
CHAPTER 4. FINITE DIFFERENCES FOR ODES 157

or in matrix form:

     
b1 c2 x1 d1
a1 b2 c3   x2   d2

     

 · · ·  
  ·  
 

·

 · · · ·
  · =
 

· (4.8)

 · · ·  
  ·  
 

·
 aN −2 bN −1 cN  xN −1  dN −1 
aN −1 bN xN dN

We notice that in this notation the coefficients of each column in the matrix
(4.8) has the same index.
The version in (4.8) may be deduced from (4.2) by subtraction of 1 from the
a-inddices and addition of 1 for the c-indices. Commercial codes like Matlab
store tridiagonal matrices on the form given in (4.8). We have implemented (4.8)
in tridiag.
def tripiv(a, b, c, d):
"""Solution of a linear system of algebraic equations with a
tri-diagonal matrix of coefficients using the Thomas-algorithm with pivoting.

Args:
a(array): an array containing lower diagonal (a[0] is not used)
b(array): an array containing main diagonal
c(array): an array containing lower diagonal (c[-1] is not used)
d(array): right hand side of the system
Returns:
x(array): solution array of the system

"""

n = len(b)
x = np.zeros(n)
fail = 0

# reordering

a[0] = b[0]
b[0] = c[0]
c[0] = 0
# elimination:

l = 0

for k in range(0,n):
q = a[k]
i = k
if l < n-1:
l = l + 1
for j in range(k+1,l+1):
q1 = a[j]
if (np.abs(q1) > np.abs(q)):
CHAPTER 4. FINITE DIFFERENCES FOR ODES 158

q = q1
i = j
if q == 0:
fail = -1
if i != k:
q = d[k]
d[k] = d[i]
d[i] = q
q = a[k]
a[k] = a[i]
a[i] = q
q = b[k]
b[k] = b[i]
b[i] = q
q = c[k]
c[k] =c[i]
c[i] = q
for i in range(k+1,l+1):
q = a[i]/a[k]
d[i] = d[i]-q*d[k]
a[i] = b[i]-q*b[k]
b[i] = c[i]-q*c[k]
c[i] = 0

# backsubstitution
x[n-1] = d[n-1]/a[n-1]
x[n-2] = (d[n-2]-b[n-2]*x[n-1])/a[n-2]

for i in range(n-3,-1,-1):
q = d[i] - b[i]*x[i+1]
x[i] = (q - c[i]*x[i+2])/a[i]
return x

emfs /src-ch3/ #python #package TRIdiagonalSolvers.py @ git@lrhgit/tkt4140/src/src-ch3/TRIdiagonalSol

4.1.1 Example: Heat conduction. Heat exchanger with


constant cross-section

T∞ D

X
Tr

Figure 4.1: Schematic illustration of a heat exchanger.


CHAPTER 4. FINITE DIFFERENCES FOR ODES 159

A circular cylindrical rod of length L, environmental temperature T∞ , and


a constant temperature Tr at X = L is illustrated in Figure 4.1. The physical
paramters relevant for the heat conduction are the heat transfer coefficient
h̄ = 100W/m2 ◦ C and the thermal conductivity k = 200W/m/◦ C.
From equation (B.0.22), appendix B in Numeriske Beregninger we find that
the governing equation for the heat transfer in the circular cylindrical rod in
Figure 4.1 is governed by:
 
d d(T − T∞ h̄P
A(X) = (T − T∞ ) (4.9)
dX dX k
which for rod with constant cross-section, i.e. A(x) = A reduces to:

d2 h̄P
(T − T∞ ) = (T − T∞ ) (4.10)
dX 2 kA
For convenience we introduce dimensonless variables:

X T − T∞ h̄P 2
x= , θ= , β2 = L (4.11)
L Tr − T∞ kA
where L is a characteristic length (see Figure B.5 i Numeriske Beregninger).
A relative, dimensionless temperature may be constructed by using a reference
temperature Tr and temperature and the temperature T∞ in combination. The
parameteren β 2 is frequently referred to as the Biot-number, Bi = β 2 .
Given the assumptions and prerequesites above (4.9) may be presented in
the more convenient and generic form:

d2 θ
− β2θ = 0 (4.12)
dx2
which is a second order ODE with the following generic analytical solution:

θ(x) = A sinh(βx) = −B cosh(βx) (4.13)


where the constants A and B must be determined from the boundary cond-
tions.
In the following we will investigate the numerical solution to two different
boundary conditions commonly denoted as prescribed boundary conditions (which
for this particular corresponds to prescribed temperatures) and mixed boundary
conditions.
Prescribed temperatures:

T = T∞ for X = 0
T = Tr for X = L
which may be presented on dimensionless form as:
θ=0 for x = 0 (4.14)
θ=1 for x = 1
CHAPTER 4. FINITE DIFFERENCES FOR ODES 160

The analytical solution (4.13) for these particular boundary conditions reduces
to:
sinh(βx) dθ cosh(βx)
θ(x) = , =β (4.15)
sinh(β) dx sinh(β)
With D = 0.02m and L = 0.2m the Biot-number β 2 = 4. By doubling the
length the Biot-number quadurples. For eksemplet ovenfor blir Biot-tallet:

h̄P 2 2 2
β2 =
L = L (4.16)
kA D
Mixed boundary conditions:

dT
Qx = 0 = for X = 0
dX
T = Tr for X = L

A zero temperature gradient at X = 0 corresponds to an isolated rod at that


location. The dimensionless representation of this boundary conditions is:

=0 for x = 0 (4.17)
dx
θ=1 for x = 1 (4.18)

The analytical solution (4.13) reduces for the mixed boundary conditions to:

cosh(βx) dθ sinh(βx)
θ(x) = , =β (4.19)
cosh(β) dx cosh(β)

d2 θ
Numerical solution. We will use central differences for the term and
dx2
2

d θ θi−1 − 2θi + θi+1
with ≈ we get the following difference equation:
dx2 i h2
θi−1 − (2 + β 2 h2 ) θi + θi+1 = 0 (4.20)
Prescribed temperatures
We enumerate the nodes for the unkowns as shown in Figure 4.2:

0.0 1.0
X

0 1 2 3 i N-1 N N+1

Figure 4.2: Enumeration of nodes for prescribed boundary temperatures.


CHAPTER 4. FINITE DIFFERENCES FOR ODES 161

The x-coordinates can be denoted in a compact manner by:: xi = i h ,


i = 0, 1, ..., N + 1 where h = N1+1 , i.e. the prescribed temperatures at the
boundaries are denoted θ0 and θN +1 , respectively.
A good practice is to apply the generic scheme (4.20) for nodes in the
immediate vincinity of the boundaries, and first we take a look at i = 1

θ0 − (2 + β 2 h2 ) θ1 + θ2 = 0 → (2 + β 2 h2 ) θ1 + θ2 = 0
which may be simplified by substitution of the prescribed boundary value
θ(0) = θ0 = 0

(2 + β 2 h2 ) θ1 + θ2 = 0
For the other boundary at i = N the generic scheme (4.20) is:

θN −1 − (2 + β 2 h2 ) θN + θN +1 = 0
which by substitution of the prescribed value for θN +1 = 1 yields:

θN −1 − (2 + β 2 h2 ) θN = −1
A complete system of equations may finally be obtained from (4.1.1), (4.20),
and (4.1.1):

i = 1 : − (2 + β 2 h2 ) θ1 + θ2 = 0
i = 2, 3, ..., N − 1 : θi−1 − (2 + β 2 h2 ) θi + θi+1 = 0 (4.21)
2 2
i = N : θN −1 − (2 + β h ) θN = −1

See appendix A, section A.5, example A.15 in Numeriske Beregninger, this


example is treated in more detail. The following system of coefficents may be
obtained by comparison with (4.1):

ai = 1 , i = 2, 3, ..., N
2 2
bi = −(2 + β h ) , i = 1, 2, ..., N (4.22)
ci = 1 , i = 1, 2, ..., N − 1
di = 0 , i = 1, 2, ..., N − 1
dN = −1

In the program ribbe1.py below the linear, tri-diagonal equation system


(4.22) resulting from the discretization in (4.20) is solved by using two SciPy mod-
ules, the generic scipy.linalg.solve and the computationally more efficient
scipy.sparse.linalg.spsolve.
SciPy is built using the optimized ATLAS LAPACK and BLAS libraries and
has has very fast linear algebra capabilities. Allegedly, all the raw lapack and
blas libraries are available for even greater speed. However, the sparse linear
CHAPTER 4. FINITE DIFFERENCES FOR ODES 162

algebra module of scipy offers easy-to-use python interfaces to these routines.


Numpy has also a linalg-module, however, an advantage of using scipy.linalg over
numpy.linalg is that it is always compiled with BLAS/LAPACK support, while
this is optional for numpy. Note that the scipy.linalg algorithms do not exploit
the sparse nature of the matrix as they use direct solvers for dense matrices.
However, SciPy offers a sparse matrix package scipy.sparse. The spdiags
function may be used to construct a sparse matrix from diagonals. Note that all
the diagonals must have the same length as the dimension of their sparse matrix
- consequently some elements of the diagonals are not used. The first k elements
are not used of the k super-diagonal, whereas the last k elements are not used
of the −k sub-diagonal. For a quick tutorial of the usage of these sparse solvers
see SciPy sparse examples.
We have implemented a simple means to compare the two solution procedures
with a tic-toc statements. You may experiment with various problems sizes
(by varying the element size h) to assess the impact on the computational speed
of the two procedures.
# src-ch3/section321/ribbe1.py

import numpy as np
import scipy as sc
import scipy.linalg
import scipy.sparse
import scipy.sparse.linalg
import time
from math import sinh

#import matplotlib.pyplot as plt


from matplotlib.pyplot import *
# Change some default values to make plots more readable on the screen
LNWDT=3; FNT=20
matplotlib.rcParams[’lines.linewidth’] = LNWDT; matplotlib.rcParams[’font.size’] = FNT

# Set simulation parameters


beta = 5.0
h = 0.001 # element size
L =1.0 # length of domain
n = int(round(L/h)) -1 # number of unknowns, assuming known boundary values
x=np.arange(n+2)*h # x includes min and max at boundaries were bc are imposed.

#Define useful functions

def tri_diag_setup(a, b, c, k1=-1, k2=0, k3=1):


return np.diag(a, k1) + np.diag(b, k2) + np.diag(c, k3)

def theta_analytical(beta,x):
return np.sinh(beta*x)/np.sinh(beta)

#Create matrix for linalg solver


a=np.ones(n-1)
b=-np.ones(n)*(2+(beta*h)**2)
c=a
A=tri_diag_setup(a,b,c)

#Create matrix for sparse solver


CHAPTER 4. FINITE DIFFERENCES FOR ODES 163

diagonals=np.zeros((3,n))
diagonals[0,:]= 1 #all elts in first row is set to 1
diagonals[1,:]= -(2+(beta*h)**2)
diagonals[2,:]= 1
A_sparse = sc.sparse.spdiags(diagonals, [-1,0,1], n, n,format=’csc’) #sparse matrix instance

#Crete rhs array


d=np.zeros(n)
d[n-1]=-1
#Solve linear problems
tic=time.clock()
theta = sc.sparse.linalg.spsolve(A_sparse,d) #theta=sc.linalg.solve_triangular(A,d)
toc=time.clock()
print ’sparse solver time:’,toc-tic

tic=time.clock()
theta2=sc.linalg.solve(A,d,)
toc=time.clock()
print ’linalg solver time:’,toc-tic
# Plot solutions
plot(x[1:-1],theta,x[1:-1],theta2,’-.’,x,theta_analytical(beta,x),’:’)
legend([’sparse’,’linalg’,’analytical’])
show()
close()
print ’done’
The numerical predictions are presented and compared with analytical values
in the table below:
x numerical analytical rel.err
0.0 0.00000 0.00000
0.1 0.05561 0.05551 0.00176
0.2 0.11344 0.11325 0.00170
0.3 0.17582 0.17554 0.00159
0.4 0.24522 0.24487 0.00144
0.5 0.32444 0.32403 0.00126
0.6 0.41663 0.41619 0.00105
0.7 0.52548 0.52506 0.00082
0.8 0.65536 0.65499 0.00056
0.9 0.81145 0.81122 0.00029
1.0 1.00000 1.00000 0.00000
Mixed boundary conditions. Version 1
For mixed boundary conditions the nodes with uknown temperatures are
enumerated as shown in Fig. (4.3), to make the first unknown temperature we
compute have index 1. The x-coordinates are given by: xi = (i − 1) h, i =
1, 2, ..., N + 1 der h = N1 and we wil use second order central differences as

an approximation of the zero-gradient boundary condition dx = 0 at the left
boundary where x = 0.
For a generic node ’i’ the central difference approximation may be denoted:

dθ θi+1 − θi−1
≈ (4.23)
dx
i 2h
CHAPTER 4. FINITE DIFFERENCES FOR ODES 164

0.0 1.0
X

1 2 3 i N-1 N N+1

Figure 4.3: Enumeration of nodes for mixed boundary conditions.

which for node 1 takes the form:


θ2 − θ0
=0 (4.24)
2h
and we observe that this strategy requires a value of the temperature θ0 at a
node 0 which is not included in Figure 4.3. However, this is not a problem since
θ0 may be eliminated using the identity obtained from (4.24):

θ0 = θ2 (4.25)

Due to the zero gradient boundary condition, the first of the N equations,
represented on generic form by (4.20), takes the particular form:

−(2 + β 2 h2 ) θ1 + 2θ2 = 0 (4.26)

This first equation (4.26) is the only equation which differs from the resulting
equation system for prescibed boundary conditions in (4.21). All the coefficients
ai , bi , and di are the same as in for the prescribed temperature version in (4.22),
except for c1 :

c1 = 2, ci = 1, i = 2, ...N − 1 (4.27)

Mixed boundary conditions. Version 2


An alternative version 2 for implementation of the zero-gradient boundary
condition may be obtained by using a forward approximation for the gradient as
given by (4.20) for a generic node i:

dθ −3θi + 4θi+1 − θi+2
≈ (4.28)
dx i 2h
which takes the following form for node 1 where is should evaluate to zero:

dθ −3θ1 + 4θ2 − θ3
≈ =0 (4.29)
dx 1 2h

From equation (4.29) we see that θ3 may be eliminated by:


CHAPTER 4. FINITE DIFFERENCES FOR ODES 165

θ3 = 4θ2 − 3θ1 (4.30)

The first difference equation (4.20) in which θ3 occurs, is the one for node 2

θ1 − (2 + β 2 h2 ) θ2 + θ3 = 0 (4.31)

and we may eliminate θ3 from equation (4.31) by substitution of (4.30):

2 θ1 − (2 + β 2 h2 ) θ2 = 0 (4.32)
This is the first equation in the system of equations and the only one which
differs from (4.21). Rather than (4.22), we get the following equations for the
coefficients:

b1 = 2 bi = (2 + β 2 h2 ) i = 2, ..., N (4.33)
2 2
c1 = −(2 − β h ) ci = 1 i = 2, ..., N − 1 (4.34)

For convenience we summarise the resulting system of equations by:

2θ1 − (2 − β 2 h2 ) θ2 = 0, i=1
2 2
θi−1 − (2 + β h ) θi + θi+1 = 0, i = 2, 3, ..., N − 1 (4.35)
2 2
θN −1 − (2 + β h ) θN = −1, i=N

Note that we in this case, with a forward difference apporoximation of a


gradient boundary condition, had to combine the approximation of the gradient
with the difference equation to get a resulting tri-diagonal system. The the
program ribbe2 we solve the mixed boundary conditions with both versions.
# src-ch3/section321/ribbe2.py

import numpy as np
import scipy as sc
import scipy.linalg
import scipy.sparse
import scipy.sparse.linalg
import time
from numpy import cosh

#import matplotlib.pyplot as plt


from matplotlib.pyplot import *
# Change some default values to make plots more readable on the screen
LNWDT=3; FNT=20
matplotlib.rcParams[’lines.linewidth’] = LNWDT; matplotlib.rcParams[’font.size’] = FNT

# Set simulation parameters


beta = 3.0
h = 0.001 # element size
L =1.0 # length of domain
CHAPTER 4. FINITE DIFFERENCES FOR ODES 166

n = int(round(L/h)) # # of unknowns, assuming known bndry values at outlet


x=np.arange(n+1)*h # x includes min and max at boundaries were bc are imposed.

#Define useful functions

def tri_diag_setup(a, b, c, k1=-1, k2=0, k3=1):


return np.diag(a, k1) + np.diag(b, k2) + np.diag(c, k3)

def theta_analytical(beta,x):
return np.cosh(beta*x)/np.cosh(beta)

#Create matrix for linalg solver


a=np.ones(n-1) # sub-diagonal
b=-np.ones(n)*(2+(beta*h)**2) # diagonal
c=np.ones(n-1) # sub-diagonal
#c=a.copy() # super-diagl, copy as elts are modified later
#c=a
# particular diagonal values due to derivative bc
version=2
if (version==1):
c[0]=2.0
else:
b[0]=2.0
c[0]=-(2-(beta*h)**2)
print ’version 2’

A=tri_diag_setup(a,b,c)
#Create matrix for sparse solver
diagonals=np.zeros((3,n))
diagonals[0,:]= 1.0 # all elts in first row is set to 1
diagonals[0,0]= 1.0
diagonals[1,:]= -(2+(beta*h)**2)
diagonals[2,:]=1.0

if (version==1):
diagonals[2,1]= 2.0 # index 1 as the superdiagonal of spdiags is not used,
else:
diagonals[1,0]=2.0 # Sets the first element in the main diagonal
diagonals[2,1]= -(2+(beta*h)**2) # index 1 as the superdiagonal of spdiags is not used,
super-diagonal

A_sparse = sc.sparse.spdiags(diagonals, [-1,0,1], n, n,format=’csc’) #sparse matrix instance


#Crete rhs array
d=np.zeros(n)
d[-1]=-1

#Solve linear problems


tic=time.clock()
theta = sc.sparse.linalg.spsolve(A_sparse,d) #theta=sc.linalg.solve_triangular(A,d)
toc=time.clock()
print ’sparse solver time:’,toc-tic

tic=time.clock()
theta2=sc.linalg.solve(A,d,)
toc=time.clock()
print ’linalg solver time:’,toc-tic

# Plot solutions
CHAPTER 4. FINITE DIFFERENCES FOR ODES 167

plot(x[0:-1],theta,x[0:-1],theta2,’-.’,x,theta_analytical(beta,x),’:’)
xlabel(’x’)
ylabel(r’Dimensionless temperature $\mathregular{\theta}$’)
legend([’sparse’,’linalg’,’analytical’])
show()
close()
print ’done’

The relative error is computed from εrel = |(θnum − θanalyt )/θanalyt |, and
the results of the computations are given in the table below:
x Anlytical Ctr.diff Rel.err Fwd.diff Rel. err
0.0 0.26580 0.26665 0.00320 0.26613 0.00124
0.1 0.27114 0.27199 0.00314 0.27156 0.00158
0.2 0.28735 0.28820 0.00295 0.28786 0.00176
0.3 0.31510 0.31594 0.00267 0.31567 0.00180
0.4 0.35549 0.35632 0.00232 0.35610 0.00171
0.5 0.41015 0.41095 0.00194 0.41078 0.00153
0.6 0.48128 0.48202 0.00154 0.48189 0.00128
0.7 0.57171 0.57237 0.00114 0.57228 0.00098
0.8 0.68510 0.68561 0.00075 0.68555 0.00067
0.9 0.82597 0.82628 0.00037 0.82625 0.00034
1.0 1.00000 1.00000 0.00000 1.00000 0.00000

We observe that the two versions for zero-gradient boundary condition yields
approximately the same result except close to x = 0, where the forward difference
is somewhat better. In section (4.5) we will take a closer look at the accuracy of
gradient boundary conditions.
Mixed boundary conditions. Version 3
Rather than the enumeration in Figure (4.3), we may use the enumeration in
Fig. (4.2) with xi = i h , i = 0, 1, ..., N + 1 where h = N1+1 such that we must
take i = 1 in (4.20) to get:

θ0 − (2 + β 2 h2 ) θ1 + θ2 = 0
The boundary condition in (4.28) the becomes:

dθ −3θ0 + 4θ1 − θ2
= =0
dx 0 2h
from which an elimination equation for θ0 may be obtained:

θ0 = 4(θ1 − θ2 )/3 (4.36)


Concequently, equation (4.36) may be used to eliminate θ0 from the first difference
equation:

−(2 + 3β 2 h2 ) θ1 + 2θ2 = 0 (4.37)


With approach θ0 is not solved with the equation system, but retrieved
subsequently from equation (4.36).
CHAPTER 4. FINITE DIFFERENCES FOR ODES 168

4.1.2 Ribbe med variabelt tverrsnitt

D
A(X)

b
L

Figure 4.4: Marit 1: description

Figure 4.4 viser en trapesformet kjøleribbe med lengde L og bredde b.


Tykkelsen variere fra d for X = 0 til D for X = L . Ribba har varmetap
for X = 0 og har en gitt temperatur TL for X = L. Omgivelsestemperaturen er
konstant lik T∞ .

T = TL
X

½D
½L
ϕ ½d
X
X=0 X=L

Figure 4.5: Marit 1: description

Figure 4.5 viser øvre halvpart av ribba. Av denne figuren finner vi følgende
relasjon:

D/2 − d/2 l/2 − d/2


tan(φ) = =
L X
som løst m.h.p. l gir:
     
D−d d d X
l =d+ X=D + 1− (4.38)
L D D L
CHAPTER 4. FINITE DIFFERENCES FOR ODES 169

Vi forutsetter at temperaturen varierer hovedsakelig i X-retning slik at


utledningen i appendiks B i kompendiet kan brukes. Antar derfor at D er liten,
d
D  L samt 0 < D <1.
Fra appendiks B, lign. (B.0.22) i kompendiet:
 
d d(T − T∞ ) h̄P (X)
A(X) = (T − T∞ ) (4.39)
dX dX k
randbetingelser:

dT (0) h̄0
= [T (0) − T∞ ] , T (L) = TL (4.40)
dX k
For trapestverrsnittet i fig. (4.4):

P (X) = 2(b + l) ≈ 2b for l  b og A(X) = b l


Innfører følgende dimensjonsløse størrelser:
T − T∞ X d
Temperatur θ = , lengde x = ,α= , 0 < α < 1 samt:
TL − T∞ L D
2h̄ L2 h̄0
Biot-tallene β 2 = og β02 = L (4.41)
Dk k
Med bruk av disse dimensjonsløse størrelsene kan (4.39) skrives:
 
d dθ(x)
{α + (1 − α) x} − β 2 θ(x) = 0 (4.42)
dx dx
med randbetingelser:

(0) = β02 θ(0) , θ(1) = 1 (4.43)
dx
Når d = 0 som betyr α = 0 , går trapesprofilet over til et trekantprofil.
Lign. (4.42) blir nå:

d2 θ dθ
x 2
+ − β 2 θ(x) = 0 (4.44)
dx dx
For x = 0:

(0) − β 2 θ(0) = 0 (4.45)
dx
Den analytiske løsningen av (4.42) og (4.44) er gitt i appendiks G, del G.5 i
kompendiet.
CHAPTER 4. FINITE DIFFERENCES FOR ODES 170

4.1.3 Example: Talleksempel for trapesprofilet


L = 0.1m, D = 0.01m, d = 0.005m, h̄ = 80W/m2 /◦ C, h̄0 =
200W/m2 /◦ C, og k = 40W/m/◦ C som gir β 2 = 4.0 , α = 12 og β02 = 0.5
(4.46)
(4.42) blir nå:
 
d dθ
(1 + x) − 8 θ(x) = 0 (4.47)
dx dx
Et Matlab-program som beregner temperaturen θ samt gradienten θ’ for
den analytiske løsningen, der x går fra 0 til 1 med skritt ∆x = 0.1 , er gitt i
appendiks G, del G.5 i kompendiet .
Programmet gir følgende tabell:

x θ (x) θ’(x)
0.00 0.18069 0.09034
0.10 0.19623 0.21842
0.20 0.22415 0.33967
0.30 0.26424 0.46318
0.40 0.31708 0.59556
0.50 0.38383 0.74211
0.60 0.46614 0.90754
0.70 0.56611 1.09629
0.80 0.68632 1.31291
0.90 0.82978 1.56211
1.00 1.00000 1.84901

Numerisk løsning av homogent trapesprofil


Vi vil nå løse lign. (4.47) numerisk med bruk av sentraldifferanser

d2 θ dθ
(1 + x) + − 8 θ(x) = 0 (4.48)
dx2 dx
med randbetingelser:

dθ θ(0)
(0) = β02 θ(0) = , θ(1) = 1 (4.49)
dx 2
Fremgangsmåten blir som for tilfelle 2, versjon 2, avsnitt (4.1.1) med samme
nummerering.
x-koordinatene er gitt ved: xi = (i − 1) h , i = 1, 2, ..., N + 1 der h = N1 .
Diskretisering:
θi+1 − 2θi + θi−1 θi+1 − θi−1
(1 + xi ) + − 8θi = 0
h2 2h
som ordnet blir:

−(1 − γi ) θi−1 + 2 (1 + 8h γi ) θi − (1 + γi ) θi+1 = 0 (4.50)


CHAPTER 4. FINITE DIFFERENCES FOR ODES 171

0.0 1.0
X

1 2 3 i N-1 N N+1

Figure 4.6: Marit 1: description

h h
der γi = = , i = 1, 2, ..., N + 1 (4.51)
2(1 + xi ) 2[1 + (i − 1) h]
θ2 −θ0 θ1
For randbetingelsen i (4.49) får vi: 2h = 2 → θ0 = θ2 − θ1 h som innsatt
i (4.50) for i = 1 gir:

[2 + h (1 + 15 γ1 )] θ1 − 2θ2 = 0 (4.52)
For i = N :

−(1 − γN ) θN −1 + 2 (1 + 8h γN ) θN = 1 + γN (4.53)
For i = 2, 3, ..., N − 1 bruker vi (4.50). Vi har da et tridiagonalt ligningsett
som kan løses med Thomas-algoritmen . Tabellen nedenfor viser beregningene
med to forskjellige verdier av h. Vi ser at feilen er 100 ganger mindre for h = 0.01
enn for h = 0.1 som betyr at feilen er av O(h2 ) ; i overenstemmelse med teorien.
Den relative feilen er beregnet fra |(θnumerisk − θanalytisk )/θanalytisk |

h = 0.1 x θ(x) rel. feil h = 0.01 x θ(x) rel. feil


0.0 0.18054 8.000E-4 0.0 0.18069 4.866E-6
0.1 0.19634 5.619E-4 0.1 0.19623 1.010E-5
0.2 0.22442 1.224E-3 0.2 0.22415 1.669E-5
0.3 0.26462 1.436E-3 0.3 0.264259 1.703E-5
0.4 0.31752 1.394E-3 0.4 0.31709 1.325E-5
0.5 0.38430 1.222E-3 0.5 0.38383 9.861E-6
0.6 0.46660 9.910E-4 0.6 0.46614 6.393E-6
0.7 0.56653 7.385E-4 0.7 0.56611 2.737E-6
0.8 0.68665 4.838E-4 0.8 0.68632 4.342E-7
0.9 0.82998 2.364E-4 0.9 0.82978 1.508E-6
1.0 1.00000 0 1.0 1.00000 0

Numerisk løsning av sammensatt trekantprofil


Figure 4.7 viser en trekantformet kjøleribbe sammensatt av en trekant (del a)
og et trapes (del b) der del a og b er laget av forskjellige materialer. Hensikten
med dette tilfellet er å vise hvordan vi kan behandle diskontinuiteter. Her er
temperaturen kontinuerlig, mens temperaturgradienten er diskontinuerlig på
grenseflata mellom de to delene p.g.a. forskjellige verdier for varmeledningstallene.
Fra appendiks B i kompendiet:
CHAPTER 4. FINITE DIFFERENCES FOR ODES 172

0.1m 0.1m

d D

Part a Part b

Figure 4.7: Marit 1: description

dT
−dQx = P h [T (X) − T∞ ] dX der Qx = −kA
dX
For dX → 0 får vi da dQ → 0 ⇒ Q = konstant som betyr at på grenseflata
mellom de to legemene gjelder følgende relasjon:
   
dT dT
Qa = Qb ⇒ ka Aa = kb Ab (4.54)
dX a dX b
   
dT ka dT
Da Aa = Ab på grenseflata, følger: = som på dimen-
dX b kb dX a
sjonsløs form (med bruk av (4.41) blir:
   
dθ ka dθ
= (4.55)
dx b kb dX a
Bruker følgende tallverdier:

L = 0.2m , D = 0.02m , d = 0.01m , h̄a = h̄b = 80W/m2 /◦ C ,


(4.56)
ka = 160W/m/◦ C og kb = 40W/m/◦ C

Med disse tallverdiene blir (4.55):


   
dθ dθ
=4 (4.57)
dx b dx a
Differensialligning:
 
d x dθ
− θ(x) = 0 (4.58)
dx β 2 dx

2h̄ L2
β2 = som gir βa2 = 2.0 og βb2 = 8.0 (4.59)
Dk
Ved å skrive (4.58) på den viste formen, har vi oppnådd kontinuiteten i (4.54)
Med henvisning til Figure 4.8 bruker vi følgende nummerering:
CHAPTER 4. FINITE DIFFERENCES FOR ODES 173

0.0 0.5 1.0


X

1 2 M-1 M M+1 N N+1

Figure 4.8: Marit 1: description

xi = (i − 1) h , i = 1, 2, ..., N + 1 der h = N1
(4.60)
M = N2 + 1 der N er et partall og xM = s0.5

Med k = ka for i = M får vi at β = βa for i = 1, 2, ..., M og β = βb for


i > M . For i 6= M kan vi skrive (4.58)
 
d dθ
x − β 2 θ(x) = 0 (4.61)
dx dx
Diskretiserer (4.61)) med bruk av (2.43)) i kap. (2):

−xi− 21 θi−1 + (xi+ 12 + xi− 21 + β 2 h2 ) θi − xi+ 21 θi+1 = 0

Innsatt for xi− 21 = (i − 32 ) h og xi+ 21 = (i − 21 ) h får vi:


   
3 1
i− θi−1 + [2(i − 1) + β 2 h] θi − i − θi+1 = 0
2 2
eller dividert med i:

β2h
       
3 1 1
− 1− θi−1 + 2 1 − + θi − 1 − θi+1 = 0 (4.62)
2i i i 2i

(4.62) brukes for alle verdier av i = 2, 3, ..., N unntatt for i = M = N/2 + 1


For i = 1
Fra (4.45) får vi for randbetingelsen for x = 0:
dθ −3θ1 + 4θ2 − θ3
(0) = βa2 θ(0) → = βa2 θ1 hvor vi har benyttet (2.4)
dx 2h
Dette gir:

θ3 = 4θ2 − (3 + 2hβa2 ) θ1 (4.63)


Skriver ut (4.62) for i = 2:

βa2 h
       
3 1 1
− 1− θ1 + 2 1 − + θ2 − 1 − θ3
4 2 2 4
CHAPTER 4. FINITE DIFFERENCES FOR ODES 174

som innsatt fra (4.59) og (4.63) gir:


   
3h h
1+ θ1 − 1 − θ2 = 0 (4.64)
2 2
Dette er den første ligningen.
For i = M.

0.5

M-1 M-½ M M+½ M+1

Figure 4.9: Marit 1: description

Her bruker vi ligningen på formen gitt i (4.58)) som diskretisert med bruk av
(2.43)) fra kap. (2) gir:

2
βM − 12
2
= βa2 = 2.0 , βM + 21
= βb2 = 8.0
h (1 − h) h (1 + h)
xM − 12 = (N − 1) = , xM + 12 = (N + 1) =
2 2 2 2
som gir:

−4 (1 − h) θM −1 + [5 − 3h + 16h2 ] θM − (1 + h) θM +1 = 0 (4.65)

For i = N kan vi bruke (4.62) med β 2 = βb2 = 8.0:


   
3h h
− 1− θN −1 + 2 [(1 − h) + 4h2 ] θN = 1 − (4.66)
2 2
Ligning (4.64)–(4.66) er et lineært ligningsystem på tridiagonal form som
kan løses med Thomasalgoritmen. I tillegg til temperaturen ønsker vi også å
beregne temperaturgradienten θ0 (x) . For x = 0 bruker vi (4.45) og sprangverdien
dθ dθ

dx (0.5+) ≡ dx b finnes fra (4.57). De andre verdiene beregnes med vanlige
sentraldifferanser, med 2. ordens bakoverdifferanser for x = 0.5 og x = 1.0 . La
oss se på bruken av differensial-ligningen som et alternativ.
Vi integrerer (4.61):

β 2 xi
Z
dθi
= θ(x)dx , i = 2, 3, ..., N + 1 (4.67)
dx xi x1
Rx
Integralet I = x1i θ(x)dx beregnes f.eks ved bruk av trapesmetoden . Bereg-
ningen av (4.67) er vist i pseudokode nedenfor:
CHAPTER 4. FINITE DIFFERENCES FOR ODES 175

θ10 := βa2 θ1
s := 0
Utfør for i := 2, ..., N + 1
x := h (i − 1)
s := s + 0.5h (θi + θi−1 )

βa2 s β2 s
Dersom (i ≤ M ) sett θi0 := ellers θi0 := b
x x
I tabellen på neste side har vi brukt (4.67) og trapesmetoden. I dette
tilfellet er nøyaktigheten av de to metodene for beregning av θ0 (x) temmelig
sammenfallende da både θ og θ0 er glatte funksjoner (bortsett fra x = 0.5),
men generelt vil integrasjonsmetoden gjerne være mer nøyaktig dersom det er
diskontinuiteter.
Løsning av lign. (4.58) med h = 0.01

x θ(x) rel. feil θ0 (x) rel. feil


0.00 0.08007 1.371E-4 0.16014 1.312E-4
0.10 0.09690 1.341E-4 0.17670 1.302E-4
0.20 0.11545 1.386E-4 0.19438 1.286E-4
0.30 0.13582 1.252E-4 0.21324 1.360E-4
0.40 0.15814 1.265E-4 0.23333 1.329E-4
0.45 0.17007 1.294E-4 0.24387 1.312E-4
0.5- 0.18253 1.260E-4 0.25472 1.021E-4
0.5+ 0.18253 1.260E-4 1.01889 1.021E-4
0.55 0.23482 5.962E-5 1.07785 1.067E-4
0.60 0.29073 5.848E-5 1.16297 9.202E-5
0.70 0.41815 3.348E-5 1.39964 7.288E-5
0.80 0.57334 1.744E-5 1.71778 5.938E-5
0.90 0.76442 7.849E-6 2.11851 4.862E-5
1.00 1.00000 0.0 2.60867 1.526E-4

4.2 To-punktsmetode. Varmeveksler.


Et system av p første ordens differensialligninger kan skrives:

yi0 (x) = fi (x, y1 , y2 , ..., yp ) , i = 1, 2, ..., p


Dersom randverdiene er foreskrevet for x = a og x = b , kan vi skrive
randverdiproblemet på vektorform:

y’(x) = f(x, y) (4.68)

A · y(a) + B · y(b) = c (4.69)


CHAPTER 4. FINITE DIFFERENCES FOR ODES 176

der A og B er p x p - matriser.

Randbetingelsene må være lineære, dvs. elementene i A og B er konstanter,


dersom de skal kunne skrives på formen i (4.69) Det eksisterer selvfølgelig mer
generelle randbetingelser; f.eks: g(y(a), y(b)) = 0 , men (4.69) dekker en lang
rekke tilfeller.

4.2.1 Example
Fra lign.(4.12) og (4.14):
d2 θ
dx2 − β 2 θ(x) = 0
0
θ (0) = 0 , θ(1) = 1
Med notasjonen i (4.68) kan dette systemet skrives:

y10 = y2
y20 = β 2 y1
         
0 1 y (0) 0 0 y (1) 0
· 1 + · 1 =
0 0 y2 (0) 1 0 y2 (1) 1
Vi diskretiserer (4.68) med bruk av sentraldifferanser. Da (4.68) er et sett
av 1. ordens ligninger, velger vi å utvikle differanseutrykkene halveis mellom to
punkt; i dette tilfellet rundt xj− 12 som vist på Figure 4.10.

j-1 j-½ j

½h ½h

Figure 4.10: Marit 1: description

yj − yj−1

dy 1
= + O(h2 ) , yj− 21 = (yj + yj−1 ) + O(h2 ) (4.70)
dx j− 1 h 2
2

(4.70) brukt i (4.68) gir:


yj − yj−1 yj + yj−1
 
− f xj− 21 , = 0 , j = 1, 2, ..., N (4.71)
h h
med randbetingelser:

A · y0 + B · yN = c (4.72)
CHAPTER 4. FINITE DIFFERENCES FOR ODES 177

Notasjon:
b−a
xj = a + j · h, j = 0, 1, ...N , h = (4.73)
N
Med denne diskretiseringen kan det vises at følgende relasjon gjelder:

y(xj ) = yj (h) + h2 e(xj ) + O(h4 ) , j = 0, 1, ..., N (4.74)


Her er yj (h) de diskretiserte verdiene ved skrittlengden h og e(xj ) er en
funksjon som kan relateres til den gitte differensialligningen. (Bevis for de
forskjellige teoremene kan finnes i Keller [8] , kapittel 3). Marie 28: Nå står
G. E. Forsythe som forfatter. Skal det egentlig være H. B. Keller?
På denne måten får vi bare to forskjellige indekser i hver ligning ; derav navnet
to-punktsmetoden. Den vesentlige fordelen med denne metoden er normalt i
forbindelse med randbetingelsene. En mindre bakdel er at vi selv for 2. ordens
differensialligninger må bruke en generalisert versjon av Thomas-algoritmen, men
disse generaliserte versjonene er også effektive. Utvider vi to-punktsmetoden
til flere dimensjoner/tidsvariasjon, kalles metoden for en boksmetode. De mest
kjente av disse er Kellers boksmetode i grensjikt-teori og Preismanns metode i
kanalstrømning. (Wendroffs metode i avsnitt 6.7 i kompendiet er et spesialtilfelle
av Preismanns metode). Vi skal nå bruke (6.7.3) på et system av to ligninger
der ligningene allerede i utgangspunktet er på formen gitt i (6.7.1).

4.2.2 Example: Varmeveksler

Wy
Wi
Wy

Figure 4.11: Marit 1: description

Figure 4.11 viser en varmeveksler som er modellert som to rør. I det ytre
røret foregår strømningen fra venstre mot høyre med konstant hastighet wy og i
det indre røret har vi en strømning med konstant hastighet wi . Vi har likestrøm
når wi er rettet mot høyre mens vi har motstrøm når wi er rettet mot venstre.
Temperaturen i det ytre og det indre røret betegnes henholdsvis Ty og Ti . Vi
regner det ytre røret så godt isolert at et eventuelt varmetap til omgivelsene kan
neglisjeres.
CHAPTER 4. FINITE DIFFERENCES FOR ODES 178

Noen betegnelser: (Indeks i henviser til det indre røret)

Rørlengde: L [m]
Lengdekoordinat: X [m]
Rørdiameter: di [m]
Areal av rørtverrsnitt: Ai = π · d2i /4 [m2 ]
Omkrets av indre rør: P = π · di [m]
(4.75)
Tetthet av medium: ρi [kg/m3 ]
Massestrøm: ṁi = ρi Ai wi [kg/s]
Totalt varmeovergangstall: h̄ [W/m2 /◦ C]
Egenvarme: ci [J/kg/◦ C]
Varmestrøm: Q̇i = ṁi ci Ti [W ]

For de indekserte størrelsene (4.75) har vi tilsvarende med indeks y for det
ytre røret. Q̇yi er varmestrømmen til det indre røret fra det ytre:
Med henvisning til Figure 4.12:

Q̇yi = h̄P · dX[Ty (X) − Ti (X)] (4.76)


Varmebalansen for det indre røret:

Q̇i = Q̇i + dQ̇i − Q̇yi som gir:


(4.77)
dQ̇i = Q̇yi = −dQ̇y
hvor vi har benyttet oss av at vi ikke har noe varmetap til omgivelsene.

dX
Qyi
Ty Wy

Qi Wi Qi + dQi
Ti Wi di dy

Ty Wy
Qyi

Figure 4.12: Marit 1: description

(4.75) - (4.77) gir:

ṁi ci dTi (X) = h̄P · dX[Ty (X) − Ti (X)] = −ṁy cy dTy (X) (4.78)
CHAPTER 4. FINITE DIFFERENCES FOR ODES 179

Fra (4.78) får vi følgende ligninger:

h̄P
dTy (X) = − [Ty (X) − Ti (X)] · dX (4.79)
ṁy cy

h̄P
dTi (X) = [Ty (X) − Ti (X)] · dX (4.80)
ṁi ci
Vi innfører nå dimensjonsløse størrelser. Lar Tir og Tyr være referansetem-
peraturer som kan gis passende verdier i konkrete tilfeller. De dimensjons-løse
temperaturene i ytre og indre rør betegnes nå henholdsvis u og v .
Ty − Tyr
Temperatur ytre rør: u = (4.81)
Tir − Tyr
Ti − Tyr
Temperatur indre rør: v = (4.82)
Tir − Tyr
X
Lengde: x = (4.83)
L

h̄P L h̄P L
αy = =
ṁy cy ρy Ay wy cy
Koeffisienter: (4.84)
h̄P L h̄P L
αi = =
ṁi ci ρi Ai wi ci
(4.81) innsatt i (4.79) gir følgende system:
du
Ytre rør: = −αy (u − v) (4.85)
dx
dv
Indre rør: = ±αi (u − v) (4.86)
dx
Vi har skrevet ± foran leddet på høyre side i (4.86) der pluss-tegnet gjelder
for strømningsretningen som vist på Figure 4.12, mens negativt fortegn gjelder
når wi skifter retning (motstrøm). Det er underforstått at u og v er funksjoner
av x slik at vi slipper å skrive u(x) og v(x).

Analytisk løsning
Dersom vi kjenner temperaturen for en gitt x-verdi både i det ytre og indre
røret, kan vi løse (4.85) analytisk.
Ved subtraksjon:
d
− (u − v) = (αy ± αi ) · (u − v)
dx
Innfører temperaturdifferansen

θ =u−v (4.87)
CHAPTER 4. FINITE DIFFERENCES FOR ODES 180


slik at vi får ligningen − dx = (αy ± αi ) · θ med løsning:

θ(x) = θ0 · e−(αy ±αi )·x , der θ0 = θ(0) (4.88)


Får da følgende løsning for u og v:
  h
αy i
u(x) = u0 − θ0 · · 1 − e−(αy ±αi )·x (4.89)
αy ± αi
  h
αi i
v(x) = v0 + θ0 · · 1 − e−(αy ±αi )·x (4.90)
αy ± αi
Her er u0 = u(0) og v0 = v(0) . Dersom f. eks. u(0) og v(1) er gitt, har vi et
tilfelle med splitta randbetingelser som må løses numerisk.
Tilfelle med splitta randbetingelser.
For et tilfelle med motstrøm blir (4.85):
du
= −αy (u − v) (4.91)
dx
dv
= −αi (u − v) (4.92)
dx
Innløpstemperaturen for det ytre røret = Ty (0) og utløpstemperaturen =
Ty (L) . Tilsvarende betegnelser for det indre røret er Ti (0) og Ti (L) . Velger nå
referansetemperaturene i (4.81) for dette tilfellet:

Tyr = Ty (0) og Tir = Ti (L)


slik at (4.81) nå blir:

Ty − Ty (0)
Temperatur ytre rør: u = (4.93)
Ti (L) − Ty (0)
Ti − Ty (0)
Temperatur indre rør: v = (4.94)
Ti (L) − Ty (0)
Dette valget av referansetemperaturer gir følgende randbetingelser:

u(0) = 0 , v(1) = 1 (4.95)


(4.91) innsatt i (4.71):
  
uj − uj−1 1 1
= −αy · (uj + uj−1 ) − (vj + vj−1 )
h 2 2
  
vj − vj−1 1 1
= −αi · (uj + uj−1 ) − (vj + vj−1 )
h 2 2
som ordnet gir følgende ligningsystem:

(h · αy − 2) · uj−1 + (2 + h · αy ) · uj − h · αy · vj−1 − h · αy · vf = 0 (4.96)


CHAPTER 4. FINITE DIFFERENCES FOR ODES 181

h · αi · uj−1 + h · αi · uj − (h · αi + 2) · vj−1 + (2 − h · αi ) · vj = 0 (4.97)

(4.96) er et spesialtilfelle av det mer generelle systemet

(1) (2) (1) (2) (1) (2) (1)


aj uj−1 + αj vj−1 + bj uj + bj vj + cj uj+1 + cj vj+1 = dj
(3) (4) (3) (4) (3) (4) (2) (4.98)
aj uj−1 + aj vj−1 + bj uj + bj vj + cj uj+1 + cj vj+1 = dj

Systemet i (4.98) kalles et bi-tridiagonalt ligningsystem. Algoritmen for


løsning av dette systemet kalles ofte Douglas-algoritmen. (Se appendiks I i
kompendiet)
Nedenfor har vi skrevet ut (4.98) på matriseform.

" # " #  " #


(1) (2) (1) (2) (1)
c c1 b1 b1 d1
 1(3)
 
 c1 (4) (3) (4)  u1  (2) 
 c1 b1 b1   u1   d1 
  
    
" # " # " #   " #
 (1) (2) (1) (2) (1) (2)       (1) 
 a2 a2 b2 b2 c2 c2   u2   d2 
 (3) (4) (3) (4) (3) (4)
  u2   d(2)
   
 a2 a2 b2 b2 c2 c2   2 

 

 · ·  ·   · 
   

 · ·  ·   · 
   

 · " · # " # " #
· · = · 
     " #
(1) (2) (1) (2) (1) (2)   uj   d(1) 

 aj aj bj bj cj cj    j 
 (3) (4) (3) (4) (3) (4)   uj   (2) 

 aj aj bj bj cj cj   ·   dj 
   

 · · 
 ·  
  · 


 · ·  ·   · 
   

 · " · # "
    · 
#  uN  " #
(1) (2) (1) (2)   (1) 
aN aN bN bN  uN  dN 


(3) (4) (3) (4) (2)
aN aN bN bN dN

Vi ser at vi har fått en tridiagonal koeffisientmatrise der hvert element i


matrisa er en 2 x 2 - matrise. En slik matrise kalles blokk-tridiagonal der hvert
element er en blokk. Vi får ofte blokk-tridiagonale matriser når vi diskretiserer
system av første ordens ordinære og partielle ligninger. Hadde vi f.eks. brukt 3
rør, ville hver blokk vært en 3 x 3 - matrise.
Den tridiagonale strukturen blir enda tydeligere når vi setter navn på
blokkene:
" # " # " #
(1) (2) (1) (2) (1) (2)
aj aj bj bj cj cj
aj = (3) (4) , bj = (3) (4) , cj = (3) (4)
aj aj bj bj cj cj
" #
  (1)
u d
xj = j , dj = j(2) , j = 1, 2, ..., N
vj dj
CHAPTER 4. FINITE DIFFERENCES FOR ODES 182

slik at systemet ovenfor kan skrives:


     
b1 c1 x1 d1
 a2 b2 c2   x2   d2 
     

 · ·   ·   · 
    

 · ·   ·   · 
    
 · ·   ·   · 
· = 
 (4.99)

 a j b j c j
  xj   dj 
    

 · ·   ·   · 
    

 · ·   ·   · 
    
 · ·   ·   · 
aN bN xN dN
Å løse dette systemet med Douglas-algoritmen, er det samme som å bruke
Thomas-algoritmen når man tar hensyn til at elementene er matriser og vektorer.
Indeksering.

x=0 x=1
Outer tube:
u0 u1 u2 uj uN-1 uN

x=0 x=1
Inner tube:
v0 v1 v2 vj vN-1 vN

Figure 4.13: Marit 1: description

Randbetingelser: u0 = 0 , uN = 1 .
Algoritmen krever at den første ukjente har indeks 1 og den siste indeks N.
Som figuren ovenfor viser, stemmer dette for det ytre røret, men ikke for det
indre der v0 er den første ukjente.
Vi forandrer indeksene som vist nedenfor:

x=0 x=1
Outer tube:
u0 u1 u2 uj uN-1 uN

x=0 x=1
Inner tube:
v1 v2 v3 vj vN vN+1

Figure 4.14: Marit 1: description

Får da følgende indeksering:


CHAPTER 4. FINITE DIFFERENCES FOR ODES 183

For u:

uj , j = 0, 1, ..., N , u0 = 0 fra randbetingelsen (4.100)


For v:

vj , j = 1, 2, ..., N + 1 , vN +1 = 1 fra randbetingelsen (4.101)


Med den nye indekseringen i (4.101), blir systemet i (4.96) nå:

(h · αy − 2) · uj−1 + (2 + h · αy ) · uj − h · αy · vj − h · αy · vj+1 = 0 (4.102)

h · αi · uj−1 + h · αi · uj − (h · αi + 2) · vj + (2 − h · αi ) · vj+1 = 0 (4.103)

Utskrevet for j = 1:

(2 + h · αy ) · u1 − h · αy · v1 − h · αy · v2 =0
h · αi · u1 − (h · αi + 2) · v1 + (2 − h · αi ) · v2 =0
hvor vi har benyttet u0 = 0 fra randbetingelsen.
Utskrevet for j = N :

(h · αy − 2) · uN −1 + (2 + h · αy ) · uN − h · αy · vN = h · αy
h · αi · uN −1 + h · αi · uN − (h · αi + 2) · vN = h · αi − 2

hvor vi har brukt vN +1 = 1 fra randbetingelsen. Ved å sammenligne vårt


system ovenfor med basissystemet i (4.98), får vi følgende koeffisienter for bruk i
Douglas-algoritmen:

(1) (2) (1) (2)


αj = h · αy − 2 , αj =0, bj = 2 + h · αy , bj = −h · αy
(1) (2) (1)
cj = 0, cj = −h · αy , dj =0, j = 1, 2, ..., N − 1
(3) (4) (3) (4)
αj = h · αi , αj =0, bj = h · αi , bj = −(h · αi + 2)
(3) (4) (2)
cj =0, cj = 2 − h · αi , dj =0, j = 1, 2, ..., N − 1
(4.104)
(1) (2)
hvor α1 og α1 ikke brukes.
CHAPTER 4. FINITE DIFFERENCES FOR ODES 184

(1) (2)
For j = N blir utrykkene som i (4.104) bortsett fra dN = h · αy og dN =
(2) (4)
h · αi − 2 . cN og cN brukes ikke. Et eksempel med N = 6 er gitt vist nedenfor.

 (1) (2) (2)



b1 b1 0 c1  

0

 (3) (4) (4)  u1
 b1 b1 0 c1 0   0 
 (1) (1) (2) (2)   v1  
 0 

a2 0 b2 b2 0 c2   
 u2  
   0 
 
a(3) 0
(3)
b2
(4)
b2 0
(4)
c2 0
 2   v2  
   0 

(1) (1) (2) (2)
0 a3 0 b3 b3 0 c3

 u3  
   0 
 
 (3) (3) (4) (4)

 a3 0 b3 b3 0 c3 0   v3  
·  =  0 

(1) (1) (2) (2) u

 0 a4 0 b4 b4 0 c4   4  0 
    
(3) (3) (4) (4)   v4  
a4 b4 b4 c4    0 

0 0 0


 (1) (1) (2)  u
(2)  5  
 0 
 
 0 a5 0 b5 b5 0 c5    v5  
 0 
 
(3) (3) (4) (4)  

 a5 0 b5 b5 0 c5   u6   (1) 
 (1) (1) (2)  d6 
 0 a6 0 b6 b6  v 6 (2)
0
(3)
a6 0
(3)
b6
(4)
b6 d6
(4.105)
Sammenlignet med det generellle systemet ser vi at fire av halv-diagonalene
(2) (4) (1) (3)
forsvinner i vårt tilfelle: aj , aj , cj , og cj . Dersom det er behov for
å spare denne plassen, kan vi skrive en spesiell versjon som ikke bruker disse
vektorene. (Se Fortran-funksjonen bitris i appendiks I i kompendietsom også
finnes i Matlab-versjon)

4.2.3 Example: Talleksempel


Vi skal avkjøle smøreoljen fra et gassturbinanlegg. Oljen har en temperatur på
100◦ C. Til disposisjon har vi vann med temperatur på 30◦ C. Andre data:

Rørlengde: L = 61m
Rørdiameter: d = 0.025m
Omkrets av rør: P = π · d = 0.07854m
Massestrøm: ṁy = 0.1 og ṁi = 0.23kJ/s
Totalt varmeovergangstal: h̄ = 40W/m2 /◦ C
Egenvarme: cy = 2130 og ci = 4180J/Kg/◦ C

Med disse data, får vi følgende verdier for koeffisientene αy og αi :

h̄P L h̄P L
αy = ≈ 0.9 , αi = ≈ 0.2 (4.106)
ṁy cy ṁi ci
Referansetemperaturene i (4.76) og (4.87):

Tir = Ti (L) = 30◦ C , Tyr = Ty (0) = 100◦ C (4.107)


CHAPTER 4. FINITE DIFFERENCES FOR ODES 185

som gir forbindelsen mellom dimensjonsløs og dimensjonelle temperaturer:

Ty (x) = 100 − 70 · u(x) , Ti (x) = 100 − 70 · v(x) (4.108)


Legg merke til at vi bruker den dimensjonsløse koordinaten x i (4.108).
Tabellen viser resultatene ved å løse (4.105) med koeffisienter gitt i (4.104)
ved bruk av bitris gitt i appendiks I i kompendiet. Vi ser av tabellen at smøroljen
blir avkjølt fra 100◦ C til 60.4◦ C, mens vannets temperatur stiger fra 30◦ C til
38.8◦ C. Temperaturforløpet i tabellen er vist i Figure 4.15.
Selv om vi ikke har noen direkte analytisk løsning å sammenligne med,
indikerer den små forskjellen mellom løsningene for h = 0.1 og h = 0.01 at
tabellverdiene sannsynligvis er temmelig nøyaktige. En delvis bekreftelse kan
fås ved å bruke den analytiske løsningen i (4.89) som innsatt for tallverdiene for
dette eksemplet blir:

u(x) = v0 97 [1 − e−0.7·x ]
(4.109)
v(x) = v0 [1 + 27 (1 − e−0.7·x )]

h = 0.1 x Ty (◦ C) Ti (◦ C) h = 0.01 x Ty (◦ )C Ti (◦ C)
0.0 100.00000 38.80441 0.0 100.00000 38.80226
0.1 94.67864 37.62189 0.1 94.68054 37.62016
0.2 89.71719 36.51934 0.2 89.72070 36.31798
0.3 85.09129 35.49137 0.3 85.09618 35.49031
0.4 80.77825 34.53291 0.4 80.78431 34.53211
0.5 76.75692 33.63928 0.5 76.76395 33.63870
0.6 73.00756 32.80609 0.6 73.01539 32.80569
0.7 69.51178 32.02925 0.7 69.52026 32.02899
0.8 66.25243 31.30495 0.8 66.26142 31.30480
0.9 63.21352 30.62964 0.9 63.22291 30.62958
1.0 60.38014 30.00000 1.0 60.38981 30.00000

Løsning av lign. (4.105)


Marie 34: figuren har norske forklaringer.
Verdien av v0 ≡ v(0) er ukjent og må beregnes numerisk. Ved å utføre
beregningen for forskjellige verdier av h, får vi følgende tabell:
h v0
0.100 0.87422266
0.050 0.87424592
0.010 0.87425336
0.005 0.87425359
0.001 0.87425359
Dersom vi aksepterer v0 − verdien for h = 0.001 som den "rette", kan vi bruke
denne i (4.109) og deretter sammenligne med tabellverdiene. Gjør vi det, finner
vi at den relative feilen for h = 0.1 ligger i intervallet [10−4 , 10−5 ] mens den for
h = 0.01 ligger i intervallet [10−6 , 10−7 ] . Dette viser at differanseskjemaet er
av O(h2 ), i overenstemmelse med teorien.
CHAPTER 4. FINITE DIFFERENCES FOR ODES 186

100.0
Oil
80.0

60.0

T i , Ty 40.0 Water

20.0

0.0
0.0 0.2 0.4 0.6 0.8 1.0
x

Figure 4.15: Marit 1: description

I kapittel 6 avsnitt 7 i kompendiet behandler vi det ikke-stasjonære tilfellet


av dette eksemplet.
Bruk av Richardson ekstrapolering
Denne teknikken som er velkjent ved Romberg-integrasjon, kan ofte brukes
til å forbedre verdier som er funnet ved bruk av differanse-metoder. (Se avsnitt
4.3 i [3] ). La oss anta at den korrekte verdien er y, mens vi har funnet en
tilnærmelse y1 med bruk av skritt lengden h1 . Dessuten antar vi at forbindelsen
mellom y og y1 er gitt ved:

y1 = y + A · hk1 + B · hk+1
1 + ... (4.110)
der A og B er konstanter.
Dersom vi nå beregner to tilnærmelser y1 og y2 med to forskjellige verdier
h1 og h2 , får vi to ligninger av typen (4.110) og kan dermed eliminere A med
følgende resultat:
!
hk2 · y1 − hk1 · y2 hk2 hk+1
1 − hk1 hk+1
2
=y+B· + ... (4.111)
hk2 − hk1 hk2 − hk1

(4.111) kan kalles hk - ekstrapoleringsformelen. Spesielt for k = 2 og h2 = 12 h1


får vi fra (4.111):
1
y ≈ y2 + (y2 − y1 ) (4.112)
3
med en feil 61 Bh31 + . . .
I noen tilfeller er vi så heldige at B = 0. Da blir feilen av O(h41 ). Dette er
nettopp tilfelle for to-punkts metoden. For denne metoden får vi fra (4.74) med
h = h1 :

y(xj ) = yj (h) + h2 e(xj ) + O(h4 ) , j = 0, 1..., N (4.113)


CHAPTER 4. FINITE DIFFERENCES FOR ODES 187

En tilstrekkelig betingelse for at (4.113) gjelder er at (4.68) har kontinuerlig


femte derivert på det aktuelle intervallet. (Se Keller [8] ). Med vår notasjon blir
(4.112):
     
h 1 h
y(xj ) = yj + y − yj (h) + O(h4 ) (4.114)
2 3 j 2

Tytre x h = 0.2 h = 0.1 Ekstrapol. h = 2 · 103


0.0 100.0000 100.00000 100.00000 100.00000
0.1 94.67864
0.2 89.70651 89.71719 89.72075 89.72073
0.3 85.09129
0.4 80.75984 80.77825 80.78439 80.78437
0.5 76.75692
0.6 72.98376 73.00756 73.01549 73.01547
0.7 69.51178
0.8 66.22511 66.25243 66.26154 66.26151
0.9 63.21352
1.0 60.35076 60.38014 60.38993 60.38990

I tabellen ovenfor har vi beregnet temperaturen Ty i det ytre røret ; først


med h=0.2 , så med h=0.1 og deretter ekstrapolert verdiene etter formelen i
(4.114) I følge denne formelen skal vi da få verdier med nøyaktighet av O(h4 )
som i dette tilfellet blir O(0.24 ) = O(10−5 ) ≈ 2 · 10−3 som eksempel. I den siste
kolonnen har vi utført beregningen med h = 2 · 10−3 med verdier som viser at
teorien stemmer.

4.3 Linearinsering av ikke-linære algebraiske ligninger


Som eksempel, bruker vi problemet i avsnitt (4.1.2):

y 00 (x) = 32 y 2
(4.115)
y(0) = 4 , y(1) = 1
der en av løsningene er gitt ved:
4
y= (4.116)
(1 + x)2
Vi diskretiserer(4.115) med bruk av sentraldifferanser for y 00 (x) :
yi+1 − 2yi + yi−1 3
= yi2
h2 2
eller ordnet:
 
3 2
yi−1 − 2 + h yi yi + yi+1 = 0 (4.117)
2
CHAPTER 4. FINITE DIFFERENCES FOR ODES 188

x0 x1 xi xN-1 xN xN+1

0.0 1.0

Figure 4.16: Marit 1: description

med h = ∆x
Vi har delt intervallet [0, 1] i N + 1 deler der h = 1/(N + 1) og xi = h · i ,
i = 0, 1, ..., N + 1. Da y0 = 4 og yN +1 = 1, blir (4.117):

− 2 + 32 h2 y1 y1 + y2 = −4


...
yi−1 − 2 + 23 h2 yi yi + yi+1 = 0

(4.118)
...
3 2

yN −1 − 2 + 2 h yN yN = −1
der i = 2, 3, ...N − 1
Koeffisientmatrisa for (4.118) er tridiagonal, men systemet er ikke-lineært.
(Et system av 2. grads ligninger). Vi har ikke formler som kan løse slike system,
og settet må derfor lineariseres. La oss skal se nærmere på to metoder for å
utføre denne lineariseringen.

4.3.1 Metoden med etterslep


Da ligningsystemet er ikke-lineært, må vi utføre en iterasjonsprosess. La yim+1
og yim være løsningen av den diskretiserte ligningen (4.117) eller (4.118) for
henholdsvis iterasjon m + 1 og m . Metoden med etterslep går ut på å erstatte
avhengige variable ved iterasjon m + 1 med tilsvarende variable fra iterasjon
m helt til vi bare har lineære ledd. I (4.117) og (4.118) er det y 2 -leddet som
forårsaker ikke-lineariteten og som derfor må lineariseres. Skriver ut (4.118):

− 2 + 23 y1m+1 h2  y1m+1 + y2m+1 = −4



m+1
yi−1 − 2 + 32 yim+1 h2 yim+1 + yi+1m+1
=0 (4.119)
m+1 3 m+1 2 m+1
N −1 − 2 + y
2 N h yN = −1
der i = 2, 3, ...N − 1 , m = 0, 1, 2, ...
Lineariseringen består nå i å erstatte 32 h2 y1m+1 , 32 h2 yim+1 og 32 h2 yN
m+1
med
3 2 m 3 2 m 3 2 m
2 h y1 , 2 h y i og 2 h y N slik at vi får følgende lineære system:

− 2 + 32 y1m h2 y1m + y2m = −4



m
yi−1 − 2 + 32 yim h2 yim + yi+1
m
=0 (4.120)
m 3 m 2 m
N −1 − 2 + 2 yN h yN = −1
der i = 2, 3, ...N − 1 , m = 0, 1, 2, ...
CHAPTER 4. FINITE DIFFERENCES FOR ODES 189

Vi har nå fått et lineært, tridiagonalt system som kan løses med Thomas-
algoritmen. For å starte iterasjonsprosessen, må vi tippe verdier for yi0 , i =
1, 2, ...N . Dersom vi ikke har spesielle opplysninger, kan vi f.eks. tippe yi0 = 0,
i = 1, 2, ...N . Gode startverdier vil generelt gi raskere konvergens. Vi må også
huske å teste for diagonal-dominans når vi bruker tdma. For (4.120) blir kravet:

2 + 3 yim h2 ≥ 2 , i = 1, 2, ..., N

2
som er oppfylt dersom alle yim > 0. Av Figure 3.8 ser vi at dette kravet er
oppfylt for den ene løsningen, men ikke for den andre. Når denne betingelsen
ikke er oppfylt, kan det være fornuftig å bruke en løsningsrutine med pivotering,
f.eks. tripiv istedenfor tdma. Når vi ikke vet hvoran iterasjonsprosessen vil
foreløpe, er det lurt å bare bruke antall iterasjoner som et stoppkrav. Etter vi
har fått innsikt i iterasjonsforløpet, kan vi legge til andre stoppkriterier. Endel
eksempler er vist i avsnitt (4.3.6)
Matlabprogrammet delay34 gir følgende resultat med h = 0.05 :

Itr. max. avvik


1 1.000e+000
2 5.525e-001
3 1.104e-001
4 2.632e-002
5 5.892e-003
6 1.328e-003
7 2.980e-004
8 6.690e-005
9 1.502e-005
10 3.370e-006
11 7.562e-007
12 1.697e-007

Max. avvik betyr her det maksimale relative avviket. Løsningen av differ-
4
anseligningen konvergerer langsomt mot løsningen yI = som vist på
(1 + x)2
(3.8) i avsnitt (3.2) . Den maksimale relative feilen i løsningen er ≈ 5.6 · 10−4 )
som ikke kan minskes uten å minske skrittlengden h.
Fordelen med denne metoden er at lineariseringsprosessen er enkel. Bakdelen
er at den konvergerer ofte langsomt, samt at vi gjerne må ha gode startverdier
for å få konvergens. Når vi vet hvordan iterasjonen forløper, kan vi som nevnt
ovenfor, legge inn et stoppkriterium basert på et iterasjonsavvik. Iterasjonsløkka
kan nå f.eks. se ut som vist nedenfor:
it = 0; itmax = 10 ; dymax = 1.0; RelTol = 1.0e-5;
d = 0 ; % høyre side
d(1) = - 4.0; d(n) = - 1.0;
while (dymax > RelTol) & (it < itmax)
it = it + 1; b = -(2.0 + fac*ym); % hoveddiagonal
ym1 = tdma(a,b,c,d); % Løser ligningsystemet
CHAPTER 4. FINITE DIFFERENCES FOR ODES 190

dymax = max(abs((ym1-ym)./ym1));% Beregner relativ avvik


ym = ym1; % Oppdatering fprintf(’ %10d %12.3e \n’,it,dymax);
end

Legg merke til at for å starte iterasjonsløkka, må dymax være større enn
RelTol

4.3.2 Newton-linearisering
Før vi setter opp den formelle utviklingen, viser vi en variant som er enkel å
bruke når ikke-linearitetene er rene produkt.

Setter yim+1 = yim + δyi (4.121)


der δyi er avviket (residuet) mellom yi -verdiene for de to iterasjonene. Ved
bruk av (4.121) :

2 2
yim+1 = (yim + δyi ) = (yim )2 + 2yim · δyi + (δyim )2
(4.122)
≈ (yim )2 + 2yim · δyi = yim (2yim+1 − yim )

Lineariseringen består i å neglisjere (δy)2 som liten i forhold til de andre


leddene.
(4.122) innsatt i (4.118) gir følgende system:

−(2 + 3y1m h2 )y1m+1 + y2m+1 = − 32 (yim h)2 − 4

m+1
yi−1 − (2 + 3yim h2 )yim+1 + yi+1
m+1
= − 23 (yim h)2 (4.123)

m+1 m 2 m+1
yN −1 − (2 + 3yN h )yN = − 32 (yN
m 2
h) − 1
der i = 2, 3, ..., N − 1 , N − 1, m = m = 0, 1, 2, ...
Vi har igjen fått et lineært, tridiagonalt system som kan løses med Thomas-
algoritmen. Velger samme startverdier som i foregående versjon. Matlabpro-
grammet taylor34 gir følgende resultat med h = 0.05 :

Itr. max. avvik


1 1.000e+000
2 3.765e-001
3 2.479e-002
4 9.174e-005
5 1.175e-009
6 2.405e-015

Vi ser at iterasjonsprosessen nå går mye raskere enn ved etterslep-metoden.


Riktignok langsomt i starten, men fra tredje iterasjon har vi rask konvergens. Lin-
eariseringen i (4.121) og (4.122) er egentlig en Taylorutvikling der vi rekkeutvikler
rundt iterasjon m og bare beholder de to første leddene. Kaller det ikke-
lineære leddet som skal lineariseres for F og antar at F er funksjon av den
CHAPTER 4. FINITE DIFFERENCES FOR ODES 191

m+1 variable z i punktet i ved iterasjon m + 1 : Vi skal linearisere leddet


avhengige
F (zi ) ≡ F (zi )m+1 . Bruker den siste notasjonen i fortsettelsen.
Rekkeutvikling:
 
∂F
F (zi )m+1 ≈ F (zi )m + δzi
dzi m (4.124)
der δzi = zim+1 − zim
I tilfellet ovenfor:

δzi → δyi , zim+1 → yim+1 , zim → yim , F (yi )m+1 = (yim+1 )2 , F (yi )m = (yim )2

som innsatt i (4.124) gir: (yim+1 )2 ≈ (yim )2 + 2yim · δyi som er identisk med
(4.122) . Fremgangsmåten i (4.124) kalles ofte Newton-linearisering.
I mange tilfeller inngår flere indekser i det ikke-linære leddet. Anta f.eks at
vi har et ledd der både zi og zi+1 inngår. Vi bruker da Taylorutvikling for to
variable:

   
∂F ∂F
F (zi , zi+1 )m+1 ≈ F (zi , zi+1 )m + δzi + δzi+1
∂zi m ∂zi+1 m (4.125)
der δzi = zim+1 − zim , δzi+1 = m+1
zi+1 − m
zi+1

Dersom både zi−1 , zi og zi+1 inngår, får vi:

F (zi−1 , zi , zi+1 )m+1 ≈ F (zi−1 , zi , zi+1 )m


     
∂F ∂F ∂F
+δzi−1 + δzi + δzi+1 (4.126)
∂zi−1 m ∂zi m ∂zi+1 m

m+1
der δzi−1 = zi−1 m
− zi−1 , δzi = zim+1 − zim , δzi+1 = zi+1
m+1 m
− zi+1

Tilsvarende for flere indekser.

4.3.3 Example:
p
Gitt differensialligningen y 00 (x) + y(x) y(x) = 0 som diskretisert med sentral-
differanser blir:

q
m+1
yi+1 − 2yim+1 + yi−1
m+1
+ h2 yim+1 yim+1 = 0 ved iterasjon m + 1.
q
Det er leddet yim+1 · yim+1 som er ikke-lineært og må lineariseres. I dette
3
tilfellet har vi bare et indeks og vi bruker (4.124) med zi → yi og F (yi ) = yi2 :
CHAPTER 4. FINITE DIFFERENCES FOR ODES 192

 
∂F 3 3 1
F (yi )m+1 ≈ F (yi )m + δyi = (yim ) 2 + δyi · 2 · (yim ) 2 eller
∂yi m
q
yim+1 yim+1 ≈ yim yim + 3
yim · δyi der δyi = yim+1 − yim
p p
2 ·

Merk at uttrykket nå er lineært da yim+1 bare inngår i 1. potens.


Innsatt i (4.3.3) får vi følgende differanseligning:

h2 m p m
 
m+1 3 2p m
yi−1 + h yi − 2 yim+1 + yi+1 m+1
= y yi (4.127)
2 2 i

4.3.4 Example:
y 00 (x) + sin (y(x)) = 0 som diskretisert med sentral-differanser blir:
m+1
− 2yim+1 + yi−1
m+1
+ h2 sin yim+1 = 0

yi+1 (4.128)
Det er leddet yim+1 som er ikke-lineært og må lineariseres. Vi har bare ett
indeks og vi bruker (4.124) med zi → yi og F (yi ) = sin(yi ):

 
∂F
F (yi )m+1 ≈ F (yi )m + δyi = sin(yim ) + δyi · cos(yim ) eller
∂yi m

sin(yim+1 ) ≈ sin(yim ) + cos(yim ) · δyi der δyi = yim+1 − yim

Innsatt i (4.128) får vi følgende differanseligning:

m+1
yi−1 + (h2 cos(yim ) − 2)yim+1 + yi+1
m+1
= h2 (yim cos(yim ) − sin(yim )) (4.129)

4.3.5 Example:
p
Gitt differensialligningen y 00 (x) + y(x) y 0 (x) = 0 som diskretisert med sentral-
differanser blir:

q p
m+1
yi+1 − 2yim+1 + yi−1
m+1
+ α · yim+1 m+1
yi+1 m+1
− yi−1 = 0 , der α = h h/2 (4.130)
q
Det er leddet yim+1 yi+1 m+1 m+1
− yi−1 som er ikke-lineært og må lineariseres. I
dette tilfellet har vi tre indekser og vi bruker (4.126) med zi−1 → yi−1 , zi → yi

og zi+1 → yi+1 samt F (yi−1 , yi , yi+1 )m = yi yi+1 − yi−1 . Finner de enkelte
leddene i (4.126) :
CHAPTER 4. FINITE DIFFERENCES FOR ODES 193

ym
 
∂F
F (yi−1 , yi , yi+1 )m = yim = − 2√ym i −ym
p m m ,
yi+1 − yi−1 ∂yi−1 ,
m i+1 i−1

m
   
∂F ∂F y
m − y m og tilslutt = 2√ym i −ym
p
∂yi = yi+1 i−1 ∂yi+1
m m i+1 i−1

Totalt:
q m
yim+1 m+1 m+1
≈ yim m − y m − √ yi
p
yi+1 − yi−1 yi+1 i−1 2 y m −y m
δyi−1
i+1 i−1

m
m − y m · δy + √ yi
p
+ yi+1 i−1 i 2 y m −y m
δyi+1
i+1 i−1

m+1 m+1
m+1
Merk at uttrykket nå er lineært da yi−1
og yi+1 , yi
bare inngår i 1.
potens. Vi setter dette inn i (4.130) som nå blir lineær:

ym ym
   
m+1
1 − α 2gim · yi−1 − (2 − αg m ) · yim+1 + 1 + α 2gim · yi+1
m+1

ym m m (4.131)
= α 2gim (yi+1 − yi−1 )

der g m =
p m m
yi+1 − yi−1

I neste avsnitt viser vi hvordan vi kan operere direkte med delta-størrelsene


m+1
δyi−1 , δyim+1 og δyi+1
m+1

Hvordan vil disse eksemplene bli dersom vi bruker


q metoden med etterslep?
m+1
Lign. (4.3.3)) i eksempel (4.3.3) skrives: yi−1 +(h2 yim+1 −2)·yim+1 +yi−1 m+1
=0
q
m+1 m+1
Koeffisienten foran yi -leddet inneholder yi som blir erstattet med
m+1 2 m+1 m+1
p m p m
yi slik at ligningen blir: yi−1 + (h yi − 2) · yi + yi−1 =0
I lign. ligning (4.128)) i eksempel (4.3.4) erstattes med slik at ligningen blir:
m+1
yi−1 − 2yim+1 + yi+1
m+1
= −h2 sin(yim ) = 0
Lign. (4.130)) q i eksempel (4.3.5) skrives:
m+1 m+1 m+1
yi−1 + (α · yi+1 − yi−1 − 2) · yim+1 + yi+1
m+1
=0
q
Koeffisienten foran yim+1 -leddet inneholder yi+1m+1 m+1
− yi−1 som erstattes
p m m
med yi+1 − yi−1 slik at ligningen blir:
m+1 m − 2) · y m+1 + y m+1 = 0
p m
yi−1 + (α · yi+1 − yi−1 i i+1

Når vi bruker denne metoden, må vi først skrive systemet på en form som viser
koeffisientene i ligning-systemet. Dersom koeffisientene inneholder avhengige
variable ved iterasjon m + 1, må disse erstattes med verdier fra iterasjon m. Men
dette er ofte det samme som å Taylor-utvikle koeffisientene rundt iterasjon m og
bruke bare 1. ledd i utviklingen.
CHAPTER 4. FINITE DIFFERENCES FOR ODES 194

Vi kan derfor vente at metoden med etterslep generelt konvergerer langsom-


mere enn når vi bruker to ledd av Taylor-utviklingen. Metoden med etterslep
brukes helst for partielle differanseligninger der f. eks. materialparametrene er
funksjon av de avhengige variable, f.eks. temperaturavhengige varmeledningstall.

4.3.6 Eksempler på stoppkriterier


Vi setter:

δyi = yim+1 − yim , i = 1, 2, ..., N , m = 0, 1, ...


(4.132)
der N er antall beregningspunkt
1. Test for absolutte størrelser.

ta1 = max(|δyi |) < tola (4.133)

N
1X
ta2 = |δyi | < tola (4.134)
n i=1
v
uN
1u X
ta3 = t (δyi )2 < tola (4.135)
n i=1

2. Test for relative størrelser.


 
δyi
tr1 = max m+1 < tolr , yim+1 6= 0 (4.136)
yi
PN
|δyi |
tr2 = PNi=1 m+1 < tolr (4.137)
y
i=1 i

max(|δyi |)
tr3 = < tolr (4.138)
max(|yim+1 |)
Dersom de størrelsene vi beregner er av størrelsesorden 1, er det likegyldig
om vi bruker en absolutt eller en relativ test. Vanligvis bruker vi en relativ test
da denne samsvarer med uttrykket "antall korrekte siffer". Dersom den størrelsen
vi beregner er liten i hele sitt beregningsområde, bruker vi vanligvis en absolutt
test.
La oss bruke testene ovenfor på problemet i avsnitt (3.2) der vi skal beregne
løsningen yII ) gitt på fig (3.8)
Vi gjentar ligningen fra (4.115) :
3 2
y 00 (x) = y (4.139)
2

y(0) = 4 , y(1) = 1 (4.140)


CHAPTER 4. FINITE DIFFERENCES FOR ODES 195

4
ys
2
yII
0

−2

ys ,yII
−4

−6

−8

−10

−12
0.0 0.2 0.4 0.6 0.8 1.0
x

Figure 4.17: Marit 36: descripton

Vi tipper et startprofil gitt ved parabelen ys = 20(x − x2 ) , 0 < x < 1 .


Denne parabelen, samt løsningen yII , er plottet i figuren nedenfor.
I dette tilfellet er det naturlig å bruke et relativt stoppkriterium da yII ligger
i intervallet [4, −10.68]. Med ni iterasjoner får vi følgende tabell:

Iter.nr. tr2 tr3


1 7.25 · 10−1 7.55 · 10−1
2 8.70 · 10−1 8.20 · 10−1
3 8.49 · 10−1 6.65 · 10−1
4 4.96 · 10−1 5.85 · 10−1
5 2.10 · 10−1 2.80 · 10−1
6 4.62 · 10−2 6.07 · 10−2
7 2.24 · 10−3 2.70 · 10−3
8 4.68 · 10−6 5.79 · 10−6
9 2.26 · 10−11 2.55 · 10−11

Iterasjonsforløpet er typisk for Newton-iterasjon da startverdiene våre ligger


et godt stykke fra de korrekte verdiene. For de seks første iterasjonene minker
feilen langsomt, mens vi har rask konvergens for de siste tre iterasjonene. Vi ser
også at det er liten forskjell mellom de to kriteriene i dette tilfellet.
Nedenfor vises listing av programmet avvikr.
clear
h = 0.025; % skrittlengde
ni = 1/h; % Antall intervall
# h maa velges slik at ni er et heltall
n = ni-1; % Antall ligninger
fac = 3.0*h*h;
a = ones(n,1) ; % underdiagonal
c = a; % overdiagonal
# a og c blir ikke ødelagt under eliminasjons-prosessen og
# kan derfor legges utenfor iterasjonsløkka.
CHAPTER 4. FINITE DIFFERENCES FOR ODES 196

x = (h:h:1.0-h)’;
ym = -20*x.*(1 - x); % Startverdier
b = zeros(n,1); d = b; dy = b; % allokering
fprintf(’ Itr. \n’);
for it = 1:9
b = -(2.0 + fac*ym); % hoveddiagonal
d = -(fac*0.5)*ym.^2 ; % høyre side
d(n) = d(n)- 1.0;
d(1) = d(1) - 4.0;
ym1 = tdma(a,b,c,d); % Løser ligningsystemet
dy = abs(ym1 - ym);
tr3 = max(dy)/max(abs(ym1));
tr2 = sum(dy)/sum(abs(ym1));
ym = ym1; % Oppdatering av y-verdier
fprintf(’ %10d %9.2e %9.2e \n’,it,tr2, tr3);
end

Programmet avvika som beregner de absolutte kriteriene, er temmelig


identisk med avvikr bortsett av vi erstatter beregningen av tr2 og tr3 med
ta1 = max(dy);
ta2 = sum(dy)/n;
ta3 = sqrt(dot(dy,dy))/n;

4.3.7 Ligninger på delta-form


Fra lign. (4.122)

(yim+1 )2 = (yim + δyi )2 = (yim )2 + 2yim · δyi + (δyi )2


≈ (yim )2 + 2yim · δyi = yim (2yim+1 − yim )
Vi har her innført δyi = yim+1 − yim slik at ligningsystemet løses m.h.p
yim+1 .Dette er ikke nødvendig. Vi kan beholde δyi som ukjent og løse systemet
m.h.p. delta-størrelsene. Ved å innføre ykm+1 = ykm + δyk , k = i − 1 , i , i + 1
samt (yim+1 )2 ≈ (yim )2 + 2yim · δyi i (4.119) eventuelt (4.123), får vi følgende
ligningsystem

−(2 + 3y1m h2 )δy1 + δy2 = −(y2m − 2y1m + 4) + 23 (y1m h)2

δyi−1 − (2 + 3yim h2 )δyi + δyi+1 m


= −(yi+1 − 2yim + yi−1
m
) + 23 (yim h)2

m 2 m m 3 m 2
δyN −1 − (2 + 3yN h )δyN = −(1 − 2yN + yN −1 ) + 2 (yN h)
(4.141)
der i = 2, 3, ..., N − 1 , m = 0, 1, 2, ...
Vi har benyttet at y0 = 4, δy0 = 0, yN +1 = 1, δyN +1 = 0 fra randbetingelsene.
For hver iterasjon oppdateres y-verdiene ved:

yim+1 = yim + δyi , i = 1, 2, ..., N (4.142)


Når vi har funnet ut hvordan iterasjonen forløper, kan vi f. eks. legge inn
stopp-kriterier som max |δyi | < ε1 eller max |δyi /yim+1 | < ε2 , i = 1, 2, ..., N
Iterasjonsløkka i programmet delta34 ser slik ut med bruk av (4.138):
CHAPTER 4. FINITE DIFFERENCES FOR ODES 197

it = 0; itmax = 10; dymax = 1.0; RelTol = 1.0e-5;


while (dymax > RelTol) & (it < itmax)
it = it + 1; b = -(2.0 + fac*y); % hoveddiagonal
d = (fac*0.5)*y.^2 ; % høyre side
for j = 2:n-1
d(j) = d(j) -(y(j+1)-2*y(j) + y(j-1));
end
d(n) = d(n)- (1.0- 2*y(n) + y(n-1));
d(1) = d(1) - (y(2)-2*y(1) + 4.0);
dy = tdma(a,b,c,d); % Løser ligningsystemet
y = y + dy; % Oppdatering av y-verdier
dymax = max(abs((dy)./y));% Beregner relativ avvik
fprintf(’ %10d %12.3e \n’,it,dymax);
end

4.3.8 Kvasilinearisering
I det foregående har vi først diskretisert ligningen og deretter linearisert den. Det
er fullt mulig å linearisere ligningen først. Dette blir gjerne kalt kvasi-linearisering.
La oss se på en generell, ikke-lineær 2. ordens ligning:

y 00 (x) = f (x, y, y 0 ) (4.143)


Skriver (4.143) på formen:

g(x, y, y 0 , y 00 ) ≡ y 00 (x) − f (x, y, y 0 ) = 0 (4.144)


Setter

δy = ym+1 − ym , δy 0 = ym+1
0 0
− ym , δy 00 = ym+1
00 00
− ym (4.145)
der m og m + 1 som vanlig betyr iterasjonsnummer. (I storparten av dette
avsnittet skriver vi iterasjonsnumrene som subindekser)
Ved rekkeutvikling av (4.144) rundt iterasjon m :

0 00 0 00
g(x, ym+1 , ym+1 , ym+1 ) ≈ g(x, ym , ym , ym )
     
∂g ∂g 0 ∂g
+ δy + δy + δy 00
∂y m ∂y 0 m ∂y 00 m
(4.146)
Anta at vi har iterert så mange ganger at
0 00 0 00
g(x, ym+1 , ym+1 , ym+1 ) ≈ g(x, ym , ym , ym )≈0
som innsatt i (4.146) gir:
     
∂g ∂g 0 ∂g
δy + δy + δy 00 = 0 (4.147)
∂y m ∂y 0 m ∂y 00 m
Ved derivasjon av (4.144):
∂g ∂f ∂g ∂f ∂g
=− , =− 0 , =1 (4.148)
∂y ∂y ∂y 0 ∂y ∂y 00
CHAPTER 4. FINITE DIFFERENCES FOR ODES 198

som innsatt i (4.147) gir:


   
00 ∂f ∂f
δy = δy + δy 0 (4.149)
∂y m ∂y 0 m

Ved å sette inn fra (4.145) i (4.149) samt bruk av (4.143), får vi:
   
00 ∂f 0 ∂f
ym+1 − ·y − · ym+1
∂y 0 m m+1 ∂y m
    (4.150)
0 ∂f ∂f 0
= f (x, ym , ym )− · ym − · ym
∂y m ∂y 0 m

Skriver tilslutt (4.150) med vår vanlige notasjon med iterasjonsnummer oppe:
   
00 m+1 ∂f 0 m+1 ∂f
(y ) − 0
· (y ) − · y m+1
∂y m ∂y m
    (4.151)
∂f ∂f
= f (x, y m , (y 0 )m ) − · (y 0 )m − · ym
∂y 0 m ∂y m
Vi har brukt en 2. ordens ligning som eksempel, men (4.149) – (4.151) lar
seg umiddelbart generalisere til en n’te ordens ligning, f.eks. en 3. ordens:

     
∂f ∂f ∂f
(y 000 )m+1 − · (y 00 )m+1 − · (y 0 )m+1 − · y m+1
∂y 00 ∂y 0 m ∂y m
 
∂f
= f (x, y m , (y 0 )m , (y 00 )m ) − · (y 00 )m
∂y 00 m
   
∂f 0 m ∂f
− · (y ) − · (y)m
∂y 0 m ∂y m
(4.152)

4.3.9 Example:
1)
3 2
Ligningen y 00 (x) = y
2
∂f ∂f
Her blir ∂y 0 =0, ∂y = 3y som innsatt i (4.151) gir:
3
(y 00 )m+1 − 3y m · y m+1 = − (y m )2
2
yi+1 −2yi +yi−1
Ved å diskretisere med sentraldifferanser yi00 ≈ h2 : får vi følgende
differanseligning:
CHAPTER 4. FINITE DIFFERENCES FOR ODES 199

m+1 3
yi−1 m+1
− (2 + 3h2 yim )yim+1 + yi+1 = − (hyim )2
2
som er i overenstemmelse med (4.123).
2)

Falkner-Skan-ligningen y 00 + y · y 00 + β · [1 − (y 0 )2 ] = 0
Vi skriver ligningen på formen:

y 00 = − y · y 00 + β · [1 − (y 0 )2 ] = f (x, y, y 0 , y 00 )


∂f ∂f ∂f
Lign. (4.152) gir med ∂y 00 = −y , ∂y 0 = 2βy 0 og ∂y = −y 00 :

(y 000 )m+1 + y m · (y 00


)m+1 − 2β(y 0)m · (y 0 )m+1 + (y 00 )m · y m+1
2
= −β 1 + [(y 0 )m ] + y m · (y 00 )m

Bruk sentraldifferanser og verifiser lign.(F.O.16) i appendiks F i kompendiet


!split

4.4 Løsning av Blasius ligning ved bruk av dif-


feransemetode
Test av kapittel 3 avsnitt 5

4.5 Differential boundary conditions/von Neu-


mann boundary conditions
To be completed. In the meantime you may consult chap. 3.6 in Numeriske
beregninger (in Norwegian).

4.6 Iterative solution of ODEs


To be completed. In the meantime you may consult chap. 3.7 in Numeriske
beregninger (in Norwegian).

xm+1
1 = xm
1 − ... (4.153)
CHAPTER 4. FINITE DIFFERENCES FOR ODES 200

R R0

P
W ϕ

Figure 4.18: Marit 1: description

4.7 Exercises
Exercise 6: Circular clamped plate with concentrated single
load
Figure 4.18 show a rigidly clamped plate with radius R0 . The plate is loaded with
a single load P in the plate centre. The differential equation for the deflection
W (R) is given by:

d3 W 1 d2 W 1 dW P
3
+ 2
− 2 = (4.154)
dR R dR R dR 2πD · R
3
Et
The plate stifness D is given by: D = 12(1−ν) , where E is the modulus of
elasticity, ν is the Poissons ratio and t is the plate thickness. The boundary
conditions are given by:

dW dW
W (R0 ) = (R0 ) = 0, (0) = 0 (4.155)
dR dR
In which the two first are because it is rigidly clamped, and the last due to
the symmetry. We introduce dimmensionless variables: r = RR0 , ω(R) = 16πDW P R02
,
so that Eq. (4.154) can be written:

d3 ω 1 d2 ω 1 dω 8
+ − 2 = , 0<r<1 (4.156)
dr3 r dr2 r dr r
and Eq. (4.155):

dω dω
ω(1) = (1) = 0, (0) = 0 (4.157)
dr dr
The analytical solution is given by:
CHAPTER 4. FINITE DIFFERENCES FOR ODES 201


ω(r) = r2 [2 ln(r) − 1] + 1, (r) = 4 r ln(r) (4.158)
dr
Pen and paper:
The following problems should be done using pen and paper:
a) We introduce the inclination φ(r) = − dω
dr and insert into Eq. (4.156):

d2 φ 1 dφ φ 8
+ − 2 =− , (4.159)
dr2 r dr r r
with boundary conditions:

φ(0) = φ(1) = 0 (4.160)

discretize Eq. (4.159) with central differences. Partion the interval [0, 1] into
N segments, so that h = ∆r = N1 , which gives r = h · i, i = 0, 1, . . . , N . The
coefficient matrix should be tridiagonal. Write out the discretized equation for
i = 1, i and i = N − 1. Write the expressions for the diagonals, and the right
hand side.
b) Choose N = 4 (h = 14 ) in a) and solve the corresponding system of
equations.
c) We will now find ω(r) by integrating the equation dω dr = −φ(r) using
Heuns method. Since the right hand side is independenpt of ω , Heuns method
reduces to the trapes method. (The predictor is not necessary).
Find the ω− values in the points as in b).
d) Eq. (4.159) can also be written:

 
d 1 d
[r · φ(r)] (4.161)
dr r dr

Discretize Eq. (4.161) using Eq. (2.43). The coefficient matrix should be
tridiagonal. Write out the discretized equation for i = 1, i and i = N − 1. Write
the expressions for the diagonals, and the right hand side.
e) Solve Eq. (4.156) and (4.157) directly by introducing a new independant
variable z = ln(r) and show that Eq. (4.156) can be written: ω 000 (z) − 2ω 00 (z) =
8r2 ≡ 8e2z . Next guess a particular solution on the form ωp (z) = k · z · e2z ,
where k is a constant. Lastly decide the constants using (4.157).
Programing:
a) Write a python program that solves b) and c) from the pen and paper
exercise, numerically. Experiment with finer segmentation. If you want you can
download the python scelleton clampedPlate.py and fill in where applicable.
CHAPTER 4. FINITE DIFFERENCES FOR ODES 202

Hint 1. pen and paper:


b) Solutions: φ1 = 142 48 6
105 = 1.3524, φ2 = 35 = 1.3714, φ3 = 7 = 0.8571
c) Since ω0 is unknown, but ω4 = φ4 = 0 is known, first find ω3 , then ω2 , ω1
and ω0 . Use the φ-values obtained in a).
94
Solutions: ω0 = 105 = 0.8953, ω1 = 61 27
84 = 0.7262, ω2 = 70 = 0.3857,
3
ω2 = 28 = 0.1071
e) Solution given in Eq. (4.158)

Hint 2. programming:
# src-ch2/clampedPlate.py

import scipy
import scipy.linalg
import scipy.sparse
import scipy.sparse.linalg

#import matplotlib; matplotlib.use(’Qt4Agg’)


import matplotlib.pylab as plt
#plt.get_current_fig_manager().window.raise_()
import numpy as np

#### set default plot values: ####


LNWDT=2; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT; plt.rcParams[’font.size’] = FNT

def solve_phi(N, h):


i_vector = np.linspace(0, N, N + 1) # vector containing the indice number of all nodes
i_mid = i_vector[1:-1] # vector containing the indice number of all interior nodes nodes

# mainDiag = ?
# subDiag = ?
# superDiag = ?

# RHS = ?

# A = scipy.sparse.diags([?, ?, ?], [?, ?, ?], format=’csc’)

# Phi = scipy.sparse.linalg.spsolve(A, RHS)


# Phi = np.append(0, Phi)
# Phi = np.append(Phi, 0)

return Phi

def solve_omega(Phi, N, h):

Omega = np.zeros_like(Phi)
Omega[-1] = 0
#for i in range(N - 1, -1, -1):
# i takes the values N-2, N-3, .... , 1, 0
#Omega[i] = ?

return Omega

N = 3
CHAPTER 4. FINITE DIFFERENCES FOR ODES 203

r = np.linspace(0, 1, N + 1)
h = 1./N

Phi = solve_phi(N, h)

Omega = solve_omega(Phi, N, h)
Omega_analytic = r[1:]**2*(2*np.log(r[1:]) - 1) + 1
Omega_analytic = np.append(1, Omega_analytic) # log(0) not possible
Phi_analytic = - 4*r[1:]*np.log(r[1:])
Phi_analytic = np.append(0, Phi_analytic) # log(0) not possible

fig, ax = plt.subplots(2, 1, sharex=True, squeeze=False)

ax[0][0].plot(r, Phi, ’r’)


ax[0][0].plot(r, Phi_analytic, ’k--’)

ax[0][0].set_ylabel(r’$\phi$’)

ax[1][0].plot(r, Omega, ’r’)


ax[1][0].plot(r, Omega_analytic, ’k--’)
ax[1][0].legend([’numerical’, ’analytical’], frameon=False)
ax[1][0].set_ylabel(r’$\omega$’)
ax[1][0].set_xlabel(’r’)

plt.show()
Chapter 5

Mathematical properties of
partial differential equations

5.1 Model equations


I appendiks ??in [?] har vi utledet Navier-Stokes ligningene og energiligningen
for strømning av en inkompressibel fluid:

 2
∂ u ∂2u

Du ∂u ∂u ∂u 1 ∂p
≡ +u +v =− +ν + 2 (5.1)
Dt ∂t ∂x ∂y ρ ∂x ∂x2 ∂y
 2
∂2v

Dv ∂v ∂v ∂v 1 ∂p ∂ v
≡ +u +v =− +ν + 2 (5.2)
Dt ∂t ∂x ∂y ρ ∂y ∂x2 ∂y
 2
∂2T

DT ∂T ∂T ∂T ∂ T
≡ +u +v =α + (5.3)
Dt ∂t ∂x ∂y ∂x2 ∂y 2

Venstre side uttrykker transport (konveksjon, adveksjon) av en størrelse mens


høyre side angir diffusjon av den samme størrelsen. Transporten uttrykkes ved
1. ordens ligninger som er ikke-lineære, mens vi har 2. ordens ligninger på høyre
side. Disse er som ovenfor, lineære for konstante materialparametre. Mange
viktige problemer lar seg beskrive av spesial-tilfeller av disse ligningene, som
f.eks. grensesjiktproblemer. Siden slike spesialtilfeller selvfølgelig er lettere å
løse og analysere, brukes disse ofte når vi skal utvikle regneskjema. Dette er
gjerne en-dimensjonale, ikke-stasjonære tilfeller.

5.1.1 Liste over noen modell-ligninger


Poisson-ligning

∂2u ∂2
2
+ 2 = f (x, y) (5.4)
∂x ∂y

204
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 205

Laplace for f (x, y) = 0 Potensialteori, stasjonær varmeledning, osv.


Endimensjonal diffusjonsligning.

∂u ∂2u
=α 2 (5.5)
∂t ∂x
Bølgeligningen, akustisk grunnligning.

∂2u 2
2∂ u
= α 0 (5.6)
∂t2 ∂x2
1. ordens lineær bølgeligning ( konstant). Transportligning, adveksjonsligninga
∂u ∂u
+ α0 =0 (5.7)
∂t ∂x
Ikke-viskøs Burgers ligninng. Modell for Eulerligningene.
∂u ∂u
+u =0 (5.8)
∂t ∂x
Burgers ligning. Modell for inkompressibel Navier-Stokes ligninger.

∂u ∂u ∂2u
+u =ν 2 (5.9)
∂t ∂x ∂x
Tricomi-ligningen. Modell for transonisk strømning.

∂2u ∂2u
y + 2 =0 (5.10)
∂x2 ∂y
Konveksjon-diffusjonsligningen. Kalles også lineær Burgers ligning. Mod-
ellerer en rekke av tilfellene ovenfor.

∂u ∂u ∂2u
+ u0 =α 2 (5.11)
∂t ∂x ∂x
Utrykkene transport, konveksjon og adveksjon blir ofte benyttet om hverandre.
(5.7) ovenfor er kjent som adveksjonsligningen.

5.2 First order partial differential equations


D()
Transportsiden av basisligningene består av leddet som er en 1. ordens
Dt
partiell differensialligning (PDL). La oss derfor se nærmere på slike ved å betrakte
følgende ligning:
∂u ∂u
α +b +c=0 (5.12)
∂x ∂y
Dersom a eller b er funksjoner av x, y og u, kalles ligningen kvasilineær. Når a
og b bare er funksjoner av x og y, er ligningen lineær.
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 206

∂u
Ligningen er ikke-lineær dersom a eller b også er funksjoner av og/eller
∂x
∂u
. Transportsiden av f. eks. Navier-Stokes-ligningene er følgelig kvasi-lineære
∂y
1. ordens PDL, selvom vi vanligvis bruker betegnelsen ikke-lineær.
Skriver (5.12) på formen:
 
∂u b ∂u
a + +c=0 (5.13)
∂x a ∂y
Antar at u er kontinuerlig deriverbar:
∂u ∂u du ∂u dy ∂u
du = dx + dy → = +
∂x ∂y dx ∂x dx ∂y
Definerer nå karakteristikken for (5.12) ved:
dy b
= (5.14)
dx a
(5.14) innsatt ovenfor gir:
 
∂u b ∂u du
a + =a
∂x a ∂y dx
som videre gir:

a · du + c · dx = 0 (5.15)
dy
Langs karakteristikken gitt ved dx = ab reduseres (5.12) til en ODL gitt i (5.15).
(5.15) kalles kompatibilitetsligningen for (5.12). Dersom (5.12) er lineær, kan vi i
prinsippet først finne karakteristikkene og deretter løse (5.15). Dette er generelt
dy
ikke mulig når (5.12) er kvasilineær eller ikke-lineær fordi dx nå er en funksjon
av u, dvs: av løsningen selv.
Example 5.2.1. .
Adveksjonsligningen (5.7) gitt ved ∂u ∂u
∂t +a0 ∂x har løsningen u(x, t) = f (x−a0 t)
som er en bølge som forplanter seg med konstant profil og hastighet langs x-aksen.
Bølgen beveger seg mot høyre for α0 > 0. Karakteristikken er her gitt ved:
dx
dt = a0 .
Denne ligningen kan integreres direkte: x = a0 t + C1 . Konstanten C1 kan
f.eks. bestemmes ved: x = x0 for t = 0 som gir C1 = x0 . Ligningen for den
karakteristiske kurven bli da: x = a0 t + x0 . (5.15) med c = 0 og a = 1 gir
du = 0 . Dette betyr at u som her er partikkelhastigheten, er konstant langs
karakteristikken.
La oss som et eksempel på startverdier, velge
(
1 − x2 for |x| ≤ 1
u(x, 0) =
0for |x| > 1
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 207

Dette er en parabel. Fra u(x, t) = f (x − a0 t) fås u(x, 0) = f (x). Med


ζ = x − a0 t, kan vi skrive løsningen:
(
1 − ζ 2 for |ζ| ≤ 1
u(x, t) =
0 for |ζ| > 1
Når vi bruker ζ som variabel, er løsningen stasjonær: Vi følger med bølgen.
Fig. 5.1 nedenfor oppsummerer eksemplet.

u
u(x,0) = 1 - x2 1

-1 1
x

t1
dx = a > 0
0
dt
t

Figure 5.1: Caption goes here.

Example 5.2.2. .
Ikke-viskøs Burgers ligning (5.8) er gitt ved:
∂u ∂u
+u =0
∂t ∂x
Denne har løsningen u(x, t) = f (x − u · t) og karakteristikker gitt ved: dx
dt = u.
Dette er samme løsningen som i forrige eksempel, med den viktige forskjellen
at nå er a0 erstattet med u. Karakteristikkenes helning varierer nå med x, som
indikert på figuren på neste side.
Samme startbetingelser som i forrige eksempel, gir følgende løsning:
(
1 − ζ 2 for |ζ| ≤ 1
u(x, t) = der ζ = x − u · t
0 for |ζ| > 1
Igjen ser vi at den eneste forskjellen fra forrige eksempel er at a0 nå er
erstattet med u. Løst eksplisitt m.h.p. u der u(x, t) = 0 for |ζ| > 1:
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 208

t
dx = u
dt

Figure 5.2: Caption goes here.

1
u(x, t) = 2 [(2xt − 1) ± g(x, t)], g(x, t)
2t
p
= 1 − 4xt + 4t2 , |ζ| ≤ 1 (5.16)
∂u g(x, t) ± 1
= (5.17)
∂x t · g(x, t)

Flertydig løsning inntreffer når karakteristikkene krysser hverandre. (Fig. 5.2)


I dette tilfellet har u(x, t) to verdier for x ≥ 1, når ∂u∂x (1, t) > 0. Den kritiske
∂u
verdien tkrit når dette inntreffer, skjer når ∂x (1, t) → ∞ som fra (5.17) impliserer
g(1, t) = 0 = 1 − 2t → tkrit = 12 .
For t ≤ 12 brukes (5.16) og (5.17) med positivt fortegn for g(x, t) for alle
2
x-verdier. For t > 12 er den kritiske verdien av x gitt ved x∗ = 1+4t 4t med
tilhørende u-verdi u∗ = 1 − 4t12 . For −1 ≤ x ≤ x∗ brukes fremdeles (5.16) og
(5.17) med positivt fortegn for g(x, t), men for 1 ≤ x ≤ x∗ er den nedre greina
av løsningen gitt ved å bruke (5.16) og (5.17) med negativt fortegn foran g(x, t).
Maksimalverdien umaks = 1 er hele tiden gitt ved x = t.
Dersom vi ønsker en entydig løsning av fysikalske grunner, må vi innføre en
bevegelig diskontinuitet: I gassdynamikk er dette et sjokk ; i væsker hydrauliske
sprang. Løsningen er presentert i grafisk form:
Ligningen for de karakteristiske kurvene i diagrammet er gitt ved:

x = (1 − x20 ) · t + x0 , der x = x0 for t = 0


CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 209

3.0

2.5

2.0

1.5

t
1.0

0.5

0.0
−2 −1 0 1 2 3
x

Figure 5.3: Illustration of the characteristic curves.

1.2
t=0
1.0 t = 12
t =1
0.8

0.6
u

0.4

0.2

0.0
−1.0 −0.5 0.0 0.5 1.0 1.5
x

Figure 5.4: Marit 38: Inviscid Burgers equation

5.3 Second order partial differenatial equations


En 2. ordens partiell differensialligning ( PDL ) i to uavhengige variable x og y
kan skrives på formen:

∂2φ ∂2φ ∂2φ


A + B + C +f =0 (5.18)
∂x2 ∂x∂y ∂y 2
Dersom A, B, C og f er funksjoner av x, y, φ, ∂φ ∂φ
∂x og ∂y , betegnes (5.18) som
kvasilineær. Dersom A, B og C bare er funksjoner av x og y, betegnes (5.18)
som semilineær. Er også f bare funksjon av x og y, er (5.18) lineær.
Example 5.3.1. .
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 210

∂ 2 φ ∂φ
 
∂φ
− − exy sin φ = 0 kvasilineær (5.19)
∂x ∂x2 ∂x
∂ 2 φ ∂φ
x 2 − − exy sin φ = 0 semilineær (5.20)
∂x ∂x
 2 2 2
∂ φ ∂ φ
2
= 0 ikke-lineær (5.21)
∂x ∂y 2
En PDL som kan skrives på formen

∂2φ ∂2φ ∂2φ ∂φ ∂φ


A 2
+B +C 2 +D +E + Fφ + G = 0 (5.22)
∂x ∂x∂y ∂x ∂x ∂y
der A, B, C, D, E, F , og G bare er funksjoner av x og y, kalles en 2. ordens
lineær PDL. (5.22) er følgelig et spesialtilfelle av (5.18). Merk: Vanligvis vil vi
bruke betegnelsen "ikke-lineær" som motsetning til "lineær". La oss nå undersøke
om (5.18) har karakteristikker.
Setter u = ∂φ ∂φ ∂u
∂x og v = ∂y som impliserer at ∂y = ∂x .
∂v

(5.18) kan da skrives som et system av to 1. ordens PDL:

∂u ∂u ∂v
A +B +C +f =0 (5.23)
∂x ∂y ∂y
∂u ∂v
− =0 (5.24)
∂y ∂x
Det kan vises at høyere ordens (kvasilineære) PDL alltid kan skrives som
et system av 1. ordens PDL, men oppspaltingen kan skje på mange måter.
Dersom (5.18) f.eks. er potensialligningen i gassdynamikk, kan vi tyde φ som
hastighetspotensialet. (5.24) er da betingelsen for rotasjonsfri strømning.
Vi vil nå forsøke å skrive (5.23) og (5.24) som et totalt differensial. (Se (5.13)
– (5.15)) Multipliserer (5.24) med en vilkårlig skalar σ og adderer med (5.23):
     
∂u B + σ ∂u ∂v C ∂v
A + −σ − +f =0 (5.25)
∂x A ∂y ∂x σ ∂y
Nå har vi:
du ∂u dy ∂u dv ∂v dy ∂v
= + , = +
dx ∂x dx ∂y dx ∂x dx ∂y
Derav:
du ∂u ∂u dv ∂v ∂v
= +λ , = +λ (5.26)
dx ∂x ∂y dx ∂x ∂y
der vi har definert λ ved:
dy
λ= (5.27)
dx
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 211

Ved å sammenligne (5.25) og (5.26):


dy B+σ C
=λ= =− (5.28)
dx A σ
(5.28) innsatt i (5.25) gir kompatibilitetsligningen
du dv
A −σ +f =0 (5.29)
dx dx
Dersom karakteristikkene er reelle, dvs. λ er reell, har vi transformert den
opprinnelige PDL til en ODL gitt i (5.29) langs retninger uttrykt i (5.27).
Fra (5.28):
C
σ=− (5.30)
λ
som også gir:

B − Cλ
λ= (5.31)
A
Følgende 2. gradsligning finnes fra (5.31) for bestemmelse av λ:

Aλ2 − Bλ + C = 0 (5.32)
eller ved bruk av (5.27):

A · (dy)2 − B · dy · dx + C · (dx)2 = 0 (5.33)


Etter at λ er funnet fra (5.32) og (5.33), kan σ finnes fra (5.30) og (5.31) slik
at kompatibilitets- ligningen i (5.29) kan bestemmes. Istedenfor (5.29), kan vi
sette inn for σ fra (5.28) i (5.29) slik at vi får følgende kompatibilitetsligning:
du C dv
A + +f =0 (5.34)
dx λ dx
2. gradsligningen (5.32) og (5.33) har røtter λ1 og λ2 der

B ± B 2 − 4AC
λ1,2 = (5.35)
2A
Vi har tre muligheter for røttene i (5.35):

• B 2 − 4AC > 0 ⇒ λ1 og λ2 er reelle


• B 2 − 4AC < 0 ⇒ λ1 og λ2 er komplekse
• B 2 − 4AC = 0 ⇒ λ1 = λ2 er reell

Den kvasilineære PDL i 5.3 kalles


CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 212

Hyperbolsk dersom B 2 − 4AC > 0: λ1 og λ reelle


• Elliptisk dersom B 2 − 4AC < 0: Ingen reelle røtter
• Parabolsk dersom B 2 − 4AC = 0: λ1 = λ2 og reell
Betegnelsene ovenfor kommer fra analogien med kjeglesnittligningen Ax2 +
Bxy + Cy 2 + Dx + F = 0 der f.eks. x2 − y 2 = 1 framstiller en hyperbel siden
B 2 − 4AC > 0.
Røttene λ1 og λ2 er karakteristikkene. Derav:
• Hyperbolsk: To reelle karakteristikker
– Elliptisk: Ingen reelle karakteristikker
– Parabolsk: En reell karakteristikk

Example 5.3.2. Examples of classification of various PDEs.


∂2u ∂2u
Bølgeligningen − 2 = 0 er hyperbolsk da B 2 − 4AC = 4 > 0 Karak-
∂x2 ∂y
2 dy
teristikkene er gitt ved λ = 1 → = ±1
dx
2 2
∂ u ∂ u
Laplace-ligningen + 2 = 0 er elliptisk da B 2 − 4AC = −4 < 0
∂x2 ∂y
∂u ∂2u
Diffusjonsligningen = er parabolsk da B 2 − 4AC = 0
∂y ∂x2
Linearisert potensial-ligning for kompressibel strømning:

∂2φ ∂2φ
(1 − M 2 ) + 2 = 0, M = Mach-tallet. (5.36)
∂x2 ∂y
• M = 1: Parabolsk (degenerert)
• M < 1: Elliptisk. Subsonisk strømning
• M > 1: Hyperbolsk. Supersonisk strømning.

5.4 RANDBETINGELSER FOR 2. ORDENS


PDL
∂2u ∂2u
+ 2 = 0 : Elliptisk . Ingen reelle karakteristikker. (5.37)
∂x2 ∂y
∂2u ∂2u
− 2 = 0 : Hyperbolsk. To reelle karakteristikker. (5.38)
∂x2 ∂y
∂u ∂2u
= : Parabolsk. En reell karakteristikk. (5.39)
∂y ∂x2
Modell-ligningene ovenfor adskiller seg ved antall reelle karakteristikker.
Dette får direkte betydning for hvilke randbetingelser det er mulig å stille i de
tre tilfellene, da fysikalsk informasjon forplanter seg langs karakteristikkene.
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 213

5.4.1 Hyberbolsk ligning


Som eksempel bruker vi bølgeligningen:

∂2u ∂2u
2
= α02 2 (5.40)
∂t ∂x
dx
(5.40) har karakteristikkene = ±a0 der a0 er bølgeforplantnings- hastigheten.
dt
dx dx
Vi betegner = +a0 med C + og = −a0 med C − . Løsningsområdet for
dt dt
(5.40) er vist i fig. 5.5 nedenfor.

Open boundary Marching direction


t
Region of
influence

C+ C-
Region of
dependency

a b x

Figure 5.5: Caption goes here.

Løsningen i P avhenger bare av løsningen i avhengighetsområdet, samtidig


som verdien i P bare innvirker på punkt innefor influensområdet. Randverdier
for rendene x = a og x = b kan ikke foreskrives uavhengig av initialverdier for
t = 0. Løst som initialverdiproblem, må (5.40) også ha en initialbetingelse for
∂u
ved t = 0.
∂t

5.4.2 Elliptisk ligning


Modell-ligning:

∂2u ∂2u
+ 2 =0 (5.41)
∂x2 ∂y
Løsningsområdet er som vist i fig. 5.6
Vi har ingen reelle karakteristikker. Hele området Ω, inkludert randkurven
C, er både avhengighetsområde og influensområde for P : Enhver forandring
av en verdi i Ω eller på C vil influere på verdien i P . (5.41) er da et rent
randverdiproblem, og følgende randbetingelser er aktuelle:
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 214

y
n
C

Region of influence
and region of dependency

Figure 5.6: Caption goes here.

• u gitt på C: Dirichlet-betingelse
∂u
– gitt på C: Neumann-betingelse
∂n
∂u
– u og gitt: Blandet betingelse (Robin-betingelse)
∂n

5.4.3 Parabolsk ligning


Modell-ligning:

∂u ∂2u
= (5.42)
∂t ∂x2
Løsningsområdet for (5.42) er gitt i fig. 5.7 nedenfor.
Fra klassifiseringsligningen (5.33) finner vi:
dt = 0 ⇒ t = konstant er karakteristikken (den karakteristiske kurva) i
dette tilfellet. Derav: a0 = dx
dt = ∞ som betyr at forplantnigshastigheten langs
karakeristikken t = konstant er uendelig stor. Verdien i P avhenger av verdien
i alle punktene i det fysiske rommet for tidligere verdier av tiden t, inkludert
nåtiden. (5.42) oppfører seg som en elliptisk ligning for hver verdi t = konstant.
Istedenfor t, kan vi ha en romkoordinat. Den tidslignende koordinaten kalles
ofte den evolusjonsvariable: Den retningen vi marsjerer i.
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 215

Open boundary Marching direction


t

Region of influence
P

Characteristic

Region of dependency

a b x

Figure 5.7: Caption goes here.

5.5 VELFORMULERT PROBLEM. OPPSUM-


MERING
Et fysisk problem er velformulert (well-posed) dersom løsningen eksisterer, er
entydig og er kontinuerlig avhengig av rand- og initialbetingelsene. Nedenfor
lister vi opp de betingelsene som må oppfylles for at et problem som kan beskrives
ved en elliptisk, parabolsk eller hyperbolsk PDL , skal være velformulert.

Elliptisk PDL. Løsningsområdet må være lukket og kontinuerlige randbetingelser


må gis langs hele randkurven. (Se fig. 5.6). Randbetingelsene kan være av Dirich-
let, Neumann eller blandet type.

Parabolsk PDL. Løsningsområdet må være åpent i marsjretningen (evolusjon-


sretningen). Initialdata må gis langs den tidslignende randen, og kontinuerlige
randbetingelser må gis langs den fysiske randen for løsningsområdet. Rand-
betingelsene er av samme type som ved elliptiske PDL.

Hyperbolske PDL. Løsningsområdet må være åpent i evolusjonsretningen.


Initialdata må gis langs den tidslignende randen, og kontinuerlige randbetingelser
må gis langs den fysiske randen for løsningsområdet. Randbetingelsene kan være
av samme type som ved elliptiske PDL. Initialdata kan ikke spesifiseres langs
en karakteristisk kurve. En hyperbolsk PDL kan løses som et rent initialverdi-
problem. Betegnes da ofte som et Cauchy-problem. Initialdata må da spesifiseres
langs en ikke-karakteristisk kurve.

Litt om Navier-Stokes ligningsystemet. Med N-S-systemet menes N-S


ligningene pluss kontinuitetsligningen og energi-ligningen. Dette settet er generelt
mye mer komplisert enn de modell-ligningene vi har sett på ovenfor. Settet har
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 216

ofte egenskapene til to eller alle tre standard-typene samtidig. (Ikke i samme
punkt heldigvis)
Example 5.5.1. .
Kontinuitetsligningen betraktet som en ligning for tettheten ρ er en 1. ordens
PDL der karakteristikken er partikkelbanen. Denne ligningen er av hyperbolsk
karakter både for stasjonær og ikke-stasjonær strømning.
Example 5.5.2. .
Bevegelsesligningene betraktet som en ligning for hastigheten V ~ , er elliptisk
for stasjonær strømning og parabolsk for ikke-stasjonær strømning. Det samme
kan sies om energiligningen når vi betrakter den som en ligning for temperaturen
T.
Dersom vi antar at N-S-systemet beholder de matematiske egenskapene for
hver av ligningene betraktet enkeltvis, kan vi si at N-S-systemet er parabolsk-
hyperbolsk for ikke-stasjonær strømning og elliptisk-hyperbolsk for stasjonær
strømning. Den hyperbolske karakteren skyldes i begge tilfeller kontinuitets-
ligningen. Merk at evolusjonskarakteren for systemet forsvinner for en inkom-
pressibel fluid selv om strømningen er ikke-stasjonær. Rand- betingelsene for
hele systemet stilles i utgangspunktet utfra betraktningene som er gitt oven-
for. I kompliserte tilfeller blir dette en blanding av matematiske, fysikalske og
empiriske overlegninger.

Tilleggsbemerkninger. Klassifiseringskriteriet i (5.35) gjelder bare for to


uavhengige variable. Dersom vi legger til ledd som gir ligningen en naturlig
utvidelse til flere dimensjoner, forandrer ikke dette karakteren av ligningen.
Example 5.5.3. .

∂2u ∂2u ∂2u


• + 2 + 2 er elliptisk
∂x2 ∂y ∂z
∂u ∂2u ∂2u
• = + 2 er parabolsk
∂t ∂x2 ∂y
∂2u ∂2u ∂2u
• 2
= + 2 er hyperbolsk
∂t ∂x2 ∂y

Fig. 5.5 viser de karakteristiske kurvene som rette linjer. Dette vil ikke
være tilfellet generelt, selv for lineære ligninger. For kvasilineære ligninger vil
karakteristikkene, som tidligere nevnt, også være funksjon av selve løsningen.
Example 5.5.4. .
Potensialligningen i to dimensjoner er gitt ved:
∂u ∂v ∂u
(u2 − a2 ) + (v 2 − a2 ) + 2uv =0
∂x ∂y ∂y
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 217

der a er lokal lydforplantningshastighet, u og v er fluidhastighet i henholdsvis x-


og y-retning. Karakteristikkene er her gitt ved:
√ √
uv ± a2 M 2 − 1
 
dy u2 + v 2
= 2 2
, der Machtallet M =
dx ± u −a a
(Se Zucrow [13], vol. II, for flere detaljer)

5.6 PARTIKULÆRLØSNINGER AV LINEÆRE


PDL
Mange lineære partielle differensialligninger lar seg løse ved separasjon av variable
som da vanligvis fører til Fourier-rekker. Eksempelvis har vi løst et diffusjon-
sproblem med denne metoden i ??appendiks 7 i [?], der løsningen er gitt ved
en uendelig Fourier-rekke. Men da ligningen er lineær, oppfyller hvert ledd i
rekka differensialligningen, slik at hvert ledd da er en partikulærløsning. Selv
om vi ikke finner den totale løsningen som tilfredstiller gitte rand-betingelser og
startbetingelser, gir likevel en partikulærløsning en god pekepinn om løsningen
for det aktuelle problemet.
Vi skal bruke følgende uttrykk for en rekke lineære modell-ligninger:

un (x, t) = ei(βn x−ωn t) = cos(βn x − ωn t) + i sin(βn x − ωn t), n = 1, 2, · · · (5.43)

Her er β et bølgetall og ω en vinkelfrekvens. Dessuten bruker vi begrep som


fasehastighet cf og gruppehastighet cg . (Henviser til appendiks ??appendiks 1 i
[?]). Velger å bruke den komplekse formen da både realdelen og imaginærdelen
hver for seg er en partikulærløsning. Utelater indeks n i (5.43) i fortsettelsen.
Vi har bruk for forskjellige deriverte av u(x, t):

∂u ∂2u
= −iω · u(x, t), = −ω 2 · u(x, t) (5.44)
∂t ∂t2
∂u ∂2u
= iβ · u(x, t), = −β 2 · u(x, t) (5.45)
∂x ∂x2
∂3u 3 ∂4u
= −β · u(x, t), = β 4 · u(x, t) (5.46)
∂x3 ∂x4
Diffusjonsligningen

∂u ∂2u
=α 2 (5.47)
∂t ∂x
Innsatt fra (5.46) i (5.47): (αβ 2 − iω) · u(x, t) = 0 → iω = αβ 2 som gir:
2
u(x, t) = e−αβ ·t
· eiβ·x (5.48)
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 218

2
Imaginærdelen av (5.48) gir u(x, t) = e−αβ ·t som f.eks. er i overenstemmelse
med løsningen i appendiks ??in appendix 7 in [?]. (Flere detaljer i kapittel ??)
Adveksjonsligningen
∂u ∂u
+ a0 =0 (5.49)
∂t ∂x
Innsatt fra (5.46) i (5.49): i · (−ω + α0 β) · u(x, t) = 0 → ω = α0 β som gir:

u(x, t) = eiβ(x−a0 t) (5.50)


Realdelen av (5.50) viser at profilet u(x, 0) = cos x forflytter seg uforandret til
høyre med konstant hastighet a0 . Dette vil gjelde for alle bølgetall βn , n =
1, 2, · · · slik at løsningen for et generelt startprofil u(x, 0) = f (x) også vil forflytte
seg uforandret. (Flere detaljer i ??appendix 1 in [?], samt kapittel ??).
Bølgeligningen

∂2u ∂2u
2
= a20 2 (5.51)
∂t ∂x
Innsatt fra (5.46) i (5.51): (−ω 2 + a20 β 2 ) · u(x, t) = 0 → ω = ±a0 β
som gir:

u(x, t) = eiβ(x±a0 t) (5.52)


Vi ser da at adveksjonsligningen er et spesialtilfelle av bølgeligningen. Fra
(5.52) ser vi at vi får to bølger, en i hver retning med uforandret profil. Da vi
ikke har noen randbetingelser, antar vi at −∞ < x < ∞. For et endelig intervall
a ≤ x ≤ b derimot, vil vi få superponering av de to bølgene ved f.eks. refleksjon
fra rendene, men de enkelte bølgene beholder profilen.
Korteweg-de Vries -ligningen

∂u ∂u ∂3u
+ a0 + b0 3 = 0 (5.53)
∂t ∂x ∂x
Dette er en ligning som beskriver vannbølger på grunt vann, og (5.53) er en lin-
earisert versjon av den egentlig ligningen. (Betegnes gjerne som KdV-ligningen).
Innsatt fra (5.46) i (5.53):

i · (−ω + a0 β − b0 β 3 ) · u(x, t) = 0 → ω = β(a0 − β 2 b0 ) (5.54)


som gir:
2
u(x, t) = eiβ[x−(a0 −β b0 )t]
(5.55)
Vi ser her at vinkelfrekvensen ω er er funksjon av bølgetallet β. Dette
betyr av de enkelte fasene βn , n = 1, 2, . . . , vil forplante seg med forskjellig
hastighet slik at et startprofil u(x, 0) = f (x) vil forandre fasong. Slike bølger
kalles dispersive og er bl. annet typisk for vannbølger. Generelt kalles relasjonen
ω(β)
ω = ω(β) for dispersjonsrelasjonen. Fasehastigheten er gitt ved cf = .
β
CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 219

β · a0
For tillfelle 2) og 3) blir fasehastigheten cf = = a0 uavhengig av
β
bølgetallet. Slike bølger kalles da ikke-dispersive.
Svingende bjelke

∂2u 4
2∂ u EI
2
+ a 4
= 0, a2 = (5.56)
∂t ∂x m
Gir transversalsvingninger av en bjelke etter elementær bjelketeori. EI er
bjelke-stivheten og m er masse pr. lengdeenhet. Innsatt fra (5.46) i (5.56):
(−ω 2 + a2 β 4 ) · u(x, t) = 0 → ω = ±a · β 2 som gir:

u(x, t) = eiβ(x±aβ·t) (5.57)


Som i tilfelle 4), har vi igjen en ligning som gir dispersive bølger. Fasehastigheten

er her gitt ved cf = a · β. Gruppehastigheten cg = = 2aβ 6= cf .

Chapter 6

Elliptic partial differential


equations

6.1 Introduction
Important and frequently occuring practical problems are governed by elliptic
PDEs, including steady-state temperature distribution in solids.

Famous elliptic PDEs.


Some famous elliptic PDEs are better know by their given names:

• Laplace:

∇2 u = 0 (6.1)

• Poisson:

∇2 u = q (6.2)

• Helmholtz:

∇2 u + c · u = q (6.3)

∂2 ∂2 ∂2
where ∇2 = + + in 3D
∂x2 ∂y 2 ∂z 2

220
CHAPTER 6. ELLIPTIC PDES 221

and
∂2 ∂2
where ∇2 = + in 2D
∂x2 ∂y 2
The 2D versions of the famous equations above are special cases of the a
generic elliptic PDE may be represented by:
   
∂ ∂u ∂ ∂u
a + b +c·u=q (6.4)
∂x ∂x ∂y ∂y
where a, b, c og q may be functions of x and y and a and b have the same sign.

• Transient heat conduction is governed by:

∂2T ∂2T ∂2T


 
∂T
=α + + (6.5)
∂t ∂x2 ∂y 2 ∂z 2
 
∂T
which is a parabolic PDE, but at steady state when = 0 , we get:
∂t
 2
∂2T ∂2T

∂ T
+ + =0 (6.6)
∂x2 ∂y 2 ∂z 2

which is an elliptic PDE.


From the classification approach in Chapter 5.3 (see also Classification of
linear 2nd order PDEs) we see that (6.1) to (6.3) are elliptic, meaning no real
characteristics. Therefore, elliptic PDEs must be treated as boundary value
problems (see 5.4 and 5.5) for a discussion about the conditions for a well posed
problem).
For the solution of a generic elliptic PDE like (6.4), in a domain in two-
dimensions bounded by the boundary curve C (6.1), we reiterate the most
common boundary value conditions from 5.4:

• Dirichlet-condition: u(x, y) = G1 (x, y) on the boundary cure C


∂u
• Neumann-condition: = G2 (x, y) on C
∂n
∂u(x, y)
• Robin-condition: a · u(x, y) + b · = G3 (x, y) on C
∂n

For the Neuman-problem, at least one value of u(x, y) must be specified on


C for the solution to be unique. Additionally, the contour integral of G2 (x, y)
on C must vanish.
Several physical problems may be modeled by the Poisson equation (6.2)
CHAPTER 6. ELLIPTIC PDES 222

C
n

u(x,y)

Figure 6.1: A solution domain in two-dimensions bounded by a boundary curve


C.

Possion problems.
• The stress equation for torsion of an elastic rod

• The displacement of an membrane under constant pressure.


• Stokes flow (low Reynolds number flow)
• Numerous analytical solutions (also in polar coordinantes) may be
found in [24] section 3-3.

6.2 Differanser. Notasjon


I avsnitt 2.4 brukte vi Taylor-utviklingen for en funksjon av en uavhengig
variabel til å utlede differanseformler. Tilsvarende kan gjøres for funksjoner av
flere uavhengige variable. Dersom uttrykkene ikke har noen kryssderiverte, kan
vi direkte bruke formlene som vi utledet i avsnitt 2.4. Vi må bare huske å holde
indekset for den andre variable konstant.
Følgende notasjon brukes for de diskrete verdiene i x- og y-retning:

xi = x0 + i · ∆x, i = 0, 1, 2, . . .
yj = y0 + j · ∆y, j = 0, 1, 2, . . .

Som tidligere forutsetter vi at ∆x og ∆y er konstante dersom intet annet


blir spesifisert. Figure 6.2 nedenfor gir eksempel på notasjonen i to dimensjoner.
CHAPTER 6. ELLIPTIC PDES 223

i-1 i i+1
j+1

y
i, j
j
Δy

j-1
x
Δx

Figure 6.2: Marit 1: description

Vi skriver nå opp en rekke formler direkte fra avsnitt 2.4.


Foroverdifferanser:

∂u ui+1,j − ui,j
= + O(∆x) (6.7)
∂x i,j ∆x
Bakoverdifferanser:

∂u ui,j − ui−1,j
= + O(∆x) (6.8)
∂x i,j ∆x
Sentraldifferanser

∂u ui+1,j − ui−1,j
+ O (∆x)2
 
= (6.9)
∂x i,j 2∆x

∂ 2 u

ui+1,j − 2ui,j + ui−1,j
+ O (∆x)2
 
2
= 2
(6.10)
∂x i,j (∆x)
∂u ∂2u
Tilsvarende formler for ∂y og ∂y 2 følger direkte:
Foroverdifferanser:

∂u ui,j+1 − ui,j
= (6.11)
∂y i,j
∆y
Bakoverdifferanser:

∂u ui,j − ui,j−1
= (6.12)
∂y i,j ∆y
Sentraldifferanser

∂u ui,j+1 − ui,j−1
= (6.13)
∂y i,j 2∆y

∂ 2 u

ui,j+1 − 2ui,j + ui,j−1
2
= (6.14)
∂y i,j (∆y)2
CHAPTER 6. ELLIPTIC PDES 224

6.2.1 Example: Discretization of the Laplace equation


2
∂2u
Vi diskretiserer Laplace-ligningen ∂∂yu2 + ∂y 2 = 0 ved å bruke (6.10)og (6.14) og
velger ∆x = ∆y.
Dette gir følgende differanseligning:

ui+1,j + ui−1,j + ui,j−1 + ui,j+1 − 4ui,j = 0


Det resulterende beregningsmolekylet er illustrert i Figure 6.3.

j+1

j-1
i-1 i i+1

Figure 6.3: 5-punkts beregningsmolekyl for diffusjonsligningen

Vi ser av formelen at senterverdien er middelverdien av verdiene i de andre


puntene. Denne formelen er velkjent og kalles gjerne 5-punkts-formelen (Brukes
i kapittel (6) ).
Ved render er vi ofte nødt til å bruke bakover eller foroverdifferanser. Vi gir
her noen formler med 2. ordens nøyaktighet.
Foroverdifferanser:

∂u −3ui,j + 4ui+1,j − ui+2,j
= (6.15)
∂x i,j 2∆x
Bakoverdifferanser:

∂u 3ui,j − 4ui−1,j + ui−2,j
= (6.16)
∂x i,j 2∆x
Formlene for 2.4 , 2.4 og 2.4 differanser gitt i kapittel 2 kan brukes nå også
bare vi utstyrer dem med to indekser. En fyldig samling av differanseformler
finnes i Anderson [23]. Detaljerte utledninger er gitt i Hirsch [11].

6.3 Direct numerical solution


In situations where the elliptic PDE correspons to the stationary solution of a
parabolic problem (6.5), one may naturally solve the parabolic equation until
stationary conditions occurs. Normally, this will be time consuming task and
one may encounter limitations to ensure a stable solution. By disregarding such
a timestepping approach one does not have to worry about stability. Apart from
CHAPTER 6. ELLIPTIC PDES 225

seeking a fast solution, we are also looking for schemes with efficient storage
management a reasonable programming effort.
Let us start by discretizing the stationary heat equation in a rectangular
plated with dimension as given in Figure 6.4:

∂2T ∂2T
+ =0 (6.17)
∂x2 ∂y 2

y
100 100 100 100
100

T1,5 T2,5 T3,5


0.0 0.0

T1,4 T2,4 T3,4


0.0 0.0

T1,3 T2,3 T3,3


1.5 0.0 0.0

T1,2 T2,2 T3,2


0.0 0.0

T1,1 T2,1 T3,1


0.0 0.0

0.0 0.0 0.0 0.0 0.0 x

1.0

Figure 6.4: Rectangular domain with prescribed values at the boundaries


(Dirichlet).

We adopt the following notation:

xi = x0 + i · h, i = 0, 1, 2, . . .
yj = y0 + j · h, j = 0, 1, 2, . . .

For convenience we assume ∆x = ∆y = h. The ordering of the unkown


temperatures is illsustrated in (6.5).
By approximation the second order differentials in (6.17) by central differences
we get the following numerical stencil:

Ti+1,j + Ti−1,j + Ti,j+1 + Ti,j−1 − 4Ti,j = 0 (6.18)

which states that the temperature Ti,j in at the location (i, j) depends on the
values of its neighbors to the left, right, up and down. Frequently, the neighbors
CHAPTER 6. ELLIPTIC PDES 226

j+1

j-1

i-1 i i+1

Figure 6.5: Illustration of the numerical stencil.

are denoted in compass notation, i.e. west = i − 1, east = i + 1, south = j − 1,


and north = j + 1. By referring to the compass directions with their first letters,
and equivalent representation of the stencil in (6.18) reads:

Te + Tw + Tn + Ts − 4Tm = 0 (6.19)

Tn

Tw Tm Te

Ts

Figure 6.6: Illustration of the numerical stencil with compass notation.

The smoothing nature of elliptic problems may be seen even more clearly by
isolating the Ti,j in (6.19) on the left hand side:

Te + Tw + Tn + Ts
Tm = (6.20)
4
showing that the temperature Tm in each point is the average temperature of
the neighbors (to the east, west, north, and south).
The temperature is prescribed at the bondaries (i.e. Dirichlet boundary
conditions) and are given by:

T = 0.0 at y = 0
T = 0.0 at x = 0 and x=1 for 0 ≤ y < 1.5 (6.21)
T = 100.0 at y = 1.5
CHAPTER 6. ELLIPTIC PDES 227

Our mission is now to find the temperature distribution over the plate by
using (6.18) and (6.21) with ∆x = ∆y = 0.25. In each discretized point in (6.5)
the temperatures need to satisfy (6.18), meaning that we have to satisfy as many
equations as we have unknown temperatures. As the temperatures in each point
depends on their neighbors, we end up with a system of algebraic equations.
To set up the system of equations we traverse our our unknows one by one
in a systematic manner and make use of use of (6.18) and (6.21) in each. All
unknown temperatures close to any of the boundaries (left, right, top, bottom)
in Figure 6.4 will be influenced by the prescribed and known temperatures the
wall via the 5-point stencil (6.18). Prescribed values do not have to be calculated
an can therefore be moved to the right hand side of the equation, and by doing
so we modify the numerical stencil in that specific discretized point. In fact,
inspection of Figure 6.4, reveals that only three unknown temperatures are not
explicitly influenced by the presences of the wall (T2,2 , T2,3 , and T2,3 ). The four
temperatures in the corners (T1,1 ,T1,5 , T3,1 , and T3,5 ) have two precribed values
to be accounted for on the right hand side of their specific version of the generic
numerical stencil (6.18). All other unknown temperatures close to the wall have
only one prescribed value to be accounted for in their specific numerical stenscil.
By starting at the lower left corner and traversing in the y-direction first,
and subsequently in the x-direction we get the following system of equations:

−4 · T11 + T12 + T21 = 0


T11 − 4 · T12 + T13 + T22 = 0
T12 − 4 · T13 + T14 + T23 = 0
T13 − 4 · T14 + T15 + T24 = 0
T14 − 4 · T15 + T25 = −100
T11 − 4 · T21 + T22 + T31 = 0
T12 + T21 − 4 · T22 + T23 + T32 = 0
T13 + T22 − 4 · T23 + T24 + T33 = 0 (6.22)
T14 + T23 − 4 · T24 + T25 + T34 = 0
T15 + T24 − 4 · T25 + T35 = 100
T21 − 4 · T31 + T32 = 0,
T22 + T31 − 4 · T32 + T33 = 0
T23 + T32 − 4 · T33 + T34 = 0
T24 + T33 − 4 · T34 + T35 = 0
T25 + T34 − 4 · T35 = −100

The equations in (6.22) represent a linear, algebraic system of equations with


5 × 3 = 15 unknowns, which has the more convenient and condensed symbolic
representation:
A·T=b (6.23)
CHAPTER 6. ELLIPTIC PDES 228

where A denotes the coefficient matrix, T holds the unknown tempeartures,


and b the prescribed boundary temperatures. Notice that the structure of the
coefficient matrix A is completely dictated by the way the unknown temperatures
are ordered. The non-zero elements in the coefficient matrix are markers for
which unknow temperatures are coupled with each other. Below we will show an
example where we order the temperatures in y-direction first and then x-direction.
In this case, the components of the coefficient matrix A and the temperature
vector T are given by:

    
−4 1 0 0 0 1 0 0 0 0 0 0 0 0 0 T11 0

 1 −4 1 0 0 0 1 0 0 0 0 0 0 0 0 
 T12  
  0 


 0 1 −4 1 0 0 0 1 0 0 0 0 0 0 0 
 T13  
  0 


 0 0 1 −4 1 0 0 0 1 0 0 0 0 0 0 
 T14  
  0 


 0 0 0 1 −4 0 0 0 0 1 0 0 0 0 0 
 T15  
  −100 


 1 0 0 0 0 −4 1 0 0 0 1 0 0 0 0 
 T21  
  0 


 0 1 0 0 0 1 −4 1 0 0 0 1 0 0 0 
 T22  
  0 


 0 0 1 0 0 0 1 −4 1 0 0 0 1 0 0 ·
 T23 =
  0 


 0 0 0 1 0 0 0 1 −4 1 0 0 0 1 0 
 T24  
  0 


 0 0 0 0 1 0 0 0 1 −4 0 0 0 0 1 
 T25  
  −100 


 0 0 0 0 0 1 0 0 0 0 −4 1 0 0 0 
 T31  
  0 


 0 0 0 0 0 0 1 0 0 0 1 −4 1 0 0 
 T32  
  0 


 0 0 0 0 0 0 0 1 0 0 0 1 −4 1 0 
 T33  
  0 

 0 0 0 0 0 0 0 0 1 0 0 0 1 −4 1  T34   0 
0 0 0 0 0 0 0 0 0 1 0 0 0 1 −4 T35 −100
(6.24)
The analytical solution of (6.17) and (6.21) may be found to be:

X
T (x, y) = 100 · An sinh(λn y) · sin(λn x) (6.25)
n=1
4
where λn = π · n and An =
λn sinh( 23 λn )

The analytical solution of the temperature field T (x, y) in (6.25) may be


proven to be symmetric around x = 0.5 (see 7).
We immediately realize that it may be inefficient to solve (6.24) as it is,
due to the presence of all the zero-elements. The coefficient matrix A has
15 × 15 = 225 elementes, out of which on 59 are non-zero. Further, a symmetric,
band structure of A is evident from (6.24). Clearly, these properties may be
exploited to construct an efficent scheme which does not need to store all non-zero
elements of A.
SciPy offers a sparse matrix package scipy.sparse, which has been used
previously (see section 4.1.1).
# src-ch7/laplace_Diriclhet1.py
import numpy as np
import scipy
CHAPTER 6. ELLIPTIC PDES 229

import scipy.linalg
import scipy.sparse
import scipy.sparse.linalg
import matplotlib.pylab as plt
import time
from math import sinh

#import matplotlib.pyplot as plt


# Change some default values to make plots more readable on the screen
LNWDT=2; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT; plt.rcParams[’font.size’] = FNT

# Set simulation parameters


n = 15
d = np.ones(n) # diagonals
b = np.zeros(n) #RHS
d0 = d*-4
d1 = d[0:-1]
d5 = d[0:10]

A = scipy.sparse.diags([d0, d1, d1, d5, d5], [0, 1, -1, 5, -5], format=’csc’)

#alternatively (scalar broadcasting version:)


#A = scipy.sparse.diags([1, 1, -4, 1, 1], [-5, -1, 0, 1, 5], shape=(15, 15)).toarray()

# update A matrix
A[4, 5], A[5, 4], A[10, 9], A[9, 10] = 0, 0, 0, 0
# update RHS:
b[4], b[9], b[14] = -100, -100, -100
#print A.toarray()

tic=time.clock()
theta = scipy.sparse.linalg.spsolve(A,b) #theta=sc.linalg.solve_triangular(A,d)
toc=time.clock()
print ’sparse solver time:’,toc-tic

tic=time.clock()
theta2=scipy.linalg.solve(A.toarray(),b)
toc=time.clock()
print ’linalg solver time:’,toc-tic

# surfaceplot:
x = np.linspace(0, 1, 5)
y = np.linspace(0, 1.5, 7)

X, Y = np.meshgrid(x, y)

T = np.zeros_like(X)

T[-1,:] = 100
for n in range(1,6):
T[n,1] = theta[n-1]
T[n,2] = theta[n+5-1]
T[n,3] = theta[n+10-1]
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
CHAPTER 6. ELLIPTIC PDES 230

import numpy as np
fig = plt.figure()
ax = fig.gca(projection=’3d’)
surf = ax.plot_surface(X, Y, T, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
ax.set_zlim(0, 110)

ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter(’%.02f’))
ax.set_xlabel(’x’)
ax.set_ylabel(’y’)
ax.set_zlabel(’T [$^o$C]’)
ax.set_xticks(x)
ax.set_yticks(y)

fig.colorbar(surf, shrink=0.5, aspect=5)


plt.show()

A somewhat more complicated solution of (6.17) may be found by specifying


the differente temperatures on all four boundaries. However, the code structure
follows the same way of reasoning as for the previous example:
# src-ch7/laplace_Diriclhet2.py
import numpy as np
import scipy
import scipy.linalg
import scipy.sparse
import scipy.sparse.linalg
import matplotlib.pylab as plt
import time
from math import sinh
#import matplotlib.pyplot as plt

# Change some default values to make plots more readable on the screen
LNWDT=2; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT; plt.rcParams[’font.size’] = FNT

# Set temperature at the top


Ttop=100
Tbottom=10
Tleft=10.0
Tright=10.0

xmax=1.0
ymax=1.5

# Set simulation parameters


#need hx=(1/nx)=hy=(1.5/ny)
Nx = 20
h=xmax/Nx
Ny = int(ymax/h)

nx = Nx-1
ny = Ny-1
n = (nx)*(ny) #number of unknowns
print n, nx, ny

d = np.ones(n) # diagonals
CHAPTER 6. ELLIPTIC PDES 231

b = np.zeros(n) #RHS
d0 = d*-4
d1 = d[0:-1]
d5 = d[0:-ny]
A = scipy.sparse.diags([d0, d1, d1, d5, d5], [0, 1, -1, ny, -ny], format=’csc’)

#alternatively (scalar broadcasting version:)


#A = scipy.sparse.diags([1, 1, -4, 1, 1], [-5, -1, 0, 1, 5], shape=(15, 15)).toarray()
# set elements to zero in A matrix where BC are imposed
for k in range(1,nx):
j = k*(ny)
i = j - 1
A[i, j], A[j, i] = 0, 0
b[i] = -Ttop

b[-ny:]+=-Tright #set the last ny elements to -Tright


b[-1]+=-Ttop #set the last element to -Ttop
b[0:ny-1]+=-Tleft #set the first ny elements to -Tleft
b[0::ny]+=-Tbottom #set every ny-th element to -Tbottom

tic=time.clock()
theta = scipy.sparse.linalg.spsolve(A,b) #theta=sc.linalg.solve_triangular(A,d)
toc=time.clock()
print ’sparse solver time:’,toc-tic

tic=time.clock()
theta2=scipy.linalg.solve(A.toarray(),b)
toc=time.clock()
print ’linalg solver time:’,toc-tic

# surfaceplot:
x = np.linspace(0, xmax, Nx + 1)
y = np.linspace(0, ymax, Ny + 1)

X, Y = np.meshgrid(x, y)

T = np.zeros_like(X)

# set the imposed boudary values


T[-1,:] = Ttop
T[0,:] = Tbottom
T[:,0] = Tleft
T[:,-1] = Tright

for j in range(1,ny+1):
for i in range(1, nx + 1):
T[j, i] = theta[j + (i-1)*ny - 1]

from mpl_toolkits.mplot3d import Axes3D


from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter

fig = plt.figure()
ax = fig.gca(projection=’3d’)
surf = ax.plot_surface(X, Y, T, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
CHAPTER 6. ELLIPTIC PDES 232

ax.set_zlim(0, Ttop+10)
ax.set_xlabel(’x’)
ax.set_ylabel(’y’)
ax.set_zlabel(’T [$^o$C]’)

nx=4
xticks=np.linspace(0.0,xmax,nx+1)
ax.set_xticks(xticks)
ny=8
yticks=np.linspace(0.0,ymax,ny+1)
ax.set_yticks(yticks)

nTicks=5
dT=int(Ttop/nTicks)
Tticklist=range(0,Ttop+1,dT)
ax.set_zticks(Tticklist)

#fig.colorbar(surf, shrink=0.5, aspect=5)


plt.show()

Numerical values are listed below with analytical values from (6.25) enclosed
in paranthesis.

T11 = T31 = 1.578 (1.406), T12 = T32 = 4.092 (3.725)


T13 = T33 = 9.057 (8.483), T14 = T34 = 19.620 (18.945)
T15 = T35 = 43.193 (43.483), T21 = 2.222 (1.987), T22 = 5.731 (5.261)
T23 = 12.518 (11.924), T24 = 26.228 (26.049), T25 = 53.154 (54.449)
The structure of the coefficient matrix will not necessarily be so regular in
all cases, e.g. more complicated operators than the Laplace-operator or even
more so for non-linear problems. Even though the matrix will predominantly be
sparse also for these problems, the requirements for fast solutions and efficent
storage will be harder to obtain for the problems. For such problems iterative
methods are appealing, as they often are relatively simple to program and hoffer
effective memory management. However, they are often hapered by convergence
challanges. We will look into iterative methods in a later section.

6.3.1 von Neumann boundary conditions


The problem illustrated in Figure 6.17 has prescribed temperatures on the
boundaries (i.e. Dirichlet boundaray conditions). In this section we will consider
a problem with identical governing equation (6.17) as for the problem in 6.17.
The only difference being that we consider von Neuman conditions, i.e. zero
derivatives, at x = 0 og y = 0, as illustrated in figure 6.7.
Mathematically the problem in Figure 6.7, is specified with the governing
equation (6.17) which we reiterate for convenience:

∂2T ∂2T
2
+ =0 (6.26)
∂x ∂y 2
CHAPTER 6. ELLIPTIC PDES 233

y
T = 1.0
1.0

∂T
=0 ∇ 2T = 0 T = 0.0
∂x

0.0 ∂T 1.0 x
=0
∂y

Figure 6.7: Laplace-equation for a quadratic domain with von Neumann


boundary conditions.

with corresponding boundary conditions (von Neuman)


∂T
=0 for x = 0, and 0 < y < 1 (6.27)
∂x
∂T
=0 for y = 0, and 0 < x < 1 (6.28)
∂y
and prescribed values for:

T =1 for y = 1, and 0 ≤ x ≤ 1
T =0 for x = 1, and 0 ≤ y < 1

By assuming ∆x = ∆y, as for the Dirichlet problem, an identical, generic


difference equation is obtained as in (6.18). However, at the boundaries we
need to take into account the von Neumann conditions. We will take a closer
∂T
look at = 0 for x = 0. The other von Neuman boundary is treated in the
∂x
same manner. Notice that we have discontinuities in the corners (1, 0) og (1, 1),
additionally the corner (0, 0) may cause problems too.
∂T
A central difference approximation (see Figure 6.8) of = 0 at i = 0 yields:
∂x
T1,j − T−1,j
= 0 → T−1,j = T1,j (6.29)
2∆x
where we have introduced ghostcells with negative indices outside the physical
domain to express the derivative at the boundary. Note that the requirement
of a zero derivative relate the value of the ghostcells to the values inside the
physical domain.
∂T
One might also approximate = 0 by forward differences (see (6.15)) for a
∂x
generic discrete point (i, j):
CHAPTER 6. ELLIPTIC PDES 234

j+1

T0,j T1,j
T-1,j T2,j

j-1

i = -1 i=0 i=1 i=2 x

Figure 6.8: Illustration of how ghostcells with negative indices may be used to
implement von Neumann boundary conditions.


∂T −3Ti,j + 4Ti+1,j − Ti+2,j
=
∂x i,j 2∆x
∂T
which for = 0 for x = 0 reduce to:
∂x
4T1,j − T2,j
T0,j = (6.30)
3
For the problem at hand, illustrated in Figure 6.7, central difference ap-
proximation (6.29) and forward difference approximation (6.30) yields fairly
similar results, but (6.30) results in a shorter code when the methods in 6.4 are
employed.
To solve the problem in Figure 6.7 we employ the numerical stencil (6.19)
for the unknows in the field (not influenced by the boundaries)

Tw + Te + Ts + Tn − 4Tm = 0 (6.31)

where we used the same ordering as given in Figurw 6.9. For the boundary
conditions we have chosen to implement the by means of (6.29) which is illustrated
in Figure 6.9 by the dashed lines.
Before setting up the complete equation system it normally pays of to look
at the boundaries, like the lowermost boundary, which by systematic usage of
(6.31) along with the boundary conditions in (6.28) yield:
CHAPTER 6. ELLIPTIC PDES 235

y
1.0 1.0 1.0 1.0 1.0

T14 T13 T14 T15 T16 0.0

T10 T9 T10 T11 T12 0.0

T6 T5 T6 T7 T8 0.0

T2 T1 T2 T3 T4 0.0
x

T5 T6 T7 T8

Figure 6.9: Von Neumann boundary conditions with ghost cells.

2T2 + 2T5 − 4T1 = 0


T1 + 2T6 + T3 − 4T2 = 0
T2 + 2T7 + T4 − 4T3 = 0
T3 + 2T8 − 4T4 = 0

The equations for the upper boundary become:

T9 + 2T14 − 4T13 = −1
T10 + T13 + T15 − 4T14 = −1
T11 + T14 + T16 − 4T15 = −1
T12 + T15 − 4T16 = −1

Notice that for the coarse mesh with only 16 unknown temperatures (see
Figure 6.7) only 4 (T6 , T7 , T10 , and T11 ) are not explicitly influenced by the
CHAPTER 6. ELLIPTIC PDES 236

boundaries.Finally, the complete discretized equation system for the problem


may be represented:

    
−4 2 0 0 2 0 0 0 0 0 0 0 0 0 0 0 T1 0

 1 −4 1 0 0 2 0 0 0 0 0 0 0 0 0 0 
 T2  
  0 


 0 1 −4 1 0 0 2 0 0 0 0 0 0 0 0 0 
 T3  
  0 


 0 0 1 −4 0 0 0 2 0 0 0 0 0 0 0 0 
 T4  
  0 


 1 0 0 0 −4 2 0 0 1 0 0 0 0 0 0 0 
 T5  
  0 


 0 1 0 0 1 −4 1 0 0 1 0 0 0 0 0 0 
 T6  
  0 


 0 0 1 0 0 1 −4 1 0 0 1 0 0 0 0 0 
 T7  
  0 


 0 0 0 1 0 0 1 −4 0 0 0 1 0 0 0 0 
· T8  
= 0 


 0 0 0 0 1 0 0 0 −4 2 0 0 1 0 0 0 
 T9  
  0 


 0 0 0 0 0 1 0 0 1 −4 1 0 0 1 0 0 
 T10  
  0 


 0 0 0 0 0 0 1 0 0 1 −4 1 0 0 1 0 
 T11  
  0 


 0 0 0 0 0 0 0 1 0 0 1 −4 0 0 0 1 
 T12  
  0 


 0 0 0 0 0 0 0 0 1 0 0 0 −4 2 0 0 
 T13  
  −1 


 0 0 0 0 0 0 0 0 0 1 0 0 1 −4 1 0 
 T14  
  −1 

 0 0 0 0 0 0 0 0 0 0 1 0 0 1 −4 1  T15   −1 
0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 −4 T16 −1
(6.32)
# src-ch7/laplace_Neumann.py; Visualization.py @ git@lrhgit/tkt4140/src/src-ch7/Visualization.py;

import numpy as np
import scipy
import scipy.linalg
import scipy.sparse
import scipy.sparse.linalg
import matplotlib.pylab as plt
import time
from math import sinh
#import matplotlib.pyplot as plt

# Change some default values to make plots more readable on the screen
LNWDT=2; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT; plt.rcParams[’font.size’] = FNT

def setup_LaplaceNeumann_xy(Ttop, Tright, nx, ny):


""" Function that returns A matrix and b vector of the laplace Neumann heat problem A*T=b using
and assuming dx=dy, based on numbering with respect to x-dir, e.g:

1 1 1 -4 2 2 0 0 0 0
T6 T5 T6 0 1 -4 0 2 0 0 0
T4 T3 T4 0 1 0 -4 2 1 0 0
T2 T1 T2 0 --> A = 0 1 1 -4 0 1 ,b = 0
T3 T4 0 0 1 0 -4 2 -1
0 0 0 1 1 -4 -1

T = [T1, T2, T3, T4, T5, T6]^T

Args:
nx(int): number of elements in each row in the grid, nx=2 in the example above
ny(int): number of elements in each column in the grid, ny=3 in the example above
CHAPTER 6. ELLIPTIC PDES 237

Returns:
A(matrix): Sparse matrix A, in the equation A*T = b
b(array): RHS, of the equation A*t = b
"""
n = (nx)*(ny) #number of unknowns
d = np.ones(n) # diagonals
b = np.zeros(n) #RHS

d0 = d.copy()*-4
d1_lower = d.copy()[0:-1]
d1_upper = d1_lower.copy()
dnx_lower = d.copy()[0:-nx]
dnx_upper = dnx_lower.copy()

d1_lower[nx-1::nx] = 0 # every nx element on first diagonal is zero; starting from the nx-th elem
d1_upper[nx-1::nx] = 0
d1_upper[::nx] = 2 # every nx element on first upper diagonal is two; stating from the first elem
# this correspond to all equations on border (x=0, y)
dnx_upper[0:nx] = 2 # the first nx elements in the nx-th upper diagonal is two;
# This correspond to all equations on border (x, y=0)

b[-nx:] = -Ttop
b[nx-1::nx] += -Tright

A = scipy.sparse.diags([d0, d1_upper, d1_lower, dnx_upper, dnx_lower], [0, 1, -1, nx, -nx], forma
return A, b

if __name__ == ’__main__’:
from Visualization import plot_SurfaceNeumann_xy
# Main program
# Set temperature at the top
Ttop=1
Tright = 0.0
xmax=1.0
ymax=1.

# Set simulation parameters


#need hx=(1/nx)=hy=(1.5/ny)

Nx = 10
h=xmax/Nx
Ny = int(ymax/h)

A, b = setup_LaplaceNeumann_xy(Ttop, Tright, Nx, Ny)

Temp = scipy.sparse.linalg.spsolve(A, b)

plot_SurfaceNeumann_xy(Temp, Ttop, Tright, xmax, ymax, Nx, Ny)


# figfile=’LaPlace_vNeumann.png’
# plt.savefig(figfile, format=’png’,transparent=True)
plt.show()

The analytical solution is given by:


CHAPTER 6. ELLIPTIC PDES 238


X
T (x, y) = An cosh(λn y) · cos(λn x), (6.33)
n=1
π (−1)n−1
der λn = (2n − 1) · , An = 2 , n = 1, 2, . . . (6.34)
2 λn cosh(λn )
The solution for the problem illustrated Figure 6.7 is computed and visualized
the the python code above. The solution is illustrated in Figure 6.10.
Marit 40: Har ikke endret figuren

Figure 6.10: Solution of the Laplace equation with von Neuman boundary
conditions.

6.4 Iterative methods for linear algebraic equa-


tion systems
In 4.6 we introduced the classical iteration methods, Jacobi, Gauss-Seidel og
SOR, for the solution of ordinary differtential equations (ODEs).
We will in this section seek to illustrate how these methods may be applied for
the numerical solution of linear, ellipitical PDEs, whereas criteria for convergence
of such iterative schemes will be presented in 6.4.6.
Discretizations of PDEs, in particular linear elliptic PDEs, will result in
a system of linear, algebraic equations on the form A · x = b, which may be
presented on component for a system of three equations as:
a11 x1 + a12 x2 + a13 x3 = b1 (6.35)
a21 x1 + a22 x2 + a23 x3 = b2 (6.36)
a31 x1 + a32 x2 + a33 x3 = b3 (6.37)
We rewrite (6.37) as an iterative scheme by normally referred to as:
CHAPTER 6. ELLIPTIC PDES 239

Jacobi’s method
1
xm+1
1 = xm
1 + [b1 − (a11 xm m m
1 + a12 x2 + a13 x3 )] (6.38)
a11
1
xm+1
2 = xm
2 + [b2 − (a21 xm m m
1 + a22 x2 + a23 x3 )] (6.39)
a22
1
xm+1
3 = xm
3 + [b3 − (a31 xm m m
1 + a32 x2 + a33 x3 )] (6.40)
a33

where we have introduced m as an iteration counter. In the case when xm i is


a solution of (6.37), the expression in the brackets of (6.40), will be zero and
thus xm+1
i = xm m
i , i.e. convergence is obtained. Whenever, xi is not a solution
of (6.37), the expression in the brackets of (6.40), will represent a correction to
the previous guess at iteration m. The intention with iterative schemes is to
construct them i
A more compact representation of (6.40) may be used for a system of n
equations:

xm+1
i = xmi + δxi (6.41)
 
n
1  X
δxi = bi − aij xm
j
 , i = 1, 2, . . . , n, m = 0, 1, . . . (6.42)
aii j=1

To start the iteration process one must chose a value x = x0 at iteration


m = 0. Jacobi’s method may also be derived directely from (4.153) in 4.6.
From (6.40) we see that Jacobi’s method may be improved by substitution
of xm+1
1 in the second equation and for xm+1
1 and xm+1
2 in the third equation,
to yield:

Gauss-Seidel’s method
1
xm+1
1 = xm
1 + [b1 − (a11 xm m m
1 + a12 x2 + a13 x3 )] (6.43)
a11
1
xm+1
2 = xm
2 + [b2 − (a21 xm+1
1 + a22 xm m
2 + a23 x3 )] (6.44)
a22
1
xm+1
3 = xm
3 + [b3 − (a31 xm+1
1 + a32 xm+1
2 + a33 xm3 )] (6.45)
a33

The successively improved Jacobi’s method, is normally referred to as Gauss-


Seidel’s method.
The incremental change may be multiplied with a factor ω, to yield another
variant of the iterative scheme:
CHAPTER 6. ELLIPTIC PDES 240

SOR method

ω
xm+1
1 = xm
1 + [b1 − (a11 xm m m
1 + a12 x2 + a13 x3 )]
a11
ω
xm+1
2 = xm
2 + [b2 − (a21 xm+1
1 + a22 xm m
2 + a23 x3 )] (6.46)
a22
ω
xm+1
3 = xm
3 + [b3 − (a31 xm+1
1 + a32 xm+1
2 + a33 xm3 )]
a33

A general version of (6.46) may be presented:

xm+1
i = xmi + δxi (6.47)
" i−1 n
!#
ω X
m+1
X
m
δxi = bi − aik xk + aik xk , i = 1, 2, . . . , n, (6.48)
aii
k=1 k=1

The factor ω is denoted the relaxation parameter or the relaxation factor.


The method in (6.48) is commonly referred to as the successive over relaxation
method when ω > 1 or simply abbreviated to the SOR method. With ω = 1
Gauss-Seidel’s method is retrieved.
The relaxation factor ω may be shown to be in the range (0, 2) for Laplace/Poisson
equations, but naturally ω > 1 is most efficient. We will not use the SOR method
is presented in (6.37), but rather use the difference equations directly, as in 4.6.
Let us first consider Poisson’s equation in two physical dimensions:

∂2u ∂2u
+ 2 = f (x, y) (6.49)
∂x2 ∂y
which after discretization with central differences, with ∆x = ∆y = h results
in the following difference equation:

ui−1,j + ui+1,j + ui,j+1 + ui,j−1 − 4ui,j − h2 · fi,j = 0 (6.50)


We discretize our two-dimensional domain in the normal manner as:

xi = x0 + i · h, i = 0, 1, 2, . . . , nx
yj = y0 + j · h, j = 0, 1, 2, . . . , ny (6.51)
where nx and ny denote the number of grid cells in the x− and y-direction,
respectively (see 6.3).
By using the general SOR method (6.48) on (6.50) and (6.51) we get the
following iterative scheme:
um+1
i,j = umi,j + δui,j (6.52)
ω  m+1
+ um+1 m m m 2

δui,j = u i,j−1 + ui+1,j + ui,j+1 − 4ui,j − h · fi,j (6.53)
4 i−1,j
CHAPTER 6. ELLIPTIC PDES 241

The scheme in (6.53) may be reformulated by introducing the residual Ri,j


Ri,j = um+1 m+1 m m m 2
 
i−1,j + ui,j−1 + ui+1,j + ui,j+1 − 4ui,j − h · fi,j (6.54)
Note that the residual Ri,j is what is left when a non correct solution is
plugged into to the difference equation (6.50) in a dicrete point (i, j). By
introducing the residual (6.54) into (6.53), the following iterative scheme may
be obtained:

ω
um+1
i,j = um
i,j + Ri,j (6.55)
4
We will now solve the example in Figure 6.4, 6.3, with the iterative SOR-
scheme in (6.53).

y
T2,7 T3,7 T4,7 T5,7

T1,7 T5,6
m
Ti,j+1
T1,6
m+1
Ti-1,j m m
Ti,j Ti+1,j
T2,3
T1,3
T2,2 T3,2 Tm+1
T1,2 i,j-1

T1,1 T2,1 T3,1 T4,1 T5,1 x

Figure 6.11: Rectangular domain as in Figure 6.4 but boundary nodes are
unknown due to von Neuman boundary conditions.

In Figure 6.11 we have introduced a new indexation as compared to the


problem in Figure 6.4, and we do not explicitly account for symmetry.
The boundary values are imposed at the boundaries, whereas the rest of the
unknown values are initialized to zero:
# Initialize T and impose boundary values
T = np.zeros_like(X)

T[-1,:] = Ttop
T[0,:] = Tbottom
T[:,0] = Tleft
T[:,-1] = Tright

In this first simple program we use ω = 1.5 and perform a fixed number of
20 iterations as shown in the program laplace_sor.py below with h = 0.25:
CHAPTER 6. ELLIPTIC PDES 242

# src-ch7/laplace_Diriclhet2.py
import numpy as np
import scipy
import scipy.linalg
import scipy.sparse
import scipy.sparse.linalg
import matplotlib.pylab as plt
import time
from math import sinh
from astropy.units import dT

#import matplotlib.pyplot as plt


# Change some default values to make plots more readable on the screen
LNWDT=2; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT; plt.rcParams[’font.size’] = FNT

# Set temperature at the top


Ttop=10
Tbottom=0.0
Tleft=0.0
Tright=0.0

xmax=1.0
ymax=1.5
# Set simulation parameters
#need hx=(1/nx)=hy=(1.5/ny)
Nx = 40
h=xmax/Nx
Ny = int(ymax/h)

nx = Nx-1
ny = Ny-1
n = (nx)*(ny) #number of unknowns

# surfaceplot:
x = np.linspace(0, xmax, Nx + 1)
y = np.linspace(0, ymax, Ny + 1)

X, Y = np.meshgrid(x, y)

# Initialize T and impose boundary values


T = np.zeros_like(X)

T[-1,:] = Ttop
T[0,:] = Tbottom
T[:,0] = Tleft
T[:,-1] = Tright

tic=time.clock()
omega = 1.5
for iteration in range(20):
for j in range(1,ny+1):
for i in range(1, nx + 1):
R = (T[j,i-1]+T[j-1,i]+T[j,i+1]+T[j+1,i]-4.0*T[j,i])
dT = 0.25*omega*R
T[j,i]+=dT
CHAPTER 6. ELLIPTIC PDES 243

toc=time.clock()
print ’GS solver time:’,toc-tic

As opposed to the above scheme with a fixed number of iterations, we seek


an iteration scheme with a proper stop criteria, reflecting that our solution
approximates the solution with a certain accuracy. Additionally, we would like to
find and relaxation parameter ω which reduces the number of required iterations
for a given accuracy. These topics will be addressed in the following section.

6.4.1 Stop criteria


Examples of equivalent stop criteria are:
• max(δTi,j ) < εa
 
δTi,j
• max < εr
Ti,j
• The residual Ri,j (6.54) may also be used
• Other alternatives:


1 XX 1 X X δTi,j
|δTi,j | < tola , < tolr , |Ti,j | =
6 0 (6.56)
N i j N i j Ti,j

where N = nx ny is the total number of unknowns. In (6.56) the residual may


be used rather than δTi,j .
In the first expression we use an abolsute tolerance, whereas a relative
tolerance is suggested in the latter. We choose to use the following alternative
for (6.56):
P P
|δTi,j | max (|δTi,j |)
Pi Pj < tolr , < tolr (6.57)
i j |Ti,j | max (|Ti,j |)
The expression (6.57) represents some kind of an average relative stop criteria,
as we sum over all computational grid points in these formulas.
From Figure 4.10 in 4.6, we observe that the number of iterations is a function
of both the relaxation parameter ω and the grid size h.
Marit 40: Har ikke endret figuren
A more generic program for the Poisson problem (6.49) with a stop criteria
max(|δTi,j |)
max(|Ti,j |) < tolr and variable grid size h is included below. As for the previous
code with a fixed number of iterations, both a Jacobi-scheme with array-slicing
and a Gauss-Seidel scheme is included for comparison.
# src-ch7/laplace_Diriclhet2.py
import numpy as np
import scipy
import scipy.linalg
import scipy.sparse
CHAPTER 6. ELLIPTIC PDES 244

300

250
h = 0.03125

200

iterasjoner
150

h = 0.0625
100

h = 0.125
50
h = 0.25

0
1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2
ω

Figure 6.12: Number of iterations as a function of ω and h with tolr = 10−5 .

import scipy.sparse.linalg
import matplotlib.pylab as plt
import time
from math import sinh
from astropy.units import dT

#import matplotlib.pyplot as plt

# Change some default values to make plots more readable on the screen
LNWDT=2; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT; plt.rcParams[’font.size’] = FNT
# Set temperature at the top
Ttop=10
Tbottom=0.0
Tleft=0.0
Tright=0.0

xmax=1.0
ymax=1.5

# Set simulation parameters


#need hx=(1/nx)=hy=(1.5/ny)
Nx = 20
h=xmax/Nx
Ny = int(ymax/h)

nx = Nx-1
ny = Ny-1
n = (nx)*(ny) #number of unknowns

# surfaceplot:
x = np.linspace(0, xmax, Nx + 1)
y = np.linspace(0, ymax, Ny + 1)

X, Y = np.meshgrid(x, y)

T = np.zeros_like(X)
CHAPTER 6. ELLIPTIC PDES 245

# set the imposed boudary values


T[-1,:] = Ttop
T[0,:] = Tbottom
T[:,0] = Tleft
T[:,-1] = Tright

T2 = T.copy()

reltol=1.0e-3

omega = 1.5
iteration = 0
rel_res=1.0

# Gauss-Seidel iterative solution


tic=time.clock()
while (rel_res > reltol):
dTmax=0.0
for j in range(1,ny+1):
for i in range(1, nx + 1):
R = (T[j,i-1]+T[j-1,i]+T[j,i+1]+T[j+1,i]-4.0*T[j,i])
dT = 0.25*omega*R
T[j,i]+=dT
dTmax=np.max([np.abs(dT),dTmax])
rel_res=dTmax/np.max(np.abs(T))
iteration+=1
toc=time.clock()
print "Gauss-Seidel solver time:\t{0:0.2f}. \t Nr. iterations {1}".format(toc-tic,iteration)

iteration = 0
rel_res=1.0
# Jacobi iterative solution
tic=time.clock()
while (rel_res > reltol):
R2 = (T2[1:-1,0:-2]+T2[0:-2,1:-1]+T2[1:-1,2:]+T2[2:,1:-1]-4.0*T2[1:-1,1:-1])
dT2 = 0.25*R2
T2[1:-1,1:-1]+=dT2
rel_res=np.max(dT2)/np.max(T2)
iteration+=1

toc=time.clock()
print "Jacobi solver time:\t\t{0:0.2f}. \t Nr. iterations {1}".format(toc-tic,iteration)

6.4.2 Optimal relaksasjonsparameter


Med optimal menes her den verdien som gir færrest mulig iterasjoner når ω
holdes konstant under hele beregningen. For Laplace- og Poisson-ligninger på
rektangulære områder er det mulig å beregne en slik optimal ω som vi vil kalle
den teoretisk optimale.
La Lx og Ly være utstrekningen av rektanglet i henholdsvis x- og y-retning.
Med den samme skrittlengden h i begge retningene, setter vi:
CHAPTER 6. ELLIPTIC PDES 246

Lx Ly
nx = , ny = der nx og ny blir antall deler i henholdsvis x- og y-retning.
h h
nx og ny skal være heltall. Den teoretisk optimale ω er da gitt ved:

1
ρ= [cos(π/nx ) + cos(π/ny )] (6.58)
2
2
ω= p (6.59)
1 + 1 − ρ2
Dersom skrittlengden h er forskjellig i x- og y- retning med h = hx i x-retning
og h = hy i y-retning, får vi isteden for (6.59):

cos(π/nx ) + (hx /hy )2 · cos(π/ny )


ρ= (6.60)
1 + (hx /hy )2
Dersom området ikke er rektangulært, kan vi bruke Garabedians estimat:
2
ω= √ , A er arealet av området (6.61)
1 + 3.014 · h/ A
La oss regne ut ω fra disse formlene for eksemplet der Lx = 1, Ly = 1.5 og
A = Lx · Ly = 1.5.

h (6.59) (6.61)
0.25 1.24 1.24
0.125 1.51 1.53
0.0625 1.72 1.74
0.03125 1.85 1.86
Vi ser at Garabedians estimat stemmer godt overens med de teoretisk eksakte
verdiene i dette tilfellet. Figur 6.12 stemmer også godt overens med verdiene i
denne tabellen.

6.4.3 Eksempel på bruk av SOR


Vi løser nå temperaturproblemet i figur 6.7 (se 6.3.1). Nummereringen blir som
vist nedenfor i figur 6.13.
Vi bruker også her falske punkt som indikert med de stiplede linjene. For
T1,1 får vi spesielt:
1 1
T1,1 = (T1,2 + T1,2 + T2,1 + T2,1 ) = (T1,2 + T2,1 ) (6.62)
4 2
Beregningen startes ved iterere langs y = 0 med start i T2,1 . Deretter itereres
langs x = 0 med start i T1,2 . Etterpå itereres i en dobbel løkke over de indre
punktene. Tilslutt beregnes T1,1 fra (6.62). Beregningen
P P er vist i programmet
i,j |δT |
lapsor2 på neste side. Vi har brukt stoppkriteriet Pi Pj |T | < tolr samt
i,j
i j
optimal ω fra (6.59) og tipper T = 0.5 som startverdier for hele feltet unntatt for
de gitte randbetingelsene. Nøyaktigheten er som i utskriften for lap2v3 i 6.3.1.
CHAPTER 6. ELLIPTIC PDES 247

1.0 1.0 1.0 1.0 1.0

T2,4 T1,4 T2,4 T3,4 T4,4 0.0

T2,3 T1,3 T2,3 T3,3 T4,3 0.0

T2,2 T1,2 T2,2 T3,2 T4,2 0.0

T2,1 T1,1 T2,1 T3,1 T4,1 0.0


x

T1,2 T2,2 T3,2 T4,2

Figure 6.13: Ghost-cells are used to implement von Neumann boundary condi-
tions.

% program lapsor2
clear
net = 1;
h = 0.25;
hn = h/2^(net -1);
nx = 1/hn; ny = nx;
imax = nx + 1; % points in x-direction
jmax = ny + 1; % points in y-direction
T = 0.5*ones(imax,jmax); % temperatures
% --- Compute optimal omega ---
ro = cos(pi/nx);
omega = 2/(1 + sqrt(1 - ro^2));
T(1:imax,jmax) = 1; % boundary values along y = 1
T(imax,1:jmax-1) = 0;% boundary values along x = 1
reltol = 1.0e-5; % relative iteration error
relres = 1.0; it = 0;
% --- Start iteration ---
while relres > reltol
it = it + 1;
Tsum = 0.0; dTsum = 0.0;
% --- boundary values along y = 0 ---
for i = 2: imax - 1
resid = 2*T(i,2) + T(i-1,1) + T(i+1,1) - 4*T(i,1);
dT = 0.25*omega*resid;
dTsum = dTsum + abs(dT);
T(i,1) = T(i,1) + dT;
Tsum = Tsum + abs(T(i,1));
end
% --- boundary values along x = 0 ---
for j = 2: jmax - 1
resid = 2*T(2,j) + T(1,j-1) + T(1,j+1) - 4*T(1,j);
dT = 0.25*omega*resid;
CHAPTER 6. ELLIPTIC PDES 248

dTsum = dTsum + abs(dT);


T(1,j) = T(1,j) + dT;
Tsum = Tsum + abs(T(1,j));
end
for i = 2: imax-1
for j = 2: jmax-1
resid = T(i-1,j) + T(i,j-1) + T(i+1,j) + T(i,j+1)-4*T(i,j);
dT = 0.25*omega*resid;
dTsum = dTsum + abs(dT);
T(i,j) = T(i,j) + dT;
Tsum = Tsum + abs(T(i,j));
end
end
T(1,1) = 0.5*(T(2,1) + T(1,2));
relres = dTsum/Tsum;
end

6.4.4 Startverdier og randbetingelser


Vi venter å få raskere konvergens dersom vi tipper startverdier som ligger nær den
korrekte løsningen. Dette er typisk for ikke-lineære ligninger, mens vi står mer
fritt til å tippe startverdier når vi løser lineære ligninger uten at det går utover
konvergenshastigheten. For temperaturproblemet i figur 6.4 for eksempel, er det
lite forskjell i antall iterasjoner om vi starter iterasjonen med å tippe T = 0 i hele
feltet eller om vi starter med T = 100. Den optimale ω for dette tilfellet er også
uavhengig av startverdiene. Situasjonen er helt forskjellig for tilfellet i figur 6.7.
Vi løser også her en lineær ligning, men har mer kompliserte randbetingelser
der vi foreskriver temperaturen langs to render (Dirichlet-betingelser) og den
deriverte av temperaturen langs de to andre rendene (Neumann-betingelser) .
Dessuten er temperaturen diskontinuerlig i hjørnet x = 1, y = 1. I hjørnet
x = 0, y = 0 er den korrekte løsningen T = 0.5 fra den analytiske løsningen.
Dersom vi tipper T = 0.5 som startverdier i hele feltet, får vi rask konvergens med
optimal ω lik den teoretiske fra (6.59). Dersom vi avviker litt fra T = 0.5 som
startverdi, er ikke lenger den optimale ω lik den teoretisk optimale. Situasjonen
blir som vist i figur 6.14 nedenfor.
Marit 40: Har ikke endret figuren
Tabellen nedenfor viser den teoretisk optimale ω etter formel (6.59) og (6.61)
h (6.59) (6.61)
0.25 1.17 1.14
0.125 1.45 1.45
0.0625 1.67 1.68
0.03125 1.82 1.83
Vi ser at tabell-verdiene stemmer godt med verdiene i figur 6.14 når startver-
dien for iterasjonsprosessen er 0.5.

6.4.5 Example: A non-linear elliptic PDE


In this example we will solve a non-linear elliptic Poisson equation for a square
2D-domain (see Figure 6.15) given by:
CHAPTER 6. ELLIPTIC PDES 249

2
h = 0.03125
1.9
h = 0.0625
1.8

1.7 h = 0.125

1.6
h = 0.25

ωopt
1.5

1.4

1.3

1.2

1.1

1
0.5 0.502 0.504 0.506 0.508 0.51 0.512 0.514 0.516 0.518 0.52
startverdier

Figure 6.14: The effect of intial values on the number of iterations for a problem
with sub-optimal ω.

∂2u ∂2u
+ 2 + u2 = −1 (6.63)
∂x2 ∂y
with Dicichlet boundary conditions, i.e precribed values u = 0 on all bound-
aries (see Figure 6.15).

y
u=0
1.0

u=0 ∇2u + u2 = -1 u=0

0.0 u=0 1.0 x

Figure 6.15: Solution domain and boundary conditions for a non-linear Poisson
equation.

The PDE in (6.63) is only weakly non-linear, so-called semi-linear, but the
approach for how to solve a non-linear elliptic PDE is still illustrated.
We discretize (6.63) with central differences over the domain in Figure 6.15
by a constant stepsize h in both physical directions and get the following system
CHAPTER 6. ELLIPTIC PDES 250

of equations when the source term on the right hands side has been moved to
the left hand side:

1
[ui+1,j + ui−1,j + ui,j−1 + ui,j‘1 − 4ui,j ] + u2i,j + 1 = 0
h2
or equivalently with by introducing the function fi,j :

fi,j = ui+1,j + ui−1,j + ui,j−1 + ui,j+1 − 4ui,j + h2 (u2i,j + 1) = 0 (6.64)


with xi = h · (i − 1), i = 1, 2, . . . and yj = h · (j − 1), j = 1, 2, . . . . A
computational mesh for h = 0.25 is illustrated in Figure 6.16.

y
u1,5 = 0 u2,5 = 0 u3,5 = 0 u4,5 = 0 u5,5 = 0

u2,4 u3,4 u4,4


u1,4 = 0 u5,4 = 0

u2,3 u3,3 u4,3


u1,3 = 0 u5,3 = 0

u2,2 u3,2 u4,2


u1,2 = 0 u5,2 = 0

u1,1 = 0 u2,1 = 0 u3,1 = 0 u4,1 = 0 u5,1 = 0 x

Figure 6.16: Computational mesh for the problem in Figure 6.15.

We will solve the non-linear function in (6.64) with Newton’s method by


changing each variable one at a time. In this case the iteration process becomes:

um+1
i,j = um
i,j + δui,j (6.65)
f (uk,l )
δui,j = −ω (6.66)
∂f (uk,l )
∂ui,j
where:

uk,l = um+1
k,l for k < i, l < j (6.67)
uk,l = um
k,l ellers (6.68)
CHAPTER 6. ELLIPTIC PDES 251

and
∂f f
= −4 + 2h2 · ui,j and δui,j = ω (6.69)
∂ui,j 4 − 2h2 ui,j

We have implemented (6.64) and (6.66) to (6.69) in the python code nonlin_poisson
below:
# Python Gauss-Seidel method
tic=time.clock()
while (rel_res > reltol):
du_max=0.0
for j in range(1,ny+1):
for i in range(1, nx + 1):
R = (U[j,i-1]+U[j-1,i]+U[j,i+1]+U[j+1,i]-4.0*U[j,i]) + h**2*(U[j,i]**2+1.0)
df=4-2*h**2*U[j,i]
dU = omega*R/df
U[j,i]+=dU
du_max=np.max([np.abs(dU),du_max])

rel_res=du_max/np.max(np.abs(U))

iteration+=1

toc=time.clock()
print "Python Gauss-Seidel CPU-time:\t{0:0.2f}. \t Nr. iterations {1}".format(toc-tic,iteration)

In this implementation we have used the following stop criterium:


max δui,j
≤ tolr (6.70)
max ui,j

nd initialize the solution in the field (excluding boundaries) with u = 0.


We have also used (6.59) to estimat an optimal ωest . In the table below we
compare the estimated optimal ωest with the real optimal ωopt in case of an
initial field of u = 0.
h ωest ωopt
0.25 1.17 1.19
0.125 1.45 1.46
0.0625 1.67 1.69
0.03125 1.82 1.83

We observe realtively good agreement between the two ω-valuse for a range of
grid sizes h, even though the PDE is weakly non-linear.
As the Gauss-Seidel algorithm above involves a triple-loop (the iterative
while-construct, pluss one loop in each physical direction), the naive python
implementation above must be expected to be computationally expensive.
For comparison we have also implemented another solution to the problem
by making use of numpy’s array slicing capabilities:
CHAPTER 6. ELLIPTIC PDES 252

# Jacobi iterative solution


tic=time.clock()
while (rel_res > reltol):
R2 = (U2[1:-1,0:-2]+U2[0:-2,1:-1]+U2[1:-1,2:]+U2[2:,1:-1]-4.0*U2[1:-1,1:-1]) + h**2*(U2[1:-1,1:-1
df=4-2*h**2*U2[1:-1,1:-1]
dU2 = R2/df
U2[1:-1,1:-1]+=dU2
rel_res=np.max(dU2)/np.max(U2)
iteration+=1
toc=time.clock()
print "Jacobi CPU-time:\t\t{0:0.2f}. \t Nr. iterations {1}".format(toc-tic,iteration)

Note with this implementation all values on the right hand side are at the
previous iteration, and thus the method must me denoted a Jacobian algorithm.
Finally, we have implemented a third method the Gauss-Seidel method (6.66)
with Cython. Cython is an optimising static compiler (based on Pyrex) for
both the Python programming language and the extended Cython programming
language. The ambition is to makes the writing of computationally superior C
extensions for Python as easy as Python itself.
The expensive triple loop is implemented in a typed Cython function which
looks very much like the Python implementation, save for the type declarations.
import cython
cimport cython

import numpy as np
cimport numpy as np

DTYPE = np.float64
ctypedef np.float64_t DTYPE_t

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)

cpdef gauss(np.ndarray[DTYPE_t, ndim=2] U, double reltol, double h, double omega):


cdef Py_ssize_t i, j, it
cdef double rel_res, dU_max, df, dU, R

cdef unsigned int rows = U.shape[0]


cdef unsigned int cols = U.shape[1]

it=0
rel_res=1.0
itmax=100

while ((rel_res>reltol) and (it<=itmax)):


dU_max=0.0
for j in range(1,rows-2):
for i in range(1,cols-2):
R = (U[j,i-1]+U[j-1,i]+U[j,i+1]+U[j+1,i]-4.0*U[j,i]) + h**2*(U[j,i]**2+1.0)
df=4.0-2*h**2*U[j,i]
dU = omega*R/df
U[j,i]+=dU
dU_max=np.max([np.abs(dU),dU_max])
CHAPTER 6. ELLIPTIC PDES 253

rel_res=dU_max/np.max(np.abs(U[:,:]))
# print ’rel_res’, rel_res
it+=1
if (it>=itmax): print ’Terminated after max iterations’
return U, rel_res, it

After compilation the Cython module is easily imported into our python-code
which allows for comparison with the methods above as illustrated in the code
below:
# Python Gauss-Seidel method
tic=time.clock()
while (rel_res > reltol):
du_max=0.0
for j in range(1,ny+1):
for i in range(1, nx + 1):
R = (U[j,i-1]+U[j-1,i]+U[j,i+1]+U[j+1,i]-4.0*U[j,i]) + h**2*(U[j,i]**2+1.0)
df=4-2*h**2*U[j,i]
dU = omega*R/df
U[j,i]+=dU
du_max=np.max([np.abs(dU),du_max])

rel_res=du_max/np.max(np.abs(U))

iteration+=1

toc=time.clock()
print "Python Gauss-Seidel CPU-time:\t{0:0.2f}. \t Nr. iterations {1}".format(toc-tic,iteration)

iteration = 0
rel_res=1.0

# Second method
# Jacobi iterative solution
tic=time.clock()
while (rel_res > reltol):
R2 = (U2[1:-1,0:-2]+U2[0:-2,1:-1]+U2[1:-1,2:]+U2[2:,1:-1]-4.0*U2[1:-1,1:-1]) + h**2*(U2[1:-1,1:-1
df=4-2*h**2*U2[1:-1,1:-1]
dU2 = R2/df
U2[1:-1,1:-1]+=dU2
rel_res=np.max(dU2)/np.max(U2)
iteration+=1

toc=time.clock()
print "Jacobi CPU-time:\t\t{0:0.2f}. \t Nr. iterations {1}".format(toc-tic,iteration)

# Third method
# Cython Gauss-Seidel method
rel_res=1.0
tic=time.clock()
U3, relreturn, itsused=gs.gauss(U3,reltol,h, omega)
toc=time.clock()
print "Cython Gauss-Seidel CPU-time:\t{0:0.2f}. \t Nr. iterations {1}".format(toc-tic,itsused)

By running the code we get the follwing results for comparison:


CHAPTER 6. ELLIPTIC PDES 254

omega=1.85
Python Gauss-Seidel CPU-time: 1.62. Nr. iterations 56
Jacobi CPU-time: 0.04. Nr. iterations 492
Cython Gauss-Seidel CPU-time: 0.97. Nr. iterations 56

which illstrates the extreme efficiency whenever a numerical scheme may


be expressed by means of numpy-array-slicing. Note that the numpy-array-
slicing Jacobi scheme converge slower than the Gauss-Seidel scheme in terms of
iterations, and need apporximately 10 times as many iterations as the Gauss-
seidel algorithm. But even in this situation the CPU-speed of the Jacobi scheme
with array-slicing is approximately 40 times faster than the Gauss-Seidel scheme
in python. We also observe that the Cython implementation Gauss-Seidel scheme
is approximately 1.7 times faster than the python counter part, but not by far
as fast as the Jacobi scheme with array-slicing, which is approximately 24 times
faster.
emfs /src-ch7/ #python #package nonlin_poisson_sor.py @ git@lrhgit/tkt4140/src/src-ch7/nonlin_poisso

6.4.6 Convergence criteria


Vi går tilbake til et lineært ligningsystem Ax = b som for et tilfelle med 4
ukjente blir:

a11 x1 + a12 x2 + a13 x3 + a14 x4 = b1


a21 x1 + a22 x2 + a23 x3 + a24 x4 = b2
a31 x1 + a32 x2 + a33 x3 + a34 x4 = b3
a41 x1 + a42 x2 + a43 x3 + a44 x4 = b4

Innfører følgende matriser:


     
a11 0 0 0 0 0 0 0 0 a12 a13 a14
 0 a22 0 0   a21 0 0 0 0 0 a23
 a24 
D =  , −L =   −U =  
 0 0 a33 0   a31 a32 0 0 0 0  0 a34 
0 0 0 a44 a41 a42 a43 0 0 0 0 0
(6.71)
D er en diagonalmatrise og L og U er henholdsvis en nedre og en øvre
trekantmatrise. Koeffisientmatrisa A kan da skrives: A = D − L − U slik at
ligningsystemet blir:

Dx = (L + U)x + b (6.72)
Med bruk av notasjonen i (6.72), kan Jacobis iterasjonsmetode i (6.40) skrives:

Dxm+1 = (L + U)xm + b

som gir:
CHAPTER 6. ELLIPTIC PDES 255

xm+1 = D−1 (L + U)xm + D−1 b (6.73)

Setter:

GJ = D−1 (L + U) (6.74)

GJ kalles iterasjonsmatrisa for Jacobis metode. Når ligningene er skrevet på


matriseform, gjelder de selvfølgelig for et vilkårlig antall ukjente.
Tilsvarende for Gauss-Seidels metode i (6.45):

Dxm+1 = Lxm+1 + Uxm + b

som gir:

xm+1 = (D − L)−1 Uxm + (D − L)−1 b (6.75)

Setter:

GGS = (D − L)−1 U (6.76)

GGS kalles iterasjonsmatrisa for Gauss-Seidels metode.


For SOR- metoden i (6.48):

(I − ωD−1 L)xm+1 = [(1 − ω)I + ωD−1 U]xm + ωD−1 b

som gir:

xm+1 = (I − ωD−1 L)−1 [(1 − ω)I + ωD−1 U]xm + (I − ωD−1 L)−1 ωD−1 b
(6.77)
Setter

GSOR = (I − ωD−1 L)−1 [(1 − ω)I + ωD−1 U] (6.78)

GSOR kalles iterasjonsmatrisa for SOR-metoden. Gauss-Seidel fås som et


spesialtilfelle ved å sette ω = 1.
Vi har delvis fulgt fremstillingen som er gitt i Smith [22], side 266.
Vi ser at alle tre metodene kan skrives:

xm+1 = Gxm + c (6.79)


G står her for GJ , GGS og GSOR (6.80)
CHAPTER 6. ELLIPTIC PDES 256

Ved konvergens blir xm+1 = xm = x slik at det eksakte systemet kan skrives:

x = Gx + c (6.81)
m
Vi kaller feil-vektoren i den m’te iterasjonen for e slik at

em = x − xm (6.82)
Ved å trekke (6.80) fra (6.81) får vi:

em+1 = Gem (6.83)


Derav følger:

em = Gem−1 = G2 em−2 = G3 em−3 = · · · = Gm e0 (6.84)


m
der e er feilvektoren i den første iterasjonen, altså forskjellen mellom startver-
diene og de rette verdiene.
Dersom prosessen i (6.83) og (6.84) skal konvergere for vilkårlige startverdier
x0 , må følgende betingelse være oppfylt:

lim Gm = 0 (6.85)
m→∞
En nødvendig og tilstrekkelig betingelse for å oppfylle (6.85), er at tallverdien
for den største egenverdien i G er mindre enn 1.
Dette skrives:

ρ = |λmax | < 1 (6.86)


Absoluttverdien av den største egenverdien av en matrise A kalles spektralra-
dien og betegnes ofte med ρ. Skrives gjerne ρ(A) når det er nødvendig å henvise
til den underliggende matrisa. (Se ??appendiks 1.5 i [?]) .
I Smith [22] er både nødvendigheten og tilstrekkeligheten vist under forutset-
ningen av at alle egenvektorene av G er uavhengige. Et generelt bevis er mer
kronglete og kan finnes i mer avansert litteratur, f.eks Hageman &Young [9].
Følger derfor Smith og antar at iterasjonsmatrisa G har dimensjon n × n og
har n uavhengige egenvektorer vk , k = 1, 2, . . . , n.
Feilvektoren e0 i den første iterasjonen kan da utrykkes i egenvektor-rommet
ved:

n
X
e0 = c1 v1 + c2 v2 + · · · + cn vn = ck vk
k=1
der ck , k = 1, 2, . . . , n er skalarer
Nå får vi:

n
X
e1 = Ge0 = c1 Gv1 + c2 Gv2 + · · · + cn Gvn = ck Gvk (6.87)
k=1
CHAPTER 6. ELLIPTIC PDES 257

La λk være den k’te egenverdien slik at med vk som den k’te egenvektoren, får
vi Gvk = λk vk som innsatt i (6.87) gir:
n
X
e1 = ck λk vk
k=1

Dette er for den første iterasjonen. For den m’te iterasjonen:


n
X
em = ck (λk )m vk (6.88)
k=1

(6.88) gir da følgende:


Nødvendig betingelse: Dersom limm→0 em = 0 skal gjelde for vilkårlige
startvektorer x0 og da også for vilkårlige feilvektorer e0 , må |λk | < 1, k =
1, 2, . . . , n.
Tilstrekkelig betingelse: Dersom |λk | < 1, k = 1, 2, . . . , n, følger umiddelbart
at em → 0 for en vilkårlig e0 .
Dette betyr at at de klassiske iterasjonsmetodene konvergerer hvis og bare
hvis spektralradien for iterasjonsmatrisa er mindre enn 1.
Vi kan også bruke (6.88) til å si noe om konvergenshastigheten. Til det
trenger vi vektor- og matrisenormer. Henviser her til ??appendiks 1.5 i [?]). La
oss se på et egenverdiproblem Ax = λx, x 6= 0, . Med bruk av lign. (??)

||Ax|| = ||λx|| = |λ|||x||


||Ax|| ≤ ||A|| · ||x||

som gir:

|λ| · ||x|| ≤ ||A|| · ||x||

eller:

|λ| ≤ ||A|| (6.89)

Merk at λ står for alle egenverdiene slik at spesielt ρ(A) ≤ ||A||


Fra (6.83):

em+1 = Gem → ||em+1 || = ||G|| · ||em ||


Anta nå at etter at vi har utført m iterasjoner, gjør k ekstra:

||em+k || = ||Gk || · ||em || (6.90)


Sorterer egenverdiene etter størrelse: |λ1 | > |λ2 | ≥ |λ3 | ≥ · · · ≥ |λn |.
Her er λ1 = λmax og ρ = |λmax |. Merk at vi har antatt at λ1 og λ2 ikke
faller sammen. Fra (6.88):
CHAPTER 6. ELLIPTIC PDES 258

em =c1 λm m m m m m
1 v1 + c2 λ2 v2 + · · · + cn λn vn → ||e || ≤ ||c1 λ1 v1 || + ||c2 λ2 v2 ||
+ · · · + ||cn λm
n vn ||
 m m 
m
λ2 λn
=|λ1 | · ||c1 v1 || + ||c2 v2 || + · · · + ||cn vn ||

λ1 λ1
For tilstrekkelig store verdier av m:

||em || ≈ |λ1 |m ||c1 v1 || = ρm ||c1 v1 || (6.91)


Fra (6.89), (6.90) og (6.91) følger:

||em+k ||
||em+k || ≈ ρk ||em || → ≈ ρk (6.92)
||em ||
Vi ønsker spesielt å finne for hvilken verdi av k er ||em+k || en tiendepart av
||em ||:

||em+k || 1
m
= ≈ ρk (6.93)
||e || 10
Ved bruk av den Briggske logaritmen i (6.93):
1
k≈− (6.94)
log10 (ρ)
k angir hvor mange iterasjoner vi må utføre for å vinne ett desimalsiffer. Stør-
relsen

R = − log10 (ρ) (6.95)


kalles ofte det midlere konvergenstallet. Istedenfor den Briggske logaritmen
brukes gjerne den naturlige.
Ved bruk av matrisenormer kan vi finne tilstrekkelige betingelser for konver-
gens. La oss f. eks. velge Jacobis metode, lign.(6.72) med iterasjonsmatrisa gitt
i (6.74):

GJ = D−1 (L + U)
For systemet i (6.71):
 1
0 0 0
  
a11 0 a12 a13 a14
 0 1
a2 0 0   a21 0 a23 a24 
GJ = −  1
· 
 0 0 a3 0   a31 a32 0 a34 
1 a41 a42 a43 0
0 0 0 a44
a12 a13 a14
0
 
a11 a11 a11
 aa21 0 a23
a22
a24
a22

=− 22
 a31 a32 a34

a33 a33 0 a33

a41 a42 a43
a44 a44 a44 0
CHAPTER 6. ELLIPTIC PDES 259

En matrise A kalles strengt diagonaldominant dersom:


n
X
|ai,j | > |ai,j | for alle 1 ≤ i ≤ n (6.96)
j=1, j6=i

Anta nå at A er strengt diagonaldominant. Da blir tallverdien av alle leddene


i Gj mindre enn 1. Bruker matrisenormen ||A||∞ samt (6.89):

n
X
|λ| < ||GJ ||∞ = max |Gi,j | < 1
1≤i≤n
j=1

Med andre ord: Dersom iterasjonsmatrisa er strengt diagonaldominant,


konvergerer Jacobis metode uavhengig av startvektoren. Det kan vises at dette
også gjelder både Gauss-Seidel og SOR også.

Eksempel ved bruk av Gauss-Seidels metode. La oss løse følgende system


Ax = b med fire ukjente der vi bruker Gauss-Seidels metode:

     
2 −1 0 0 x1 −1
 −1 3 −1 0   x2   4 
 · = 
 0 −1 3 −1   x3   7 
0 0 −1 2 x4 0

Dette systemet har løsningen x1 = 1, x2 = 3, x3 = 4, x4 = 2. I praksis ville


vi selvfølgelig ikke bruke Gauss-Seidels metode på et slik system, men systemet
er så enkelt at det er mulig å analysere det. Lign. (6.71) blir i dette tilfellet:

−1
     
2 0 0 0 0 0 0 0 0 0 0
0 3 0 0  , −U =  0 0 −1 0  −L =  −1 0 0 0
D = 
0 0 3 0 0 0 0 −1 0 −1 0 0
0 0 0 2 0 0 0 0 0 0 −1 0
Videre får vi:
 1

0 0 0
 
2 0 0 0 2
1 1
−1 3 0 0  , (D − L)−1 =  6 3
0 0
D−L=

0 −1 3 0 1 1 1

18 9 3
0 
0 0 −1 2 1 1 1 1
36 18 6 2
Iterasjonsmatrisa GGS i (6.76) blir nå:
 1

0 2
0 0
1 1
0 0
GGS = (D − L)−1 U =  6 3
 
1 1 1
0 18 9 3

1 1 1
0 36 18 6
Beregner egenverdiene av iterasjonsmatrisa:
 1

−λ 2
0 0
1 1
0 6
−λ 3
0
det(GGS − λI) = det 
 =0
1 1 1
0 18 9
−λ 3

1 1 1
0 36 18 6
−λ
CHAPTER 6. ELLIPTIC PDES 260

Vi får en enkel 4. grads ligning: λ2 (λ2 − 49 λ + 1


36
) = 0 med løsning:

ρ = λ1 = 0.3692, λ2 = 0.0752, λ3 = λ4 = 0
Vi kan selvfølgelig bruke Matlab direkte til å finne egenverdiene:
> Ggs = [0 1/2 0 0; 0 1/6 1/3 0; 0 1/18 1/9 1/3; 0 1/36 1/18 1/6];
>> eig(Ggs)
ans = 0 0.0752 0.3692 0.0000
>>
Da tallverdien for alle egenverdiene er mindre enn 1, følger at Gauss-Seidels metode
konvergerer for dette tilfellet. (Systemet er strengt diagonaldominant). Konvergenstallet
− log10 (ρ) fra (6.95) blir − log10 (0.3692) = 0.4327 slik at k ≈ 2.3 som betyr at vi må utføre
litt mer enn to iterasjoner for hvert desimalsiffer vi ønsker.
Gauss-Seidel systemet i (6.75) blir i vårt tilfelle:

m+1  1
  m  − 1 
0 0 0

x1 2 x1 2
1 1
x2 0 6 3
0   x2   76 
= · +  49  , m = 0, 1, . . .

1 1 1
 
x3 0 18 9 3
x3 18
x4 1 1 1 x4 49
0 36 18 6 36

Vi skriver et lite Matlabprogram som utfører iterasjonsprosessen:


% Program GStest
Ggs = [0 1/2 0 0; 0 1/6 1/3 0; 0 1/18 1/9 1/3 ; 0 1/36 1/18 1/6];
c = [ -1/2; 7/6 ; 49/18; 49/36 ];
x = zeros(4,1); % Startverdier
for k = 1:12
x = Ggs*x + c;
fprintf(’ $%6.4f %6.4f %6.4f %6.4f \n’,x’)
end
>> GStest
-0.5000 1.1667 2.7222 1.3611
0.0833 2.2685 3.5432 1.7716
0.6343 2.7258 3.8325 1.9162
0.8629 2.8985 3.9382 1.9691
0.9492 2.9625 3.9772 1.9886
0.9812 2.9861 3.9916 1.9958
0.9931 2.9949 3.9969 1.9984
0.9974 2.9981 3.9989 1.9994
0.9991 2.9993 3.9996 1.9998
0.9997 2.9997 3.9998 1.9999
0.9999 2.9999 3.9999 2.0000
1.0000 3.0000 4.0000 2.0000
>>
Vi ser at i dette tilfellet konvergerer Gauss-Seidels metode raskt, noe som skyldes at
spektralradien er liten og godt separert fra λ2 . Desverre er nok ikke forholdene så gunstige for
de tilfellene der vi ønsker å bruke iterasjonsmetoder.
Anta at vi skal løse en Poisson-ligning ∇2 u = f (x, y) på et enhetskvadrat, se f.eks.
figur 6.15, og la skrittlengden være h i begge koordinat-retningene. For dette tilfellet er det
mulig å finne spektralradien analytisk, se. f.eks Hageman & Young [9]. Vi finner følgende
uttrykk:
Jacobis metode:

(πh)2
ρ = cosh(πh) ≈ 1 − for små h (6.97)
2
Gauss-Seidels metode:

ρ = cosh2 (πh) ≈ 1 − (πh)2 for små h (6.98)


CHAPTER 6. ELLIPTIC PDES 261

SOR:

1 − sinh(πh)
ρ= ≈ 1 − 2πh for små h (6.99)
1 + sinh(πh)
Tilfelle (c) er basert på optimal ω.
Vi husker at betingelsen for konvergens er at spektralradien ρ < 1. For små h nærmer
spektralradien seg raskt 1 for alle metodene, men særlig er dette tydelig for Jacobi- og
Gauss-Seidels metode. Tabellen nedenfor viser dette klart.
1 1 1
Spektral radius h = 32 h = 64 h = 128
ρJ 0.9952 0.9988 0.9997
ρGS 0.9904 0.9976 0.9994
ρSOR 0.8215 0.9065 0.9521
Dette vises enda tydligere når vi beregner antall iterasjoner som behøves for å vinne ett
desimalsiffer, se lign. (6.94).
1 1 1
Iterasjoner h = 32 h = 64 h = 128
kJ 477 1910 7644
kGS 239 955 3822
kSOR 12 23 47
Konklusjon: Det er bare SOR som er praktisk brukbare av disse metodene.
På grunn av denne konklusjonen, har vi bare brukt SOR på eksemplene i dette avsnittet
med unntak av et demo-eksempel med Gauss-Seidel. Det er mulig å forbedre SOR betraktelig.
Vi kan f.eks. variere ω for hver iterasjon etter bestemte skjema istedenfor å la den være konstant
i hele iterasjonsprosessen. Legg også merke til at SOR, med Gauss-Seidel som spesialtilfelle,
er avhengig av nummereringen. Vi kan forbedre konvergensen ved f.eks å bruke sjakkbrett-
nummerering, dvs: Først gjennomløpe 1, 3, 5, . . . og deretter 2, 4, 6, . . . . Den SOR-versjonen vi
har brukt kalles punkt-SOR fordi vi går fra punkt til punkt. Her er det forbedringspotensiale
ved heller å operere på hele blokker, eventuelt hele linjer. For dem som er interessert i disse
variantene, henvises til Press [19] og Hageman & Young [9] der det også finnes programmer.
Det er sjelden bryet verdt å bruke disse mer avanserte versjonene fordi det idag finnes mer
effektive iterasjons-metoder. Fordelen med den enkle SOR-metoden vi har brukt, er at den er
lett å programmere både for lineære- og ikke-lineære ligninger. Legg merke til at når vi brukte
direkte-løsere (se 6.3), måtte vi sette opp hele matrisa på forhånd. Dette var forholdsvis enkelt
i de viste eksemplene, noe som ofte ikke er tilfelle ellers. Samtidig var vi avhengige av de
innebygde løserne i Matlab.
Dersom du ønsker å bruke iterasjonsmetoder på et fint nett, bør du bruke noen av de nyere
metodene. Disse går under betegnelsene Flernett-metoder (Multigrid) og Krylov-metoder.
En god introduksjon til Flernett-metoder finnes i Briggs [2]. En rekke av Krylov-metodene
finnes tilgjengelig i Matlab. Stikkord er her bicg, cgs, bicgstab, pcg, gmresogqmr. Skriv f.eks
doc gmres og se på eksemplene. Istedenfor matrisene som er gitt i eksemplene der, kan du bruke
koeffisient-matrisene fra eksemplene i avsnitt 6.3. Se Saad [20] for mer om Krylov-metoder.
Mange av disse metodene er også behandlet av Kelley [15] med nedlastbare Matlabprogram.

6.4.7 UTNYTTELSE AV SYMMETRI


Ved å utnytte eventuell symmetri for et problem, kan vi redusere antall ukjente. Dersom vi ser
på figur 6.17, har vi symmetri om linja x = 0.5.
CHAPTER 6. ELLIPTIC PDES 262

Formelt får vi da betingelsen ∂T∂x


= 0 langs denne linja, men det er selvfølgelig ikke
nødvendig å utføre noe diskretisering da det følger direkte at
T11 = T31 , T12 = T32 osv. Dette fører til at at systemet i (6.24) i dette tilfellet blir:

 −4 1 0 0 0 1 0 0 0 0   T11   0 
−4
1 1 0 0 0 1 0 0 0
  T12 0
−4

  T13
  
 0 1 1 0 0 0 1 0 0   0 
 0
 0 1 −4 1 0 0 0 1 0   T14
 
 
  0 

 0 0 0 1 −4 0 0 0 0 1  ·  T15 = −100 
 2
 0 0 0 0 −4 1 0 0 0   T21
 
 
  0 

 0 2 0 0 0 1 −4 1 0 0   T22   0 
−4
 0 0 2 0 0 0 1 1 0
  T   0

   23   
0 0 0 2 0 0 0 1 −4 1 T24 0
0 0 0 0 2 0 0 0 1 −4 T25 −100
(6.100)
Løsningen av (6.100) er gitt i Matlab-programmet lap1s nedenfor.
% program lap1s
clear
n = 10;
d = ones(n,1); % diagonal
b = zeros(n,1); % right hand side
% --- Update b ---
b(5) = -100; b(10) = -100;
% --- Generate A-matrix ---
A = spdiags([2*d d -4*d d d],[-5 -1 0 1 5], n,n);
% --- Update A ---
A(5,6) = 0; A(6,5) = 0;
% --- Solve system ---
T = A\b;

Poisson-ligning. La oss se på lign. (??) for et kvadratisk tverrsnitt av en kanal

1.0

C
0.5

0.0
A B 1.0 x

Figure 6.17: Quadratic cross-section of a channel. AC is a line of symmetry


and is is sufficent to solve for the triangle ABC only.

Dersom vi ikke utnytter symmetrien, blir problemet fra (??)

∂2u ∂2u
+ = −1 (6.101)
∂x2 ∂y 2
CHAPTER 6. ELLIPTIC PDES 263

Randbetingelser: u = 0 langs hele randkurven.


Dette er et problem med Dirichlet-betingelser. Dersom vi utnytter symmetrien om x = 0.5
og y = 0.5, blir formelt symmetri-betingelsene:

∂u
= 0 for x = 0.5
∂x
∂u
= 0 for y = 0.5
∂y
Vi ser at vi også kan benytte oss av symmetrien om diagonalene, slik at det f.eks er
tilstrekkelig å løse ligningen i trekanten ABC da AC er en symmetrilinje. Figur 6.18 på
neste side viser trekanten ABC med nummerering der vi har utnyttet symmetrien. Vi setter
u1 = u1,1 , u2 = u1,2 , u3 = u1,3 osv. Langs AB har vi avmerket randverdien u = 0.

14

14 C
14
15
11
13
13 14
7
11
10 11 12
2
8
6 7 8 9
0.0
4
1 2 3 4 5

A 0.0 0.0 0.0 0.0 B

Figure 6.18: Computational mesh and enumeration for the problem in 6.17.

Den diskretiserte versjonen av (6.101) blir:

ui+1,j + ui−1,j + ui,j+1 + ui,j−1 − 4ui,j = −h2 (6.102)

med ∆x = ∆y = h
Vi har valgt h = 0.1 i figur 6.18. Beregningsmolekylet med enkle indekser:

ud

ua uc
um

ub

Figure 6.19: Numerical stencil forthe problem in 6.17.


CHAPTER 6. ELLIPTIC PDES 264

slik at (6.102) blir:

ua + ub + uc + ud − 4um = −h2 (6.103)


Noen eksempler på bruk av (6.103):

2u2 − 4u1 = −h2


2u4 + u9 − 4u5 = −h2
u7 + u4 + u9 + u11 − 4u8 = −h2
med m = 1, 5 og 8. Det endelige ligningsystemet blir som gitt i (6.104):

 
 −4 2 0 0 0 0 0 0 0 0 0 0 0 0 0
 u
1
 h2
h2
 1 −4 1 0 0 1 0 0 0 0 0 0 0 0 0
  u2  
−4 h2

 0 1 1 0 0 1 0 0 0 0 0 0 0 0   u3   
h2
 
 0 0 1 −4 1 0 0 1 0 0 0 0 0 0 0   u4   
h2
  
 0 0 0 2 −4 0 0 0 1 0 0 0 0 0 0   u5  



 0
 2 0 0 0 −4 2 0 0 0 0 0 0 0 0  u
 6

  h2 
 0 0 1 0 0 1 −4 1 0 1 0 0 0 0 0   u7 h2
  
 0 0 0 1 0 0 1 −4 1 0 1 0 0 0 0
· u  = − h2

  8   
−4 h2
 0   u9  
0 0 0 1 0 0 2 0 0 1 0 0 0   
h2
  
 0 0 0 0 0 0 2 0 0 −4 2 0 0 0 0   u10   
h2
 
 0
 0 0 0 0 0 0 1 0 1 −4 1 1 0 0   u11


  
 0 0 0 0 0 0 0 0 1 0 2 −4 0 1 0   u12 h2
  
 
−4 h2
 0 0 0 0 0 0 0 0 0 0 2 0 2 0
 u 
   13   
0 0 0 0 0 0 0 0 0 0 0 1 2 −4 1 u14 h2
 
0 0 0 0 0 0 0 0 0 0 0 0 0 4 −4 u15 h2
(6.104)
Selv om bandstrukturen er tydelig, blir den mer rotet fordi vi har utnyttet symmetrien.
Det blir mer oppdatering av koeffisientmatrisa. Programmet poisson løser (6.104):
% program poisson
clear
n = 15;
h = 0.1; h2 = h*h;
d0 = zeros(n,1); % diagonal
d = ones(n,1); % diagonal
b = -h2*ones(n,1); % right hand side
% --- generate A-matrix ---
A = spdiags([d0 d0 d0 d -4*d d d0 d0 d0],[-4 -3 -2 -1 0 1 2 3 4], n,n);
% === Update A ===
% --- sub-diagonals ---
A(6,2) = 2; A(7,3) = 1; A(8,4) = 1; A(9,5) = 1;
A(10,7) = 2; A(11,8) = 1; A(12,9) = 1;
A(13,11) = 2; A(14,12) = 1;
A(5,4) = 2; A(6,5) = 0; A(9,8) = 2; A(10,9) = 0; A(12,11) = 2;
A(13,12) = 0; A(14,13) = 2; A(15,14) = 4;
% --- super-diagonals ---
A(1,2) = 2; A(5,6) = 0; A(6,7) = 2; A(9,10) = 0;
A(10,11) = 2; A(12,13) = 0; A(13,14) = 2;
A(11,13) = 1; A(12,14) = 1;
A(7,10 ) = 1; A(8,11) = 1; A(9,12) = 1;
A(2,6) = 1; A(3,7) = 1; A(4,8) = 1; A(5,9) = 1;
% --- solve system ---
u = A\b;
Tabellen nedenfor viser de numeriske verdiene fra programmet. De analytiske verdiene er
gitt i siste kolonne. Senterverdien u15 har en feil på 0.8%. Koordinatene refererer til figur 6.17.
CHAPTER 6. ELLIPTIC PDES 265

u1 = u(0.1, 0.1) 0.0128 0.0131


u2 = u(0.2, 0.1) 0.0206 0.0209
u3 = u(0.3, 0.1) 0.0254 0.0256
u4 = u(0.4, 0.1) 0.0280 0.0282
u5 = u(0.5, 0.1) 0.0288 0.0290
u6 = u(0.2, 0.2) 0.0343 0.0346
u7 = u(0.3, 0.2) 0.0430 0.0433
u8 = u(0.4, 0.2) 0.0478 0.0482
u9 = u(0.5, 0.2) 0.0493 0.0497
u10 = u(0.3, 0.3) 0.0544 0.0548
u11 = u(0.4, 0.3) 0.0608 0.0613
u12 = u(0.5, 0.3) 0.0629 0.0634
u13 = u(0.4, 0.4) 0.0682 0.0687
u14 = u(0.5, 0.4) 0.0706 0.0712
u15 = u(0.5, 0.5) 0.0731 0.0737
De analytiske verdiene er beregnet fra:


(1 − ζ) 4 X 1 cosh(nπ ȳ)
u=ζ· − 3  · sin(nπζ) (6.105)
2 π n3 cosh nπ
n=1,3,5,... 2

1 1 1
der x̄ = x − , ȳ = y − 2 , ζ = 2 − x̄, (x, y) ∈ [0, 1].

2
Bytt om x̄ og ȳ dersom ȳ > x̄ (6.106)

Exercise 7: Symmetric solution


Prove that the analytical solution of the temperature field T (x, y) in (6.25) is symmetric
around x = 0.5.

Exercise 8: Stop criteria for the Poisson equation


Implement the various stop criteria outlined in 6.4.1 for the Possion equation in two dimensions
(6.49).
Chapter 7

Diffusjonsproblemer

7.1 Introduction
A one-dimensional diffusion equation takes the canonical form:

∂u ∂2u
=α 2 (7.1)
∂t ∂x
where t is an evolutionary variable, which might be both a time-coordinaten and a spatial
coordinate. Some classical diffusion problems are listed below:
• Heat conduction
∂T ∂2T
=α 2
∂t ∂x
• Unsteady boundary layers (Stokes’ problem):
∂u ∂2u
=ν 2
∂t ∂y
• Linearized boundary layer equation with x as an evolutionary variable:
∂u ν ∂2u
=
∂x U0 ∂y 2
• Flow in porous media:
∂u ∂2u
=c 2
∂t ∂x
Our model equation (7.1) may be classified according to (5.18):

∂2φ ∂2φ ∂2φ


A 2
+B +C 2 +f =0 (7.2)
∂x ∂x∂y ∂y

A · (dy)2 − B · dy · dx + C · (dx)2 = 0 (7.3)



B 2 − 4AC

λ1,2 = (7.4)
2A
B = C = 0 and A = 1 which by substitution in (5.33) and (5.35) yield:

dt = 0, B 2 − 4AC = 0

266
CHAPTER 7. DIFFUSJONSPROBLEMER 267

And we find that (7.1) is a parabolic PDE with the characteristics given by t = constant.
By dividing dt with dx we get:

dt dx
=0→ =∞ (7.5)
dx dt
which corresponds to an infinite propagation speed along the characteristic curve t =
constant.

7.2 Confined, unsteady Couette flow


The classical versicon of unsteady Couette flow with b = ∞ has been presented as Stokes first
problem and discussed in section (3.3).

Y b
U0

Figure 7.1: Confined, unsteady Couette flow or channel flow. The channel with
is b
In this section we will look at the problem of unsteady Couette flow, confined by two walls,
which has the following governing equation:

∂U ∂2U
=ν , 0<Y <b (7.6)
∂τ ∂Y 2
with the following boundary conditions, representing the presence of the two walls or
channel if you like:
o
U (0, τ ) = U0
=τ ≥0 (7.7)
U (b, τ ) = 0
Futher, the parabolic problem also needs initial conditions to be solved and we assume:

U (Y, τ ) = 0, τ < 0 (7.8)


In section 3.3 we have presented several ways to render (7.6)) dimensionless, and for the
current problem we introduce the following dimesionless variables:
Y U τν
y= , u= , t= 2 (7.9)
b U0 b
which allow (7.6) to be written:

∂u ∂2u
= , 0<y<1 (7.10)
∂t ∂y 2
with the corresponding boundary conditions:
o
u(0, t) = 1
, t≥0 (7.11)
u(1, t) = 0
CHAPTER 7. DIFFUSJONSPROBLEMER 268

and initial conditions:

u(y, t) = 0, t < 0 (7.12)


As for the problemn in section 3.3, this present example may also be formulated as a
heat conduction problem. The problem of confined, unsteady Couette flow has the following
analytical solution:

2 X1
u(y, t) = 1 − y − · exp[−(nπ)2 t] sin(nπy) (7.13)
π n
n=1
A detailed derivation of (7.13) may be found in appendix G.6 of Numeriske beregninger.
We discretize (7.10) by a forward difference for the time t:

∂u n
un+1
j − un
j
≈ (7.14)
∂t j ∆t

and central differences for the spatial coordinate y:
∂2u un n n
j+1 − 2uj + uj−1
2
≈ 2
(7.15)
∂y (∆y)
where:

tn = n · ∆t, n = 0, 1, 2, . . . , yj = j · ∆y, j = 0, 1, 2, . . .
Substitution of (7.14) in (7.10) results in the following difference equation:

un+1
j = D (un n n
j+1 + uj−1 ) + (1 − 2D) uj (7.16)
where D is a dimesionless group, commonly denoted the diffusion number or the Fourier
number in heat conduction. See section 13.1 in [3])) for a discussion of (7.16).

∆t ∆τ
D= =ν (7.17)
(∆y)2 (∆Y )2
A scheme with Forward differences for the Time (evolutionary) variable and Central
differences for the Space variable, is commonly referred to as a FTCS (Forward Time Central
Space). For a FTCS-scheme we normally mean a scheme which is first order in t og and second
order in y. Another common name for this scheme is the Euler-scheme.
In section 7.6 we show that for D = 1/6, the scheme (7.16)) is second order in t og and
fourth order in y. Further, in fluid mechanics it is customary to write un
j rather than uj,n , such
that index for the evolutionary variable has a super index. We seek to adopt this convention
in general.
In Figure 7.2 we try to illustrate that the scheme is explicitt, meaning that the unknown
value at time n + 1 can be found explicitly from the formula without having to solve an equation
system. In other words, the unknown value at time n + 1 is not implicitly dependent on other
values at other spatial locations at time n + 1.
The above example is implemented in the code below. Download the code and experiment
using different diffusion numbers. The FTCS-scheme is explicitt and thus has a stability
constraint. We will look further into stability in the next sections, but as can be seen in
Figure 7.3 the stability limit in this example is D = 12 .
# src-ch5/couette_Flow_FTCS.py;Visualization.py @ git@lrhgit/tkt4140/src/src-ch5/Visualization.py;
import matplotlib; matplotlib.use(’Qt4Agg’)
import matplotlib.pylab as plt
plt.get_current_fig_manager().window.raise_()

import numpy as np
from math import exp, sin, pi
CHAPTER 7. DIFFUSJONSPROBLEMER 269

n+1

0.0 j-1 j j+1 1.0

Figure 7.2: FTCS-skjemaet

def analyticSolution(y, t, N=100):

""" Method that calculates the analytical solution to the differential equation:
du/dt = d^2(u)/dx^2 , u = u(y,t), 0 < y < 1
Boundary conditions: u(0, t) = 1, u(1, t) = 0
Initial condition: u(t, 0) = 0 t<0, u(t, 0) = 1 t>0

Args:
y(np.array): radial coordinat
t(float): time
N(int): truncation integer. Truncate sumation after N elements

Returns:
w(float): velocity, us - ur
"""
sumValue = 0
for n in range(1,N+1):
temp = np.exp(-t*(n*np.pi)**2)*np.sin(n*np.pi*y)/n
sumValue += temp
u = 1 - y - (2/pi)*sumValue
return u

def solveNextTimestepFTCS(Uold, D, U_b=1, U_t=0):


""" Method that solves the transient couetteflow using the FTCS-scheme..
At time t=t0 the plate starts moving at y=0
The method solves only for the next time-step.
The Governing equation is:

du/dt = d^2(u)/dx^2 , u = u(y,t), 0 < y < 1

Boundary conditions: u(0, t) = 1, u(1, t) = 0

Initial condition: u(t, 0) = 0 t<0, u(t, 0) = 1 t>0


Args:
uold(array): solution from previous iteration
CHAPTER 7. DIFFUSJONSPROBLEMER 270

D(float): Numerical diffusion number


Returns:
unew(array): solution at time t^n+1
"""
Unew = np.zeros_like(Uold)

Uold_plus = Uold[2:]
Uold_minus = Uold[:-2]
Uold_mid = Uold[1:-1]

Unew[1:-1] = D*(Uold_plus + Uold_minus) + (1 - 2*D)*Uold_mid


Unew[0] = U_b
Unew[-1] = U_t

return Unew

if __name__ == ’__main__’:

import numpy as np
from Visualization import createAnimation

D = 0.49 # numerical diffusion number

N = 20
y = np.linspace(0, 1, N + 1)
h = y[1] - y[0]
dt = D*h**2
T = 0.2 # simulation time
time = np.arange(0, T + dt, dt)

# Spatial BC
U_bottom = 1.0 # Must be 1 for analytical solution
U_top = 0.0 # Must be 0 for analytical solution

# solution matrices:
U = np.zeros((len(time), N + 1))
U[0, 0] = U_bottom # no slip condition at the plate boundary
U[0,-1] = U_top
#
Uanalytic = np.zeros((len(time), N + 1))
Uanalytic[0, 0] = U[0,0]

for n, t in enumerate(time[1:]):

Uold = U[n, :]

U[n + 1, :] = solveNextTimestepFTCS(Uold, D, U_b=U_bottom, U_t=U_top)


Uanalytic[n + 1, :] = analyticSolution(y,t)

U_Visualization = np.zeros((1, len(time), N + 1))


U_Visualization[0, :, :] = U

createAnimation(U_Visualization, Uanalytic, ["FTCS"], y, time, symmetric=False)


In Figure 7.3 we illustrate the simulated time evolution of the velocity as a function of y
between the two walls in the channel for various diffusion numbers D. Note that the velocity
is plotted on the abscissa, whereas the spatial coordinate y is along the ordinate. Notice, how
the solutions starts to become unstable as soon as D > 0.5.
CHAPTER 7. DIFFUSJONSPROBLEMER 271

D = 0.4
1.0
0.8
D = 0.4

0.6
y [-]

increasing
0.4 time

0.2
0.0
D = 0.45
1.0
0.8
D = 0.45

0.6
y [-]

0.4
0.2
0.0
D = 0.5
1.0
0.8
D = 0.5

0.6
y [-]

0.4
0.2
0.0
D = 0.503
1.0
0.8
D = 0.503

0.6
y [-]

0.4
0.2
0.0
D = 0.51
1.0
0.8
D = 0.51

0.6
y [-]

0.4
0.2
0.0
0.0 0.2 0.4 0.6 0.8 1.0
Velocity [-]

Figure 7.3: Numerical solutions of the FTCS-scheme for various diffusion


numbers D with a constant ∆y = 0.02.
CHAPTER 7. DIFFUSJONSPROBLEMER 272

7.3 Stability: Criterion for positive coefficients.


PC-criterion
Consider the following sum:
s = a1 x1 + a2 x2 + · · · + ak xk (7.18)
where a1 , a2 , . . . , ak are positive coefficients. Now, by introuducing the extrema of xi as:

xmin = min(x1 , x2 , . . . , xk ) and xmax = max(x1 , x2 , . . . , xk ) (7.19)


we may deduce from (7.18):

xmin · (a1 + a2 + · · · + ak ) ≤ s ≤ xmax · (a1 + a2 + · · · + ak ) (7.20)


Note, that the above is valid only when a1 , a2 , . . . , ak are all positive. In the following we
will consider two cases:
Case 1: a1 + a2 + · · · + ak = 1
In this case (7.20) simplifies to:

xmin ≤ s ≤ xmax (7.21)


Equality in (7.21) is obtained when x1 = x2 = · · · = xk .
Let us now apply (7.21) on the difference equation in (7.16):

un+1
j = D (un n n
j+1 + uj−1 ) + (1 − 2 D) uj
In this case the coefficients are a1 = D, a2 = D, a3 = 1 − 2D such that the sum of all
coefficents is: a1 + a2 + a3 = 1.
From (7.21) we get:
n+1
min(un n n
j+1 , uj , uj−1 ) ≤ uj ≤ max(un n n
j+1 , uj , uj−1 )

Meaning that un+1


j is restricted by the extrema of un
j , i.e. all the solutions at the previous
timestep, and will thus not have to ability to grow without bounds and therefore be stable.
The conditions for stability are that all the coefficients a1 , a2 . . . . , ak are positive. As
D > 0, this means that only a3 = 1 − 2D may become negative. The condition for a3 to be
positive becomes: 1 − 2D > 0 which yields D < 12 . When D = 12 , the coefficient a3 = 0, such
that a1 + a2 = 1, which still satisfies the condition. Thus the condition for stability becomes:
1
D≤ (7.22)
2
which is commonly referred to as the Bender-Schmidt formula.
For explicit, homogenous schemes which has a constant solution u = u0 , the sum of the
coefficients will often be one. (Substitute e.g. u = u0 in (7.16)). This property is due to
the form of the difference equations from the Taylor-expansions. (See (2.4) , (2.4) and (2.4)
differences in (2)).
Case 2: a1 + a2 + · · · + ak < 1
As a remedy to that the sum of the coefficient do not sum to unity we define b =
1 − (a1 + a2 + · · · + ak ) > 0 such that a1 + a2 + · · · + ak + b = 1.
We may the construct the following sum: a = a1 x1 + a2 x2 + · · · + ak + b · 0 which satisfies
the conditions for Case 1 and we get:

min(0, x1 , x2 , . . . , xk ) ≤ s ≤ max(0, x1 , x2 , . . . , xk ) (7.23)


The only difference from (7.21) being that we have introduced 0 for the x-es, which
naturally has concequences for the extremal values.
Let us look at an example:

∂T ∂2T
= α 2 + bT, b = konstant, t < tmaks
∂t ∂x
CHAPTER 7. DIFFUSJONSPROBLEMER 273

which may be discretized with the FTCS-scheme to yield:

∆t
Tjn+1 = D (Tj+1
n n
+ Tj−1 ) + (1 − 2D + ∆t · b)Tjn , D=α
(∆x)2
and with the following coefficients a1 = a2 = D og a3 = 1 − 2D + ∆t · b we get:
a1 + a2 + a3 = 1 + ∆t · b ≤ 1
only for negative b-values.
The condition of positive coefficients then becomes: 1 − 2D + ∆t · b > 0 which corresponds
to
1 ∆t · b
0<D< +
2 2
where b < 0.
In this situation the criterion implies that the T − values from the difference equation will
not increase or be unstable for a negative b. This result agrees well the physics, as a a negative
b corresponds to a heat sink.
Note that (7.21) and (7.23) provide limits within which the solution is bounded, and
provides a sufficient criteria to prevent the occurrence of unstable ocillations in the solution.
This criteria may be far more restrictive that what is necessary for a stable solution. However,
in many situations we may be satisfied with such a criteria. The PC-criterion is used frequently
on difference equations for which a more exact analysis is difficult to pursue. Note that the
PC-criterion may only be applied for explicit schemes if no extra information is provided. For
parabolic equations we often have such extra information by means of max/min principles (see
(7.5.3)). Further, the criterion must be modified in case of increasing amplitudes.
One would of course hope for the existence of a necessary and sufficient condition for
numerical stability. However, for general difference equations we have no such condition, which
is hardly surprising. But a method which often leads to sufficient, and in some cases necessary,
conditions for stabily, is von Neumann’s method. This method involves Fourier-analysis of
the linearized difference equation and may be applied for both explicit and implicit numerical
schemes. We will present this method in 7.4.

7.4 Stability analysis with von Neumann’s method


The von Neumann analysis is commonly used to determine stability criteria as it is generally
easy to apply in a straightforward manner. Unfortunately, it can only be used to find necessary
and sufficient conditions for the numerical stability of linear initial value problems with constant
coefficients. Practical problems may typically involve variable coefficients, nonlinearities and
complicated boundary conditions. For such cases the von Neumann analysis may only be
applied locally on linearized equations. In such situations the von Neumann analysis provides
sufficient, but not alwasy necessary conditions for stability [7]. Further, due to the basis on
Fourier analysis, the method is strictly valid only for interior points, i.e. excluding boundary
conditions.
In this section we will show how von Neumann stability analysis may be applied to the
parabolic PDE:

∂u ∂2u
= (7.24)
∂t ∂x2
To motivate the rationale for the basis of the von Neumann analysis, we will start by a
revisit on the analytical solution of (7.24) by the method of separation of variables. The aim
of the method is to simplify the PDE to two ODEs which has analytical solutions. With this
approach we assume that the solution may constructed by means of separation of variables as
u(x, t), i.e. as a product of to f (t) og g(x), which each are only functions of time and space,
repsectively:

u(x, t) = f (t) g(x) (7.25)


CHAPTER 7. DIFFUSJONSPROBLEMER 274

We may now differentiate (7.25) with respect to time and space:


∂u df (t) ∂2u d2 g(x) 1
= g(x), 2
= f (t) (7.26)
∂t dt ∂x dx2 g(x)
which upon substitution in (7.25) results in the following equation:

df (t) d2 g(x)
g(x) = f (t) (7.27)
dt dx2
or more conveniently:
df (t) 1 d2 g(x) 1
= (7.28)
dt f (t) dx2 g(x)
Observe that the left hand side of (7.28) is a function of t only, whereas the right hand
side is a function of x only. As the both sides of (7.28) must be satisfied for arbitrary values of
t and x, the only possible solution is that both sides of the equation equals a constant, which
we for convenience denote −β 2 , thus our original PDE in (7.24) has been transformed to two
ODEs:

df (t) 1 df (t)
= −β 2 → + β 2 f (t) = 0 (7.29)
dt f (t) dt
d2 g(x) 1 d2 g(x)
= −β 2 → + β 2 g(x) = 0 (7.30)
dx2 g(x) dx2
The first ODE (7.29) is of first order and has the solution (verify by susbtitution):
2
f (t) = e−β t
(7.31)
whereas the second ODE is of second order with solution (7.30):

g(x) = A sin(βx) + B cos(βx) (7.32)


such that a particluar solution to (7.25) is found by the product of (7.31) and (7.32):

2
u(x, t) = e−β t
[A sin(βx) + B cos(βx)] (7.33)
and since (7.25) is a linear PDE, the sum or superposition of solutions like (7.33) will also
represent a solution:
m=∞
X 2
u(x, t) = e−βm t [Am sin(βm x) + Bm cos(βm x)]
m=0
The coefficients Am , Bm og βm may be determined from the initial conditions and the
boundary conditions as demonstrated in Appendix G.6 of Numeriske Beregninger.
However, for the current purpose of demonstration of von Neumann analysis, two particular
solutions suffice:
 2
e−β t sin(βx)
u(x, t) = 2 (7.34)
e−β t cos(βx)
which may be presented in a more compact for by making use of Euler’s formula:

ei x = cos(x) + i sin(x), i= −1 (7.35)
The more compact form of (7.34) is then:
2 2
u(x, t) = e−β t i βx
e = e−β t+i βx
(7.36)
Note. Both the real and the imaginary part of the complex (7.36) satisfy (7.24) and is
therefore included in the somewhat general solution. For particular problem (7.36) will be
multiplied with complex cofficients such that the solution is real.
CHAPTER 7. DIFFUSJONSPROBLEMER 275

By adpoting the common notation: xj = j ∆x, j = 0, 1, 2, . . . og tn = n ∆t, n = 0, 1, 2, . . .


for (7.36), the solution at location xj and time tn is:
2 2 2
u(xj , tn ) = e−β tn
ei βxj = e−β n ∆t iβxj
e = (e−β ∆t n iβxj
) e (7.37)
and the solution at location xj at the next timestep n + 1 is:

2 2 2
u(xj , tn+1 ) = e−β tn+1
ei βxj = e−β (n+1) ∆t iβxj
e = (e−β ∆t n+1 iβxj
) e (7.38)
If we divide (7.37) with (7.38), the spatial dependency vanishes and a we get a spatially
independent expression for how the solution is amplified (or damped):

u(xj , tn+1 ) 2
Ga = = e−β ∆t (7.39)
u(xj , tn )
For this reason, Ga is commonly denoted the analytical amplificaiton factor. (See section
1.6.1 i Numeriske Beregninger). In our particular case we find that Ga < 1. Having introduced
the the amplification factor Ga we may rewrite (7.37) as:

u(xj , tn ) = (Ga )n ei βxj ≡ Gn


a e
i βxj
(7.40)
For the current problem Ga < 1, and consequently Gn a → 0 for n → ∞.
As shown previously in (7.16), the following difference equation for the solution of (7.24)
may be obtained:

∆t
un+1
j = D (un n n
j+1 + uj−1 ) + (1 − 2D)uj , D= (7.41)
(∆x)2
Clearly, the solution of the difference equation (7.41) will deviate from the analytical
solution to the differential equation for finite values of ∆x and ∆t. The deviation/error will
increase for increasing values of ∆x and ∆t and we have seen that when D > 12 , the difference
equation becomes unstable, with constantly increasing amplitudes and alternating signs. As
(7.40) is a solution of the differential equuation, we introuce a simpliar expression for the
difference equation (7.41):

un n n i βxj
j → Ej = G e (7.42)
where we have introduced the numerical ampflicication factor G:

Ejn+1
G= (7.43)
Ejn
which may be complex and is a function og ∆t and β. From (7.43) we may relate the error
Ejn at the n-th timestep with the initial error Ej0 :

Ejn = Gn Ej0 , Ej0 = ei β xj (7.44)


Given that Ga is derived from the analytical solution of the differetial equation, and that
G is derived from the difference equation approximating the same differential equation, we can
not expect perfect agreement between the two factors. We will discuss this further in 7.4.1
and illustrated in Figure 7.4.
From (7.44) we find a that if Ejn is to be limited and not grow exponentially the following
condition must be satisfied, which is denoted:

The strict von Neumann condition.

|G| ≤ 1 (7.45)
CHAPTER 7. DIFFUSJONSPROBLEMER 276

The condition (7.45) is denoted strict as no increase in amplitude is allowed for. This
condition will be relaxed in section (7.5.4).
Even though we have demostrated the von Neumann method for a relatively simple
diffusion equation, the method is applicable for more generic equations. The method is simple:

The strict von Neumann method.


• Substitute (7.42) in the difference equation in question.
• Test if the condition (7.45) is satisfied.
Some properties of the condition:
1. The linear difference equation must have constant coefficients. In case of variable
coefficients, the condition may be applied on
linearized difference equations with frozen coefficients locally. Based on experience this
results in a necessary condition for stability.
1. The criterion do not consider the effect of boundary conditions as it is based on
periodic initital data. If the impact of boundary
conditions is to be investigated on may use matrix methods for the coefficient matrix of
the difference scheme [4].

7.4.1 Example: Practical usage of the von Neumann con-


dition
In this example we will demonstrate how the von Neumann method may be used on the simple
scheme (7.16) on the following form:

Ejn+1 = D (Ej+1
n n
+ Ej−1 ) + (1 − 2D) Ejn (7.46)
We have previously (see (7.42)) established how the error Ejn is related with the numerical
amplification factor: Ejn = Gn ei β yj which upon substitution in (7.46) yields:

Gn+1 ei βyj = D (Gn ei βyj+1 + Gn ei βyj−1 ) + (1 − 2D)Gn ei βyj


Note that Gn means G in the n-th power, whereas Ejn denotes the error at timelevel n
and the spatial location yj .
The expression in (7.4.1) is a nonlinear, n + 1-order polynomial in G which may be
simplified by division of Gn ei βyj :

G = D (ei βh + e−i βh ) + (1 − 2D) = D (eiδ + e−iδ ) + (1 − 2D) (7.47)


where we introduce δ as:

δ = βh (7.48)
By using terminology for periodical functions, β may be thought of as a wavenumber
(angular frequency) and δ as a phase angle. (See appendix A.3 in Numeriske Beregninger)
For further simplification we introduce some standard trigonometric formulas:
2 cos(x) = eix + e−ix
i 2 sin(x) = eix − e−ix (7.49)
cos(x) = 1 − 2 sin2 ( x2 )
By substitution (7.49) in (7.47) we get the simpler expression:

δ
 
G = 1 − 2D (1 − cos(δ)) = 1 − 4D sin2 (7.50)
2
As G is real, the condition |G| ≤ 1 has the following mathematical interpretation:
CHAPTER 7. DIFFUSJONSPROBLEMER 277

δ
 
−1 ≤ G ≤ 1 or − 1 ≤ 1 − 4D sin2 ≤1 (7.51)
2

The right hand side of (7.4.1) is always true as D ≥ 0. For the left hand side of (7.4.1) we
have
1
D≤
2 sin2 ( 2δ )
1
which is true for all δ ( −π ≤ δ ≤ π) when D ≤ 2
. A von Neumann condition for stability
of (7.16) may then be presented as:
1
0<D< (7.52)
2
∆t
where D = (∆y) 2 from (7.17).

As (7.16) is a two-level scheme with constant coefficients, the condition in (7.52) is both
sufficient and necessary for numerical stability. This condition agrees well in the previous
condition in (7.21), which is sufficient only.
The stability condition impose a severe limitation on the size of the timestep ∆t, which of
course influence the CPU-time.
A rough estimate of the CPU-time for the FTCS-schemes with constant D-value yields:

T2 h1 3
 

T1 h2
where T1 and T2 are the CPU-times for ∆y = h1 and ∆y = h2 , respectively. For example
for a reduction in spatial resolution from h1 = 0.1 by a factor 10 to h2 = 0.01 we get an
increase in CPU-time by a factor T T
2
= 1000.
1

Differentiation to find stability conditions. An alternative method to find


extremal values (i.e. max/min) for G as a function of δ, is to compute dGdδ
and then set it to
dG

= 0. A stability condition may then be found from the criterion |G| < 1. For the current
example we have from (7.50):

dG
G = 1 − 2D (1 − cos(δ)) ⇒ = −2D sin(δ)

which has extremal values for δ = 0,
δ = ±π, δ = 0 gir G = 1, whereas δ = ±π yields the condition G = 1 − 4D. Finally, the
condition |G| ≤ 1 yields:

−1 ≤ 1 − 4D ≤ 1
The right hand side of the inequality will always be satisfied for positive D, whereas the
left hand side yields D ≤ 21 as before.
In many situations we will find that δ = ±π are critical values, and it may therefore be
wise to assess these values, but remember it might not be sufficent in order to prove stability.
On the other hand these values might sufficient to prove instabilities for those values, as the
condition |G| ≤ 1 must be satisfied for all δ-values in the range [−π, π].

Comparison of the amplification factors. In this section we will compare the


numerical amplification factor G in (7.50) with the analytical amplification factor Ga in (7.39)
By making use of (7.41) and (7.48) we may present the analytical amplification factor
(7.39) as:

Ga = exp(−δ 2 D) (7.53)
CHAPTER 7. DIFFUSJONSPROBLEMER 278

And from (7.50) we have an expression for the numerical amplification factor:

δ
 
G = 1 − 2D (1 − cos(δ)) = 1 − 4D sin2 (7.54)
2
In figure 7.4 we plot G and Ga as functions of δ ∈ [0, π] for selected values of D. For
small values of δ we observe small differences between G and Ga , with slightly larger values of
G than for Ga , with progressively increasing differences as a function of δ.

1.0

0.5
G

0.0
Ga (D = 0.25)
G (D = 0.25)
Ga (D = 0.35)
−0.5
G (D = 0.35)
Ga (D = 0.5)
G (D = 0.5)
−1.0
0 20 40 60 80 100 120 140 160 180
[degrees]

Figure 7.4: The amplification factors G (dotted) and Ga (solid) as a function


of δ for specific values of D.

Further, we observe large errors for δ ∈ [90◦ , 180◦ ] and that the amplification factor G
even has the wrong sign, which will lead to unpysical oscillations in the numerical solution.
The reason why the solution may still be usable is due to that the analytical solution
has an amplitude Ga which diminishes strongly with increasing frequency (see the analytical
solution in (7.13)). Such a smoothing effect is typical for parbolic PDEs. Yet the effect is
noticable as we in the current example have a discontinuity at y = 0, such that the solution
contains many high frequent components.
Errors in the amplitude is commonly quantified with εD = GG and denoted diffusion
a
error or dissipation error. No diffusion error corresponds to εD = 1. The term diffusive scheme
will normally refer to a numerical scheme with decreasing amplitude with increasing t. For our
FTCS-scheme applied for the diffusion equation we have:

εD = 1 − 4D sin2 (δ/2) exp(δ 2 D) (7.55)
The expression in (7.55) may be simplified by a Taylor-expansion:

εD = 1 − D2 δ 4 /2 + Dδ 4 /12 + O(δ 6 )
which confirms that the dissipation error is smal for low frequencies when D ≤ 1/2.

7.5 Flere skjema for parabolske ligninger


7.5.1 Richardson-skjemaet (1910)
FTCS-skjemaet er av 1. ordens nøyaktighet i t og 2. orden i y. Vi ønsker et skjema som også
er av av 2. ordens nøyaktighet i t. Dette oppnår vi ved å benytte sentraldifferanser for leddet
∂u
∂t
:
CHAPTER 7. DIFFUSJONSPROBLEMER 279

∂u n
un+1
j − ujn−1

∂t j 2∆t

som gir følgende differanseligning:

un+1
j = ujn−1 + 2D un n n
j−1 − 2uj + uj+1 (7.56)
Dette er et eksplisitt, 3-nivå skjema som kalles Richardson-skjemaet; se Figure 7.5.

n+1

n-1

j-1 j j+1

Figure 7.5: Marit 1: description

Stabilitetsanalyse.
La oss først forsøke det tilstrekkelige kriteriet i (7.21). Betingelsen om bare positive
koeffisienter lar seg ikke oppfylle da koeffisienten foran un
j -leddet alltid er negativt for D > 0.
Vi prøver derfor med von Neumanns metode. (7.42) innsatt i (7.56) gir:

Gn+1 ei·βyj = Gn−1 ei·βyj + 2D[Gn ei·βyj−1 − 2Gn ei·βyj + Gn ei·βyj+1 ]


Dividerer med Gn−1 eiβyj der yj = j · h :

G2 = 1 + 2DG · e−iδ + eiδ − 2 = 1 + 4DG · (cos(δ) − 1)

= 1 − 8GD · sin2 2δ
hvor vi har brukt (7.48) og (7.49). Vi har fått en 2. gradsligning fordi vi har et 3-nivå skjema:

G2 + 2bG − 1 = 0 med løsning


√ δ

G1,2 = −b ± b2 + 1, b = 4D sin2 2
≥0
|G| = 1 for b = 0. For alle andre verdier av b har vi |G2 | > 1. Skjemaet er følgelig ustabilt
for alle aktuelle verdier av D. Et slikt skjema betegnes som ubetinget ustabilt. Dette tilfellet
viser at det ikke er noen sammenheng mellom nøyaktighet og stabilitet.
Bruk av derivasjon
Vi kan bruke derivasjon her også:

G2 = 1 + 4DG  · (cos(δ) − dG
1) 
2G dG

= 4D (cos(δ) − 1) dδ
− G sin(δ) , som med dG

=0
gir max-min for δ = 0, δ = ±π som for FTCS-skjemaet.p
δ = 0 gir G1,2 = ±1 mens δ = ±π gir G1,2 = −4D ± 1 + (4D)2
med instabilitet for |G2 | > 1 som tidligere.
CHAPTER 7. DIFFUSJONSPROBLEMER 280

7.5.2 Dufort-Frankel skjemaet (1953)


Richardson-skjemaet i (7.56) kan gjøres stabilt ved følgende modifikasjon:
1 n+1
un
j = (u + ujn−1 ) (7.57)
2 j
som innsatt i (7.56) gir:
1  
un+1
j = (1 − 2D)ujn−1 + 2D(un n
j+1 + uj−1 ) (7.58)
1 + 2D
Dette er et eksplisitt 3-nivå skjema som kalles DuFort-Frankel-skjemaet, se Figure 7.6

n+1

n-1

j-1 j j+1

Figure 7.6: Marit 1: description

3-nivå skjema der leddet un


j -leddet mangler, kalles skjema av “Leap-frog”-typen. (Leap-
frog: hoppe bukk). Det tilstrekkelige kriteriet om positive koeffisienter fra (7.21) krever D ≤ 12
for et stabilt skjema. Stabilitetsanalysen er her litt mer komplisert p.g.a. at vi også må drøfte
komplekse verdier av G.
iδj
Innsatt fra (7.42) og divisjon med Gn−1 ee :

1   1
G2 = (1 − 2r) + 2r · G · (eiδ + e−iδ ) = [(1 − 2r) + 4r · G · cos(δ)]
1 + 2r 1 + 2r
som gir følgende 2. grads ligning:

(1 + 2D) · G2 − 4D · G cos(δ) − (1 − 2D) = 0 med løsning:


p
4D cos(δ) ± (4D cos(δ))2 + 4(1 + 2D) · (1 − 2D)
G1,2 =
2(1 + 2D)
p
2D cos(δ) ± 1 − D2 sin2 (δ)
=
1 + 2D
For stabilitet må begge røttene oppfylle betingelsen |G| ≤ 1. Generelt må vi dessuten
skille mellom reelle og komplekse røtter for å ta vare på det tilfellet at G ≤ 0 når G er reell.
1. Reelle røtter: 1 − 4D2 sin(δ)
p ≥0
2D · | cos(δ)| + 1 − 4D2 sin2 (δ) 1 + 2D
|G1,2 | ≤ ≤ ≤1
1 + 2r 1 + 2D
CHAPTER 7. DIFFUSJONSPROBLEMER 281
p p
2. Komplekse røtter: 1 − 4D2 sin2 (δ) < 0 → 1 − 4D2 sin2 (δ) = i · 4D2 sin2 (δ) − 1
2
+4D 2 sin2 (δ)−1
2D cos(δ)

4D2 −1 2D−1
|G1,2 |2 = = 4D2 +4D+1 = 2D+1 < 1

(1+2D)2

Analysen viser at (7.58) faktisk er ubetinget stabilt. DuFort-Frankel skjemaet er det eneste
enkle kjente eksplisitte skjemaet med 2. ordens nøyaktighet som har denne egenskapen. Det
har derfor vært en del brukt ved løsning av Navier-Stokes ligninger. I avsnitt (7.6) skal vi
se at forholdene ikke er så fullt så rosenrøde som analysen ovenfor kan tyde på. For å starte
beregningen, kan FTCS-skjemaet brukes.

7.5.3 Crank-Nicolson skjemaet. θ-skjemaet


En av bakdelene ved DuFort-Frankel skjemaet er at det behøves et spesielt skjema for å starte
regneprosessen. Vi forsøker derfor å finne en approksimasjon for ∂u
∂t
av 2. ordens nøyaktighet
der bare to tidsnivå inngår.
Bruker sentraldifferanser for halve tidsintervallet:

un+1
1
∂u n+ 2

j − un
j
= + O(∆t)2 (7.59)
∂t j ∆t

1
∂u n+ 2

Problemet blir nå å approksimere uten at nivået n + 12 eksplisitt inngår i skjemaet.
∂t j

Dette oppnås ved Crank-Nicolson
approksimasjonen (1947):

un+1 n+1
+ un+1
1
un n n
 
∂ 2 u n+ 2 j+1 − 2uj j+1 − 2uj + uj−1

1 j−1
= + + O(∆x)2 (7.60)
∂x2 j 2 (∆x)2 (∆x)2

Differanseligningen blir nå:

1 n+1 1 n
un+1
j−1 − 2(1 + )u + un+1 n
j+1 = −uj−1 + 2(1 − )u − un (7.61)
D j D j j+1

∆t
der D = som før.
(δx)2
Skjemaet er illustrert i Figure 7.7.
Vi ser av (7.61) og Figure 7.7 at skjemaet er implisitt. Dette betyr at vi må løse
et ligningsystem. I dette tilfellet er systemet tridiagonalt, slik at Thomasalgoritmen og
programmet tdma kan brukes. Marie 46: Henvisning til Matlab
Vi skal nå undersøke stabiliteten av (7.61). For å slå flere fluer i et smekk, tar vi for oss
følgende differanseligning som kalles θ-skjemaet:

 
un+1
j = un n+1 n+1
j + D θ(uj+1 − 2uj + un+1 n n n
j−1 ) + (1 − θ)(uj+1 − 2uj + uj−1 ) (7.62)

der 0 ≤ θ ≤ 1 (7.63)
For θ = 0 får vi det eksplisitte FTCS-skjemaet. For θ = 12 får vi Crank-Nicolson
skjemaet. For θ = 1 fås et implisitt skjema som ofte kalles Laasonen-skjemaet (1949). I
strømningsmekanikken brukes gjerne betegnelsen BTCS-skjemaet. (Backward Time Central
Space) eller det totalt implisitte skjemaet.
(7.42) innsatt i (7.62) og divisjon med Gn · ei·βxj gir:

G = 1 + D[Gθ(eiδ + e−i·δ − 2) + (1 − θ)(eiδ + e−iδ − 2)]


= 1 + D(eiδ + e−iδ − 2) · (Gθ + 1 − θ)

der δ = β · h
CHAPTER 7. DIFFUSJONSPROBLEMER 282

n+1

n+½

j-1 j j+1

Figure 7.7: Marit 1: description

Med bruk av formlene i (7.49):

1 − 4D(1 − θ) sin2 ( 2δ )
G= (7.64)
1 + 4Dθ sin2 ( 2δ )
Betingelsen for stabilitet er |G| ≤ 1 eller siden G er reell: −1 ≤ G ≤ 1
Da 0 ≤ θ ≤ 1 , er den høyre betingelsen tilfredstilt med D ≥ 0. For den venstre siden:

δ
 
2D sin2 (1 − 2θ) ≤ 1 eller
2
1 δ
 
D(1 − 2θ) ≤ da sin2 ≤1
2 2
For 21 ≤ θ ≤ 1 er betingelsen oppfylt for alle D ≥ 0, dvs.: Ubetinget stabil.
For 0 ≤ θ ≤ 12 er skjemaet betinget stabilt.
Stabilitetsbetingelsen er da:
1
D(1 − 2θ) ≤ , 0≤θ≤1 (7.65)
2
Bruk av derivasjon
Vi skriver nå:


G = 1 + D(eiδ + e−iδ − 2) · (Gθ + 1 − θ) = 1 + 2D cos(δ) − 1 · (Gθ + 1 − θ)
dG d  dG i
h 
= 2D (Gθ + 1 − θ) cos(δ) − 1 + cos(δ) − 1 θ ·
dδ dδ dδ
dG
Med = 0 får vi igjen max-min for δ = 0, δ = ±π (δ = 0 gir G = 1 som ventet) δ = ±δ

1 − 4D(1 − θ)
gir G = som er identisk med (7.64) innsatt for 2δ = 90◦ . Betingelsen |G| ≤ 1
1 + 4Dθ
1 − 4D(1 − θ)
blir −1 ≤ ≤ 1 med samme resultat som tidligere.
1 + 4Dθ
Nøyaktighet
La oss se nærmere på nøyaktigheten av -skjemaet som gitt i (7.62).
Skriver et enkelt Maple-program
CHAPTER 7. DIFFUSJONSPROBLEMER 283

> eq1:= u(x+h,t+k) - 2*u(x,t+k) + u(x-h,t+k):


> eq2:= u(x+h,t) - 2*u(x,t) + u(x-h,t):
> eq:= (u(x,t+k) - u(x,t))/k -(theta*eq1 + (1-theta)*eq2)/h^2:
> Tnj:= mtaylor(eq,[h,k]):
> Tnj:= simplify(Tnj):
> Tnj:= convert(Tnj,diff);
Vi har her brukt h = ∆x og k = ∆t. T nj er trunkeringsfeilen som er mer detaljert
behandlet i avsnitt (7.6). Anta nå at u(x, t) er den analytiske løsningen av diff.-ligningen
∂u ∂2u ∂ ∂2
= slik at vi kan sette () = osv. Dersom vi bruker disse relasjonene i utskriften
∂t ∂x2 ∂t ∂x2
av T nj, får vi følgende resultat:

1 1 ∂4u 1 ∂6u
h  i
Tjn = −θ · ∆t − (∆x)2 · + (∆t)2 (1 − 3θ) · + ... (7.66)
2 12 ∂x4 6 ∂x6
Vi ser at Tjn = O(∆t) + O(∆x)2 for θ = 0 og 1, altså for henholdsvis Euler-skjemaet og
1
Laasonen-skjemaet, mens Tjn = O(∆t)2 + O(∆x)2 for θ = 2
som er Crank-Nicolson skjemaet.
Dersom vi legger til en linje
Tnj:= simplify(subs(theta =(1-h^2/(6*k))/2,Tnj));
1
i programmet ovenfor, finner vi at Tjn = O(∆t)2 + O(∆x)4 dersom vi velger D =
6(1 − 2θ)
1
når D ≤ .
2(1 − 2θ)
Mer om stabiliteten.
Vi har funnet at skjemaet er ubetinget stabilt for 12 ≤ θ ≤ 1. I praksis viser det seg at
skjemaet kan gi oscillasjoner rundt diskontinuiteter for θ = 12 . En θ-verdi > 0.5 vil dempe
disse oscillasjonene og denne dempningen er sterkest for θ = 1. La oss se på et eksempel der vi
bruker varmeledningsligningen på dimensjonell form.

100mm 100mm 100mm

Figure 7.8: Marit 1: description

Figuren viser en tynn aluminiumstang med lengde 300 mm.


Varmeledningsligningen er som vanlig gitt ved:

∂T ∂2T
= α 2 , T = T (x, t)
∂t ∂x
Randbetingelser:

T (0, t) = T (300, t) = 20◦ C


Startbetingelser:

T (x, 0) = 270◦ C for x ∈ (100, 200)


T (x, 0) = 20◦ C for x ∈ (0, 100) og x ∈ (200, 300)
Termisk diffusivitet:

α = 100mm2 /s
Det numeriske Fourier-tallet:
CHAPTER 7. DIFFUSJONSPROBLEMER 284

∆t
D=α
(∆x)2

Velger ∆t = 0.25 s slik at ∆x = 5/ D. Ved å velge D = 4, får vi ∆x = 2.5 mm. Figurene
på neste side viser en beregning med θ = 12 og en med θ = 1; altså Crank-Nicolson skjemaet
og Laasonen-skjemaet.
Marit 48: Interaktivt plot?

Figure 7.9: Marit 1: description

Marit 48: Interaktivt plot?

Figure 7.10: Marit 1: description

Vi ser at C-N-skjemaet gir kraftige oscillasjoner ved diskontinuitetene x = 100 of x = 200


for startprofilet. Etter t = 4 s er disse oscillajonene nesten borte. For Laasonen-skjemaet har
vi ingen oscillasjoner selv rundt t = 0. For å finne årsaken til dette, må vi gå tilbake til lign.
(7.64):
CHAPTER 7. DIFFUSJONSPROBLEMER 285

1 − 4D(1 − θ) sin2 ( 2δ )
G=
1 + 4D sin2 ( 2δ )
1
For θ = 2
får vi:

1 − 2D sin2 ( 2δ )
G=
1 + 2D sin2 ( 2δ )
For δ i nærheten av π, vil G ligge rundt −1 for store verdier av D. Dette ser vi tydeligst
1 − 2D
ved å velge δ = π = β · h som gir G = .
1 + 2D
Fra (7.44) har vi:

Ejn = Gn · Ej0 , Ej0 = ei·βxj


Derfor ser vi at vi vil få oscillasjoner for δ i nærheten av π. Disse høye bølgetallene vil dø
ut for økende t fordi startprofilet blir utglattet av dissipasjonen. Dersom vi setter D = 4 som
 16
7
brukt i eksemplet, vil vi etter 16 tidsteg med ∆t = 0.25s få G16 = − ≈ 0.12, mens vi
8
med D = 1 ville fått G16 = 2.3 · 10−8 . Dette betyr at de høye bølgetallene avtar langsomt
for store verdier av D. Mye likt Gibbs-fenomenet ved Fourierutvikling av diskontinuerlige
funksjoner. (Se appendiks A.3, tilfelle 1 i Numeriske Beregninger).
For Laasonen-skjemaet med θ = 1 får vi derimot:
1
G=
δ
 
1 + 4D sin2
2
Vi får her ingen oscillasjoner for noen av bølgetallene.
Dersom vi bruker uttrykk fra stabilitet av ordinære differential-ligninger, kan vi si at
θ-skjemaet er absolutt stabilt (A-stabilt) for θ = 12 og strengt absolutt stabilt (eller L-stabilt)
for θ = 1 . (Se avsnitt 1.6.1 i Numeriske Beregninger)
Dersom vi bruker θ-skjemaet på et varmeledningsproblem av den typen som vist ovenfor
med foreskrevet temperatur på begge rendene (Dirichlet-betingelser), vet vi at den maksimale
temperaturen til enhver tid må ligge mellom den største som er gitt i startprofilet og den minste
som er gitt på randen, eller Tmin ≤ Tjn ≤ Tmax . For eksemplet ovenfor, er Tmin = 20◦ C og
Tmax = 270◦ C. Men da oppfyller vi kravene til PK-kriteriet .
Skriver (7.62) løst med hensyn på un+1
j :

1  
un+1
j = θD(un+1 n+1 n n
j−1 + uj+1 ) + (1 − θ)D(uj−1 + uj+1 ) + 1 − (1 − θ)2D (7.67)
1 + 2θD
Ved å summere koeffisientene på høyre side, finner vi at summen er lik 1. Deretter må vi
forlange at koeffisientene er positive. Dette betyr at 0 < θ < 1 og 1 − (1 − θ) · 2D > 0. Den
siste ulikheten er oppfylt for D · (1 − θ) < 21 . Ved å sette θ = 0 og θ = 1, finner vi at summen
er lik 1 også for disse verdiene, slik at vi får følgende betingelse for oppfyllelse av PK-kriteriet:
1
D · (1 − θ) ≤ (7.68)
2
Fra von Neumann-analysen fant vi følgende betingelse fra (7.65):
1
D · (1 − 2θ) ≤ (7.69)
2
Vi ser at (7.68) er vesentlig strengere enn (7.69). Mens C-N-skjemaet med θ = 12 er
ubetinget stabil i følge von Neumann-analysen, må vi ha D ≤ 1 ifølge PK-kriteriet. PK-
kriteriet gir her en sikker betingelse forat det fysiske max-min-kriteriet også oppfylles for
differanseligningen. En test med eksemplet ovenfor, bekrefter dette kriteriet. Finnes det
CHAPTER 7. DIFFUSJONSPROBLEMER 286

da et kriterium som er både nødvendig og tilstrekkelig for dennne enkle modell-ligningen?


Kraaijevanger fant i 1992 følgende nødvendige og tilstrekkelige kriterium:

2−θ
D · (1 − θ) ≤ (7.70)
4(1 − θ)
Vi ser at for θ = 12 gir dette kriteriet betingelsen D ≤ 32 . For θ = 34 gir (7.70) D ≤ 5 mens
PK-kriteriet gir D ≤ 2.
Hensikten med store D-verdier er for å kunne bruke forholdsvis store tidskritt når vi
ønsker å følge hele tidsforløpet mot en stasjonær tilstand. Men vi må selvfølgelig tenke på
nøyaktigheten også. Husk dessuten at dette er en enkel endimensjonal differanseligning med
konstante koeffisienter som kan løses meget raskt med en moderne PC nærmest uavhengig
at ∆t og ∆x så lenge vi holder oss innfor stabilitetsområdet. Ikke-stasjonære problem i tre
dimensjoner krever fremdeles mye regnetid.

7.5.4 Von Neumanns generelle stabilitetsbetingelse


Vi har omtalt stabilitetsbetingelsen |G| ≤ 1 som von Neumanns strenge stabilitetsbetingelse.
Årsaken til denne betegnelsen, er at dersom |G| ≤ 1 er oppfylt, kan ikke amplituden øke.
I mange tilfeller har vi selvfølgelig fysikalske problemer der amplituden vokser med t. ( t
begrenset ). Et enkelt eksempel er varmeledningsligningen med et kildeledd:

∂T ∂2T
= α 2 + bT, b = konstant, t < tmaks (7.71)
∂t ∂x
Med b < 0 har vi et varmesluk, mens for b > 0 har vi en varmekilde. I det første tilfellet
kan vi bruke det strenge kriteriet, men for det andre tilfellet er det nødvendig å tillate |G| > 1.
En partikulær løsning av (7.71) er gitt ved:
2 2
T (x, t) = ebt · e−αβ ·t
cos(βx) = e(b−αβ )·t
cos(βx) (7.72)
La oss bruke (7.72) til å bestemme en analytisk forsterkningsfaktor, se (7.39):

T (xj , tn+1 )   2
Ga = = exp (b − αβ 2 ) · tn+1 − (b − αβ 2 ) · tn = eb∆t · e−αβ ∆t (7.73)
T (xj , tn )

Vi ser at det er leddet eb·∆t som får amplituden til å øke med positiv b.
En rekkeutvikling for små ∆t:

b2
eb∆t = 1 + b · ∆t + (∆t)2 + . . . (7.74)
2
Dersom vi bruker FTCS-skjemaet, får vi:

Tjn+1 = D(Tj+1
n n
+ Tj−1 ) + (1 − 2D)Tjn + ∆tbTjn (7.75)
med
∆t
D=α (7.76)
(∆x)2
Dersom vi bruker PK-kriteriet, finner vi at summen av koeffisientene er lik 1 + b · ∆t, slik
at dette kriteriet bare kan brukes for b < 0.
Får ved å bruke von Neumanns metode på (7.75):

δ
 
G = 1 − 4D sin2 + ∆t · b (7.77)
2
1
Ved å sette D = 2
, får vi:

δ
 
|G| ≤ 1 − 2 sin2 + |∆t · b| ≤ 1 + ∆t · b, b > 0

2
Dersom vi sammenligner med (7.74), ser vi at vi får god overenstemmelse mellom den
analytiske og den numeriske forsterkningsfaktoren i dette tilfellet.
CHAPTER 7. DIFFUSJONSPROBLEMER 287

Innfører von Neumanns generelle betingelsen ved:

|G| ≤ 1 + K · ∆t (7.78)
der K er en positiv konstant.
Dette betyr at vi tillater amplituden å øke eksponentsielt for t < tmaks . I dette tilfellet
kan vi bruke den strenge betingelsen dersom vi resonnerer på følgende måte:
Da kildeleddet i (7.71) ikke inneholder noen derivert størrelse, kan vi se bort fra dette
leddet ved stabilitetsundersøkelsen. Vi har her samme type problemstilling som i avsnitt 1.6 i
Numeriske Beregninger, der vi diskuterer stive, ordinære differensialligninger. (Se f.eks. lign.
(1.6.8) i avsnitt 1.6.1 i Numeriske Beregninger).
For en voksende amplitude må vi minske skrittlengden for den uavhengige variable dersom
vi skal oppnå en foreskrevet nøyaktighet. For en minskende amplitude må vi derimot holde
oss under en maksimum skrittlengde for å få en stabil regneprosess.
La oss se på et annet eksempel med bruk av FTCS-skjemaet.

∂u ∂2u ∂u
= α 2 + a0 , α>0 (7.79)
∂t ∂x ∂x
Denne ligningen som kalles adveksjon-diffusjonsligningen, er fremdeles en parabolsk ligning
ifølge klassifiseringskjemaet i avsnitt 4.3 i Numeriske Beregninger.
∂u
Ved bruk av FTCS-skjemaet på (7.79) med sentraldifferanser for :
∂x

∆t ∆t
un+1 = un n n n
j + D · (uj+1 − 2uj + uj−1 ) + a0 (un − un
j−1 ), D = α
j
2∆x j+1 (∆x)2
Bruker von Neumanns metode:

δ ∆t
 
G = 1 − 4D sin2 + i · a0 sin(δ)
2 ∆x
som videre gir:

a20 · D
 2 2  2
δ ∆t δ
  
|G|2 = 1 − 4D sin2 + a0 sin(δ) = 1 − 4D sin2 + · ∆t sin2 (δ)
2 ∆x 2 α
1
Velger igjen D = 2
:
r
a20 a20
 2
δ
|G| = 1 − 2 sin2 + · ∆t · sin2 (δ) ≤ 1 + · ∆t
2 2α 2α
p
Vi har her brukt x2 + y 2 ≤ |x| + |y|
a2
0
Med K = ,
ser vi at den generelle betingelsen i (7.78) er oppfylt.

Adveksjon-diffusjonsligningen er behandlet mer detaljert i avsnitt 6.10 i Numeriske Bereg-
ninger.

7.6 Trunkeringsfeil, konsistens og konvergens


7.6.1 Trunkeringsfeil
La U (x, t) være den eksakte løsningen av en PDL, skrevet L(U ) = 0, og u den eksakte løsningen
av den tilhørende differanseligningen, skrevet F (u) = 0. Den eksakte løsningen i (xi , tn ) er
gitt ved:

Uin ≡ U (xi , tn ) der xi = i · ∆x = i · h, i = 0, 1, 2, . . . (7.80)


tn = n · ∆t = n · k, n = 0, 1, 2, . . . (7.81)
CHAPTER 7. DIFFUSJONSPROBLEMER 288

For den lokale trunkeringsfeilen Tin får vi da følgende uttrykk:

Tin = F (Uin ) − L(Uin ) = F (Uin ) (7.82)


Tinfinnes ved Taylor-utvikling.
Noen rekkeutviklinger:

∂U n h2 ∂ 2 U n h3 ∂ 3 U n

n
Ui±1 ≡ U (xi±h , tn ) = Uin ± h · + · 2
± · + ... (7.83)
∂x i 2 ∂x i 6 ∂x3 i

∂U n k 2 ∂ 2 U n k 3 ∂ 3 U n

Uin±1 ≡ U (xi , tn±k ) = Uin ± k · + 2 · ∂t2 ± 6 · ∂t3 + . . . (7.84)
∂t i i i

La oss som eksempel finne den lokale trunkeringsfeilen Tin for FTCS-metoden anvendt på
diffusjonsligningen L(U ) = 0 der

∂U ∂2U
L(U ) = − =0
∂t ∂x2
Uin+1 − Uin n
Ui−1 − 2Uin + Ui+1
n
Tin = F (Uin ) = − (7.85)
k h2
Innsatt fra (7.83) i (7.85):

 n  n
∂2U k ∂2U h2 ∂ 4 U k 2 ∂ 3 U n

∂U
Tin = − + − + + O(k3 , h4 )
∂t ∂x2 2 ∂t 2 12 ∂x4 6 ∂t3 i
i i
∂U ∂2U
Da − =0
∂t ∂x2
 n
k ∂2U h2 ∂ 4 U
Tin = 2
− + høyere ordens ledd (7.86)
2 ∂t 12 ∂x4
i
(7.86) viser at Tin = O(k) + O(h2 ) som ventet.
(7.86) kan også skrives:
 n
h2 k ∂2U ∂4U
Tin = · 6 − + O(k2 ) + O(h4 )
12 h2 ∂t2 ∂x4
i
k 1
Ved å velge D = = , får vi:
h2 6
Tin = O(k2 ) + O(h4 ) (7.87)
∆t blir svært liten for D = 1/6, men med dagens PC-er er dette ikke noen problem,
bortsett fra eventuell akkumulering av avrundingsfeil.

7.6.2 Konsistens
Vi sier at differanseligningen er konsistent med den gitte differensial-ligningen dersom den
lokale trunkeringsfeilen Tin → 0 når ∆x og ∆t → 0 uavhengig av hverandre.

7.6.3 Example: Consistency of the FTCS-scheme


Fra (7.86)
 n
k ∂2U h2 ∂ 4 U
Tin = − → 0 for h og k → 0
2 ∂t2 12 ∂x4
i
Dette betyr at FTCS -skjemaet er konsistent med diffusjonsligningen .
CHAPTER 7. DIFFUSJONSPROBLEMER 289

7.6.4 Example: Consistency of the DuFort-Frankel scheme


La oss se nærmere på DuFort-Frankel skjemaet fra avsnitt (7.5.2):
 n n − (U n+1 + U n−1 )

Uin+1 − Uin−1 Ui−1 + Ui+1 i i
Tin = −
2k h2
Med bruk av rekkeutviklingene i (7.83) og (7.84):

  2 n  n  
∂U ∂2U k ∂2U k2 ∂ 3 U h2 ∂ 4 U k4 4 4
Tin = − + + − +O ,k ,h (7.88)
∂t ∂x2 h ∂t2 6 ∂t3 12 ∂x4 h2
i i
 2
k
P.g.a faktoren er det viktig å spesifisere hvordan k og h → 0. Skjemaet er ikke
h
uten videre konsistent med den gitte ligningen. Et slikt skjema betegnes gjerne som betinget
konsistent.
Tilfelle 1
k
Setter r0 = → k = r0 · h, r0 en konstant > 0.
h
Innsatt for k i (7.88):
 n
∂U ∂2U ∂2U
Tin = − + r02 · + O(h2 )
∂t ∂x2 ∂t2
i
For h → 0, ser vi at DuFort-Frankel skjemaet nå er konsistent med den hyperbolske
∂U ∂2U ∂2U
ligningen + r02 2 = og ikke den opprinnelige diffusjonsligningen.
∂t ∂t ∂x2
Tilfelle 2
k
Setter r0 = 2 → k = r0 · h2 . Innsatt for k i (7.88):
h
h in h in  
∂U ∂2U 2
k2 ∂ 3 U h2 ∂ 4 U k4
Tin = ∂t
− ∂x2
+ r02 h2 ∂∂tU
2 + 6 ∂t3
− 12 ∂x4
+O h2
, k 4 , h4
h i in i
2
k2 ∂ 3 U h2 ∂ 4 U

= r02 h2 ∂∂tU
2 + 6 ∂t3
− 12 ∂x4
+ O r04 h6 , k4 , h4
i
 n
∂U ∂2U
da − =0
∂T ∂x2
i
Vi ser at Tin → 0 for h og t → 0 med Tin = + O(h2 ). O(k2 )
Skjemaet er nå konsistent med diffusjonsligningen. D-F-skjemaet kan derfor brukes med
k = r0 · h2 . Men da har vi fått en begrensning på ∆t, ikke som et stabilitetskrav, men ved
kravet til konsistens. Ikke-konsistente skjema oppstår vanligvis når vi trikser med skjemaene
etter at vi har Taylor-utviklet dem på vanlig måte.

7.6.5 Konvergens
Med U som den eksakte løsningen av differensialligningen og u som den eksakte løsningen av
den tilhørende differanseligningen, sier vi at differanseligningen er konvergent dersom

lim → U for gitt tn og xi


∆x,∆t→0
Det er generelt vanskelig å bevise konvergensen av et differanseskjema. Derfor har det
vært gjort mange forsøk på å erstatte definisjonen ovenfor med betingelser som er lettere å
bevise hver for seg, men som tilsammen er tilstrekkelig for konvergens.
Det mest kjente av disse teoremene er
CHAPTER 7. DIFFUSJONSPROBLEMER 290

Lax’s teorem: Dersom det lineære initialverdiproblemet er velformulert og den


tilhørende differanseligningen er konsistent, er stabilitet en nødvendig og tilstrekkelig
betingelse for konvergens.

Se avsnitt 4.3 i Numeriske Beregninger angående begrepet velformulert. Når vi ser


alle betingelsene som må oppfylles forat Lax’s teorem skal kunne anvendes, skjønner vi
vanskelighetene med å bevise konvergens i mer generelle problemstillinger.

7.7 Eksempler med radiell symmetri


2 2 2
Dersom vi transformerer diffusjonsligningen ∂u
∂t
= ∂∂xu ∂ u ∂ u
2 + ∂y 2 + ∂z 2 til henholdsvis sylinder-
og kule-koordinater og forlanger at u bare skal være funksjon av tiden t og radien r, får vi:
Sylinder:

∂u ∂2u 1 ∂u
= +
∂t ∂r2 r ∂r
Kule:

∂u ∂2u 2 ∂u
= +
∂t ∂r2 r ∂r
Ligningene kan da skrives:

∂u ∂2u λ ∂u
= + , λ = 0, 1, 2 (7.89)
∂t ∂r2 r ∂r
λ = 0 med r → x gir det velkjente kartesiske tilfellet.
(7.89) er en partiell diff. ligning med variable koeffisienter. Vi vil nå forsøke en von
Neumann-analyse av denne ligningen med θ-skjemaet fra avsnitt (7.5.3).
Stabilitetsanalyse med bruk av θ -skjemaet for radius r > 0
∆t
Setter rj = ∆r · j, j = 0, 1, . . . og innfører D = (∆r) 2
For r > 0:

 
un+1
j = un n+1 n+1
j + D θ(uj+1 − 2uj + un+1 n n n
j−1 ) + (1 − θ)(uj+1 − 2uj + uj−1 )
  (7.90)
+ λD
2j
θ(un+1 n+1 n n
j+1 − uj−1 ) + (1 − θ)(uj+1 − uj−1 )

Utførerer en von Neumann-analyse ved å sette inn Ejn = Gn · ei·βrj = Gn ei·δ·j med
δ = β · ∆r og bruk av de vanlige formlene (7.49) og (7.50).
Vi får:

δ θλD δ (1 − θ)λD
     
G · 1 + 4θD sin2 −i· sin(δ) = 1 − 4(1 − θ)D · sin2 +i sin(δ)
2 j 2 j
δ δ
   
som ved bruk av formelen sin(δ) = 2 sin cos og betingelsen |G| ≤ 1 blir:
2 2
 2  2
δ (1 − θ)2 λ2 D2 δ θ2 λ2 D2
 
1 − 4(1 − θ)D sin2 + sin2 (δ) ≤ 1 + 4θD sin2 + sin2 (δ)
2 j2 2 j2
og som videre gir:
 
δ λ2 λ2
   
2
D · (1 − 2θ) · sin · 4− 2 + 2 ≤ 2, j ≥ 1 (7.91)
2 j j
CHAPTER 7. DIFFUSJONSPROBLEMER 291

δ
 
Det er ikke vanskelig å se at leddet i parentesen har sin største verdi for sin2 = 1;
2
dvs. for δ = π. (Kan også finnes ved å derivere leddet m.h.p. δ som gir maksimum for δ = π).
λ2
Faktoren 2 faller da ut.
j
Vi får:

D · (1 − 2θ) · 2 ≤ 1 (7.92)
Som i avsnitt (7.5.3), må vi skille mellom to tilfeller.
1.
1
0≤θ≤
2
∆t 1
D= ≤ (7.93)
(∆r)2 2(1 − 2θ)
2.
1
≤θ≤1
2
Skifter fortegn i (7.92):

D · (2θ − 1) · 2 ≥ −1
Denne betingelsen er alltid oppfylt, slik at differanseligningen er ubetinget stabil for disse
θ-verdiene.
Vi har med andre ord fått de samme stabilitetsbetingelsene som for ligningen med konstante
∂u ∂2u
koeffisienter: = der vi har FTCS-skjemaet for θ = 0, Crank-Nicolson-skjemaet for
∂t ∂r2
θ = 1/2, og Laasonen-skjemaet for θ = 1.
Merk at denne analysen bare gjelder for r > 0.
Vi må da se på ligningen for r = 0.
λ ∂u
Leddet må behandles spesielt for r = 0.
r ∂r
L’Hopitals regel:

λ ∂u ∂2u ∂u ∂2u
lim =λ 2 → = (1 + λ) 2 for r = 0 (7.94)
r→0 r ∂r ∂r ∂t ∂r
Vi har funnet at ved bruk av FTCS-skjemaet, har vi den vanlige begrensningen D ≤ 1/2.
La oss derfor undersøke om randbetingelsene gir begrensninger når vi bruker FTCS-skjemaet.
Versjon 1
Diskretiserer (7.94) for r = 0 og utnytter symmetribetingelsen ∂u
∂r
(0) = 0:

un+1
0 = [1 − 2(1 + λ)D] · un n
0 + 2(1 + λ)D · u1 (7.95)
Dersom vi bruker PK-kriteriet på (7.95), får vi:
1
D≤ (7.96)
2(1 + λ)
For λ = 0 får vi den velkjente betingelsen D ≤ 1/2, mens vi for sylinderen med λ = 1 får
D ≤ 1/4 og for kule med λ = 2 får D ≤ 1/6. Spørsmålet er om disse betingelsen for sylinder
og kule er nødvendige. Vi vet at D ≤ 1/2 er både tilstrekkelig og nødvendig for λ = 0.
Det er vanskelig å finne et nødvendig og tilstrekkelig kriterium i dette tilfellet. Ser derfor
på et eksempel med oppstart av strømning i et rør, gitt som eksempel (7.7.1).
Versjon 2
For å unngå å bruke en separat ligning for r = 0 , diskretiserer vi symmetribetingelsen
∂u
(0) = 0 med 2. ordens foroverdifferanser:
∂r
∂u −3un n
0 + 4u1 − u2
n
1
(0) = 0 → → un
0 = (4un n
1 − u2 ) (7.97)
∂r 2∆r 3
For kula finnes det en detaljert analyse av Dennis Eisen i tidskriftet Numerische Mathematik
vol. 10, 1967, side 397-409. Han viser at en nødvendig og tilstrekkelig betingelse for løsning av
CHAPTER 7. DIFFUSJONSPROBLEMER 292

(7.90) sammen med (7.95) (for λ = 2 og θ = 0) er at D < 1/3. Dessuten viser han at ved å
unngå å bruke (7.95), får vi stabilitet for FTCS-skjemaet når D < 1/2.
Vi beregner nå to tilfeller for å se hvilke stabilitetskrav vi får i praksis når vi bruker begge
versjonene av randbetingelsene.

7.7.1 Example: Oppstart av rørstrømning

R0
R

Figure 7.11: Marit 1: description

Figuren viser hastighetsprofilet ved strømning i et rør av en inkompressibel fluid ved et


gitt tidspunkt. Vi tenker oss at profilet har utviklet seg fra null ved å sette på en konstant
trykkgradient dpdz
< 0, slik at hastighetsprofilet for det stasjonære tilfellet er det velkjente
parabolske profilet for Poiseuille-strømning.
Bevegelsesligning:
 
∂U 1 dp ∂2U 1 ∂U
=− +ν + (7.98)
∂τ ρ dz ∂R2 R ∂R
der hastighetsprofilet U = U (R, τ ). 0 ≤ R ≤ R0 , og τ er den fysikalske tiden.
Dimensjonsløse variable:

τ R U Us R2 dp
t=ν 2
, r= , u = , us = der k = − 0 (7.99)
R0 R0 k k 4µ dz
som innført i (7.98) gir:

∂u ∂2u 1 ∂u
=4+ + (7.100)
∂t ∂r2 r ∂r
Randbetingelser:

∂u
u(±1, t) = 0, (0, t) = 0 (7.101)
∂r
∂u
Den siste er en symmetribetingelse. Finner stasjonær løsning us for ∂t
= 0:

d2 us 1 dus 1 d dus
 
+ = −4 → r = −4 som gir:
dr2 r dr r dr dr
dus C1 dus (0)
= −2r + med C1 = 0 da =0
dr r dr
Etter en ny integrasjon og bruk av randbetingelsene, får vi den velkjente parabolske
hastighetsfordelingen:

us = 1 − r2 (7.102)
CHAPTER 7. DIFFUSJONSPROBLEMER 293

Vi antar nå at vi har et tilfelle med fullt utviklet profil som gitt i (7.102). Plutselig fjerner
vi trykkgradienten. Fra (7.98) ser vi at dette gir en enklere ligning. Hastigheten ω(r, t) for
dette tilfellet er gitt ved:
W
ω(r, t) = us − u(r, t) med ω = (7.103)
k
Vi skal nå løse følgende problem:

∂ω ∂2ω 1 ∂ω
= + (7.104)
∂t ∂r2 r ∂r
Randbetingelser:

∂ω
ω(±1, t) = 0, (0, t) = 0 (7.105)
∂r
Startbetingelse:

ω(r, 0) = us = 1 − r2 (7.106)
Det opprinnelige problemet er da:

u(r, t) = 1 − r2 − ω(r, t) (7.107)


Den analytiske løsningen av (7.104), (7.107), først gitt av Szymanski i 1932, finnes i
appendiks G.8 i Numeriske Beregninger.
La oss se spesielt på FTCS-skjemaet.
Fra (7.90), med λ = 1, θ = 0 og j ≥ 0:
D
ωjn+1 = ωjn + D · (ωj+1
n
− 2ωjn + ωj−1
n
)+ n
· (ωj+1 n
− ωj−1 ) (7.108)
2j
For j = 0 får vi fra (7.95):

ω0n+1 = (1 − 4D) · ω0n + 4D · ω1n (7.109)


Fra (7.93) får vi stabilitetsintervallet 0 < D ≤ 12 for r > 0 og 0 < D ≤ 1
4
fra (7.96) for r = 0 som er en tilstrekkelig betingelse.
Ved å løse (7.108), får vi følgende tabell for stabilitetsgrensa:
∆r D
0.02 0.413
0.05 0.414
0.1 0.413
0.2 0.402
0.25 0.394
0.5 0.341
For tilfredstillende nøyaktighet bør vi her ha ∆r ≤ 0.1. Av tabellen ovenfor ser vi at da er
betingelsen D < 0.4 er tilstrekkelig. Med andre ord en slags midlere verdi av D = 12 og D = 14 .
Det er ligningen i (7.109) som skaper problemer. Vi kan unngå denne ved isteden å bruke
(7.97):
1
ω0n =(4ω1n − ω2n ), n = 0, 1, . . . (7.110)
3
Beregningen viser da at grensa for hele systemet er gitt ved 0 < D ≤ 12 for FTCS-skjemaet.
Figuren nedenfor viser u-profilet for D = 0.45 med ∆r = 0.1 etter 60 tidskritt med bruk av
(7.109). Tydelig utvikling av instabilitet for r = 0.
Marit 53: Har ikke endret noe her
Programmering av θ-skjemaet:
Boundary conditions given in (7.109)
1
We set rj = ∆r · (j), ∆r = N , j = 0, 1, 2, . . . , N as shown in Fig. 7.13. From Eq. (7.90)
and (7.94) we get:
CHAPTER 7. DIFFUSJONSPROBLEMER 294

Figure 7.12: Marit 1: description

0.0 1.0
r

0 1 2 i N-1 N N+1

Figure 7.13: Marit 1: description

For j = 0:

(1 + 4D · θ) · ω0n+1 − 4D · θ · ω1n+1 = ω0n + 4D(1 − θ) · (ω1n − ω0n ) (7.111)


For j = 1, . . . , N − 1:
 n+1

−Dθ · 1 − 1
2j
· ωj−1 + (1 + 2Dθ) · ωjn+1 − Dθ · 1 + 1
2j
n+1
· ωj+1
1
 n
= D(1 − θ) · 1 − 2j · ωj−1 + [1 − 2D(1 − θ)] · ωjn (7.112)
1
 n
+D(1 − θ) · 1 + 2j
· ωj+1
Initial values:

ωj0 = 1 − rj2 = 1 − [∆r · j]2 , j = 0, . . . , N (7.113)


In addition we have that ωN = 0 for every n-values.
CHAPTER 7. DIFFUSJONSPROBLEMER 295

The system written in matrix form now becomes:

 
1 + 4Dθ −4Dθ 0 0 0 0 0
 −Dθ(1 − 0.5
1
) 1 + 2Dθ −Dθ(1 + 0.5
1
) 0 0 0 0 

 0 −Dθ(1 − 0.5
2
) 1 + 2Dθ −Dθ(1 + 0.5
2
) 0 0 0 

 0 0 · · · 0 0 ·
0 0 0 · · · 0
 
 
0.5
 0 0 0 0 −Dθ(1 − N −2
) 1 + 2Dθ −Dθ(1 + N0.5
−2
) 
0 0 0 0 0 −Dθ(1 − N0.5
−1
) 1 + 2Dθ
(7.114)
Note that we can also use a linalg-solver for θ = 0 (FTCS-scheme). In this case the
elements in the first upper- and lower diagonal are all 0. The determinant of the matrix is now
the product of the elements on the main diagonal. The criterion for non singualar matrix is
then that all the elements on the main diagonal are 6= 0, which is satisfied.
The python function thetaSchemeNumpyV1 show how one could implement the algo-
rithm for solving wn+1 . The function is part of the script/module startup.py which may be
downloaded in your LiClipse workspace.
# Theta-scheme and using L’hopital for r=0
def thetaSchemeNumpyV1(theta, D, N, wOld):
""" Algorithm for solving w^(n+1) for the startup of pipeflow
using the theta-schemes. L’hopitals method is used on the
governing differential equation for r=0.
Args:
theta(float): number between 0 and 1. 0->FTCS, 1/2->Crank, 1->Laasonen
D(float): Numerical diffusion number [dt/(dr**2)]
N(int): number of parts, or dr-spaces. In this case equal to the number of unknowns
wOld(array): The entire solution vector for the previous timestep, n.

Returns:
wNew(array): solution at timestep n+1
"""

superDiag = np.zeros(N - 1)
subDiag = np.zeros(N - 1)
mainDiag = np.zeros(N)
RHS = np.zeros(N)

j_array = np.linspace(0, N, N + 1)
tmp = D*(1. - theta)
superDiag[1:] = -D*theta*(1 + 0.5/j_array[1:-2])
mainDiag[1:] = np.ones(N - 1)*(1 + 2*D*theta)
subDiag[:] = -D*theta*(1 - 0.5/j_array[1:-1])

a = tmp*(1 - 1./(2*j_array[1:-1]))*wOld[0:-2]
b = (1 - 2*tmp)*wOld[1:-1]
c = tmp*(1 + 1/(2*j_array[1:-1]))*wOld[2:]
RHS[1:] = a + b + c

superDiag[0] = -4*D*theta
mainDiag[0] = 1 + 4*D*theta
RHS[0] = (1 - 4*tmp)*wOld[0] + 4*tmp*wOld[1]

A = scipy.sparse.diags([subDiag, mainDiag, superDiag], [-1, 0, 1], format=’csc’)


CHAPTER 7. DIFFUSJONSPROBLEMER 296

wNew = scipy.sparse.linalg.spsolve(A, RHS)


wNew = np.append(wNew, 0)

return wNew
Randbetingelse gitt i (7.97)
Now let us look at the numerical solution when using the second order forward difference
for the bc at r = 0 repeated here for convinience:
1
ω0n =
(4ω1n − ω2n ), n = 0, 1, 2 . . . (7.115)
3
The difference equation for the θ-scheme for j = 1, . . . , N − 1 are the same as in the
previous case:
 n+1

−Dθ · 1 − 1
2j
· ωj−1 + (1 + 2Dθ) · ωjn+1 − Dθ · 1 + 1
2j
n+1
· ωj+1
1
 n
= D(1 − θ) · 1 − 2j · ωj−1 + [1 − 2D(1 − θ)] · ωjn (7.116)
1
 n
+D(1 − θ) · 1 + 2j
· ωj+1
Now inserting Eq. (7.115) into Eq. (7.116) and collecting terms we get the following
difference equation for j = 1:

4 4 4 4
(1 + Dθ) · ω1n+1 − Dθω2n+1 = [1 − D(1 − θ)] · ω1n + D(1 − θ)ω2n (7.117)
3 3 3 3
When ω1 , ω2 , . . . are found, we can calculate ω0 from (7.115).
The initial values are as in Eq. (7.113), repeated here for convonience:

ωj0 = 1 − rj2 = 1 − (∆r · j)2 , j = 0, . . . , N + 1 (7.118)


The system written in matrix form now becomes:

1 + 34 Dθ − 43 Dθ
 
0 0 0 0 0
 −Dθ(1 − 0.5
2
) 1 + 2Dθ −Dθ(1 + 0.5
2
) 0 0 0 0 

 0 −Dθ(1 − 0.53
) 1 + 2Dθ −Dθ(1 + 0.5
3
) 0 0 0 

 0 0 · · · 0 0 ·
0 0 0 · · · 0
 
 
0.5
 0 0 0 0 −Dθ(1 −
N −2
) 1 + 2Dθ −Dθ(1 + N0.5
−2
) 
0 0 0 0 0 −Dθ(1 − N0.5
−1
) 1 + 2Dθ
(7.119)
The python function thetaSchemeNumpyV2 show how one could implement the algo-
rithm for solving wn+1 . The function is part of the script/module startup.py which may be
downloaded in your LiClipse workspace.
In Fig. 7.14 we see that the stability-limit for the two version is different for the to versions
of treating the BC, for FTCS. Using L’hopital’s rule for r=0 give a smaller stability-limit, and
we see that unstability arises at r=0, befor the general stability-limit for the FTSC scheme
(D = 1/2).
# Theta-scheme and using 2nd order forward difference for r=0
def thetaScheme_numpy_V2(theta, D, N, wOld):
""" Algorithm for solving w^(n+1) for the startup of pipeflow
using the theta-schemes. 2nd order forward difference is used
on the von-Neumann bc at r=0.
Args:
theta(float): number between 0 and 1. 0->FTCS, 1/2->Crank, 1->Laasonen
D(float): Numerical diffusion number [dt/(dr**2)]
N(int): number of parts, or dr-spaces.
wOld(array): The entire solution vector for the previous timestep, n.
CHAPTER 7. DIFFUSJONSPROBLEMER 297

Returns:
wNew(array): solution at timestep n+1
"""
superDiag = np.zeros(N - 2)
subDiag = np.zeros(N - 2)
mainDiag = np.zeros(N-1)

RHS = np.zeros(N - 1)
j_array = np.linspace(0, N, N + 1)
tmp = D*(1. - theta)
superDiag[1:] = -D*theta*(1 + 0.5/j_array[2:-2])
mainDiag[1:] = np.ones(N - 2)*(1 + 2*D*theta)
subDiag[:] = -D*theta*(1 - 0.5/j_array[2:-1])

a = tmp*(1 - 1./(2*j_array[2:-1]))*wOld[1:-2]
b = (1 - 2*tmp)*wOld[2:-1]
c = tmp*(1 + 1/(2*j_array[2:-1]))*wOld[3:]
RHS[1:] = a + b + c

superDiag[0] = -(4./3)*D*theta
mainDiag[0] = 1 + (4./3)*D*theta
RHS[0] = (1 - (4./3)*tmp)*wOld[1] + (4./3)*tmp*wOld[2]

A = scipy.sparse.diags([subDiag, mainDiag, superDiag], [-1, 0, 1], format=’csc’)


wNew = scipy.sparse.linalg.spsolve(A, RHS)
w_0 = (1./3)*(4*wNew[0] - wNew[1])

wNew = np.append(w_0, wNew)


wNew = np.append(wNew, 0)

return wNew

Movie 3: Animasjon av eksepelet med bruk av tre θ-skjemaene samt analytisk


øsning. mov-ch5/startup.mp4
emfs /src-ch5/ #python #package startup.py @ git@lrhgit/tkt4140/src/src-ch5/startup_compendium.py; V

7.7.2 Example: Avkjøling av kule


Figuren viser en kule som blir avkjølt i vann. Kula har radius b = 5 og har temperatur Tk før
den senkes i vannet. Vannet holder en konstant temperatur Tv under hele prosessen. Vi ser
bort fra varmetap til omgivelsene.
Andre data:

V armeledningstall : k = 0.1W/(cm ·◦ C) (7.120)


V armeovergangstall : h̄ = 0.2W/(cm ·◦ C) (7.121)
2
T ermiskdif f usitivitet : α = 0.04cm /s (7.122)

h̄ · b
Vi har valgt verdiene slik at forholdet = 1, noe som fører til en enklere analytisk
k
løsning. Verdiene som er angitt i (7.120), (7.121) og (7.122), passer bra for nikkel-legeringer.
CHAPTER 7. DIFFUSJONSPROBLEMER 298

FTCSV1 FTCSV2 Crank-Nicolson Laasonen


1.0

radius [-]
0.8
D = 0.4 0.6
0.4
0.2
0.0

1.0

radius [-]
0.8
D = 0.45 0.6
0.4
0.2
0.0

1.0

radius [-]
0.8
D = 0.5 0.6
0.4
0.2
0.0

1.0

radius [-]
0.8
D = 0.53 0.6
0.4
0.2
0.0

1.0
radius [-]

0.8
D=1 0.6
0.4
0.2
0.0
0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0 0.0 0.2 0.4 0.6 0.8 1.0
Velocity [-] Velocity [-] Velocity [-] Velocity [-]

Figure 7.14: resultat fra test av stabilitet av de to forskjellige variantene av


FTCS samt Crank og Laasonen. Ser at versjon 1 av FTCS utvikler innstabilitet
før D=0.5, og at instabiliteten starter ved r=0. For versjon 2 oppstår innstabilitet
ved D=0.5 og for alle r, som ventet.

Tv
b

Tk

Figure 7.15: Marit 1: description

Vi skal nå løse følgende problem med T = T (r, t):


 
∂T ∂2T 2 ∂T
=α + (7.123)
∂t ∂r2 r ∂r
Randbetingelser:

∂T
(0, t) = 0, (symmetribetingelse) (7.124)
∂r
For r = b :

∂T
k = h̄ · (Tv − Tb ) (7.125)
∂r
CHAPTER 7. DIFFUSJONSPROBLEMER 299

Startbetingelse:

T (r, 0) = Tk (7.126)
I dette eksemplet nøyer vi oss med bruk av FTCS-skjemaet, men beregningen kan lett
utvides til θ-skjemaet som vist i eksempel (7.7.1). Med rj = ∆r · j, ∆r = N1+1 , j =
∆t
0, 1, . . . , N + 1 og D = α (∆r)2 får vi fra (7.90) når u(r, t) → T (r, t), θ = 0 og λ = 2:

Tjn+1 = (1 − 2D) · Tjn + D[(1 − 1/j) · Tj−1


n n
+ (1 + 1/j) · Tj+1 ], j = 1, 2, . . . (7.127)

Som i eksempel (7.7.1), bruker vi to versjoner for symmetribetingelsen for r = 0. 1)


Fra (7.95) med λ = 2:

T0n+1 = (1 − 6D) · T0n + 6D · T1n (7.128)


2) Fra (7.97):
1
T0n = (4T1n − T2n ), alle n (7.129)
3
Randbetingelsen for r = b.
Diskretiserer (7.124) med bruk av 2. ordens bakoverdifferanser:
n n n
 
3TN +1 − 4TN + TN −1 n
k· = h̄ · (Tv − Tb ) som løst m.h.p TN +1 gir:
2 · ∆r
n − Tn
n
4TN N −1 + 2δ · Tv
TN +1 = (7.130)
3 + 2δ
∆r · h̄
der δ = (7.131)
k
Vi har tidligere vist at vi må ha D < 1/3 når vi bruker randbetingelsen i (7.128)). I
eksempel (7.7.1) for sylinderen, fant vi at stabilitetsgrensen for D økte når vi minsket ∆r ved
bruk av FTCS-skjemaet. For kula derimot viser det seg at betingelsen D < 1/3 er uavhengig
av ∆r. Årsaken til dette finner vi når vi skriver ut (7.127) for j = 1:

T1n+1 = (1 − 2D) · T1n + 2D · T2n


Leddet (1 − 1/j) · n
Tj−1= (1 − 1) · T0n forsvinner for j = 1, slik at temperaturen i kulas
sentrum ikke influerer på noen av de andre verdiene. Dette forklarer hvorfor stabilitetsgrensa
er uavhengig av ∆r. Vi kan da faktisk løse (??) for j = 1, 2, . . . , N uten å bry oss om
randbetingelsene i (7.128) og (7.129). Randbetingelsen i (7.129) trenger vi bare for å finne
temperaturen T0n i sentrum av kula.
Neumann-analysen som ikke tar hensyn til rendene, viste at (7.127) er stabil for D ≤ 1/2.
Dessuten viste analysen at innflytelsen av den variable koeffisienten forsvant både for sylinderen
og kula. (Se diskusjonen i forbindelse med (7.91)). Vi har ikke vist at D ≤ 1/2 er en tilstrekkelig
betingelse for hele systemet, siden vi da også må ta med randbetingelsen i (7.130).
Vi kan da oppsummerer for bruk av FTCS-skjemaet for kula:
Skjemaet i (7.130) er stabilt for D < 1/2 for j = 1, 2, . . .
Dersom sentrumstemperaturen også beregnes, må vi ha D < 1/3 når (7.128) brukes.
Med bruk av (7.129), kan sentrumstemperaturen beregnes for D < 1/2.
Dette passer godt med Eisens analyse, omtalt i forbindelse med (7.97).
Nedenfor er vist utskrift fra programmet kule av en beregning med D = 0.4 og ∆r = 0.1cm.
Tk = 300◦ C og Tv = 20◦ C og beregningen varer i 10 min. med tidskritt 1 sekund. De analytiske
verdiene er beregnet av funksjonen kanalyt. Vi ser at det er god overenstemmelse mellom de
numeriske og de analytiske verdiene. (Analytisk løsning i appendiks G.9)
CHAPTER 7. DIFFUSJONSPROBLEMER 300

r(cm) T (◦ C) Ta r(cm) T (◦ C) Ta
0.00 53.38 53.37 2.60 49.79 49.78
0.10 53.37 53.36 2.70 49.52 49.51
0.20 53.36 53.35 2.80 49.24 49.23
0.30 53.33 53.32 2.90 48.95 48.94
0.40 53.29 53.28 3.00 48.65 48.64
0.50 53.24 53.23 3.10 48.35 48.34
0.60 53.18 53.17 3.20 48.03 48.03
0.70 53.11 53.10 3.30 47.71 47.71
0.80 53.03 53.02 3.40 47.38 47.38
0.90 52.93 52.93 3.50 47.05 47.04
1.00 52.83 52.82 3.60 46.70 46.70
1.10 52.72 52.71 3.70 46.35 46.35
1.20 52.59 52.58 3.80 46.00 45.99
1.30 52.46 52.45 3.90 45.63 45.63
1.40 52.31 52.30 4.00 45.26 45.26
1.50 52.16 52.15 4.10 44.89 44.88
1.60 51.99 51.98 4.20 44.50 44.50
1.70 51.81 51.81 4.30 44.11 44.11
1.80 51.63 51.62 4.40 43.72 43.71
1.90 51.43 51.42 4.50 43.32 43.31
2.00 51.22 51.22 4.60 42.92 42.91
2.10 51.01 51.00 4.70 42.51 42.50
2.20 50.78 50.78 4.80 42.09 42.09
2.30 50.55 50.54 4.90 41.67 41.67
2.40 50.30 50.30 5.00 41.25 41.24
2.50 50.05 50.04

Movie 4: Animasjon av eksepelet med bruk av tre θ-skjemaene samt analytisk


øsning. mov-ch5/sphere.mp4
Chapter 8

Convection problems and


hyperbolic PDEs

8.1 The advection equation


The classical advection equation is very often used as an example of a hyperbolic partial
differential equation which illustrates many features of convection problems, while still being
linear:
∂u ∂u
+ a0 =0 (8.1)
∂t ∂x
Another convenient feature of the model equation (8.1) is that is has an analytical solution:

u = u0 f (x − a0 t) (8.2)
and represents a wave propagating with a constant velocity a0 with unchanged shape. When
a0 > 0, the wave propagates in the positive x-direction, whereas for a0 < 0, the wave propagates
in the negative x-direction.
Equation (8.1) may serve as a model-equation for a compressible fluid, e.g if u denote
pressure it represents a pressure wave propagating with the velocity a0 . The advection equation
may also be used to model the propgation of pressure or flow in a compliant pipe, such as a
blood vessel.
To allow for generalization we will also when appropriate write (8.1) on the following form:

∂u ∂F
+ =0 (8.3)
∂t ∂x
where for the linear advection equation F (u) = a0 u.

8.1.1 Forward in time central in space discretization


We may discretize (8.1) with a forward difference in time and a central difference in space,
normally abberviated as the FTCS-scheme:

∂u un+1
j − un
j ∂u un n
j+1 − uj−1
≈ , ≈
∂t ∆t ∂x 2∆x
and we may substitute the approximations (8.1.1) into the advection equation (8.1) to yield:
C n
un+1 = un
j − (u − un
j−1 ) (8.4)
j
2 j+1

301
CHAPTER 8. HYPERBOLIC PDES 302

For convenience we have introduced the non-dimensional Courant-Friedrich-Lewy number (or


CFL-number for short):
∆t
C = a0 (8.5)
∆x
The scheme in (8.4) is first order in time and second order in space (i.e. (O(∆t) + O(∆x2 ))),
and explicit in time as can bee seen both from Figure 8.1 and (8.4).

n+1

j-1 j j+1

Figure 8.1: Illustration of the first order in time central in space scheme.

We will try to solve model equation (8.1) with the scheme (8.4) and initial conditions
illustrated in Fig (8.2) with the mathematical representation:
u(x, 0) = 1 for x < 0.5
u(x, 0) = 0 for x > 0.5

1.0

0.0 0.5 1.0 x

Figure 8.2: Initial values for the advection equaution (8.1).

Solutions for three CFL-numbers: C=0.25, 0.5 and 1.0 are illustrated in Figure 8.3. Large
oscillations are observed for all values of the CFL-number, even though they seem to be sligtly
reduced for smaller C-values,; thus we have indications of an unstable scheme. As a first
approach observe that the coefficient for un j+1 in (8.4) always will be negative, and thus the
criterion of positive coefficients (PC-criterion) may not be satisfied for any value of C.
Marit 40: Har ikke endret figuren
However, as we know that the PC-criterion may be too strict in some cases, we proceed
with a von Neumann analysis by introducing the numerical amplification factor Gn for the
CHAPTER 8. HYPERBOLIC PDES 303

C = 1.0
4

u
0

-2

-4
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1

2.5

2 C = 0.5

u1.5
1

0.5

-0.5

-1
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1

C = 0.25
1.5

u
1

0.5

0
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
x

Figure 8.3: Computed solutions with the (8.4). Dotted line: analytical solution,
solid line: computed soultion.

error Ejn in the numerical scheme to be analyzed

un n n
j → Ej = G · e
i·βxj
(8.6)
Substitution of (8.6) into (8.4) yields:
C 
Gn+1 ei·β·xj = Gn ei·β·xj − Gn ei·βxj+1 − Gn ei·βxj−1
2
which after division with Gn ei·β·xj and introduction of the simplified notation δ = β · h yields:
C i·βh 
G=1− e − e−i·βh = 1 − i · C sin(δ)
2
where the trigonometric relations:
2 cos(x) = eix + e−ix (8.7)
ix −ix
i · 2 sin(x) = e −e (8.8)
x 2
cos(x) = 1 − 2 sin ( ) (8.9)
2
CHAPTER 8. HYPERBOLIC PDES 304

have been introduced for convenience. Finally, we get the following expression for the
numerical ampliciation factor:
p
|G| = 1 + C 2 sin2 (δ) ≥ 1 for all C and δ
and concequently the FTCS-scheme is unconditionally unstable for the advection equation
and is thus not a viable scheme. Even a very small value of C will not suffice to dampe the
oscillations.

8.1.2 Upwind schemes


Oppstrømsdifferanser (upstream differences) kalles også motvind-differanser (upwind dif-
ferences). Numerisk mener vi bakoverdifferanser i forhold til strømretningen. Medstrøms
(downstream) eller medvind (downwind) blir da foroverdifferanser i forhold til strømretningen.
Oppstrømsdifferanser anvendes utelukkende på de konvektive leddene, dvs.: de leddene som
utfører transporten; aldri på diffusjonsleddene. Fig. 8.4 viser betydningen av begrepet anvendt
på adveksjonsligning en. Et slikt skjema kalles et enveis-skjema.

a0

n+1

j-1 j

Figure 8.4: Caption goes here.

Oppstrømsdifferanse for det konvektive leddet:


n
uj − uj−1n
∂u
= + O(∆x) (8.10)
∂x ∆x
a0 ∆t
(8.10) innsatt i (8.1) med foroverdifferanser for ∂u
∂t
og med C = ∆x

un+1
j = un n n n n
j − C · (uj − uj−1 ) = (1 − C)uj + C · uj−1 (8.11)
(8.11) har nøyaktighet O∆t) + O(∆x)
CHAPTER 8. HYPERBOLIC PDES 305

Setter vi C = 1 inn i (8.11), får vi un+1


j = un
j−1 som er den eksakte løsningen av
∂u
∂t
+ a0 ∂u
∂x
= 0 . ( Se avsnitt 5.2) For C < 1 blir bølgefronten "smurt" utover, noe som
indikerer at skjemaet inneholder numerisk viskositet for disse verdiene av C. ( Vi kommer
tilbake til begrepet "numerisk viskositet" senere.) Beregningen i fig.reffig:65 indikerer at
skjemaet ihvertfall er stabilt for C ≤ 1 . PK- kriteriet viser at skjemaet er stabilt for C ≤ 1 .
La oss bruke von Neumann kriteriet for å se om stabilitetsintervallet strekker seg til høyere
verdier av C. Innsatt i (8.11) fra (7.42) i kap. 7:

Gn+1 ei·β·xj = (1 − C) · Gn ei·β·xj + C · Gn ei·β·xj−1


som dividert med Gn ei·β·xj gir:

G = (1 − C) + C · e−i·β·h = 1 − C + C · (cos(δ) − i · sin(δ)) = 1 + C · (cos(δ) − 1) − i · C · sin(δ)

p p
|G| = [1 + C cos(δ − 1)]2 + C 2 sin2 (δ) = 1 − 2C(1 − cos(δ)) · (1 − C) (8.12)
Stabilitetskriteriet |G| ≤ 1 gir følgende betingelse for C:

1 − 2C · (1 − cos(δ)) · (1 − C) ≤ 1 ⇒ C · (1 − cos(δ)) · (1 − C) ≥ 0
eller

δ
 
C · sin2 (1 − C) ≥ 0
2
Stabilitetsintervall:

0<C≤1 (8.13)
(8.13) gjelder også når vi setter C = |a0 | · ∆t/∆x . Alle stabile, eksplisitte 2-nivå skjema
for løsning av adveksjonsligning en har begrensninger på Courant-tallet .
Marit 58: Har ikke endret figur
CHAPTER 8. HYPERBOLIC PDES 306

1.5

C = 1.0
1

u
0.5

-0.5
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1

1.5
C = 0.5

1 C = 0.5

u
0.5

-0.5
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1

1.5

C = 0.25
1

u
0.5

-0.5
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1

Figure 8.5: Caption goes here.


CHAPTER 8. HYPERBOLIC PDES 307

8.2 The modified differential equation


I avsnitt 7.6 Taylor-utviklet vi noen differanseskjema for å finne trunkerings-feilen samt å
undersøke konsistensen av skjemaene. Vi skal nå vise at vi kan bruke slike rekkeutviklinger til
også å si noe om stabiliteten. I hovedsak vil vi konsentrere oss om adveksjonsligning
Ser først på FTCS-skjemaet i avsnitt 6.2:

un+1
j − un
j un n
j+1 − uj−1
+ a0 =0 (8.14)
k 2h
Innsatt i (8.14) fra rekkeutviklingene i (??), kap. 7:
( )
i n i n
1 a0
h 2
h
k h2 h3
u + kut + 2
utt + · · · − un
j + u + hux + u
2 xx
+ u
6 xxx
+ · · ·
k 2h
j j

i n
a0
h
h2 h3
− u − hux + 2 uxx − 6 uxxx + · · · = 0
2h
j

Ordnet:

∂u ∂u k ∂2u a0 h2 ∂ 3 u
+ a0 =− 2
− + ··· (8.15)
∂t ∂x 2 ∂t 6 ∂x3
2
∂u
Vi bruker nå differensialligningen ∂t
+ a0 ∂u
∂x
= 0 til å transformere leddet − k2 ∂ u
∂t2
til å
uttrykke derivasjon m.h.p. x.
Differensialligningen gir:

∂u ∂u
= −a0 (8.16)
∂t ∂x
Deriverer (8.16) m.h.p. t:

∂2u ∂2u
2
= −a0
∂t ∂t∂x
Deretter deriveres (8.16) m.h.p. x:

∂2u ∂2u ∂2u ∂2u


= −a0 2 → −a0 = a20 2
∂t∂x ∂x ∂t∂x ∂x
slik at vi totalt får:

∂2u ∂2u
2
= a20 2 (8.17)
∂t ∂x
(8.17) innsatt i (8.15):

∂u ∂u ka2 ∂ 2 u a0 h2 ∂ 3 u
+ a0 =− 0 − + ···
∂t ∂x 2 ∂x2 6 ∂x3
som ved innføring av Courant-tallet gir:
C = ah
0k

∂u ∂u Cha20 ∂ 2 u a0 h2 ∂ 3 u
+ a0 =− − + ··· (8.18)
∂t ∂x 2 ∂x2 6 ∂x3
(8.18) viser tydelig hvorfor skjemaet i (8.14) er ustabilt. I strømningsmekanikken kalles
ofte koeffisienten νN = − Cha2
0
kalles den numeriske viskositeten analogt med den virkelige
2
viskositeten i ligningen ∂u ∂t
= ν ∂∂xu
2 . Når vi bruker skjemaet i (8.14), gir dette den samme
effekten som å løse diffusjonsligningen
2
∂u
∂t
= ν ∂∂xu2 med negativ viskositet Helt sikkert ustabilt. (8.18) forklarer også hvorfor
oscillasjonene i fig. 8.3 avtar med minkende C. Ligning (8.18) kalles den modifiserte ligningen
for det gitte skjemaet og den tilhørende differensial-ligningen.
CHAPTER 8. HYPERBOLIC PDES 308

Forsøker nå samme prosedyre på oppstrømskjemaet i avsnitt 8.1.2. Skjemaet skrevet på


basisform:

un+1
j − un
j (un n
j − uj−1 )
+ a0 =0 (8.19)
k h
Innsatt fra rekkeutviklingene i(??) og ordnet:

∂u ∂u k ∂2u a0 h ∂ 2 u
= a0 =− 2
+ + ··· (8.20)
∂t ∂x 2 ∂t 2 ∂x2
Da differensialligningen er den samme, får vi fra (8.17):
∂2u 2 a0 k
∂t2
= a20 ∂∂xu2 som innsatt i (8.19) sammen med gir C = h :

∂u ∂u a0 h ∂2u
+ a0 = (1 − C) 2 + · · · (8.21)
∂t ∂x 2 ∂x
a0 h
Koeffisienten νN = 2 (1 − C) gir nå den numeriske viskositeten.
For C > 1 blir dette leddet negativt, og differanseligningen er ustabil. Nødvendig betingelse
for stabilitet blir derfor C ≤ 1 som er i overenstemmelse med tidligere resultater. Legg merke
til at i dette tilfellet vil øke med minkende C. Dette betyr at en bratt front blir "smurt" utover
når C blir liten, noe som tydelig framgår av fig. 8.5.
Bemerkninger: Ved utledningen av både lign. (8.18) og (8.21) har vi brukt differensial-
2 2
ligningen til å finne relasjonen ∂∂t2u = a20 ∂∂xu2 . Problemet er at differanseligningen generelt ikke
tilfredstiller differensialligningen. Det betyr at vi istedenfor å derivere differensialligningen,
må derivere henholdsvis lign.(8.15) og (8.20) . Denne framgangsmåten, som er adskillig mer
arbeidskrevende, må benyttes i det generelle tilfellet. For adveksjonsligning en blir det første
leddet som skal omformes, korrekt når vi bruker differensialligningen. Dette stemmer også
for mer kompliserte transportligninger uten diffusjonsledd. Symbolske program som Maple
kommer her til sin rett. Nedenfor er det vist et Maple-program som gir lign. (8.18) med
korreksjon.
> restart:
> EQ:= (u(x,t+k)-u(x,t))/k + a*(u(x+h,t)-u(x-h,t))/(2*h):
> EQT:= mtaylor(EQ,[h,k]):
> MDE:=EQT:
> ELIM:=proc(i::integer,j::integer)
local DE,uxt,UXT:
global EQT,MDE:
DE:=convert(diff(EQT,x$i,t$j-1,D):
uxt:=convert(diff(u(x,t),x$i,t$j),D):
UXT:=solve(DE = 0,uxt):
subs(uxt = UXT,MDE):
end:
> MDE:=ELIM(0,2):
> MDE:=ELIM(1,1):
> MDE:=ELIM(0,3):
> MDE:=ELIM(1,2):
> MDE:=ELIM(2,1):
> # Substitute the Courant number C = a*k/h
> MDE:=expand(subs(k=C*h/a,MDE)):
> u2x:=convert(diff(u(x,t),x$2),D):
> u3x:=convert(diff(u(x,t),x$3),D):
> collect(MDE,[u2x,u3x]):
> RHSMDE:=-coeff(MDE,u2x)*convert(u2x,diff)
-coeff(MDE,u3x)*convert(u3x,diff);
   
∂2 ∂2
RHSMDE:= − 21 Cha ∂x2
u(x, t) − 1
6
ah2 + 13 C 2 h2 a ∂x2
u(x, t)

Legg merke til at vi her har fått med leddet 13 C 2 h2 a som mangler i (8.18). Teknikken
med den modifiserte ligningen kan også brukes på ikke-lineære differensialligninger. Det kan
CHAPTER 8. HYPERBOLIC PDES 309

vises at metoden har forbindelse med von Neumanns metode. Både i Hirsch [11] og Anderson
[23] finnes den modifiserte ligningen for de mest brukte differanseskjemaene.

8.3 Errors due to diffusion and dispersion


We have previously seen that the numerical amplification factor G is complex, i.e. it has a real
part Gr and a imaginary part Gi . Being a complex number G may be represented in the two
traditional ways:
G = Gr + i · Gi = |G| · e−iφ (8.22)
where the latter is normally referred to as the polar form which provides a means to
express G by the amplitude (or absolute value) |G| and the phase φ.
−Gi
p  
|G| = G2r + G2i , φ = arctan (8.23)
Gr
I section 7.4 we introduced the diffusion/dissipation error εD (dissipasjonsfeilen) as:

|G|
εD = (8.24)
|Ga |
where |Ga | is the amplituden of analytical amplification factor Ga , i.e. we have no dissipative
error when εD = 1 .
For problems and models related with convection we also need to consider the error related
with timing or phase, and introduce a measure for this kind error as the dispersion error εφ :

φ
εφ = (8.25)
φa

where φa is the phase for the analytical amplification factor. And again εφ = 1 corresponds
to no dispersion error. Note for parabolic problems with φa = 0 , it is common to use εφ = φ.

8.3.1 Example: Advection equation


∂u ∂u
+ a0 =0
∂t ∂x
I avsnitt 5.6 brukte vi

u(x, t) = ei(βx−ωt) som gav ω = a0 β , β er et bølgetall. (8.26)


Med notasjonen ovenfor får vi

u(x, t) = ei(βx−ωt) = e−i·φa , φa = ωt − βx (8.27)


Fra lign. (7.39) i avsnitt 7.4:

u(xj , tn+1 ) ei(βxj −ωtn+1 )


Ga = = i(βx −ωt ) = exp[i(βxj − ωtn+1 ) − i(βxj − ωtn )] = exp(−iω · ∆t)
u(xj , tn ) e j n

hvor vi har satt inn fra (8.27). Dermed blir |Ga | = 1 → εD = |G| .
Derav:

∆t
φa = ω · ∆t = a0 β · ∆t = a0 β · ∆x = C · δ (8.28)
∆x
C er Courant-tallet og δ = β · ∆x som vanlig.
Fra (8.28) får vi også:

φa
a0 = (8.29)
β · ∆t
CHAPTER 8. HYPERBOLIC PDES 310

Analogt med (8.29) kan vi definere en numerisk forplantningshastighet anum :

φ
anum = (8.30)
β · ∆t
Dispersjonsfeilen i (8.25) kan da skrives:
anum
εφ = (8.31)
a0
Når dispersjonsfeilen er større enn 1, betyr dette at den numeriske hastigheten er større
enn den fysiske. Den numerisk beregnede løsningen vil da synes å bevege seg hurtigere enn
den eksakte. For εφ < 1 vil derimot den numerisk beregnede løsningen synes å bevege seg
langsommere enn den eksakte.
La oss se nærmere på oppstrømskjemaet samt Lax-Wendroff metode.

8.3.2 Example: Diffusion and dispersion errors for the up-


winding schemes
Fra lign. (8.12), avsnitt 8.1.2:

G = 1 + C · (cos(δ) − 1) − i · C sin(δ) = Gr + i · Gi (8.32)


som innsatt i (8.23) og (8.25) gir:
p
εD = |G| = [1 + C · (cos(δ) − 1)]2 + [C sin(δ)]2
p (8.33)
= 1 − 4C(1 − C) sin2 ( 2δ )
φ 1 C sin(δ)
h i
εφ = = arctan (8.34)
φa Cδ 1 − C(1 − cos(δ))
Figur 8.6 på neste side viser (8.33) og (8.34) som funksjon av δ for tre forskjellige verdier
av Courant-tallet C. Vi ser at εD minker sterkt med økende frekvens, noe som betyr at den
numeriske amplituden blir mye mindre enn den eksakte når vi bruker mange tidskritt. Dette
gjelder selv for C = 0.8 . Husk her at amplitudeforholdet ette n tidskritt blir |G|η . (Se også
fig. 8.5). Skjemaet egner seg derfor dårlig for generelt bruk selv om det er stabilt.
For C = 0.5 har vi ingen dispersjonsfeil. For C < 0.5 blir εφ < 1 som betyr at den
numeriske hastigheten er mindre enn den fysiske hastigheten a0 .
For C > 0.5 blir εφ > 1 som betyr at den numeriske hastigheten er størst.

8.3.3 Example: Diffusion and disperision errors for Lax-


Wendroff schemes
Fra lign. (8.47),

G = 1 + C 2 · (cos(δ) − 1) − i · C sin(δ) = Gr + i · Gi (8.35)


som innsatt i (8.23) og (8.25) gir:
p
εD = |G| = [1 + C 2 · (cos(δ) − 1)]2 + (C sin(δ))2
q  (8.36)
δ
= 1 − 4C 2 (1 − C 2 ) sin4 2

φ 1 Csin(δ)
h i
εφ = = arctan (8.37)
φa Cδ 1 + C 2 (cos(δ) − 1)
Figur 8.7 og 8.8 viser (8.36) og (8.37) som funksjon av δ for forskjellige verdier av Courant-
tallet C. Området hvor εD er nær 1 er større på fig. 8.7 enn for oppstrømskjemaet, fig. ??.
Dette viser forskjellen på en første ordens metode og en 2. ordens metode. Fig. ?? viser εφ er
CHAPTER 8. HYPERBOLIC PDES 311

1.2 1.4

1.2
1.0

1.0
0.8

0.8
|G|

<G
0.6
0.6

0.4
CFL = 0.25 0.4
CFL = 0.5
0.2
CFL = 0.8 0.2
CFL = 1.0
0.0 0.0
0 20 40 60 80 100 120 140 160 180
[deg]

Figure 8.6: Diffusion error εD (left y-axis) and dispersion error εφ (right y-axis)
for the upwind scheme as a function of frequency for the upwind scheme. The
dotted lines of εφ correspond to same CFL-numbers as solid lines of εD with the
same color.

stort sett er mindre enn 1, slik at den numeriske hastigheten er lavere enn den fysiske. Det
er dette som er årsaken til oscillasjonene for eksempel i 5. Von Neumann-kriteriet garanterer
at |G| ≤ 1 , men utfører ingen test på fasehastigheten, slik at feil i fasehastigheten i dette
tilfellet gir en amplitude som er større enn 1. Husk at PK-kriteriet sikrer at det ikke oppstår
voksende oscillasjoner. Derfor blir ikke PK-kriteriet oppfylt for Lax-Wendroffs metode anvendt
på adveksjonsligningen. Vi kan da forlange at våre skjema skal tilfredstille PK-kriteriet for å
hindre oscillasjoner. Slik skjema kalles monotone skjema. Dessverre er slike skjema anvendt
på konvektive ligninger bare av første orden.
Marit 40: Har ikke endret figuren
CHAPTER 8. HYPERBOLIC PDES 312

1.2 1.4

1.2
1.0

1.0
0.8

0.8
|G|

<G
0.6
0.6

0.4
CFL = 0.25 0.4
CFL = 0.5
0.2
CFL = 0.8 0.2
CFL = 1.0
0.0 0.0
0 20 40 60 80 100 120 140 160 180
[deg]

Figure 8.7: Diffusion error εD (left y-axis) and dispersion error εφ (right y-axis)
as a function of frequency for the Lax-Wendroff scheme. The dotted lines of εφ
correspond to same CFL-numbers as solid lines of εD with the same color.
Amplitude |G| som funksjon av C og δ

0.8

0.6

0.4

0.2

0
0
0.5
1 1
1.5 0.8
0.6
δ(rad.) 2
0.4
2.5
0.2 C
3
0

Figure 8.8: Diffusion error εD as a function of frequency and Courant-number


for the Lax-Wendroff scheme.
CHAPTER 8. HYPERBOLIC PDES 313

8.4 The Lax-Friedrich Scheme


Lax-Friedrichs scheme is an explicit, first order scheme, using forward difference in time
and central difference in space. However, the scheme is stabilized by averaging un
j over the
neighbour cells in the in the temporal approximation:

un+1
j − 21 (un n
j+1 + uj−1 )
n
Fj+1 n
− Fj−1
=− (8.38)
∆t 2∆x
The Lax-Friedrich scheme is the obtained by isolation un+1
j at the right hand side:

1 n ∆t
un+1 = (u + un
j−1 ) −
n
(F n − Fj−1 ) (8.39)
j
2 j+1 2∆x j+1
By assuming a linear flux F = a0 u it may be shown that the Lax-Friedrich scheme takes
the form:
1 C n
un+1 = (un + un
j−1 ) − (u − unj−1 ) (8.40)
j
2 j+1 2 j+1
where we have introduced the CFL-number as given by (8.5) and have the simple python-
implementation:
def lax_friedrich(u):
u[1:-1] = (u[:-2] +u[2:])/2.0 - c*(u[2:] - u[:-2])/2.0
return u[1:-1]
whereas a more generic flux implementation is implemented as:
def lax_friedrich_Flux(u):
u[1:-1] = (u[:-2] +u[2:])/2.0 - dt*(F(u[2:])-F(u[:-2]))/(2.0*dx)
return u[1:-1]

8.5 Lax-Wendroff Schemes


These schemes were proposed in 1960 by P.D. Lax and B. Wendroff [17] for solving, approxi-
mately, systems of hyperbolic conservation laws on the generic form given in (8.3).
A large class of numerical methods for solving (8.3) are the so-called conservative methods:

∆t 
un+1
j = un
j + Fj−1/2 − Fj+1/2 (8.41)
∆x

Linear advection. The Lax–Wendroff method belongs to the class of conservative


schemes (8.3) and can be derived in various ways. For simplicity, we will derive the method by
using a simple model equation for (8.3), namely the linear advection equation with F (u) = a u
as in (8.1), where a is a constant propagation velocity. The Lax-Wendroff outset is a Taylor
approximation of un+1
j :
n n
∂u (∆t) ∂ 2 u
un+1
j = un
j + ∆t + + ··· (8.42)
∂t 2 ∂t2
j j

From the differential equation (8.3) we get by differentiation


n n n n
∂u ∂u ∂ 2 u ∂2u
= −a0 and 2
= a20 2 (8.43)
∂t ∂x ∂t ∂x
j j j j

Before substitution of (8.43) in the Taylor expansion (8.42) we approximate the spatial
derivatives by central differences:
n n
∂u un n
j+1 − uj−1 ∂ 2 u un n n
j+1 − 2uj + uj−1
≈ and ≈ (8.44)
∂x (2∆x) ∂x2 (∆x)2
j j
CHAPTER 8. HYPERBOLIC PDES 314

and then the Lax-Wendroff scheme follows by substitution:


C  C2 n 
un+1
j = un
j − un n
j+1 − uj−1 + uj+1 − 2un n
j + uj−1 (8.45)
2 2
with the local truncation error Tjn :
 n
1 ∂3u ∂3u
Tjn = · (∆t)2 3 + a0 (∆x)2 3 = O[(∆t)2 , (∆x)2 ] (8.46)
6 ∂t ∂x
j

The resulting difference equation in (8.45) may also be formulated as:


C C
un+1
j = (1 + C)un 2 n
j−1 + (1 − C )uj − (1 − C)un
j+1 (8.47)
2 2
The explicit Lax-Wendroff stenticl is illustrated in Figure 8.9

un+1
j

n+1

j-1 j j+1

Figure 8.9: Schematic of the Lax-Wendroff scheme.

An example of how to implement the Lax-Wendroff scheme is given as follows:


def lax_wendroff(u):
u[1:-1] = c/2.0*(1+c)*u[:-2] + (1-c**2)*u[1:-1] - c/2.0*(1-c)*u[2:]
return u[1:-1]

8.5.1 Lax-Wendroff for non-linear systems of hyperbolic


PDEs
For non-linear equations (8.3) the Lax–Wendroff method is no longer unique and naturally
various methods have been suggested. The challenge for a non-linear F (u) is that the
substitution of temporal derivatives with spatial derivatives (as we did in (8.43)) is not
straightforward and unique.

Ricthmyer Scheme. One of the earliest extensions of the scheme is the Richtmyer
two-step Lax–Wendroff method, which is on the conservative form (8.41) with the numerical
fluxes computed as follows:

n+1/2 1  1 ∆t n 
uj+1/2 = un n
j + uj+1 +
n
Fj − Fj+1 (8.48)
2 2 ∆x
n+1/2
Fj+1/2 = F (uj+1/2 ) (8.49)
CHAPTER 8. HYPERBOLIC PDES 315

Lax-Wendroff two step. A Lax-Wendroff two step method is outlined in the following.
In the first step u(x, t) is evaluated at half time steps n + 1/2 and half grid points j + 1/2.
In the second step values at the next time step n + 1 are calculated using the data for n and
n + 1/2.
First step:
n+1/2 1  ∆t 
uj+1/2 = un n
j+1 + uj − F (un n
j+1 ) − F (uj ) (8.50)
2 2∆x
n+1/2 1  ∆t 
uj−1/2 = un n
j + uj−1 − F (un n
j ) − F (uj−1 ) (8.51)
2 2∆x
Second step:
∆t
 
n+1/2 n+1/2
un+1
j = un
j − F (uj+1/2 ) − F (uj−1/2 ) (8.52)
∆x
Notice that for a linear flux F = a0 u, the two-step Lax-Wendroff method ((8.51) and
(8.52)) may be shown to reduce to the one-step Lax-Wendroff method outlined in (8.45) or
(8.47).

MacCormack Scheme. A simpler and popular extension/variant of Lax-Wendroff


schemes like in the previous section, is the MacCormack scheme [18]:

∆t
upj = un

j + Fjn − Fj+1
n
∆x
(8.53)
1 p
 1 ∆t p
Fj−1 − Fjp

un+1
j = un
j + uj +
2 2 ∆x
where we have introduced the convention Fjp = F (upj ).
Note that in the predictor step we employ the conservative formula (8.41) for a time
n
∆t with forward differencing, i.e. . Fj+1/2 = Fj+1 = F (un j+1 ). The corrector step may be
p

interpreted as using (8.41) for a time ∆t/2 with initial condition 12 un
j + uj+1 and backward
differencing.
Another MacCormack scheme may be obtained by reversing the predictor and corrector
steps. Note that the MacCormack scheme (8.53) is not written in conservative form (8.41).
However, it easy to express the scheme in conservative form by expressing the flux in (8.41) as:
1
Fjp + Fj+1
m n

Fj+1 = (8.54)
2
For a linear flux F (u) = a0 u, one may show that the MacCormack scheme in (8.53)
reduces to a two-step scheme:

upj = un n n

j + C uj − uj+1 (8.55)
1 p C
upj−1 − uj p
 
un+1
j = un
j + uj + (8.56)
2 2
and substitution of (8.55) into (8.56) shows that the MacCormack scheme is identical to
the Lax-Wendroff scheme (8.47) for the linear advection flux. A python implementation is
given by:
def macCormack(u):
up = u.copy()
up[:-1] = u[:-1] - c*(u[1:]-u[:-1])
u[1:] = .5*(u[1:]+up[1:] - c*(up[1:]-up[:-1]))
return u[1:-1]

# Constants and parameters


a = 1.0 # wave speed
CHAPTER 8. HYPERBOLIC PDES 316

tmin, tmax = 0.0, 1.0 # start and stop time of simulation


xmin, xmax = 0.0, 2.0 # start and end of spatial domain
Nx = 80 # number of spatial points
c = 0.9 # courant number, need c<=1 for stability

8.5.2 Code example for various schemes for the advection


equation
A complete example showing how a range of hyperbolic schemes are implemented and applied
to a particular example:
# src-ch6/advection_schemes.py

import numpy as np
from matplotlib import animation
from scipy import interpolate
from numpy import where
from math import sin

import matplotlib; matplotlib.use(’Qt4Agg’)


import matplotlib.pylab as plt
plt.get_current_fig_manager().window.raise_()

LNWDT=2; FNT=15
plt.rcParams[’lines.linewidth’] = LNWDT; plt.rcParams[’font.size’] = FNT

init_func=1 # Select stair case function (0) or sin^2 function (1)

# function defining the initial condition


if (init_func==0):
def f(x):
"""Assigning a value of 1.0 for values less than 0.1"""
f = np.zeros_like(x)
f[np.where(x <= 0.1)] = 1.0
return f
elif(init_func==1):
def f(x):
"""A smooth sin^2 function between x_left and x_right"""
f = np.zeros_like(x)
x_left = 0.25
x_right = 0.75
xm = (x_right-x_left)/2.0
f = where((x>x_left) & (x<x_right), np.sin(np.pi*(x-x_left)/(x_right-x_left))**4,f)
return f
def ftbs(u): # forward time backward space
u[1:-1] = (1-c)*u[1:-1] + c*u[:-2]
return u[1:-1]

# Lax-Wendroff
def lax_wendroff(u):
u[1:-1] = c/2.0*(1+c)*u[:-2] + (1-c**2)*u[1:-1] - c/2.0*(1-c)*u[2:]
return u[1:-1]

# Lax-Friedrich Flux formulation


def lax_friedrich_Flux(u):
u[1:-1] = (u[:-2] +u[2:])/2.0 - dt*(F(u[2:])-F(u[:-2]))/(2.0*dx)
return u[1:-1]
CHAPTER 8. HYPERBOLIC PDES 317

# Lax-Friedrich Advection
def lax_friedrich(u):
u[1:-1] = (u[:-2] +u[2:])/2.0 - c*(u[2:] - u[:-2])/2.0
return u[1:-1]

# macCormack for advection quation


def macCormack(u):
up = u.copy()
up[:-1] = u[:-1] - c*(u[1:]-u[:-1])
u[1:] = .5*(u[1:]+up[1:] - c*(up[1:]-up[:-1]))
return u[1:-1]

# Constants and parameters


a = 1.0 # wave speed
tmin, tmax = 0.0, 1.0 # start and stop time of simulation
xmin, xmax = 0.0, 2.0 # start and end of spatial domain
Nx = 80 # number of spatial points
c = 0.9 # courant number, need c<=1 for stability

# Discretize
x = np.linspace(xmin, xmax, Nx+1) # discretization of space
dx = float((xmax-xmin)/Nx) # spatial step size
dt = c/a*dx # stable time step calculated from stability requirement
Nt = int((tmax-tmin)/dt) # number of time steps
time = np.linspace(tmin, tmax, Nt) # discretization of time
# solve from tmin to tmax

solvers = [ftbs,lax_wendroff,lax_friedrich,macCormack]
#solvers = [ftbs,lax_wendroff,macCormack]
#solvers = [ftbs,lax_wendroff]
#solvers = [ftbs]

u_solutions=np.zeros((len(solvers),len(time),len(x)))
uanalytical = np.zeros((len(time), len(x))) # holds the analytical solution

for k, solver in enumerate(solvers): # Solve for all solvers in list


u = f(x)
un = np.zeros((len(time), len(x))) # holds the numerical solution
for i, t in enumerate(time[1:]):

if k==0:
uanalytical[i,:] = f(x-a*t) # compute analytical solution for this time step
u_bc = interpolate.interp1d(x[-2:], u[-2:]) # interplate at right bndry

u[1:-1] = solver(u[:]) # calculate numerical solution of interior


u[-1] = u_bc(x[-1] - a*dt) # interpolate along a characteristic to find the boundary value

un[i,:] = u[:] # storing the solution for plotting

u_solutions[k,:,:] = un
CHAPTER 8. HYPERBOLIC PDES 318

### Animation
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(xmin,xmax), ylim=(np.min(un), np.max(un)*1.1))

lines=[] # list for plot lines for solvers and analytical solutions
legends=[] # list for legends for solvers and analytical solutions

for solver in solvers:


line, = ax.plot([], [])
lines.append(line)
legends.append(solver.func_name)

line, = ax.plot([], []) #add extra plot line for analytical solution
lines.append(line)
legends.append(’Analytical’)
plt.xlabel(’x-coordinate [-]’)
plt.ylabel(’Amplitude [-]’)
plt.legend(legends, loc=3, frameon=False)

# initialization function: plot the background of each frame


def init():
for line in lines:
line.set_data([], [])
return lines,

# animation function. This is called sequentially


def animate(i):
for k, line in enumerate(lines):
if (k==0):
line.set_data(x, un[i,:])
else:
line.set_data(x, uanalytical[i,:])
return lines,
def animate_alt(i):
for k, line in enumerate(lines):
if (k==len(lines)-1):
line.set_data(x, uanalytical[i,:])
else:
line.set_data(x, u_solutions[k,i,:])
return lines,

# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate_alt, init_func=init, frames=Nt, interval=100, blit=False)

plt.show()
Movie 5: Result from code example above using a step function as the initial
value. mov-ch6/step.mp4
Movie 6: Result from code example above using a sine squared function as the
initial value mov-ch6/sine.mp4
CHAPTER 8. HYPERBOLIC PDES 319

8.6 Order analysis on various schemes for the


advection equation
The schemes  presented have different theoretical
 order; ftbs: O (∆x, ∆t), Lax-Friedrich:
O ∆x2 , ∆t , Lax-Wendroff : O ∆x2 , ∆t2 , MacCormack: O ∆x2 , ∆t2 . For the linear
advection equation the MacCormack and Lax-Wendroff schemes are identical, and we will thus
only consider Lax-Wendroff in this section. Assuming the wavespeed a0 is not very big, nor
very small we will have ∆t = O (∆x), because of the cfl constraint condition. Thus for the
advection schemes the discretization error  will be of order min(p, q). Where p is the spatial
order, and q the temporal order. Thus we could say that ftbs, and Lax-Friedrich are both first
order, and Lax-Wendroff is of second order. In order to determine the observed (dominating)
order of accuracy of our schemes we could adapt the same procedure outlined in Example 2.7.1,
where we determined the observed order of accuracy of ODEschemes. For the schemes solving
the Advection equation the discretization error will be a combination of ∆x and ∆t, however
since ∆t = O (∆x), we may still assume the following expression for the discretization error:
 ≈ Chp (8.57)
where h is either ∆x or ∆t, and p is the dominating order. Further we can calculate the
discretization error, observed for our schemes by successively refining h with a ratio r, keeping
the cfl-number constant. Thus refining ∆x and ∆t with the same ratio r. Now dividing n−1
by n and taking the log on both sides and rearranging lead to the following expression for the
observed order of accuracy:
n−1 
log n

n−1

p= = logr
log (r) n
To determine the observed discretization error we will use the root mean square error of all
our discrete soultions:
v
u N
u1 X 2
E=t fˆ − f
N
i=1

where N is the number of sampling points, fˆ is the numerical-, and f is the analytical solution.
A code example performing this test on selected advections schemes, is showed below. As can
be seen in Figure 8.10, the Lax-Wendroff scheme quickly converge to it’s theoretical order,
whereas the ftbs and Lax Friedrich scheme converges to their theoretical order more slowly.
def test_convergence_MES():
from numpy import log
from math import sqrt
global c, dt, dx, a

# Change default values on plots


LNWDT=2; FNT=13
plt.rcParams[’lines.linewidth’] = LNWDT; plt.rcParams[’font.size’] = FNT

a = 1.0 # wave speed


tmin, tmax = 0.0, 1 # start and stop time of simulation
xmin, xmax = 0.0, 2.0 # start and end of spatial domain
Nx = 160 # number of spatial points
c = 0.8 # courant number, need c<=1 for stability

# Discretize
x = np.linspace(xmin, xmax, Nx + 1) # discretization of space
dx = float((xmax-xmin)/Nx) # spatial step size
dt = c/a*dx # stable time step calculated from stability requirement
time = np.arange(tmin, tmax + dt, dt) # discretization of time
CHAPTER 8. HYPERBOLIC PDES 320

−1


2
−2

¢
f-f
¡
−3 ftbs

N
1
µq
lax_friedrich
−4

log10
lax_wendroff
−5
160320 640 1280 2560
Nx

2
log2( n-1
n
)

1, 2 2, 3 3, 4 4, 5
( n-1, n)

Figure 8.10: The root mean square error E for the various advection schemes
as a function of the number of spatial nodes (top), and corresponding observed
convergence rates (bottom).

init_funcs = [init_step, init_sine4] # Select stair case function (0) or sin^4 function (1)
f = init_funcs[1]
solvers = [ftbs, lax_friedrich, lax_wendroff]

errorDict = {} # empty dictionary to be filled in with lists of errors


orderDict = {}

for solver in solvers:


errorDict[solver.func_name] = [] # for each solver(key) assign it with value=[], an empt
orderDict[solver.func_name] = []

hx = [] # empty list of spatial step-length


ht = [] # empty list of temporal step-length

Ntds = 5 # number of grid/dt refinements


# iterate Ntds times:
for n in range(Ntds):
hx.append(dx)
ht.append(dt)

for k, solver in enumerate(solvers): # Solve for all solvers in list


u = f(x) # initial value of u is init_func(x)
error = 0
samplePoints = 0

for i, t in enumerate(time[1:]):
u_bc = interpolate.interp1d(x[-2:], u[-2:]) # interplate at right bndry
u[1:-1] = solver(u[:]) # calculate numerical solution of interior
u[-1] = u_bc(x[-1] - a*dt) # interpolate along a characteristic to find the bound

error += np.sum((u - f(x-a*t))**2) # add error from this timestep


samplePoints += len(u)

error = sqrt(error/samplePoints) # calculate rms-error


errorDict[solver.func_name].append(error)
CHAPTER 8. HYPERBOLIC PDES 321

if n>0:
previousError = errorDict[solver.func_name][n-1]
orderDict[solver.func_name].append(log(previousError/error)/log(2))
print " finished iteration {0} of {1}, dx = {2}, dt = {3}, tsample = {4}".format(n+1, Ntd
# refine grid and dt:
Nx *= 2
x = np.linspace(xmin, xmax, Nx+1) # new x-array, twice as big as the previous
dx = float((xmax-xmin)/Nx) # new spatial step size, half the value of the previous
dt = c/a*dx # new stable time step
time = np.arange(tmin, tmax + dt, dt) # discretization of time
# Plot error-values and corresponding order-estimates:
fig , axarr = plt.subplots(2, 1, squeeze=False)
lstyle = [’b’, ’r’, ’g’, ’m’]
legendList = []
N = Nx/2**(Ntds + 1)
N_list = [N*2**i for i in range(1, Ntds+1)]
N_list = np.asarray(N_list)

epsilonN = [i for i in range(1, Ntds)]


epsilonlist = [’$\epsilon_{0} , \epsilon_{1}$’.format(str(i), str(i+1)) for i in range(1, Ntd

for k, solver in enumerate(solvers):


axarr[0][0].plot(N_list, np.log10(np.asarray(errorDict[solver.func_name])),lstyle[k])
axarr[1][0].plot(epsilonN, orderDict[solver.func_name],lstyle[k])
legendList.append(solver.func_name)

axarr[1][0].axhline(1.0, xmin=0, xmax=Ntds-2, linestyle=’:’, color=’k’)


axarr[1][0].axhline(2.0, xmin=0, xmax=Ntds-2, linestyle=’:’, color=’k’)

8.6.1 Separating spatial and temporal discretization error


The test performed in the previous example verify the dominating order of accuracy of the
advection schemes. However in order to verify our implementations of the various schemes
we would like to ensure that both the observed temporal- and spatial order are close to the
theoretical orders. The expression for the discretization error in (8.57) is a simplification of
the more general expression
 ≈ Cx hpx + Ct hqt (8.58)
where Cx , and Ct are constants, hx and ht are the spatial- and temporal step lengths and p
and q are the spatial- and temporal orders respectively. We are interested in confirming that p
is close to the theoretical spatial order of the scheme, and that q is close to the theoretical
temporal order of the scheme. The method of doing this is not necessarily straight forward,
especially since ht and hx are coupled through the cfl-constraint condition. In chapter one we
showed that we were able to verify C and p in the case of only one step-length dependency
(time or space), by solving two nonlinear equations for two unknowns using a Newton-Rhapson
solver. To expand this method would now involve solving four nonlinear algebraic equations
for the four unknowns Cx , Ct , p, q. However since it is unlikely that the observed discretization
error match the expression in (8.58) exactly, we now sugest a method based on optimization
and curve-fitting. From the previous code example we calculated the root mean square error
E(hx , ht ) of the schemes by succecively refining hx and ht by a ratio r. We now assume that
E is related to Cx , Ct , p, q as in (8.58). In other words we would like to find the parameters
Cx , Ct , p, q, so that the difference between our caluclated errors E(hx, ht), and the function
CHAPTER 8. HYPERBOLIC PDES 322

 (hx , ht ; Cx , p, Ct , q) = Cx hpx + Ct hqt is as small as possible. This may be done by minimizing


the sum (S) of squared residuals of E and :
N
X
S= ri2 , ri = Ei −  (hx , ht ; Cx , p, Ct , q)i
i=1

The python module scipy.optimize has many methods for parameter optimization and curve-
fitting. In the code example below we use scipy.optimize.curve_fit which fits a function
"f(x;params)" to a set of data "y-data" using a Levenberg-Marquardt algorithmwith a least
square minimization criteria. In the code example below we start by loading the calculated root
mean square errors E (hx , ht ) of the schemes from "advection_scheme_errors.txt", which
where calculated in the same manner as in the previous example. As can be seen by Figure 8.10
the ftbs, and Lax Friedriech scheme takes a while before they are in their asymptotic range
(area where they converge at a constant rate). In "advection_scheme_errors.txt" we have
computed E (hx , ht ) up to Nx = 89120 in which all schemes should be close to their asymptotic
range. This procedure is demonstrated in the code example below in which the following
expressions for the errors are obtained:
f tbs →  = 1.3 h0.98
x + 6.5 h0.98
t (8.59)
laxF riedrich →  = −1484 h1.9 1.0
x + 26 ht (8.60)
laxW endrof f →  = −148 h2.0
x + 364. h2.0
t (8.61)
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from sympy import symbols, lambdify, latex

def optimize_error_cxct(errorList, hxList,


htList, p=1.0, q=1.0):
""" Function that optimimze the values Cx and Ct in the expression
E = epsilon = Cx hx^p + Ct ht^q, assuming p and q are known,
using scipy’s optimization tool curve_fit

Args:
errorList(array): array of calculated numerical discretization errors E
hxList(array): array of spatial step lengths corresponding to errorList
htList(array): array of temporal step lengths corresponding to errorList
p (Optional[float]): spatial order. Assumed to be equal to theoretical value
q (Optional[float]): temporal order. Assumed to be equal to theoretical value
Returns:
Cx0(float): the optimized values of Cx
Ct0(float): the optimized values of Ct
"""
def func(h, Cx, Ct):
""" function to be matched with ydata:
The function has to be on the form func(x, parameter1, parameter2,...,parametern)
where where x is the independent variable(s), and parameter1-n are the parameters to be o
"""
return Cx*h[0]**p + Ct*h[1]**q

x0 = np.array([1,2]) # initial guessed values for Cx and Ct


xdata = np.array([hxList, htList])# independent variables
ydata = errorList # data to be matched with expression in func
Cx0, Ct0 = curve_fit(func, xdata, ydata, x0)[0] # call scipy optimization tool curvefit

return Cx0, Ct0


CHAPTER 8. HYPERBOLIC PDES 323

def optimize_error(errorList, hxList, htList,


Cx0, p0, Ct0, q0):
""" Function that optimimze the values Cx, p Ct and q in the expression
E = epsilon = Cx hx^p + Ct ht^q, assuming p and q are known,
using scipy’s optimization tool curve_fit

Args:
errorList(array): array of calculated numerical discretization errors E
hxList(array): array of spatial step lengths corresponding to errorList
htList(array): array of temporal step lengths corresponding to errorList
Cx0 (float): initial guessed value of Cx
p (float): initial guessed value of p
Ct0 (float): initial guessed value of Ct
q (float): initial guessed value of q

Returns:
Cx(float): the optimized values of Cx
p (float): the optimized values of p
Ct(float): the optimized values of Ct
q (float): the optimized values of q
"""

def func(h, gx, p, gt, q):


""" function to be matched with ydata:
The function has to be on the form func(x, parameter1, parameter2,...,parametern)
where where x is the independent variable(s), and parameter1-n are the parameters to be o
"""
return gx*h[0]**p + gt*h[1]**q

x0 = np.array([Cx0, p0, Ct0, q0]) # initial guessed values for Cx, p, Ct and q
xdata = np.array([hxList, htList]) # independent variables
ydata = errorList # data to be matched with expression in func

gx, p, gt, q = curve_fit(func, xdata, ydata, x0)[0] # call scipy optimization tool curvefit
gx, p, gt, q = round(gx,2), round(p, 2), round(gt,2), round(q, 2)

return gx, p, gt, q

# Program starts here:

# empty lists, to be filled in with values from ’advection_scheme_errors.txt’


hxList = []
htList = []

E_ftbs = []
E_lax_friedrich = []
E_lax_wendroff = []

lineNumber = 1
with open(’advection_scheme_errors.txt’, ’r’) as FILENAME:
""" Open advection_scheme_errors.txt for reading.
structure of file:
hx ht E_ftbs E_lax_friedrich E_lax_wendroff

with the first line containing these headers, and the next lines containing
the corresponding values.
"""
CHAPTER 8. HYPERBOLIC PDES 324

# iterate all lines in FILENAME:


for line in FILENAME:
if lineNumber ==1:
# skip first line which contain headers
lineNumber += 1
else:
lineList = line.split() # sort each line in a list: lineList = [hx, ht, E_ftbs, E_lax_fri

# add values from this line to the lists


hxList.append(float(lineList[0]))
htList.append(float(lineList[1]))

E_ftbs.append(float(lineList[2]))
E_lax_friedrich.append(float(lineList[3]))
E_lax_wendroff.append(float(lineList[4]))

lineNumber += 1
FILENAME.close()

# convert lists to numpy arrays:


hxList = np.asarray(hxList)
htList = np.asarray(htList)

E_ftbs = np.asarray(E_ftbs)
E_lax_friedrich = np.asarray(E_lax_friedrich)
E_lax_wendroff = np.asarray(E_lax_wendroff)

ErrorList = [E_ftbs, E_lax_friedrich, E_lax_wendroff]


schemes = [’ftbs’, ’lax_friedrich’, ’lax_wendroff’]
p_theoretical = [1, 2, 2] # theoretical spatial orders
q_theoretical = [1, 1, 2] # theoretical temporal orders
h_x, h_t = symbols(’h_x h_t’)

XtickList = [i for i in range(1, len(hxList)+1)]


Xticknames = [r’$(h_x , h_t)_{0}$’.format(str(i)) for i in range(1, len(hxList)+1)]
lstyle = [’b’, ’r’, ’g’, ’m’]
legendList = []

# Optimize Cx, p, Ct, q for every scheme


for k, E in enumerate(ErrorList):

# optimize using only last 5 values of E and h for the scheme, as the first values may be outside

Cx0, Ct0 = optimize_error_cxct(E[-5:], hxList[-5:], htList[-5:],


p=p_theoretical[k], q=q_theoretical[k]) # Find appropriate initial

Cx, p, Ct, q = optimize_error(E[-5:], hxList[-5:], htList[-5:],


Cx0, p_theoretical[k], Ct0, q_theoretical[k]) # Optimize for all pa

# create sympy expressions of e, ex and et:


errorExpr = Cx*h_x**p + Ct*h_t**q

print errorExpr
errorExprHx = Cx*h_x**p
errorExprHt = Ct*h_t**q
CHAPTER 8. HYPERBOLIC PDES 325

# convert e, ex and et to python functions:


errorFunc = lambdify([h_x, h_t], errorExpr)
errorFuncHx = lambdify([h_x], errorExprHx)
errorFuncHt = lambdify([h_t], errorExprHt)

# plotting:
fig , ax = plt.subplots(2, 1, squeeze=False)

ax[0][0].plot(XtickList, np.log10(E),lstyle[k])
ax[0][0].plot(XtickList, np.log10(errorFunc(hxList, htList)),lstyle[k] + ’--’)

ax[1][0].plot(XtickList[-5:], E[-5:],lstyle[k])
ax[1][0].plot(XtickList[-5:], errorFunc(hxList, htList)[-5:],lstyle[k] + ’--’)
ax[1][0].plot(XtickList[-5:], errorFuncHx(hxList[-5:]), lstyle[k] + ’-.’)
ax[1][0].plot(XtickList[-5:], errorFuncHt(htList[-5:]),lstyle[k] + ’:’)

−1.0
ftbs −1.0
lax_friedrich −1
lax_wendroff
=E =E =E
−1.5 −1.5 −2
0.98
=6.45 hx + 1.32 ht0.98 =-1483.49 hx
1.87
+ 25.85 ht1.0 =364.05 hx
2.0
+ -148.59 ht2.0
−2.0 −3
−2.0
log10( )

log10( )

log10( )
−2.5 −4
−2.5
−3.0 −5

−3.5 −3.0 −6

−4.0 −3.5 −7
1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
(hx ,ht )n (hx ,ht )n (hx ,ht )n

0.0035 0.00006
=E 0.008 =E 0.00005 =E
0.0030
0.98
0.0025 =6.45 hx + 1.32 ht0.98 0.006 =-1483.49 hx
1.87
+ 25.85 ht1.0 0.00004 =364.05 hx
2.0
+ -148.59 ht2.0
0.98 1.87 0.00003 2.0
0.0020 =6.45 hx =-1483.49 hx =364.05 hx
0.98 0.004 1.0 0.00002 2.0
0.0015 =1.32 ht =25.85 ht =-148.59 ht
0.00001
0.0010 0.002
0.00000
0.0005 −0.00001
0.000
0.0000 −0.00002
5 6 7 8 9 5 6 7 8 9 5 6 7 8 9
(hx ,ht )n (hx ,ht )n (hx ,ht )n

Figure 8.11: Optimized error expressions for all schemes. Test using doconce
combine images

Marit 40: Har ikke endret figuren


CHAPTER 8. HYPERBOLIC PDES 326

Figure 8.12: The solutions at time t=T=1 for different grids corresponding
to the code-example above. A sin4 wave with period T = 0.4 travelling with
wavespeed a = 1. The solutions were calculated with a cfl-number of 0.8

8.7 Flux limiters


Looking at the previous examples and especially Figure 8.12 we clearly see the difference
between first and second order schemes. Using a first order scheme require a very high resolution
(and/or a cfl number close to one) in order to get a satisfying solution. What characterizes the
first order schemes is that they are highly diffusive (loss of amplitude). Unless the resolution
is very high or the cfl-number is very close to one, the first order solutions will lose amplitude
as time passes. This is evident in the animation (6). (To see how the different schemes behave
with different combinations of CFL-number, and frequencies try the sliders app located in the
git repo in chapter 6.Fredrik 61: add a link or something? ) However if the solution contain
big gradients or discontinuities, the second order schemes fail, and introduce nonphysical
oscillations due to their dispersive nature. In other words the second order schemes give a
much higher accuracy on smooth solutions, than the first order schemes, whereas the first
order schemes behave better in regions containing sharp gradients or discontinuities. First
order upwind methods are said to behave monotonically varying in regions where the solution
should be monotone (cite:Second Order Positive Schemes by means of Flux Limiters for the
Advection Equation.pdf). Figure 8.13 show the behavior of the different advection schemes in a
solution containing discontinuities; oscillations arises near discontinuities for the Lax-Wendroff
scheme, independent of the resolution. The dissipative nature of the first order schemes are
evident in solutions with "low" resolution.
Marit 40: Har ikke endret figuren
The idea of Flux limiters is to combine the best features of high and low order schemes.
In general a flux limiter method can be obtained by combining any low order flux Fl , and high
order flux Fh . Further it is convenient/required to write the schemes in the so the so-called
conservative form as in (8.41) repeated here for convenience

∆t 
un+1
j = un
j + Fj−1/2 − Fj+1/2 (8.62)
∆x
Fredrik 63: do we need clarifying more about conservative methods and Fluxes calculated
at midpoints and halftime?

The general flux limiter method solves (8.62) with the following definitions of the fluxes
Fi−1/2 and Fi+1/2
CHAPTER 8. HYPERBOLIC PDES 327

Figure 8.13: Effect of refining grid on a solution containing discontinuities; a


square box moving with wave speed a=1. Solutions are showed at t=1, using a
cfl-number of 0.8.

 
Fj−1/2 = Fl (j − 1/2) + φ(rj−1/2 ) Fh (j − 1/2) − Fl (j − 1/2) (8.63)
 
Fj+1/2 = Fl (j + 1/2) + φ(rj+1/2 ) Fh (j + 1/2) − Fl (j + 1/2) (8.64)

where φ(r) is the limiter function, and r is a measure of the smoothness of the solution.
The limiter function φ is designed to be equal to one in regions where the solution is smooth,
in which F reduces to Fh , and a pure high order scheme. In regions where the solution is not
smooth (i.e. in regions containing sharp gradients and discontinuities ) φ is designed to be
equal to zero, in which F reduces to Fl , and a pure low order scheme. As a measure of the
smoothness, r is commonly taken to be the ratio of consecutive gradients
uj−1 − uj−2 uj − uj−1
rj−1/2 = , rj+1/2 = (8.65)
uj − uj−1 uj+1 − uj
In regions where the solution is constant (zero gradients), some special treatment of r is
needed to avoid division by zero. However the choice of this treatment is not important since
in regions where the solution is not changing, using a high or low order method is irrelevant.

Lax-Wendroff limiters. The Lax-Wendroff scheme for the advection equation may be
written in the form of (8.62) by defining the Lax-Wendroff Flux FLW as:

1 ∆t
 
 
FLW (j − 1/2) = FLW (uj−1 , uj ) = a uj−1 + a 1− a uj − uj−1 (8.66)
2 ∆x
1 ∆t
  
FLW (j + 1/2) = FLW (uj , uj+1 ) = a uj + a 1 − a uj+1 − uj (8.67)
2 ∆x
which may be showed to be the Lax-Wendroff two step method condensed to a one
∆t
step method as outlined in (8.5.1). Notice the term ∆x a = c. Now the Lax-Wendroff
flux assumes  that of an
 upwind flux (a uj−1 or a uj ) with an additional anti diffusive term
( 12 a (1 − c) uj − uj−1 for FLW (j − 1/2)). A flux limited version of the Lax-Wendroff scheme
could thus be obtained by adding a limiter function φ to the second term
CHAPTER 8. HYPERBOLIC PDES 328

1  
F (j − 1/2) = a uj−1 + φ rj−1/2 a (1 − c) uj − uj−1 (8.68)
2
1  
F (j + 1/2) = a uj + φ rj+1/2 a (1 − c) uj+1 − uj (8.69)
2
When φ = 0 the scheme is the upwind scheme, and when φ = 1 the scheme is the Lax-
Wendroff scheme. Many different limiter functions have been proposed, the optimal function
however is dependent on the solution. Sweby (Fredrik 64: Cite sweby ) showed that in order
for the Flux limiting scheme to possess the wanted properties of a low order scheme; TVD,
or monotonically varying in regions where the solution should be monotone, the following
equality must hold Fredrik 65: definition of TVD? more theory backing these statements?

φ(r)
 
0≤ , φ(r) ≤2 (8.70)
r
Where we require

φ(r) = 0, r ≤ 0 (8.71)
Hence for the scheme to be TVD the limiter must lie in the shaded region of Figure 8.14,
where the limiter function for the two second order schemes, Lax-Wendroff and Warming and
Beam are also plotted.

3
Warming and Beam, =r

Lax-Wendroff, =1
1

0 1 2 3
r

Figure 8.14: TVD region for flux limiters (shaded), and the limiters for the
second order schemes; Lax-Wendroff, and Warming and Beam
For the scheme Fredrik 66: maybe add only using uj−2 , uj−1 uj uj+1 to be second order
accurate whenever possible, the limiter must be an arithmetic average of the limiter of Lax-
Wendroff (φ = 1) and that of Warming and Beam(φ = r) Fredrik 67: need citing(Sweby),
and maybe more clearification . With this extra constraint a second order TVD limiter must
lie in the shaded region of Figure 8.15
Note that φ(0) = 0, meaning that second order accuracy must be lost at extrema. All
schemes pass through the point φ(1) = 1, which is a general requirement for second order
schemes. Many limiters that pass the above constraints have been proposed. Here we will only
consider a few:

Superbee : φ(r) = max (0, min(1, 2r), min(2, r)) (8.72)


r + |r|
V an − Leer : φ(r) = (8.73)
1 + |r|
minmod : φ(r) = minmod(1, r) (8.74)
CHAPTER 8. HYPERBOLIC PDES 329

0 1 2 3
r

Figure 8.15: Second orderTVD region for flux limiters; sweby diagram Fredrik
68: cite sweby?

where minmod of two arguments is defined as


(
a if a · b > 0 and |a| > |b|
minmod(a, b) = b if a · b > 0 and |b| > |a| > 0 (8.75)
0 if a·b<0
The limiters given in (8.72) -(8.74) are showed in Figure 8.16. Superbee traverses the upper
bound of the second order TVD region, whereas minmod traverses the lower bound of the
region. Keeping in mind that in our scheme, φ regulates the anti diffusive flux, superbee is
thus the least diffusive scheme of these.

Superbee Van-Leer

Min-Mod

0 1 2 3
r

Figure 8.16: Second order TVD limiters

In addition we will consider the two base cases:


upwind : φ(r) = 0 (8.76)
Lax − W endrof f : φ(r) = 1 (8.77)
in which upwind, is TVD, but first order, and Lax-Wendroff is second order, but not TVD.
CHAPTER 8. HYPERBOLIC PDES 330

Example of Flux limiter schemes on a solution with continuos and


discontinuous sections. All of the above schemes have been implemented in the
python class Fluxlimiters, and a code example of their application on a solution containing
combination of box, and sine moving with wavespeed a=1, may be found in the python script
advection-schemes-flux-limiters.py. The result may be seen in the video (7)
Movie 7: The effect of Flux limiting schemes on solutions containing continuos
and discontinuous sections mov-ch6/flux_limiter.mp4

1.0
0.8
0.6
u

0.4
0.2
0.0
0.0 0.2 0.4 0.6 0.8 1.0
x
3.0
2.5
2.0
1.5
r

1.0
0.5
0.0
0.0 0.2 0.4 0.6 0.8 1.0
u
2.0
1.5 superbee
1.0
0.5
van-Leer
0.0 minmod
0.0 0.2 0.4 0.6 0.8 1.0
r

Figure 8.17: Relationship between u and smoothness measure r, and different


limiters φ, on continuos and discontinuous solutions

8.8 Example: Burgers equation


The 1D Burgers equation is a simple (if not the simplest) non-linear hyperbolic equation
commonly used as a model equation to illustrate various numerical schemes for non-linear
hyperbolic differential equations. It is normally prestented as:
∂u ∂u
+u =0 (8.78)
∂t ∂x
To enable us to present schemes for a greater variety of hyperbolic differenctial equations
and to better handle shocks (i.e discontinuities in the solution), we will present our model
equation on conservative form:
 
∂u ∂ u2
+ =0 (8.79)
∂t ∂x 2

and by introducing a flux function


u2
F (u) = (8.80)
2
the conservative formulation of the Burgers equation may be represented by a generic
transport equation:

∂u ∂F (u)
+ =0 (8.81)
∂t ∂x
CHAPTER 8. HYPERBOLIC PDES 331

8.8.1 Upwind Scheme


The upwind scheme for the general conservation equation take the form:

∆t 
un+1
j = un
j − F (un n
j+1 ) − F (uj ) (8.82)
∆x
0
where we have assumed a forward propagating wave (a(u) = F (u) > 0, i.e. u > 0 for the
∂F (u) 1

burger equation). In the opposite case ∂x will be approximated by ∆x F (un n
j ) − F (uj−1 )

8.8.2 Lax-Friedrich
The Lax-Friedrich conservation equation take the form as given in (8.38), repeated here for
convinience:
n
Fj+1 n
− Fj−1
∆t n
un+1
j = (uj+1 + un
j−1 ) − (8.83)
2 2∆x

8.8.3 Lax-Wendroff
As outlined in ((8.5.1)), the general Lax-Wendroff two step method takes the form as given in
(8.51) and (8.52) repeated here for convinience:
First step:
n+1/2 1  ∆t 
uj+1/2 = un n
j+1 + uj − F (un n
j+1 ) − F (uj ) (8.84)
2 2∆x
n+1/2 1  ∆t 
uj−1/2 = un n
j + uj−1 − F (un n
j ) − F (uj−1 ) (8.85)
2 2∆x

∆t
 
n+1/2 n+1/2
un+1
j = un
j − F (uj+1/2 ) − F (uj−1/2 ) (8.86)
∆x
In the previous section ((8.5.1)) we showed how the two step Lax-Wendroff method could
be condensed to a one step method. The same procedure may be applied to a the general
transport equation given by (8.81). However for the nonlinear case (8.43) no longer holds.
This may be overcome be rewriting (8.43):

n n n n  n
∂F (u)
∂u ∂F ∂ 2 u ∂ 2 F (u) ∂ ∂t

=− and = − =−
∂t ∂x ∂t2 ∂t∂x ∂x
j j  nj j n j
∂F (u) ∂u (8.87)
∂ ∂u ∂t
∂ a(u) ∂F
∂x

=− =
∂x ∂x
j j

Now inserting into the Taylor series we get


∂F

∂F (u) ∆t2 ∂ a(u) ∂x
= un+1
j− ∆t un
j + (8.88)
∂x 2 ∂x
and further we may obtain the general Lax-Wendroff one-step method for a generic
transport equation

∆t ∆t2
h i
un+1
j = un
j − (Fj+1 − Fj−1 )+ aj+1/2 (Fj+1 − Fj )−aj−1/2 (Fj − Fj−1 ) (8.89)
2∆x 2∆x2
where a(u) is the wavespeed, or the Jacobian of F, F 0 (u), which is u for the burger equation.
As indicated a(u) has to be approximated at the indice (j + 1/2) and (j − 1/2). This may
simply be done by averaging the neighboring values:
1 
aj+1/2 = un n
j + uj+1 (8.90)
2
CHAPTER 8. HYPERBOLIC PDES 332

for the burger equation. Another method that assure conservation is to use the following
approximation ( n
Fj+1 −Fjn
un −un
if uj+1 6= uj
aj+1/2 = j+1 j (8.91)
uj otherwise

8.8.4 MacCormack
The MacCormack scheme was discussed in ((8.5.1)) and is given by (8.94) repeated her for
convinience
∆t
upj = un

j +
n
Fjn − Fj+1 (8.92)
∆x
1 p
 1 ∆t p
Fj−1 − Fjp

un+1
j = un
j + uj + (8.93)
2 2 ∆x
(8.94)

8.8.5 Method of Manufactured solution


For the Advection equation we were able to verify our schemes by comparing with exact
solutions, using MES. For the burger equation it is not easy to find an analytical solution, so in
order to verify our schemes we use the MMS approach. However this requires that our schemes
can handle source terms. The new equation to solve is thus the modified burgers equation

∂u ∂u
+u =Q (8.95)
∂t ∂x
In this chapter we will consider source terms that are a function of x and t only. The
basic approach to adding source terms to our schemes is to simply add a term Qn i to our
discrete equations. The schemes mentioned above with possibility to handle source terms are
summarized in Table (8.8.5).
Name of Scheme Scheme order
Upwind un+1
j = un
j −
∆t
∆x
+ ∆tQn j 1
n n
Fj+1 −Fj−1
Lax-Friedrichs un+1
j = ∆t2
(un n
j+1 + uj−1 ) − 2∆x
+ ∆tQn
j 1
n+1/2 1
 ∆t
 ∆t n
uj+1/2 = 2 uj+1 + uj − 2∆x F (uj+1 ) − F (un
n n n
j ) + 2 Qj+1/2
n+1/2
 
Lax-Wendroff uj−1/2 = 2 uj + uj−1 − 2∆x F (uj ) − F (uj−1 ) + ∆t
1 n n ∆t n n
2
Qn
j−1/2
2
 
n+1/2 n+1/2
un+1
j = un − ∆t
j ∆x
F (uj+1/2
) − F (u j−1/2
) + ∆tQ n
j

upj = un n + ∆tQn+1/2
∆t n

macCormack j − ∆x
Fj+1 − F j j 2
p p p ∆t n+1/2
 
un+1
j = 12 un 1 ∆t
j + uj − 2 ∆x Fj − Fj−1 + 2 Qj

Examples on how to implement these schemes are given below, where we have used
RHS(x, t) instead of Q for the source term:

ftbs or upwind:
def ftbs(u, t):
"""method that solves u(n+1), for the scalar conservation equation with source term:
du/dt + dF/dx = RHS,
where F = 0.5u^2 for the burger equation
with use of the forward in time backward in space (upwind) scheme

Args:
u(array): an array containg the previous solution of u, u(n). (RHS)
t(float): an array
Returns:
u[1:-1](array): the solution of the interior nodes for the next timestep, u(n+1).
CHAPTER 8. HYPERBOLIC PDES 333

"""
u[1:-1] = u[1:-1] - (dt/dx)*(F(u[1:-1])-F(u[:-2])) + dt*RHS(t-0.5*dt, x[1:-1])
return u[1:-1]
Lax-Friedrichs:
def lax_friedrich_Flux(u, t):
"""method that solves u(n+1), for the scalar conservation equation with source term:
du/dt + dF/dx = RHS,
where F = 0.5u^2 for the burger equation
with use of the lax-friedrich scheme

Args:
u(array): an array containg the previous solution of u, u(n). (RHS)
t(float): an array
Returns:
u[1:-1](array): the solution of the interior nodes for the next timestep, u(n+1).
"""
u[1:-1] = (u[:-2] +u[2:])/2.0 - dt*(F(u[2:])-F(u[:-2]))/(2.0*dx) + dt*(RHS(t, x[:-2]) + RHS(t, x
return u[1:-1]
Lax-Wendroff-Two-step:
def Lax_W_Two_Step(u, t):
"""method that solves u(n+1), for the scalar conservation equation with source term:
du/dt + dF/dx = RHS,
where F = 0.5u^2 for the burger equation
with use of the Two-step Lax-Wendroff scheme
Args:
u(array): an array containg the previous solution of u, u(n).
t(float): time at t(n+1)
Returns:
u[1:-1](array): the solution of the interior nodes for the next timestep, u(n+1).
"""
ujm = u[:-2].copy() #u(j-1)
uj = u[1:-1].copy() #u(j)
ujp = u[2:].copy() #u(j+1)
up_m = 0.5*(ujm + uj) - 0.5*(dt/dx)*(F(uj)-F(ujm)) + 0.5*dt*RHS(t-0.5*dt, x[1:-1] - 0.5*dx) #u(n+
up_p = 0.5*(uj + ujp) - 0.5*(dt/dx)*(F(ujp)-F(uj)) + 0.5*dt*RHS(t-0.5*dt, x[1:-1] + 0.5*dx)#u(n+0

u[1:-1] = uj -(dt/dx)*(F(up_p) - F(up_m)) + dt*RHS(t-0.5*dt, x[1:-1])


return u[1:-1]
macCormack:
def macCormack(u, t):
"""method that solves u(n+1), for the scalar conservation equation with source term:
du/dt + dF/dx = RHS,
where F = 0.5u^2 for the burger equation
with use of the MacCormack scheme

Args:
u(array): an array containg the previous solution of u, u(n). (RHS)
t(float): an array
Returns:
u[1:-1](array): the solution of the interior nodes for the next timestep, u(n+1).
"""
up = u.copy()
up[:-1] = u[:-1] - (dt/dx)*(F(u[1:]) - F(u[:-1])) + dt*RHS(t-0.5*dt, x[:-1])
u[1:] = .5*(u[1:] + up[1:] - (dt/dx)*(F(up[1:]) - F(up[:-1])) + dt*RHS(t-0.5*dt, x[1:]))
return u[1:-1]
CHAPTER 8. HYPERBOLIC PDES 334

Exercise 9: Stability analysis of the Lax-Friedrich scheme


In this exercise we want to assess the stability of the Lax-Friedrich scheme for the advection
equation as formulated in (8.40).
a) Use the PC-criterion to find a sufficient condition for stability for (8.40).
b) Use the von Neumann method to find a sufficient and necessary condition for stability for
(8.40) and compare with the PC-condition
Chapter 9

Python Style Guide

PEP 8, and Google have python style guides which we generally try to follow, though we have
made some different choices in some respect.
• https://www.python.org/dev/peps/pep-0008/
• https://google-styleguide.googlecode.com/svn/trunk/pyguide.html

9.1 The conventions we use


First off we try to be compliant to the https://www.python.org/dev/peps/pep-0008/ the
summary is as follows:
• Use 4 spaces, not tabs (you can get your editor to do this automatically, and it is
recommended for coding in general).
• If your function has many inputs, list them vertically by having an extra indent or more
• We use CapitalizedWords and MixedCase mostly in our code. We capitalize the first
letter to signal that this is a class, and we keep it in lowercase if it is an instance of a
class, or a function. This allows us to easily see what we´re working with.
• We disobey the convention on function names, where PEP 8 wants them to be lowercase
and separated by underscores, we use mixedCase for functions as well. This is due to
underscore being a hassle to use.
• If you have a list of things, add list to the name. Do not use plurals. good: vesselList,
bad: vessels
• Further, as we have a project with a lot of functional files, we often use "import .... as"
method, where we have a list of abbreviations that are convenient to follow

9.2 Summary
• Have clear names and use proper namespacing in your code
• Document your code with docstrings adhering to the Goodle docstring standard. Clearly
indicate what is input and what is outout. Especially side-effects!
• Structure your code so that it is as self-explanatory as possible, and use comments
where additional clarification is useful.
• Remember that all code you write will end up being treated as a "black box" sooner or
later. So make sure that it actually works like one, with clean input-output dichotomy.

335
CHAPTER 9. PYTHON STYLE GUIDE 336

• Exceptions should crash your program, unless you have very specific reasons why it
should not.
• If you absolutely want to stop exceptions, you should not use "except", as this will catch
the system exit and keyboard interrupts. If you want catch-all use "except Exception as
e"
• You should catch, append and re-raise the exception at each level of the code, so that
an informative traceback will appear when the program dies.
• Unit Testing is desirable, and you should test the crucial behavior of each feature you
wish to push to the main project. Also, test that the code fails the way it should. Few
things are as hard to track down as code that passes wrong data onto other parts in the
program
• Keep your Unit tests. Write them well. Systematize them. Make sure they´re thorough,
independent of each other, and fast.

9.3 The code is the documentation... i.e. the


docs always lie!
Write the code as clearly as possible to what it is doing. Clear, succinct variable names and
conventions, and ideally code review.

9.4 Docstring Guide


The google docstring guide is located at Google Style Python Docstrings
Chapter 10

Sympolic computation with


SymPy

In this chapter we provide a very short introduction to SymPy customized for the applications
and examples in the current setting. For a more thorough presentation see e.g. [14].

10.1 Introduction
SymPy is a Python library for symbolic mathematics, with the ambition to offer a full-featured
computer algebra system (CAS). The library design makes SymPy ideally suited to make
symbolic mathematical computations integrated in numerical Python applications.

10.2 Basic features


The SymPy library is implemented in the Python module sympy. To avoid namespace conflicts
(e.g. with other modules like NumPy/SciPy) we propose to import the SymPy as:
import sympy

Symbols. SymPy introduces the class symbols (or Symbol) to represent mathematical
symbols as Python objects. An instance of type symbols has a set of attributes to hold the its
properties and methods to operate on those properties. Such symbols may be used to represent
and manipulate algebraic expressions. Unlike many symbolic manipulation systems, variables
in SymPy must be defined before they are used (for justification see sympy.org)
As an example, let us define a symbolic expression, representing the mathematical expres-
sion x2 + xy − y
import sympy
x, y = sympy.symbols(’x y’)
expr = x**2 + x*y -y
expr
Note that we wrote the expression as if "x" and "y" were ordinary Python variables, but
instead of being evaluated the expression remains unaltered.
To make the output look nicer we may invoke the pretty print feature of SymPy by:
sympy.init_printing(use_latex=True)
expr
The expression is now ready for algebraic manipulation:

337
CHAPTER 10. SYMPOLIC COMPUTATION WITH SYMPY 338

expr + 2
x**2 + x*y -y + 2
and
expr + y
x**2 + x*y
Note that the result of the above is not x2 + xy − y + y but rather x2 + xy, i.e. the −y and
the +y are added and found to cancel automatically by SymPy and a simplified expression is
outputted accordingly. Appart from√ rather obvious simplifications like discarding subexpression
that add up to zero (e.g. y − y or 9 = 3), most simplifications are not performed automatically
by SymPy.
expr2 = x**2 + 2*x + 1
expr3 = sympy.factor(expr2)
expr3

Matrices. Matrices in SymPy are implemented with the Matrix class and are constructed
by providing a list of row the vectors in the following manner:
sympy.init_printing(use_latex=’mathjax’)
M = sympy.Matrix([[1, -1], [2, 1], [4, 4]])
M
A matrix with symbolic elements may be constructed by:
a, b, c, d = sympy.symbols(’a b c d’)
M = sympy.Matrix([[a, b],[c, d]])
M
The matrices may naturally be manipulated like any other object in SymPy or Python.
To illustrate this we introduce another 2x2-matrix
n1, n2, n3, n4 =sympy.symbols(’n1 n2 n3 n4’)
N=sympy.Matrix([[n1, n2],[n3, n4]])
N
The two matrices may then be added, subtracted, multiplied, and inverted by the following
simple statements
M+N, M-N, M*N, M.inv()
M=sympy.Matrix([[0, a], [a, 0]])
Diagonaliztion:
L, D = M.diagonalize()
L, D

Differentiating and integrating. Consider also the parabolic function which may
describe the velocity profile for fully developed flow in a cylinder.
from sympy import integrate, diff, symbols, pi
v0, r = symbols(’v0 r’)
v = v0*(1 - r**2)
Q = integrate(2*pi*v*r, r)
Q
Q = sympy.factor(Q)
Q
newV = diff(Q, r)/(r*2*pi)
newV
sympy.simplify(newV)
R
compute cos(x)
from sympy import cos
integrate(cos(x), x)
CHAPTER 10. SYMPOLIC COMPUTATION WITH SYMPY 339

R∞
compute sin(x2 )
−∞

from sympy import sin, oo


integrate(sin(x**2), (x, -oo, oo))

sin(x)
limits. perform limx→0 x
from sympy import limit
limit(sin(x)/x, x, 0)

solving equations. solve the algebraic equation x2 − 4 = 0


from sympy import solve
solve(x**2 - 4*x, x)
solve the differential equation y 00 − y 0 = et
from sympy import dsolve, Function, Eq, exp
y = Function(’y’)
t = symbols(’t’)
diffeq = Eq(y(t).diff(t, t) - y(t), exp(t))
dsolve(diffeq, y(t))
Bibliography

[1] P.W. Bearman and J.K. Harvey. Golf ball aerodynamics. Aeronaut Q, 27(pt 2):112–122,
1976. cited By 119.
[2] William L. Briggs. A Multigrid Tutorial. SIAM, 2. edition, 2000.
[3] E. Cheney and David Kincaid. Numerical Mathematics and Computing. Cengage Learning,
4th edition, 1999.
[4] E. Cheney and David Kincaid. Numerical Mathematics and Computing 7th. Cengage
Learning, 7th edition, 2012.
[5] H. Evans. Laminar Boundary-Layer Theory. Addison-Wesley Publishing Company, 1968.
[6] J. Evett and C. Liu. 2,500 Solved Problems in Fluid Mechanics and Hydraulics. Schaum’s
Solved Problems Series. McGraw-Hill Education, 1989.
[7] C. A. J. Fletcher. Computational Techniques for Fluid Dynamics. 1. , Fundamental and
General Techniques. Springer series in computational physics. Springer, Berlin, Paris,
1991.
[8] G.E. Forsythe. Computer Methods for Mathematical Computations. Prentice-Hall, 1977.
[9] Louis A. Hageman and David M. Young. Applied Iterative Methods. Academic Press,
1981.
[10] Ernst Hairer, Syvert Paul Norsett, and Gerhard Wanner. Solving Ordinary Differential
Equations I: Nonstiff Problems, volume 1. Springer Science & Business, 2008.
[11] C. Hirsch. Numerical Computation of Internal and External Flows. Elsevier, 2007.
[12] George A. Hool and Nathan Clarke Johnson. Elements of Structural Theory-Definitions.
Handbook of Building Construction. New York. McGraw-Hill. Google Books, 1920. p.2.
[13] Hoffman J. D. Zucrow M. J. Gas Dynamics, volume I & II. John Wiley & Sons, 1976-77.
[14] Robert Johansson. Numerical Python. a Practical Techniques Approach for Industry.
Springer, 2015.
[15] C. T. Kelley. Iterative Methods for Linear and Nonlinear Equations. SIAM, 1995.
[16] Hans Petter Langtangen. A Primer on Scientific Programming With Python. Springer,
Berlin; Heidelberg; New York, fourth edition, 2011.
[17] P. D. Lax. Hyperbolic Systems of Conservation Laws and the Mathematical Theory of
Shock Waves. Society for Industrial and Applied Mathematics, 1973. Regional conference
series in applied mathematics.
[18] R. W. MacCormack. The effect of viscosity in hypervelocity impact cratering. Astronautics,
AIAA, 69:354, 1969.
[19] W. H. Press. Numerical Recipes in Fortran. the Art of Scientific Computing, volume 1 &
2. Cambridge University Press, 2. edition, 1992.
[20] Yousef Saad. Iterative Methods for Sparse Linear Systems. SIAM, 2. edition, 2003.
[21] H. Schlichting. Boundary Layer Theory. McGraw-Hill, 7th edition, 1978.

340
BIBLIOGRAPHY 341

[22] G. D. Smith. Numerical Solution of Partial Diff. Equations : Finite Difference Methods.
Oxford, 3. edition, 1985.
[23] John. C. Tannehil, Dale A. Anderson, and Richard H. Pletcher. Computational Fluid
Mechanics and Heat Transfer. Taylor & Francis, 1997.
[24] F.M. White. Viscous Fluid Flow. WCB/McGraw-Hill, 1991.
[25] F.M. White. Fluid Mechanics. McGraw-Hill series in mechanical engineering.
WCB/McGraw-Hill, 1999.
Index

Amplification factor, 74

Biot-number, 139

Diagonally dominat matrix, 137

Euler’s method, 21, 72, 75


Eulers metode, 75

Heat transfer coefficient, 138


Heun’s method, 42, 75

Implisitt, 76

Runge-Kutta, 75, 76

Thermal conductivity, 138


Trapesmetoden, 151

342

You might also like