Numerical Methods for Engineers A digital compendium Leif Rune Hellevik Department of Structural Engineering, NTNU Jan 16, 2017 Contents 1 Introduction 1.1 Check Python and LiClipse plugin . . . . . . . . . . . . . . . . . 1.2 Scientific computing with Python . . . . . . . . . . . . . . . . . . 7 7 8 2 Initial value problems for ODEs 2.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1.1 Example: A mathematical pendulum . . . . . . . . . . . . 2.1.2 n-th order linear ordinary differential equations . . . . . . 2.2 Taylor’s method . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.1 Example: Taylor’s method for the non-linear mathematical pendulum . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.2 Example: Newton’s first differential equation . . . . . . . 2.3 Reduction of Higher order Equations . . . . . . . . . . . . . . . . 2.3.1 Example: Reduction of higher order systems . . . . . . . 2.4 Differences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4.1 Example: Discretization of a diffusion term . . . . . . . . 2.5 Euler’s method . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.1 Example: Eulers method on a simple ODE . . . . . . . . 2.5.2 Example: Eulers method on the mathematical pendulum 2.5.3 Example: Generic euler implementation on the mathematical pendulum . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.4 Example: Sphere in free fall . . . . . . . . . . . . . . . . . 2.5.5 Example: Falling sphere with constant and varying drag . 2.6 Python functions with vector arguments and modules . . . . . . 2.7 How to make a Python-module and some useful programming features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.7.1 Example: Numerical error as a function of ∆t . . . . . . . 2.8 Heun’s method . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.8.1 Example: Newton’s equation . . . . . . . . . . . . . . . . 2.8.2 Example: Falling sphere with Heun’s method . . . . . . . 2.9 Generic second order Runge-Kutta method . . . . . . . . . . . . 2.10 Runge-Kutta of 4th order . . . . . . . . . . . . . . . . . . . . . . 2.10.1 Example: Falling sphere using RK4 . . . . . . . . . . . . 2.10.2 Example: Particle motion in two dimensions . . . . . . . 9 9 10 11 12 2 13 14 14 16 16 23 24 25 26 27 29 32 39 41 47 50 51 53 56 57 59 61 CONTENTS 3 2.10.3 Example: Numerical error as a function of ∆t for ODEschemes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.11 Stability of explicit RK-methods . . . . . . . . . . . . . . . . . . 2.11.1 Example: Stability of Euler’s method . . . . . . . . . . . 2.11.2 Example: Stability of Heun’s method . . . . . . . . . . . 2.11.3 Stability of higher order RK-methods . . . . . . . . . . . 2.12 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Shooting Methods 3.1 Linear equations . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Example: Couette-Poiseuille flow . . . . . . . . . . 3.1.2 Example: Simply supported beam with constant sectional area . . . . . . . . . . . . . . . . . . . . . 3.1.3 Example: Simply supported beam with varying sectional area . . . . . . . . . . . . . . . . . . . . . 3.2 Non-linear boundary value problems of ODEs . . . . . . . 3.2.1 Example: Large deflection of a cantilever . . . . . 3.3 Notes on similarity solutions . . . . . . . . . . . . . . . . . 3.3.1 Example: Freezing of a waterpipe . . . . . . . . . . 3.3.2 Example: Stokes 1. problem . . . . . . . . . . . . . 3.3.3 Example: Blasius-ligningen . . . . . . . . . . . . . 3.3.4 Example:Falkner-Skan ligningen . . . . . . . . . . 3.4 Skyting med to startbetingelser . . . . . . . . . . . . . . . 3.4.1 Lineære ligninger . . . . . . . . . . . . . . . . . . . 3.4.2 Example: Sylindrisk tank med væske . . . . . . . . 3.4.3 Eksempel på ikke-lineære ligninger . . . . . . . . . 3.5 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . cross. . . . cross. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Finite differences for ODEs 4.1 Tridiagonal systems of algebraic equations . . . . . . . . . . . . . 4.1.1 Example: Heat conduction. Heat exchanger with constant cross-section . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.2 Ribbe med variabelt tverrsnitt . . . . . . . . . . . . . . . 4.1.3 Example: Talleksempel for trapesprofilet . . . . . . . . . . 4.2 To-punktsmetode. Varmeveksler. . . . . . . . . . . . . . . . . . . 4.2.1 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.2 Example: Varmeveksler . . . . . . . . . . . . . . . . . . . 4.2.3 Example: Talleksempel . . . . . . . . . . . . . . . . . . . 4.3 Linearinsering av ikke-linære algebraiske ligninger . . . . . . . . . 4.3.1 Metoden med etterslep . . . . . . . . . . . . . . . . . . . . 4.3.2 Newton-linearisering . . . . . . . . . . . . . . . . . . . . . 4.3.3 Example: . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.4 Example: . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.5 Example: . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.6 Eksempler på stoppkriterier . . . . . . . . . . . . . . . . . 4.3.7 Ligninger på delta-form . . . . . . . . . . . . . . . . . . . 67 83 84 86 87 89 96 96 100 103 107 111 117 122 126 127 129 135 140 140 141 146 149 154 154 158 168 170 175 176 177 184 187 188 190 191 192 192 194 196 CONTENTS 4.4 4.5 4.6 4.7 4 4.3.8 Kvasilinearisering . . . . . . . . . . . . . . . . . . . . . . . 197 4.3.9 Example: . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 Løsning av Blasius ligning ved bruk av differansemetode . . . . . 199 Differential boundary conditions/von Neumann boundary conditions199 Iterative solution of ODEs . . . . . . . . . . . . . . . . . . . . . . 199 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 5 Mathematical properties of PDEs 5.1 Model equations . . . . . . . . . . . . . . . . . . . . 5.1.1 Liste over noen modell-ligninger . . . . . . . 5.2 First order partial differential equations . . . . . . . 5.3 Second order partial differenatial equations . . . . . 5.4 RANDBETINGELSER FOR 2. ORDENS PDL . . . 5.4.1 Hyberbolsk ligning . . . . . . . . . . . . . . . 5.4.2 Elliptisk ligning . . . . . . . . . . . . . . . . . 5.4.3 Parabolsk ligning . . . . . . . . . . . . . . . . 5.5 VELFORMULERT PROBLEM. OPPSUMMERING 5.6 PARTIKULÆRLØSNINGER AV LINEÆRE PDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 204 204 205 209 212 213 213 214 215 217 6 Elliptic PDEs 6.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 6.2 Differanser. Notasjon . . . . . . . . . . . . . . . . . . . . 6.2.1 Example: Discretization of the Laplace equation 6.3 Direct numerical solution . . . . . . . . . . . . . . . . . 6.3.1 von Neumann boundary conditions . . . . . . . . 6.4 Iterative methods for linear algebraic equation systems . 6.4.1 Stop criteria . . . . . . . . . . . . . . . . . . . . 6.4.2 Optimal relaksasjonsparameter . . . . . . . . . . 6.4.3 Eksempel på bruk av SOR . . . . . . . . . . . . 6.4.4 Startverdier og randbetingelser . . . . . . . . . . 6.4.5 Example: A non-linear elliptic PDE . . . . . . . 6.4.6 Convergence criteria . . . . . . . . . . . . . . . . 6.4.7 UTNYTTELSE AV SYMMETRI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 220 222 224 224 232 238 243 245 246 248 248 254 261 7 Diffusjonsproblemer 7.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 Confined, unsteady Couette flow . . . . . . . . . . . . . . . . . . 7.3 Stability: Criterion for positive coefficients. PC-criterion . . . . . 7.4 Stability analysis with von Neumann’s method . . . . . . . . . . 7.4.1 Example: Practical usage of the von Neumann condition . 7.5 Flere skjema for parabolske ligninger . . . . . . . . . . . . . . . . 7.5.1 Richardson-skjemaet (1910) . . . . . . . . . . . . . . . . . 7.5.2 Dufort-Frankel skjemaet (1953) . . . . . . . . . . . . . . . 7.5.3 Crank-Nicolson skjemaet. θ-skjemaet . . . . . . . . . . . . 7.5.4 Von Neumanns generelle stabilitetsbetingelse . . . . . . . 7.6 Trunkeringsfeil, konsistens og konvergens . . . . . . . . . . . . . . 266 266 267 272 273 276 278 278 280 281 286 287 . . . . . . . . . . CONTENTS 7.7 5 7.6.1 Trunkeringsfeil . . . . . . . . . . . . . . . . . . . . . 7.6.2 Konsistens . . . . . . . . . . . . . . . . . . . . . . . . 7.6.3 Example: Consistency of the FTCS-scheme . . . . . 7.6.4 Example: Consistency of the DuFort-Frankel scheme 7.6.5 Konvergens . . . . . . . . . . . . . . . . . . . . . . . Eksempler med radiell symmetri . . . . . . . . . . . . . . . 7.7.1 Example: Oppstart av rørstrømning . . . . . . . . . 7.7.2 Example: Avkjøling av kule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 288 288 289 289 290 292 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 9.1 The conventions we use . . . . . . . 9.2 Summary . . . . . . . . . . . . . . . 9.3 The code is the documentation... i.e. 9.4 Docstring Guide . . . . . . . . . . . . . . . the . . . . . . . . docs . . . . . . . . . . . always . . . . . . . . . . lie! . . . . . . . . . . . . . . . . . . . . 335 335 335 336 336 10 Sympolic computation with SymPy 337 10.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337 10.2 Basic features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337 Bibliography 340 CONTENTS Index 6 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 associate 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 enormously 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 and around x0 . Similarly for higher order equations. ∂f ∂y 0 are continuous in Violation of the criteria for existence and uniqueness 1 y 0 = y 3 , y(0) = 0 1 Here f = y 3 and case for ∂f ∂y . ∂f ∂y = 1 2 3y 3 . f is continuous in x = 0, but that’s not the 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 + sin(θ) = 0 2 ∂τ l dθ θ(0) = θ0 , (0) = 0 dτ (2.5) (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 m 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 θ(0) = θ0 , θ̇(0) = 0 (2.9) (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. 1 For instance the equation y 0 (x) = y 2 (x), y(0) = 1 has the solution y(x) = 1−x 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 (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): f (x) = f (x0 )+(x−x0 )·f 0 (x0 )+ θ̈(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: θ(t) ≈ θ(0) + t · θ̇(0) + t2 t3 ... t4 θ̈(0) + θ (0) + θ(4) (0) 2 6 24 (2.15) By use of the initial conditions of the ODE in (2.14) θ(0) = θ0 , θ̇(0) = 0 we get t2 t3 ... t4 θ̈ + θ (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) θ(t) ≈ θ0 + Expressions for higher order differentials evaluated at the initial point may be obtained by further differentiation of the ODE (2.14) ... (2.18) θ (t) = −θ̇(t) → θ̈(0) = −θ(0) = −θ0 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 24 2! 4! (2.19) CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 13 If we include n terms, we get 2n t4 t6 t2 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 mathematical 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 t Inserted above: θ(t) ≈ θ0 − t2 sin(θ0 ) + 24 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 2.2.2 14 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 (0) + y 000 (0) + y (4) (0) 2 6 24 y(x) ≈ x · y 0 (0) + 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 000 y (x) = y 00 + 2 + xy 00 + 2y 0 y (4) (x) = y 000 + xy 000 + 3y 00 3 → y 00 (0) = −2 → y 000 (0) = 2 → y (4) (0) = −4 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 0 00 y(0) = a0 , y (0) = b0 , y (0) = c0 (2.20) 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) ) 0 y(x0 ) = a0 , y (x0 ) = a1 , . . . , y (m−1) where y (m) ≡ dm y dxm (2.21) (x0 ) = am−1 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-2) y(xj-1) y(xj) y(x1) y(x0) h x0 h xj-2 x1 h 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+1½ yj+2 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 1 (n) n · · · + y (x0 ) · (x − x0 ) + Rn n! (2.23) The remainder Rn is given by 1 y (n+1) (ξ) · (x − x0 )n+1 (n + 1)! where ξ ∈ (x0 , x) Rn = (2.24) 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: y(xj+1 ) ≡y(xj + h) = y(xj ) + hy 0 (xj ) + ··· + h2 00 y (xj )+ 2 (2.25) hn y (n) (xj ) + Rn n! where the remainder Rn = O(hn+1 ), h → 0. From (2.25) we also get hk (−1)k y (k) (xj ) h2 00 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 − h) = y(xj ) − hy 0 (xj ) + y 0 (xj ) = y(xj+1 ) − y(xj ) + O(h) h (2.27) 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 ) + 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 0 (xj ) = y 00 (xj ) = y(xj+1 ) − 2y(xj ) + y(xj−1 ) + O(h2 ) h2 (2.29) By subtraction of (2.26) from (2.25) we get a backward difference approximation of the first order derivative at the location xj : y 0 (xj ) = y(xj+1 ) − y(xj−1 ) + O(h2 ) 2h (2.30) 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 ; truncation error O(h) h yj − yj−1 ; truncation error O(h) yj0 = h yj+1 − 2yj + yj−1 yj00 = ; truncation error O(h2 ) h2 yj+1 − yj−1 yj0 = ; truncation error O(h2 ) 2h yj0 = (2.31) (2.32) (2.33) (2.34) 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: yj+1 − yj yj − yj−1 1 yj+1 − 2yj + yj−1 00 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: yj − yj−1 1 yj+1 − yj−1 yj+1 − yj 0 yj = + · = h h 2 2h CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 20 yj+1 y yj yj-1 ½h ½h xj-1 ½h ½h 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 6 2 h 00 h3 000 0 c · yj + hyj + yj + yj (ξ) 2 6 (2.36) 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 (a + c) (2.37) 3 h 00 h 000 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 a+c=0 (2.38) CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 21 The solution to (2.38) is a=− 1 1 , b = 0 and c = 2h 2h which when inserted in (2.35) gives yj0 = yj+1 − yj−1 h2 − y 000 (ξ) 2h 6 (2.39) By comparison of (2.39) with (2.35) we see that the error term is O(hm ) = 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, 2 − h6 y 000 (ξ), 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 b + 2c = 0 2 (2.41) The solution of (2.41) is a=− 3 2 1 , b= , c=− 2h h 2h which inserted in (2.40) gives yj0 = −3yj + 4yj+1 − yj+2 h2 + y 000 (ξ) 2h 3 2 (2.42) 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 Forward differences: dyi dx dyi dx dyi dx d2 yi dx2 d2 yi dx2 = = = = = yi+1 − yi 1 + y 00 (ξ)∆x ∆x 2 −3yi + 4yi+1 − yi+2 1 + y 000 (ξ) · (∆x)2 2∆x 3 −11yi + 18yi+1 − 9yi+2 + yi+3 1 + y (4) (ξ) · (∆x)3 6∆x 4 yi − 2yi+1 + yi+2 + y 000 (ξ) · ∆x (∆x)2 2yi − 5yi+1 + 4yi+2 − yi+3 11 + y (4) (ξ) · (∆x)2 (∆x)2 12 Backward differences: dyi dx dyi dx dyi dx d2 yi dx2 d2 yi dx2 = = = = = yi − yi−1 1 + y 00 (ξ)∆x ∆x 2 3yi − 4yi−1 + yi−2 1 + y 000 (ξ) · (∆x)2 2∆x 3 11yi − 18yi−1 + 9yi−2 − yi−3 1 + y (4) (ξ) · (∆x)3 6∆x 4 yi − 2yi−1 + yi−2 000 + y (ξ) · ∆x (∆x)2 2yi − 5yi−1 + 4yi−2 − yi−3 11 + y (4) (ξ) · (∆x)2 (∆x)2 12 Central differences: dyi dx dyi dx d2 yi dx2 d2 yi dx2 d3 yi dx3 = = = = = yi+1 − yi−1 1 − y 000 (ξ)(∆x)2 2∆x 6 −yi+2 + 8yi+1 − 8yi−1 + yi−2 1 + y (5) (ξ) · (∆x)4 12∆x 30 yi+1 − 2yi + yi−1 1 − y (4) (ξ) · (∆x)2 2 (∆x) 12 −yi+2 + 16yi+1 − 30yi + 16yi−1 − yi−2 1 + y (6) (ξ) · (∆x)4 12(∆x)2 90 yi+2 − 2yi+1 + 2yi−1 − yi−2 1 + y (5) (ξ) · (∆x)2 2(∆x)3 4 22 CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 2.4.1 23 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: d dx We use central differences (recall Figure 2.3) as follows, [p(x) · u0 (x)]|i+ 21 − [p(x) · u0 (x)]|i− 21 d p(x) · u(x) ≈ dx h i 0 p(xi+ 12 ) · u (xi+ 21 ) − p(xi− 21 ) · u0 (xi− 21 ) = h Using central differences again, we get u0 (xi+ 12 ) ≈ ui+1 − ui ui − ui−1 , 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 h2 i (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 p(x1+ 12 ) ≈ 1 1 (pi+1 + pi ), p(x1− 12 ) ≈ (pi + pi−1 ) 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 ) · − p(xi ) · u0 (xi ) h ≈ h 2 (2.44) CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 24 which gives d dx p(x) · du dx 2 · [p(xi+ 21 ) · (ui+1 − ui ) − h · p(xi ) · u0 (xi )] = + error term h2 i (2.45) where h [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 error term = − u00i = 2 · [ui+1 − ui − h · u0 (xi )] h 000 − u (xi ) + O(h2 ) h2 3 (2.47) Backward Differences: We start with p(xi ) · u0 (xi ) − p(xi ) · u0 (xi− 21 ) · u0 (xi− 21 ) du d ≈ p(x) h dx dx i 2 i−1 0 p(xi ) · u (xi ) − p(xi− 21 ) ui −u h ≈ h 2 which gives d dx p(x) du dx 2 · [h · p(xi )u0 (xi ) − p(xi− 21 ) · (ui − ui−1 )] = + error term h2 i (2.48) where error term = h [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 u00i = 2.5 2 · [h · u0 (xi ) − (ui − ui−1 )] h 000 + u (xi ) + O(h2 ) h2 3 (2.50) Euler’s method The ODE is given as dy = y 0 (x) = f (x, y) dx y(x0 ) =y0 (2.51) (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) numerical solution y(x) yn+1 yn+2 y(xn+1) yn xn h∙f(xn,yn) 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 2.6 ex euler 2.4 2.2 y 2.0 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 pendulum # 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 mathematical 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.15 0 0 cos(t) euler 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 m dv 1 dv 1 = mg − mf g − mf − ρf v |v| Ak CD , dt 2 dt 2 (2.54) 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 z v= 30 dz dt d mg Figure 2.8: Falling sphere due to gravity. introduce the following abbreviations: ρ= ρf 3ρ ρ . , A = 1 + , B = (1 − ρ)g, C = ρk 2 4d (2.55) 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 1 dv = (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 CD 10 0 10 -1 10 -2 10 -1 10 0 1 10 2 10 3 10 10 Re 4 10 5 10 6 10 7 10 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 y30 = − y1 y3 (2.62) 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 dt dv = g − αv 2 dt where α= (2.65) (2.66) 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) = α r g √ v(t) = · tanh( αg · t) α r dv g The terminal velocity vt is found by = 0 which gives vt = . dt α (2.67) (2.68) CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 3 33 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 6 1 v(t) =gt · (1 − αgt2 ) 3 (2.69) (2.70) By applying the Euler scheme (2.53) on (2.65) and (2.66) zn+1 = zn + ∆t · vn vn+1 = vn + ∆t · (g − α · (2.71) 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 d = 41.0e-3 rho_f = 1.22 rho_s = 1275 nu = 1.5e-5 CD = 0.4 # # # # # # Gravity m/s^2 Diameter of the sphere Density of fluid [kg/m^3] Density of sphere [kg/m^3] Kinematical viscosity [m^2/s] 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) ze2 = euler(f2, z0, time) # compute response with constant CD using Euler’s method # 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 Velocity [m/s] 30 25 Analytical (constant CD) Euler (constant CD) Euler (varying CD) Taylor (constant CD) 20 15 10 5 0 −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 functions 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 function. 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 calculates 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) return CD # condition 8 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 condition2 condition3 condition4 condition5 condition6 condition7 condition8 = = = = = = = = Re < 0 logical_and(0 < Re, Re <= 0.5) logical_and(0.5 < Re, Re <= 100.0) logical_and(100.0 < Re, Re <= 1.0e4) logical_and(1.0e4 < Re, Re <= 3.35e5) logical_and(3.35e5 < Re, Re <= 5.0e5) logical_and(5.0e5 < Re, Re <= 8.0e6) 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 implementations of the drag function, we have collected them all in a file DragCoefficientGeneric.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 statements 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 Pythoncode 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, starting 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 cd_sphere_vector cd_sphere_auto_vector cd_sphere_py_vector execution execution execution execution time time time time = = = = 0.000312 0.000641 0.009497 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) return CD # condition 8 # 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 condition2 condition3 condition4 condition5 condition6 condition7 condition8 = = = = = = = = Re < 0 logical_and(0 < Re, Re <= 0.5) logical_and(0.5 < Re, Re <= 100.0) logical_and(100.0 < Re, Re <= 1.0e4) logical_and(1.0e4 < Re, Re <= 3.35e5) logical_and(3.35e5 < Re, Re <= 5.0e5) logical_and(5.0e5 < Re, Re <= 8.0e6) 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 # set fontsize prms fnSz = 16; font = {’size’ 47 : 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 d = 41.0e-3 rho_f = 1.22 rho_s = 1275 nu = 1.5e-5 CD = 0.4 # # # # # # Gravity m/s^2 Diameter of the sphere Density of fluid [kg/m^3] Density of sphere [kg/m^3] Kinematical viscosity [m^2/s] 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 N = 10 # end of simulation # 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: n = log2 i ≈ 1 ⇒ i+1 ≈ 0.488483620 i i+1 (2.73) 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 0 −2 log2 -error −4 −6 −8 Euler scheme: N 10 timesteps Euler scheme: N 20 timesteps Euler scheme: N 40 timesteps Euler scheme: N 80 timesteps Euler scheme: N 160 timesteps −10 −12 −14 −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 y 00 (xn , yn ) = f 0 (xn , y(xn , yn )) ≈ f (xn + h) − f (xn ) h (2.74) The Taylor series expansion (2.25) gives y(xn + h) = y(xn ) + hy 0 [xn , y(xn )] + h2 00 y [xn , y(xn )] + O(h3 ) 2 which, inserting (2.74), gives yn+1 = yn + h · [f (xn , yn ) + f (xn+1 , y(xn+1 ))] 2 (2.75) 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 ) h p yn+1 = yn + · [f (xn , yn ) + f (xn+1 , yn+1 )] 2 (2.76) (2.77) 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 yn+1 corrected slope slope f(xn+1,yn+1) y(x) ypn+1 slope f(xn,yn) 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 ) h p yn+1 = yn + · [f (xn , yn ) + f (xn+1 , yn+1 )] 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: (2.78) (2.79) (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 · erf y(x) =3 2πe · exp x 1 + (1 + x) − erf 2 2 2 h x i −x (2.81) +4 · 1 − exp x 1 + 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 y −1.0 −1.5 −2.0 −2.5 −3.0 −3.5 0.0 Heun Analytical 0.5 1.0 x 1.5 2.0 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 p vn+1 = vn + ∆t · (g − (2.82) αvn2 ) Corrector: p ) zn+1 = zn + 0.5∆t · (vn + vn+1 p 2 )2 vn+1 = vn + 0.5∆t · 2g − α[vn + (vn+1 (2.83) 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 Velocity [m/s] 30 25 20 Analytical (constant CD) Euler (constant CD) Heun (constant CD) Euler (varying CD) Heun (varying CD) 15 10 5 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 ODEschemes.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 d = 41.0e-3 rho_f = 1.22 rho_s = 1275 nu = 1.5e-5 CD = 0.4 # # # # # # Gravity m/s^2 Diameter of the sphere Density of fluid [kg/m^3] Density of sphere [kg/m^3] Kinematical viscosity [m^2/s] 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) ze2 = euler(f2, z0, time) zh = heun(f, z0, time) zh2 = heun(f2, z0, time) # compute response with constant CD using Euler’s method # compute response with varying CD using Euler’s method # compute response with constant CD using Heun’s method # 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 2.9 56 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 ) K1 = f (xn + p1 h, yn + p2 K1 h) and (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 derivatives fx ≡ ∂f ∂x and fy ≡ ∂f ∂y (2.88) 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: y 00 = df dx dy d2 y = = ∂f x + ∂f y = fx + f fy 2 dx dx dx dx (2.90) which may be used in a second order Taylor expansion of the solution of (2.1): y(xn + h) = yn + hy 0 + h2 00 y + O(h3 ) 2 (2.91) Substitution of (2.90) and (2.1) into (2.91) yields: y(xn + h) = yn + hf + h2 (fx + f fy ) + O(h3 ) 2 (2.92) 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 1 a2 p2 = 2 (2.93) 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 2 k4 = f (xn + h, yn + hk3 ) h yn+1 = yn + (k1 + 2k2 + 2k3 + k4 ) 6 (2.94) 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 1 yn 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 (k1 + 2k2 + 2k3 + k4 ) 6 h = (y2 )n + (l1 + 2l2 + 2l3 + l4 ) 6 h = (y3 )n + (m1 + 2m2 + 2m3 + m4 ) 6 (y1 )n+1 = (y1 )n + (y2 )n+1 (y3 )n+1 (2.95) (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 FallingSphereEulerHeunRK4.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 40 35 Velocity [m/s] 30 25 Analytical (constant CD) Euler (constant CD) Heun (constant CD) RK4 (constant CD) Euler (varying CD) Heun (varying CD) RK4 (varying CD) 20 15 10 5 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 d = 41.0e-3 rho_f = 1.22 rho_s = 1275 nu = 1.5e-5 CD = 0.4 # # # # # # Gravity m/s^2 Diameter of the sphere Density of fluid [kg/m^3] Density of sphere [kg/m^3] Kinematical viscosity [m^2/s] 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) 60 CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 61 z0=np.zeros(2) z0[0] = 2.0 ze = euler(f, z0, time) ze2 = euler(f2, z0, time) zh = heun(f, z0, time) zh2 = heun(f2, z0, time) zrk4 = rk4(f, z0, time) zrk4_2 = rk4(f2, z0, time) # compute response with constant CD using Euler’s method # compute response with varying CD using Euler’s method # compute response with constant CD using Heun’s method # compute response with varying CD using Heun’s method # compute response with constant CD using RK4 # 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 Fɭ v0 vr Fd ϕ m g α x 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 ρf ACD vr2 2 1 Fl = ρf ACL vr2 2 Fd = (2.97) (2.98) 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 A 2 dvx = −ρf v (CD · cos(φ) + CL sin(φ)) dt 2m r dvy A 2 = ρf v (CL · cos(φ) − CD sin(φ)) − g dt 2m r (2.99) (2.100) From the figure we have vrx vr vry sin(φ) = vr cos(φ) = 3ρ A 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 ) dt dvy = C · vr (CL · vrx − CD · vry ) − g dt With dx dt = vx and dy dt (2.101) (2.102) = vy we get a system of 1st order equations as follows, dx = vx dt dy = vy dt dvx = −C · vr (CD · vrx + CL · vry ) dt dvy = C · vr (CL · vrx − CD · vry ) − g dt (2.103) Introducing the notation x = y1 , y = y2 , vx = y3 , vy = y4 , we get dy1 dt dy2 dt dy3 dt dy4 dt = y3 = y4 = −C · vr (CD · vrx + CL · vry ) (2.104) = C · vr (CL · vrx − CD · vry ) − g Here q we have vrx = vx − vf x = y3 − vf x , vry = vy − vf y = y4 − vf y , 2 + v2 vr = vrx 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): Diameter d = 41mm, mass m = 46g which gives ρk = 6m 3 = 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 angle=15.0, smooth ball 20 y [m] 15 10 5 00 20 40 x [m] 60 80 100 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 angle=15.0, smooth ball angle=30.0, golf ball angle=25.0, golf ball angle=20.0, golf ball angle=15.0, golf ball angle=30.0, golf ball (with lift) angle=25.0, golf ball (with lift) angle=20.0, golf ball (with lift) angle=15.0, golf ball (with lift) 40 y [m] 30 20 10 00 50 100 x [m] 150 200 250 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 nu = 1.5e-5 rho_f = 1.20 rho_s = 1275 d = 41.0e-3 v0 = 50.0 vfx = 0.0 vfy = 0.0 # # # # # # # # nrpm = 3500 # no of rpm of golf ball Gravity [m/s^2] Kinematical viscosity [m^2/s] Density of fluid [kg/m^3] Density of sphere [kg/m^3] Diameter of the sphere [m] Initial velocity [m/s] x-component of fluid’s velocity y-component of fluid’s velocity # 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 , u= u0 + b t, a 6= 0 a=0 (2.106) 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: n ≈ log2 i i+1 (2.108) 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 convergence 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 element 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 Scheme order approximation 5 rk4 heun euler theoretical 4 3 2 1 0 0 192 960 480 240 120 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 downloaded 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 z0 is a vector for the the right hand side of a vector with the same solution of systems of ODEs. initial conditions, the system is represented by func which returns 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 y 0 (x) = λ · y(x) 84 (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 2.5 =1 = -2 e x 2.0 1.5 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: Ga = y(xn+1 ) = exp[λ(xn+1 − xn )] = eλh = 1 + λh + (λh)2 /2 . . . y(xn ) (2.115) 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 amplification factor G as: G= yn+1 yn (2.120) which for the current example (2.112) reduces to: G= yn+1 = 1 + λh = 1 − αh yn (2.121) 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 oscillations 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: yn+1 = yn + h 1 p · (f + fn+1 ) = 1 − αh + (αh)2 2 2 (2.128) 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); G= yn+1 1 = 1 − αh + (αh)2 yn 2 (2.129) 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: y(x) = eλx = 1 + λx + (λx)2 (λx)3 (λx)n + + ··· + + ··· 2! 3! n! (2.131) 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: G = 1 + λh + (λh)2 (λh)3 (λh)n + + ··· + , n = 1, 2, . . . , 2! 3! n! (2.132) 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: G = 1 + λh + (λh)2 (λh)3 + 2! 3! (2.134) 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 + + 2! 3! 4! which for G = 1 has the real roots: G = 1 + λh + −2.7853 < λh < 0 (2.136) (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 3 89 RK4 RK3 imaginary part of h 2 RK2 1 RK1 0 −1 −2 −3 −3 −2 −1 0 real part of h 1 2 3 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 using 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: y(x) ≈ x − x2 + x3 x4 x5 x6 − + − 3 6 30 45 (2.139) Today it is possible to give the solution on closed form with known functions as follows, √ √ h h √ x i 2 2 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 y 0.0 −0.2 −0.4 −0.6 0.0 analytical euler Newton 0.2 0.4 0.6 0.8 x 1.0 1.2 1.4 1.6 Figure 2.23: Problem 1 with 101 samplepoints between x = 0 and x = 1.5 . Exercise 2: Solitary wave A Y D 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 = 2 dX 2 D A 3 − Y D 2D (2.141) 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. A Y By using dimensionless variables: x = X D , a = D , y = A , Eq. (2.141) can be written as: 00 y (x) = a 3 y(x) 3 1 − y(x) 2 (2.142) 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 p dy √ = −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 0.86 0.84 0.82 0.0 euler, y(0.6)=0.88 heun, y(0.6)=0.8336 taylor, y(0.6)=0.8416 analytic, y(0.6)=0.8396 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 dτ 2 l (2.143) with initial conditions θ(0) = θ0 dθ (0) = θ̇0 dτ (2.144) (2.145) CHAPTER 2. INITIAL VALUE PROBLEMS FOR ODES 94 ɭ g θ θ0 m Figure 2.26: Mathematical pendulum. We introduce a dimensionless time t = pg lt such that (2.143) may be written as θ̈(t) + sin θ(t) = 0 (2.146) θ(0) = θ0 (2.147) θ̇(0) = θ̇0 (2.148) with initial conditions 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 2 (2.149) We define an energy function E(θ) from (2.149) as E(θ) = 1 [(θ̇)2 − (θ̇0 )2 ] + cos θ0 − cos θ 2 (2.150) 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 HeunLin EulerNonlin HeunNonlin 1.5 Amplitude [rad] 1.0 0.5 0.0 −0.5 −1.0 −1.5 −2.0 0 2 4 6 8 10 Dimensionless time [-] 12 14 16 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 L x 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) 96 (3.1) 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 s∗ = 1 sinh(1) (3.5) 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 , k = b s1 − s0 s1 − s0 ∗ and concequently we may find s as: ka = s∗ = φ1 s0 − φ0 s1 φ1 − φ0 (3.12) (3.13) CHAPTER 3. SHOOTING METHODS 99 which also may be presented on an incremental form as: 1 s − s0 ∗ 1 1 s = s + ∆s, ∆s = −φ · φ1 − φ0 (3.14) 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) g 0 (x) = y(x) (3.15) 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 0 1 sm 0.2 0.7 φ(sm ) -0.7650 -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 ) y 0.6 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: y(x) = y0 (x) + φ0 β − y0 (b) · y1 (x) = y0 (x) − 1 · y1 (x) y1 (b) φ +β (3.19) 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 ∂U ∂p ∂ U ∂2U ρU · =− +µ + ∂X ∂X ∂X 2 ∂Y 2 CHAPTER 3. SHOOTING METHODS 101 y U0 p(x) U X 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 dY µ dX (3.20) 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 dy 2 with corresponding boundary conditions: u = 0 for y = 0, u = 1 for y = 1 (3.21) (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) u01 (y) = −P (3.24) 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 0.8 y 0.6 P = -8 P = -4 P = -2 P=0 P=4 P=8 0.4 0.2 0.01.0 0.5 0.0 0.5 u 1.0 1.5 2.0 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 crosssectional 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 dX 2 EI 2EI with the following boundary conditions: U (−L) = U (L) = 0 (3.26) (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 B P A 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= x P P L2 , u= · U, θ2 = 2 L qL EI (3.28) which by substitution in (3.26) and (3.27) yield: 2 d2 u 2 2 (1 − x ) + θ · u = θ , −1 < x < 1 dx2 2 with the corresponding boundary conditions: u(−1) = 0, u(1) = 0 (3.29) (3.30) Equation (3.29) with boundary conditions (3.30) have the analytixcal solution: 1 cos(θx) (1 − x2 ) u(x) = 2 · −1 − (3.31) θ cos(θ) 2 The buckling load for this case is given by Pk = 0≤θ≤ πEI such that 4L2 π 2 (3.32) 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 u000 (x) = −θ2 u0 (x) + θ2 (1 − x2 ) , 2 u0 (−1) = 0, u00 (−1) = 0 (3.33) (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: u(x) = u0 (x) − u0 (1) · u1 (x) u1 (1) (3.37) 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 y20 (3.40) 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 u 0.25 0.20 0.15 0.10 shooting technique analytical solution 0.05 0.001.0 0.5 0.0 x 0.5 1.0 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 crosssectional area In this example we will study a simply supported beam with varying crosssectional 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: I(X) = I0 , n = 2, 4, 6, . . . 1 + (X/L)n (3.42) Consider a rectangular cross-sectional area with a constant width b and a varying height h: h(X) = h0 [1 + (X/L)n ]1/3 (3.43) 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 ) dX 2 EI 2EI dU (0) U (−L) = U (L) = 0, =0 dX (3.44) (3.45) 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 =− (3.46) 2 dX EI By substitution of equation (3.46) in (3.44) and two esubsequent differentiations we get: d2 M P + @, M = −q (3.47) 2 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= L qL2 (3.48) EI0 L2 (3.49) and let P = 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 displacement 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: U= qL4 u EI0 (3.53) 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) numerically 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: s∗ = φ0 φ0 − φ1 (3.58) 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 u 0.8 m, u 0.6 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 y(0) = 4, y(1) = 1 (3.59) Our model problem (3.59) may be proven to have two solutions. Solution I: yI = 4 (1 + x)2 (3.60) CHAPTER 3. SHOOTING METHODS 112 Solution II: Can be expressed by elliptic Jacobi-functions ( see G.3 in Numeriske Beregninger) Both solutions are illustrated in Figure 3.8 . 4 2 0 y −2 −4 −6 −8 −10 −12 0.0 yI yII 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 y1 (x) = 32 [y0 (x)]2 (3.61) 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 m+1 ∆s = s sm − sm−1 = −φ(s ) · , m = 1, 2, . . . φ(sm ) − φ(sm−1 ) m m −s ϕ ϕ(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) ∆s sm+1 < ε2 (3.66) Control of relative error: 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 nonlinear 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 m 1 2 3 4 sm−1 -3.0 -6.0 -6.9054 -7.7177 φ(sm−1 ) 26.8131 6.2161 2.9395 0.6697 sm -6.0 -6.9054 -7.7177 -7.9574 117 φ(sm ) 6.2161 2.9395 0.6697 0.09875 sm+1 -6.9054 -7.7177 -7.9574 -7.9989 φ(sm+1 ) 2.9395 0.6697 0.09875 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 x 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 = L · dl EI (3.68) 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 substitution of (3.70) yields: d2 θ P L2 + cos θ = 0 dl2 EI For convenience we introduce the parameter α which is defined as: α2 = P L2 EI (3.71) (3.72) As a result we must solve the following differential equations: d2 θ + α2 cos θ = 0 dl2 dy = sin θ dl with the following boundary conditions: (3.73) (3.74) dθ (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: y(0) = 0, θ(0) = 0, z00 = z1 z10 = −α2 cos z0 z20 (3.76) = 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). Consequently, 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∗ (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. lh = # 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() 2 1 (s) 0 −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 ,d /dl,y for 2 =5.0 3.0 d /dl y 2.5 2.0 1.5 1.0 0.5 0.0 0.50.0 0.2 0.4 y/L 0.6 0.8 1.0 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: u= T − T0 , Ts − T0 x= X , L t= τ ·α L2 (3.83) 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<∞ ∂t ∂x2 accompanied by the dimensionless intitial condition: u(x, t) = 1, t<0 (3.84) (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) = b ∂ x̄2 ∂ t̄ We chose b = a2 to bring the scaled eqution (3.88) on the canonical, dimensionless 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 Boltzmanntransformation. 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: τ ·α , L2 x X η= √ = √ 2 τα 2 t Let us now solve equation (3.84) analytically and introduce: t= u = f (η) (3.93) (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 2t 4t t ∂2u ∂ ∂u ∂u ∂η 1 1 1 0 √ = = = f 0 (η) √ , f = f 00 (η) (η) ∂x ∂η ∂x ∂x2 ∂x 4t 2 t 2 t ∂u ∂2u 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: By substituting the expressions for f 00 (η) 1 η + 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: f 0 (η) = C1 e−η 2 and integrated once again to yield: Z f (η) = C1 η 2 e−t dt 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) 2 0 (3.98) CHAPTER 3. SHOOTING METHODS where the error function erf (x) is defined as: Z x 2 2 √ e−t dt π 0 126 (3.99) 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 onedimensional 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): u= T − T0 0 − (−15) 3 = = = 0.4286 Ts − T0 20 − (−15) 7 Some values for erf(η) are tabulated below : CHAPTER 3. SHOOTING METHODS 127 1.0 erf , erfc 0.8 0.6 erf 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 0.00 0.20 0.40 0.60 0.80 erf(η) 0.00000 0.22270 0.42839 0.60386 0.74210 η 1.00 1.20 1.40 1.60 1.80 erf(η) 0.84270 0.91031 0.95229 0.97635 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 X 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 1 ∂p ∂ U ∂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 <∞ ∂τ ∂Y 2 (3.104) U (U, 0) = 0 (3.105) Initialbetingelse: Randbetingelser: U (0, τ ) = U0 (heftbet.) U (∞, τ ) = 0 (3.106) Innfører følgende dimensjonsløse variable: u= τ ·ν Y U , y= , t= 2 U0 L L (3.107) der U0 og L er henholdsvis en karakteristisk hastighet og lengde. (3.107) innsatt i (3.104) gir følgende ligning: ∂2u ∂u = , 0<y<∞ ∂t ∂y 2 (3.108) u(y, 0) = 0 (3.109) u(0, t) = 1 u(∞, t) = 0 (3.110) Initialbetingelse: Randbetingelser: 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 2 τ ·ν 3.3.3 (3.112) Example: Blasius-ligningen U = constant y v δ u x 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 ∂x ∂y (3.113) ∂u ∂u 1 dp ∂2u +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 ∂u ∂2u +v =ν 2 ∂x ∂y ∂y (3.115) u(0) = 0 (3.116) u → U0 for y → δ (3.117) u Randbetingelser: For å oppfylle kontinuitetsligningen (3.113), innfører vi strømfunksjonen ψ(x, y) definert ved: u= ∂ψ ∂ψ , v=− ∂y ∂x (3.118) CHAPTER 3. SHOOTING METHODS 130 Vi definerer et Reynoldstall: U0 x (3.119) ν Innfører følgende likedannhetsvariable for koordinat og strømfunksjon: r U0 ψ (3.120) η= · y og f (η) = √ 2νx 2Uo νx Rex = Transformasjonen (3.120) gir Blasius-ligningen for strømfunksjonen f : f 000 (η) + f (η) · f 00 (η) = 0 (3.121) df dη ≡ f 0 (η) og tilsvarende for høyere deriverte. De fysikalske Notasjon: hastighetskomponentene er gitt ved: u v η · f 0 (η) − f (η) √ = f 0 (η), = U0 U0 2Rex (3.122) 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 τxy = µU0 · f (η) U0 2νx (3.124) 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 differensialligninger: f 0 = f1 (3.125) f10 f20 = f2 (3.126) = −f · f2 (3.127) f (0) = f1 (0) = 0 f1 (η∞ ) = 1 (3.128) Randbetingelser: 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: m+1 s sm − sm−1 = s + δs, δs = −φ(s ) · , m = 1, 2. . . . φ(sm ) − φ(sm−1 ) m m (3.130) 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 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 132 CHAPTER 3. SHOOTING METHODS 133 6 5 f'( ) - velocity f''( ) - wall shear stress 4 3 2 1 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 dimensjonslø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ærspenningen 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. 1 2 3 4 s 0.471625 0.469580 0.469601 0.469601 ds - 2.837e-002 - 2.046e-003 2.146e-005 - 1.540e-008 CHAPTER 3. SHOOTING METHODS η 0.00 0.25 0.50 0.75 1.00 1.25 1.50 1.75 2.00 2.25 2.50 2.75 3.00 3.25 3.50 3.75 4.00 4.25 4.50 4.75 5.00 5.25 5.50 5.75 3.3.4 f 0.000000 0.014673 0.058643 0.131642 0.232991 0.361431 0.515032 0.691201 0.886798 1.098374 1.322442 1.555766 1.795573 2.039661 2.286412 2.534723 2.783894 3.033509 3.283340 3.533271 3.783244 4.033235 4.283232 4.533231 f’ 0.000000 0.117364 0.234228 0.349324 0.460634 0.565601 0.661476 0.745765 0.816697 0.873559 0.916810 0.947928 0.969057 0.982573 0.990711 0.995319 0.997773 0.999000 0.999577 0.999832 0.999938 0.999980 0.999995 1.000000 135 f" 4.69601e-001 4.69027e-001 4.65032e-001 4.54373e-001 4.34380e-001 4.03495e-001 3.61805e-001 3.11302e-001 2.55671e-001 1.99544e-001 1.47476e-001 1.02930e-001 6.77108e-002 4.19262e-002 2.44148e-002 1.33643e-002 6.87412e-003 3.32201e-003 1.50841e-003 6.43473e-004 2.57831e-004 9.70546e-005 3.43646e-005 1.15317e-005 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 grensesjiktligningen 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 geometriske 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 (2 − β)νx (2 − β)U νx (3.133) 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 f 0 (η∞ ) = 1 (3.135) 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 f10 f20 (3.136) = f2 = −[f f2 + β(1 − (3.137) f12 )] (3.138) Randbetingelser: f (0) = f1 (0) = 0 f1 (η∞ ) = 1 (3.139) 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 3 2 1 0 −1 =4 =5 =6 −2 −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 tilbakestrø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 5 4 = -0.198837 = -0.15 =0 = 0.3 =1 3 2 1 0 0.0 0.2 0.4 0.6 0.8 1.0 f' Figure 3.22: Marit 1: description 6 = -0.198837 = -0.15 =0 = 0.3 =1 5 4 3 2 1 0 0.0 0.2 0.4 0.6 f'' 0.8 1.0 1.2 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 0 f (η∞ ) = 1 (3.142) (3.143) Løsningen kan da skrives: √ √ f (η) = η + 2 3 − 3 2 · tanh(z) 0 2 f (η) = 3 tanh (z) − 2 √ f 00 (η) = 3 2 · tanh(z) · [1 − tanh2 (z)] (3.144) (3.145) (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 3.4.1 Skyting med to startbetingelser Lineære ligninger Vi vil nå utvide teknikken som vi brukte i avsnitt (3.1) til to ukjente startbetingelser. 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 ψ =D·s+E·r+F (3.147) 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 1 1 (3.148) 1 φ =A·s +B·r +C φ (2) (2) =A·s +B·r (2) (3.149) +C (3.150) (3.151) CHAPTER 3. SHOOTING METHODS 141 ψ 0 = D · s0 + E · r0 + F 1 1 (3.152) 1 ψ =D·s +E·r +F ψ (2) (2) =D·s +E·r (2) (3.153) +F (3.154) (3.155) der s0 , s1 , s(2) , r0 , r1 og r(2) er verdier som vi har tippet for initialbetingelsene.For å forenkle slutt-resultatet, velger vi følgende verdier: 1) s0 = 0, r0 = 0 1 1 2) s = 0, r = 1 (2) 3) s = 1, r (2) =0 (3.156) (3.157) (3.158) Vi får da følgende uttrykk for konstantene: C = φ0 , B = φ1 − φ0 , A = φ(2) − φ0 F = ψ 0 , E = ψ 1 − ψ 0 , D = ψ (2) − ψ 0 (3.159) 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 , r∗ = D·B−A·E D·B−A·E som innsatt for A, B, C, . . . , F gir: s∗ = s∗ = ψ 1 ·φ0 −φ1 ·ψ 0 (ψ (2) −ψ 0 )·(φ1 −φ0 )−(φ(2) −φ0 )·(ψ 1 −ψ 0 ) (3.160) ∗ r = φ(2) ·ψ 0 −ψ (2) ·φ0 (ψ (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 + B · W = −γ 4 dX D (3.161) CHAPTER 3. SHOOTING METHODS 142 R g t ∇ X M V W V H M Figure 3.26: Marit 1: description 12(1 − ν 2 ) Et3 , D = , γ = ρg R2 t2 12(1 − ν 2 ) Her er ν Poissons tall, E elastisitetsmodelen og ρ væskas tetthet. Innfører dimensjonsløse størrelser: der B = x= X E og w = · H γHt t R 2 ·W (3.162) som innsatt i (3.161) gir følgende differensialligning: d4 w + 4β 4 · w = −4β 4 (1 − x) dx4 (3.163) der β4 = 3(1 − ν 2 )H 4 R2 t2 (3.164) Randverdier. For x = 0: dW = 0 (Fast innspent) dX Skjærkraft og moment = 0 for X = H som gir: W = 0, d2 W d3 W = 0, V = −D =0 2 dX dX 3 Randverdiene uttrykt ved dimensjonsløse størrelser blir da: M = −D For x = 0 : w = 0, 2 For x = 1 : ddxw2 = 0, dw dx3 = 0 d w dx3 = 0 (3.165) CHAPTER 3. SHOOTING METHODS Dimensjonsløst moment m(x) = − − 143 d2 w 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 γ = 9810N/m3 (vann), ν = 0.2, E = 2 · 104 MPa (3.166) 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 y30 = y4 0 y4 = −4β 4 (y + 1 − x) (3.167) 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 0.000 0.100 0.200 0.300 0.400 0.500 0.600 0.700 0.800 0.900 1.000 w 0.00000e+000 -1.89049e-001 -4.57346e-001 -6.03796e-001 -6.16145e-001 -5.43811e-001 -4.35148e-001 -3.18861e-001 -2.06030e-001 -9.76194e-002 8.92555e-003 dw/dx m(x) v(x) 0.00000e+000 -2.86464e+000 -2.19767e+000 -7.32255e-001 3.93069e-001 9.70524e-001 1.15559e+000 1.15307e+000 1.10306e+000 1.07014e+000 1.06379e+000 6.00946e+001 4.85241e+000 -1.36887e+001 -1.38468e+001 -8.41051e+000 -3.44813e+000 -6.10973e-001 4.27833e-001 4.68862e-001 1.76515e-001 1.20446e-004 -7.93776e+002 -3.36907e+002 -6.60901e+001 4.15724e+001 5.74987e+001 3.94237e+001 1.81108e+001 4.09131e+000 -2.15847e+000 -2.96401e+000 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 1.0 0.9 0.8 0.7 0.6 0.5 −v0 793.809 793.715 793.670 793.598 791.835 781.541 m0 60.098 60.093 60.099 60.079 59.816 58.879 DEL 2: Lineært variabel veggtykkelse R g ∇ X M V t1 W H 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 H (3.169) CHAPTER 3. SHOOTING METHODS 145 Differensialligningen for forskyvningen W er nå gitt ved: 2 d W tW d2 D + E 2 = −γ(H − X) 2 2 dX dX R (3.170) Et3 , γ = ρg 12(1 − ν 2 ) Konstantene har samme betydning som i del 1. (Se appendiks D i Numeriske Beregninger for flere detaljer). der D = Dimensjonsløs form X E x= , w= H γHt0 t0 R 2 · W, β 4 = 3(1 − ν 2 ) · H4 R2 t20 (3.171) innsatt i (3.170): 2 d2 3d w (1 − αx) + 4β 4 (1 − αx) · w = −4β 4 (1 − x) dx2 dx2 (3.171) (3.172) 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 γ = 9810N/m3 (vann), ν = 0.2, E = 2 · 104 MPa Her blir α = t0 −t1 t0 = 5 7 (3.174) 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 4 6α 6α2 0 y4 = z y4 − z2 y3 − 4β z 2 y1 − (3.175) 4β 4 (1−x) 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 0.000 0.100 0.200 0.300 0.400 0.500 0.600 0.700 0.800 0.900 1.000 w 0.00000e+000 -2.15376e-001 -5.66553e-001 -8.05113e-001 -8.79417e-001 -8.34707e-001 -7.31823e-001 -6.05528e-001 -4.57651e-001 -2.72819e-001 -5.26758e-002 dw/dx m(x) v(x) 0.00000e+000 -3.45545e+000 -3.16644e+000 -1.53673e+000 -3.87614e-002 8.24809e-001 1.17417e+000 1.35136e+000 1.63752e+000 2.06404e+000 2.26301e+000 6.23338e+001 9.04151e+000 -8.14798e+000 -8.34542e+000 -4.36688e+000 -1.47715e+000 -3.81333e-001 -2.49403e-001 -3.00683e-001 -1.83081e-001 3.87892e-005 -7.73773e+002 -3.18887e+002 -5.86193e+001 3.32725e+001 3.81223e+001 1.90313e+001 4.52213e+000 -5.41818e-001 8.66313e-002 2.16427e+000 -1.76069e-006 Vi finner god overenstemmelse ved å sammenligne med den analytiske løsningen 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) f 0 (−η∞ ) = U2 U1 (3.180) 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 Beregninger) 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∗ U2 = 0 for s = s∗ , r = r∗ U1 ψ(−η∞ ; r, s) = f 0 (−η∞ ; r, s) − (3.183) (3.184) 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 (3.188) φ(η∞ ; r, s) = f (η∞ ; r, s) − 1 = 0 II. For det nedre sjiktet: f 000 (ζ) − f (ζ) · f 00 (ζ) = 0 (3.189) med rand - og initialbetingelser: U2 U1 f (0) = 0, f 0 (0) = −r, f 00 (0) = s U2 ψ(ζ∞ ; r, s) = f 0 (ζ∞ ; r, s) + =0 U1 f 0 (ζ∞ ) = − 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η (3.190) (3.191) (3.192) 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 ψ(r∗ , s∗ ) = 0 (3.193) 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 2 [3]. Figure ?? gjelder for en bestemt verdi av α = U U1 slik at vi i prinsippet må 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 2 funksjon av U U1 : CHAPTER 3. SHOOTING METHODS U2 U1 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 Med α = r∗ 0.583776 0.613568 0.646947 0.683594 0.723101 0.765049 0.809060 0.854807 0.902021 0.950480 1.000000 U2 U1 149 s∗ 0.284447 0.267522 0.247879 0.225504 0.200460 0.172847 0.142779 0.110363 0.075701 0.038886 0.000000 finner vi følgende kurvetilpasninger for r∗ og s∗ fra tabellen: r∗ ≈ r̄ = 0.1076 · α2 + 0.3086 · α + 0.5838 s∗ ≈ s̄ = −0.1224 · α2 − 0.1620 · α + 0.2844 (3.194) Istedenfor denne litt omstendelige fremgangsmåten, kan du forsøke programmet 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) x 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 = ∂t ∂y (3.195) The relation between the shear stress τxy and the velocitygradient ∂u ∂y is given by: τxy 21 ∂u ∂u = K · ∂y ∂y (3.196) where K is a positive constant. We introduce the following transformation which reduces the system to an ordinary differential equation: η=C· y 2 , t5 f (η) = u U0 (3.197) 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: f 00 (η) + 2 η p 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=[] legends=[] # list for plot lines for solvers and analytical solutions # 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 ··· aN xN −1 + bN xN = dN i = 1, 2, ...N , a1 = cN = 0 (4.1) or more convenient in a matrix representation: b1 a2 c1 b2 · c2 · · · · · · · · aN −1 bN −1 aN 154 x1 x2 · · · d1 d2 · · · · = cN −1 xN −1 dN −1 bN xN dN (4.2) 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 N . may the be computed as xN := dbN 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: qj := aj bj−1 for j = 2, 3 · · · , N bj := bj − qj · cj−1 (4.3) dj := dj − qj · dj−1 Back substitution: dN bN dj − cj · xj+1 xj := bj xN := for j = N − 1, N − 2, · · · , 1 (4.4) (4.5) The Python-code for (4.3) and (4.4) is implemented in tdma, which corresponds 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 | bn |>| aN |> 0 (4.6) 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 CPUintensive. 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 ··· aN −1 xN −1 + bN xN = dN i = 1, 2, ...N , a1 = cN = 0 (4.7) CHAPTER 4. FINITE DIFFERENCES FOR ODES 157 or in matrix form: b1 a1 c2 b2 · c3 · · · · · · · · aN −2 bN −1 aN −1 x1 x2 · · · d1 d2 · · · = · dN −1 xN −1 cN dN xN bN (4.8) 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): b(array): c(array): d(array): Returns: x(array): an array containing lower diagonal (a[0] is not used) an array containing main diagonal an array containing lower diagonal (c[-1] is not used) right hand side of the system 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 L 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: h̄P d2 (T − T∞ ) = (T − T∞ ) dX 2 kA For convenience we introduce dimensonless variables: (4.10) T − T∞ X h̄P 2 , θ= L (4.11) , β2 = 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: x= 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 condtions. 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 θ=1 for x = 1 (4.14) CHAPTER 4. FINITE DIFFERENCES FOR ODES 160 The analytical solution (4.13) for these particular boundary conditions reduces to: θ(x) = sinh(βx) dθ cosh(βx) , =β sinh(β) dx sinh(β) (4.15) 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 L = L kA D Mixed boundary conditions: β2 = Qx = 0 = dT dX (4.16) for X = 0 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: dθ =0 dx θ=1 for x = 0 (4.17) for x = 1 (4.18) The analytical solution (4.13) reduces for the mixed boundary conditions to: θ(x) = cosh(βx) dθ sinh(βx) , =β cosh(β) dx cosh(β) (4.19) d2 θ Numerical solution. We will use central differences for the term and dx2 2 θi−1 − 2θi + θi+1 d θ ≈ we get the following difference equation: with dx2 h2 i θ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 0 1.0 X 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 ci = 1 , i = 1, 2, ..., N − 1 di = 0 , i = 1, 2, ..., N − 1 (4.22) 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 modules, 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 dθ 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 2h i CHAPTER 4. FINITE DIFFERENCES FOR ODES 0.0 1 1.0 X 2 164 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 2h (4.24) 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 2 2 c1 = −(2 − β h ) bi = (2 + β 2 h2 ) i = 2, ..., N (4.33) 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, 2 2 θi−1 − (2 + β h ) θi + θi+1 = 0, 2 2 θN −1 − (2 + β h ) θN = −1, i=1 i = 2, 3, ..., N − 1 (4.35) 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 n = int(round(L/h)) x=np.arange(n+1)*h 166 # # of unknowns, assuming known bndry values at outlet # 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 diagonals[0,0]= 1.0 diagonals[1,:]= -(2+(beta*h)**2) diagonals[2,:]=1.0 # all elts in first row is set to 1 if (version==1): diagonals[2,1]= 2.0 else: diagonals[1,0]=2.0 diagonals[2,1]= -(2+(beta*h)**2) super-diagonal # index 1 as the superdiagonal of spdiags is not used, # Sets the first element in the main diagonal # index 1 as the superdiagonal of spdiags is not used, 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 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 Anlytical 0.26580 0.27114 0.28735 0.31510 0.35549 0.41015 0.48128 0.57171 0.68510 0.82597 1.00000 Ctr.diff 0.26665 0.27199 0.28820 0.31594 0.35632 0.41095 0.48202 0.57237 0.68561 0.82628 1.00000 Rel.err 0.00320 0.00314 0.00295 0.00267 0.00232 0.00194 0.00154 0.00114 0.00075 0.00037 0.00000 Fwd.diff 0.26613 0.27156 0.28786 0.31567 0.35610 0.41078 0.48189 0.57228 0.68555 0.82625 1.00000 Rel. err 0.00124 0.00158 0.00176 0.00180 0.00171 0.00153 0.00128 0.00098 0.00067 0.00034 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 4.1.2 168 Ribbe med variabelt tverrsnitt D A(X) X d 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=0 X=L X Figure 4.5: Marit 1: description Figure 4.5 viser øvre halvpart av ribba. Av denne figuren finner vi følgende relasjon: tan(φ) = D/2 − d/2 l/2 − d/2 = L X som løst m.h.p. l gir: D−d d d X l =d+ X=D + 1− L D D L (4.38) 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(T − T∞ ) h̄P (X) d A(X) = (T − T∞ ) (4.39) dX dX k randbetingelser: h̄0 dT (0) = [T (0) − T∞ ] , T (L) = TL dX k For trapestverrsnittet i fig. (4.4): (4.40) P (X) = 2(b + l) ≈ 2b for l b og A(X) = b l Innfører følgende dimensjonsløse størrelser: Temperatur θ = d T − T∞ X ,α= , 0 < α < 1 samt: , lengde x = TL − T∞ L D 2h̄ L2 h̄0 og β02 = L Dk k Med bruk av disse dimensjonsløse størrelsene kan (4.39) skrives: d dθ(x) {α + (1 − α) x} − β 2 θ(x) = 0 dx dx Biot-tallene β 2 = (4.41) (4.42) med randbetingelser: dθ (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å: x d2 θ dθ + − β 2 θ(x) = 0 2 dx dx (4.44) For x = 0: dθ (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 4.1.3 170 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 0.00 0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 1.00 θ (x) 0.18069 0.19623 0.22415 0.26424 0.31708 0.38383 0.46614 0.56611 0.68632 0.82978 1.00000 θ’(x) 0.09034 0.21842 0.33967 0.46318 0.59556 0.74211 0.90754 1.09629 1.31291 1.56211 1.84901 Numerisk løsning av homogent trapesprofil Vi vil nå løse lign. (4.47) numerisk med bruk av sentraldifferanser (1 + x) d2 θ dθ + − 8 θ(x) = 0 dx2 dx (4.48) med randbetingelser: θ(0) dθ (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: (1 + xi ) θi+1 − 2θi + θi−1 θi+1 − θi−1 + − 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 0.0 1 171 1.0 X 2 3 i N-1 N N+1 Figure 4.6: Marit 1: description der γi = h h = , i = 1, 2, ..., N + 1 2(1 + xi ) 2[1 + (i − 1) h] For randbetingelsen i (4.49) får vi: i (4.50) for i = 1 gir: θ2 −θ0 2h = θ1 2 (4.51) → θ0 = θ2 − θ1 h som innsatt [2 + h (1 + 15 γ1 )] θ1 − 2θ2 = 0 (4.52) −(1 − γN ) θN −1 + 2 (1 + 8h γN ) θN = 1 + γN (4.53) For i = N : 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 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 θ(x) 0.18054 0.19634 0.22442 0.26462 0.31752 0.38430 0.46660 0.56653 0.68665 0.82998 1.00000 rel. feil 8.000E-4 5.619E-4 1.224E-3 1.436E-3 1.394E-3 1.222E-3 9.910E-4 7.385E-4 4.838E-4 2.364E-4 0 h = 0.01 x 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 θ(x) 0.18069 0.19623 0.22415 0.264259 0.31709 0.38383 0.46614 0.56611 0.68632 0.82978 1.00000 rel. feil 4.866E-6 1.010E-5 1.669E-5 1.703E-5 1.325E-5 9.861E-6 6.393E-6 2.737E-6 4.342E-7 1.508E-6 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 0.1m 172 0.1m d Part a D Part b Figure 4.7: Marit 1: description dT 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 = kb Ab (4.54) Qa = Qb ⇒ ka Aa dX a dX b dT ka dT Da Aa = Ab på grenseflata, følger: = som på dimendX b kb dX a sjonsløs form (med bruk av (4.41) blir: dθ ka dθ = (4.55) dx b kb dX a −dQx = P h [T (X) − T∞ ] dX der Qx = −kA Bruker følgende tallverdier: L = 0.2m , D = 0.02m , d = 0.01m , h̄a = h̄b = 80W/m2 /◦ C , ka = 160W/m/◦ C og kb = 40W/m/◦ C Med disse tallverdiene blir (4.55): dθ dθ =4 dx b dx a (4.56) (4.57) Differensialligning: d dx x dθ β 2 dx − θ(x) = 0 (4.58) 2h̄ L2 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: β2 = CHAPTER 4. FINITE DIFFERENCES FOR ODES 0.0 1 X 2 173 0.5 M-1 M M+1 1.0 N N+1 Figure 4.8: Marit 1: description xi = (i − 1) h , i = 1, 2, ..., N + 1 der h = N1 M = N2 + 1 der N er et partall og xM = s0.5 (4.60) 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: 3 1 β2h 1 − 1− θi−1 + 2 1 − + θi − 1 − θi+1 = 0 2i i i 2i (4.62) (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 Skriver ut (4.62) for i = 2: 3 1 βa2 h 1 − 1− θ1 + 2 1 − + θ2 − 1 − θ3 4 2 2 4 (4.63) CHAPTER 4. FINITE DIFFERENCES FOR ODES som innsatt fra (4.59) og (4.63) gir: 3h h 1+ θ1 − 1 − θ2 = 0 2 2 174 (4.64) 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: xM − 12 2 2 = βa2 = 2.0 , βM = βb2 = 8.0 βM + 21 − 12 h h (1 − h) (1 + h) = (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 For i = N kan vi bruke (4.62) med β 2 = βb2 = 8.0: 3h h − 1− θN −1 + 2 [(1 − h) + 4h2 ] θN = 1 − 2 2 (4.65) (4.66) 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θ (0.5+) ≡ finnes fra (4.57). De andre verdiene beregnes med vanlige dx dx b 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): Z dθi β 2 xi = θ(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 . Beregningen av (4.67) er vist i pseudokode nedenfor: CHAPTER 4. FINITE DIFFERENCES FOR ODES θ10 s Utfør for i x s 175 := βa2 θ1 := 0 := 2, ..., N + 1 := h (i − 1) := s + 0.5h (θi + θi−1 ) β2 s βa2 s 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 Dersom (i ≤ M ) sett θi0 := x 0.00 0.10 0.20 0.30 0.40 0.45 0.50.5+ 0.55 0.60 0.70 0.80 0.90 1.00 4.2 θ(x) 0.08007 0.09690 0.11545 0.13582 0.15814 0.17007 0.18253 0.18253 0.23482 0.29073 0.41815 0.57334 0.76442 1.00000 rel. feil 1.371E-4 1.341E-4 1.386E-4 1.252E-4 1.265E-4 1.294E-4 1.260E-4 1.260E-4 5.962E-5 5.848E-5 3.348E-5 1.744E-5 7.849E-6 0.0 θ0 (x) 0.16014 0.17670 0.19438 0.21324 0.23333 0.24387 0.25472 1.01889 1.07785 1.16297 1.39964 1.71778 2.11851 2.60867 rel. feil 1.312E-4 1.302E-4 1.286E-4 1.360E-4 1.329E-4 1.312E-4 1.021E-4 1.021E-4 1.067E-4 9.202E-5 7.288E-5 5.938E-5 4.862E-5 1.526E-4 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 0 − β 2 θ(x) = 0 θ (0) = 0 , θ(1) = 1 Med notasjonen i (4.68) kan dette systemet skrives: 0 0 y10 = y2 y20 = β 2 y1 1 y (0) 0 0 y (1) 0 · 1 + · 1 = 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-½ ½h j ½h Figure 4.10: Marit 1: description yj − yj−1 dy 1 = + O(h2 ) , yj− 21 = (yj + yj−1 ) + O(h2 ) dx j− 1 h 2 (4.70) 2 (4.70) brukt i (4.68) gir: yj − yj−1 yj + yj−1 − f xj− 21 , = 0 , j = 1, 2, ..., N h h (4.71) med randbetingelser: A · y0 + B · yN = c (4.72) CHAPTER 4. FINITE DIFFERENCES FOR ODES 177 Notasjon: b−a (4.73) N Med denne diskretiseringen kan det vises at følgende relasjon gjelder: xj = a + j · h, j = 0, 1, ...N , h = 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 X 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: Lengdekoordinat: Rørdiameter: Areal av rørtverrsnitt: Omkrets av indre rør: Tetthet av medium: Massestrøm: Totalt varmeovergangstall: Egenvarme: Varmestrøm: L X di Ai = π · d2i /4 P = π · di ρi ṁi = ρi Ai wi h̄ ci Q̇i = ṁi ci Ti [m] [m] [m] [m2 ] [m] [kg/m3 ] [kg/s] [W/m2 /◦ C] [J/kg/◦ C] [W ] (4.75) 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: dQ̇i = Q̇yi = −dQ̇y (4.77) hvor vi har benyttet oss av at vi ikke har noe varmetap til omgivelsene. dX Qyi Ty Wy Ti Wi Ty Wy di dy Qi Wi Qi + dQi 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: dTy (X) = − dTi (X) = h̄P [Ty (X) − Ti (X)] · dX ṁy cy h̄P [Ty (X) − Ti (X)] · dX ṁi ci (4.79) (4.80) Vi innfører nå dimensjonsløse størrelser. Lar Tir og Tyr være referansetemperaturer 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 . Temperatur ytre rør: u = Ty − Tyr Tir − Tyr (4.81) Temperatur indre rør: v = Ti − Tyr Tir − Tyr (4.82) Lengde: x = αy = X L (4.83) h̄P L h̄P L = ṁy cy ρy Ay wy cy (4.84) Koeffisienter: h̄P L h̄P L = αi = ṁi ci ρi Ai wi ci (4.81) innsatt i (4.79) gir følgende system: du = −αy (u − v) dx Ytre rør: (4.85) dv = ±α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). Indre rør: 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 dθ slik at vi får ligningen − dx = (αy ± αi ) · θ med løsning: θ(x) = θ0 · e−(αy ±αi )·x , der θ0 = θ(0) Får da følgende løsning for u og v: h i αy u(x) = u0 − θ0 · · 1 − e−(αy ±αi )·x αy ± αi h i αi v(x) = v0 + θ0 · · 1 − e−(αy ±αi )·x αy ± αi (4.88) (4.89) (4.90) 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) dx (4.91) 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: Temperatur ytre rør: u = Ty − Ty (0) Ti (L) − Ty (0) (4.93) Temperatur indre rør: v = Ti − Ty (0) Ti (L) − Ty (0) (4.94) 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) aj uj−1 + aj vj−1 + bj uj + bj vj + cj uj+1 + cj vj+1 = dj (4.98) 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) c 1(3) c1 " (1) a2 (3) a2 (2) c1 (4) c1 # " (1) b1 (3) b1 b1 (4) b1 # " b2 (4) b2 (2) a2 (4) a2 (1) b2 (3) b2 (2) # (2) # " (1) c2 (3) c2 · · · (2) c2 (4) c2 # · · · " (1) aj (3) aj (2) aj (4) aj # " (1) (2) bj (3) bj bj (4) bj # " (1) cj (3) cj · · · (2) cj (4) cj # · · · " (1) aN (3) aN (2) aN (4) aN # " (1) bN (3) bN 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) , bj = (3) (4) , cj = (3) (4) (4) aj aj bj bj cj cj " # (1) d u xj = j , dj = j(2) , j = 1, 2, ..., N vj dj " # (1) d1 (2) u1 u1 d1 " # (1) u2 d2 u2 d(2) 2 · · · · · · = · " # uj d(1) j uj (2) · dj · · · · · # uN " # (1) (2) bN uN dN (4) (2) bN dN CHAPTER 4. FINITE DIFFERENCES FOR ODES 182 slik at systemet ovenfor kan skrives: d1 x1 b1 c1 x2 d2 a2 b2 c2 · · · · · · · · · · · · · = xj dj a b c j j j · · · · · · · · · · · · dN xN aN bN (4.99) Å 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 Outer tube: u0 x=1 u1 u2 uj uN-1 uN x=0 Inner tube: v0 x=1 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 Outer tube: u0 x=1 u1 u2 uj uN-1 uN x=0 Inner tube: v1 x=1 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) vj , j = 1, 2, ..., N + 1 , vN +1 = 1 fra randbetingelsen (4.101) For v: 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 h · αi · u1 − (h · αi + 2) · v1 + (2 − h · αi ) · v2 =0 =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 · αi · uN −1 + h · αi · uN − (h · αi + 2) · vN = h · αy = 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) αj (1) cj (3) αj (3) cj = h · αy − 2 , = 0, = h · αi , =0, (1) hvor α1 (2) og α1 (2) αj (2) cj (4) αj (4) cj =0, = −h · αy , =0, = 2 − h · αi , ikke brukes. (1) bj (1) dj (3) bj (2) dj = 2 + h · αy , =0, = h · αi , =0, (2) = −h · αy j = 1, 2, ..., N − 1 (4) bj = −(h · αi + 2) j = 1, 2, ..., N − 1 (4.104) bj 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) b1 (3) b1 (1) a2 a(3) 2 (2) b1 (4) b1 0 0 0 0 0 (2) c1 (4) c1 (2) b2 (4) b2 0 0 0 0 u1 0 0 v1 (1) (2) 0 b2 0 c2 u2 (3) (4) 0 b2 0 c2 0 v2 0 (1) (1) (2) (2) u3 a3 b3 b3 0 c3 0 (3) (3) (4) (4) v3 a3 b3 b3 0 c3 0 · = 0 (1) (1) (2) (2) u a4 0 b4 b4 0 c4 4 0 v4 (3) (3) (4) (4) 0 a4 0 b4 b4 0 c4 0 u (1) (1) (2) (2) 5 0 0 a5 0 b5 b5 0 c5 v5 (4) (3) (3) (4) 0 b5 0 c5 0 b5 a5 u6 (1) d6 (2) (1) (1) 0 a6 0 b6 b6 v 6 (2) (3) (4) (3) d6 b6 0 a6 0 b6 (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: Rørdiameter: Omkrets av rør: Massestrøm: Totalt varmeovergangstal: Egenvarme: L d P ṁy h̄ cy = 61m = 0.025m = π · d = 0.07854m = 0.1 og ṁi = 0.23kJ/s = 40W/m2 /◦ C = 2130 og ci = 4180J/Kg/◦ C Med disse data, får vi følgende verdier for koeffisientene αy og αi : αy = h̄P L h̄P L ≈ 0.9 , αi = ≈ 0.2 ṁy cy ṁi ci (4.106) 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 ] v(x) = v0 [1 + 27 (1 − e−0.7·x )] h = 0.1 x 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 Ty (◦ C) 100.00000 94.67864 89.71719 85.09129 80.77825 76.75692 73.00756 69.51178 66.25243 63.21352 60.38014 Ti (◦ C) 38.80441 37.62189 36.51934 35.49137 34.53291 33.63928 32.80609 32.02925 31.30495 30.62964 30.00000 h = 0.01 (4.109) x 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 Ty (◦ )C 100.00000 94.68054 89.72070 85.09618 80.78431 76.76395 73.01539 69.52026 66.26142 63.22291 60.38981 Ti (◦ C) 38.80226 37.62016 36.31798 35.49031 34.53211 33.63870 32.80569 32.02899 31.30480 30.62958 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 0.100 0.050 0.010 0.005 0.001 v0 0.87422266 0.87424592 0.87425336 0.87425359 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 T i , Ty 80.0 60.0 40.0 Water 20.0 0.0 0.0 0.2 0.4 x 0.6 0.8 1.0 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 − hk1 hk+1 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 ) 3 (4.112) 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): 1 h h y(xj ) = yj + y − yj (h) + O(h4 ) (4.114) 2 3 j 2 Tytre x 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 h = 0.2 100.0000 89.70651 80.75984 72.98376 66.22511 60.35076 h = 0.1 100.00000 94.67864 89.71719 85.09129 80.77825 76.75692 73.00756 69.51178 66.25243 63.21352 60.38014 Ekstrapol. 100.00000 h = 2 · 103 100.00000 89.72075 89.72073 80.78439 80.78437 73.01549 73.01547 66.26154 66.26151 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 y(0) = 4 , y(1) = 1 (4.115) der en av løsningene er gitt ved: y= 4 (1 + x)2 (4.116) 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 2 (4.117) CHAPTER 4. FINITE DIFFERENCES FOR ODES x0 x1 xi 188 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 m+1 yi−1 − 2 + 32 yim+1 h2 yim+1 + yi+1 =0 (4.119) m+1 m+1 3 m+1 2 y = −1 y h − 2 + N −1 N 2 N der i = 2, 3, ...N − 1 , m = 0, 1, 2, ... m+1 Lineariseringen består nå i å erstatte 32 h2 y1m+1 , 32 h2 yim+1 og 32 h2 yN med 3 2 m 3 2 m 3 2 m h y , h y og h y slik at vi får følgende lineære system: 1 i N 2 2 2 − 2 + 32 y1m h2 y1m + y2m = −4 m m yi−1 − 2 + 32 yim h2 yim + yi+1 =0 (4.120) 3 m 2 m m yN = −1 N −1 − 2 + 2 yN h 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 Thomasalgoritmen. 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. 1 2 3 4 5 6 7 8 9 10 11 12 max. avvik 1.000e+000 5.525e-001 1.104e-001 2.632e-002 5.892e-003 1.328e-003 2.980e-004 6.690e-005 1.502e-005 3.370e-006 7.562e-007 1.697e-007 Max. avvik betyr her det maksimale relative avviket. Løsningen av differ4 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 = d = 0 ; % høyre side d(1) = - 4.0; d(n) = - 1.0; while (dymax > RelTol) & (it it = it + 1; b = ym1 = tdma(a,b,c,d); 1.0; RelTol = 1.0e-5; < itmax) -(2.0 + fac*ym); % hoveddiagonal % 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) : yim+1 2 2 = (yim + δyi ) = (yim )2 + 2yim · δyi + (δyim )2 ≈ (yim )2 + 2yim · δyi = yim (2yim+1 − yim ) (4.122) 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 m+1 m+1 yi−1 − (2 + 3yim h2 )yim+1 + yi+1 m+1 m 2 m+1 yN −1 − (2 + 3yN h )yN = − 32 (yim h)2 − 4 = − 23 (yim h)2 (4.123) m 2 = − 32 (yN 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 Thomasalgoritmen. Velger samme startverdier som i foregående versjon. Matlabprogrammet taylor34 gir følgende resultat med h = 0.05 : Itr. 1 2 3 4 5 6 max. avvik 1.000e+000 3.765e-001 2.479e-002 9.174e-005 1.175e-009 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. Lineariseringen 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 ikkelineære leddet som skal lineariseres for F og antar at F er funksjon av den CHAPTER 4. FINITE DIFFERENCES FOR ODES 191 avhengige m+1 variable z i punktet i ved iterasjon m + 1 : Vi skal linearisere leddet F (zi ) ≡ F (zi )m+1 . Bruker den siste notasjonen i fortsettelsen. Rekkeutvikling: ∂F F (zi )m+1 ≈ F (zi )m + δzi (4.124) dzi m 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 (zi , zi+1 )m+1 ≈ F (zi , zi+1 )m + δzi der δzi = zim+1 − zim ∂F ∂zi , δzi+1 = + δzi+1 m m+1 zi+1 − ∂F ∂zi+1 m (4.125) 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 +δzi−1 ∂F ∂zi−1 + δzi m ∂F ∂zi + δzi+1 m ∂F ∂zi+1 (4.126) m m+1 m+1 m m der δzi−1 = zi−1 − zi−1 , δzi = zim+1 − zim , δzi+1 = zi+1 − zi+1 Tilsvarende for flere indekser. 4.3.3 Example: p Gitt differensialligningen y 00 (x) + y(x) y(x) = 0 som diskretisert med sentraldifferanser blir: m+1 m+1 yi+1 − 2yim+1 + yi−1 + h2 yim+1 Det er leddet yim+1 · q q yim+1 = 0 ved iterasjon m + 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 F (yi )m+1 ≈ F (yi )m + δyi yim+1 q yim+1 ≈ yim p ∂F ∂yi yim + 3 2 3 = (yim ) 2 + δyi · 192 3 2 1 · (yim ) 2 eller m · p yim · δyi der δyi = yim+1 − yim 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: 3 2p m h2 m p m m+1 m+1 + yi−1 = h yi − 2 yim+1 + yi+1 y yi 2 2 i 4.3.4 (4.127) Example: y 00 (x) + sin (y(x)) = 0 som diskretisert med sentral-differanser blir: m+1 m+1 yi+1 − 2yim+1 + yi−1 + h2 sin yim+1 = 0 (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 (yi )m+1 ≈ F (yi )m + δyi ∂F ∂yi = sin(yim ) + δyi · cos(yim ) eller 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 m+1 yi−1 + (h2 cos(yim ) − 2)yim+1 + yi+1 = h2 (yim cos(yim ) − sin(yim )) 4.3.5 (4.129) Example: p Gitt differensialligningen y 00 (x) + y(x) y 0 (x) = 0 som diskretisert med sentraldifferanser blir: m+1 m+1 yi+1 − 2yim+1 + yi−1 + α · yim+1 q p m+1 m+1 yi+1 − yi−1 = 0 , der α = h h/2 (4.130) q m+1 m+1 Det er leddet yim+1 yi+1 som er ikke-lineært og må lineariseres. I − yi−1 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 F (yi−1 , yi , yi+1 )m = yim ∂F ∂yi = p m p m ∂F m , yi+1 − yi−1 ∂yi−1 m − y m og tilslutt yi+1 i−1 ∂F ∂yi+1 m 193 ym m = − 2√ym i −ym i+1 , i−1 m y = 2√ym i −ym i+1 i−1 Totalt: yim+1 q m+1 m+1 yi+1 − yi−1 ≈ yim + p p m m − y m − √ yi δyi−1 yi+1 i−1 2 y m −y m i+1 i−1 m m − y m · δy + √ yi yi+1 δyi+1 i i−1 2 y m −y m i+1 i−1 m+1 m+1 yi−1 , yi m+1 Merk at uttrykket nå er lineært da og yi+1 bare inngår i 1. potens. Vi setter dette inn i (4.130) som nå blir lineær: ym ym m+1 m+1 1 − α 2gim · yi−1 − (2 − αg m ) · yim+1 + 1 + α 2gim · yi+1 ym m m = α 2gim (yi+1 − yi−1 ) der g m = (4.131) p m m yi+1 − yi−1 I neste avsnitt viser vi hvordan vi kan operere direkte med delta-størrelsene m+1 m+1 δyi−1 , δyim+1 og δyi+1 Hvordan vil disse eksemplene bli dersom vi bruker q metoden med etterslep? m+1 m+1 Lign. (4.3.3)) i eksempel (4.3.3) skrives: yi−1 +(h2 yim+1 −2)·yim+1 +yi−1 =0 q m+1 m+1 Koeffisienten foran yi -leddet inneholder yi som blir erstattet med p m p m m+1 m+1 m+1 2 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 m+1 yi−1 − 2yim+1 + yi+1 = −h2 sin(yim ) = 0 Lign. (4.130)) q i eksempel (4.3.5) skrives: m+1 yi−1 + (α · m+1 m+1 m+1 yi+1 − yi−1 − 2) · yim+1 + yi+1 =0 q m+1 m+1 Koeffisienten foran yim+1 -leddet inneholder yi+1 som erstattes − yi−1 p m m med yi+1 − yi−1 slik at ligningen blir: m+1 yi−1 + (α · p m m − 2) · y m+1 + y m+1 = 0 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 langsommere 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, ... der N er antall beregningspunkt (4.132) 1. Test for absolutte størrelser. ta1 = max(|δyi |) < tola (4.133) N 1X |δyi | < tola ta2 = n i=1 v uN X 1u ta3 = t (δyi )2 < tola n i=1 2. Test for relative størrelser. δyi tr1 = max m+1 < tolr , yim+1 6= 0 yi PN |δyi | tr2 = PNi=1 m+1 < tolr y i=1 tr3 = (4.134) (4.135) (4.136) (4.137) i max(|δyi |) < tolr max(|yim+1 |) (4.138) 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) : y 00 (x) = 3 2 y 2 y(0) = 4 , y(1) = 1 (4.139) (4.140) CHAPTER 4. FINITE DIFFERENCES FOR ODES 195 4 ys yII 2 0 ys ,yII −2 −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. 1 2 3 4 5 6 7 8 9 tr2 7.25 · 10−1 8.70 · 10−1 8.49 · 10−1 4.96 · 10−1 2.10 · 10−1 4.62 · 10−2 2.24 · 10−3 4.68 · 10−6 2.26 · 10−11 tr3 7.55 · 10−1 8.20 · 10−1 6.65 · 10−1 5.85 · 10−1 2.80 · 10−1 6.07 · 10−2 2.70 · 10−3 5.79 · 10−6 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 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 yim+1 . −(2 + 3y1m h2 )δy1 + δy2 δyi−1 − (2 + 3yim h2 )δyi + δyi+1 = −(y2m − 2y1m + 4) + 23 (y1m h)2 m m = −(yi+1 − 2yim + yi−1 ) + 23 (yim h)2 3 m 2 m m = −(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: m 2 δyN −1 − (2 + 3yN h )δyN 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) g(x, y, y 0 , y 00 ) ≡ y 00 (x) − f (x, y, y 0 ) = 0 (4.144) Skriver (4.143) på formen: Setter 0 0 00 00 δy = ym+1 − ym , δy 0 = ym+1 − ym , δy 00 = ym+1 − 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 ∂y δy + m ∂g ∂y 0 ∂g δy + ∂y 00 m (4.146) 0 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 ∂g 0 δy + δy + δy 00 = 0 ∂y m ∂y 0 m ∂y 00 m (4.147) Ved derivasjon av (4.144): ∂g ∂f ∂g ∂f ∂g =− , =− 0 , =1 ∂y ∂y ∂y 0 ∂y ∂y 00 (4.148) m δy 00 CHAPTER 4. FINITE DIFFERENCES FOR ODES 198 som innsatt i (4.147) gir: 00 δy = ∂f ∂y δy + m ∂f ∂y 0 δy 0 (4.149) m Ved å sette inn fra (4.145) i (4.149) samt bruk av (4.143), får vi: ∂f ∂f 00 0 ym+1 − ·y − · ym+1 ∂y 0 m m+1 ∂y m (4.150) 0 = f (x, ym , ym )− ∂f ∂y · ym − m ∂f ∂y 0 0 · ym m Skriver tilslutt (4.150) med vår vanlige notasjon med iterasjonsnummer oppe: ∂f ∂f 0 m+1 00 m+1 · (y ) − · y m+1 (y ) − 0 ∂y m ∂y m (4.151) ∂f ∂f · ym = f (x, y m , (y 0 )m ) − · (y 0 )m − ∂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: (y 000 )m+1 − ∂f ∂y 00 · (y 00 )m+1 − ∂f ∂y 0 m = f (x, y m , (y 0 )m , (y 00 )m ) − − ∂f ∂y 0 0 m · (y ) − m · (y 0 )m+1 − ∂f ∂y 00 ∂f ∂y ∂f ∂y · y m+1 m · (y 00 )m m · (y)m m (4.152) 4.3.9 Example: 1) Ligningen y 00 (x) = Her blir ∂f ∂y 0 =0, ∂f ∂y 3 2 y 2 = 3y som innsatt i (4.151) gir: 3 (y 00 )m+1 − 3y m · y m+1 = − (y m )2 2 Ved å diskretisere med sentraldifferanser yi00 ≈ differanseligning: yi+1 −2yi +yi−1 h2 : får vi følgende CHAPTER 4. FINITE DIFFERENCES FOR ODES 199 3 m+1 m+1 = − (hyim )2 − (2 + 3h2 yim )yim+1 + yi+1 yi−1 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 ) Lign. (4.152) gir med ∂f ∂y 00 = −y , ∂f ∂y 0 = 2βy 0 og ∂f ∂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 = −β 1 + [(y 0 )m ] 2 + 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 differansemetode Test av kapittel 3 avsnitt 5 4.5 Differential boundary conditions/von Neumann 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 = xm 1 − ... 1 (4.153) CHAPTER 4. FINITE DIFFERENCES FOR ODES R P 200 R0 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: 1 d2 W 1 dW P d3 W + − 2 = 3 2 dR R dR R dR 2πD · R (4.154) 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: W (R0 ) = dW (0) = 0 dR dW (R0 ) = 0, dR (4.155) 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 = , dr3 r dr2 r dr r 0<r<1 (4.156) and Eq. (4.155): ω(1) = dω (1) = 0, dr The analytical solution is given by: dω (0) = 0 dr (4.157) CHAPTER 4. FINITE DIFFERENCES FOR ODES ω(r) = r2 [2 ln(r) − 1] + 1, dω (r) = 4 r ln(r) dr 201 (4.158) 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): 8 d2 φ 1 dφ φ + − 2 =− , dr2 r dr r r (4.159) 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)] dr r dr (4.161) 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: 48 6 b) Solutions: φ1 = 142 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 27 Solutions: ω0 = 105 = 0.8953, ω1 = 61 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 import import import scipy scipy.linalg scipy.sparse 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 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() 203 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 Du ∂u ∂u ∂u 1 ∂p ∂ u ∂2u ≡ +u +v =− +ν + 2 Dt ∂t ∂x ∂y ρ ∂x ∂x2 ∂y 2 ∂v ∂v ∂v 1 ∂p ∂ v ∂2v Dv ≡ +u +v =− +ν + 2 Dt ∂t ∂x ∂y ρ ∂y ∂x2 ∂y 2 ∂T ∂T ∂T ∂ T ∂2T DT ≡ +u +v =α + Dt ∂t ∂x ∂y ∂x2 ∂y 2 (5.1) (5.2) (5.3) 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 = f (x, y) 2 ∂x ∂y 204 (5.4) CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 205 Laplace for f (x, y) = 0 Potensialteori, stasjonær varmeledning, osv. Endimensjonal diffusjonsligning. ∂2u ∂u =α 2 ∂t ∂x Bølgeligningen, akustisk grunnligning. (5.5) 2 ∂2u 2∂ u = α (5.6) 0 ∂t2 ∂x2 1. ordens lineær bølgeligning ( konstant). Transportligning, adveksjonsligninga ∂u ∂u + α0 =0 ∂t ∂x Ikke-viskøs Burgers ligninng. Modell for Eulerligningene. (5.7) ∂u ∂u +u =0 ∂t ∂x Burgers ligning. Modell for inkompressibel Navier-Stokes ligninger. (5.8) ∂u ∂u ∂2u +u =ν 2 ∂t ∂x ∂x Tricomi-ligningen. Modell for transonisk strømning. y ∂2u ∂2u + 2 =0 ∂x2 ∂y (5.9) (5.10) Konveksjon-diffusjonsligningen. Kalles også lineær Burgers ligning. Modellerer en rekke av tilfellene ovenfor. ∂u ∂2u ∂u + 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() som er en 1. ordens Dt partiell differensialligning (PDL). La oss derfor se nærmere på slike ved å betrakte følgende ligning: Transportsiden av basisligningene består av leddet α ∂u ∂u +b +c=0 ∂x ∂y (5.12) 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 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: b ∂u ∂u a + +c=0 (5.13) ∂x a ∂y Ligningen er ikke-lineær dersom a eller b også er funksjoner av Antar at u er kontinuerlig deriverbar: du = ∂u ∂u du ∂u dy ∂u dx + dy → = + ∂x ∂y dx ∂x dx ∂y Definerer nå karakteristikken for (5.12) ved: dy b = dx a (5.14) (5.14) innsatt ovenfor gir: a b ∂u ∂u + ∂x a ∂y =a du 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. . ∂u Adveksjonsligningen (5.7) gitt ved ∂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 x 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 ∂u g(x, t) ± 1 = ∂x t · g(x, t) (5.16) (5.17) 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 med 4t 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 t 2.0 1.5 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 t = 12 1.0 t =1 u 0.8 0.6 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: A ∂2φ ∂2φ ∂2φ + B + C +f =0 ∂x2 ∂x∂y ∂y 2 (5.18) ∂φ 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 ∂φ ∂x ∂ 2 φ ∂φ − − exy sin φ = 0 kvasilineær ∂x2 ∂x ∂ 2 φ ∂φ x 2 − − exy sin φ = 0 semilineær ∂x ∂x 2 2 2 ∂ φ ∂ φ = 0 ikke-lineær 2 ∂x ∂y 2 210 (5.19) (5.20) (5.21) En PDL som kan skrives på formen ∂2φ ∂φ ∂2φ ∂2φ ∂φ +B +C 2 +D +E + Fφ + G = 0 (5.22) 2 ∂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. ∂φ ∂u ∂v Setter u = ∂φ ∂x og v = ∂y som impliserer at ∂y = ∂x . (5.18) kan da skrives som et system av to 1. ordens PDL: A A ∂u ∂u ∂v +B +C +f =0 ∂x ∂y ∂y ∂u ∂v − =0 ∂y ∂x (5.23) (5.24) 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: ∂u ∂u dv ∂v ∂v du = +λ , = +λ dx ∂x ∂y dx ∂x ∂y der vi har definert λ ved: λ= dy dx (5.26) (5.27) CHAPTER 5. MATHEMATICAL PROPERTIES OF PDES 211 Ved å sammenligne (5.25) og (5.26): dy B+σ C =λ= =− dx A σ (5.28) innsatt i (5.25) gir kompatibilitetsligningen (5.28) du dv −σ +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): A σ=− C λ (5.30) som også gir: B − Cλ A Følgende 2. gradsligning finnes fra (5.31) for bestemmelse av λ: λ= (5.31) Aλ2 − Bλ + C = 0 (5.32) A · (dy)2 − B · dy · dx + C · (dx)2 = 0 (5.33) eller ved bruk av (5.27): 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 + +f =0 dx λ dx 2. gradsligningen (5.32) og (5.33) har røtter λ1 og λ2 der √ B ± B 2 − 4AC λ1,2 = 2A Vi har tre muligheter for røttene i (5.35): A • 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 • (5.34) (5.35) 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 − 2 = 0 er hyperbolsk da B 2 − 4AC = 4 > 0 KarakBølgeligningen ∂x2 ∂y dy 2 = ±1 teristikkene er gitt ved λ = 1 → dx 2 2 ∂ u ∂ u Laplace-ligningen + 2 = 0 er elliptisk da B 2 − 4AC = −4 < 0 ∂x2 ∂y ∂2u ∂u = Diffusjonsligningen er parabolsk da B 2 − 4AC = 0 ∂y ∂x2 Linearisert potensial-ligning for kompressibel strømning: (1 − M 2 ) ∂2φ ∂2φ + 2 = 0, M = Mach-tallet. ∂x2 ∂y (5.36) • 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 5.4.1 213 Hyberbolsk ligning Som eksempel bruker vi bølgeligningen: ∂2u ∂2u = α02 2 (5.40) 2 ∂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. Marching direction Open boundary t Region of influence P 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 ∂x2 ∂y (5.41) 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 y 214 n C Ω P Region of influence and region of dependency x Figure 5.6: Caption goes here. • u gitt på C: Dirichlet-betingelse ∂u gitt på C: Neumann-betingelse ∂n ∂u gitt: Blandet betingelse (Robin-betingelse) – u og ∂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 Open boundary 215 Marching direction t Region of influence P Characteristic Region of dependency a b x Figure 5.7: Caption goes here. 5.5 VELFORMULERT PROBLEM. OPPSUMMERING 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 Dirichlet, Neumann eller blandet type. Parabolsk PDL. Løsningsområdet må være åpent i marsjretningen (evolusjonsretningen). Initialdata må gis langs den tidslignende randen, og kontinuerlige randbetingelser må gis langs den fysiske randen for løsningsområdet. Randbetingelsene 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 initialverdiproblem. 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. . ~ , er elliptisk Bevegelsesligningene betraktet som en ligning for hastigheten V 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 parabolskhyperbolsk for ikke-stasjonær strømning og elliptisk-hyperbolsk for stasjonær strømning. Den hyperbolske karakteren skyldes i begge tilfeller kontinuitetsligningen. Merk at evolusjonskarakteren for systemet forsvinner for en inkompressibel fluid selv om strømningen er ikke-stasjonær. Rand- betingelsene for hele systemet stilles i utgangspunktet utfra betraktningene som er gitt ovenfor. 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 er hyperbolsk 2 ∂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: (u2 − a2 ) ∂u ∂v ∂u + (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 xog y-retning. Karakteristikkene er her gitt ved: √ √ dy uv ± a2 M 2 − 1 u2 + v 2 , der Machtallet M = = 2 2 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 diffusjonsproblem 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) ∂t ∂t2 ∂u ∂2u = iβ · u(x, t), = −β 2 · u(x, t) ∂x ∂x2 ∂3u ∂4u 3 = −β · u(x, t), = β 4 · u(x, t) ∂x3 ∂x4 (5.44) (5.45) (5.46) Diffusjonsligningen ∂2u ∂u =α 2 ∂t ∂x (5.47) Innsatt fra (5.46) i (5.47): (αβ 2 − iω) · u(x, t) = 0 → iω = αβ 2 som gir: u(x, t) = e−αβ 2 ·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 = a20 2 2 ∂t ∂x (5.51) 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 linearisert 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: u(x, t) = eiβ[x−(a0 −β 2 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 For tillfelle 2) og 3) blir fasehastigheten cf = 219 β · a0 = a0 uavhengig av β bølgetallet. Slike bølger kalles da ikke-dispersive. Svingende bjelke 4 EI ∂2u 2∂ u + a = 0, a2 = (5.56) 2 4 ∂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 dω = 2aβ 6= cf . er her gitt ved cf = a · β. Gruppehastigheten cg = dβ 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) ∇2 u = q (6.2) ∇2 u + c · u = q (6.3) • Poisson: • Helmholtz: where ∇2 = ∂2 ∂2 ∂2 + + in 3D ∂x2 ∂y 2 ∂z 2 220 CHAPTER 6. ELLIPTIC PDES and where ∇2 = 221 ∂2 ∂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 + + (6.5) ∂x2 ∂y 2 ∂z 2 ∂T = 0 , we get: which is a parabolic PDE, but at steady state when ∂t 2 ∂ T ∂2T ∂2T + + =0 (6.6) ∂x2 ∂y 2 ∂z 2 ∂T =α ∂t 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 twodimensions 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 • Neumann-condition: ∂u = G2 (x, y) on C ∂n • Robin-condition: a · u(x, y) + b · ∂u(x, y) = 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) ∂x i,j ∆x (6.7) Bakoverdifferanser: ∂u ui,j − ui−1,j = + O(∆x) ∂x i,j ∆x (6.8) Sentraldifferanser ui+1,j − ui−1,j ∂u = + O (∆x)2 ∂x i,j 2∆x ui+1,j − 2ui,j + ui−1,j ∂ 2 u = + O (∆x)2 2 2 ∂x i,j (∆x) Tilsvarende formler for Foroverdifferanser: ∂u ∂y og ∂2u ∂y 2 (6.9) (6.10) følger direkte: ui,j+1 − ui,j ∂u = ∂y i,j ∆y (6.11) ∂u ui,j − ui,j−1 = ∂y i,j ∆y (6.12) Bakoverdifferanser: Sentraldifferanser ∂u ui,j+1 − ui,j−1 = ∂y i,j 2∆y ∂ 2 u ui,j+1 − 2ui,j + ui,j−1 = 2 ∂y i,j (∆y)2 (6.13) (6.14) CHAPTER 6. ELLIPTIC PDES 6.2.1 224 Example: Discretization of the Laplace equation 2 Vi diskretiserer Laplace-ligningen ∂∂yu2 + velger ∆x = ∆y. Dette gir følgende differanseligning: ∂2u ∂y 2 = 0 ved å bruke (6.10)og (6.14) og 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 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 = ∂x i,j 2∆x (6.16) 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 ∂x2 ∂y 2 y 100 100 100 (6.17) 100 100 T1,5 T2,5 T3,5 0.0 0.0 T1,4 T2,4 T3,4 0.0 0.0 T1,3 1.5 T2,3 T3,3 0.0 0.0 0.0 0.0 0.0 T1,2 T2,2 T3,2 T1,1 T2,1 T3,1 0.0 0.0 0.0 0.0 0.0 0.0 x 1.0 Figure 6.4: (Dirichlet). Rectangular domain with prescribed values at the boundaries 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 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: Tm = Te + Tw + Tn + Ts 4 (6.20) 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 T = 100.0 at and y = 1.5 x=1 for 0 ≤ y < 1.5 (6.21) 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 1 −4 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 −4 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 −4 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 −4 0 0 −4 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 −4 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 −4 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 −4 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 −4 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 −4 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 −4 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 −4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 −4 1 1 −4 (6.24) The analytical solution of (6.17) and (6.21) may be found to be: T (x, y) = 100 · ∞ X An sinh(λn y) · sin(λn x) (6.25) n=1 where λn = π · n and An = 4 λ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 · T11 T12 T13 T14 T15 T21 T22 T23 T24 T25 T31 T32 T33 T34 T35 = 0 0 0 0 −100 0 0 0 0 −100 0 0 0 0 −100 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 + =0 2 ∂x ∂y 2 (6.26) CHAPTER 6. ELLIPTIC PDES 233 y T = 1.0 1.0 ∂T =0 ∂x ∇ 2T = 0 0.0 ∂T =0 ∂y T = 0.0 1.0 x Figure 6.7: Laplace-equation for a quadratic domain with von Neumann boundary conditions. with corresponding boundary conditions (von Neuman) ∂T =0 ∂x ∂T =0 ∂y for x = 0, and 0 < y < 1 (6.27) for y = 0, and 0 < x < 1 (6.28) 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 y j+1 T0,j T-1,j T1,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 = 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 approximation (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) which for 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 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 −4 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 −4 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 −4 0 0 0 1 0 0 0 0 0 0 0 0 2 0 0 0 −4 1 0 0 1 0 0 0 0 0 0 0 0 2 0 0 2 −4 1 0 0 1 0 0 0 0 0 0 0 0 2 0 0 1 −4 1 0 0 1 0 0 0 0 0 0 0 0 2 0 0 1 −4 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 −4 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 2 −4 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 −4 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 1 −4 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 −4 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 2 0 0 −4 1 0 1 −4 1 0 1 −4 (6.32) · T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 = 0 0 0 0 0 0 0 0 0 0 0 0 −1 −1 −1 −1 # 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: T6 T4 T2 1 T5 T3 T1 T3 1 T6 T4 T2 T4 1 0 0 0 -4 2 2 0 0 0 1 -4 0 2 0 0 1 0 -4 2 1 0 --> A = 0 1 1 -4 0 1 0 0 1 0 -4 2 0 0 0 1 1 -4 0 0 0 ,b = 0 -1 -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 T (x, y) = ∞ X An cosh(λn y) · cos(λn x), 238 (6.33) n=1 der λn = (2n − 1) · π (−1)n−1 , An = 2 , n = 1, 2, . . . 2 λn cosh(λn ) (6.34) 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: conditions. 6.4 Solution of the Laplace equation with von Neuman boundary Iterative methods for linear algebraic equation 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 m m [b1 − (a11 xm 1 + a12 x2 + a13 x3 )] a11 1 m m = xm [b2 − (a21 xm 2 + 1 + a22 x2 + a23 x3 )] a22 1 m m = xm [b3 − (a31 xm 3 + 1 + a32 x2 + a33 x3 )] a33 = xm xm+1 1 + 1 (6.38) xm+1 2 (6.39) xm+1 3 (6.40) 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 m thus xm+1 = xm i , i.e. convergence is obtained. Whenever, xi is not a solution i 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 = xm i + δxi i n X 1 , i = 1, 2, . . . , n, m = 0, 1, . . . δxi = bi − aij xm j aii j=1 (6.41) (6.42) 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 in the second equation and for xm+1 and xm+1 in the third equation, 1 1 2 to yield: Gauss-Seidel’s method 1 m m [b1 − (a11 xm 1 + a12 x2 + a13 x3 )] a11 1 m = xm [b2 − (a21 xm+1 + a22 xm 2 + a23 x3 )] 2 + 1 a22 1 = xm [b3 − (a31 xm+1 + a32 xm+1 + a33 xm 3 + 3 )] 1 2 a33 xm+1 = xm 1 + 1 (6.43) xm+1 2 (6.44) xm+1 3 (6.45) The successively improved Jacobi’s method, is normally referred to as GaussSeidel’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 ω m m [b1 − (a11 xm 1 + a12 x2 + a13 x3 )] a11 ω m = xm + a22 xm [b2 − (a21 xm+1 2 + 2 + a23 x3 )] 1 a22 ω = xm + a33 xm + a32 xm+1 [b3 − (a31 xm+1 3 + 3 )] 2 1 a33 xm+1 = xm 1 + 1 xm+1 2 xm+1 3 (6.46) A general version of (6.46) may be presented: xm+1 = xm i + δxi i " !# i−1 n X X ω m+1 m δxi = bi − aik xk + aik xk , i = 1, 2, . . . , n, aii k=1 (6.47) (6.48) 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 = um i,j + δui,j i,j ω m+1 m m m 2 δui,j = u + um+1 i,j−1 + ui+1,j + ui,j+1 − 4ui,j − h · fi,j 4 i−1,j (6.52) (6.53) CHAPTER 6. ELLIPTIC PDES 241 The scheme in (6.53) may be reformulated by introducing the residual Ri,j m+1 m m m 2 Ri,j = um+1 (6.54) i−1,j + ui,j−1 + ui+1,j + ui,j+1 − 4ui,j − h · fi,j 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 = um i,j + i,j ω Ri,j 4 (6.55) We will now solve the example in Figure 6.4, 6.3, with the iterative SORscheme 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 T1,3 T1,2 m Ti,j T2,3 T2,2 T3,2 T1,1 T2,1 T3,1 T4,1 T5,1 m Ti+1,j Tm+1 i,j-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 < εr • max Ti,j • The residual Ri,j (6.54) may also be used • Other alternatives: 1 X X δTi,j 1 XX |δTi,j | < tola , < tolr , |Ti,j | = 6 0 N i j N i j Ti,j (6.56) 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) |T | max (|Ti,j |) i,j i 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 iterasjoner 200 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 der nx og ny blir antall deler i henholdsvis x- og y-retning. nx = , ny = h h nx og ny skal være heltall. Den teoretisk optimale ω er da gitt ved: 1 [cos(π/nx ) + cos(π/ny )] 2 2 p ω= 1 + 1 − ρ2 ρ= (6.58) (6.59) 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 ) 1 + (hx /hy )2 (6.60) Dersom området ikke er rektangulært, kan vi bruke Garabedians estimat: ω= 2 √ , A er arealet av området 1 + 3.014 · h/ A (6.61) La oss regne ut ω fra disse formlene for eksemplet der Lx = 1, Ly = 1.5 og A = Lx · Ly = 1.5. h 0.25 0.125 0.0625 0.03125 (6.59) 1.24 1.51 1.72 1.85 (6.61) 1.24 1.53 1.74 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,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 er vist i programmet P P T1,1 = |δT | i,j 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 y 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 conditions. % 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 0.25 0.125 0.0625 0.03125 (6.59) 1.17 1.45 1.67 1.82 (6.61) 1.14 1.45 1.68 1.83 Vi ser at tabell-verdiene stemmer godt med verdiene i figur 6.14 når startverdien 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 h = 0.125 1.7 ωopt 1.6 h = 0.25 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 startverdier 0.52 Figure 6.14: The effect of intial values on the number of iterations for a problem with sub-optimal ω. ∂2u ∂2u + 2 + u2 = −1 ∂x2 ∂y (6.63) with Dicichlet boundary conditions, i.e precribed values u = 0 on all boundaries (see Figure 6.15). y u=0 1.0 u=0 0.0 ∇2u + u2 = -1 u=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 u1,4 = 0 u1,3 = 0 u1,2 = 0 u2,4 u3,4 u4,4 u2,3 u3,3 u4,3 u2,2 u3,2 u4,2 u5,4 = 0 u5,3 = 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 = um i,j + δui,j i,j δui,j = −ω f (uk,l ) ∂f (uk,l ) ∂ui,j (6.65) (6.66) where: uk,l = um+1 for k < i, l < j k,l uk,l = um k,l ellers (6.67) (6.68) CHAPTER 6. ELLIPTIC PDES 251 and ∂f = −4 + 2h2 · ui,j ∂ui,j and δui,j = ω f 4 − 2h2 ui,j (6.69) 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 max ui,j (6.70) 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 0.25 0.125 0.0625 0.03125 ωest 1.17 1.45 1.67 1.82 ωopt 1.19 1.46 1.69 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 omega=1.85 Python Gauss-Seidel CPU-time: Jacobi CPU-time: Cython Gauss-Seidel CPU-time: 254 1.62. 0.04. 0.97. Nr. iterations 56 Nr. iterations 492 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-arrayslicing Jacobi scheme converge slower than the Gauss-Seidel scheme in terms of iterations, and need apporximately 10 times as many iterations as the Gaussseidel 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 6.4.6 @ git@lrhgit/tkt4140/src/src-ch7/nonlin_poisso 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 a22 0 0 , −L = D = 0 0 a33 0 0 0 0 a44 0 0 −U = 0 0 0 a12 a13 0 0 a23 0 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: 0 a21 a31 a41 0 0 a32 a42 0 0 0 a43 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: a14 a24 a34 0 CHAPTER 6. ELLIPTIC PDES 255 xm+1 = D−1 (L + U)xm + D−1 b (6.73) GJ = D−1 (L + U) (6.74) Setter: 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) GGS = (D − L)−1 U (6.76) Setter: 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) em = Gem−1 = G2 em−2 = G3 em−3 = · · · = Gm e0 (6.84) Derav følger: m der e er feilvektoren i den første iterasjonen, altså forskjellen mellom startverdiene 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 spektralradien 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 forutsetningen 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: e0 = c1 v1 + c2 v2 + · · · + cn vn = n X ck vk k=1 der ck , k = 1, 2, . . . , n er skalarer Nå får vi: e1 = Ge0 = c1 Gv1 + c2 Gv2 + · · · + cn Gvn = n X k=1 ck Gvk (6.87) 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: e1 = n X ck λk vk k=1 Dette er for den første iterasjonen. For den m’te iterasjonen: em = n X 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 m m m m m em =c1 λm 1 v1 + c2 λ2 v2 + · · · + cn λn vn → ||e || ≤ ||c1 λ1 v1 || + ||c2 λ2 v2 || + · · · + ||cn λm n vn || m m λn λ2 m =|λ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 || ≈ ρk ||em || → ||em+k || ≈ ρk ||em || (6.92) Vi ønsker spesielt å finne for hvilken verdi av k er ||em+k || en tiendepart av ||em ||: ||em+k || 1 = ≈ ρk m ||e || 10 Ved bruk av den Briggske logaritmen i (6.93): (6.93) 1 (6.94) log10 (ρ) k angir hvor mange iterasjoner vi må utføre for å vinne ett desimalsiffer. Størrelsen k≈− 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 konvergens. 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 a11 0 GJ = − 0 0 0 aa21 22 =− a31 a33 a41 a44 0 1 a2 0 0 a12 a11 0 a32 a33 a42 a44 0 0 1 a3 0 a13 a11 a23 a22 0 a43 a44 0 0 a21 0 · 0 a31 1 a41 a44 a14 a11 a24 a22 a34 a33 0 a12 0 a32 a42 a13 a23 0 a43 a14 a24 a34 0 CHAPTER 6. ELLIPTIC PDES 259 En matrise A kalles strengt diagonaldominant dersom: |ai,j | > n X |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): |λ| < ||GJ ||∞ = max 1≤i≤n n X |Gi,j | < 1 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 −1 3 −1 0 0 x1 x2 0 · −1 x3 2 x4 0 −1 3 −1 −1 4 = 7 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: D = 2 0 0 0 0 3 0 0 0 0 3 0 0 0 0 2 , −U = 0 0 0 0 −1 0 0 0 0 −1 0 0 0 0 −1 0 0 −1 0 0 −L = 0 0 −1 0 0 0 0 −1 Videre får vi: D−L= 2 −1 0 0 0 3 −1 0 0 0 3 −1 0 0 0 2 , (D − L)−1 = 1 2 1 6 1 18 1 36 0 1 3 1 9 1 18 0 0 1 3 1 6 Iterasjonsmatrisa GGS i (6.76) blir nå: 0 0 0 0 GGS = (D − L)−1 U = 1 2 1 6 1 18 1 36 0 0 0 1 3 1 9 1 18 1 3 1 6 Beregner egenverdiene av iterasjonsmatrisa: det(GGS − λI) = det −λ 0 0 0 1 6 1 2 0 −λ 1 18 1 36 1 9 0 0 1 3 −λ 1 18 1 6 1 3 −λ =0 0 0 0 1 2 0 0 0 0 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: x1 x2 x3 x4 m+1 = 0 0 0 0 1 2 1 6 1 18 1 36 0 1 3 1 9 1 18 0 0 1 3 1 6 m − 1 x1 2 x2 76 + 49 · , m = 0, 1, . . . x3 x4 18 49 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 0.0833 2.2685 0.6343 2.7258 0.8629 2.8985 0.9492 2.9625 0.9812 2.9861 0.9931 2.9949 0.9974 2.9981 0.9991 2.9993 0.9997 2.9997 0.9999 2.9999 1.0000 3.0000 >> 2.7222 3.5432 3.8325 3.9382 3.9772 3.9916 3.9969 3.9989 3.9996 3.9998 3.9999 4.0000 1.3611 1.7716 1.9162 1.9691 1.9886 1.9958 1.9984 1.9994 1.9998 1.9999 2.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 for små h 2 (6.97) ρ = cosh2 (πh) ≈ 1 − (πh)2 for små h (6.98) ρ = cosh(πh) ≈ 1 − Gauss-Seidels metode: 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. ρ= Spektral radius ρJ ρGS ρSOR 1 h = 32 0.9952 0.9904 0.8215 1 h = 64 0.9988 0.9976 0.9065 1 h = 128 0.9997 0.9994 0.9521 Dette vises enda tydligere når vi beregner antall iterasjoner som behøves for å vinne ett desimalsiffer, se lign. (6.94). Iterasjoner kJ kGS kSOR 1 h = 32 477 239 12 1 h = 64 1910 955 23 1 h = 128 7644 3822 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 sjakkbrettnummerering, 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 = 0 langs denne linja, men det er selvfølgelig ikke ∂x 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 1 −4 1 0 0 0 1 0 1 −4 1 0 0 0 1 0 0 0 1 −4 1 0 0 0 0 0 0 1 −4 0 0 0 2 0 0 0 0 −4 1 0 0 2 0 0 0 1 −4 1 0 0 2 0 0 0 1 −4 0 0 0 0 0 0 2 0 0 2 0 0 0 0 1 0 0 0 0 1 0 0 0 1 −4 1 0 0 0 0 1 0 0 0 1 −4 T11 T12 T13 T14 · T15 T21 T22 T 23 T24 T25 = 0 0 0 0 −100 0 0 0 0 −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 y 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 ∂x2 ∂y 2 (6.101) 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 C 15 14 11 13 14 10 11 12 6 7 8 9 1 2 3 4 5 0.0 0.0 0.0 0.0 B 7 2 0.0 A 14 13 11 8 4 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 med ∆x = ∆y = h Vi har valgt h = 0.1 i figur 6.18. Beregningsmolekylet med enkle indekser: ud ua um uc ub Figure 6.19: Numerical stencil forthe problem in 6.17. (6.102) 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 1 0 0 0 0 0 0 0 1 −4 1 1 −4 1 0 0 1 0 0 0 0 0 0 0 0 0 1 −4 1 0 0 1 0 0 0 0 0 0 0 0 2 −4 0 0 0 1 0 0 0 0 0 2 0 0 0 −4 2 0 0 0 0 0 0 0 0 1 0 0 1 −4 1 0 1 0 0 0 0 0 0 1 0 0 1 −4 1 0 1 0 0 0 0 0 0 1 0 0 2 −4 0 0 1 0 0 0 0 0 0 2 0 0 −4 2 0 0 0 0 0 0 0 0 0 0 1 0 1 −4 1 1 0 0 0 0 0 0 0 0 1 0 2 −4 0 0 0 0 0 0 0 0 0 0 0 2 0 −4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 2 0 0 0 0 0 0 0 0 0 0 0 0 1 2 −4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 1 −4 u 1 u2 u3 u4 u5 u 6 u7 · u 8 u9 u10 u11 u12 u 13 u14 u15 (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 % === Update A === -1 0 1 2 3 4], n,n); % --- 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. = − h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 h2 CHAPTER 6. ELLIPTIC PDES u1 = u(0.1, 0.1) u2 = u(0.2, 0.1) u3 = u(0.3, 0.1) u4 = u(0.4, 0.1) u5 = u(0.5, 0.1) u6 = u(0.2, 0.2) u7 = u(0.3, 0.2) u8 = u(0.4, 0.2) u9 = u(0.5, 0.2) u10 = u(0.3, 0.3) u11 = u(0.4, 0.3) u12 = u(0.5, 0.3) u13 = u(0.4, 0.4) u14 = u(0.5, 0.4) u15 = u(0.5, 0.5) 0.0128 0.0206 0.0254 0.0280 0.0288 0.0343 0.0430 0.0478 0.0493 0.0544 0.0608 0.0629 0.0682 0.0706 0.0731 265 0.0131 0.0209 0.0256 0.0282 0.0290 0.0346 0.0433 0.0482 0.0497 0.0548 0.0613 0.0634 0.0687 0.0712 0.0737 De analytiske verdiene er beregnet fra: u=ζ· ∞ X 4 (1 − ζ) − 3 2 π n=1,3,5,... 1 cosh(nπ ȳ) · sin(nπζ) n3 cosh nπ 2 1 1 1 , ȳ = y − 2 , ζ = 2 − x̄, (x, y) ∈ [0, 1]. 2 Bytt om x̄ og ȳ dersom ȳ > x̄ der x̄ = x − (6.105) (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: ∂2u ∂u =α 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): ∂2u ∂u =ν 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): A ∂2φ ∂2φ ∂2φ +B +C 2 +f =0 2 ∂x ∂x∂y ∂y A · (dy)2 − B · dy · dx + C · (dx)2 = 0 B± (7.3) √ B 2 − 4AC 2A B = C = 0 and A = 1 which by substitution in (5.33) and (5.35) yield: λ1,2 = (7.2) dt = 0, B 2 − 4AC = 0 266 (7.4) 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: U (0, τ ) = U (b, τ ) = U0 0 o =τ ≥0 (7.7) 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= Y U τν , u= , t= 2 b U0 b (7.9) which allow (7.6) to be written: ∂u ∂2u = , 0<y<1 ∂t ∂y 2 with the corresponding boundary conditions: u(0, t) = u(1, t) = 1 0 o , t≥0 (7.10) (7.11) 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: ∞ u(y, t) = 1 − y − 2 X1 · exp[−(nπ)2 t] sin(nπy) π n (7.13) 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: un+1 − un ∂u n j j ≈ ∂t j ∆t (7.14) and central differences for the spatial coordinate y: n n un ∂2u j+1 − 2uj + uj−1 ≈ 2 2 ∂y (∆y) (7.15) 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: n n = D (un un+1 j+1 + uj−1 ) + (1 − 2D) uj j (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 ∆τ =ν (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 . D= # 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 n 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 0.8 y [-] D = 0.4 1.0 0.6 increasing time 0.4 0.2 0.0 D = 0.45 0.8 y [-] D = 0.45 1.0 0.6 0.4 0.2 0.0 D = 0.5 0.8 y [-] D = 0.5 1.0 0.6 0.4 0.2 0.0 D = 0.503 0.8 y [-] D = 0.503 1.0 0.6 0.4 0.2 0.0 D = 0.51 0.8 y [-] D = 0.51 1.0 0.6 0.4 0.2 0.0 0.0 0.2 0.4 0.6 Velocity [-] 0.8 1.0 Figure 7.3: Numerical solutions of the FTCS-scheme for various diffusion numbers D with a constant ∆y = 0.02. CHAPTER 7. DIFFUSJONSPROBLEMER 7.3 272 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 ) xmax = max(x1 , x2 , . . . , xk ) and (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): n n un+1 = D (un j+1 + uj−1 ) + (1 − 2 D) uj j 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 n n n n min(un ≤ max(un j+1 , uj , uj−1 ) ≤ uj j+1 , uj , uj−1 ) Meaning that un+1 is restricted by the extrema of un j , i.e. all the solutions at the previous j 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: D≤ 1 2 (7.22) 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 (∆x)2 and with the following coefficients a1 = a2 = D og a3 = 1 − 2D + ∆t · b we get: n n ) + (1 − 2D + ∆t · b)Tjn , + Tj−1 Tjn+1 = D (Tj+1 D=α 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 0<D< 1 ∆t · b + 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: ∂2u ∂u = (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), = f (t) 2 ∂t dt ∂x dx2 g(x) (7.26) which upon substitution in (7.25) results in the following equation: d2 g(x) df (t) g(x) = f (t) dt dx2 (7.27) 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) df (t) 1 = −β 2 → + β 2 f (t) = 0 dt f (t) dt (7.29) d2 g(x) 1 d2 g(x) = −β 2 → + β 2 g(x) = 0 dx2 g(x) dx2 (7.30) The first ODE (7.29) is of first order and has the solution (verify by susbtitution): f (t) = e−β 2 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): u(x, t) = e−β 2 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=∞ u(x, t) = X 2 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: u(x, t) = 2 e−β t sin(βx) 2 e−β t cos(βx) (7.34) 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: u(x, t) = e−β 2 t i βx e = e−β 2 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: u(xj , tn ) = e−β 2 tn ei βxj = e−β 2 n ∆t iβxj e = (e−β 2 ∆t n iβxj ) e (7.37) 2 ∆t n+1 iβxj (7.38) and the solution at location xj at the next timestep n + 1 is: u(xj , tn+1 ) = e−β 2 tn+1 ei βxj = e−β 2 (n+1) ∆t iβxj e = (e−β ) e 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): Ga = 2 u(xj , tn+1 ) = e−β ∆t u(xj , tn ) (7.39) 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: i βxj u(xj , tn ) = (Ga )n ei βxj ≡ Gn a e (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 (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): n n un+1 = D (un j+1 + uj−1 ) + (1 − 2D)uj , j D= n n i βxj un j → Ej = G e (7.42) where we have introduced the numerical ampflicication factor G: G= Ejn+1 Ejn (7.43) 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 condition In this example we will demonstrate how the von Neumann method may be used on the simple scheme (7.16) on the following form: n n Ejn+1 = D (Ej+1 + 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) where we introduce δ as: (7.47) δ = β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 cos(x) = 1 − 2 sin2 ( x2 ) (7.49) By substitution (7.49) in (7.47) we get the simpler expression: δ (7.50) 2 As G is real, the condition |G| ≤ 1 has the following mathematical interpretation: G = 1 − 2D (1 − cos(δ)) = 1 − 4D sin2 CHAPTER 7. DIFFUSJONSPROBLEMER −1 ≤ G ≤ 1 277 − 1 ≤ 1 − 4D sin2 or δ 2 ≤1 (7.51) 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 D≤ 1 2 sin2 ( 2δ ) which is true for all δ ( −π ≤ δ ≤ π) when D ≤ of (7.16) may then be presented as: 0<D< 1 . 2 A von Neumann condition for stability 1 2 (7.52) ∆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 2 increase in CPU-time by a factor T = 1000. T 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 dG and then set it to dδ dG = 0. A stability condition may then be found from the criterion |G| < 1. For the current dδ example we have from (7.50): G = 1 − 2D (1 − cos(δ)) ⇒ dG = −2D sin(δ) dδ 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: δ (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 δ. G = 1 − 2D (1 − cos(δ)) = 1 − 4D sin2 1.0 G 0.5 0.0 Ga G Ga G Ga G −0.5 −1.0 0 20 (D = 0.25) (D = 0.25) (D = 0.35) (D = 0.35) (D = 0.5) (D = 0.5) 40 60 80 100 [degrees] 120 140 160 180 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 7.5.1 Flere skjema for parabolske ligninger 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 un+1 − ujn−1 ∂u n j ≈ ∂t j 2∆t som gir følgende differanseligning: n n un+1 = ujn−1 + 2D un j−1 − 2uj + uj+1 j (7.56) Dette er et eksplisitt, 3-nivå skjema som kalles Richardson-skjemaet; se Figure 7.5. n+1 n 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 1) · (cos(δ) − dG 2G dG = 4D (cos(δ) − 1) − G sin(δ) , som med dG =0 dδ dδ dδ 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 7.5.2 280 Dufort-Frankel skjemaet (1953) Richardson-skjemaet i (7.56) kan gjøres stabilt ved følgende modifikasjon: un j = 1 n+1 (u + ujn−1 ) 2 j (7.57) som innsatt i (7.56) gir: 1 n (7.58) (1 − 2D)ujn−1 + 2D(un j+1 + uj−1 ) 1 + 2D Dette er et eksplisitt 3-nivå skjema som kalles DuFort-Frankel-skjemaet, se Figure 7.6 un+1 = j n+1 n 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. (Leapfrog: 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 [(1 − 2r) + 4r · G · cos(δ)] (1 − 2r) + 2r · G · (eiδ + e−iδ ) = 1 + 2r 1 + 2r som gir følgende 2. grads ligning: G2 = (1 + 2D) · G2 − 4D · G cos(δ) − (1 − 2D) = 0 med løsning: G1,2 = 4D cos(δ) ± p (4D cos(δ))2 + 4(1 + 2D) · (1 − 2D) 2(1 + 2D) = 2D cos(δ) ± p 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 |G1,2 | ≤ 2D · | cos(δ)| + 1 − 4D2 sin2 (δ) 1 + 2r ≤ 1 + 2D ≤1 1 + 2D CHAPTER 7. DIFFUSJONSPROBLEMER 2. Komplekse røtter: 1 − 4D2 sin2 (δ) < 0 → |G1,2 |2 = 2 2D cos(δ) +4D 2 sin2 (δ)−1 (1+2D)2 281 p 1 − 4D2 sin2 (δ) = i · p 4D2 sin2 (δ) − 1 4D2 −1 2D−1 = 4D2 +4D+1 = 2D+1 < 1 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 av 2. ordens nøyaktighet ∂t der bare to tidsnivå inngår. Bruker sentraldifferanser for halve tidsintervallet: − un un+1 ∂u n+ 2 j j = + O(∆t)2 ∂t j ∆t 1 Problemet blir nå å approksimere (7.59) 1 ∂u n+ 2 uten at nivået n + 12 eksplisitt inngår i skjemaet. ∂t j Dette oppnås ved Crank-Nicolson approksimasjonen (1947): 1 1 ∂ 2 u n+ 2 = ∂x2 j 2 n+1 + un+1 un+1 j−1 j+1 − 2uj (∆x)2 + n n un j+1 − 2uj + uj−1 (∆x)2 + O(∆x)2 (7.60) Differanseligningen blir nå: un+1 j−1 − 2(1 + der D = 1 n 1 n+1 n + un+1 )u )u − un j+1 j+1 = −uj−1 + 2(1 − D j D j (7.61) ∆t 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: n+1 n+1 n n n + un+1 un+1 = un j + D θ(uj+1 − 2uj j j−1 ) + (1 − θ)(uj+1 − 2uj + uj−1 ) der 0 ≤ θ ≤ 1 (7.62) (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+½ n j-1 j j+1 Figure 7.7: Marit 1: description Med bruk av formlene i (7.49): G= 1 − 4D(1 − θ) sin2 ( 2δ ) (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 δ 2 D(1 − 2θ) ≤ (1 − 2θ) ≤ 1 eller 1 da sin2 2 δ 2 ≤1 For 21 ≤ θ ≤ 1 er betingelsen oppfylt for alle D ≥ 0, dvs.: Ubetinget stabil. For 0 ≤ θ ≤ 12 er skjemaet betinget stabilt. Stabilitetsbetingelsen er da: D(1 − 2θ) ≤ 1 , 0≤θ≤1 2 (7.65) Bruk av derivasjon Vi skriver nå: G = 1 + D(eiδ + e−iδ − 2) · (Gθ + 1 − θ) = 1 + 2D cos(δ) − 1 · (Gθ + 1 − θ) h dG i dG d = 2D (Gθ + 1 − θ) cos(δ) − 1 + cos(δ) − 1 θ · dδ dδ dδ dG = 0 får vi igjen max-min for δ = 0, δ = ±π (δ = 0 gir G = 1 som ventet) δ = ±δ dδ 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 Med CHAPTER 7. DIFFUSJONSPROBLEMER > > > > > > eq1:= eq2:= eq:= Tnj:= Tnj:= Tnj:= 283 u(x+h,t+k) - 2*u(x,t+k) + u(x-h,t+k): u(x+h,t) - 2*u(x,t) + u(x-h,t): (u(x,t+k) - u(x,t))/k -(theta*eq1 + (1-theta)*eq2)/h^2: mtaylor(eq,[h,k]): simplify(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: Tjn = h 1 −θ 2 · ∆t − ∂4u 1 1 ∂6u (∆x)2 · + (∆t)2 (1 − 3θ) · + ... 12 ∂x4 6 ∂x6 i (7.66) Vi ser at Tjn = O(∆t) + O(∆x)2 for θ = 0 og 1, altså for henholdsvis Euler-skjemaet og Laasonen-skjemaet, mens Tjn = O(∆t)2 + O(∆x)2 for θ = Dersom vi legger til en linje 1 2 som er Crank-Nicolson skjemaet. Tnj:= simplify(subs(theta =(1-h^2/(6*k))/2,Tnj)); i programmet ovenfor, finner vi at Tjn = O(∆t)2 + O(∆x)4 dersom vi velger D = 1 6(1 − 2θ) 1 . 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. når D ≤ x 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 D=α 284 ∆t (∆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 G= For θ = 1 2 285 1 − 4D(1 − θ) sin2 ( 2δ ) 1 + 4D sin2 ( 2δ ) får vi: G= 1 − 2D sin2 ( 2δ ) 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 . 1 + 2D Fra (7.44) har vi: ved å velge δ = π = β · h som gir G = 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: G= 1 δ 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 + 4D sin2 un+1 = j 1 n+1 n n θD(un+1 (7.67) j−1 + uj+1 ) + (1 − θ)D(uj−1 + uj+1 ) + 1 − (1 − θ)2D 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 2 Fra von Neumann-analysen fant vi følgende betingelse fra (7.65): D · (1 − θ) ≤ (7.68) 1 (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. PKkriteriet 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 D · (1 − 2θ) ≤ 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: D · (1 − θ) ≤ 2−θ 4(1 − θ) (7.70) 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: ∂2T ∂T = α 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: T (x, t) = ebt · e−αβ 2 ·t cos(βx) = e(b−αβ 2 )·t cos(βx) (7.72) La oss bruke (7.72) til å bestemme en analytisk forsterkningsfaktor, se (7.39): Ga = 2 T (xj , tn+1 ) = exp (b − αβ 2 ) · tn+1 − (b − αβ 2 ) · tn = eb∆t · e−αβ ∆t T (xj , tn ) (7.73) Vi ser at det er leddet eb·∆t som får amplituden til å øke med positiv b. En rekkeutvikling for små ∆t: eb∆t = 1 + b · ∆t + b2 (∆t)2 + . . . 2 (7.74) Dersom vi bruker FTCS-skjemaet, får vi: n n ) + (1 − 2D)Tjn + ∆tbTjn + Tj−1 Tjn+1 = D(Tj+1 (7.75) med ∆t (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): D=α G = 1 − 4D sin2 Ved å sette D = 1 , 2 δ 2 + ∆t · b (7.77) 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 n n n un+1 = un j + D · (uj+1 − 2uj + uj−1 ) + a0 j ∆t ∆t (un − un j−1 ), D = α 2∆x j+1 (∆x)2 Bruker von Neumanns metode: G = 1 − 4D sin2 δ 2 + i · a0 ∆t sin(δ) ∆x som videre gir: |G|2 = 1 − 4D sin2 2 Velger igjen D = |G| = Vi har her brukt δ 2 2 ∆t sin(δ) ∆x + a0 = 1 − 4D sin2 2 δ 2 + a20 · D α · ∆t sin2 (δ) 1 : 2 r 1 − 2 sin2 2 δ 2 + a20 2α · ∆t · sin2 (δ) ≤ 1 + a20 2α · ∆t p x2 + y 2 ≤ |x| + |y| a2 0 , 2α 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 Beregninger. 7.6 7.6.1 Trunkeringsfeil, konsistens og konvergens 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, tn = n · ∆t = n · k, n = 0, 1, 2, . . . i = 0, 1, 2, . . . (7.80) (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) Tin finnes ved Taylor-utvikling. Noen rekkeutviklinger: n ≡ U (xi±h , tn ) = Uin ± h · Ui±1 ∂U n h2 ∂ 2 U n h3 ∂ 3 U n + · ± · + ... 2 ∂x i 2 ∂x i 6 ∂x3 i (7.83) Uin±1 ≡ U (xi , tn±k ) = Uin ± k · ∂U n k 2 ∂ 2 U n k 3 ∂ 3 U n + 2 · ∂t2 ± 6 · ∂t3 + . . . ∂t i i i (7.84) La oss som eksempel finne den lokale trunkeringsfeilen Tin for FTCS-metoden anvendt på diffusjonsligningen L(U ) = 0 der L(U ) = ∂U ∂2U − =0 ∂t ∂x2 Uin+1 − Uin Tin = F (Uin ) = − k n n Ui−1 − 2Uin + Ui+1 h2 (7.85) Innsatt fra (7.83) i (7.85): Tin = ∂U ∂2U − ∂t ∂x2 Tin = n i n h2 ∂ 4 U k ∂2U − + 2 2 ∂t 12 ∂x4 ∂U ∂2U Da − =0 ∂t ∂x2 k ∂2U h2 ∂ 4 U − 2 2 ∂t 12 ∂x4 + i k 2 ∂ 3 U n + O(k3 , h4 ) 6 ∂t3 i n + høyere ordens ledd (7.86) i (7.86) viser at Tin = O(k) + O(h2 ) som ventet. (7.86) kan også skrives: Tin = Ved å velge D = h2 · 12 6 k ∂2U ∂4U − h2 ∂t2 ∂x4 n + O(k2 ) + O(h4 ) i k 1 = , 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) Tin = k ∂2U h2 ∂ 4 U − 2 ∂t2 12 ∂x4 n → 0 for h og k → 0 i Dette betyr at FTCS -skjemaet er konsistent med diffusjonsligningen . CHAPTER 7. DIFFUSJONSPROBLEMER 7.6.4 289 Example: Consistency of the DuFort-Frankel scheme La oss se nærmere på DuFort-Frankel skjemaet fra avsnitt (7.5.2): Tin Uin+1 − Uin−1 n n − (U n+1 + U n−1 ) Ui−1 + Ui+1 i i − 2k Med bruk av rekkeutviklingene i (7.83) og (7.84): Tin = = ∂U ∂2U − + ∂t ∂x2 2 k h ∂2U ∂t2 n + i h2 h2 ∂ 4 U k2 ∂ 3 U − 6 ∂t3 12 ∂x4 n +O i k4 4 4 ,k ,h h2 (7.88) 2 k 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): P.g.a faktoren Tin = ∂U ∂2U ∂2U − + r02 · ∂t ∂x2 ∂t2 n + O(h2 ) i For h → 0, ser vi at DuFort-Frankel skjemaet nå er konsistent med den hyperbolske ∂2U ∂U ∂2U + 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 ligningen Tin = h h ∂U ∂t − ∂2U ∂x2 in 2 = r02 h2 ∂∂tU 2 + h 2 + r02 h2 ∂∂tU 2 + i k2 ∂ 3 U 6 ∂t3 − da h2 ∂ 4 U 12 ∂x4 k2 ∂ 3 U 6 ∂t3 n i i − h2 ∂ 4 U 12 ∂x4 in +O i + O r04 h6 , k4 , h4 ∂2U ∂U − ∂T ∂x2 k4 , k 4 , h4 h2 n =0 i O(k2 ) Vi ser at Tin → 0 for h og t → 0 med Tin = + O(h2 ). 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 ∆x,∆t→0 → U for gitt tn og xi 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 ∂ u ∂ u Dersom vi transformerer diffusjonsligningen ∂u = ∂∂xu 2 + ∂y 2 + ∂z 2 til henholdsvis sylinder∂t 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: ∂2u 2 ∂u ∂u = + ∂t ∂r2 r ∂r Ligningene kan da skrives: ∂2u λ ∂u ∂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 n+1 n+1 n n n + un+1 un j + D θ(uj+1 − 2uj j−1 ) + (1 − θ)(uj+1 − 2uj + uj−1 ) (7.90) n+1 n n + λD θ(un+1 j+1 − uj−1 ) + (1 − θ)(uj+1 − uj−1 ) 2j 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: G · 1 + 4θD sin2 δ 2 −i· θλD sin(δ) j = 1 − 4(1 − θ)D · sin2 som ved bruk av formelen sin(δ) = 2 sin 1 − 4(1 − θ)D sin2 2 δ 2 + δ 2 cos δ 2 (1 − θ)2 λ2 D2 sin2 (δ) ≤ j2 δ 2 +i (1 − θ)λD sin(δ) j og betingelsen |G| ≤ 1 blir: 1 + 4θD sin2 2 δ 2 + θ2 λ2 D2 sin2 (δ) j2 og som videre gir: D · (1 − 2θ) · sin 2 δ 2 λ2 · 4− 2 j λ2 + 2 j ≤ 2, j ≥ 1 (7.91) CHAPTER 7. DIFFUSJONSPROBLEMER 291 δ = 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: Det er ikke vanskelig å se at leddet i parentesen har sin største verdi for sin2 D · (1 − 2θ) · 2 ≤ 1 Som i avsnitt (7.5.3), må vi skille mellom to tilfeller. 1. 1 0≤θ≤ 2 D= 2. 1 ∆t ≤ (∆r)2 2(1 − 2θ) (7.92) (7.93) 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 må behandles spesielt for r = 0. Leddet r ∂r L’Hopitals regel: λ ∂u ∂2u ∂u ∂2u =λ 2 → = (1 + λ) 2 for r = 0 (7.94) 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 (0) = 0: ∂r lim r→0 n = [1 − 2(1 + λ)D] · un un+1 0 + 2(1 + λ)D · u1 0 Dersom vi bruker PK-kriteriet på (7.95), får vi: (7.95) 1 (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 n n −3un ∂u 1 0 + 4u1 − u2 n (0) = 0 → → un (4un (7.97) 0 = 1 − u2 ) ∂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 D≤ 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 z 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 dp < 0, slik at hastighetsprofilet for det stasjonære tilfellet er det velkjente dz parabolske profilet for Poiseuille-strømning. Bevegelsesligning: ∂U 1 dp =− +ν ∂τ ρ dz ∂2U 1 ∂U + ∂R2 R ∂R (7.98) der hastighetsprofilet U = U (R, τ ). 0 ≤ R ≤ R0 , og τ er den fysikalske tiden. Dimensjonsløse variable: t=ν R2 dp Us τ R U der k = − 0 , r= , u = , us = 2 R0 k k 4µ dz R0 (7.99) som innført i (7.98) gir: ∂u ∂2u 1 ∂u =4+ + ∂t ∂r2 r ∂r (7.100) Randbetingelser: ∂u (0, t) = 0 ∂r Den siste er en symmetribetingelse. Finner stasjonær løsning us for u(±1, t) = 0, d2 us 1 dus 1 d + = −4 → dr2 r dr r dr r dus dr (7.101) ∂u ∂t = 0: = −4 som gir: 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: ω(r, t) = us − u(r, t) med ω = W k (7.103) Vi skal nå løse følgende problem: ∂ω ∂2ω 1 ∂ω = + ∂t ∂r2 r ∂r (7.104) Randbetingelser: ω(±1, t) = 0, ∂ω (0, t) = 0 ∂r (7.105) 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: n n ωjn+1 = ωjn + D · (ωj+1 − 2ωjn + ωj−1 )+ D n n · (ωj+1 − ωj−1 ) 2j (7.108) For j = 0 får vi fra (7.95): ω0n+1 = (1 − 4D) · ω0n + 4D · ω1n Fra (7.93) får vi stabilitetsintervallet 0 < D ≤ 12 for r > 0 og 0 < D ≤ 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 0.02 0.05 0.1 0.2 0.25 0.5 (7.109) 1 4 D 0.413 0.414 0.413 0.402 0.394 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 (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: ω0n = 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: −Dθ · 1 − 1 2j n+1 + (1 + 2Dθ) · ωjn+1 − Dθ · 1 + · ωj−1 1 2j n 1 = D(1 − θ) · 1 − 2j · ωj−1 + [1 − 2D(1 − θ)] · ωjn 1 n +D(1 − θ) · 1 + 2j n+1 · ωj+1 (7.112) · ωj+1 Initial values: ωj0 = 1 − rj2 = 1 − [∆r · j]2 , j = 0, . . . , N In addition we have that ωN = 0 for every n-values. (7.113) CHAPTER 7. DIFFUSJONSPROBLEMER 295 The system written in matrix form now becomes: 1 + 4Dθ −Dθ(1 − 0.5 ) 1 0 0 0 0 0 −4Dθ 1 + 2Dθ ) −Dθ(1 − 0.5 2 0 0 0 0 0 −Dθ(1 + 0.5 ) 1 1 + 2Dθ · 0 0 0 0 0 −Dθ(1 + · · 0 0 0 0 0 · · −Dθ(1 − 0 0 0 0.5 ) 0 2 0 · 0.5 ) 1 + 2Dθ N −2 ) −Dθ(1 − N0.5 −1 (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 algorithm for solving wn+1 . The function is part of the script/module startup.py which may be downloaded in your LiClipse workspace. 0 0 0 0 0 −Dθ(1 + N0.5 ) −2 1 + 2Dθ # 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 (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: ω0n = −Dθ · 1 − 1 2j n+1 · ωj−1 + (1 + 2Dθ) · ωjn+1 − Dθ · 1 + 1 2j n+1 · ωj+1 n 1 = D(1 − θ) · 1 − 2j · ωj−1 + [1 − 2D(1 − θ)] · ωjn 1 n +D(1 − θ) · 1 + 2j (7.116) · ωj+1 Now inserting Eq. (7.115) into Eq. (7.116) and collecting terms we get the following difference equation for j = 1: (1 + 4 4 4 4 Dθ) · ω1n+1 − Dθω2n+1 = [1 − D(1 − θ)] · ω1n + D(1 − θ)ω2n 3 3 3 3 (7.117) 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θ ) −Dθ(1 − 0.5 2 0 0 0 0 0 − 43 Dθ 1 + 2Dθ −Dθ(1 − 0.5 ) 3 0 0 0 0 0 −Dθ(1 + 0.5 ) 2 1 + 2Dθ · 0 0 0 0 0 −Dθ(1 + · · 0 0 0 0 0 · · −Dθ(1 − 0 0 0 0.5 ) 0 3 0 · 0.5 ) 1 + 2Dθ N −2 ) −Dθ(1 − N0.5 −1 (7.119) The python function thetaSchemeNumpyV2 show how one could implement the algorithm 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. 0 0 0 0 0 −Dθ(1 + N0.5 ) −2 1 + 2Dθ · 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 7.7.2 @ git@lrhgit/tkt4140/src/src-ch5/startup_compendium.py; V 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 = 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. Vi har valgt verdiene slik at forholdet CHAPTER 7. DIFFUSJONSPROBLEMER D=1 radius [-] radius [-] D = 0.53 radius [-] D = 0.5 1.0 0.8 0.6 0.4 0.2 0.0 1.0 0.8 0.6 0.4 0.2 0.0 1.0 0.8 0.6 0.4 0.2 0.0 radius [-] D = 0.45 1.0 0.8 0.6 0.4 0.2 0.0 radius [-] FTCSV1 D = 0.4 1.0 0.8 0.6 0.4 0.2 0.0 0.0 0.2 0.4 0.6 0.8 1.0 Velocity [-] 298 FTCSV2 Crank-Nicolson Laasonen 0.0 0.2 0.4 0.6 0.8 1.0 Velocity [-] 0.0 0.2 0.4 0.6 0.8 1.0 Velocity [-] 0.0 0.2 0.4 0.6 0.8 1.0 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 =α ∂t ∂2T 2 ∂T + ∂r2 r ∂r (7.123) Randbetingelser: ∂T (0, t) = 0, (symmetribetingelse) ∂r (7.124) ∂T = h̄ · (Tv − Tb ) ∂r (7.125) For r = b : k 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: n n ], j = 1, 2, . . . + (1 + 1/j) · Tj+1 Tjn+1 = (1 − 2D) · Tjn + D[(1 − 1/j) · Tj−1 (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 (4T1n − T2n ), alle n 3 T0n = (7.129) Randbetingelsen for r = b. Diskretiserer (7.124) med bruk av 2. ordens bakoverdifferanser: k· n n n 3TN +1 − 4TN + TN −1 2 · ∆r n TN +1 = n = h̄ · (Tv − Tb ) som løst m.h.p TN +1 gir: n − Tn 4TN N −1 + 2δ · Tv 3 + 2δ (7.130) ∆r · h̄ (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: der δ = T1n+1 = (1 − 2D) · T1n + 2D · T2n n Tj−1 Leddet (1 − 1/j) · = (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 r(cm) 0.00 0.10 0.20 0.30 0.40 0.50 0.60 0.70 0.80 0.90 1.00 1.10 1.20 1.30 1.40 1.50 1.60 1.70 1.80 1.90 2.00 2.10 2.20 2.30 2.40 2.50 T (◦ C) 53.38 53.37 53.36 53.33 53.29 53.24 53.18 53.11 53.03 52.93 52.83 52.72 52.59 52.46 52.31 52.16 51.99 51.81 51.63 51.43 51.22 51.01 50.78 50.55 50.30 50.05 Ta 53.37 53.36 53.35 53.32 53.28 53.23 53.17 53.10 53.02 52.93 52.82 52.71 52.58 52.45 52.30 52.15 51.98 51.81 51.62 51.42 51.22 51.00 50.78 50.54 50.30 50.04 r(cm) 2.60 2.70 2.80 2.90 3.00 3.10 3.20 3.30 3.40 3.50 3.60 3.70 3.80 3.90 4.00 4.10 4.20 4.30 4.40 4.50 4.60 4.70 4.80 4.90 5.00 T (◦ C) 49.79 49.52 49.24 48.95 48.65 48.35 48.03 47.71 47.38 47.05 46.70 46.35 46.00 45.63 45.26 44.89 44.50 44.11 43.72 43.32 42.92 42.51 42.09 41.67 41.25 300 Ta 49.78 49.51 49.23 48.94 48.64 48.34 48.03 47.71 47.38 47.04 46.70 46.35 45.99 45.63 45.26 44.88 44.50 44.11 43.71 43.31 42.91 42.50 42.09 41.67 41.24 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 ∂t ∂x where for the linear advection equation F (u) = a0 u. 8.1.1 (8.3) 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: un+1 − un ∂u j j ≈ , ∂t ∆t n un ∂u j+1 − uj−1 ≈ ∂x 2∆x and we may substitute the approximations (8.1.1) into the advection equation (8.1) to yield: un+1 = un j − j C n (u − un j−1 ) 2 j+1 301 (8.4) 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 n 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 u 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 6 C = 1.0 4 2 u 0 -2 -4 0 0.1 0.2 0.3 0.4 0.6 0.5 0.7 0.8 0.9 1 0.9 1 3 2.5 C = 0.5 2 u1.5 1 0.5 0 -0.5 -1 0 0.1 0.2 0.3 0.4 0.6 0.5 0.7 0.8 2 C = 0.25 1.5 u 1 0.5 0 0 0.1 0.2 0.3 0.4 0.6 0.5 x 0.7 0.8 0.9 1 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 n n i·βxj un j → Ej = G · e (8.6) Substitution of (8.6) into (8.4) yields: Gn+1 ei·β·xj = Gn ei·β·xj − C Gn ei·βxj+1 − Gn ei·βxj−1 2 which after division with Gn ei·β·xj and introduction of the simplified notation δ = β · h yields: G=1− C i·βh e − e−i·βh = 1 − i · C sin(δ) 2 where the trigonometric relations: 2 cos(x) = eix + e−ix i · 2 sin(x) = e ix −e −ix x cos(x) = 1 − 2 sin ( ) 2 2 (8.7) (8.8) (8.9) CHAPTER 8. HYPERBOLIC PDES 304 have been introduced for convenience. Finally, we get the following expression for the numerical ampliciation factor: |G| = p 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 differences). 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 n j-1 j Figure 8.4: Caption goes here. Oppstrømsdifferanse for det konvektive leddet: n n uj − uj−1 ∂u = + O(∆x) ∂x ∆x (8.10) innsatt i (8.1) med foroverdifferanser for ∂u og med C = ∂t (8.10) a0 ∆t ∆x n n n n un+1 = un j − C · (uj − uj−1 ) = (1 − C)uj + C · uj−1 j (8.11) har nøyaktighet O∆t) + O(∆x) (8.11) CHAPTER 8. HYPERBOLIC PDES 305 Setter vi C = 1 inn i (8.11), får vi un+1 = un j−1 som er den eksakte løsningen av j + a0 ∂u = 0 . ( Se avsnitt 5.2) For C < 1 blir bølgefronten "smurt" utover, noe som ∂x 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: ∂u ∂t 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(δ) |G| = p [1 + C cos(δ − 1)]2 + C 2 sin2 (δ) = p 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 δ 2 (1 − C) ≥ 0 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 -0.5 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 0.9 1 C = 0.5 1.5 C = 0.5 1 u 0.5 0 -0.5 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 1.5 C = 0.25 1 u 0.5 0 -0.5 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 Figure 8.5: Caption goes here. 0.8 0.9 1 CHAPTER 8. HYPERBOLIC PDES 8.2 307 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 − un j j + a0 n un j+1 − uj−1 k 2h Innsatt i (8.14) fra rekkeutviklingene i (??), kap. 7: 1 k ( h u + kut + 2 k 2 i n utt + · · · − un j ) j =0 a0 + u + hux + 2h h h2 u 2 xx (8.14) + h3 u 6 xxx i n + · · · j h i n a0 h2 h3 − u − hux + 2 uxx − 6 uxxx + · · · = 0 2h j Ordnet: k ∂2u a0 h2 ∂ 3 u ∂u ∂u + a0 =− − + ··· 2 ∂t ∂x 2 ∂t 6 ∂x3 Vi bruker nå differensialligningen uttrykke derivasjon m.h.p. x. Differensialligningen gir: ∂u ∂t + a0 ∂u = 0 til å transformere leddet − k2 ∂x ∂u ∂u = −a0 ∂t ∂x (8.15) 2 ∂ u ∂t2 til å (8.16) Deriverer (8.16) m.h.p. t: ∂2u ∂2u = −a0 2 ∂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 = a20 2 2 ∂t ∂x (8.17) (8.17) innsatt i (8.15): ka2 ∂ 2 u ∂u ∂u a0 h2 ∂ 3 u + a0 =− 0 − + ··· ∂t ∂x 2 ∂x2 6 ∂x3 som ved innføring av Courant-tallet gir: 0k C = ah Cha20 ∂ 2 u ∂u ∂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 0 ofte koeffisienten νN = − Cha kalles den numeriske viskositeten analogt med den virkelige 2 2 viskositeten i ligningen ∂u = ν ∂∂xu 2 . Når vi bruker skjemaet i (8.14), gir dette den samme ∂t effekten som å løse diffusjonsligningen 2 ∂u = ν ∂∂xu 2 med negativ viskositet Helt sikkert ustabilt. (8.18) forklarer også hvorfor ∂t 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 − un j j + a0 n (un j − uj−1 ) k Innsatt fra rekkeutviklingene i(??) og ordnet: h =0 (8.19) ∂u ∂u k ∂2u a0 h ∂ 2 u = a0 =− + + ··· 2 ∂t ∂x 2 ∂t 2 ∂x2 Da differensialligningen er den samme, får vi fra (8.17): 2 a0 k ∂2u = a20 ∂∂xu 2 som innsatt i (8.19) sammen med gir C = h : ∂t2 (8.20) ∂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 differensial2 2 ligningen til å finne relasjonen ∂∂t2u = a20 ∂∂xu 2 . 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); RHSMDE:= − 21 Cha ∂2 u(x, t) ∂x2 − 1 ah2 6 + 13 C 2 h2 a ∂2 u(x, t) ∂x2 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 (8.23) Gr I section 7.4 we introduced the diffusion/dissipation error εD (dissipasjonsfeilen) as: |G| = p G2r + G2i , φ = arctan |G| (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 εφ : εD = εφ = φ φa (8.25) 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: Ga = u(xj , tn+1 ) ei(βxj −ωtn+1 ) = i(βx −ωt ) = exp[i(βxj − ωtn+1 ) − i(βxj − ωtn )] = exp(−iω · ∆t) n j u(xj , tn ) e hvor vi har satt inn fra (8.27). Dermed blir |Ga | = 1 → εD = |G| . Derav: φa = ω · ∆t = a0 β · ∆t = a0 ∆t β · ∆x = C · δ ∆x (8.28) C er Courant-tallet og δ = β · ∆x som vanlig. Fra (8.28) får vi også: a0 = φa β · ∆t (8.29) CHAPTER 8. HYPERBOLIC PDES 310 Analogt med (8.29) kan vi definere en numerisk forplantningshastighet anum : anum = φ β · ∆t (8.30) 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 upwinding 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: εD = |G| = p [1 + C · (cos(δ) − 1)]2 + [C sin(δ)]2 (8.33) = p 1 − 4C(1 − C) sin2 ( 2δ ) φ 1 C sin(δ) 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. h εφ = 8.3.3 i Example: Diffusion and disperision errors for LaxWendroff 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: εD = |G| = p [1 + C 2 · (cos(δ) − 1)]2 + (C sin(δ))2 = (8.36) q 1 − 4C 2 (1 − C 2 ) sin4 δ 2 φ 1 Csin(δ) = 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 Couranttallet 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 εφ = h i CHAPTER 8. HYPERBOLIC PDES 311 1.2 1.4 1.2 1.0 1.0 0.8 <G |G| 0.8 0.6 0.6 0.4 CFL = 0.25 CFL = 0.5 CFL = 0.8 CFL = 1.0 0.2 0.0 0 20 40 60 0.4 0.2 80 100 [deg] 120 140 160 0.0 180 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 <G |G| 0.8 0.6 0.6 0.4 CFL = 0.25 CFL = 0.5 CFL = 0.8 CFL = 1.0 0.2 0.0 0 20 40 60 0.4 0.2 80 100 [deg] 120 140 160 0.0 180 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 δ 1 0.8 0.6 0.4 0.2 0 0 0.5 1 1 1.5 δ(rad.) 2 2.5 3 0 0.2 0.6 0.4 0.8 C Figure 8.8: Diffusion error εD as a function of frequency and Courant-number for the Lax-Wendroff scheme. CHAPTER 8. HYPERBOLIC PDES 8.4 313 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: n un+1 − 21 (un j+1 + uj−1 ) j =− n n Fj+1 − Fj−1 ∆t 2∆x The Lax-Friedrich scheme is the obtained by isolation un+1 at the right hand side: j un+1 = j ∆t 1 n n ) + un (u (F n − Fj−1 j−1 ) − 2 j+1 2∆x j+1 (8.38) (8.39) By assuming a linear flux F = a0 u it may be shown that the Lax-Friedrich scheme takes the form: C n 1 (8.40) + un − un (u un+1 = (un j−1 ) − j−1 ) j 2 j+1 2 j+1 where we have introduced the CFL-number as given by (8.5) and have the simple pythonimplementation: def lax_friedrich(u): u[1:-1] = (u[:-2] +u[2:])/2.0 return u[1:-1] c*(u[2:] - u[:-2])/2.0 whereas a more generic flux implementation is implemented as: def lax_friedrich_Flux(u): u[1:-1] = (u[:-2] +u[2:])/2.0 return u[1:-1] 8.5 dt*(F(u[2:])-F(u[:-2]))/(2.0*dx) Lax-Wendroff Schemes These schemes were proposed in 1960 by P.D. Lax and B. Wendroff [17] for solving, approximately, 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: un+1 = un j + j ∆t Fj−1/2 − Fj+1/2 ∆x (8.41) 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 un+1 j = un j n n j j ∂u (∆t) ∂ 2 u + ∆t + + ··· ∂t 2 ∂t2 (8.42) From the differential equation (8.3) we get by differentiation n n ∂u ∂u = −a0 ∂t ∂x j and j n n j j ∂ 2 u ∂2u = a20 2 2 ∂t ∂x (8.43) Before substitution of (8.43) in the Taylor expansion (8.42) we approximate the spatial derivatives by central differences: n n un ∂u j+1 − uj−1 ≈ ∂x (2∆x) j n and n n un ∂ 2 u j+1 − 2uj + uj−1 ≈ ∂x2 (∆x)2 j (8.44) CHAPTER 8. HYPERBOLIC PDES 314 and then the Lax-Wendroff scheme follows by substitution: un+1 = un j − j C2 n C n n un uj+1 − 2un j + uj−1 j+1 − uj−1 + 2 2 (8.45) with the local truncation error Tjn : Tjn = 1 ∂3u ∂3u · (∆t)2 3 + a0 (∆x)2 3 6 ∂t ∂x n = O[(∆t)2 , (∆x)2 ] (8.46) j The resulting difference equation in (8.45) may also be formulated as: un+1 = j C C 2 n (1 + C)un (1 − C)un j−1 + (1 − C )uj − j+1 2 2 (8.47) The explicit Lax-Wendroff stenticl is illustrated in Figure 8.9 un+1 j n+1 n 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 uj+1/2 = 1 ∆t n 1 n n un Fj − Fj+1 j + uj+1 + 2 2 ∆x n+1/2 Fj+1/2 = F (uj+1/2 ) (8.48) (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 n un j+1 + uj − 2 1 n = un j + uj−1 − 2 uj+1/2 = n+1/2 uj−1/2 ∆t n F (un j+1 ) − F (uj ) 2∆x ∆t n F (un j ) − F (uj−1 ) 2∆x (8.50) (8.51) Second step: ∆t n+1/2 n+1/2 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). un+1 = un j − j MacCormack Scheme. A simpler and popular extension/variant of Lax-Wendroff schemes like in the previous section, is the MacCormack scheme [18]: upj = un j + ∆t n Fjn − Fj+1 ∆x (8.53) un+1 j 1 ∆t p 1 p = un Fj−1 − Fjp 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 n Fjp + 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: m Fj+1 = n n upj = un j + C uj − uj+1 un+1 = j (8.55) 1 C un upj−1 − uj j + uj + 2 2 p p (8.56) 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 return u[1:-1] dt*(F(u[2:])-F(u[:-2]))/(2.0*dx) CHAPTER 8. HYPERBOLIC PDES # Lax-Friedrich Advection def lax_friedrich(u): u[1:-1] = (u[:-2] +u[2:])/2.0 return u[1:-1] 317 c*(u[2:] - u[:-2])/2.0 # 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=[] legends=[] # list for plot lines for solvers and analytical solutions # 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 8.6 319 Order analysis on various schemes for the advection equation The schemes order; ftbs: O (∆x, ∆t), Lax-Friedrich: presented have different theoretical 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: log p= n−1 n log (r) = logr n−1 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 ftbs lax_friedrich lax_wendroff −3 log10 µq 1 N ¡ f-f ¢ 2 ¶ −1 −2 −4 −5 160320 640 1280 2560 log2( n-1 ) n Nx 2 1 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 orderDict[solver.func_name] = [] solver(key) assign it with value=[], an empt 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 : S= N X ri2 , ri = Ei − (hx , ht ; Cx , p, Ct , q)i i=1 The python module scipy.optimize has many methods for parameter optimization and curvefitting. 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 + 6.5 h0.98 x t (8.59) 1.0 laxF riedrich → = −1484 h1.9 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): p (float): Ct(float): q (float): the the the the optimized optimized optimized optimized values values values values of of of of Cx p Ct 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:], ax[1][0].plot(XtickList[-5:], ax[1][0].plot(XtickList[-5:], ax[1][0].plot(XtickList[-5:], ftbs −1.0 −1.5 −2.5 1.87 =-1483.49 hx 2.0 −2.5 + -148.59 ht2.0 =364.05 hx −3 −2.0 −3.0 −4 −5 −3.0 −3.5 −4.0 =E −2 + 25.85 ht1.0 log10( ) log10( ) + 1.32 ht0.98 lax_wendroff −1 =E 0.98 =6.45 hx −2.0 log10( ) lax_friedrich −1.0 =E −1.5 E[-5:],lstyle[k]) errorFunc(hxList, htList)[-5:],lstyle[k] + ’--’) errorFuncHx(hxList[-5:]), lstyle[k] + ’-.’) errorFuncHt(htList[-5:]),lstyle[k] + ’:’) 1 2 3 4 5 (hx ,ht )n 6 7 8 9 −3.5 −6 1 2 3 4 5 (hx ,ht )n 6 7 8 9 0.0035 0.0030 =E 0.0025 =6.45 hx 0.98 0.0020 0.0015 =6.45 0.98 hx =1.32 0.98 ht + 1.32 ht0.98 0.008 =E 0.006 =-1483.49 hx 1.87 =-1483.49 0.004 =25.85 + 25.85 ht1.0 1.87 hx 1 2 3 4 5 (hx ,ht )n 6 0.0005 7 8 9 7 (hx ,ht )n 8 9 5 =E =364.05 hx 0.00003 =364.05 hx 2.0 + -148.59 ht2.0 2.0 =-148.59 0.00001 2.0 ht 0.00000 −0.00001 0.000 6 0.00005 0.00004 0.00002 1.0 ht 0.002 0.0010 0.0000 5 −7 0.00006 6 7 (hx ,ht )n 8 9 −0.00002 5 6 7 (hx ,ht )n 8 9 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 un+1 = un j + j ∆t Fj−1/2 − Fj+1/2 ∆x (8.62) 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. (8.63) (8.64) Fj−1/2 = Fl (j − 1/2) + φ(rj−1/2 ) Fh (j − 1/2) − Fl (j − 1/2) Fj+1/2 = Fl (j + 1/2) + φ(rj+1/2 ) Fh (j + 1/2) − Fl (j + 1/2) 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 rj−1/2 = uj−1 − uj−2 , uj − uj−1 rj+1/2 = uj − uj−1 uj+1 − uj (8.65) 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 a 1− 2 1 (uj , uj+1 ) = a uj + a 1 − 2 FLW (j − 1/2) = FLW (uj−1 , uj ) = a uj−1 + FLW (j + 1/2) = FLW ∆t a uj − uj−1 ∆x ∆t a uj+1 − uj ∆x (8.66) (8.67) 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 u or a u ) with an additional anti diffusive term j−1 j ( 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 F (j − 1/2) = a uj−1 + φ rj−1/2 1 a (1 − c) uj − uj−1 (8.68) 2 1 a (1 − c) uj+1 − uj (8.69) F (j + 1/2) = a uj + φ rj+1/2 2 When φ = 0 the scheme is the upwind scheme, and when φ = 1 the scheme is the LaxWendroff 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? 0≤ φ(r) , φ(r) r ≤2 (8.70) 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 2 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 LaxWendroff (φ = 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| φ(r) = 1 + |r| (8.73) φ(r) = minmod(1, r) (8.74) V an − Leer : minmod : CHAPTER 8. HYPERBOLIC PDES 329 3 2 1 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 ( minmod(a, b) = a if b if 0 if a · b > 0 and |a| > |b| a · b > 0 and |b| > |a| > 0 a·b<0 (8.75) 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. 2 Superbee Van-Leer 1 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) u 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 0.4 0.2 0.0 0.0 0.2 0.4 0.6 0.8 1.0 0.6 0.8 1.0 r x 3.0 2.5 2.0 1.5 1.0 0.5 0.0 0.0 0.2 0.4 u 2.0 1.5 1.0 0.5 0.0 0.0 0.2 0.4 0.6 superbee van-Leer minmod 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 ∂t ∂x (8.78) 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 ∂ + ∂t ∂x u2 2 =0 (8.79) and by introducing a flux function u2 (8.80) 2 the conservative formulation of the Burgers equation may be represented by a generic transport equation: F (u) = ∂u ∂F (u) + =0 ∂t ∂x (8.81) CHAPTER 8. HYPERBOLIC PDES 8.8.1 331 Upwind Scheme The upwind scheme for the general conservation equation take the form: ∆t n (8.82) F (un j+1 ) − F (uj ) ∆x 0 where we have assumed a forward propagating wave (a(u) = F (u) > 0, i.e. u > 0 for the ∂F (u) 1 n burger equation). In the opposite case ∂x will be approximated by ∆x F (un j ) − F (uj−1 ) un+1 = un j − j 8.8.2 Lax-Friedrich The Lax-Friedrich conservation equation take the form as given in (8.38), repeated here for convinience: un+1 = j 8.8.3 n n Fj+1 − Fj−1 ∆t n (uj+1 + un j−1 ) − 2 2∆x (8.83) 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 n un j+1 + uj − 2 1 n un = j + uj−1 − 2 uj+1/2 = n+1/2 uj−1/2 ∆t n F (un j+1 ) − F (uj ) 2∆x ∆t n F (un j ) − F (uj−1 ) 2∆x (8.84) (8.85) ∆t n+1/2 n+1/2 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): = un un+1 j − j n n j j ∂F ∂u =− ∂t ∂x n ∂ n ∂ ∂ 2 u ∂ 2 F (u) = − =− ∂t2 ∂t∂x and =− ∂F (u) ∂u ∂u ∂t ∂x nj j n ∂ a(u) ∂F ∂x = ∂x j n ∂x j ∂F (u) ∂t (8.87) j Now inserting into the Taylor series we get ∂F ∂F (u) ∆t2 ∂ a(u) ∂x = − ∆t + (8.88) ∂x 2 ∂x and further we may obtain the general Lax-Wendroff one-step method for a generic transport equation un+1 j un+1 = un j − j un j ∆t2 ∆t (Fj+1 − Fj−1 )+ aj+1/2 (Fj+1 − Fj )−aj−1/2 (Fj − Fj−1 ) 2∆x 2∆x2 h i (8.89) 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: aj+1/2 = 1 n un j + uj+1 2 (8.90) CHAPTER 8. HYPERBOLIC PDES 332 for the burger equation. Another method that assure conservation is to use the following approximation ( n Fj+1 −Fjn aj+1/2 = 8.8.4 if un −un j+1 j uj uj+1 6= uj (8.91) otherwise MacCormack The MacCormack scheme was discussed in ((8.5.1)) and is given by (8.94) repeated her for convinience ∆t n Fjn − Fj+1 ∆x 1 ∆t p 1 p = un Fj−1 − Fjp j + uj + 2 2 ∆x upj = un j + (8.92) un+1 j (8.93) (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 Upwind Lax-Friedrichs Lax-Wendroff Scheme = un un+1 j − j ∆t + ∆tQn j ∆x n n Fj+1 −Fj−1 n = ∆t un+1 (un + ∆tQn j+1 + uj−1 ) − j j 2 2∆x n+1/2 1 ∆t ∆t n n n n uj+1/2 = 2 uj+1 + uj − 2∆x F (uj+1 ) − F (un j ) + 2 Qj+1/2 n+1/2 ∆t 1 n n n n Qn uj−1/2 = 2 uj + uj−1 − 2∆x F (uj ) − F (uj−1 ) + ∆t 2 j−1/2 n+1/2 n+1/2 n − ∆t n = u un+1 F (u ) − F (u ) + ∆tQ j j j ∆x j+1/2 j−1/2 ∆t n n + ∆tQn+1/2 F − F upj = un − j+1 j j j ∆x p p p 1 ∆t ∆t n+1/2 = 12 un un+1 j + uj − 2 ∆x Fj − Fj−1 + 2 Qj j macCormack order 1 1 2 2 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 """ u[1:-1] = u[1:-1] return u[1:-1] 333 (dt/dx)*(F(u[1:-1])-F(u[:-2])) + dt*RHS(t-0.5*dt, x[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 return u[1:-1] dt*(F(u[2:])-F(u[:-2]))/(2.0*dx) + dt*(RHS(t, x[:-2]) + RHS(t, x 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 expression 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) compute R cos(x) from sympy import cos integrate(cos(x), x) CHAPTER 10. SYMPOLIC COMPUTATION WITH SYMPY compute R∞ −∞ sin(x2 ) from sympy import sin, oo integrate(sin(x**2), (x, -oo, oo)) limits. perform limx→0 sin(x) 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)) 339 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. WCB/McGraw-Hill, 1999. McGraw-Hill series in mechanical engineering. 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
© Copyright 2025 Paperzz