DOKK Library

Computational Physics - A Practical Introduction to Computational Physics and Scientific Computing (using C++)

Authors Konstantinos N. Anagnostopoulos

License CC-BY-SA-4.0

Plaintext
Computational Physics
                           (using C++)




   Konstantinos N. Anagnostopoulos
   COMPUTATIONAL PHYSICS

  A Practical Introduction to Computational Physics
        and Scientific Computing (using C++)



                    Athens, 2016




KONSTANTINOS N. ANAGNOSTOPOULOS
        National Technical University of Athens




   National Technical University of Athens
COMPUTATIONAL PHYSICS
A Practical Introduction to Computational Physics and Scientific Computing (C++ version)


AUTHORED BY KONSTANTINOS N. ANAGNOSTOPOULOS
Physics Department, National Technical University of Athens, Zografou Campus, 15780 Zografou, Greece
konstant@mail.ntua.gr, www.physics.ntua.gr/˜konstant/


PUBLISHED BY KONSTANTINOS N. ANAGNOSTOPOULOS
and the
NATIONAL TECHNICAL UNIVERSITY OF ATHENS


Book Website:
www.physics.ntua.gr/˜konstant/ComputationalPhysics

©Konstantinos N. Anagnostopoulos 2014, 2016

First Published 2014
Second Edition 2016
Version¹ 2.0.20161206201400

Cover: Design by K.N. Anagnostopoulos. The front cover picture is a snapshot taken during Monte Carlo sim-
ulations of hexatic membranes. Work done with Mark J. Bowick. Relevant video at youtu.be/Erc7Q6YXfLk

 ⃝
 CC   This book and its cover(s) are subject to copyright. They are licensed under the Creative Commons
Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit
creativecommons.org/licenses/by-sa/4.0/
The book is accompanied by software available at the book’s website. All the software, unless the copyright
does not belong to the author, is open source, covered by the GNU public license, see www.gnu.org/licenses/.
This is explicitly mentioned at the end of the respective source files.


ISBN 978-1-365-58322-3 (lulu.com, vol. I)
ISBN 978-1-365-58338-4 (lulu.com, vol. II)




    ¹The first number is the major version, corresponding to an “edition” of a conventional book. Versions
differing by major numbers have been altered substantially. Chapter numbers and page references are not
guaranteed to match between different versions. The second number is the minor version. Versions differing
by a minor version may have serious errors/typos corrected and/or substantial text modifications. Versions
differing by only the last number may have minor typos corrected, added references etc. When reporting
errors, please mention the version number you are referring to.
Contents

Foreword to the Second Edition                                                                                        vii

Foreword to the First Edition                                                                                         ix

1 The Computer                                                                                                         1
  1.1 The Operating System . . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .    2
      1.1.1 Filesystem . . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .    3
      1.1.2 Commands . . . . . . . . .                        .   .   .   .   .   .   .   .   .   .   .   .   .   .   10
      1.1.3 Looking for Help . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   14
  1.2 Text Processing Tools – Filters . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   16
  1.3 Programming with Emacs . . . . .                        .   .   .   .   .   .   .   .   .   .   .   .   .   .   20
      1.3.1 Calling Emacs . . . . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   21
      1.3.2 Interacting with Emacs . .                        .   .   .   .   .   .   .   .   .   .   .   .   .   .   22
      1.3.3 Basic Editing . . . . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   25
      1.3.4 Cut and Paste . . . . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   27
      1.3.5 Windows . . . . . . . . . .                       .   .   .   .   .   .   .   .   .   .   .   .   .   .   28
      1.3.6 Files and Buffers . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   29
      1.3.7 Modes . . . . . . . . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   30
      1.3.8 Emacs Help . . . . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   32
      1.3.9 Emacs Customization . . .                         .   .   .   .   .   .   .   .   .   .   .   .   .   .   34
  1.4 The C++ Programming Language                            .   .   .   .   .   .   .   .   .   .   .   .   .   .   35
      1.4.1 The Foundation . . . . . .                        .   .   .   .   .   .   .   .   .   .   .   .   .   .   35
  1.5 Gnuplot . . . . . . . . . . . . . . .                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   47
  1.6 Shell Scripting . . . . . . . . . . .                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   52

2 Kinematics                                                                                                          63
  2.1 Motion on the Plane .     .   .   .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   63
      2.1.1 Plotting Data .     .   .   .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   72
      2.1.2 More Examples       .   .   .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   75
  2.2 Motion in Space . . .     .   .   .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   87
  2.3 Trapped in a Box . . .    .   .   .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   96

                                        iii
iv                                                                                    CONTENTS

         2.3.1 The One Dimensional Box            .   .   .   .   .   .   .   .   .   .   .   .   .   .    97
         2.3.2 Errors . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   105
         2.3.3 The Two Dimensional Box            .   .   .   .   .   .   .   .   .   .   .   .   .   .   109
     2.4 Applications . . . . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   112
     2.5 Problems . . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   132

3 Logistic Map                                                                                            137
  3.1 Introduction . . . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   137
  3.2 Fixed Points and 2n Cycles . . . . .            .   .   .   .   .   .   .   .   .   .   .   .   .   139
  3.3 Bifurcation Diagrams . . . . . . . .            .   .   .   .   .   .   .   .   .   .   .   .   .   146
  3.4 The Newton-Raphson Method . . .                 .   .   .   .   .   .   .   .   .   .   .   .   .   150
  3.5 Calculation of the Bifurcation Points           .   .   .   .   .   .   .   .   .   .   .   .   .   156
  3.6 Liapunov Exponents . . . . . . . . .            .   .   .   .   .   .   .   .   .   .   .   .   .   160
  3.7 Problems . . . . . . . . . . . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   174

4 Motion of a Particle                                                                                  185
  4.1 Numerical Integration of Newton’s Equations . . .                               .   .   .   .   . 185
  4.2 Prelude: Euler Methods . . . . . . . . . . . . . . .                            .   .   .   .   . 186
  4.3 Runge–Kutta Methods . . . . . . . . . . . . . . . .                             .   .   .   .   . 198
      4.3.1 A Program for the 4th Order Runge–Kutta                                   .   .   .   .   . 202
  4.4 Comparison of the Methods . . . . . . . . . . . . .                             .   .   .   .   . 206
  4.5 The Forced Damped Oscillator . . . . . . . . . . .                              .   .   .   .   . 209
  4.6 The Forced Damped Pendulum . . . . . . . . . . .                                .   .   .   .   . 217
  4.7 Appendix: On the Euler–Verlet Method . . . . . .                                .   .   .   .   . 223
  4.8 Appendix: 2nd order Runge–Kutta Method . . .                                    .   .   .   .   . 227
  4.9 Problems . . . . . . . . . . . . . . . . . . . . . . .                          .   .   .   .   . 230

5 Planar Motion                                                                                        235
  5.1 Runge–Kutta for Planar Motion           .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 235
  5.2 Projectile Motion . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 240
  5.3 Planetary Motion . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 248
  5.4 Scattering . . . . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 252
      5.4.1 Rutherford Scattering . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 255
      5.4.2 More Scattering Potentials        .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 263
  5.5 More Particles . . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 265
  5.6 Problems . . . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 277

6 Motion in Space                                                 281
  6.1 Adaptive Stepsize Control for RK Methods . . . . . . . . . 282
      6.1.1 The rksuite Suite of RK Codes . . . . . . . . . . . . 282
      6.1.2 Interfacing C++ Programs with Fortran . . . . . . . 286
CONTENTS                                                                                                      v

        6.1.3 The rksuite Driver . . . . .               .   .   .   .   .   .   .   .   .   .   .   .   .   292
    6.2 Motion of a Particle in an EM Field              .   .   .   .   .   .   .   .   .   .   .   .   .   297
    6.3 Relativistic Motion . . . . . . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   298
    6.4 Problems . . . . . . . . . . . . . . .           .   .   .   .   .   .   .   .   .   .   .   .   .   310

7   Electrostatics                                                                                         313
    7.1 Electrostatic Field of Point Charges . . .               .   .   .   .   .   .   .   .   .   .   . 313
    7.2 The Program – Appetizer and ... Desert                   .   .   .   .   .   .   .   .   .   .   . 316
    7.3 The Program – Main Dish . . . . . . . .                  .   .   .   .   .   .   .   .   .   .   . 325
    7.4 The Program - Conclusion . . . . . . . .                 .   .   .   .   .   .   .   .   .   .   . 331
    7.5 Electrostatic Field in the Vacuum . . . .                .   .   .   .   .   .   .   .   .   .   . 336
    7.6 Results . . . . . . . . . . . . . . . . . . .            .   .   .   .   .   .   .   .   .   .   . 343
    7.7 Poisson Equation . . . . . . . . . . . . .               .   .   .   .   .   .   .   .   .   .   . 344
    7.8 Problems . . . . . . . . . . . . . . . . .               .   .   .   .   .   .   .   .   .   .   . 351

8 Diffusion Equation                                                                                       355
  8.1 Introduction . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 355
  8.2 Heat Conduction in a Thin Rod          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 357
  8.3 Discretization . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 358
  8.4 The Program . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 360
  8.5 Results . . . . . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 363
  8.6 Diffusion on the Circle . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 365
  8.7 Analysis . . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 369
  8.8 Problems . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 373

9 The    Anharmonic Oscillator                                                                               375
  9.1    Introduction . . . . . . . . . . . . . . . . .              .   .   .   .   .   .   .   .   .   .   375
  9.2    Calculation of the Eigenvalues of Hnm (λ)                   .   .   .   .   .   .   .   .   .   .   377
  9.3    Results . . . . . . . . . . . . . . . . . . . .             .   .   .   .   .   .   .   .   .   .   387
  9.4    The Double Well Potential . . . . . . . . .                 .   .   .   .   .   .   .   .   .   .   392
  9.5    Problems . . . . . . . . . . . . . . . . . .                .   .   .   .   .   .   .   .   .   .   401

10 Time Independent Schrödinger Equation                                                                  405
   10.1 Introduction . . . . . . . . . . . . . . .           .   .   .   .   .   .   .   .   .   .   .   . 405
   10.2 The Infinite Potential Well . . . . . . .             .   .   .   .   .   .   .   .   .   .   .   . 408
   10.3 Bound States . . . . . . . . . . . . . .             .   .   .   .   .   .   .   .   .   .   .   . 420
   10.4 Measurements . . . . . . . . . . . . . .             .   .   .   .   .   .   .   .   .   .   .   . 430
   10.5 The Anharmonic Oscillator - Again...                 .   .   .   .   .   .   .   .   .   .   .   . 436
   10.6 The Lennard–Jones Potential . . . . .                .   .   .   .   .   .   .   .   .   .   .   . 441
   10.7 Problems . . . . . . . . . . . . . . . .             .   .   .   .   .   .   .   .   .   .   .   . 443
vi                                                                                          CONTENTS

11 The    Random Walker                                                                                      449
   11.1   (Pseudo)Random Numbers . . . . . . . . .                          .   .   .   .   .   .   .   .   . 450
   11.2   Using Pseudorandom Number Generators .                            .   .   .   .   .   .   .   .   . 461
   11.3   The MIXMAX Random Number Generator                                .   .   .   .   .   .   .   .   . 466
   11.4   Random Walks . . . . . . . . . . . . . . . .                      .   .   .   .   .   .   .   .   . 470
   11.5   Problems . . . . . . . . . . . . . . . . . . .                    .   .   .   .   .   .   .   .   . 479

12 Monte Carlo Simulations                                                                                   483
   12.1 Statistical Physics . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 484
   12.2 Entropy . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 487
   12.3 Fluctuations . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 491
   12.4 Correlation Functions . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 493
   12.5 Sampling . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 495
        12.5.1 Simple Sampling . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 496
        12.5.2 Importance Sampling          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 497
   12.6 Markov Processes . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 498
   12.7 Detailed Balance Condition .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 499
   12.8 Problems . . . . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   . 501

13 Simulation of the d = 2 Ising Model                                                                       503
   13.1 The Ising Model . . . . . . . . . . . . . . . .                         .   .   .   .   .   .   .   . 503
   13.2 Metropolis . . . . . . . . . . . . . . . . . . . .                      .   .   .   .   .   .   .   . 509
   13.3 Implementation . . . . . . . . . . . . . . . . .                        .   .   .   .   .   .   .   . 512
        13.3.1 The Program . . . . . . . . . . . . . .                          .   .   .   .   .   .   .   . 517
        13.3.2 Towards a Convenient User Interface .                            .   .   .   .   .   .   .   . 523
   13.4 Thermalization . . . . . . . . . . . . . . . . .                        .   .   .   .   .   .   .   . 534
   13.5 Autocorrelations . . . . . . . . . . . . . . . .                        .   .   .   .   .   .   .   . 537
   13.6 Statistical Errors . . . . . . . . . . . . . . . .                      .   .   .   .   .   .   .   . 543
        13.6.1 Errors of Independent Measurements                               .   .   .   .   .   .   .   . 544
        13.6.2 Jackknife . . . . . . . . . . . . . . . .                        .   .   .   .   .   .   .   . 547
        13.6.3 Bootstrap . . . . . . . . . . . . . . . .                        .   .   .   .   .   .   .   . 549
   13.7 Appendix: Autocorrelation Function . . . . .                            .   .   .   .   .   .   .   . 550
   13.8 Appendix: Error Analysis . . . . . . . . . . .                          .   .   .   .   .   .   .   . 557
        13.8.1 The Jackknife Method . . . . . . . . .                           .   .   .   .   .   .   .   . 557
        13.8.2 The Bootstrap Method . . . . . . . . .                           .   .   .   .   .   .   .   . 562
        13.8.3 Comparing the Methods . . . . . . . .                            .   .   .   .   .   .   .   . 565
   13.9 Problems . . . . . . . . . . . . . . . . . . . .                        .   .   .   .   .   .   .   . 568

14 Critical Exponents                                                   577
   14.1 Critical Slowing Down . . . . . . . . . . . . . . . . . . . . . 579
   14.2 Wolff Cluster Algorithm . . . . . . . . . . . . . . . . . . . . 580
CONTENTS                                                                                                     vii

  14.3 Implementation . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   587
       14.3.1 The Program . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   589
  14.4 Production . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   594
  14.5 Data Analysis . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   597
  14.6 Autocorrelation Times . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   605
  14.7 Temperature Scaling . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   608
  14.8 Finite Size Scaling . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   614
  14.9 Calculation of βc . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   616
  14.10Studying Scaling with Collapse       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   621
  14.11Binder Cumulant . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   631
  14.12Appendix: Scaling . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   634
       14.12.1Binder Cumulant . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   634
       14.12.2Scaling . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   640
       14.12.3Finite Size Scaling . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   642
  14.13Appendix: Critical Exponents .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   645
       14.13.1Definitions . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   645
       14.13.2Hyperscaling Relations .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   646
  14.14Problems . . . . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   646

Bibliography                                                                                                650
viii                                                           CONTENTS




       This book has been written assuming that the reader executes
       all the commands presented in the text and follows all the
       instructions at the same time. If this advice is neglected, then
       the book will be of little help and some parts of the text may
       seem incomprehensible.


    The book’s website is at
http://www.physics.ntua.gr/˜konstant/ComputationalPhysics/
From there, you can can download the accompanying software, which con-
tains, among other things, all the programs presented in the book.
   Some conventions: Text using the font shown below refers to com-
mands given using a shell (the “command line”), input and output of
programs, code written in Fortran (or any other programming language),
as well as to names of files and programs:

> echo Hello world
Hello world

When a line starts with the prompt

>

then the text that follows is a command, which can be given from the
command line of a terminal. The second line, Hello World, is the output
of the command.
    The contents of a file with C++ code is listed below:

i n t main ( ) {
    double x = 0 . 0 ;
    f o r ( i n t i =0;i <10; i++){
        x += i ;
   }
}


What you need in order to work on your PC:
CONTENTS                                                                 ix

  • An operating system of the GNU/Linux family and its basic tools.

  • A Fortran compiler. The gfortran compiler is freely available
    for all major operating systems under an open source license at
    http://www.gfortran.org.

  • An advanced text editor, suitable for editing code in several pro-
    gramming languages, like Emacs².

  • A good plotting program, suitable for data analysis, like gnuplot³.

  • The shell tcsh⁴.

  • The programs awk⁵, grep, sort, cat, head, tail, less. Make sure
    that they are available in your computer environment.

    If you have installed a GNU/Linux distribution on your computer,
all of the above can be installed easily. For example, in a Debian like
distribution (Ubuntu, ...) the commands

> sudo apt−get install tcsh emacs gnuplot gnuplot−doc
> sudo apt−get install gfortran gawk gawk−doc binutils
> sudo apt−get install manpages−dev coreutils liblapack3

install all the necessary tools.
    If you don’t wish to install GNU/Linux on your computer, you can
try the following:

  • Boot your computer using a usb/DVD live GNU/Linux, like Ubuntu⁶.
    This will not make any permanent changes in your hard drive but
    it will start and run slower. On the other hand, you may save all
    your computing environment and documents and use it on any
    computer you like.

  • Install Cygwin⁷ in your Microsoft Windows. It is a very good solu-
    tion for Microsoft-addicted users. If you choose the full installation,
    then you will find all the tools needed in this book.
  ²http://www.gnu.org/software/emacs/
  ³http://www.gnuplot.info
  ⁴http://www.tcsh.org
  ⁵http://www.gnu.org/software/gawk
  ⁶http://www.ubuntu.com
  ⁷http://www.cygwin.com
x                                                             CONTENTS

    • Mac OS X is based on Unix. It is possible to install all the software
      needed in this book and follow the material as presented. Search
      the internet for instructions, e.g. google “gfortran for Mac”, “emacs
      for Mac”, “tcsh for Mac”, etc.
Foreword to the Second Edition

This book has been out “in the wild” for more than two years. Since
then, its pdf version has been downloaded 2-5000 times/month from the
main server and has a few thousand hits from sites that offer science e-
books for free. I have also received positive feedback from students and
colleagues from all over the world and that gave me the encouragement
to devote some time to create a C++ version of the book. As far as
scientific programming is concerned, the material has not changed apart
from some typo and error corrections⁸.
    I have to make it clear that by using this book you will not learn
much on the advanced features of C++. Scientific computing is usually
simple at its core and, since it must be made efficient and accurate, it
needs to go down to the lowest levels of programming. This also partly
the reason of why I chose to use Fortran for the core programming in
the first edition of the book: It is a language designed for numerical
programming and high performance computing in mind. It is simple
and a scientist or engineer can go directly into programming her code.
C++ is not designed for scientific applications⁹ in mind and this reflects
on some trivial omissions in its standard. Still, many scientific groups are
now using C++ for programming and the C++ compilers have improved
quite a lot. There is still an advantage in performance using a Fortran
compiler on a supercomputer, but this is not going to last for much longer.
    Still, for a scientist, the programming language is a tool to solve her
scientific problems. One should not bind herself to a specific language.
The treasures of today are the garbage of tomorrow, and the time scale
for this happening is small in today’s computing environments. What
has really lasting value is the ability to solve problems using a computer
and this is what needs to be emphasized. Consistent with this idea is
that, in the course of reading this book, you will also learn how to make

    ⁸Check the errata section at the book’s homepage.
    ⁹Object oriented languages’ aim is to improve modularity, maintenability and flexi-
bility of programs.


                                         xi
xii                             FOREWORD TO THE SECOND EDITION

your C++ code interact with code written in Fortran, like in the case of
the popular library Lapack. This will improve your “multilingual skills”
and flexibility with interacting with legacy code.
    The good news for us scientists is that numerical code usually needs
simple data structures and programming is similar in any language. It
was simple for me to “translate” my book from Fortran to C++. Un-
fortunately I will not touch on all this great stuff in true object oriented
programming but you may be happy to know that you will most likely
not need it¹⁰.
    So, I hope that you will enjoy using my book and I remind you that
I love fan mail and I appreciate comments/corrections/suggestions sent
to me. Now, if you want to learn about the structure and educational
procedure in this book, read the foreword to the first edition, otherwise
skip to the real fun of solving scientific problems numerically.
    Athens, 2016.




  ¹⁰A lot of C++ code out there is realizing procedural and not true object oriented
programming.
Foreword to the First Edition

This book is the culmination of my ten years’ experience in teaching
three introductory, undergraduate level, scientific computing/computational
physics classes at the National Technical University of Athens. It is suit-
able mostly for junior or senior level science courses, but I am currently
teaching its first chapters to sophomores without a problem. A two
semester course can easily cover all the material in the book, including
lab sessions for practicing.
    Why another book in computational physics? Well, when I started
teaching those classes there was no bibliography available in Greek, so I
was compelled to write lecture notes for my students. Soon, I realized that
my students, majoring in physics or applied mathematics, were having
a hard time with the technical details of programming and computing,
rather than with the physics concepts. I had to take them slowly by the
hand through the “howto” of computing, something that is reflected in
the philosophy of this book. Hoping that this could be useful to a wider
audience, I decided to translate these notes in English and put them in
an order and structure that would turn them into “a book”.
    I also decided to make the book freely available on the web. I was
partly motivated by my anger caused by the increase of academic (e)book
prices to ridiculous levels during times of plummeting publishing costs.
Publishers play a diminishing role in academic publishing. They get an
almost ready-made manuscript in electronic form by the author. They
need to take no serious investment risk on an edition, thanks to print-
on-demand capabilities. They have virtually zero cost ebook publishing.
Moreover, online bookstores have decreased costs quite a lot. Academic
books need no advertisement budget, their success is due to their aca-
demic reputation. I don’t see all of these reflected on reduced book
prices, quite the contrary, I’m afraid.
    My main motivation, however, is the freedom that independent pub-
lishing would give me in improving, expanding and changing the book
in the future. It is great to have no length restrictions for the presenta-

                                   xiii
xiv                                   FOREWORD TO THE FIRST EDITION

tion of the material, as well as not having to report to a publisher. The
reader/instructor that finds the book long, can read/print the portion of
the book that she finds useful for her.
    This is not a reference book. It uses some interesting, I hope, physics
problems in order to introduce the student to the fundamentals of solv-
ing a scientific problem numerically. At the same time, it keeps an eye
in the direction of advanced and high performance scientific computing.
The reader should follow the instructions given in each chapter, since
the book teaches by example. Several skills are taught through the solution
of a particular problem. My lectures take place in a (large) computer
lab, where the students are simultaneously doing what I am doing (and
more). The program that I am editing and the commands that I am
executing are shown on a large screen, displaying my computer monitor
and actions live. The book provides no systematic teaching of a program-
ming language or a particular tool. A very basic introduction is given in
the first chapter and then the reader learns whatever is necessary for the
solution of her problem. There is more than one way to do it¹¹ and the
problems can be solved by following a basic or a fancy way, depending
on the student’s computational literacy. The book provides the necessary
tools for both. A bibliography is provided at the end of the book, so that
the missing pieces of a puzzle can be sought in the literature.
    This is also not a computational physics playground. Of course I
hope that the reader will have fun doing what is in the book, but my
goal is to provide an experience that will set the solid foundation for
her becoming a high performance computing, number crunching, heavy
duty data analysis expert in the future. This is why the programming
language of the core numerical algorithms has been chosen to be Fortran,
a highly optimized, scientifically oriented, programming language. The
computer environment is set in a Unix family operating system, enriched
by all the powerful GNU tools provided by the FSF¹². These tools are
indispensable in the complicated data manipulation needed in scientific
research, which requires flexibility and imagination. Of course, Fortran
is not the best choice for heavy duty object oriented programming, and is
not optimal for interacting with the operating system. The philosophy¹³

   ¹¹A Perl moto!
   ¹²Free Software Foundation, www.fsf.org.
  ¹³Java and C++ have been popular choices in computational physics courses. But
object oriented programming is usually avoided in the high performance part of a com-
putation. So, one usually uses those languages in a procedural style of programming,
cheating herself that she is actually learning the advantages of object oriented program-
ming.
                                                                         xv

is to let Fortran do what is best for, number crunching, and leave data
manipulation and file administration to external, powerful tools. Tools,
like awk, shell scripting, gnuplot, Perl and others, are quite powerful
and complement all the weaknesses of Fortran mentioned before. The
plotting program is chosen to be gnuplot, which provides very powerful
tools to manipulate the data and create massive and complicated plots. It
can also create publication quality plots and contribute to the “fun part”
of the learning experience by creating animations, interactive 3d plots
etc. All the tools used in the book are open source software and they are
accessible to everyone for free. They can be used in a Linux environment,
but they can also be installed and used in Microsoft Windows and Mac
OS X.
    The other hard part in teaching computational physics to scientists
and engineers is to explain that the approach of solving a problem nu-
merically is quite different from solving it analytically. Usually, students
of this level are coming with a background in analysis and fundamental
physics. It is hard to put them into the mode of thinking about solving
a problem using only additions, multiplications and some logical opera-
tions. The hardest part is to explain the discretization of a model defined
analytically, which can be done in many ways, depending on the accu-
racy of the approximation. Then, one has to extrapolate the numerical
solution, in order to obtain a good approximation of the analytic one.
This is done step by step in the book, starting with problems in simple
motion and ending with discussing finite size scaling in statistical physics
models in the vicinity of a continuous phase transition.
    The book comes together with additional material which can be found
at the web page of the book¹⁴. The accompanying software contains all the
computer programs presented in the book, together with useful tools and
programs solving some of the exercises of each chapter. Each chapter has
problems complementing the material covered in the text. The student
needs to solve them in order to obtain hands on experience in scientific
computing. I hope that I have already stressed enough that, in order for
this book to be useful, it is not enough to be read in a café or in a living
room, but one needs to do what it says.
    Hoping that this book will be useful to you as a student or as an
instructor, I would like to ask you to take some time to send me feedback
for improving and/or correcting it. I would also appreciate fan mail or,
if you are an expert, a review of the book. If you use the book in a
class, as a main textbook or as supplementary material, I would also be

  ¹⁴www.physics.ntua.gr/˜konstant/ComputationalPhysics/
xvi                           FOREWORD TO THE FIRST EDITION

thrilled to know about it. Send me email at konstantmail.ntua.gr and
let me know if I can publish, anonymously or not, (part of) what you say
on the web page (otherwise I will only use it privately for my personal
ego-boost). Well, nothing is given for free: As one of my friends says,
some people are payed in dollars and some others in ego-dollars!
    Have fun computing scientifically!
    Athens, 2014.
Chapter 1

The Computer

The aim of this chapter is to lay the grounds for the development of
the computational skills which are necessary in the following chapters.
It is not an in depth exposition but a practical training by example.
For a more systematic study of the topics discussed, we refer to the
bibliography. Many of the references are freely available οn the web.
    The are many choices that one has to make when designing a com-
puter project. These depend on the needs for numerical efficiency, on
available programming hours, on the needs for extensibility and upgrad-
ability and so on. In this book we will get the flavor of a project that is
mostly scientifically and number crunching oriented. One has to make
the best of the available computing resources and have powerful tools
available for a productive analysis of the data. Such an environment,
found in most of today’s supercomputers, that offers flexibility, depend-
ability, simplicity, powerful tools for data analysis and effective compilers
is provided by the family of the Unix operating systems. The GNU/Linux
operating system is a Unix variant that is freely available and most of its
utilities are open source software. The voluntary work of millions of
excellent programmers worldwide has built the most stable, fastest and
highest quality software available for scientific computing today. Thanks
to the idea of the open source software pioneered by Richard Stallman¹
this giant collaboration has been made possible.
    Another choice that we have to make is the programming language.
In this edition of the book we will be programming in C++. C++ is a
language with very high level of abstraction designed for projects where
modular programming and the use of complicated data structures is of
very high priority. A large and complicated project should be divided into

  ¹www.stallman.org


                                     1
2                                           CHAPTER 1. THE COMPUTER

independent programming tasks (modules), where each task contains
everything that it needs and does not interfere with the functionality of
other modules. Although it has not been designed for high performance
numerical applications, it is becoming more and more popular in the
recent years.
    C++, as well as other languages like C, Java and Fortran, is a language
that needs to be compiled by a compiler. Other languages, like python,
perl, awk, shell scripting, Macsyma, Mathematica, Octave, Matlab, . . ., are
interpreted line by line. These languages can be simple in their use, but
they can be prohibitively slow when it comes to a numerically demand-
ing program. A compiler is a tool that analyzes the whole program and
optimizes the computer instructions executed by the computer. But if
programming time is more valuable, then a simple, interpreted language
can lead to faster results.
    Another choice that we make in this book, and we mention it because
it is not the default in most Linux distributions, is the choice of shell.
The shell is a program that “connects” the user to the operating system.
In this book, we will teach how to use a shell² to “send” commands to the
operating system, which is the most effective way to perform complicated
tasks. We will use the shell tcsh, although most of the commands can be
interpreted by most popular shells. Shell scripting is simpler in this shell,
although shells like bash provide more powerful tools, mostly needed
for complicated system administration tasks. That may cause a small
inconvenience to some readers, since tcsh is not preinstalled in Linux
distributions³.



1.1 The Operating System
The Unix family of operating systems offer an environment where com-
plicated tasks can be accomplished by combining many different tools,
each of which performs a distinct task. This way, one can use the power
of each tool, so that trivial but complicated parts of a calculation don’t
have to be programmed. This makes the life of a researcher much easier
and much more productive, since research requires from us to try many
things before we understand how to compute what we are looking for.

   ²It is more popular to be called “the command line”, or the “terminal”, or the
“console”, but in fact the user interaction is through a shell.
   ³See www.tcsh.org. On Debian like systems, like Ubuntu, installation is very simple
through the software center or by the command sudo apt-get install tcsh.
1.1. THE OPERATING SYSTEM                                                          3

    In the Unix operating system everything is a file, and files are or-
ganized in a unique and unified filesystem. Documents, pictures, music,
movies, executable programs are files. But also directories or devices,
like hard disks, monitors, mice, sound cards etc, are, from the point of
view of the operating system, files. In order for a music file to be played
by your computer, the music data needs to be written to a device file,
connected by the operating system to the sound card. The characters
you type in a terminal are read from a file “the keyboard”, and written
to a file “the monitor” in order to be displayed. Therefore, the first thing
that we need to understand is the structure of the Unix filesystem.


1.1.1 Filesystem
There is at least one path in the filesystem associated with each file. There
are two types of paths, relative paths and absolute paths. These are two
examples:

bin / RungeKutta / rk . exe
/ home / george / bin / RungeKutta / rk . exe

The paths shown above may refer to the same or a different file. This
depends on “where we are”. If “we are” in the directory /home/george,
then both paths refer to the same file. If on the other way “we are” in
a directory /home/john or /home/george/CompPhys, then the paths refer⁴
to two different files. In the last two cases, the paths refer to the files

/ home / john / bin / RungeKutta / rk . exe
/ home / george / CompPhys / bin / RungeKutta / rk . exe

respectively. How can we tell the difference? An absolute path always
begins with the / character, whereas a relative path does not. When we
say that “we are in a directory”, we refer to a position in the filesystem
called the current directory, or working directory. Every process in the
operating system has a unique current directory associated with it.
    The filesystem is built on its root and looks like a tree positioned
upside down. The symbol of the root is the character / The root is
a directory. Every directory is a file that contains a list of files, and it
is connected to a unique directory, its parent directory . Its list of files
contains other directories, called its subdirectories, which all have it as
  ⁴Some times two or more paths refer to the same file, or as we say, a file has two or
more “links” in the same filesystem, but let’s keep it simple for the moment.
4                                              CHAPTER 1. THE COMPUTER




Figure 1.1: The Unix filesystem. It looks like a tree, with the root directory / at the
top and branches that connect directories with their parents. Every directory contains
files, among them other directories called its subdirectories. Every directory has a unique
parent directory, noted by .. (double dots). The parent of the root directory is itself.




their parent directory. All these files are the contents of the directory.
Therefore, the filesystem is a tree of directories with the root directory
at its top which branch to its subdirectories, which in their turn branch
into other subdirectories and so on. There is practically no limit to how
large this tree can become, even for a quite demanding environment⁵.
    A path consists of a string of characters, with the characters / sep-
arating its components, and refers to a unique location in the filesystem.
Every component refers to a file. All, but the last one, must be directories
in a hierarchy, from parent directory to subdirectory. The only exception
is a possible / in the beginning, which refers to the root directory. Such

    ⁵Of course, the capacity of the filesystem is finite, issue the command “df -i .” in
order to see the number of inodes available in your filesystem. Every file corresponds
to one and only one inode of the filesystem. Every path is mapped to a unique inode,
but an inode maybe pointed to by more than one paths.
1.1. THE OPERATING SYSTEM                                                                5

an example can be seen in figure 1.1.
    In a Unix filesystem there is complete freedom in the choice of the loca-
tion of the files⁶. Fortunately, there are some universally accepted conven-
tions respected by almost everyone. One expects to find home directories
in the directory /home, configuration files in the directory /etc, appli-
cation executables in directories with names such as /bin, /usr/bin,
/usr/local/bin, software libraries in directories with names such as
/lib, /usr/lib etc.
    There are some important conventions in the naming of the paths. A
single dot “.” refers to the current directory and a double dot “..” to the
parent directory. Similarly, a tilde “~” refers to the home directory of the
user. Assume, e.g., that we are the user george running a process with
a current directory /home/george/Music/Rock (see figure 1.1). Then, the
following paths refer to the same file /home/george/Doc/lyrics.doc:

. . / . . / Doc / lyrics . doc
~/ Doc / lyrics . doc
~george / Doc / lyrics . doc
. / . . / . . / Doc / lyrics . doc

Notice that ~ and ~george refer to the home directory of the user george
(ourselves), whereas ~mary refer to the home directory of another user,
mary.
   We are now going to introduce the basic commands for filesystem
navigation and manipulation⁷. The command cd (=change directory)
changes the current directory, whereas the command pwd (=print working
directory) prints the current directory:

> cd / usr / bin
> pwd
/ usr / bin
> cd / usr / local / lib
> pwd
/ usr / local / lib
> cd

    ⁶This gives a great sense of freedom, but historically this was a important factor that
led the Unix operating systems, although superior in quality, not to win a fair share
of the market! The Linux family tries to keep things simple and universal to a large
extent, but one should be aware that because of this freedom files in different version
of Linuxes or Unices can be in different places.
    ⁷Remember that lines that begin with the > character are commands. All other lines
refer to the output of the commands.
6                                         CHAPTER 1. THE COMPUTER

> pwd
/ home / george
> cd −
> pwd
/ usr / local / lib
> cd . . / . . /
> pwd
/ usr

The argument of the command cd is an absolute or a relative path. If
the path is correct and we have the necessary permissions, the command
changes the current directory to this path. If no path is given, then
the current directory changes to the home directory of the user. If the
character - is given instead of a path, then the command changes the
current directory to the previous current directory.
   The command mkdir creates new directories, whereas the command
rmdir removes empty directories. Try:

> mkdir new
> mkdir new / 0 1
> mkdir new / 0 1 / 0 2 / 0 3
mkdir : cannot create directory ‘ new / 0 1 / 0 2 / 0 3 ’ : No such file or
        directory
> mkdir −p new / 0 1 / 0 2 / 0 3
> rmdir new
rmdir : ‘ new ’ : Directory not empty
> rmdir new / 0 1 / 0 2 / 0 3
> rmdir new / 0 1 / 0 2
> rmdir new / 0 1
> rmdir new

Note that the command mkdir cannot create directories more than one
level down the filesystem, whereas the command mkdir -p can. The
“switch” -p makes the behavior of the command different than the default
one.
    In order to list the contents of a directory, we use the command ls
(=list):

> ls
BE . eps Byz . eps    Programs         srBE_xyz . eps   srB_xyz . eps
B . eps  Bzy . eps    srBd_xyz . eps   srB_xy . eps
> l s Programs
Backup                 rk3_Byz . cpp   rk3 . cpp
plot−commands          rk3_Bz . cpp    rk3_g . cpp
1.1. THE OPERATING SYSTEM                                                                 7

The first command is given without an argument and it lists the con-
tents of the current directory. The second one, lists the contents of the
subdirectory of the current directory Programs. If the argument is a list
of paths pointing to regular files, then the command prints the names of
the paths. Another way of giving the command is

total 252
-rw-r--r--       1   george   users   24284   May    1   12:08   BE . eps
-rw-r--r--       1   george   users   22024   May    1   11:53   B . eps
-rw-r--r--       1   george   users   29935   May    1   13:02   Byz . eps
-rw-r--r--       1   george   users   48708   May    1   12:41   Bzy . eps
drwxr -xr-x      4   george   users    4096   May    1   23:38   Programs
-rw-r--r--       1   george   users   41224   May    1   22:56   srBd_xyz . eps
-rw-r--r--       1   george   users   23187   May    1   21:13   srBE_xyz . eps
-rw-r--r--       1   george   users   24610   May    1   20:29   srB_xy . eps
-rw-r--r--       1   george   users   23763   May    1   20:29   srB_xyz . eps

The switch -l makes ls to list the contents of the current directory to-
gether with useful information on the files in 9 columns. The first column
lists the permissions of the files (see below). The second one lists the num-
ber of links of the files⁸. The third one lists the user who is the owner of
each file. The fourth one lists the group that is assigned to the files. The
fifth one lists the size of the file in bytes (=8 bits). The next three ones
list the modification time of the file and the last one the paths of the files.
     File permissions⁹ are separated in three classes: owner permissions,
group permissions and other permissions. Each class is given three spe-
cific permissions, r=read, w=write and x=execute. For regular files, read
permission effectively means access to the file for reading/copying, write
permission means permission to modify the contents of the file and ex-
ecute permission means permission to execute the file as a command¹⁰.
For directories, read permission means that one is able to read the names
of the files in the directory (but not make it as current directory with the
cd command), write permission means to be able to modify its contents
(i.e. create, delete, and rename files) and execute permission grants per-
mission to access/modify the contents of the files (but not list the names
of the files, this is granted by the read permission).
     The command ls -l lists permissions in three groups. The owner
    ⁸For a directory it means the number of its subdirectories plus 2 (the parent directory
and itself). For a regular file, it shows how many paths in the filesystem point to this
file.
    ⁹See the “File system permissions” entry in en.wikipedia.org.
   ¹⁰Of course it is the user’s responsibility to make sure the file with execute permission
is actually a program that is possible to execute. An error results if this is not the case.
8                                      CHAPTER 1. THE COMPUTER

(positions 2-4), the group (positions 5-7) and the rest of the world (others
- positions 8-10). For example

-rw-r--r--
-rwxr-----
drwx--x--x

In the first case, the owner has read and write but not execute permissions
and the group+others have only read permissions. In the second case,
the user has read, write and execute permissions, the group has read
permissions and others have no permissions at all. In the last case, the
user has read, write and execute permissions, whereas the group and the
world have only execute permissions. The first character d indicates a
special file, which in this case is a directory. All special files have this
position set to a character, while regular files have it set to -.
    File permissions can be modified by using the command chmod:

> chmod u+x file
> chmod og−w file1 file2
> chmod a+r file

Using the first command, the owner (u≡ user) obtains (+) permission
to execute (x) the file named file. Using the second one, the rest of
the world (o≡ others) and the group (g≡group) loose (-) the write (w)
permission to the files named file1 and file2. Using the third one,
everyone (a≡all) obtain read (r) permission on the file named file.
   We will close this section by discussing some commands which are
used for administering files in the filesystem. The command cp (copy)
copies the contents of files into other files:

> cp file1 . cpp file2 . cpp
> cp file1 . cpp file2 . cpp file3 . cpp Programs

If the file file2.cpp does not exist, the first command copies the contents
of file1.cpp to a new file file2.cpp. If it already exists, it replaces its
contents by the contents of the file file2.cpp. In order for the second
command to be executed, Programs needs to be a directory. Then, the
contents of the files file1.cpp, file2.cpp, file3.cpp are copied to
indentical files in the directory Programs. Of course, we assume that
the user has the appropriate privileges for the command to be executed
successfully.
    The command mv “moves”, or renames, files:
1.1. THE OPERATING SYSTEM                                                            9


> mv file1 . cpp file2 . cpp
> mv file1 . cpp file2 . cpp file3 . cpp Programs

The first command renames the file file1.cpp to file2.cpp. The second
one moves files file1.cpp, file2.cpp, file3.cpp into the directory
Programs.
   The command rm (remove) deletes files¹¹. Beware, the command is
unforgiving: after deletion, a file cannot be restored into the filesystem¹².
Therefore, after executing successfully the following commands

> ls
file1 . cpp file2 . cpp file3 . cpp file4 . csh
> rm file1 . cpp file2 . cpp file3 . cpp
> ls
file4 . csh

the files file1.cpp, file2.cpp, file3.cpp do not exist in the filesystem
anymore. A more prudent use of the command demands the flag -i.
Then, before deletion we are asked for confirmation:

> rm −i *
rm : remove   regular    file   ‘ file1 . cpp ’ ?   y
rm : remove   regular    file   ‘ file2 . cpp ’ ?   y
rm : remove   regular    file   ‘ file3 . cpp ’ ?   y
rm : remove   regular    file   ‘ file4 . csh ’ ?   n
> ls
file4 . csh

When we type y, the file is deleted, when we type n, the file is not deleted.
   We cannot remove directories the same way. It is possible to use
the command rmdir in order to remove empty directories. In order to
delete directories together with their contents (including subdirectories
and their contents) use the command¹³ rm -r. For example, assume that
the contents of the directories dir1 and dir1/dir2 are the files:

. / dir1

  ¹¹Actually it removes “links” from files. A file may have more than one links in the
same partition of a filesystem. A file is deleted when its last link is removed.
  ¹²This does not mean that its contents have been deleted from the disk. Deletion
means marking for overwriting. Until the data is overwritten it can be recovered by the
use of special tools. Shredding sensitive data can be tricky business...
  ¹³A small mistake, like rm -rf * and your data is ... history!
10                                      CHAPTER 1. THE COMPUTER

. / dir1 / file2 . cpp
. / dir1 / file1 . cpp
. / dir1 / dir2
. / dir1 / dir2 / file3 . cpp

Then the results of the following commands are:

> rm dir1
rm : cannot remove ‘ dir1 ’ : Is a directory
> rm dir1 / dir2
rm : cannot remove ‘ dir1 / dir2 ’ : Is a directory
> rmdir dir1
rmdir : dir1 : Directory not empty
> rmdir dir1 / dir2
rmdir : dir1 / dir2 : Directory not empty
> rm −r dir1

The last command removes all files (assuming that we have write per-
missions for all directories and subdirectories). Alternatively, we can
empty the contents of all directories first, and then remove them with the
command rmdir:

>   cd   dir1 / dir2 ; rm file3 . cpp
>   cd   . . ; rmdir dir2
>   rm   file1 . cpp file2 . cpp
>   cd   . . ; rmdir dir1

Note that by using a semicolon, we can execute two or more commands
on the same line.


1.1.2 Commands
Commands in a Unix operating system are files with execute permission.
When we write a sentence on the command line, like

> l s −l test . cpp test . dat

the shell reads its and interprets it. The shell is a program that creates a
interface between a user and the operating system. The first word (ls) of
the sentence is interpreted as a command. The rest of the words are the
arguments of the command and the program can use them (or not) at the
discretion of its programmer. There is a special convention for arguments
that begin with a - (e.g. -l, --help, --version, -O3). They are called
1.1. THE OPERATING SYSTEM                                                         11

options or switches, and they act as virtual switches that make the program
act in a particular way. We have already seen that the program ls gives
a different output with the switch -l.
    In order for a command to be executed, the shell looks for a file that
has the same name as the command (here a file named ls). In order
to understand where the shell looks for such a file, we should digress
a little bit and explain the use of shell variables and environment variables.
These have a name, which is a string of permissible characters, and their
values are obtained by preceding their name with the $ character. For
example the variable PATH has value $PATH. The values of the environment
variables can be set with the command¹⁴ setenv and of the shell variables
with the command set:

> s e t e n v MYVAR test−env
> s e t myvar = test−s h e l l
> echo $MYVAR $myvar
test−env test−s h e l l

Two special variables are the variables PATH and path:

>echo $PATH
/ usr / local / bin : / usr / bin : / bin : / usr / X11 / bin
>echo $path
/ usr / local / bin / usr / bin / bin / usr / X11 / bin

The first one is an environment variable and the second one is a shell
variable. Their values are set by the shell, and we don’t need to worry
about them, unless we want to change them. Their value is a string of
characters whose components should be valid paths to directories. In
the first case, the components are separated by a :, while in the second
case, by one or more spaces. In the example shown above, the shell
searches each component of the path or PATH variables (in this order)
until it finds a file ls in their contents. If it succeeds and the file has
execute permissions, then the program in this file is executed. If it fails,
then it prints an error message. Try the commands:

> which l s
/ bin / l s
> l s −l / bin / l s

   ¹⁴The command setenv is special to the tcsh shell. For example the bash shell uses
the syntax MYVAR=test-env in order to set the value of an environment variable.
12                                        CHAPTER 1. THE COMPUTER

−rwxr−xr−x 1 root root 93560 Sep 28          2006 / bin / l s

We see that the program that the ls command executes the program in
the file /bin/ls.
   The arguments of a command are passed on to the program that the
command executes for possible interpretation. For example:

> l s −l test . cpp test . dat

The argument -l is the switch that results in a long listing of the files.
The arguments test.cpp and test.dat are interpreted by the program
ls as paths that it will look up for file information.
   You can use the * (wildcard) character as a shorthand notation for a
group of files. For example, in the command shown below

> l s −l * . cpp * . dat

the shell will expand *.cpp and *.dat to a list of all files whose names
end with .cpp or .dat. Therefore, if the current directory contains the
files test.cpp, test1.cpp, myprog.cpp, test.dat, hello.dat, the ar-
guments that will be passed on to the command ls are

> l s −l myprog . cpp test1 . cpp test . cpp hello . dat test . dat

    For each command there are three special files associated with it. The
first one is the standard input (stdin), the second one is the standard output
(stdout) and the third one the standard error (stderr). These are files
where the program can print or read data from. By default, these files
are the terminal that the user uses to execute the command. In this case,
when the program reads data from the stdin, then it reads the data
that we type to the terminal using the keyboard. When the program
writes data to the stdout or to the stderr, then the data is written to the
terminal.
    The advantage of using these special files in order to read/write data
is that the user can redirect the input/output to these files to any file she
wants. Using the character > at the end of a command redirects the
stdout to the file whose name is written after >. For example:

> ls
file1 . cpp file2 . cpp    file3 . cpp   file4 . csh
> l s > results
1.1. THE OPERATING SYSTEM                                                           13

> ls
file1 . cpp   file2 . cpp    file3 . cpp      file4 . csh   results


The first of the above commands, prints the contents of the current work-
ing directory to the terminal. The second command redirects data written
to the stdout to the file results. After executing the command, the file
results is created and its contents are the names of the files file1.cpp
file2.cpp file3.cpp file4.csh. If the file results does not exist (as in
the above example), the file is created. If it already exists, it is truncated
and its contents replaced by the data written to the stdout of the com-
mand. If we want to append data without erasing the existing contents,
then we should use the string of characters >>. Therefore, if we give the
command

> l s >> results


after executing the previous commands, then the contents of the file
results will be

file1 . cpp   file2 . cpp    file3 . cpp      file4 . csh
file1 . cpp   file2 . cpp    file3 . cpp      file4 . csh   results


   The redirection of the stdin is accomplished by the use of the char-
acter < while that of the stderr by the use of the string of characters¹⁵
>&. We will see more examples in section 1.2.
   It is possible to redirect the stdout of a command to be the stdin
of another command. This is very useful for creating filters. A filter is
a command that creates a flow of data between two or more programs.
This process is called piping. Pipes are creating by using the character |

> cmd1 | cmd2 | cmd3 |         ...   | cmdN


Using the syntax shown above, the stdout of the command cmd1 is redi-
rected to the stdin of the command cmd2, the stdout of the command
cmd2 is redirected to the stdin of the command cmd3 etc. More examples
will be presented in section 1.2.

   ¹⁵This syntax is particular to the tcsh shell. For other shells (bash, sh, ...) read
their documentation.
14                                        CHAPTER 1. THE COMPUTER

1.1.3 Looking for Help
Unix got itself a reputation for not being user friendly. This is far from the
truth. Although there is a steep learning curve, detailed documentation
for almost everything is available online.
    The key for a comfortable ride is to learn how to use the help system
available on your computer and on the internet. Most of the commands
are self documented. A simple test, like the one shown below, will help
you with the basic usage of most of the commands:

>   cmd   --help
>   cmd   -h
>   cmd   -help
>   cmd   -\?

For example, try the command ls --help. For a window application,
start from the menu “Help”. You should not be afraid and/or lazy and
you should proceed with careful searching and reading.
    For example, let’s assume that you have heard about a command that
sounds like printf, or something like that. The first level of online help
is the man (=manual) command that searches the “man pages”. Read the
output of the command

> man p r i n t f

The command info usually provides more detailed and user friendly
documentation. It has basic browsing capabilities like the browsers you
use to read pages from the internet. Try the command

> info printf

Furthermore, the commands

> man −k p r i n t f
> whatis p r i n t f

will inform you that there are other, possibly related, commands with
names like fprintf, fwprintf, wprintf, sprintf...:

> whatis p r i n t f
printf                   (1)      − format and p r i n t data
printf                   (1 p )   − write formatted output
1.1. THE OPERATING SYSTEM                                                     15

printf                       (3)      − formatted output conversion
printf                       (3 p )   − p r i n t formatted output
p r i n t f [ builtins ]     (1)      − bash built−in commands , see bash←-
      (1)

The second column printed by the whatis command is the “section” of
the man pages. In order to gain access to the information in a particular
section, you have to give it as an argument to the man command:

>   man   1 printf
>   man   1p p r i n t f
>   man   3 printf
>   man   3p p r i n t f
>   man   bash

Section 1 of the man pages contains information of ordinary command
line commands, section 3 contains information on functions in libraries
of the C language. Section 2 contains information on commands used for
system administration. You may browse the directory /usr/share/man,
or read the man page of the man command (use the command man man
for that!).
    By using the command

> p r i n t f --help

we obtain plenty of memory refreshing information. The command

> locate printf

shows us many files related to the command printf. The commands

> which p r i n t f
> where p r i n t f

give information on the location of the executable(s) of the command
printf.
   Another useful feature of the shell is the command or it filename com-
pletion.   This means that we can write only the first characters of the
name of a command or filename and then press simultaneously the keys
[Ctrl-d]¹⁶ (i.e. press the key Ctrl and the key of the letter d at the same

    ¹⁶If you use the bash shell press [Tab] once or twice.
16                                            CHAPTER 1. THE COMPUTER

time). Then the shell will complete the name of the command up to the
point that is is unique with the given string of characters¹⁷:

> pri [ Ctrl−d ]
printafm       printf      printenv       printnodetest

Try to type an x on the command line and then type [Ctrl-d]. You will
learn all the commands that are available and whose name begins with
an x: xterm, xeyes, xclock, xcalc, ...
    Finally, the internet contains a wealth of information. Google your
blues... and you will be rewarded!


1.2 Text Processing Tools – Filters
For doing data analysis, we will need powerful tools for manipulating
data in text files. These are files that consist solely of printable charac-
ters. Some tools that can be used in order to construct complicated and
powerful filters are the programs cat, less, head, tail, grep, sort
and awk.
    Suppose that we have data in a file named data¹⁸ which contains
information on the contents of a food warehouse and their prices:

bananas     100   pieces   1.45
apples      325   boxes    1.18
pears        34   kilos    2.46
bread        62   kilos    0.60
ham          85   kilos    3.56

The command

> c a t data

prints the contents of the file data to the stdout. In general, this com-
mand prints the contents of all files given in its arguments or the stdin
if none is given. Since the stdin and the stdout can be redirected, the
command
   ¹⁷Use the same procedure to auto-complete the names of files in the arguments of
commands.
   ¹⁸The particular file, as well as most of the files in this section, can be found in the
accompanying software of the chapter. It is highly recommended that you try all the
commands in this section by using all the provided files.
1.2. TEXT PROCESSING TOOLS – FILTERS                                   17


> cat <       data > data1

takes the contents of the file data from the stdin and prints them to the
stdout, which in this case is the file data1. This command has the same
result as the command:

> cp data data1

The command

> c a t data data1 > data2

prints the contents of the file data and then the contents of the file data1
to the stdout. Since the stdout is redirected to the file data2, data2
contains the data of both files.
   By giving the command

> l e s s g f o r t r a n . txt

you can browse the data contained in the file gfortran.txt one page at
a time. Press [space] in order to “turn” a page, [b] to turn back a page.
Press the up and down arrows to move one line backwards/forward.
Press [g] in order to jump to the beginning of the file and press [G] in
order to jump to the end. Press [h] in order to get a help message and
press [q] in order to quit.
    The commands

> head −n 1 data
bananas 100 pieces 1 . 4 5
> t a i l −n 2 data
bread        62 kilos 0.60
ham          85 kilos 3.56
> t a i l −n 2 data | head −n 1
bread        62 kilos 0.60

print the first line, the last two lines and the second to the last line of
the file data to the stdout respectively. Note that, by piping the stdout
of the command tail to the stdin of the command head, we are able to
construct the filter “print the line before the last one”.
    The command sort sorts the contents of a file by comparing each line
of its text with all others. The sorting is alphabetical, unless otherwise
set by using options. For example
18                                    CHAPTER 1. THE COMPUTER


> s o r t data
apples      325   boxes    1.18
bananas 100       pieces   1.45
bread        62   kilos    0.60
ham          85   kilos    3.56
pears        34   kilos    2.46

For reverse sorting, try sort -r data. We can also sort by comparing
specific fields of each line. By default, fields are words separated by one
or more spaces. For example, in order to sort w.r.t. the second column
of the file data, we can use the switch -k 2 (=second field). Furthermore,
we can use the switch -n for numerical sorting:

> s o r t −k 2 −n data
pears        34 kilos      2.46
bread        62 kilos      0.60
ham          85 kilos      3.56
bananas 100 pieces         1.45
apples      325 boxes      1.18

If we omit the switch -n, the comparison of the lines is performed based
on character sorting of the second field and the result is

> s o r t −k 2 data
bananas 100 pieces         1.45
apples      325 boxes      1.18
pears        34 kilos      2.46
bread        62 kilos      0.60
ham          85 kilos      3.56

The last column contains floating point numbers (not integers). In order
to sort by the values of such numbers we should use the switch -g:

> s o r t −k 4 −g data
bread        62 kilos      0.60
apples      325 boxes      1.18
bananas 100 pieces         1.45
pears        34 kilos      2.46
ham          85 kilos      3.56

    The command grep processes a text file line by line, searching for a
given string of characters. When this string is found anywhere in a line,
this line is printed to the stdout. The command
1.2. TEXT PROCESSING TOOLS – FILTERS                                     19


> grep kilos data
pears     34 kilos          2.46
bread     62 kilos          0.60
ham       85 kilos          3.56

prints each line containing the string “kilos”. If we want to search for all
line not containing the string “kilos”, then we add the switch -v:

> grep −v kilos data
bananas 100 pieces 1 . 4 5
apples   325 boxes 1 . 1 8

We can use a regular expression for searching a whole family of strings
of characters. These monsters need a full book for discussing them in
detail! But it is not hard to learn how to use some simple forms of
regular expressions. Here are some examples:

> grep ^b data
bananas 100 pieces          1.45
bread        62 kilos       0.60
> grep ’0$ ’ data
bread        62 kilos       0.60
> grep ’ 3 [ 2 4 ] ’ data
apples    325 boxes         1.18
pears        34 kilos       2.46

The first one, prints each line whose first character is a b. The second
one, prints each line that ends with a 0. The third one, prints each line
contaning the strings 32 or 34.
   By far, the strongest tool in our toolbox is the awk program. By
default, awk analyzes a text file line by line. Each word (or field in the
awk jargon) of these lines is stored in a set of variables with names
$1, $2, .... The variable $0 contains the full line currently processed,
whereas the variable NF counts the number of fields in the current line.
The variable NR counts the number of lines of the file processed so far by
awk.
   An awk program can be written in the command line. A set of com-
mands within { ... } is executed for each line of input. The constructs
BEGIN{ ... } and END{ ... } contain commands executed, only once,
before and after the processing of the file respectively. For example, the
command
20                                                 CHAPTER 1. THE COMPUTER

> awk ’{ p r i n t   $1 , ” t o t a l v a l u e= ” , $2 * $4 } ’ data
bananas total        value= 145
apples total         value= 383.5
pears    total       value= 83.64
bread    total       value= 3 7 . 2
ham      total       value= 302.6

prints the name of the product (1st column = $1) and the total value
stored in the warehouse (2nd column = $2) × (4th column = $4). More
examples are given below:

> awk ’{ value += $2 * $4 }END{ p r i n t ” T o t a l= ” , value } ’ data
Total= 951.94
> awk ’{ av += $4 }END{ p r i n t ” Average P r i c e = ” , av / NR } ’ data
Average Price= 1.85
> awk ’{ p r i n t $2^2 * sin ( $4 ) + exp ( $4 ) } ’ data

The first one calculates the total value of all products: The processing
of each line results in the increment (+=) of the variable value by the
product of the second and fourth fields. In the end (END{ ... }),
the string Total= is printed, together with the final value of the variable
value. This is an easy way for computing the sum of the values calculated
for each line. The second command, calculates and prints an average.
The sum is calculated in each line and stored in the variable av. In the
end, we print the quotient of the sum of all values by the number of
lines that have been processed (NR). The last command shows a (crazy)
mathematical expression based on numerical values found in each line
of the file data: It computes the square of the second field times the sine
of the fourth field plus the exponential of the fourth field.
    There is much more potential in the commands presented above.
Reading the documentation and getting experience by using them will
provide you with very strong tools in order to accomplish complicated
tasks.


1.3 Programming with Emacs
For a programmer that spends many hours programming every day, the
environment and the tools available for editing the commands of a large
and complicated program determine, to a large extent, the quality of
her life! An editor edits the contents of a text file, that consists solely of
printable characters. Such editors, available in most Linux environments,
are the programs gedit, vim, pico, nano, zile... They provide basic
1.3. PROGRAMMING WITH EMACS                                                          21

functionality such as adding, removing or changing text within a file as
well as more complicated functions, such as copying, pasting, searching
and replacing text etc. There are many functions that are particularly
useful to a programmer, such as detecting and formatting keywords of
a particular programming language, pretty printing, closing scopes etc,
which can be very useful for comfortable programming and for spotting
errors. A very powerful and “knowledgeable” editor, offering many such
functions for several programming languages, is the GNU Emacs editor¹⁹.
Emacs is open source software, it is available for free and can be used
in most available operating systems. It is programmable²⁰ and the user
can automate most of her everyday repeated tasks and configure it to her
liking. There is a full interaction with the operating system, in fact Emacs
has been built with the ambition of becoming an operating system. For
example, a programmer can edit a C++ file, compile it, debug it and run
it, everything done with Emacs commands.


1.3.1     Calling Emacs
In the command line type

> emacs &

Note the character & at the end of the line. This makes the particular
command to run in the background. Without it, the shell waits until a
command exits in order to return the prompt.
   In a desktop environment, Emacs starts in its own window. For a
quick and dirty editing session, or in the case that a windows environ-
ment is not available²¹, we can run Emacs in a terminal mode. Then, we
omit the & at the end of the line and we run the command

> emacs −nw

The switch -nw forces Emacs to run in terminal mode.
   ¹⁹http://www.gnu.org/software/emacs/                    (main                  site),
http://www.emacswiki.org/ (expert tips), http://en.wikipedia.org/wiki/Emacs
(general info)
   ²⁰Emacs is written in a dialect of the programming language Lisp, called Elisp. There
is no need of an in-depth knowledge of the language in order to program simple
functions, just see how others are doing it...
   ²¹Quite handy when we edit files in a remote computer.
22                                             CHAPTER 1. THE COMPUTER




Figure 1.2: The Emacs window in a windows environment. The buttons of very
basic functions found on its toolbar are shown and explained.



1.3.2 Interacting with Emacs
We can interact with Emacs in various ways. Newbies will prefer buttons
and menus that offer a simple and intuitive interface. For advanced
usage, however, we recommend that you make an effort to learn the
keyboard shortcuts. There are also thousands of functions available to
be used interactively. They are called from a “command line”, called the
minibuffer in the Emacs jargon.
    Keyboard shortcuts are usually combinations of keystrokes that con-
sist of the simultaneous pressing of the Ctrl or Alt keys together with
other keys. Our convention is that a key sequence starting with a C-
means that the characters that follow are keys simultaneously pressed
with the Ctrl key. A key sequance starting with a M- means that the
characters that follow are keys simultaneously pressed with the Alt key²².

   ²²Actually, M- is the so called Meta key, usually bound to the Alt key. It is also bound
to the Esc and C-[ keys. The latter can be our only choices available in dumb terminals.
1.3. PROGRAMMING WITH EMACS                                                       23




Figure 1.3: Emacs in a non-window mode running on the console. In this figure,
we have typed the command save-buffers-kill-emacs in the minibuffer, a command
that exits Emacs after saving edited data from all buffers. The same command can be
given using the keyboard shortcut C-x C-c. We can see the mode line and the name of
the buffer toy.f written on it, the percentage of the buffer (6%) shown in the window,
the line and columns (33,0) where the point lies and the editing mode which is active
on the buffer (Fortran mode (Fortran), Abbreviation mode (Abbrev), Auto Fill mode
(Fill)).



Some commands have shortcuts consisting of two or more composite
keystrokes. For example by C-x C-c we mean that we have to press
simultaneously the Ctrl key together with x and then press simultane-
ously the Ctrl key together with c. This sequence is a shortcut to the
command that exits Emacs. Another example is C-x 2 which means to
press the Ctrl key together with x and then press only the key 2. This
is a shortcut to the command that splits a window horizontally to two
equal parts.
    The most useful shortcuts are M-x (press the Alt key siumutaneously
with the x key) and C-g. The first command takes us to the minibuffer
where we can give a command by typing its name. For example, type
M-x and then type save-buffers-kill-emacs in the minibuffer (this will
terminate Emacs). The second one is an “SOS button” that interrupts
anything Emacs does and returns control to the working buffer. This
24                                         CHAPTER 1. THE COMPUTER

can be pretty handy when a command hangs or destroys our work and
we need to interrupt it.




Figure 1.4: The basic menus found in Emacs when run in a desktop environment. We
can see the basic commands and the keyboard shortcut reminders in the parentheses.
E.g. the command File → Visit New File can be given by typing C-x C-f. Note
the commands File → Visit New File (open a file), File→Save (write contents of
a buffer to a file), File→Exit Emacs, File → Split Window (split window in two),
File→New Frame (open a new Emacs desktop window) and of course the well known
commands Cut, Copy, Paste, Undo from the Edit menu. We can choose different
buffers from the menu Buffers, which contain the contents of other files that we have
opened for editing. We recommend trying the Emacs Tutorial and Read Emacs Manual
in the Help menu.



   The conventions for the mouse events are as follows: With Mouse-1,
Mouse-2 and Mouse-3 we denote a simple click with the left, middle and
right buttons of the mouse respectively. With Drag-Mouse-1 we mean to
press the left button of the mouse and at the same time drag the mouse.
   We summarize the possible ways of giving a command in Emacs with
the following examples that have the same effect: Open a file and put its
contents in a buffer for editing.

     • By pressing the toolbar button that looks like a white sheet of paper
       (see figure 1.2).

     • By choosing the File→Visit New File menu entry.
1.3. PROGRAMMING WITH EMACS                                                             25

   • By typing the keyboard shortcut C-x C-f.
   • By typing the name of the command in the minibuffer: M-x find-file
The number of available commands increases from the top to the bottom
of the above list.

1.3.3      Basic Editing
In order to edit a file, Emacs places the contents of a file in a buffer. Such
a buffer is a chunk of computer memory where the contents of the file
are copied and it is not the file itself. When we make changes to the
contents of a buffer, the file remains intact. For our changes to take effect
and be written to the file, we have to save the buffer. Then, the contents
of the buffer are written back to the file. It is important to understand
the following cycle of events:
   • Read a file’s contents to a buffer.
   • Edit buffer contents.
   • Write (save) buffer’s contents back into the file.
Emacs may have more than one buffers open for editing simultaneously.
By default, the name of the buffer is the same as the name of the file
that is edited, although this is not necessary²³. The name of a buffer is
written in the modeline of the window of the buffer, as can be seen in
figure 1.3.
   If Emacs crashes or exits before we save our edits, it is possible to
recover (part of) them. There is a command M-x recover-file that will
guide us through the necessary recovery steps, or we can look for a file
that has the same name as the buffer we were editing surrounded by two
#. For example, if we were editing the file file.cpp, the automatically
saved changes can be found in the file #file.cpp#. Auto saving is done
periodically by Emacs and its frequency can be controlled by the user.
   The point where we insert text while editing is called “the point”.
This is right before the blinking cursor²⁴. Each buffer has another posi-
   ²³The user can change the name of the buffer without affecting the name of the file
it edits. Also, if we open more than one files with the same name, emacs gives each
buffer a unique name. E.g. if we edit more than one files named index.html then the
corresponding buffers are named index.html, index.html<2>, index.html<3>, ... .
   ²⁴Strictly speaking, the point lies between two characters and not on top of a character.
The cursor lies on the character immediately to the right of the point. A point is assigned
to every window, therefore a buffer can have multiple points, one for each window that
displays its contents.
26                                         CHAPTER 1. THE COMPUTER

tion marked by “the mark”. A point and the mark define a “region”
in the buffer. This is a part of the text in the buffer where the func-
tions of Emacs can act (e.g. copy, cut, change case, spelling etc.). We
can set the region by setting a point and then press C-SPC²⁵ or give the
command M-x set-mark-command. This defines the current point to be
the mark. Then we can move the cursor to another point which will
define a region together with the mark that we set. Alternatively we can
use Drag-Mouse-1 (hold the left mouse button and drag the mouse) and
mark a region. The mark can be set with Mouse-3, i.e. with a simple
click of the right button of the mouse. Therefore by Mouse-1 at a point
and then Mouse-3 at a different point will set the region between the two
points.
    We can open a file in a buffer with the command C-x C-f, and then
by typing its path. If the file already exists, its contents are copied to a
buffer, otherwise a new buffer is created. Then:

     • We can browse the buffer’s contents with the Up/Down/Left/Right
       arrows. Alternatively, by using the commands C-n, C-p, C-f and
       C-b.

     • If the buffer is large, we can browse its contents one page at a time
       by using the Page Up/Page Dn keys. Alternatively, by using the
       commands C-v, M-v.

     • Enter text at the points simply by typing it.

     • Delete characters before the point by using the Backspace key and
       after the point by using the Delete key. The command C-d deletes
       a forward character.

     • Erase all the characters in a line that lie ahead of the point by using
       the command C-k.

     • Open a new line by using Enter or C-o.

     • Go to the first character of a line by using Home and the last one
       by using End. Alternatively, by using the commands C-a and C-e,
       respectively.

     • Go to the first character of the buffer with the key C-Home and the
       last one with the key C-End. Alternatively, with M-x beginning -of
       -buffer and M-x end-of-buffer.
  ²⁵Press the Ctrl and spacebar keys simultanesouly.
1.3. PROGRAMMING WITH EMACS                                            27

   • Jump to any line we want: Type M-x goto-line and then the line
     number.

   • Search for text after the point: Press C-s and then the text you
     are looking for. This is an incremental search and the point jumps
     immediately to the first string that matches the search. The same
     search can be repeated by pressing C-s repeatedely.

    When we finish editing (or frequently enough so that we don’t loose
our work due to an unfortunate event), we save the changes in the buffer,
either by pressing the save icon on the toolbar, or by pressing the keys
C-s, or by giving the command M-x save-buffer.


1.3.4   Cut and Paste
Use the instructions below for slightly more advanced editing:

   • Undo! Some of the changes described below can be catastrophic.
     Emacs has a great Undo function that keeps in its memory many
     of the changes inflicted by our editing commands. By repeatedely
     pressing C-/, we undo the changes we made. Alternatively, we
     can use C-x u or the menu entry Edit→Undo. Remember that C-g
     interrupts any Emacs process currently running in the buffer.

   • Cut text by using the mouse: Click with Mouse-1 at the point before
     the beginning of the text and then Mouse-3 at the point after the
     end. A second Mouse-3 and the region is ... gone (in fact it is
     written in the “kill ring” and it is available for pasting)!

   • Cut text by using a keyboard shortcut: Set the mark by C-SPC at the
     point before the beginning of the text that you want to cut. Then
     move the cursor after the last character of the text that you want to
     cut and type C-w.

   • Copy text by using the mouse: Drag the mouse Drag-Mouse-1 and
     mark the region that you want to copy. Alternatively, Mouse-1 at
     the point before the beginning of the text and then Mouse-3 at the
     point after the end.

   • Copy text by using a keyboard shortcut: Set the mark at the begin-
     ning of the text with C-SPC and then move the cursor after the last
     character of the text. Then type M-w.
28                                            CHAPTER 1. THE COMPUTER

     • Pasting text with the mouse: We click the middle button²⁶ Mouse-2
       at the point that we want to insert the text from the kill ring (the
       copied text).

     • Pasting text with a keyboard shortcut: We move the point to the
       desired insertion point and type C-y.

     • Pasting text from previous copying: A fast choice is the menu entry
       Edit→Paste from kill manu and then select from the copied texts.
       The keyboard shortcut is to first type C-y and then M-y repeatedly,
       until the text that we want is yanked.

     • Insert the contents of a file: Move the point to the desired place and
       type C-x i and the path of the file. Alternatively, give the command
       M-x insert-file.

     • Insert the contents of a buffer: We can insert the contents of a whole
       buffer at a point by giving the command M-x insert-buffer.

     • Replace text: We can replace text interactively with the command
       M-x query-replace, then type the string we want to replace, and
       then the replacement string. Then, we will be asked whether we
       want the change to be made and we can answer by typing y (yes),
       n (no), q (quit the replacements). A , (comma) makes only one
       replacement and quits (useful if we know that this is the last change
       that we want to make). If we are confident, we can change all
       string in a buffer, no questions asked, by giving the command M-x
       replace-string.

     • Change case: We can change the case in the words of a region with
       the commands M-x upcase-region, M-x capitalize-region and
       M-x downcase-region. Try it.

We note that cutting and pasting can be made between different windows
of the same or different buffers.


1.3.5 Windows
Sometimes it is very convenient to edit one or more different buffers in
two or more windows. The term “windows” in Emacs refers to regions
of the same Emacs desktop window. In fact, a desktop window running
  ²⁶If it is a two button mouse, try clicking the left and right buttons simultaneously.
1.3. PROGRAMMING WITH EMACS                                                       29

an Emacs session is referred to as a frame in the Emacs jargon. Emacs
can split a frame in two or more windows, horizontally or/and vertically.
Study figure 1.5 on page 58 for details. We can also open a new frame
and edit several buffers simultaneously²⁷. We can manipulate windows
and frames as follows:

   • Position the point at the center of the window and clear the screen
     from garbage: C-l (careful: l not 1).
   • Split a window in two, horizontally: C-x 2.
   • Split a window in two, vertically: C-x 3.
   • Delete all other windows (remain only with the current one): C-x
     1.
   • Delete the current windows (the others remain): C-x 0.
   • Move the cursor to the other window: Mouse-1 or C-x o.
   • Change the size of window: Use Drag-Mouse-1 on the line sepa-
     rating two windows (the mode line). Use C-^, C-} for making a
     change of the horizontal/vertical size of a window respectively.
   • Create a new frame: C-x 5 2.
   • Delete a frame: C-x 5 0.
   • Move the cursor to a different frame: With Mouse-1 or with C-x 5
     o.

You can have many windows in a dumb terminal. This is a blessing
when a dekstop environment is not available. Of course, in that case you
cannot have many frames.

1.3.6     Files and Buffers
   • Open a file: C-x C-f or M-x find-file.
   • Save a buffer: C-x C-s or M-x save buffer. With C-x C-c or
     M-x save-buffers-kill-emacs we can also exit Emacs. From the
     menu: File→Save. From the toolbar: click on the save icon.
   ²⁷Be careful not to start a new Emacs session each time that all you need is a new
frame. A new Emacs process takes time to start, binds computer resources and does
not communicate with a different Emacs process.
30                                     CHAPTER 1. THE COMPUTER

     • Save buffer contents to a different file: C-x C-w or M-x write-file.
       From the menu: File→Save As. From the toolbar: click on the
       “save as” icon.

     • Save all buffers: C-x s or M-x save-some-buffers.

     • Connect a buffer to a different file: M-x set-visited-filename.

     • Kill a buffer: C-x k.

     • Change the buffer of the current window: C-x b. Also, use the
       menu Buffers, then choose the name of the buffer.

     • Show the list of all buffers: C-x C-b. From the menu: Buffers
       → List All Buffers. By typing Enter next to the name of the
       buffer, we make it appear in the window. There are several buffer
       administration commands. Learn about them by typing C-h m when
       the cursor is in the Bufer List window.

     • Recover data from an edited buffer: If Emacs crashed, do not de-
       spair. Start a new Emacs and type M-x recover-file and follow
       the instructions. The command M-x recover-session recovers all
       unsaved buffers.

     • Backup files: When you save a buffer, the previous contents of the
       file become a backup file. This is a file whose path is the same as
       the original’s file with a ˜ appended in the end. For example a
       file test.cpp will have as a backup the file test.cpp˜. Emacs has
       version control, and you can configure it to keep as many versions
       of your edits as you want.

     • Directory browsing and directory administration commands: C-x
       d or M-x dired. You can act on the files of a directory (open,
       delete, rename, copy etc) by giving appropriate commands. When
       the cursor is in the dired window, type C-h m to read the relevant
       documentation.


1.3.7 Modes
Each buffer can be in different modes. Each mode may activate different
commands or editing environment. For example each mode can color
keywords relevant to the mode and/or bind keys to different commands.
There exist major modes, and a buffer can be in only one of them. There
1.3. PROGRAMMING WITH EMACS                                             31

are also minor modes, and a buffer can be in one or more of them. Emacs
activates major and minor modes by default for each file. This usually
depends on the filename but there are also other ways to control this. The
user can change both major and minor modes at will, using appropriate
commands.
    Active modes are shown in a parenthesis on the mode line (see figures
1.3 and 1.5.
   • M-x c++-mode: This mode is of special interest in this book since
     we will edit a lot of C++ code. We need it activated in buffers
     that contain a C++ program and its most useful characteristics are
     automatic code alignment by pressing the key TAB, the coloring of
     C++ statements, variables and other structural constructs (classes, if
     statements, for loops, variable declarations, comments etc). Another
     interesting function is the one that comments out a whole region of
     code, as well as the inverse function.

   • M-x c-mode: For files containing programs written in the C lan-
     guage. Related modes are the java-mode, perl-mode, awk-mode,
     python-mode, makefile-mode, octave-mode, gnuplot-mode and
     others.

   • latex-mode: For files containing LATEX text formatting commands.

   • text-mode: For editing simple text files (.txt).

   • fundamental-mode: The basic mode, when one that fits better doesn’t
     exist...
   Some interesting minor modes are:
   • M-x auto-fill-mode: When a line becomes too long, it is wrapped
     automatically. A related command to do that for the whole region
     is M-x fill-region, and for a paragraph M-x fill-paragraph.

   • M-x overwite-mode: Instead of inserting characters at the point,
     overwrite the existing ones. By giving the command several times,
     we toggle between activating and deactivating the mode.

   • M-x read-only mode: When visiting a file with valuable data that
     we don’t want to change by mistake, we can activate this mode so
     that changes will not be allowed by Emacs. When we open a file
     with the command C-x C-r or M-x find-file-read-only this mode
     is activated. We can toggle this mode on and off with the command
32                                         CHAPTER 1. THE COMPUTER

       C-x C-q (M-x toggle-read-only). See the mode line of the buffer
       jack.c in figure 1.5 which contains a string %%. By clicking on the
       %% we can toggle the read-only mode on and off.
     • flyspell-mode: Spell checking as we type.
     • font-lock-mode: Colors the structural elements of the buffer which
       are defined by the major mode (e.g. the commands of a C++ pro-
       gram).
   In a desktop environment, we can choose modes from the menu of
the mode line. By clicking with Mouse-3 on the name of a mode we are
offered options for (de)activating minor modes. With a Mouse-1 we can
(de)activate the read-only mode with a click on :%% or :-- respectively.
See figure 1.5.

1.3.8 Emacs Help
Emacs’ documentation is impressive. For newbies, we recommend to
follow the mini course offered by the Emacs tutorial. You can start the
tutorial by typing C-h t or select Help → Emacs Tutorial from the
menu. Enjoy... The Emacs man page (give the man emacs command in
the command line) will give you a summary of the basic options when
calling Emacs from the command line.
    A quite detailed manual can be found in the Emacs info pages²⁸.
Using info needs some training, but using the Emacs interface is quite
intuitive and similar to using a web browser. Type the command C-h r
(or choose Help→Emacs Tutorial from the menu) and you will open the
front page of the emacs manual in a new window. By using the keys SPC
and Backspace we can read the documentation page by page. When you
find a link (similar to web page hyperlinks), you can click on it in order
to open to read the topic it refers to. Using the navigation icons on the
toolbar, you can go to the previous or to the next pages, go up one level
etc. There are commands that can be given by typing single characters.
For example, type d in order to jump to the main info directory. There
you can find all the available manuals in the info system installed on
your computer. Type g (emacs) and go to the top page of the Emacs
manual. Type g (info) and read the info manual.
    Emacs is structured in an intuitive and user friendly way. You will
learn a lot from the names of the commands: Almost all names of Emacs
  ²⁸If you prefer books in the form of PDF visit the page www.gnu.org/software/emacs
and click on Documentation. You will find a 600 page book that has almost everything!
1.3. PROGRAMMING WITH EMACS                                           33

commands consist of whole words, separated by a hyphen “-”, which
almost form a full sentence. These make them quite long sometimes,
but by using auto completion of their names this does not pose a grave
problem.

  • auto completion: The names of the commands are auto completed
    by typing a TAB one or more times. E.g., type M-x in order to go to
    the minibuffer. Type capi[TAB] and the command autocompletes
    to capitalize-. By typing [TAB] for a second time, a new window
    opens and offers the options for completing to two possible com-
    mands: capitalize-region and capitalize-word. Type an extra
    r[TAB] and the command auto completes to the only possible choice
    capitalize-region. You can see all the commands that start with
    an s by typing M-x s[TAB][TAB]. Sure, there are many... Click on
    the *Completions* buffer and browse the possibilities. A lot will
    become clear just by reading the names of the commands. By typ-
    ing M-x [TAB][TAB], all available commands will appear in your
    buffer!

  • keyboard shortcuts: If you don’t remember what happens when
    you type C-s, no problem: Type C-h k and then the ... forgotten key
    sequence C-s. Conversely, have you forgotten what is the keyboard
    shortcut of the command save-buffer? Type C-h w and then the
    command.

  • functions: Are you looking for a command, e.g. save-something
    -I-forgot? Type C-h f and then save-[TAB] in order to browse
    over different choices. Use Mouse-2 in order to select the command
    you are interested in, or type and complete the rest of its name (you
    may use [TAB] again). Read about the function in the *Help* buffer
    that opens.

  • variables: Do the same after typing C-h v in order to see a vari-
    able’s value and documentation.

  • command apropos: Have you forgotten the exact name of a com-
    mand? No problem... Type C-h a and a keyword. All commands
    related to the keyword you typed will appear in a buffer. Use C-h
    d for even more information.

  • modes: When in a buffer, type C-h m and read information about
    the active modes of the buffer.
34                                          CHAPTER 1. THE COMPUTER

     • info: Type C-h i


     • Have you forgotten everything mentioned above? Just type C-h ?



1.3.9 Emacs Customization
You can customize everything in Emacs. From key bindings to program-
ming your own functions in the Elisp language. The most common way
for a user to customize her Emacs sessions, is to put all her customization
commands in the file ∼/.emacs in her home directory. Emacs reads and
executes all these commands just before starting a session. Such a .emacs
file is given below:

; D e f i n e F1 key t o save t h e b u f f e r
( global-set-key [ f1 ]          ’ save-buffer )
; D e f i n e Control−c s t o save t h e b u f f e r
( global-set-key ”\C−cs ” ’ save-some-buffers )
; D e f i n e Meta−s ( Alt−s ) t o i n t e r a c t i v e l y s e a r c h forward
( global-set-key ”\M−s” ’ isearch-forward )
; D e f i n e M−x i s            t o i n t e r a c t i v e l y s e a r c h forward
( defalias               ’ is    ’ isearch-forward )
; D e f i n e M−x cm             t o s e t c++−mode f o r t h e b u f f e r
( defun cm ( )         ( interactive ) ( c++−mode ) )
; D e f i n e M−x s i g n        t o s i g n my name
( defun sign ( ) ( interactive ) ( insert ”K. N. Anagnostopoulos ” ) )


    Everything after a ; is a comment. Functions/commands are enclosed
in parentheses. The first three ones bind the keys F1, C-c s and M-s to
the commands save-buffer, save-some-buffers and isearch-forward
respectively. The next one defines an alias of a command. This means
that, when we give the command M-x is in the minibuffer, then the
command isearch-forward will be executed. The last two commands
are the definitions of the functions (fm) and (sign), which can be called
interactively from the minibuffer.
    For more complicated examples google “emacs .emacs file” and you
will see other users’ .emacs files. You may also customize Emacs from the
menu commands Options→Customize Emacs. For learning the Elisp lan-
guage, you can read the manual “Emacs Lisp Reference Manual” found
at the address
www.gnu.org/software/emacs/manual/elisp.html
1.4. THE C++ PROGRAMMING LANGUAGE                                                  35

1.4       The C++ Programming Language
In this section, we give a very basic introduction to the C++ programming
language. This is not a systematic exposition and you are expected to
learn what is needed in this book by example. So, please, if you have
not already done it, get in front of a computer and do what you read.
You can find many good tutorials and books introducing C++ in a more
complete way in the bibliography.

1.4.1      The Foundation
The first program that one writes when learning a new programming
language is the “Hello World!” program. This is the program that prints
“Hello World!” on your screen:

# i n c l u d e < iostream >
using namespace std ;

i n t main ( ) {

    / / This i s a comment .
    cout << ” H e l l o World ! \ n” ;

}

Commands, or statements, in C++ are strings of characters separated by
blanks (“words”) and end with a semicolon (;). We can put more than
one command on each line by separating them with a semicolon.
    Everything after two slashes (//) is a comment. Proliferation of com-
ments is necessary for documenting our code. Good documentation of
our code is an integral part of programming. If we plan to have our
code read by others (or by us) at a later time, we have to make sure to
explain in detail what each line is supposed to do. You and your col-
laborators will save a lot of time in the process of debugging, improving
and extending your code.
    The first line of the code shown above is a preprocessor directive. These
lines start with a # and are interpreted by a separate program, the pre-
processor. The #include directive, inserts the contents of a file replacing
the line where the directive is. This acts like an editor! Actually, the code
that will be compiled is not the one shown above, but the result of adding
the contents of a file whose name is iostream²⁹. iostream is an example
    ²⁹The path to the file is determined by the compiler. If you are curious to see the
36                                           CHAPTER 1. THE COMPUTER

of a header file that has many definitions of functions and symbols used
by the program. The particular header has the necessary definitions in
order to perform standard input and standard output operations.
   The execution of a C++ program starts by calling a function whose
name is main(). Therefore, the line int main(){ shows how to actually
define a function in C++. Its name is the word before the parentheses ()
and the keyword int specifies that the function returns a value of integer
type³⁰. Within the parentheses placed after the name of the function, we
put the arguments that we pass to the function. In our case the parentheses
contain nothing, showing how to define a function without arguments.
   The curly brackets { ... } define the scope or the body of the function
and contain the statements to be executed when the function is called.
   The line

  cout << ” H e l l o World ! \ n” ;

is the only line that contains an executable statement that actually does
something. Notice that it ends with a semicolon. This statement performs
an output operation printing a string to the standard output. The sentence
Hello World!\n is a constant string and contains a sequence of printable
characters enclosed in double quotes. The last character \n is a newline
character, that prints a new line to the stdout.
    cout identifies the standard character output device, which gives ac-
cess to the stdout. The characters << indicate that we write to cout the
expression to the right. In order to make cout accessible to our program,
we need both the inclusion of the header file iostream and the statement
using namespace std³¹.
    Statements in C++ end with a semicolon. Splitting them over a num-
ber of lines is only a matter of making the code legible. Therefore, the
following parts of the code have equivalent effect as the one written
above:
file, search for it with the command locate iostream. In order to see the result of
adding the contents of the file (and, actually several other files added by preprocessor
directives in iostream), call the preprocessor with the command cpp hello.cpp
   ³⁰The value returned by main() is useless within our program, but it is used by the
operating system in order to inform us about the successful (or not) termination of the
program. Of course, functions returning values is a very useful feature in general!
   ³¹Omitting using namespace std does not make cout inaccessible. One can use its
“full name” std::cout instead. Remove the statement and try it. cout is part of the
C++ Standard Library. All elements of the library belong to the std namespace and their
names can be prefixed by std:: Using the using namespace std statement, the prefix
may be omitted.
1.4. THE C++ PROGRAMMING LANGUAGE                                                  37


i n t main ( )
{
    cout <<
     ” H e l l o World ! \ n” ;
}



i n t main ( ) { cout <<” H e l l o World ! \ n” ; }

    Finally notice that, for C++, uppercase and lowercase characters are
different. Therefore main(), Main() and MAIN() are names of different
functions.
    In order to execute the commands in a program, it is necessary to com-
pile it. This is a job done by a program called the compiler that translates
the human language programming statements into binary commands
that can be loaded to the computer memory for execution. There are
many C++ compilers available, and you should learn which compilers
are available for use in your computing environment. Typical names for
C++ compilers are g++, c++, icc, .... You should find out which
compiler is best suited for your program and spend time reading its
documentation carefully. It is important to learn how to use a new com-
piler so that you can finely tune it to optimize the performance of your
program.
    We are going to use the open source and freely available compiler
g++, which can be installed on most popular operating systems³². The
compilation command is:

> g++ hello . cpp −o hello

The extension .cpp to the file name hello.cpp is important and instructs
the compiler that the file contains source code in C++. Use your editor
and edit a file with the name hello.cpp with the program shown above
before executing the above command.
   The switch -o defines the name of the executable file, which in our
case is hello. If the compilation is successful, the program runs with the
command:


   ³²g++ is a front end to the GNU collection of compilers gcc. By installing gcc, you
obtain a collection of compilers for several languages, like C, C++, Fortran, Java and
others. See http://gcc.gnu.org/
38                                              CHAPTER 1. THE COMPUTER

> . / hello
Hello world !

The ./ is not a special symbol for running programs. The dot is the
current working directory and ./hello is the full path to the file hello.
   Now, we will try a simple calculation. Given the radius of a circle we
will compute its length and area. The program can be found in the file
area_01.cpp:

# i n c l u d e < iostream >
using namespace std ;

i n t main ( ) {
    double PI = 3.1415926535897932;
    double R = 4 . 0 ;

    cout << ” P e r i m e t e r= ” << 2 . 0 * PI * R << ”\n” ;
    cout << ” Area=              ” << PI * R * R     << ”\n” ;

}

The first two statements in main() declare the values of the variables PI and
R. These variables are of type double, which are floating point numbers³³.
   The following two commands have two effects: Computing the length
2πR and the area πR2 of the circle and printing the results. The ex-
pressions 2.0*PI*R and PI*R*R are evaluated before being printed to the
stdout. Note the explicit decimal points at the constants 2.0 and 4.0.
If we write 2 or 4 instead, then these are going to be constants of the
int type and by using them the wrong way we may obtain surprising
results³⁴. We compile and run the program with the commands:

> g++ area_01 . cpp −o area
> . / area
Perimeter= 25.1327
Area=      50.2655


   ³³Don’t confuse double variables with the real numbers. double variables take values
that are finite approximations of real numbers and take values that are a subset of
the rational numbers. This approximation becomes better by increasing the amount
of memory allocated to store them. In most computing environments, doubles are
allocated 8 bytes of memory, in which case they approximate real numbers with, more
or less, 17 significant digits.
   ³⁴Try adding the command cout << 2/4 << 2.0/4.0; and check the results.
1.4. THE C++ PROGRAMMING LANGUAGE                                            39

    Now we will try a process that repeats itself for many times. We will
calculate the length and area of 10 circles of different radii Ri = 1.28 + i,
i = 1, 2, . . . , 10. We will store the values of the radii in an array R[10] of
the double type. The code can be found in the file area_02.cpp:

# i n c l u d e < iostream >
using namespace std ;

i n t main ( ) {
    double PI = 3.1415926535897932;
    double R [ 1 0 ] ;
    double area , perimeter ;
    int i;

    R [0] = 2.18;
    f o r ( i =1; i <10; i++){
        R [ i ] = R [ i−1] + 1 . 0 ;
    }

    f o r ( i =0;i <10; i++){
        perimeter = 2 . 0 * PI * R [ i ] ;
        area          = PI * R [ i ] * R [ i ] ;
        cout << ( i +1) << ” ) R= ” << R [ i ] << ” p e r i m e t e r= ”
                << perimeter << ’\n ’ ;
        cout << ( i +1) << ” ) R= ” << R [ i ] << ” a r e a          = ”
                << area           << ’\n ’ ;
    }

}

The declaration double R[10] defines an array of length 10. This way,
the elements of the array are referred to by an index that takes values
from 0 to 9. For example, R[0] is the first, R[3] is the fourth and R[9]
is the last element of the array.
    Between the lines

    f o r ( i =1; i <10; i++){
        ...
    }

we can write commands that are repeatedly executed while the int vari-
able i takes values from 1 to 9 with increasing step equal to 1. The way
it works is the following: In the round brackets after the keyword for,
there exist three statements separated by semicolons. The first, i=1, is
the statement executed once before the loop starts. The second, i<10,
40                                        CHAPTER 1. THE COMPUTER

is a statement that is evaluated each time before the loop repeats itself.
If it is true, then the statements in the loop are executed. If it is false,
the control of the program is transferred after the end of the loop. The
last statement, i++, is evaluated each time after the last statement in the
loop has been executed. The operator ++ is the increment operator, and
its effect is equivalent to the statement:

     i = i + 1;

The value of i is increased by one. The command:

      R [ i ] = R [ i−1] + 1 . 0 ;

defines the i-th radius from the value R[i-1]. For the loop to work
correctly, we must define the initial value of R[0], otherwise³⁵ R[0]=0.0.
The second loop uses the defined R-values in order to do the computation
and print of the results.
   Now we will write an interactive version of the program. Instead of
hard coding the values of the radii, we will interact with the user asking
her to give her own values. The program will read the 10 values of the
radii from the standard input (stdin). We will also see how to write
the results directly to a file instead of the standard output (stdout). The
program can be found in the file area_03.cpp:

# i n c l u d e < iostream >
# i n c l u d e < fstream >
using namespace std ;

i n t main ( ) {
    const int        N = 10;
    c o n s t double PI = 3.1415926535897932;
    double R [ N ] ;
    double area , perimeter ;
    int        i;

  f o r ( i =0;i<N ; i++){
      cout << ” Enter r a d i u s o f c i r c l e : ” ;
      cin >> R [ i ] ;
      cout << ” i = ” << ( i +1) << ” R( i )= ” << R [ i ] << ’\n ’ ;
  }

  ofstream myfile ( ”AREA.DAT” ) ;

  ³⁵Arrays in C++ are zero-initialized.
1.4. THE C++ PROGRAMMING LANGUAGE                                               41

    f o r ( i =0;i<N ; i++){
        perimeter = 2 . 0 * PI * R [ i ] ;
        area           = PI * R [ i ] * R [ i ] ;
        myfile << ( i +1) << ” ) R= ”               <<   R[i]
                  << ” p e r i m e t e r= ”         <<   perimeter << ’\n ’ ;
        myfile << ( i +1) << ” ) R= ”               <<   R[i]
                  << ” a r e a           = ”        <<   area      << ’\n ’ ;
    }

    myfile . close ( ) ;

}

In the above program, the size of the array R is defined by a const int. A
const declares a variable to be a parameter whose value does not change
during the execution of the program and, if it is of int type, it can be
used to declare the size of an array.
    The array elements R[i] are read using the command:

       cin     >> R [ i ] ;

cin is the standard input stream, the same way that cout is the standard
output stream³⁶. We read input using the >> operator, which indicates
that input is written to the variable on the right.
   In order to interact with ordinary files, we need to include the header

# i n c l u d e < fstream >

In this header, the C++ class ofstream is defined and it can be used in
order to write to files (output stream). An object in this class, like myfile,
is defined (“instantiated”) by the statement:

    ofstream myfile ( ”AREA.DAT” ) ;

This object’s constructor is called by placing the parentheses ("AREA.DAT"),
and then the output stream myfile is directed to the file AREA.DAT. Then
we can write output to the file the same way we have already done with
cout:

    myfile << ( i +1) << ” ) R= ” << R [ i ]
           << ” p e r i m e t e r= ” << perimeter << ’\n ’ ;

    ³⁶And cerr is the standard error stream.
42                                         CHAPTER 1. THE COMPUTER

When we are done writing to the file, we can close the stream with the
statement:

  myfile . close ( ) ;

Reading from files is done in a similar way by using the class ifstream
instead of ofstream.
    The next step will be to learn how to define and use functions. The
program below shows how to define a function area_of_circle(), which
computes the length and area of a circle of given radius. The following
program can be found in the file area_04.cpp:

# i n c l u d e < iostream >
# i n c l u d e < fstream >
using namespace std ;

c o n s t double PI = 3.1415926535897932;

void area_of_circle ( c o n s t double& R , double& L , double& A ) ;

i n t main ( ) {
    const int        N = 10;
    double R [ N ] ;
    double area , perimeter ;
    int      i;

  f o r ( i =0;i<N ; i++){
      cout << ” Enter r a d i u s o f c i r c l e : ” ;
      cin >> R [ i ] ;
      cout << ” i = ” << ( i +1) << ” R( i )= ” << R [ i ] << ’\n ’ ;
  }

  ofstream myfile ( ”AREA.DAT” ) ;
  f o r ( i =0;i<N ; i++){
      area_of_circle ( R [ i ] , perimeter , area ) ;
      myfile << ( i +1) << ” ) R= ” << R [ i ] << ” p e r i m e t e r= ”
                << perimeter << ’\n ’ ;
      myfile << ( i +1) << ” ) R= ” << R [ i ] << ” a r e a          = ”
                << area          << ’\n ’ ;
  }

  myfile . close ( ) ;

}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void area_of_circle ( c o n s t double& R , double& L , double& A ) {
1.4. THE C++ PROGRAMMING LANGUAGE                                           43

    L = 2 . 0 * PI * R ;
    A =         PI * R * R ;
}

The calculation of the length and the area of the circle is performed by
the function

       area_of_circle ( R [ i ] , perimeter , area ) ;

Calling a function, transfers the control of the program to the statements
within the body of the function. The above function has arguments (R[i],
perimeter, area). The argument R[i] is intended to be only an input
variable whose value is not going to change during the calculation. The
arguments perimeter and area are intended for output. Upon return of
the function to the main program, they store the result of the compu-
tation. The user of a function must learn how to use its arguments in
order to be able to call it in her program. These must be documented
carefully by the programmer of the function.
    In order to use a function, we need to declare it the same way we do
with variables or, as we say, to provide its prototype. The prototype of a
function can be declared without providing the function’s definition. We
may provide just enough details that determine the types of its arguments
and the value returned. In our program this is done on the line:

void area_of_circle ( c o n s t double& R , double& L , double& A ) ;

This is the same syntax used later in the definition of the function, but
replacing the body of the function with a semicolon. The argument list
does not need to include the argument names, only their types. We
could have also used the following line in order to declare the function’s
prototype:

void area_of_circle ( c o n s t double&         , double&   , double& ) ;

We could also have used different names for the arguments, if we wished
so. Including the names is a matter of style that improves legibility of
the code.
    The argument R is intended to be left unchanged during the function
execution. This is why we used the keyword const in its declaration.
The arguments L and R, however, will return a different value to the
calling program. This is why const is not used for them.
    The actual program executed by the function is between the lines:
44                                             CHAPTER 1. THE COMPUTER


void area_of_circle ( c o n s t double& R , double& L , double& A ) {
  L = 2 . 0 * PI * R ;
  A =         PI * R * R ;
}

The type of the value returned by a function is declared by the keyword
before its name. In our case, this is void which declares that the function
does not return a value.
    The arguments (R,L,A) must be declared in the function and need
not have the same names as the ones that we use when we call it. All
arguments are declared to be of type double. The character & indicates
that they are passed to the function by reference. This makes possible to
change their values from within the function.
    If & is omitted, then the arguments will be passed by value and a
statement like L = 2.0*PI*R will not change the value of the variable
passed by the calling program. This happens because, in this case, only
the value of the variable L of the calling program is copied to a local variable
which is used only within the function. This is important to understand
and you are encouraged to run the program with and without the & and
check the difference in the computed results.
    The names of variables in a function are only valid within the scope
of the function, i.e. between the curly brackets that contain the body of
the function. Therefore the variable const int N is valid only within the
scope of main(). You may use any name you like, even if it is already
used outside the scope of the function. The names of arguments need
not be the same as the ones used in the calling program. Only their types
have to match.
    Variables in the global scope are accessible by all functions in the same
file³⁷. An example of such a variable is PI, which is accessible by main(),
as well as by area_of_circle().
    We summarize all of the above in a program trionymo.cpp, which
computes the roots of a second degree polynomial:

/ / =========================================================
/ / Program t o compute r o o t s o f a 2nd order polynomial
/ / Tasks : Input from u s e r , l o g i c a l s t a t e m e n t s ,
//          use o f f u n c t i o n s , e x i t
//

   ³⁷If the code is spread over multiple files, then all files must use the keyword external
in order to make the variable accessible to the functions that they contain. In one of the
files, the variable must be defined without the word external. More on that later...
1.4. THE C++ PROGRAMMING LANGUAGE                                                   45

/ / T e s t s : a , b , c= 1 2 3 D=     −8
//               a , b , c= 1 −8 16 D=    0   x1= 4
//               a , b , c= 1 −1 −2 D=    9 . x1= 2 . x2= −1.
//               a , b , c= 2.3 −2.99 −16.422 x1= 3. 4 x2= −2.1
/ / =========================================================
# i n c l u d e < iostream >
# include <cstdlib >
# i n c l u d e <cmath>
using namespace std ;

double Discriminant ( double a , double b , double c ) ;
void   roots ( double a , double b , double c , double& x1 ,
               double& x2 ) ;

i n t main ( ) {
    double a , b , c , D ;
    double x1 , x2 ;

  cout << ” Enter a , b , c : ” ;
  cin >> a >> b >> c ;
  cout << a << ” ” << b << ” ” << c << ” ” << ’\n ’ ;

  / / T e s t i f we have a w e l l d e f i n e d polynomial o f 2nd degree :
  i f ( a == 0.0 ) {
      cerr << ” Trionymo : a=0\n” ;
      exit ( 1 ) ;
  }

  / / Compute t h e d i s c r i m i n a n t
  D = Discriminant ( a , b , c ) ;
  cout << ” D i s c r i m i n a n t : D= ” << D << ’\n ’ ;

  / / Compute t h e r o o t s i n each c a s e : D>0 , D=0 , D<0 ( no r o o t s )
  if          (D > 0.0) {
      roots ( a , b , c , x1 , x2 ) ;
      cout << ” Roots : x1= ” << x1 << ” x2= ”<< x2 << ’\n ’ ;
  }
  e l s e i f ( D == 0 . 0 ) {
      roots ( a , b , c , x1 , x2 ) ;
      cout << ” Double Root : x1= ” << x1 << ’\n ’ ;
  }
  else {
      cout << ”No r e a l r o o t s \n” ;
      exit ( 1 ) ;
  }

}
/ / =========================================================
/ / This i s t h e f u n c t i o n t h a t computes t h e d i s c r i m i n a n t
46                                                CHAPTER 1. THE COMPUTER

/ / A f u n c t i o n r e t u r n s a v a l u e . This v a l u e i s r e t u r n e d using
/ / the return statement
/ / =========================================================
double Discriminant ( double a , double b , double c ) {
   r e t u r n b * b − 4.0 * a * c ;
}
/ / =========================================================
/ / The f u n c t i o n t h a t computes t h e r o o t s .
/ / a , b , c a r e passed by v a l u e : Their v a l u e s cannot change
//                                               within the function
/ / x1 , x2 a r e passed by r e f e r e n c e : Their v a l u e s DO change
//                                               within the function
/ / =========================================================
void roots ( double a , double b , double c , double& x1 ,
                    double& x2 ) {
   double D ;

    D = Discriminant ( a , b , c ) ;
    i f ( D >= 0 . 0 ) {
        D = sqrt ( D ) ;
    } else {
        cerr << ” r o o t s : Sorry , cannot compute r o o t s , D<0=”
              << D << ’\n ’ ;
    }

    x1 = (−b + D ) / ( 2 . 0 * a ) ;
    x2 = (−b − D ) / ( 2 . 0 * a ) ;
}

The program reads the coefficients of the polynomial ax2 + bx + c. After
a check whether a ̸= 0, it computes the discriminant D = b2 − 4ac by
calling the Discriminant(a,b,c).
    The type of the value returned must be declared at the function’s
prototype

double Discriminant ( double a , double b , double c ) ;

and at the function’s definition

double Discriminant ( double a , double b , double c ) {
  r e t u r n b * b − 4.0 * a * c ;
}

The value returned to the calling program is the value of the expression
given as an argument to the return statement. return has also the effect
of transferring the control of the program back to the calling statement.
1.5. GNUPLOT                                                                     47

1.5     Gnuplot
Plotting data is an indispensable tool for their qualitative, but also quanti-
tative, analysis. Gnuplot is a high quality, open source, plotting program
that can be used for generating publication quality plots, as well as for
heavy duty analysis of a large amount of scientific data. Its great ad-
vantage is the possibility to use it from the command line, as well as
from shell scripts and other programs. Gnuplot is programmable and it
is possible to call external programs in order manipulate data and cre-
ate complicated plots. There are many mathematical functions built in
gnuplot and a fit command for non linear fitting of data. There exist
interactive terminals where the user can transform a plot by using the
mouse and keyboard commands.
    This section is brief and only the features, necessary for the fol-
lowing chapters, are discussed. For more information visit the offi-
cial page of gnuplot http://gnuplot.info. Try the rich demo gallery
at http://gnuplot.info/screenshots/, where you can find the type of
graph that you want to create and obtain an easy to use recipe for it. The
book [16] is an excellent place to look for many of gnuplot’s secrets³⁸.
    You can start a gnuplot session with the gnuplot command:

> gnuplot

  G N U P L O T
  Version X . XX
  ....
  The gnuplot FAQ is available from www . gnuplot . i n f o / faq /
  ....
gnuplot >

There is a welcome message and then a prompt gnuplot> is issued wait-
ing for your command. Type a command an press [Enter]. Type quit
in order to quit the program. In the following, when we show a prompt
gnuplot>, it is assumed that the command after the prompt is executed
from within gnuplot.
    Plotting a function is extremely easy. Use the command plot and x
as the independent variable of the function³⁹. The command

   ³⁸A the time of the writing of this book, there was a very nice site
www.gnuplotting.org which shows how to create many beautiful and complicated
plots.
   ³⁹You can change the symbol of the independent variable. For example, the command
set dummy t sets the independent variable to be t.
48                                                CHAPTER 1. THE COMPUTER


gnuplot > p l o t x

plots the function y = f (x) = x which is a straight line with slope 1. In
order to plot many functions simultaneously, you can write all of them
in one line:

gnuplot > p l o t [ −5:5][ −2:4] x , x * * 2 , s i n ( x ) , b e s j 0 ( x )

The above command plots the functions x, x2 , sin x and J0 (x). Within the
square brackets [:], we set the limits of the x and y axes, respectively. The
bracket [-5:5] sets −5 ≤ x ≤ 5 and the bracket [-2:4] sets −2 ≤ y ≤ 4.
You may leave the job of setting such limits to gnuplot, by omitting some,
or all of them, from the respective positions in the brackets. For example,
typing [1:][:5] changes the lower and upper limits of x and y and leaves
the upper and lower limits unchanged⁴⁰.
   In order to plot data points (xi , yi ), we can read their values from files.
Assume that a file data has the following numbers recorded in it:

# x    y1     y2
0.5   1.0   0.779
1.0   2.0   0.607
1.5   3.0   0.472
2.0   4.0   0.368
2.5   5.0   0.287
3.0   6.0   0.223

The first line is taken by gnuplot as a comment line, since it begins with
a #. In fact, gnuplot ignores everything after a #. In order to plot the
second column as a function of the first, type the command:

gnuplot > p l o t ” data ” using 1 : 2 with points

The name of the file is within double quotes. After the keyword using,
we instruct gnuplot which columns to use as the x and y coordinates,
respectively. The keywords with points instructs gnuplot to add each
pair (xi , yi ) to the plot with points.
   The command
   ⁴⁰By default, the x and y ranges are determined automatically. In order to force them
to be automatic, you can insert a * in the brackets at the corresponding position(s). For
example plot [1:*][*:5] sets the upper and lower limits of x and y to be determined
automatically.
1.5. GNUPLOT                                                                  49


gnuplot > p l o t ” data ” using 1 : 3 with lines

plots the third column as a function of the first, and the keywords with
lines instruct gnuplot to connect each pair (xi , yi ) with a straight line
segment.
   We can combine several plots together in one plot:

gnuplot > p l o t     ” data ” using 1 : 3 with points , exp ( −0.5* x )
gnuplot > r e p l o t ” data ” using 1 : 2
gnuplot > r e p l o t 2* x

The first line plots the 1st and 3rd columns in the file data together with
the function e−x/2 . The second line adds the plot of the 1st and 2nd
columns in the file data and the third line adds the plot of the function
2x.
    There are many powerful ways to use the keyword using. Instead of
column numbers, we can put mathematical expressions enclosed inside
brackets, like using (...):(...). Gnuplot evaluates each expression
within the brackets and plots the result. In these expressions, the values
of each column in the file data are represented as in the awk language. $i
are variables that expand to the number read from columns i=1,2,3,....
Here are some examples:

gnuplot > p l o t ” data ” using 1 : ( $2 * s i n ( $1 ) * $3 ) with points
gnuplot > r e p l o t 2* x * s i n ( x ) * exp(−x / 2 )

The first line plots the 1st column of the file data together with the
value yi sin(xi )zi , where yi , xi and zi are the numbers in the 2nd, 1st and
3rd columns respectively. The second line adds the plot of the function
2x sin(x)e−x/2 .

gnuplot > p l o t ” data ” using ( l o g ( $1 ) ) : ( l o g ( $2 * * 2 ) )
gnuplot > r e p l o t 2* x+ l o g ( 4 )

The first line plots the logarithm of the 1st column together with the
logarithm of the square of the 2nd column.
   We can plot the data written to the standard output of any command.
Assume that there is a program called area that prints the perimeter and
area of a circle to the stdout in the form shown below:

> . / area
50                                                   CHAPTER 1. THE COMPUTER

R=       3.280000              area=         33.79851
R=       6.280000              area=         123.8994
R=       5.280000              area=         87.58257
R=       4.280000              area=         57.54895

The interesting data is at the second and fourth columns. These can be
plotted directly with the gnuplot command:

gnuplot > p l o t ”< . / a r e a ” using 2:4

All we have to do is to type the full command after the < within the
double quotes. We can create complicated filters using pipes as in the
following example:

gnuplot > p l o t \
 ”< . / a r e a | s o r t −g −k 2 | awk ’{ p r i n t l o g ( $2 ) , l o g ( $4 ) } ’ ” \
 using 1 : 2

The filter produces data to the stdout, by combining the action of the
commands area, sort and awk. The data printed by the last program is
in two columns and we plot the results using 1:2.
    In order to save plots in files, we have to change the terminal that gnu-
plot outputs the plots. Gnuplot can produce plots in several languages
(e.g. PDF, postscript, SVG, LATEX, jpeg, png, gif, etc), which can be inter-
preted and rendered by external programs. By redirecting the output to
a file, we can save the plot to the hard disk. For example:

gnuplot >     p l o t ” data ” using 1 : 3
gnuplot >     s e t t e r m i n a l jpeg
gnuplot >     s e t output ” data . j p g ”
gnuplot >     replot
gnuplot >     s e t output
gnuplot >     s e t t e r m i n a l qt

The first line makes the plot as usual. The second one sets the output
to be in the JPEG format and the third one sets the name of the file to
which the plot will be saved. The fourth lines repeats all the previous
plotting commands and the fifth one closes the file data.jpg. The last line
chooses the interactive terminal qt to be the output of the next plot. High
quality images are usually saved in the PDF, encapsulated postcript or
SVG format. Use set terminal pdf,postscript eps or svg, respectively.
   And now a few words for 3-dimensional (3d) plotting. The next
example uses the command splot in order to make a 3d plot of the
1.5. GNUPLOT                                                                              51

function f (x, y) = e−x −y . After you make the plot, you can use the
                                    2   2


mouse in order to rotate it and view it from a different perspective:

gnuplot >       s e t pm3d
gnuplot >       s e t hidden3d
gnuplot >       s e t s i z e ratio 1
gnuplot >       s e t i s o s a m p l e s 50
gnuplot >       s p l o t [ −2:2][ −2:2] exp(−x**2−y * * 2 )

    If you have data in the form (xi , yi , zi ) and you want to create a plot
of zi = f (xi , yi ), write the data in a file, like in the following example:

−1 −1 2.000
−1 0 1.000
−1 1 2.000

 0 −1 1.000
 0 0 0.000
 0 1 1.000

 1 −1 2.000
 1 0 1.000
 1 1 2.000

Note the empty line that follows the change of the value of the first
column. If the name of the file is data3, then you can plot the data with
the commands:

gnuplot >       s e t pm3d
gnuplot >       s e t hidden3d
gnuplot >       s e t s i z e ratio 1
gnuplot >       s p l o t ” data3 ” with lines

    We close this section with a few words on parametric plots. A para-
metric plot on the plane (2-dimensions) is a curve (x(t), y(t)), where t
is a parameter. A parametric plot in space (3-dimensions) is a surface
(x(u, v) , y(u, v), z(u, v)), where (u, v) are parameters. The following com-
mands plot the circle (sin t, cos t) and the sphere (cos u cos v, cos u sin v,
sin u):

gnuplot > s e t p a r a m e t r i c
gnuplot > p l o t s i n ( t ) , c o s ( t )
gnuplot > s p l o t c o s ( u ) * c o s ( v ) , c o s ( u ) * s i n ( v ) , s i n ( u )
52                                          CHAPTER 1. THE COMPUTER

1.6 Shell Scripting
A typical GNU/Linux environment offers very powerful tools for compli-
cated system administration tasks. They are much more simple to use
than to incorporate them into your program. This way, the programmer
can concentrate on the high performance and scientific computing part
of the project and leave the administration and trivial data analysis tasks
to other, external, programs.
    One can avoid repeating the same sequence of commands by coding
them in a file. An example can be found in the file script01.csh:

# ! / bin / t c s h −f
g++ area_01 . cpp        −o area
. / area
g++ area_02 . cpp        −o area
. / area
g++ area_03 . cpp        −o area
. / area
g++ area_04 . cpp        −o area
. / area

This is a very simple shell script. The first line instructs the operating
system that the lines that follow are to be interpreted by the program
/bin/tcsh⁴¹. This can be any program in the system, which in our case
is the tcsh shell. The following lines are valid commands for the shell,
one in each line. They compile the C++ programs found in the files
that we created in section 1.4 with g++, and then they run the executable
./area. In order to execute the commands in the file, we have to make
sure that the file has the appropriate execute permissions. If not, we have
to give the command:

> chmod u+x script01 . csh

Then we simply type the path to the file script01.csh

> . / script01 . csh

and the above commands are run the one after the other. Some of the
versions of the programs that we wrote are asking for input from the
stdin, which, normally, you have to type on the terminal. Instead of

  ⁴¹Use #!/bin/bash if you prefer the bash shell.
1.6. SHELL SCRIPTING                                                           53

interacting directly with the program, we can write the input data to a
file Input, and run the command

. / area < Input

A more convenient solution is to use the, so called, “Here Document”. A
“Here Document” is a section of the script that is treated as if it were a
separate file. As such, it can be used as input to programs by sending its
“contents” to the stdin of the command that runs the program⁴². The
“Here Document” does not appear in the filesystem and we don’t need to
administer it as a regular file. An example of using a “Here Document”
can be found in the file script02.csh:

# ! / bin / t c s h −f
g++ area_04 . cpp −o area
. / area <<EOF
1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0
10.0
EOF

The stdin of the command ./area is redirected to the contents between
the lines

. / area <<EOF
...
EOF

The string EOF marks the beginning and the end of the “Here Document”,
and can be any string you like. The last EOF has to be placed exactly in
the beginning of the line.
   The power of shell scripting lies in its programming capabilities: Vari-
ables, arrays, loops and conditionals can be used in order to create a
complicated program. Shell variables can be used as discussed in section
   ⁴²Their great advantage is that we can use variable and command substitution in
them, therefore sending this information to the program that we want to run.
54                                       CHAPTER 1. THE COMPUTER

1.1.2: The value of a variable name is $name and it can be set with the
command set name = value. An array is defined, for example, by the
command

s e t R = ( 1 . 0 2.0 3.0 4.0 5.0 6.0 7 . 0 8.0 9.0 1 0 . 0 )

and its data can be accessed using the syntax $R[1] ... $R[10].
   Lets take a look at the following script:

# ! / bin / t c s h −f

s e t files = ( area_01 . cpp area_02 . cpp area_03 . cpp area_04 . cpp )
set R       = ( 1 . 0 2.0 3.0 4.0 5.0 6.0 7 . 0 8.0 9.0 1 0 . 0 )

echo ” H e l l o $USER Today i s ” ‘ date ‘
f o r e a c h file ( $files )
  echo ” # −−−−−−−−−−− Working on f i l e $ f i l e ”
  g++ $file −o area
  . / area <<EOF
$R [ 1 ]
$R [ 2 ]
$R [ 3 ]
$R [ 4 ]
$R [ 5 ]
$R [ 6 ]
$R [ 7 ]
$R [ 8 ]
$R [ 9 ]
$R [ 1 0 ]
EOF
  echo ” # −−−−−−−−−−− Done ”
  i f ( −f AREA . DAT ) c a t AREA . DAT
end

The first two lines of the script define the values of the arrays files (4
values) and R (10 values). The command echo echoes its argument to
the stdin. $USER is the name of the user running the script. `date` is an
example of command substitution: When a command is enclosed between
backquotes and is part of a string, then the command is executed and its
stdout is pasted back to the string. In the example shown above, `date`
is replaced by the current date and time in the format produced by the
date command.
    The foreach loop
1.6. SHELL SCRIPTING                                                                                   55

f o r e a c h file ( $files )
   ...
end

is executed once for each of the 4 values of the array files. Each time the
value of the variable file is set equal to one of the values area_01.cpp,
area_02.cpp, area_03.cpp, area_04.cpp. These values can be used by
the commands in the loop. Therefore, the command g++ $file -o area
compiles a different file each time that it is executed by the loop.
    The last line in the loop

  i f ( −f AREA . DAT ) c a t AREA . DAT

is a conditional. It executes the command cat AREA.DAT if the condition
-f AREA.DAT is true. In this case, -f constructs a logical expression which
is true when the file AREA.DAT exists.
    We close this section by presenting a more complicated and advanced
script. It only serves as a demonstration of the shell scripting capabilities.
For more information, the reader is referred to the bibliography [18, 19,
20,21,22]. Read carefully the commands, as well as the comments which
follow the # mark. Then, write the commands to a file script04.csh⁴³,
make it an executable file with the command chmod u+x script04.csh
and give the command

> . / script04 . csh This is my first serious tcsh script

The script will run with the words “This is my first serious tcsh script”
as its arguments. Notice how these arguments are manipulated by the
script. Then, the script asks for the values of the radii of ten or more
circles interactively, so that it will compute their perimeter and area. Type
them on the terminal and then observe the script’s output, so that you
understand the function of each command. You will not regret the time
investment!

# ! / bin / t c s h −f
# Run t h i s s c r i p t as :
# . / s c r i p t 0 4 . csh H e l l o t h i s i s a t c s h s c r i p t
#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# ‘command‘ i s command s u b s t i t u t i o n : i t i s r e p l a c e d by s t d o u t o f command
s e t now = ‘ date ‘ ; s e t mypc = ‘ uname −a ‘
# P r i n t i n f o r m a t i o n : v a r i a b l e s a r e expanded w i t h i n double q u o t e s
echo ” I am u s e r $us er working on t h e computer $HOST” #HOST i s p r e d e f i n e d

   ⁴³You will find it also in the accompanying software
56                                                           CHAPTER 1. THE COMPUTER

echo ”Today t h e d a t e i s                : $now”             #now i s d e f i n e d above
echo ”My home d i r e c t o r y i s          : $home”            #home i s p r e d e f i n e d
echo ”My c u r r e n t d i r e c t o r y i s : $cwd”             #cwd changes with cd
echo ”My computer runs                       : $mypc”            #mypc i s d e f i n e d above
echo ”My p r o c e s s i d i s               : $$    ”           #$$        i s predefined
# Manipulate t h e command l i n e : ( $# argv i s number o f e l e m e n t s i n a r r a y argv )
echo ”The command l i n e has $# argv arguments ”
echo ”The name o f t h e command I am running i s : $0 ”
echo ” Arguments 3rd t o l a s t o f t h e command     : $argv [3 −] ”         # third to l a s t
echo ”The l a s t argument i s                         : $argv [ $# argv ] ” # l a s t element
echo ” A l l arguments                                 : $argv ”

# Ask u s e r f o r i n p u t : e n t e r r a d i i o f c i r c l e s
echo −n ” Enter r a d i i o f c i r c l e s : ” # v a r i a b l e $< s t o r e s one l i n e o f i n p u t
s e t Rs = ( $ <) #Rs i s now an a r r a y with a l l words e n t e r e d by u s e r
i f ( $#Rs < 10 ) then #make a t e s t , need a t l e a s t 10 o f them
  echo ”Need more than 10 r a d i i . E x i t i n g . . . . ”
  exit (1)
endif
echo ”You e n t e r e d $#Rs r a d i i , t h e f i r s t i s $Rs [ 1 ] and t h e l a s t $Rs [ $#Rs ] ”
echo ” Rs= $Rs ”
# Now, compute t h e p e r i m e t e r o f each c i r c l e :
f o r e a c h R ( $Rs )
  # −v rad=$R s e t t h e awk v a r i a b l e rad equal t o $R . p i=atan2 (0 , −1) = 3 . 1 4 . . .
  s e t l = ‘awk −v rad=$R ’BEGIN{ p r i n t 2* atan2 (0 , −1) * rad } ’ ‘
  echo ” C i r c l e with R= $R has p e r i m e t e r $ l ”
end
# a l i a s d e f i n e s a command t o do what you want : use awk as a c a l c u l a t o r
a l i a s acalc ’awk ”BEGIN{ p r i n t \ ! * } ” ’ # \ ! * s u b s t i t u t e s a r g s o f a c a l c
echo ” Using a c a l c t o compute                        2+3=” ‘ acalc 2+3‘
echo ” Using a c a l c t o compute c o s ( 2 * p i )=” ‘ acalc cos ( 2 * atan2 (0 , −1) ) ‘
# Now do t h e same loop over r a d i i as above i n a d i f f e r e n t way
# while ( e x p r e s s i o n ) i s e x e c u t e d as long as ” e x p r e s s i o n ” i s t r u e
while ( $#Rs > 0) # e x e c u t e d as long as $Rs c o n t a i n s r a d i i
  s e t R = $Rs [ 1 ] # t a k e f i r s t element o f $Rs
  s h i f t Rs            #now $Rs has one l e s s element : old $Rs [ 1 ] has vanished
  s e t a = ‘ acalc atan2 (0 , −1) * ${R }* ${R } ‘ # =p i *R*R c a l c u l a t e d by a c a l c
  # c o n s t r u c t a f i l e n a m e t o save t h e r e s u l t from t h e v a l u e o f R :
  s e t file = area$ {R } . dat
  echo ” C i r c l e with R= $R has a r e a $a ” > $file # save r e s u l t i n a f i l e
end                       #end while
# Now look f o r our f i l e s : save t h e i r names i n an a r r a y f i l e s :
s e t files = ( ‘ l s −1 area * . dat ‘ )
i f ( $# f i l e s == 0) echo ” Sorry , no a r e a f i l e s found ”
echo ”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−”
echo ” f i l e s : $ f i l e s ”
l s −l $files
echo ”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−”
echo ”And t h e r e s u l t s f o r t h e a r e a a r e : ”
f o r e a c h f ( $files )
  echo −n ” f i l e ${ f } : ”
  c a t $f
end
# now play a l i t t l e b i t with f i l e names :
echo ”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−”
s e t f = $files [ 1 ] # t e s t p e r m i s s i o n s on f i r s t f i l e
# −f , −r , −w, −x , −d t e s t e x i s t e n c e o f f i l e , rwxd p e r m i s s i o n s
# t h e ! n e g a t e s t h e e x p r e s s i o n ( t r u e −> f a l s e , f a l s e −> t r u e )
echo ” t e s t i n g p e r m i s s i o n s on f i l e s : ”
i f ( −f $f              ) echo ” $ f i l e e x i s t s ”
i f ( −r $f              ) echo ” $ f i l e i s r e a d a b l e by me”
i f ( −w $f              ) echo ” $ f i l e i s w r i t a b l e by be ”
1.6. SHELL SCRIPTING                                                                    57

i f ( ! −w / bin / l s ) echo ” / bin / l s i s NOT w r i t a b l e by me”
i f ( ! −x $f            ) echo ” $ f i l e i s NOT an e x e c u t a b l e ”
i f ( −x / bin / l s ) echo ” / bin / l s i s e x e c u t a b l e by me”
i f ( ! −d $f            ) echo ” $ f i l e i s NOT a d i r e c t o r y ”
i f ( −d / bin           ) echo ” / bin i s a d i r e c t o r y ”
echo ”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−”
# t r a n s f o r m t h e name o f a f i l e
s e t f = $cwd / $f                  # add t h e f u l l path i n $ f
s e t filename = $f : r # removes e x t e n s i o n . dat
s e t extension = $f : e # g e t s                   e x t e n s i o n . dat
s e t fdir             = $f : h # g e t s            directory of $f
s e t base             = ‘ basename $f ‘ # removes d i r e c t o r y name
echo ” f i l e              i s : $f ”
echo ” f i l e n a m e i s : $ f i l e n a m e ”
echo ” e x t e n s i o n i s : $ e x t e n s i o n ”
echo ” d i r e c t o r y i s : $ f d i r ”
echo ” basename i s : $base ”
# now t r a n s f o r m t h e name t o one with d i f f e r e n t e x t e n s i o n :
s e t newfile = ${ filename } . jpg
echo ” j p e g name i s : $ n e w f i l e ”
echo ” j p e g base i s : ” ‘ basename $newfile ‘
i f ( $newfile : e == jpg ) echo ‘ basename $newfile ‘ ” i s a p i c t u r e ”
echo ”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−”
# Now save a l l data i n a f i l e using a ” here document ”
# A here document s t a r t s with <<EOF and ends with a l i n e
# s t a r t i n g e x a c t l y with EOF (EOF can be any s t r i n g as below )
# In a ” here document ” we can use v a r i a b l e s and command
# substitution :
c a t <<AREAS >> areas . dat
# This f i l e c o n t a i n s t h e a r e a s o f c i r c l e o f g ive n r a d i i
# Computation done by ${ u s e r } on ${HOST} . Today i s ‘ date ‘
‘ c a t $files ‘
AREAS
# now s e e what we g o t :
i f ( −f areas . dat ) c a t areas . dat
# You can use a ” here document ” as standard i n p u t t o any command :
# use gnuplot t o save a p l o t : gnuplot does t h e j o b and e x i t s . . .
gnuplot <<GNU
s e t terminal jpeg
s e t output          ” areas . jpg ”
plot ” a r e a s . dat ” using 4 : 7 title ” a r e a s . dat ” ,\
        pi * x * x                           title ” p i *R^2 ”
s e t output
GNU
# check our r e s u l t s : d i s p l a y t h e j p e g f i l e using eog
i f ( −f areas . jpg ) eog areas . jpg &
58                                          CHAPTER 1. THE COMPUTER




Figure 1.5: In this figure, the Emacs window has been split in three windows. The
splitting was done horizontally first (C-x 2), and then vertically (C-x 3). By dragging
the mouse (Drag-Mouse-1) on the horizontal mode lines and vertical lines that separate
the windows, we can change window sizes. Notice the useful information diplayed on
the mode lines. Each window has one point and the cursor is on the active window (in
this case the window of the buffer named ELines.f). A buffer with no active changes
in its contents is marked by a --, an edited buffer is marked by ** and a buffer in read
only mode with (%%). With a mouse click on a %%, we can change them to -- (so that we
can edit) and vice versa. With Mouse-3 on the name of a mode we can activate a choice
of minor modes. With Mouse-1 on the name of a mode we ca have access to commands
relevant to the mode. The numbers (17,31), (16,6) and (10,15) on the mode lines show
the (line,column) of the point location on the respective windows.
1.6. SHELL SCRIPTING                                             59


 awk      search for and process patterns in a file,
 cat      display, or join, files
 cd       change working directory
 chmod    change the access mode of a file
 cp       copy files
 date     display current time and date
 df       display the amount of available disk space
 diff     display the differences between two files
 du       display information on disk usage
 echo     echo a text string to output
 find     find files
 grep     search for a pattern in files
 gzip     compress files in the gzip (.gz) format (gunzip to uncompress)
 head     display the first few lines of a file
 kill     send a signal (like KILL) to a process
 locate   search for files stored on the system (faster than find)
 less     display a file one screen at a time
 ln       create a link to a file
 lpr      print files
 ls       list information about files
 man      search information about command in man pages
 mkdir    create a directory
 mv       move and/or rename a file
 ps       report information on the processes run on the system
 pwd      print the working directory
 rm       remove (delete) files
 rmdir    remove (delete) a directory
 sort     sort and/or merge files
 tail     display the last few lines of a file
 tar      store or retrieve files from an archive file
 top      dynamic real-time view of processes
 wc       counts lines, words and characters in a file
 whatis   list man page entries for a command
 where    show where a command is located in the path (alternatively: whereis)
 which    locate an executable program using ”path”
 zip      create compressed archive in the zip format (.zip)
 unzip    get/list contents of zip archive


                 Table 1.1: Basic Unix commands.
60                                                     CHAPTER 1. THE COMPUTER

                             Table 1.2: Basic Emacs commands.

            Leaving Emacs
            suspend Emacs (or iconify it under X)              C-z
            exit Emacs permanently                             C-x C-c
            Files
            read a file into Emacs                              C-x C-f
             save a file back to disk                           C-x C-s
            save all files                                      C-x s
            insert contents of another file into this buffer     C-x i
            toggle read-only status of buffer                   C-x C-q
            Getting Help
            The help system is simple. Type C-h (or F1) and follow the directions. If you
            are a first-time user, type C-h t for a tutorial.
            remove help window                                 C-x 1
            apropos: show commands matching a string           C-h a
            describe the function a key runs                   C-h k
            describe a function                                C-h f
            get mode-specific information                       C-h m
            Error Recovery
            abort partially typed or executing command         C-g
            recover files lost by a system crash                M-x recover-session
            undo an unwanted change                            C-x u, C-_ or C-/
     restore a buffer to its original contents            M-x revert-buffer
     redraw garbaged screen                              C-l
     Incremental Search
     search forward                                      C-s
     search backward                                     C-r
     regular expression search                           C-M-s
     abort current search                                C-g
     Use C-s or C-r again to repeat the search in either direction. If Emacs is still
     searching, C-g cancels only the part not matched.
     Motion
     entity to move over                                 backward                       forward
     character                                           C-b                            C-f
     word                                                M-b                            M-f
     line                                                C-p                            C-n
     go to line beginning (or end)                       C-a                            C-e
     go to buffer beginning (or end)                      M-<                            M->
     scroll to next screen                               C-v


             Continued...
1.6. SHELL SCRIPTING                                                                   61


                                   Table 1.2: Continued...

    scroll to previous screen                    M-v
    scroll left                                  C-x <
    scroll right                                 C-x >
    scroll current line to center of screen      C-u C-l
    Killing and Deleting
    entity to kill                               backward                   forward
    character (delete, not kill)                 DEL                        C-d
    word                                         M-DEL                      M-d
    line (to end of)                             M-0 C-k                    C-k
    kill region                                  C-w
    copy region to kill ring                     M-w
    yank back last thing killed                  C-y
    replace last yank with previous kill         M-y
    Marking
    set mark here                                C-@ or C-SPC
    exchange point and mark                      C-x C-x
    mark paragraph                               M-h
    mark entire buffer                            C-x h
    Query Replace
    interactively replace a text string          M-% or M-x query-replace
    using regular expressions                    M-x query-replace-regexp
    Buffers
    select another buffer                         C-x b
    list all buffers                              C-x C-b
    kill a buffer                                 C-x k
    Multiple Windows
    When two commands are shown, the second is a similar command for a frame
    instead of a window.
    delete all other windows                    C-x 1                        C-x 5 1
    split window, above and below                C-x 2                      C-x 5 2
    delete this window                           C-x 0                      C-x 5 0
    split window, side by side                   C-x 3
    switch cursor to another window              C-x o                      C-x 5 o
    grow window taller                           C-x ^
    shrink window narrower                       C-x {
    grow window wider                            C-x }


           Continued...
62                                                CHAPTER 1. THE COMPUTER


                                   Table 1.2: Continued...

     Formatting
     indent current line (indent code etc)          TAB
     insert newline after point                     C-o
     fill paragraph                                  M-q
     Case Change
     uppercase word                                 M-u
     lowercase word                                 M-l
     capitalize word                                M-c
     uppercase region                               C-x C-u
     lowercase region                               C-x C-l
     The Minibuffer
     The following keys are defined in the minibuffer.
     complete as much as possible                   TAB
     complete up to one word                        SPC
     complete and execute                           RET
     abort command                                  C-g
     Type C-x ESC ESC to edit and repeat the last command that used the minibuffer.
     Type F10 to activate menu bar items on text terminals.
     Spelling Check
     check spelling of current word                 M-$
     check spelling of all words in region          M-x ispell-region
     check spelling of entire buffer                 M-x ispell-buffer
     On the fly spell checking                       M-x flyspell-mode
     Info – Getting Help Within Emacs
     enter the Info documentation reader            C-h i
     scroll forward                                 SPC
     scroll reverse                                 DEL
     next node                                      n
     previous node                                  p
     move up                                        u
     select menu item by name                       m
     return to last node you saw                    l
     return to directory node                       d
     go to top node of Info file                     t
     go to any node by name                         g
     quit Info                                      q
Chapter 2

Kinematics

In this chapter we show how to program simple kinematic equations of
motion of a particle and how to do basic analysis of numerical results.
We use simple methods for plotting and animating trajectories on the
two dimensional plane and three dimensional space. In section 2.3 we
study numerical errors in the calculation of trajectories of freely moving
particles bouncing off hard walls and obstacles. This will be a prelude to
the study of the integration of the dynamical equations of motion that we
will introduce in the following chapters.


2.1     Motion on the Plane
 When a particle moves on the plane, its position can be given in Cartesian
 coordinates (x(t), y(t)). These, as a function of time, describe the particle’s
 trajectory. The position vector is ⃗r(t) = x(t) x̂ + y(y) ŷ, where x̂ and ŷ are
 the unit vectors on the x and y axes respectively. The velocity vector is
⃗v (t) = vx (t) x̂ + vy (t) ŷ where

                                               d⃗r(t)
                                   ⃗v (t) =
                                                 dt
                                  dx(t)                   dy(t)
                       vx (t) =                vy (t) =         ,               (2.1)
                                   dt                      dt
The acceleration ⃗a(t) = ax (t) x̂ + ay (t) ŷ is given by

                               d⃗v (t)         d2⃗r(t)
                        ⃗a(t) =           =
                                 dt             dt2
                    dvx (t)   d2 x(t)                     dvy (t)   d2 y(t)
           ax (t) =         =                  ay (t) =           =         .   (2.2)
                      dt       dt2                          dt       dt2

                                          63
64                                                  CHAPTER 2. KINEMATICS

              y                           vy                              v

                                               11
                                               00
                                               00
                                               11
                                                            ax             vx




                                          ay
                              r
                                                                  a

              ^y

                   x^                                                 x


Figure 2.1: The trajectory of a particle moving in the plane. The figure shows its
position vector ⃗r, velocity ⃗v and acceleration ⃗a and their Cartesian components in the
chosen coordinate system at a point of the trajectory.




      In this section we study the kinematics of a particle trajectory, there-
fore we assume that the functions (x(t), y(t)) are known. By taking
their derivatives, we can compute the velocity and the acceleration of
the particle in motion. We will write simple programs that compute the
values of these functions in a time interval [t0 , tf ], where t0 is the initial
and tf is the final time. The continuous functions x(t), y(t), vx (t), vy (t)
are approximated by a discrete sequence of their values at the times
t0 , t0 + δt, t0 + 2δt, t0 + 3δt, . . . such that t0 + nδt ≤ tf .
      We will start the design of our program by forming a generic template
to be used in all of the problems of interest. Then we can study each
problem of particle motion by programming only the equations of mo-
tion without worrying about the less important tasks, like input/output,
user interface etc. Figure 2.2 shows a flowchart of the basic steps in the
algorithm. The first part of the program declares variables and defines
the values of the fixed parameters (like π = 3.1459 . . ., g = 9.81, etc). The
program starts by interacting with the user (“user interface”) and asks
for the values of the variables x0 , y0 , t0 , tf , δt . . .. The program prints
these values to the stdout so that the user can check them for correctness
and store them in her data.
      The main calculation is performed in a loop executed while t ≤ tf .
The values of the positions and the velocities x(t), y(t), vx (t), vy (t) are
2.1. MOTION ON THE PLANE                                                         65

                                       Declare variables


                                       Define fixed parameters (PI,...)




                                       User Interface:
                                       Get input from user
                                       x0,y0, t0, tf, dt, ...
                                       Print parameters to stdout


                                       Initialize variables and other
                                       parameters of the motion
                                       Open data file
                                                        t = t0




                          END                           t < tf
                                  NO



                                                                 YES


                                         Calculate
                                         x, y, vx, vy

                                         Print results in data file



                                                t = t + dt




Figure 2.2: The flowchart of a typical program computing the trajectory of a particle
from its (kinematic) equations of motion.



calculated and printed in a file together with the time t. At this point we
fix the format of the program output, something that is very important
to do it in a consistent and convenient way for easing data analysis. We
choose to print the values t, x, y, vx, vy in five columns in each line of
the output file.
    The specific problem that we are going to solve is the computation of
the trajectory of the circular motion of a particle on a circle with center
(x0 , y0 ) and radius R with constant angular velocity ω. The position on
the circle can be defined by the angle θ, as can be seen in figure 2.3. We
define the initial position of the particle at time t0 to be θ(t0 ) = 0.
    The equations giving the position of the particle at time t are

                        x(t) = x0 + R cos (ω(t − t0 ))
                        y(t) = y0 + R sin (ω(t − t0 )) .                      (2.3)

Taking the derivative w.r.t. t we obtain the velocity

                         vx (t) = −ωR sin (ω(t − t0 ))
                         vy (t) = ωR cos (ω(t − t0 )) ,                       (2.4)
66                                                            CHAPTER 2. KINEMATICS

                      y




                                                   (R cos θ , R sin θ )
                                                    θ



                          (x,y)
                                        (x0, y0)


                      ^
                      y
                           x^                                             x


Figure 2.3: The trajectory of a particle moving on a circle with constant angular
velocity calculated by the program Circle.cpp.



and the acceleration

                ax (t) = −ω 2 R cos (ω(t − t0 )) = −ω 2 (x(t) − x0 )
                ay (t) = −ω 2 R sin (ω(t − t0 )) = −ω 2 (y(t) − y0 ) .         (2.5)

 We note that the above equations imply that R   ⃗ · ⃗v = 0 (R
                                                             ⃗ ≡ ⃗r − ⃗r0 , ⃗v ⊥ R,
                                                                                 ⃗
⃗v tangent to the trajectory) and ⃗a = −ω 2 R  ⃗ and ⃗a anti-parallel, ⃗a ⊥ ⃗v ).
                                            ⃗ (R
     The data structure is quite simple. The constant angular velocity ω is
 stored in the double variable omega. The center of the circle (x0 , y0 ), the
 radius R of the circle and the angle θ are stored in the double variables
 x0, y0, R, theta. The times at which we calculate the particle’s position
 and velocity are defined by the parameters t0 , tf , δt and are stored in the
 double variables t0, tf, dt. The current position (x(t), y(t)) is calculated
 and stored in the double variables x, y and the velocity (vx (t), vy (t)) in
 the double variables vx, vy. The declarations of the variables are put in
 the beginning of the program:

  double x0 , y0 , R , x , y , vx , vy , t , t0 , tf , dt ;
  double theta , omega ;

    The user interface of the program is the interaction of the program
with the user and, in our case, it is the part of the program where the
user enters the parameters omega, x0, y0, R, t0, tf, dt. The program
issues a prompt with the names the variables expected to be read. The
variables are read from the stdin by reading from the stream cin and
2.1. MOTION ON THE PLANE                                                                      67

the values entered by the user are printed to the stdout using the stream
cout¹:

  cout << ” # Enter       omega : \ n” ;
  cin  >> omega ;                       getline ( cin , buf ) ;
  cout << ” # Enter       c e n t e r o f c i r c l e ( x0 , y0 ) and r a d i u s R: \ n” ;
  cin  >> x0 >> y0        >> R ;        getline ( cin , buf ) ;
  cout << ” # Enter       t0 , t f , dt : \ n” ;
  cin  >> t0 >> tf        >> dt ; getline ( cin , buf ) ;
  cout <<” # omega=       ” << omega << endl ;
  cout <<” # x0= ”           << x0           << ” y0= ” << y0
       << ” R= ”             << R            << endl ;
  cout <<” # t 0= ”          << t0           << ” t f = ” << tf
       << ” dt= ”            << dt           << endl ;

There are a couple of things to explain. Notice that after reading each
variable from the standard input stream cin, we call the function getline.
By calling getline(cin,buf), a whole line is read from the input stream
cin into the string buf². Then the statement

  cin    >> x0 >> y0 >> R ;           getline ( cin , buf ) ;

has the effect of reading three doubles from the stdin and put the rest of
the line in the string buf. Since we never use buf, this is a mechanism to
discard the rest of the line of input. The reason for doing so will become
clear later.
    Objects of type string in C++ store character sequences. In order to
use them you have to include the header

# include <string >

and, e.g., declare them like

  string buf , buf1 , buf2 ;

Then you can store data in the obvious way, like buf="Hello World!",
manipulate string data using operators like buf=buf1 (assign buf1 to

    ¹This is done so that the used can check for typos and see the actual value read by
the program. By redirecting the stdout of a file on the hard disk, the parameters can
be saved for future reference and used in data analysis.
    ²In fact it is possible to call getline(cin,buf,char) and read a line until the char-
acter char is encountered.
68                                                   CHAPTER 2. KINEMATICS

buf), buf=buf1+buf2 (concatenate buf1 and buf2 and store the result in
buf), buf1==buf2 (compare strings) etc.
    Finally, endl is used to end all the cout statements. This has the effect
of adding a newline to the output stream and flush the output³.
    Next, the program initializes the state of the computation. This in-
cludes checking the validity of the parameters entered by the user, so
that the computation will be possible. For example, the program com-
putes the expression 2.0*PI/omega, where it is assumed that omega has
a non zero value. We will also demand that R > 0 and ω > 0. An
if statement will make those checks and if the parameters have illegal
values, the exit statement⁴ will stop the program execution and print an
informative message to the standard error stream cerr⁵. The program
opens the file Circle.dat for writing the calculated values of the position
and the velocity of the particle.

  i f (R      <=0.0) { cerr <<” I l l e g a l v a l u e o f R    \n” ; exit ( 1 ) ; }
  i f ( omega <=0.0) { cerr <<” I l l e g a l v a l u e o f omega\n” ; exit ( 1 ) ; }
  cout        << ” # T= ” << 2 . 0 * PI / omega                        << endl ;
  ofstream myfile ( ” C i r c l e . dat ” ) ;
  myfile . precision ( 1 7 ) ;

The line myfile.precision(17) sets the precision of the floating point
numbers (like double) printed to myfile to 17 significant digits accuracy.
The default is 6 which is a pity, because doubles have up to 17 significant
digits accuracy.
   If R ≤ 0 or ω ≤ 0 the corresponding exit statements are executed
which end the program execution. The optional error messages are in-
cluded after the stop statements which are printed to the stderr. The
value of the period T = 2π/ω is also calculated and printed for reference.
   The main calculation is performed within the loop


    ³When buffered output is used, it is not written out immediately but stored in a
temporary memory location (a buffer). When the buffer fills, it is automatically flushed
to the output stream. If we want to force flushing before the buffer is full, then we
have to flush the buffer. There are several methods to flush an output stream os (like
os.flush()).
    ⁴The exit(1) statement returns 1 as exit code for the program. This is the int that
main() returns. exit(0) is conventionally used for a normal exit and a non zero value
is used when an error occurs. In order to use exit() you must include the header
cstdlib.
    ⁵Note that there are more assumptions that need to be checked by the program. We
leave this as an exercise for the reader.
2.1. MOTION ON THE PLANE                                             69

  t = t0 ;
  while ( t <= tf ) {
    .........
    t = t + dt ;
  }

The first statement sets the initial value of the time. The statements
between within the scope of the while(condition) are executed as long as
condition has a true value. The statement t=t+dt increments the time
and this is necessary in order not to enter into an infinite loop. Τhe
statements put in place of the dots ......... calculate the position and
the velocity and print them to the file Circle.dat:

# i n c l u d e <cmath>
................
        theta = omega * ( t−t0 ) ;
        x = x0+R * cos ( theta ) ;
        y = y0+R * sin ( theta ) ;
        vx = −omega * R * sin ( theta ) ;
        vy =      omega * R * cos ( theta ) ;
        myfile << t << ” ”
              << x << ” ” << y << ” ”
              << vx << ” ” << vy << endl ;

Notice the use of the functions sin and cos that calculate the sine and
cosine of an angle expressed in radians. The header cmath is necessary
to be included.
   The program is stored in the file Circle.cpp and can be found in
the accompanied software. The extension .cpp is used to inform the
compiler that the file contains source code written in the C++ language.
Compilation and running can be done using the commands:

> g++ Circle . cpp −o cl
> . / cl

The switch -o cl forces the compiler g++ to write the binary commands
executed by the program to the file⁶ cl. The command ./cl loads the
program instructions to the computer memory for execution. When the
programs starts execution, it first asks for the parameter data and then
performs the calculation. A typical session looks like:


   ⁶If omitted, the executable file has the default name a.out.
70                                                     CHAPTER 2. KINEMATICS

> g++ Circle . cpp −o cl
> . / cl
# Enter omega :
1.0
# Enter c e n t e r o f c i r c l e ( x0 , y0 ) and r a d i u s R :
1 . 0 1 . 0 0.5
# Enter t0 , t f , dt :
0.0 20.0 0.01
# omega= 1
# x0= 1 y0= 1 R= 0.5
# t 0= 0 t f = 20 dt= 0.01
# T= 6.28319

The lines shown above that start with a # character are printed by the
program and the lines without # are the values of the parameters entered
interactively by the user. The user types in the parameters and then
presses the Enter key in order for the program to read them. Here we
have used ω = 1.0, x0 = y0 = 1.0, R = 0.5, t0 = 0.0, tf = 20.0 and δt = 0.01.
    You can execute the above program many times for different values of
the parameters by writing the parameter values in a file using an editor.
For example, in the file Circle.in type the following data:

1.0                   omega
1 . 0 1 . 0 0.5       ( x0 , y0 ) , R
0.0 20.0 0.01         t0 tf dt

Each line has the parameters that we want to pass to the program with
each call to cout. The rest of the line consists of comments that explain
to the user what each number is there for. We want to discard these
characters during input and this is the reason for using getline to com-
plete reading the rest of the line. The program can read the above values
of the parameters with the command:

> . / cl < Circle . in > Circle . out

The command ./cl runs the commands found in the executable file ./cl.
The < Circle.in redirects the contents of the file Circle.in to the stan-
dard input (stdin) of the command ./cl. This way the program reads
in the values of the parameters from the contents of the file Circle.in.
The > Circle.out redirects the standard output (stdout) of the com-
mand ./cl to the file Circle.out. Its contents can be inspected after the
execution of the program with the command cat:
2.1. MOTION ON THE PLANE                                                                  71

>   c a t Circle . out
#   Enter omega :
#   Enter c e n t e r o f c i r c l e ( x0 , y0 ) and r a d i u s R :
#   Enter t0 , t f , dt :
#   omega= 1
#   x0= 1 y0= 1 R= 0.5
#   t 0= 0 t f = 20 dt= 0.01
#   T= 6.28319

     We list the full program in Circle.cpp below:

/ / ============================================================
/ / F i l e C i r c l e . cpp
/ / C o n s t a n t angular v e l o c i t y c i r c u l a r motion
/ / S e t ( x0 , y0 ) c e n t e r o f c i r c l e , i t s r a d i u s R and omega .
/ / At t =t0 , t h e p a r t i c l e i s a t t h e t a =0
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

# d e f i n e PI 3.1415926535897932

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of v ar i ab l e s
    double x0 , y0 , R , x , y , vx , vy , t , t0 , tf , dt ;
    double theta , omega ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter omega : \ n” ;
    cin >> omega ;                         getline ( cin , buf ) ;
    cout << ” # Enter c e n t e r o f c i r c l e ( x0 , y0 ) and r a d i u s R: \ n” ;
    cin >> x0 >> y0 >> R ;                 getline ( cin , buf ) ;
    cout << ” # Enter t0 , t f , dt : \ n” ;
    cin >> t0 >> tf >> dt ; getline ( cin , buf ) ;
    cout <<” # omega= ” << omega << endl ;
    cout <<” # x0= ”              << x0         << ” y0= ” << y0
           << ” R= ”              << R          << endl ;
    cout <<” # t 0= ”             << t0         << ” t f = ” << tf
           << ” dt= ”             << dt         << endl ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    i f (R     <=0.0) { cerr <<” I l l e g a l v a l u e o f R     \n” ; exit ( 1 ) ; }
72                                                   CHAPTER 2. KINEMATICS

    i f ( omega <=0.0) { cerr <<” I l l e g a l v a l u e o f omega\n” ; exit ( 1 ) ; }
    cout        << ” # T= ” << 2 . 0 * PI / omega                        << endl ;
    ofstream myfile ( ” C i r c l e . dat ” ) ;
    / / S e t p r e c i s i o n f o r numeric output t o m y f i l e t o 17 d i g i t s
    myfile . precision ( 1 7 ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    t = t0 ;
    while ( t <= tf ) {
        theta = omega * ( t−t0 ) ;
        x = x0+R * cos ( theta ) ;
        y = y0+R * sin ( theta ) ;
        vx = −omega * R * sin ( theta ) ;
        vy =     omega * R * cos ( theta ) ;
        myfile << t << ” ”
            << x << ” ” << y << ” ”
            << vx << ” ” << vy << endl ;
        t = t + dt ;
    }
} / / main ( )



2.1.1 Plotting Data
We use gnuplot for plotting the data produced by our programs. The
file Circle.dat has the time t and the components x, y, vx, vy in five
columns. Therefore we can plot the functions x(t) and y(t) by using the
gnuplot commands:

gnuplot > p l o t     ” C i r c l e . dat ” using 1 : 2 with lines t i t l e ” x ( t ) ”
gnuplot > r e p l o t ” C i r c l e . dat ” using 1 : 3 with lines t i t l e ” y ( t ) ”

The second line puts the second plot together with the first one. The
results can be seen in figure 2.4.
   Let’s see now how we can make the plot of the function θ(t). We can
do that using the raw data from the file Circle.dat within gnuplot, with-
out having to write a new program. Note that θ(t) = tan−1 ((y − y0 )/(x − x0 )).
The function atan2 is available in gnuplot⁷ as well as in C++. Use the
online help system in gnuplot in order to see its usage:

gnuplot > help atan2
 The ‘ atan2 ( y , x ) ‘ f u n c t i o n returns the arc tangent ( inverse
 tangent ) of the ratio of the r e a l parts of its arguments .

     ⁷The command help functions will show you all the available functions in gnuplot.
2.1. MOTION ON THE PLANE                                                                                                       73

       1.5                                                        4
                                                     x(t)                                                      theta(t)
                                                     y(t)                                                            pi
       1.4                                                                                                          -pi
                                                                  3

       1.3
                                                                  2
       1.2

                                                                  1
       1.1


        1                                                         0


       0.9
                                                                  -1

       0.8
                                                                  -2
       0.7

                                                                  -3
       0.6


       0.5                                                        -4
             0   2   4   6   8   10   12   14   16      18   20        0   2   4   6   8   10   12   14   16         18   20




Figure 2.4: The plots (x(t), y(t)) (left) and θ(t) (right) from the data in Circle.dat
for ω = 1.0, x0 = y0 = 1.0, R = 0.5, t0 = 0.0, tf = 20.0 and δt = 0.01.



 ‘ atan2 ‘ returns its argument in radians or degrees , as
 selected by ‘ s e t a n g l e s ‘ , in the correct quadrant .

Therefore, the right way to call the function is atan2(y-y0,x-x0). In
our case x0=y0=1 and x, y are in the 2nd and 3rd columns of the file
Circle.dat. We can construct an expression after the using command as
in page 49, where $2 is the value of the second and $3 the value of the
third column:

gnuplot > x0 = 1 ; y0 = 1
gnuplot > p l o t ” C i r c l e . dat ” using 1 : ( atan2 ( $3−y0 , $2−x0 ) ) \
                                        with lines t i t l e ” t h e t a ( t ) ” , pi ,−pi

The second command is broken in two lines by using the character \
so that it fits conveniently in the text⁸. Note how we defined the val-
ues of the variables x0, y0 and how we used them in the expression
atan2($3-x0,$2-y0). We also plot the lines which graph the constant
functions f1 (t) = π and f2 (t) = −π which mark the limit values of θ(t).
The gnuplot variable⁹ pi is predefined and can be used in formed ex-
pressions. The result can be seen in the left plot of figure 2.4.
   The velocity components (vx (t), vy (t)) as function of time as well as
the trajectory ⃗r(t) can be plotted with the commands:

gnuplot > p l o t            ” C i r c l e . dat ” using 1 : 4 t i t l e ” v_x ( t ) ” \
                                                   with lines

   ⁸This can be done on the gnuplot command line as well.
   ⁹Use the command show variables in order to see the current/default values of
gnuplot variables.
74                                                                      CHAPTER 2. KINEMATICS

gnuplot > r e p l o t ” C i r c l e . dat ” using 1 : 5 t i t l e ” v_y ( t ) ” \
                                            with lines
gnuplot > p l o t     ” C i r c l e . dat ” using 2:3 t i t l e ”x−y ”
                                            with lines


                                         t= 20.000000 (x,y)= (1.208431,1.454485)
                         1.6


                         1.4


                         1.2


                          1


                         0.8


                         0.6


                         0.4


                         0.2


                          0
                               0   0.2    0.4      0.6     0.8      1      1.2     1.4   1.6



Figure 2.5: The particle trajectory plotted by the gnuplot program in the file
animate2D.gnu of the accompanied software. The position vector is shown at a given
time t, which is marked on the title of the plot together with the coordinates (x,y).
The data is produced by the program Circle.cpp described in the text.



    We close this section by showing how to do a simple animation of the
particle trajectory using gnuplot. There is a file animate2D.gnu in the
accompanied software which you can copy in the directory where you
have the data file Circle.dat. We are not going to explain how it works¹⁰
but how to use it in order to make your own animations. The final result
is shown in figure 2.5. All that you need to do is to define the data file¹¹,
the initial time t0, the final time tf and the time step dt. These times
can be different from the ones we used to create the data in Circle.dat.
A full animation session can be launched using the commands:

gnuplot > file = ” C i r c l e . dat ”
gnuplot > s e t xrange [ 0 : 1 . 6 ] ; s e t yrange [ 0 : 1 . 6 ]
gnuplot > t0     = 0 ; tf = 20 ; dt = 0 . 1

   ¹⁰You are most welcome to study the commands in the script and guess how it works
of course!
   ¹¹It can be any file that has (t, x, y) in the 1st, 2nd and 3rd columns respectively.
2.1. MOTION ON THE PLANE                                                 75

gnuplot > load ” animate2D . gnu”

The first line defines the data file that animate2D.gnu reads data from.
The second line sets the range of the plots and the third line defines
the time parameters used in the animation. The final line launches the
animation. If you want to rerun the animation, you can repeat the last
two commands as many times as you want using the same or different
parameters. E.g. if you wish to run the animation at “half the speed”
you should simply redefine dt=0.05 and set the initial time to t0=0:

gnuplot > t0   = 0 ; dt = 0.05
gnuplot > load ” animate2D . gnu”




2.1.2 More Examples
We are now going to apply the steps described in the previous section
to other examples of motion on the plane. The first problem that we are
going to discuss is that of the small oscillations of a simple pendulum.
Figure 2.6 shows the single oscillating degree of freedom θ(t), which
is the small angle that the pendulum forms with the √    vertical direction.
The motion is periodic with angular frequency ω = g/l and period

                                y
                                                     x

                                        l
                                    θ


                                            T
                                        111
                                        000
                                        111
                                        000
                                        111
                                        000
                                        111
                                        000
                                        111
                                        000




                                                mg


Figure 2.6: The simple pendulum whose motion for θ ≪ 1 is described by the
program SimplePendulum.cpp.



T = 2π/ω. The angular velocity is computed from θ̇ ≡ dθ/dt which gives

                       θ(t) = θ0 cos (ω(t − t0 ))
                       θ̇(t) = −ωθ0 sin (ω(t − t0 ))                  (2.6)
76                                           CHAPTER 2. KINEMATICS

We have chosen the initial conditions θ(t0 ) = θ0 and θ̇(t0 ) = 0. In order to
write the equations of motion in the Cartesian coordinate system shown
in figure 2.6 we use the relations

                      x(t) = l sin (θ(t))
                      y(t) = −l cos (θ(t))
                              dx(t)
                     vx (t) =        = lθ̇(t) cos (θ(t))
                                dt
                              dy(t)
                     vy (t) =        = lθ̇(t) sin (θ(t)) .              (2.7)
                                dt
These are similar to the equations (2.3) and (2.4) that we used in the case
of the circular motion of the previous section. Therefore the structure of
the program is quite similar. Its final form, which can be found in the
file SimplePendulum.cpp, is:

/ / ============================================================
/ / F i l e SimplePendulum . cpp
/ / S e t pendulum o r i g i n a l p o s i t i o n a t t h e t a 0
/ / with no i n i t i a l speed
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

# d e f i n e PI 3.1415926535897932
# d e f i n e g 9.81

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of va ri a bl e s
    double l , x , y , vx , vy , t , t0 , tf , dt ;
    double theta , theta0 , dtheta_dt , omega ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter l : \ n” ;
    cin >> l ;                       getline ( cin , buf ) ;
    cout << ” # Enter t h e t a 0 : \ n” ;
    cin >> theta0 ;             getline ( cin , buf ) ;
    cout << ” # Enter t0 , t f , dt : \ n” ;
    cin >> t0 >> tf >> dt ; getline ( cin , buf ) ;
    cout <<” # l = ”         << l << ” t h e t a 0= ” << theta0 << endl ;
2.1. MOTION ON THE PLANE                                                     77

    cout <<” # t 0= ” << t0 << ” t f = ” << tf
          << ” dt= ” << dt << endl ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    omega = sqrt ( g / l ) ;
    cout << ” # omega= ” << omega
          << ” T= ”            << 2 . 0 * PI / omega << endl ;
    ofstream myfile ( ” SimplePendulum . dat ” ) ;
    myfile . precision ( 1 7 ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    t    = t0 ;
    while ( t <= tf ) {
      theta       =              theta0 * cos ( omega * ( t−t0 ) ) ;
      dtheta_dt = −omega * theta0 * sin ( omega * ( t−t0 ) ) ;
      x = l * sin ( theta ) ;
      y = −l * cos ( theta ) ;
      vx = l * dtheta_dt * cos ( theta ) ;
      vy = l * dtheta_dt * sin ( theta ) ;
      myfile << t            << ” ”
          << x       << ” ” << y << ” ”
          << vx      << ” ” << vy << ” ”
          << theta << dtheta_dt
          << endl ;
      t = t + dt ;
    }
} / / main ( )

We note that the acceleration of gravity g is hard coded in the program
and that the user can only set the length l of the pendulum. The data
file SimplePendulum.dat produced by the program, contains two extra
columns with the current values of θ(t) and the angular velocity θ̇(t).
   A simple session for the study of the above problem is shown below¹²:

> g++ SimplePendulum . cpp −o sp
> . / sp
# Enter l :
1.0
# Enter t h e t a 0 :
0.314
# Enter t0 , t f , dt :
0 20 0.01
# l = 1 t h e t a 0= 0.314
# t 0= 0 t f = 20 dt= 0.01

  ¹²Notice that we replaced the command “using 1:2 with lines title” with “u
1:2 w lines t”. These abbreviations can be done with every gnuplot command if an
abbreviation uniquely determines a command.
78                                                      CHAPTER 2. KINEMATICS

# omega= 3.13209 T= 2.00607
> gnuplot
gnuplot > p l o t     ” SimplePendulum . dat ”         u 1:2 w l t ”x ( t ) ”
gnuplot > p l o t     ” SimplePendulum . dat ”         u 1:3 w l t ”y ( t ) ”
gnuplot > p l o t     ” SimplePendulum . dat ”         u 1 : 4 w l t ” v_x ( t ) ”
gnuplot > r e p l o t ” SimplePendulum . dat ”         u 1 : 5 w l t ” v_y ( t ) ”
gnuplot > p l o t     ” SimplePendulum . dat ”         u 1:6 w l t ” theta ( t ) ”
gnuplot > r e p l o t ” SimplePendulum . dat ”         u 1:7 w l t ” theta ’( t ) ”
gnuplot > p l o t     [ −0.6:0.6][ −1.1:0.1]           ” SimplePendulum . dat ” \
                                                       u 2:3 w l t ”x−y ”
gnuplot >    file = ” SimplePendulum . dat ”
gnuplot >    t0 =0; tf =20.0; dt =0.1
gnuplot >    s e t xrange [ − 0 . 6 : 0 . 6 ] ; s e t yrange [ − 1 . 1 : 0 . 1 ]
gnuplot >    load ” animate2D . gnu”

   The next example is the study of the trajectory of a particle shot near
the earth’s surface¹³ when we consider the effect of air resistance to be
negligible. Then, the equations describing the trajectory of the particle
and its velocity are given by the parametric equations

                                   x(t) = v0x t
                                                  1
                                   y(t) = v0y t − gt2
                                                  2
                                  vx (t) = v0x
                                  vy (t) = v0y − gt ,                                  (2.8)

where t is the parameter. The initial conditions are x(0) = y(0) = 0,
vx (0) = v0x = v0 cos θ and vy (0) = v0y = v0 sin θ, as shown in figure 2.7.




Figure 2.7: The trajectory of a particle moving under the influence of a constant
gravitational field. The initial conditions are set to x(0) = y(0) = 0, vx (0) = v0x = v0 cos θ
and vy (0) = v0y = v0 sin θ.


  ¹³I.e. ⃗g = const. and the Coriolis force can be ignored.
2.1. MOTION ON THE PLANE                                                            79

    The structure of the program is similar to the previous ones. The user
enters the magnitude of the particle’s initial velocity and the shooting
angle θ in degrees. The initial time is taken to be t0 = 0. The program
calculates v0x and v0y and prints them to the stdout. The data is written
to the file Projectile.dat. The full program is listed below and it can
be found in the file Projectile.cpp in the accompanied software:

/ / ============================================================
/ / F i l e P r o j e c t i l e . cpp
/ / Shooting a p r o g e c t i l e near t h e e a r t h s u r f a c e .
/ / No a i r r e s i s t a n c e .
/ / S t a r t s a t ( 0 , 0 ) , s e t ( v0 , t h e t a ) .
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

# d e f i n e PI 3.1415926535897932
# d e f i n e g 9.81

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of v ar i ab l e s
    double x0 , y0 , R , x , y , vx , vy , t , tf , dt ;
    double theta , v0x , v0y , v0 ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter v0 , t h e t a ( i n d e g r e e s ) : \ n” ;
    cin >> v0 >> theta ;                    getline ( cin , buf ) ;
    cout << ” # Enter t f , dt : \ n” ;
    cin >> tf >> dt ;                       getline ( cin , buf ) ;
    cout <<” # v0= ”              << v0
             << ” t h e t a = ”<< theta << ” o ( d e g r e e s ) ” << endl ;
    cout <<” # t 0= ”             << 0.0        << ” t f = ”           << tf
             << ” dt= ”           << dt         << endl ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    i f ( v0    <= 0 . 0 )
        { cerr <<” I l l e g a l v a l u e o f v0        <= 0\n” ; exit ( 1 ) ; }
    i f ( theta<= 0 . 0 )
        { cerr <<” I l l e g a l v a l u e o f t h e t a <= 0\n” ; exit ( 1 ) ; }
    i f ( theta >=90.0)
        { cerr <<” I l l e g a l v a l u e o f t h e t a >=90\n” ; exit ( 1 ) ; }
80                                                          CHAPTER 2. KINEMATICS

    theta       = ( PI / 1 8 0 . 0 ) * theta ; / / c o n v e r t t o r a d i a n s
    v0x         = v0 * cos ( theta ) ;
    v0y         = v0 * sin ( theta ) ;
    cout       << ” # v0x= ” << v0x
         << ” v0y= ” << v0y << endl ;
    ofstream myfile ( ” P r o j e c t i l e . dat ” ) ;
    myfile . precision ( 1 7 ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    t = 0.0;
    while ( t <= tf ) {
      x = v0x * t ;
      y = v0y * t − 0 . 5 * g * t * t ;
      vx = v0x ;
      vy = v0y            −            g*t ;
      myfile << t << ” ”
          << x << ” ” << y << ” ”
          << vx << ” ” << vy << endl ;
      t = t + dt ;
    }
} / / main ( )


     A typical session for the study of this problem is shown below:

> g++ Projectile . cpp −o pj
> . / pj
# Enter v0 , t h e t a ( i n d e g r e e s ) :
10 45
# Enter t f , dt :
1.4416 0.001
# v0= 10 t h e t a = 45o ( d e g r e e s )
# t 0= 0 t f = 1.4416 dt= 0.001
# v0x= 7 . 0 7 1 0 7 v0y= 7 . 0 7 1 0 7
> gnuplot
gnuplot > p l o t     ” P r o j e c t i l e . dat ”   using    1:2   w   l   t   ”x ( t ) ”
gnuplot > r e p l o t ” P r o j e c t i l e . dat ”   using    1:3   w   l   t   ”y ( t ) ”
gnuplot > p l o t     ” P r o j e c t i l e . dat ”   using    1:4   w   l   t   ” v_x ( t ) ”
gnuplot > r e p l o t ” P r o j e c t i l e . dat ”   using    1:5   w   l   t   ” v_y ( t ) ”
gnuplot > p l o t     ” P r o j e c t i l e . dat ”   using    2:3   w   l   t   ”x−y ”
gnuplot > file = ” P r o j e c t i l e . dat ”
gnuplot > s e t xrange [ 0 : 1 0 . 3 ] ; s e t        yrange [ 0 : 1 0 . 3 ]
gnuplot > t0 =0; tf = 1 . 4 4 1 6 ; dt =0.05
gnuplot > load ” animate2D . gnu”


  Next, we will study the effect of air resistance of the form F⃗ = −mk⃗v .
The solutions to the equations of motion
2.1. MOTION ON THE PLANE                                                      81




Figure 2.8: The forces that act on the particle of figure 2.7 when we assume air
resistance of the form F⃗ = −mk⃗v .



                                        dvx
                              ax =          = −kvx
                                         dt
                                        dvy
                              ay      =     = −kvy − g                      (2.9)
                                         dt
with initial conditions x(0) = y(0) = 0, vx (0) = v0x = v0 cos θ and vy (0) =
v0y = v0 sin θ are¹⁴

                     vx (t) = v0x e−kt
                              (        g ) −kt g
                     vy (t) = v0y +       e −
                                       k          k
                              v0x (          )
                      x(t) =        1 − e−kt
                               k
                              1(         g)(          ) g
                      y(t) =       v0y +      1 − e−kt − t                 (2.10)
                              k          k              k
    Programming the above equations is as easy as before, the only dif-
ference being that the user needs to provide the value of the constant k.
The full program can be found in the file ProjectileAirResistance.cpp
and it is listed below:

/ / ============================================================
/ / F i l e P r o j e c t i l e A i r R e s i s t a n c e . cpp
/ / Shooting a p r o g e c t i l e near t h e e a r t h s u r f a c e .
/ / No a i r r e s i s t a n c e .
/ / S t a r t s a t ( 0 , 0 ) , s e t k , ( v0 , t h e t a ) .
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >
# i n c l u d e < fstream >

  ¹⁴The proof of equations (2.10) is left as an exercise for the reader.
82                                                 CHAPTER 2. KINEMATICS

# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

# d e f i n e PI 3.1415926535897932
# d e f i n e g 9.81

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of va ri a bl e s
    double x0 , y0 , R , x , y , vx , vy , t , tf , dt , k ;
    double theta , v0x , v0y , v0 ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter k , v0 , t h e t a ( i n d e g r e e s ) : \ n” ;
    cin >> k >> v0 >> theta ; getline ( cin , buf ) ;
    cout << ” # Enter t f , dt : \ n” ;
    cin >> tf >> dt ;                        getline ( cin , buf ) ;
    cout <<” # k = ”              << k          << endl ;
    cout <<” # v0= ”              << v0
             << ” t h e t a = ”<< theta << ” o ( d e g r e e s ) ” << endl ;
    cout <<” # t 0= ”             << 0.0        << ” t f = ”                 << tf
             << ” dt= ”           << dt         << endl ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    i f ( v0    <= 0 . 0 )
        { cerr <<” I l l e g a l v a l u e o f v0        <= 0\n” ; exit ( 1 ) ; }
    i f (k      <= 0 . 0 )
        { cerr <<” I l l e g a l v a l u e o f k         <= 0\n” ; exit ( 1 ) ; }
    i f ( theta<= 0 . 0 )
        { cerr <<” I l l e g a l v a l u e o f t h e t a <= 0\n” ; exit ( 1 ) ; }
    i f ( theta >=90.0)
        { cerr <<” I l l e g a l v a l u e o f t h e t a >=90\n” ; exit ( 1 ) ; }
    theta        = ( PI / 1 8 0 . 0 ) * theta ; / / c o n v e r t t o r a d i a n s
    v0x          = v0 * cos ( theta ) ;
    v0y          = v0 * sin ( theta ) ;
    cout        << ” # v0x= ” << v0x
           << ” v0y= ” << v0y << endl ;
    ofstream myfile ( ” P r o j e c t i l e A i r R e s i s t a n c e . dat ” ) ;
    myfile . precision ( 1 7 ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    t = 0.0;
    while ( t <= tf ) {
        x = ( v0x / k ) *(1.0 − exp(−k * t ) ) ;
        y = ( 1 . 0 / k ) * ( v0y +( g / k ) ) *(1.0 − exp(−k * t ) ) −(g / k ) * t ;
        vx = v0x * exp(−k * t ) ;
2.1. MOTION ON THE PLANE                                                                                                                                83

              vy = ( v0y +( g / k ) ) * exp(−k * t ) −(g / k ) ;
              myfile << t << ” ”
                 << x << ” ” << y << ” ”
                 << vx << ” ” << vy << endl ;
              t = t + dt ;
  }
} / / main ( )


                                                                                     8
                                                                         x(t)                                                                 v_x(t)
                                                                       v0x/k                                                                       0
    1.4                                                                  y(t)                                                                 v_y(t)
                                                                                     7
                                                     -(g/k)*x+(g/k**2)+v0y/k                                                                    -g/k

                                                                                     6
    1.2

                                                                                     5
     1
                                                                                     4


    0.8                                                                              3


                                                                                     2
    0.6
                                                                                     1

    0.4
                                                                                     0


                                                                                     -1
    0.2

                                                                                     -2
     0
          0      0.1   0.2   0.3   0.4   0.5   0.6    0.7       0.8        0.9   1        0   0.1   0.2   0.3   0.4   0.5   0.6   0.7   0.8       0.9   1




Figure 2.9: The plots of x(t),y(t) (left) and vx (t),vy (t) (right) from the data produced
by the program ProjectileAirResistance.cpp for k = 5.0, v0 = 10.0, θ = π/4, tf =
0.91 and δt = 0.001. We also plot the asymptotes of these functions as t → ∞.



   We also list the commands of a typical session of the study of the
problem:

> g++ ProjectileAirResistance . cpp −o pja
# Enter k , v0 , t h e t a ( i n d e g r e e s ) :
5.0 10.0 45
# Enter t f , dt :
0.91 0.001
# k = 5
# v0= 10 t h e t a = 45o ( d e g r e e s )
# t 0= 0 t f = 0.91 dt= 0.001
# v0x= 7 . 0 7 1 0 7 v0y= 7 . 0 7 1 0 7
> gnuplot
gnuplot > v0x = 10* c o s ( pi / 4 ) ; v0y = 10* s i n ( pi / 4 )
gnuplot > g = 9.81 ; k = 5
gnuplot > p l o t [ : ] [ : v0x / k + 0 . 1 ] ” P r o j e c t i l e A i r R e s i s t a n c e . dat ” \
           using 1 : 2 with lines t i t l e ” x ( t ) ” , v0x / k
gnuplot > r e p l o t                            ” P r o j e c t i l e A i r R e s i s t a n c e . dat ” \
           using 1 : 3 with lines t i t l e ” y ( t ) ” ,\
           −(g / k ) * x +( g / k * * 2 ) +v0y / k
gnuplot > p l o t [ : ] [ − g / k − 0 . 6 : ]    ” P r o j e c t i l e A i r R e s i s t a n c e . dat ” \
           using 1 : 4 with lines t i t l e ” v_x ( t ) ” , 0
84                                                            CHAPTER 2. KINEMATICS

                  3
                                                                  With air resistance k=5.0
                                                                   No air resistance k=0.0


                 2.5




                  2




                 1.5




                  1




                 0.5




                  0
                       0        2          4           6          8                10         12



Figure 2.10: Trajectories of the particles shot with v0 = 10.0, θ = π/4 in the absence
of air resistance and when the air resistance is present in the form F⃗ = −mk⃗v with
k = 5.0.



gnuplot > r e p l o t                          ” P r o j e c t i l e A i r R e s i s t a n c e . dat ” \
          using 1 : 5 with lines t i t l e ” v_y ( t ) ” ,−g / k
gnuplot > p l o t                              ” P r o j e c t i l e A i r R e s i s t a n c e . dat ” \
          using 2:3 with lines t i t l e ” With a i r r e s i s t a n c e k=5.0 ”
gnuplot > r e p l o t                          ” P r o j e c t i l e . dat ”                           \
          using 2:3 with lines t i t l e ”No a i r r e s i s t a n c e k=0.0 ”
gnuplot > file = ” P r o j e c t i l e A i r R e s i s t a n c e . dat ”
gnuplot > s e t xrange [ 0 : 1 . 4 ] ; s e t yrange [ 0 : 1 . 4 ]
gnuplot > t0 =0; tf = 0 . 9 1 ; dt =0.01
gnuplot > load ” animate2D . gnu”

Long commands have been continued to the next line as before. We
defined the gnuplot variables v0x, v0y, g and k to have the values that
we used when running the program. We can use them in order to
construct the asymptotes of the plotted functions of time. The results are
shown in figures 2.9 and 2.10.
   The last example of this section will be that of the anisotropic har-
monic oscillator. The force on the particle is

                               Fx = −mω12 x                Fy = −mω22 y                            (2.11)

where the “spring constants” k1 = mω12 and k2 = mω22 are different in the
directions of the axes x and y. The solutions of the dynamical equations
2.1. MOTION ON THE PLANE                                                            85

of motion for x(0) = A, y(0) = 0, vx (0) = 0 and vy (0) = ω2 A are

              x(t) = A cos(ω1 t)      y(t) = A sin(ω2 t)
             vx (t) = −ω1 A sin(ω1 t)     vy (t) = ω2 A cos(ω2 t) .          (2.12)

If the angular frequencies ω1 and ω2 satisfy certain relations, the trajec-
tories of the particle are closed and self intersect at a given number of
points. The proof of these relations, as well as their numerical confirma-
tion, is left as an exercise for the reader. The program listed below is in
the file Lissajoux.cpp:

/ / ============================================================
/ / F i l e L i s s a j o u s . cpp
/ / Lissajous curves ( s p e c i a l case )
/ / x ( t )= c o s ( o1 t ) , y ( t )= s i n ( o2 t )
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

# d e f i n e PI 3.1415926535897932

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of v ar i ab l e s
    double x0 , y0 , R , x , y , vx , vy , t , t0 , tf , dt ;
    double o1 , o2 , T1 , T2 ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter omega1 and omega2 : \ n” ;
    cin >> o1                >> o2 ; getline ( cin , buf ) ;
    cout << ” # Enter t f , dt : \ n” ;
    cin >> tf                >> dt ; getline ( cin , buf ) ;
    cout <<” # o1= ” << o1 << ” o2= ” << o2 << endl ;
    cout <<” # t 0= ” << 0.0 << ” t f = ” << tf
            << ” dt= ” << dt << endl ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    i f ( o1 <=0.0) { cerr <<” I l l e g a l v a l u e o f o1\n” ; exit ( 1 ) ; }
    i f ( o2 <=0.0) { cerr <<” I l l e g a l v a l u e o f o2\n” ; exit ( 1 ) ; }
    T1        = 2 . 0 * PI / o1 ;
    T2        = 2 . 0 * PI / o2 ;
    cout      << ” # T1= ” << T1 << ” T2= ” << T2 << endl ;
86                                                      CHAPTER 2. KINEMATICS

    ofstream myfile ( ” L i s s a j o u s . dat ” ) ;
    myfile . precision ( 1 7 ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    t = t0 ;
    while ( t <= tf ) {
      x = cos ( o1 * t ) ;
      y = sin ( o2 * t ) ;
      vx = −o1 * sin ( o1 * t ) ;
      vy = o2 * cos ( o2 * t ) ;
      myfile << t << ” ”
          << x << ” ” << y << ” ”
          << vx << ” ” << vy << endl ;
      t = t + dt ;
    }
} / / main ( )




   We have set A = 1 in the program above. The user must enter the two
angular frequencies ω1 and ω2 and the corresponding times. A typical
session for the study of the problem is shown below:

> g++ Lissajous . cpp −o lsj
> . / lsj
# Enter omega1 and omega2 :
3 5
# Enter t f , dt :
10.0 0.01
# o1= 3 o2= 5
# t 0= 0 t f = 10 dt= 0.01
# T1= 2.0944 T2= 1.25664
>gnuplot
gnuplot > p l o t     ” L i s s a j o u s . dat ” using 1 : 2   w   l   t   ”x ( t ) ”
gnuplot > r e p l o t ” L i s s a j o u s . dat ” using 1 : 3   w   l   t   ”y ( t ) ”
gnuplot > p l o t     ” L i s s a j o u s . dat ” using 1 : 4   w   l   t   ” v_x ( t ) ”
gnuplot > r e p l o t ” L i s s a j o u s . dat ” using 1 : 5   w   l   t   ” v_y ( t ) ”
gnuplot > p l o t     ” L i s s a j o u s . dat ” using 2:3     w   l   t   ”x−y f o r 3:5 ”
gnuplot > file = ” L i s s a j o u s . dat ”
gnuplot > s e t xrange [ − 1 . 1 : 1 . 1 ] ; s e t yrange       [ −1.1:1.1]
gnuplot > t0 =0; tf =10; dt =0.1
gnuplot > load ” animate2D . gnu”




The results for ω1 = 3 and ω2 = 5 are shown in figure 2.11.
2.2. MOTION IN SPACE                                                             87

                                t= 6.400000 (x,y)= (0.949047,0.509265)

                      1




                    0.5




                      0




                    -0.5




                     -1

                           -1     -0.5            0             0.5      1



 Figure 2.11: The trajectory of the anisotropic oscillator with ω1 = 3 and ω2 = 5.



2.2     Motion in Space
By slightly generalizing the methods described in the previous section,
we will study the motion of a particle in three dimensional space. All
we have to do is to add an extra equation for the coordinate z(t) and the
component of the velocity vz (t). The structure of the programs will be
exactly the same as before.
   The first example is the conical pendulum, which can be seen in figure
2.12. The particle moves on the xy plane with constant angular velocity
ω. The equations of motion are derived from the relations

                Tz = T cos θ = mg               Txy = T sin θ = mω 2 r ,     (2.13)

where r = l sin θ. Their solution¹⁵ is

                                x(t) = r cos ωt
                                y(t) = r sin ωt
                                z(t) = −l cos θ ,                            (2.14)

  ¹⁵One has to choose appropriate initial conditions. Exercise: find them!
88                                                  CHAPTER 2. KINEMATICS


                                                          y
                           x
                                      θ l
                                  z
                                            T

                                       r        θ
                                                               v
                                 ωt   Txy       00
                                                11
                                                00
                                                11
                                                00
                                                11




                                                          mg

     Figure 2.12: The conical pendulum of the program ConicalPendulum.cpp.


where we have to substitute the values
                                    g
                         cos θ =
                                   ω2l
                                   √
                         sin θ =     1 − cos2 θ
                                    g sin θ
                             r =             .                         (2.15)
                                   ω 2 cos θ
For the velocity components we obtain
                               vx = −rω sin ωt
                               vy = rω cos ωt
                               vz = 0 .                                (2.16)
Therefore we must have
                                            √
                                                    g
                               ω ≥ ωmin =             ,                (2.17)
                                                    l
and when ω → ∞, θ → π/2.
     In the program that we will write, the user must enter the parameters
l, ω, the final time tf and the time step δt. We take t0 = 0. The convention
that we follow for the output of the results is that they should be written
in a file where the first 7 columns are the values of t, x, y, z, vx , vy and
vz . The full program is listed below:
2.2. MOTION IN SPACE                                                               89


/ / ============================================================
/ / F i l e ConicalPendulum . cpp
/ / S e t pendulum angular v e l o c i t y omega and d i s p l a y motion i n 3D
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

# d e f i n e PI 3.1415926535897932
# d e f i n e g 9.81

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of v ar i ab l e s
    double l , r , x , y , z , vx , vy , vz , t , tf , dt ;
    double theta , cos_theta , sin_theta , omega ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter l , omega : \ n” ;
    cin >> l >> omega ;                                getline ( cin , buf ) ;
    cout << ” # Enter t f , dt : \ n” ;
    cin >> tf >> dt ;                                  getline ( cin , buf ) ;
    cout << ” # l = ” << l                 << ” omega= ” << omega << endl ;
    cout << ” # T= ” << 2 . 0 * PI / omega
           << ” omega_min= ” << sqrt ( g / l ) << endl ;
    cout <<” # t 0= ” << 0.0 << ” t f = ”                     << tf
           << ” dt= ” << dt << endl ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    cos_theta = g / ( omega * omega * l ) ;
    i f ( cos_theta >= 1 . 0 ) {
        cerr << ” c o s ( t h e t a )>= 1\n” ;
        exit ( 1 ) ;
    }
    sin_theta = sqrt (1.0 − cos_theta * cos_theta ) ;
    z = −g / ( omega * omega ) ; / / they remain c o n s t a n t throught ;
    vz= 0 . 0 ;                        / / t h e motion
    r = g / ( omega * omega ) * sin_theta / cos_theta ;
    ofstream myfile ( ” ConicalPendulum . dat ” ) ;
    myfile . precision ( 1 7 ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    t      = 0.0;
    while ( t <= tf ) {
90                                                  CHAPTER 2. KINEMATICS

     x = r * cos ( omega * t ) ;
     y = r * sin ( omega * t ) ;
     vx = −r * sin ( omega * t ) * omega ;
     vy = r * cos ( omega * t ) * omega ;
     myfile << t         << ” ”
        << x         << ” ” << y << ” ” << z << ” ”
        << vx        << ” ” << vy << ” ” << vz << ” ”
        << endl ;
     t = t + dt ;
  }
} / / main ( )

   In order to compile and run the program we can use the commands
shown below:

> g++ ConicalPendulum . cpp −o cpd
> . / cpd
# Enter l , omega :
1 . 0 6.28
# Enter t f , dt :
10.0 0.01
# l = 1 omega= 6.28
# T= 1.00051 omega_min= 3.13209
# t 0= 0 t f = 10 dt= 0.01

   The results are recorded in the file ConicalPendulum.dat. In order to
plot the functions x(t), y(t), z(t), vx (t), vy (t), vz (t) we give the following
gnuplot commands:

> gnuplot
gnuplot > p l o t       ” ConicalPendulum . dat ”   u   1:2   w   l   t   ”x ( t ) ”
gnuplot > r e p l o t   ” ConicalPendulum . dat ”   u   1:3   w   l   t   ”y ( t ) ”
gnuplot > r e p l o t   ” ConicalPendulum . dat ”   u   1:4   w   l   t   ”z( t )”
gnuplot > p l o t       ” ConicalPendulum . dat ”   u   1:5   w   l   t   ” v_x ( t ) ”
gnuplot > r e p l o t   ” ConicalPendulum . dat ”   u   1:6   w   l   t   ” v_y ( t ) ”
gnuplot > r e p l o t   ” ConicalPendulum . dat ”   u   1:7   w   l   t   ” v_z ( t ) ”

The results are shown in figure 2.13. In order to make a three dimen-
sional plot of the trajectory, we should use the gnuplot command splot:

gnuplot > s p l o t ” ConicalPendulum . dat ” u 2 : 3 : 4 w l t ” r ( t ) ”

The result is shown in figure 2.14. We can click on the trajectory and
rotate it and view it from a different angle. We can change the plot limits
with the command:
2.2. MOTION IN SPACE                                                                                           91

     1                                                      8
                                                x(t)                                                 v_x(t)
                                                y(t)                                                 v_y(t)
    0.8                                         z(t)                                                 v_z(t)
                                                            6

    0.6
                                                            4
    0.4

                                                            2
    0.2


     0                                                      0


   -0.2
                                                            -2

   -0.4
                                                            -4
   -0.6

                                                            -6
   -0.8


     -1                                                     -8
          0   1   2   3   4    5   6   7    8      9   10        0   1   2   3   4   5   6   7   8        9   10




Figure 2.13: The plots of the functions x(t), y(t), z(t), vx (t), vy (t), vz (t) of the program
ConicalPendulum.cpp for ω = 6.28, l = 1.0.




gnuplot > s p l o t [ − 1 . 1 : 1 . 1 ] [ − 1 . 1 : 1 . 1 ] [ − 0 . 3 : 0 . 0 ] \
 ” ConicalPendulum . dat ” using 2 : 3 : 4 w l t ” r ( t ) ”




   We can animate the trajectory of the particle by using the file animate3D.gnu
from the accompanying software. The commands are similar to the ones
we had to give in the two dimensional case for the planar trajectories
when we used the file animate2D.gnu:

gnuplot >         file = ” ConicalPendulum . dat ”
gnuplot >         s e t xrange [ − 1 . 1 : 1 . 1 ] ; s e t yrange [ − 1 . 1 : 1 . 1 ]
gnuplot >         s e t zrange [ − 0 . 3 : 0 ]
gnuplot >         t0 =0; tf =10; dt =0.1
gnuplot >         load ” animate3D . gnu”




The result can be seen in figure 2.15. The program animate3D.gnu can
be used on the data file of any program that prints t x y z as the first
words on each of its lines. All we have to do is to change the value of
the file variable in gnuplot.
    Next, we will study the trajectory of a charged particle in a homoge-
neous magnetic field B      ⃗ = B ẑ. At time t0 , the particle is at ⃗r0 = x0 x̂ and
its velocity is ⃗v0 = v0y ŷ + v0z ẑ, see figure 2.16. The magnetic force on the
particle is F⃗ = q(⃗v × B) ⃗ = qBvy x̂ − qBvx ŷ and the equations of motion
92                                                CHAPTER 2. KINEMATICS




Figure 2.14:         The plot of the particle trajectory ⃗r(t) of the program
ConicalPendulum.cpp for ω = 6.28, l = 1.0. We can click and drag with the mouse on
the window and rotate the curve and see it from a different angle. At the bottom left of
the window, we see the viewing direction, given by the angles θ = 55.0 degrees (angle
with the z axis) and ϕ = 62 degrees (angle with the x axis).



are
                                dvx                      qB
                         ax =       = ωvy           ω≡
                                 dt                      m
                                dvy
                         ay   =     = −ωvx
                                 dt
                         az   = 0.                                             (2.18)

By integrating the above equations with the given initial conditions we
obtain

                                vx (t) = v0y sin ωt
                                vy (t) = v0y cos ωt
                                vz (t) = v0z .                                 (2.19)

Integrating once more, we obtain the position of the particle as a function
of time
                     (      v0y ) v0y
             x(t) = x0 +         −     cos ωt = x0 cos ωt
                             ω     ω
                     v0y                                   v0y
             y(t) =      sin ωt = −x0 sin ωt με x0 = −
                      ω                                     ω
             z(t) = v0z t ,                                          (2.20)
2.2. MOTION IN SPACE                                                                             93

                               t= 10.100000 (x,y,z)= (0.964311,-0.090732,-0.248742)




                         0
                      -0.05
                       -0.1
                     z-0.15

                       -0.2
                      -0.25
                       -0.3




                              -1                                            0.5       1
                                   -0.5    0                           0
                                      x         0.5             -0.5         y
                                                       1   -1




Figure 2.15:       The particle trajectory ⃗r(t) computed by the program
ConicalPendulum.cpp for ω = 6.28, l = 1.0 and plotted by the gnuplot script
animate3D.gnu. The title of the plot shows the current time and the particles coor-
dinates.



where we have chosen x0 = −v0y /ω. This choice places the center of the
circle, which is the projection of the trajectory on the xy plane, to be at
the origin of the coordinate system. The trajectory is a helix with radius
R = −x0 and pitch v0z T = 2πv0z /ω.
    We are now ready to write a program that calculates the trajectory
given by (2.20). The user enters the parameters v0 and θ, shown in
figure 2.16, as well as the angular frequency ω (Larmor frequency). The
components of the initial velocity are v0y = v0 cos θ and v0z = v0 sin θ.
The initial position is calculated from the equation x0 = −v0y /ω. The
program can be found in the file ChargeInB.cpp:

/ / ============================================================
/ / F i l e ChargeInB . cpp
/ / A charged p a r t i c l e o f mass m and charge q e n t e r s a magnetic
/ / f i e l d B i n +z d i r e c t i o n . I t e n t e r s with v e l o c i t y
/ / v0x =0 , v0y=v0 c o s ( t h e t a ) , v0z=v0 s i n ( t h e t a ) , 0<= t h e t a < p i / 2
/ / a t t h e p o s i t i o n x0=−v0y / omega , omega=q B/m
//
/ / Enter v0 and t h e t a and s e e t r a j e c t o r y from
94                                                      CHAPTER 2. KINEMATICS

                                    z

                B
                                                  v0z               v0

                                             x0              θ
                                                                    v0y

                                                                          y


         x

Figure 2.16: A particle at time t0 = 0 is at the position ⃗r0 = x0 x̂ with velocity
                                                     ⃗ = B ẑ.
⃗v0 = v0y ŷ + v0z ẑ in a homogeneous magnetic field B




/ / t 0=0 t o t f a t s t e p dt
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

# d e f i n e PI 3.1415926535897932

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of va ri a bl e s
    double x , y , z , vx , vy , vz , t , tf , dt ;
    double x0 , y0 , z0 , v0x , v0y , v0z , v0 ;
    double theta , omega ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter omega : \ n” ;
    cin >> omega ;                         getline ( cin , buf ) ;
    cout << ” # Enter v0 , t h e t a ( d e g r e e s ) : \ n” ;
    cin >> v0 >> theta ;                   getline ( cin , buf ) ;
    cout << ” # Enter t f , dt : \ n” ;
    cin >> tf >> dt ;                               getline ( cin , buf ) ;
    cout << ” # omega= ” << omega
         << ” T= ”                << 2 . 0 * PI / omega << endl ;
    cout << ” # v0=             ” << v0
         << ” t h e t a = ” << theta
2.2. MOTION IN SPACE                                                           95

            << ” o ( d e g r e e s ) ”<< endl ;
    cout <<” # t 0= ”                 << 0.0 << ” t f = ”          << tf
            << ” dt= ”                << dt << endl ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    i f ( theta <0.0 | | theta >=90.0) exit ( 1 ) ;
    theta = ( PI / 1 8 0 . 0 ) * theta ; / / c o n v e r t t o r a d i a n s
    v0y      = v0 * cos ( theta ) ;
    v0z      = v0 * sin ( theta ) ;
    cout << ” # v0x= ” << 0.0
            << ” v0y= ” << v0y
            << ” v0z= ” << v0z << endl ;
    x0       = − v0y / omega ;
    cout << ” # x0= ” << x0
            << ” y0= ” << y0
            << ” z0= ” << z0                << endl ;
    cout << ” # xy plane : C i r c l e with c e n t e r ( 0 , 0 ) and R= ”
            << abs ( x0 )                   << endl ;
    cout << ” # s t e p o f h e l i x : s=v0z *T= ”
            << v0z * 2 . 0 * PI / omega << endl ;
    ofstream myfile ( ” ChargeInB . dat ” ) ;
    myfile . precision ( 1 7 ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    t       = 0.0;
    vz      = v0z ;
    while ( t <= tf ) {
        x = x0 * cos ( omega * t ) ;
        y = −x0 * sin ( omega * t ) ;
        z = v0z * t ;
        vx = v0y * sin ( omega * t ) ;
        vy = v0y * cos ( omega * t ) ;
        myfile << t                << ” ”
            << x          << ” ” << y << ” ” << z << ” ”
            << vx         << ” ” << vy << ” ” << vz << ” ”
            << endl ;
        t = t + dt ;
    }
} / / main ( )

   A typical session in which we calculate the trajectories shown in figures
2.17 and 2.18 is shown below:

> g++ ChargeInB . cpp −o chg
> . / chg
# Enter omega :
6.28
# Enter v0 , t h e t a ( d e g r e e s ) :
96                                                                     CHAPTER 2. KINEMATICS

     3.5                                                      1
                                                x(t)                                                           v_x(t)
                                                y(t)                                                           v_y(t)
                                                z(t)        0.8                                                v_z(t)
       3

                                                            0.6
     2.5
                                                            0.4

       2
                                                            0.2


     1.5                                                      0


                                                            -0.2
       1

                                                            -0.4
     0.5
                                                            -0.6

       0
                                                            -0.8


     -0.5                                                    -1
            0   1   2   3   4   5   6   7   8      9   10          0   1   2   3     4     5     6    7   8         9   10




Figure 2.17: The plots of the x(t), y(t), z(t), vx (t), vy (t), vz (t) functions calculated by
the program in ChargeInB.cpp for ω = 6.28, x0 = 1.0, θ = 20 degrees.



1 . 0 20
# Enter t f , dt :
10 0.01
# omega= 6.28 T= 1.00051
# v0=        1 t h e t a = 20o ( d e g r e e s )
# t 0= 0 t f = 10 dt= 0.01
# v0x= 0 v0y= 0.939693 v0z= 0.34202
# x0= −0.149633 y0= 0 z0= 3.11248 e −317
# xy plane : C i r c l e with c e n t e r ( 0 , 0 ) and R=                         0.149633
# s t e p o f h e l i x : s=v0z *T= 0.342194
> gnuplot
gnuplot > p l o t        ” ChargeInB . dat ” u 1 : 2      w l                      title       ”x ( t ) ”
gnuplot > r e p l o t ” ChargeInB . dat ” u 1 : 3         w l                      title       ”y ( t ) ”
gnuplot > r e p l o t ” ChargeInB . dat ” u 1 : 4         w l                      title       ”z( t )”
gnuplot > p l o t        ” ChargeInB . dat ” u 1 : 5      w l                      title       ” v_x ( t ) ”
gnuplot > r e p l o t ” ChargeInB . dat ” u 1 : 6         w l                      title       ” v_y ( t ) ”
gnuplot > r e p l o t ” ChargeInB . dat ” u 1 : 7         w l                      title       ” v_z ( t ) ”
gnuplot > s p l o t ” ChargeInB . dat ” u 2 : 3 : 4 w l                            title       ”r( t )”
gnuplot > file = ” ChargeInB . dat ”
gnuplot > s e t xrange [ − 0 . 6 5 : 0 . 6 5 ] ; s e t yrange                      [ −0.65:0.65]
gnuplot > s e t zrange [ 0 : 1 . 3 ]
gnuplot > t0 =0; tf = 3 . 5 ; dt =0.1
gnuplot > load ” animate3D . gnu”




2.3 Trapped in a Box
In this section we will study the motion of a particle that is free, except
when bouncing elastically on a wall or on certain obstacles. This motion
is calculated by approximate algorithms that introduce systematic errors.
2.3. TRAPPED IN A BOX                                                                                          97

                                  t= 3.500000 (x,y,z)= (0.149623,0.001671,1.197069)




                     1.2
                       1
                   z
                     0.8
                     0.6
                     0.4
                     0.2
                       0




                           -0.6                                                                          0.6
                                  -0.4                                                             0.4
                                         -0.2                                                0.2
                                                0                                        0
                                         x          0.2                           -0.2         y
                                                          0.4              -0.4
                                                                0.6 -0.6




Figure 2.18: The trajectory ⃗r(t) calculated by the program in ChargeInB.cpp for
ω = 6.28, v0 = 1.0, θ = 20 degrees as shown by the program animate3D.gnu. The
current time and the coordinates of the particle are printed on the title of the plot.




These types of errors¹⁶ are also encountered in the study of more compli-
cated dynamics, but the simplicity of the problem will allow us to control
them in a systematic and easy to understand way.


2.3.1     The One Dimensional Box
The simplest example of such a motion is that of a particle in a “one
dimensional box”. The particle moves freely on the x axis for 0 < x < L,
as can be seen in figure 2.19. When it reaches the boundaries x = 0 and
x = L it bounces and its velocity instantly reversed. Its potential energy
is
                              {
                                 0     0<x<L
                      V (x) =                      ,                 (2.21)
                                 +∞ elsewhere

   ¹⁶In the previous sections, our calculations had a small systematic error due to the
approximate nature of numerical floating point operations which approximate exact real
number calculations. But the algorithms used were not introducing systematic errors
like in the cases discussed in this section.
98                                              CHAPTER 2. KINEMATICS

which has the shape of an infinitely deep well. The force F = −dV (x)/dx =
0 within the box and F = ±∞ at the position of the walls.


                x    1111
                     0000
                                      v
                     1111
                     0000
                     1111
                     0000
                      1111111111111
                      0000000000000
                     1111
                     0000
                     1111
                     0000



          11111111111111111111111111111111
          00000000000000000000000000000000

                                  L
Figure 2.19: A particle in a one dimensional box with its walls located at x = 0 and
x = L.


    Initially we have to know the position of the particle x0 as well as
its velocity v0 (the sign of v0 depends on the direction of the particle’s
motion) at time t0 . As long as the particle moves within the box, its
motion is free and

                            x(t) = x0 + v0 (t − t0 )
                            v(t) = v0 .                                     (2.22)

For a small enough change in time δt, so that there is no bouncing on
the wall in the time interval (t, t + δt), we have that

                           x(t + δt) = x(t) + v(t)δt
                           v(t + δt) = v(t) .                               (2.23)

Therefore we could use the above relations in our program and when
the particle bounces off a wall we could simple reverse its velocity v(t) →
−v(t). The devil is hiding in the word “when”. Since the time interval
δt is finite in our program, there is no way to know the instant of the
collision with accuracy better than ∼ δt. However, our algorithm will
change the direction of the velocity at time t + δt, when the particle will
have already crossed the wall. This will introduce a systematic error,
which is expected to decrease with decreasing δt. One way to implement
the above idea is by constructing the loop

  while ( t <= tf ) {
   x += v * dt ;
   t +=      dt ;
2.3. TRAPPED IN A BOX                                                  99

      i f ( x < 0.0 | | x > L ) v = −v ;
  }

where the last line gives the testing condition for the wall collision and
the subsequent change of the velocity.
   The full program that realizes the proposed algorithm is listed below
and can be found in the file box1D_1.cpp. The user can set the size of
the box L, the initial conditions x0 and v0 at time t0, the final time tf
and the time step dt:

/ / ============================================================
/ / F i l e box1D_1 . cpp
/ / Motion o f a f r e e p a r t i c l e i n a box 0<x<L
/ / Use i n t e g r a t i o n with time s t e p dt : x = x + v * dt
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >
# i n c l u d e <iomanip >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of v ar i ab l e s
    f l o a t L , x0 , v0 , t0 , tf , dt , t , x , v ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter L: \ n” ;
    cin >> L ;                         getline ( cin , buf ) ;
    cout << ” # L = ” << L << endl ;
    cout << ” # Enter x0 , v0 : \ n” ;
    cin >> x0 >> v0 ;                  getline ( cin , buf ) ;
    cout << ” # x0= ” << x0 << ” v0= ” << v0 << endl ;
    cout << ” # Enter t0 , t f , dt : \ n” ;
    cin >> t0 >> tf >> dt ; getline ( cin , buf ) ;
    cout << ” # t 0= ” << t0 << ” t f = ” << tf
             << ” dt= ” << dt << endl ;
    i f ( L <= 0.0 f ) { cerr << ”L <=0\n” ; exit ( 1 ) ; }
    i f ( x0< 0.0 f ) { cerr << ”x0<=0\n” ; exit ( 1 ) ; }
    i f ( x0> L           ) { cerr << ”x0> L\n” ; exit ( 1 ) ; }
    i f ( v0== 0.0 f ) { cerr << ” v0 =0\n” ; exit ( 1 ) ; }
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    t = t0 ;
100                                                  CHAPTER 2. KINEMATICS

    x = x0 ;
    v = v0 ;
    ofstream myfile ( ” box1D_1 . dat ” ) ;
    myfile . precision ( 9 ) ; / / f l o a t p r e c i s i o n ( and a b i t more . . . )
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    while ( t <= tf ) {
      myfile << setw ( 1 7 ) << t << ” ”                  / / s e t width o f f i e l d
            << setw ( 1 7 ) << x << ” ”          / / t o 17 c h a r a c t e r s
            << setw ( 1 7 ) << v << ’\n ’ ;      / / using setw ( 1 7 )
      x += v * dt ;
      t +=      dt ;
      i f ( x < 0.0 f | | x > L ) v = −v ;
    }
    myfile . close ( ) ;
} / / main ( )

    In this section we will study the effects of roundoff errors in numeri-
cal computations. Computers store numbers in memory, which is finite.
Therefore, real numbers are represented in some approximation that de-
pends on the amount of memory that is used for their storage. This
approximation corresponds to what is termed as floating point numbers.
C++ is supposed to provide at least three basic types of floating point
numbers, float, double and long double. In most implementations¹⁷,
float uses 4 bytes of memory and double 8. In this case, float has
an accuracy to, approximately, 7 significant digits and double 17. See
Chapter 1 of [8] and [14] for details. Moreover, float represent num-
bers with magnitude in the, approximate, range (10−38 , 1038 ) while double
in (10−308 , 10308 ). Note that variables of the integer type (int, long, ...)
are exact representations of integers, whereas floating point numbers are
approximations to reals.
    In the program shown above, we used numbers of the float type
instead of double in order to exaggerate roundoff errors. This way we
can study the dependence of this type of errors on the accuracy of the
floating point numbers used in a program¹⁸. In order to do that, we
declared the floating point variables as float:
   ¹⁷Notice that the C++ standard states that the value representation of floating-point
types is implementation-defined. The C standard requires that the type double provides
at least as much precision as float, and the type long double provides at least as much
precision as double. The gcc 5.4 version that we are using in this book represents
float using 4 bytes and double with 8, but you should check whether this is true with
the compiler that you are using.
   ¹⁸The use of float can be the preferred choice of a programmer for some applications.
First, in order to save memory, because float occupies half the memory of a double.
Second, it is not always true that increasing the accuracy of floating point numbers
2.3. TRAPPED IN A BOX                                                                    101


   f l o a t L , x0 , v0 , t0 , tf , dt , t , x , v ;

We also used numerical constants of type float. This is indicated by the
letter f at the end of their names: 2.0 is a constant of type double (the
C++ default), whereas 2.0f is a constant of type float. Determining the
accuracy of floating point constants is a thorny issue that can be the cause
on introducing subtle bugs in a program and the programmer should be
very careful about doing it carefully.
    Finally we changed the form of the output. Since a float represents a
real number with at most 7 significant digits, there is no point of printing
more. That is why we used the statements

   myfile . precision ( 9 ) ;
   myfile . setw ( 1 7 ) ;

For purposes of studying the numerical accuracy of our results, we used
9 digits of output, which is, of course, slightly redundant. setw(17)
prints the numbers of the next output of the stream myfile using at
least 17 character spaces. This improves the legibility of the results when
inspecting the output files. The use of setw requires the header iomanip.
    The computed data is recorded in the file box1D_1.dat in three columns.
Compiling, running and plotting the trajectory using gnuplot can be done
as follows:

> g++ box1D_1 . cpp −o box1
> . / box1
# Enter L :
10
# L = 10
# Enter x0 , v0 :
0 1.0
# x0= 0 v0= 1
# Enter t0 , t f , dt :
0 100 0.01
# t 0= 0 t f = 100 dt= 0.01
> gnuplot
gnuplot > p l o t ” box1D_1 . dat ” using           1 : 2 w l t i t l e ” x ( t ) ” ,\
                                                     0 notitle , 1 0 notitle
gnuplot > p l o t [ : ] [ − 1 . 2 : 1 . 2 ] ” box1D_1 . dat ” \
                                            using 1 : 3 w l t i t l e ” v ( t ) ”


will increase the accuracy of a computation, although in most of the cases it will. The
wisdom of the field is to always to use as much accuracy as you need and no more!
102                                                              CHAPTER 2. KINEMATICS

   12
                                                    x(t)


   10



   8
                                                                                                         x(t)

                                                                 10.0002


   6                                                             10.0001


                                                                 10.0001

   4
                                                                     10


                                                                     10
   2

                                                                 9.99995

   0
                                                                  9.9999


                                                                 9.99985
   -2
        0   10   20   30   40   50   60   70   80     90   100             90   90.0005   90.001   90.0015




Figure 2.20: The trajectory x(t) of a particle in a box with L = 10, x0 = 0.0, v0 = 1.0,
t0 = 0, δt = 0.01. The plot to the right magnifies a detail when t ≈ 90 which exposes
the systematic errors in determining the exact moment of the collision of the particle
with the wall at tk = 90 and the corresponding maximum value of x(t), xm = L = 10.0.



    The trajectory x(t) is shown in figure 2.20. The effects of the system-
atic errors can be easily seen by noting that the expected collisions occur
every T /2 = L/v = 10 units of time. Therefore, on the plot to the right
of figure 2.20, the reversal of the particle’s motion should have occurred
at t = 90, x = L = 10.
    The reader should have already realized that the above mentioned
error can be made to vanish by taking arbitrarily small δt. Therefore,
we naively expect that as long as we have the necessary computer power
to take δt as small as possible and the corresponding time intervals as
many as possible, we can achieve any precision that we want. Well,
that is true only up to a point. The problem is that the next position is
determined by the addition operation x+v*dt and the next moment in
time by t+dt. Floating point numbers of the float type have a maximum
accuracy of approximately 7 significant decimal digits. Therefore, if the
operands x and v*dt are real numbers differing by more than 7 orders
of magnitude (v*dt≲ 10−7 x), the effect of the addition x+v*dt=x, which
is null! The reason is that the floating point unit of the processor has
to convert both numbers x and v*dt into a representation having the
same exponent and in doing so, the corresponding significant digits of
the smaller number v*dt are lost. The result is less catastrophic when
v*dt≲ 10−a x with 0 < a < 7, but some degree of accuracy is also lost at
each addition operation. And since we have accumulation of such errors
over many intervals t→t+dt, the error can become significant and destroy
our calculation for large enough times. A similar error accumulates in
2.3. TRAPPED IN A BOX                                                           103

the determination of the next instant of time t+dt, but we will discuss
below how to make this contribution to the total error negligible. The
above mentioned errors can become less detrimental by using floating
point numbers of greater accuracy than the float type. For example
double numbers have approximately 17 significant decimal digits. But
again, the precision is finite and the same type of errors are there only
to be revealed by a more demanding and complicated calculation.
    The remedy to such a problem can only be a change in the algorithm.
This is not always possible, but in the case at hand this is easy to do.
For example, consider the equation that gives the position of a particle
in free motion
                          x(t) = x0 + v0 (t − t0 ) .              (2.24)
Let’s use the above relation for the parts of the motion between two
collisions. Then, all we have to do is to reverse the direction of the
motion and reset the initial position and time to be the position and time
of the collision. This can be done by using the loop:

  while ( t <= tf ) {
    x = x0 + v0 * ( t−t0 ) ;
    i f ( x < 0.0 f | | x > L ) {
        x0= x ;
        t0= t ;
        v0= −v0 ;
    }
    t += dt ;
  }

    In the above algorithm, the error in the time of the collision is not
vanishing but we don’t have the “instability” problem of the dt→ 0 limit¹⁹.
Therefore we can isolate and study the effect of each type of error. The
full program that implements the above algorithm is given below and
can be found in the file box1D_2.cpp:

/ / ============================================================
/ / F i l e box1D_2 . cpp
/ / Motion o f a f r e e p a r t i c l e i n a box 0<x<L
/ / Use c o n s t a n t v e l o c i t y e q u a t i o n : x = x0 + v0 * ( t−t 0 )
/ / Rev erse v e l o c i t y and r e d e f i n e x0 , t 0 on boundaries
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >

   ¹⁹We still have this problem in the t=t+dt operation. See discussion in the next
section.
104                                                  CHAPTER 2. KINEMATICS

# i n c l u d e <iomanip >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of va ri a bl e s
    f l o a t L , x0 , v0 , t0 , tf , dt , t , x , v ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter L: \ n” ;
    cin >> L ;                         getline ( cin , buf ) ;
    cout << ” # L = ” << L << endl ;
    cout << ” # Enter x0 , v0 : \ n” ;
    cin >> x0 >> v0 ;                  getline ( cin , buf ) ;
    cout << ” # x0= ” << x0 << ” v0= ” << v0 << endl ;
    cout << ” # Enter t0 , t f , dt : \ n” ;
    cin >> t0 >> tf >> dt ; getline ( cin , buf ) ;
    cout << ” # t 0= ” << t0 << ” t f = ” << tf
               << ” dt= ” << dt << endl ;
    i f ( L <= 0.0 f ) { cerr << ”L <=0\n” ; exit ( 1 ) ; }
    i f ( x0< 0.0 f ) { cerr << ”x0<=0\n” ; exit ( 1 ) ; }
    i f ( x0> L           ) { cerr << ”x0> L\n” ; exit ( 1 ) ; }
    i f ( v0== 0.0 f ) { cerr << ” v0 =0\n” ; exit ( 1 ) ; }
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    t = t0 ;
    ofstream myfile ( ” box1D_2 . dat ” ) ;
    myfile . precision ( 9 ) ; / / f l o a t p r e c i s i o n ( and a b i t more . . . )
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    while ( t <= tf ) {
        x = x0 + v0 * ( t−t0 ) ;
        myfile << setw ( 1 7 ) << t << ” ”
               << setw ( 1 7 ) << x << ” ”
               << setw ( 1 7 ) << v0 << ’\n ’ ;
         i f ( x < 0.0 f | | x > L ) {
             x0= x ;
             t0= t ;
             v0= −v0 ;
        }
        t += dt ;
    }
    myfile . close ( ) ;
} / / main ( )
2.3. TRAPPED IN A BOX                                                    105

   Compiling and running the above program is done as before and the
results are stored in the file box1D_2.dat.

2.3.2    Errors
In this section we will study the effect of the systematic errors that we
encountered in the previous section in more detail. We considered two
types of errors: First, the systematic error of determining the instant
of the collision of the particle with the wall. This error is reduced by
taking a smaller time step δt. Then, the systematic error that accumulates
with each addition of two numbers with increasing difference in their
orders of magnitude. This error is increased with decreasing δt. The
competition of the two effects makes the optimal choice of δt the result of
a careful analysis. Such a situation is found in many interesting problems,
therefore it is quite instructive to study it in more detail.
    When the exact solution of the problem is not known, the systematic
errors are controlled by studying the behavior of the solution as a function
of δt. If the solutions are converging in a region of values of δt, one gains
confidence that the true solution has been determined up to the accuracy
of the convergence.
    In the previous sections, we studied two different algorithms, pro-
grammed in the files box1D_1.cpp and box1D_2.cpp. We will refer to
them as “method 1” and “method 2” respectively. We will study the
convergence of the results as δt → 0 by fixing all the parameters except δt
and then study the dependence of the results on δt. We will take L = 10,
v0 = 1.0, x0 = 0.0, t0 = 0.0, tf = 95.0, so that the particle will collide
with the wall every 10 units of time. We will measure the position of
the particle x(t ≈ 95)²⁰ as a function of δt and study its convergence to a
limit²¹ as δt → 0.
    The analysis requires a lot of repetitive work: Compiling, setting the
parameter values, running the program and calculating the value of x(t ≈
95) for many values of δt. We write the values of the parameters read by
the program in a file box1D_anal.in:

10        L
0 1.0     x0 v0
0 95 0.05 t0 tf dt

Then we compile the program
  ²⁰Note the ≈!
  ²¹Of course we know the answer: x(95) = 5.
106                                              CHAPTER 2. KINEMATICS


> g++ box1D_1 . cpp −o box

and run it with the command:

> c a t box1D_anal . in |    . / box

By using the pipe |, we send the contents of box1D_anal.in to the stdin
of the command ./box by using the command cat. The result x(t ≈ 95)
can be found in the last line of the file box1D_1.dat:

> t a i l −n 1 box1D_1 . dat
  94.9511948 5.45000267 −1.

The third number in the above line is the value of the velocity. In a
file box1D_anal.dat we write δt and the first two numbers coming out
from the command tail. Then we decrease the value δt → δt/2 in
the file box1D_anal.in and run again. We repeat for 12 more times
until δt reaches the value²² 0.000012. We do the same²³ using method 2
and we place the results for x(t ≈ 95) in two new columns in the file
box1D_anal.dat. The result is

# −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# dt      t1_95    x1 (9 5 ) x2 (9 5 )
# −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
0.050000 94.95119 5.450003 5.550126
0.025000 94.97849 5.275011 5.174837
0.012500 94.99519 5.124993 5.099736
0.006250 94.99850 4.987460 5.063134
0.003125 94.99734 5.021894 5.035365
0.001563 94.99923 5.034538 5.017764
0.000781 94.99939 4.919035 5.011735
0.000391 94.99979 4.695203 5.005493
0.000195 95.00000 5.434725 5.001935
0.000098 94.99991 5.528124 5.000745
0.000049 94.99998 3.358000 5.000330
0.000024 94.99998 2.724212 5.000232
0.000012 94.99999 9.240705 5.000158

   Convergence is studied in figure 2.21. The 1st method maximizes its
accuracy for δt ≈ 0.01, whereas for δt < 0.0001 the error becomes > 10%
  ²²Try the command sed 's/0.05/0.025/' box1D_anal.in | ./box by changing
0.025 with the desired value of δt.
  ²³See the shell script box1D_anal.csh as a suggestion on how to automate this boring
process.
2.3. TRAPPED IN A BOX                                                107

and the method becomes useless. The 2nd method has much better
behavior that the 1st one.
    We observe that as δt decreases, the final value of t approaches the
expected tf = 95. Why don’t we obtain t = 95, especially when t/δt is an
integer? How many steps does it really take to reach t ≈ 95, when the
expected number of those is ≈ 95/δt? Each time you take a measurement,
issue the command

> wc −l box1D_1 . dat

which measures the number of lines in the file box1D_1.dat and compare
this number with the expected one. The result is interesting:

# −−−−−−−−−−−−−−−−−−−−−−
#   dt   N       N0
# −−−−−−−−−−−−−−−−−−−−−−
0.050000 1900    1900
0.025000 3800    3800
0.012500 7601    7600
0.006250 15203   15200
0.003125 30394   30400
0.001563 60760   60780
0.000781 121751 121638
0.000391 243753 242966
0.000195 485144 487179
0.000098 962662 969387
0.000049 1972589 1938775
0.000024 4067548 3958333
0.000012 7540956 7916666

where the second column has the number of steps computed by the
program and the third one has the expected number of steps. We
observe that the accuracy decreases with decreasing δt and in the end
the difference is about 5%! Notice that the last line should have given
tf = 0.000012 × 7540956 ≈ 90.5, an error comparable to the period of the
particle’s motion.
    We conclude that one important source of accumulation of system-
atic errors is the calculation of time. This type of errors become more
significant with decreasing δt. We can improve the accuracy of the calcu-
lation significantly if we use the multiplication t=t0+i*dt instead of the
addition t=t+dt, where i is a step counter:

// t = t   + dt ;   / / Not a c c u r a t e ,   avoid
108                                                                  CHAPTER 2. KINEMATICS

   t = t0 + i * dt ;             / / B e t t e r accuracy , p r e f e r

The main loop in the program box1D_1.cpp becomes:

   t = t0 ;
   x = x0 ;
   v = v0 ;
   i = 0;
   while ( t <= ( tf +1.0 e−5f ) ) {
     i +=       1;
     x += v * dt ;
     t = t0 + i * dt ;
     i f ( x < 0.0 f | | x > L ) v = −v ;
   }

    The full program can be found in the file box1D_4.cpp of the accom-
panying software. We call this “method 3”. We perform the same change
in the file box1D_2.cpp, which we store in the file box1D_5.cpp. We call
this “method 4”. We repeat the same analysis using methods 3 and 4
and we find that the problem of calculating time accurately practically
vanishes. The result of the analysis can be found on the right plot of fig-
ure 2.21. Methods 2 and 4 have no significant difference in their results,
whereas methods 1 and 3 do have a dramatic difference, with method 3
decreasing the error more than tenfold. The problem of the increase of
systematic errors with decreasing δt does not vanish completely due to
the operation x=x+v*dt. This type of error is harder to deal with and one
has to invent more elaborate algorithms in order to reduce it significantly.
This will be discussed further in chapter 4.

             100                                                     100

              10                                                      10

               1                                                       1
  δx (%)




                                                          δx (%)




              0.1                                                     0.1

             0.01                                                    0.01

            0.001                                                   0.001
                                         method 1                            method 3
                                         method 2                            method 4
           0.0001                                                  0.0001
                1e-05   0.0001   0.001       0.01   0.1                 1e-05     0.0001   0.001   0.01   0.1
                                   δt                                                        δt


Figure 2.21: The error δx = 2|xi (95) − x(95)|/|xi (95) + x(95)| × 100 where xi (95) is
the value calculated by method i = 1, 2, 3, 4 and x(95) the exact value according to the
text.
2.3. TRAPPED IN A BOX                                                          109

2.3.3    The Two Dimensional Box
A particle is confined to move on the plane in the area 0 < x < Lx and
0 < y < Ly . When it reaches the boundaries of this two dimensional
box, it bounces elastically off its walls. The particle is found in an infinite
depth orthogonal potential well. The particle starts moving at time t0
from (x0 , y0 ) and our program will calculate its trajectory until time tf
with time step δt. Such a trajectory can be seen in figure 2.23.
    If the particle’s position and velocity are known at time t, then at time
t + δt they will be given by the relations

                          x(t + δt)    =   x(t) + vx (t)δt
                          y(t + δt)    =   y(t) + vy (t)δt
                         vx (t + δt)   =   vx (t)
                         vy (t + δt)   =   vy (t) .                         (2.25)

The collision of the particle off the walls is modeled by reflection of the
normal component of the velocity when the respective coordinate of the
particle crosses the wall. This is a source of the systematic errors that we
discussed in the previous section. The central loop of the program is:

    i ++;
    t = t0 + i * dt ;
    x += vx * dt ;
    y += vy * dt ;
    i f ( x < 0.0 | | x > Lx ) {
        vx = −vx ;
        nx ++;
    }
    i f ( y < 0.0 | | y > Ly ) {
        vy = −vy ;
        ny ++;
    }

   The full program can be found in the file box2D_1.cpp. Notice that
we introduced two counters nx and ny of the particle’s collisions with the
walls:

/ / ============================================================
/ / F i l e box2D_1 . cpp
/ / Motion o f a f r e e p a r t i c l e i n a box 0<x<Lx 0<y<Ly
/ / Use i n t e g r a t i o n with time s t e p dt : x = x + vx * dt y=y+vy * dt
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
110                                            CHAPTER 2. KINEMATICS

# i n c l u d e < iostream >
# i n c l u d e <iomanip >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of va ri a bl e s
    double Lx , Ly , x0 , y0 , v0x , v0y , t0 , tf , dt , t , x , y , vx , vy ;
    int         i , nx , ny ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter Lx , Ly : \ n” ;
    cin >> Lx >> Ly ;                                 getline ( cin , buf ) ;
    cout << ” # Lx = ”<< Lx << ” Ly= ” << Ly << endl ;
    cout << ” # Enter x0 , y0 , v0x , v0y : \ n” ;
    cin >> x0 >> y0 >> v0x >> v0y ;                   getline ( cin , buf ) ;
    cout << ” # x0= ” << x0 << ” y0= ” << y0
            << ” v0x= ” << v0x << ” v0y= ” << v0y << endl ;
    cout << ” # Enter t0 , t f , dt : \ n” ;
    cin >> t0 >> tf >> dt ;                           getline ( cin , buf ) ;
    cout << ” # t 0= ” << t0 << ” t f = ” << tf
            << ” dt= ” << dt << endl ;
    i f ( Lx<= 0 . 0 ) { cerr << ”Lx<=0 \n” ; exit ( 1 ) ; }
    i f ( Ly<= 0 . 0 ) { cerr << ”Ly<=0 \n” ; exit ( 1 ) ; }
    i f ( x0< 0 . 0 ) { cerr << ”x0<=0 \n” ; exit ( 1 ) ; }
    i f ( x0> Lx ) { cerr << ”x0> Lx\n” ; exit ( 1 ) ; }
    i f ( y0< 0 . 0 ) { cerr << ”x0<=0 \n” ; exit ( 1 ) ; }
    i f ( y0> Ly ) { cerr << ”y0> Ly\n” ; exit ( 1 ) ; }
    i f ( v0x * v0x+v0y * v0y == 0.0 ) { cerr << ” v0 =0\n” ; exit ( 1 ) ; }
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    i = 0 ;
    nx = 0 ; ny = 0 ;
    t = t0 ;
    x = x0 ; y = y0 ;
    vx = v0x ; vy = v0y ;
    ofstream myfile ( ” box2D_1 . dat ” ) ;
    myfile . precision ( 1 7 ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    while ( t <= tf ) {
        myfile << setw (2 8) << t << ” ”
            << setw (2 8) << x << ” ”
            << setw (2 8) << y << ” ”
2.3. TRAPPED IN A BOX                                                                111

           << setw (28 ) <<   vx << ” ”
           << setw (28 ) <<   vy << ’\n ’ ;
     i +=        1;
     t = t0 + i * dt ;
     x += vx * dt ;
     y += vy * dt ;
     i f ( x < 0.0 | | x >    Lx ) {
         vx = −vx ;
         nx ++;
     }
     i f ( y < 0.0 | | y >    Ly ) {
         vy = −vy ;
         ny ++;
     }
  }
  myfile . close ( ) ;
  cout << ” # Number o f c o l l i s i o n s : \ n” ;
  cout << ” # nx= ” << nx << ” ny= ” << ny << endl ;
} / / main ( )

   A typical session for the study of a particle’s trajectory could be:

> g++ box2D_1 . cpp −o box
> . / box
# Enter Lx , Ly :
10.0 5.0
# Lx = 10 Ly= 5
# Enter x0 , y0 , v0x , v0y :
5.0 0.0 1 . 2 7 1.33
# x0= 5 y0= 0 v0x= 1 . 2 7 v0y= 1.33
# Enter t0 , t f , dt :
0 50 0.01
# t 0= 0 t f = 50 dt= 0.01
# Number o f c o l l i s i o n s :
# nx= 6 ny= 13
> gnuplot
gnuplot > p l o t     ” box2D_1 . dat ” using   1:2   w   l   title   ”x ( t ) ”
gnuplot > r e p l o t ” box2D_1 . dat ” using   1:3   w   l   title   ”y ( t ) ”
gnuplot > p l o t     ” box2D_1 . dat ” using   1:4   w   l   title   ” vx ( t ) ”
gnuplot > r e p l o t ” box2D_1 . dat ” using   1:5   w   l   title   ” vy ( t ) ”
gnuplot > p l o t     ” box2D_1 . dat ” using   2:3   w   l   title   ”x−y ”

Notice the last line of output from the program: The particle bounces off
the vertical walls 6 times (nx=6) and from the horizontal ones 13 (ny=13).
The gnuplot commands construct the diagrams displayed in figures 2.22
and 2.23.
   In order to animate the particle’s trajectory, we can copy the file
112                                                     CHAPTER 2. KINEMATICS

      12                                     1.5
                                 x(t)                                     vx(t)
                                 y(t)                                     vy(t)
      10                                       1

      8
                                             0.5
      6
                                               0
      4
                                             -0.5
      2

      0                                       -1

      -2                                     -1.5
           0   10     20    30    40    50          0      10   20   30     40    50



Figure 2.22: The results for the trajectory of a particle in a two dimensional box
given by the program box2D_1.cpp. The parameters are Lx = 10, Ly = 5, x0 = 5,
y0 = 0, v0x = 1.27, v0y = 1.33, t0 = 0, tf = 50, δt = 0.01.



box2D_animate.gnu of the accompanying software to the current direc-
tory and give the gnuplot commands:

gnuplot >      file   = ” box2D_1 . dat ”
gnuplot >      Lx =   10 ; Ly = 5
gnuplot >      t0 =   0 ; tf = 50; dt = 1
gnuplot >      load   ” box2D_animate . gnu”
gnuplot >      t0 =   0 ; dt = 0 . 5 ; load ” box2D_animate . gnu”

The last line repeats the same animation at half speed. You can also
use the file animate2D.gnu discussed in section 2.1.1. We add new com-
mands in the file box2D_animate.gnu so that the plot limits are calculated
automatically and the box is drawn on the plot. The arrow drawn is not
the position vector with respect to the origin of the coordinate axes, but
the one connecting the initial with the current position of the particle.
    The next step should be to test the accuracy of your results. This can
be done by generalizing the discussion of the previous section and it is
left as an exercise for the reader.


2.4 Applications
In this section we will study simple examples of motion in a box with
different types of obstacles. We will start with a game of ... mini golf.
The player shoots a (point) “ball” which moves in an orthogonal box of
linear dimensions Lx and Ly and which is open on the x = 0 side. In
the box there is a circular “hole” with center at (xc , yc ) and radius R. If
2.4. APPLICATIONS                                                                             113



                          t= 48.000000 (x,y)= (5.901700,3.817100)

              5

              4

              3
       y




              2

              1

              0

                      0           2           4           6           8          10
                                                    x


Figure 2.23: The trajectory of the particle of figure 2.22 until t = 48. The origin of
the arrow is at the initial position of the particle and its end is at its current position.
The bold lines mark the boundaries of the box.



the “ball” falls in the “hole”, the player wins. If the ball leaves out of the
box through its open side, the player loses. In order to check if the ball
is in the hole when it is at position (x, y), all we have to do is to check
whether (x − xc )2 + (y − yc )2 ≤ R2 .
    Initially we place the ball at the position (0, Ly /2) at time t0 = 0. The
player hits the ball which leaves with initial velocity of magnitude v0 at
an angle θ degrees with the x axis. The program is found in the file
MiniGolf.cpp and is listed below:

/ / ============================================================
/ / F i l e MiniGolf . cpp
/ / Motion o f a f r e e p a r t i c l e i n a box 0<x<Lx 0<y<Ly
/ / The box i s open a t x=0 and has a h o l e a t ( xc , yc ) o f r a d i u s R
/ / B a l l i s s h o t a t ( 0 , Ly / 2 ) with speed v0 , a n g l e t h e t a ( d e g r e e s )
/ / Use i n t e g r a t i o n with time s t e p dt : x = x + vx * dt y=y+vy * dt
/ / B a l l s t o p s i n h o l e ( s u c c e s s ) or a t x=0 ( f a i l u r e )
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >
# i n c l u d e <iomanip >
# i n c l u d e < fstream >
114                                                 CHAPTER 2. KINEMATICS



                        t= 45.300000 (x,y)= (7.854117,2.982556)

            5

            4

            3
      y




            2

            1

            0

                    0          2          4          6          8         10
                                               x


Figure 2.24: The trajectory of the particle calculated by the program MiniGolf.cpp
using the parameters chosen in the text. The moment of ... success is shown. At time
t = 45.3 the particle enters the hole’s region which has its center at (8, 2.5) and its
radius is 0.5.




# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

# d e f i n e PI 3.14159265358979324

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of va ri a bl e s
    double Lx , Ly , x0 , y0 , v0x , v0y , t0 , tf , dt , t , x , y , vx , vy ;
    double v0 , theta , xc , yc , R , R2 ;
    int      i , nx , ny ;
    string result ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter Lx , Ly : \ n” ;
    cin >> Lx >> Ly ;                  getline ( cin , buf ) ;
    cout << ” # Lx = ” << Lx << ” Ly= ” << Ly << endl ;
    cout << ” # Enter h o l e p o s i t i o n and r a d i u s : ( xc , yc ) , R: \ n” ;
2.4. APPLICATIONS                                                                    115

    cin >> xc >> yc >> R ; getline ( cin , buf ) ;
    cout << ” # ( xc , yc )= ( ” << xc << ” , ” << yc << ” ) ”
              << ” R= ”          << R << endl ;
    cout << ” # Enter v0 , t h e t a ( d e g r e e s ) : \ n” ;
    cin >> v0 >> theta ;                     getline ( cin , buf ) ;
    cout << ” # v0= ” << v0 << ” t h e t a = ” << theta
              << ” d e g r e e s ”          << endl ;
    cout << ” # Enter dt : \ n” ;
    cin >> dt ;                              getline ( cin , buf ) ;
    i f ( Lx<=                  0 . 0 ) { cerr << ”Lx<=0          \n” ; exit ( 1 ) ; }
    i f ( Ly<=                  0 . 0 ) { cerr << ”Ly<=0          \n” ; exit ( 1 ) ; }
    i f ( v0<=                  0 . 0 ) { cerr << ”v0<=0          \n” ; exit ( 1 ) ; }
    i f ( abs ( theta ) > 9 0 . 0 ) { cerr << ” t h e t a > 90\n” ; exit ( 1 ) ; }
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    t0          = 0.0;
    x0          = 0.00001; / / s m a l l but non−z e r o
    y0          = Ly / 2 . 0 ;
    R2          = R*R ;
    theta = ( PI / 1 8 0 . 0 ) * theta ;
    v0x         = v0 * cos ( theta ) ;
    v0y         = v0 * sin ( theta ) ;
    cout << ” # x0= ” << x0 << ” y0= ” << y0
              << ” v0x= ” << v0x << ” v0y= ” << v0y << endl ;
    i = 0 ;
    nx = 0 ; ny = 0 ;
    t = t0 ;
    x = x0 ; y = y0 ;
    vx = v0x ; vy = v0y ;
    ofstream myfile ( ” MiniGolf . dat ” ) ;
    myfile . precision ( 1 7 ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    while ( t r u e ) {
        myfile << setw (28 ) << t << ” ”
              << setw (28 ) << x << ” ”
              << setw (28 ) << y << ” ”
              << setw (28 ) << vx << ” ”
              << setw (28 ) << vy << ’\n ’ ;
        i ++;
        t = t0 + i * dt ;
        x += vx * dt ;
        y += vy * dt ;
        i f ( x > Lx ) { vx = −vx ; nx ++;}
        i f ( y < 0 . 0 ) {vy = −vy ; ny ++;}
        i f ( y > Ly ) { vy = −vy ; ny ++;}
        i f ( x <=0.0)
            { result=” F a i l u r e ” ; break ; } / / e x i t loop
        i f ( ( ( x−xc ) * ( x−xc ) +(y−yc ) * ( y−yc ) ) <= R2 )
116                                                 CHAPTER 2. KINEMATICS

        { result=” S u c c e s s ” ; break ; } / / e x i t loop
  }
  myfile . close ( ) ;
  cout << ” # Number o f c o l l i s i o n s : \ n” ;
  cout << ” # R e s u l t= ” << result
          << ” nx= ” << nx << ” ny= ” << ny << endl ;
} / / main ( )

In order to run it, we can use the commands:

> g++ MiniGolf . cpp −o mg
> . / mg
# Enter Lx , Ly :
10 5
# Lx = 10 Ly= 5
# Enter h o l e p o s i t i o n and r a d i u s : ( xc , yc ) , R :
8 2.5 0.5
# ( xc , yc )= ( 8 , 2 . 5 ) R= 0.5
# Enter v0 , t h e t a ( d e g r e e s ) :
1 80
# v0= 1 t h e t a = 80 d e g r e e s
# Enter dt :
0.01
# x0= 1 e−05 y0= 2.5 v0x= 0.173648 v0y= 0.984808
# Number o f c o l l i s i o n s :
# R e s u l t= S u c c e s s nx= 0 ny= 9

You should construct the plots of the position and the velocity of the
particle. You can also use the animation program found in the file
MiniGolf_animate.gnu for fun. Copy it from the accompanying software
to the current directory and give the gnuplot commands:

gnuplot >   file   = ” MiniGolf . dat ”
gnuplot >   Lx =   1 0 ; Ly = 5
gnuplot >   xc =   8 ; yc = 2.5 ; R = 0.5
gnuplot >   t0 =   0 ; dt = 0 . 1
gnuplot >   load   ” MiniGolf_animate . gnu”

The results are shown in figure 2.24.
    The next example with be three dimensional. We will study the mo-
tion of a particle confined within a cylinder of radius R and height L.
The collisions of the particle with the cylinder are elastic. We take the
axis of the cylinder to be the z axis and the two bases of the cylinder to
be located at z = 0 and z = L. This is shown in figure 2.26.
    The collisions of the particle with the bases of the cylinder are easy to
2.4. APPLICATIONS                                                                     117

program: we follow the same steps as in the case of the simple box. For
the collision with the cylinder’s side, we consider the projection of the
motion on the x − y plane. The projection of the particle moves within
a circle of radius R and center at the intersection of the z axis with the
plane. This is shown in figure 2.25. At the collision, the r component
of the velocity is reflected vr → −vr , whereas vθ remains the same. The
velocity of the particle before the collision is
                                   ⃗v = vx x̂ + vy ŷ
                                       = vr r̂ + vθ θ̂                            (2.26)
and after the collision is
                                  ⃗v ′ = vx′ x̂ + vy′ ŷ
                                      = −vr r̂ + vθ θ̂                            (2.27)
From the relations
                              r̂ = cos θx̂ + sin θŷ
                              θ̂ = − sin θx̂ + cos θŷ ,                          (2.28)
and vr = ⃗v · r̂, vθ = ⃗v · θ̂, we have that
                            vr = vx cos θ + vy sin θ
                            vθ = −vx sin θ + vy cos θ .                           (2.29)
The inverse relations are
                             vx = vr cos θ − vθ sin θ
                             vy = vr sin θ + vθ cos θ .                           (2.30)
With the transformation vr → −vr , the new velocity in Cartesian coordi-
nates will be
                            vx′ = −vr cos θ − vθ sin θ
                            vy′ = −vr sin θ + vθ cos θ .                          (2.31)
 The transformation vx → vx′ , vy → vy′ will be performed in the function
reflectVonCircle(vx,vy,x,y,xc,yc,R). Upon entry to the function, we
provide the initial velocity (vx,vy), the collision point (x,y), the center
of the circle (xc,yc) and the radius of the circle²⁴ R. Upon exit from the
function, (vx,vy) have been replaced with the new values²⁵ (vx′ , vy′ ).
  ²⁴Of course one expects R2 = (x − xc )2 + (y − yc )2 , but because of systematic errors,
we require R to be given.
  ²⁵Notice that upon exit, the particle is also placed exactly on the circle.
118                                                      CHAPTER 2. KINEMATICS

                                                                             v
                                                              ^ y^
                                                              θ vθ      ^r        vr

                                                  v’                         ^x
                                                                (x,y)
                                                  R
                                                       − vr
                                                       θ

                                        (xc,yc)




Figure 2.25: The elastic collision of the particle moving within the circle of radius
R = |R|⃗ and center ⃗rc = xc x̂ + yc ŷ at the point ⃗r = xx̂ + y ŷ. We have that R  ⃗ =
(x − xc )x̂ + (y − yc )ŷ. The initial velocity is ⃗v = vr r̂ + vθ θ̂ where r̂ ≡ R/R. After
                                                                                 ⃗
reflecting vr → −vr the new velocity of the particle is ⃗v ′ = −vr r̂ + vθ θ̂.




   The program can be found in the file Cylinder3D.cpp and is listed
below:

/ / ============================================================
/ / F i l e Cylinder3D . cpp
/ / Motion o f a f r e e p a r t i c l e i n a c y l i n d e r with a x i s t h e z−a x i s ,
/ / r a d i u s R and 0<z<L
/ / Use i n t e g r a t i o n with time s t e p dt : x = x + vx * dt
//                                                             y = y + vy * dt
//                                                             z = z + vz * dt
/ / Use f u n c t i o n r e f l e c t V o n C i r c l e f o r c o l i s i o n s a t r=R
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >
# i n c l u d e <iomanip >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

void reflectVonCircle ( double& vx , double& vy ,
              double& x , double& y ,
2.4. APPLICATIONS                                                                       119

                    const          double& xc ,
                    const          double& yc ,
                    const          double& R ) ;

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of v ar i ab l e s
    double x0 , y0 , z0 , v0x , v0y , v0z , t0 , tf , dt , t , x , y , z , vx , vy , vz ;
    double L , R , R2 , vxy , rxy , r2xy , xc , yc ;
    int         i , nr , nz ;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter R , L: \ n” ;
    cin >> R >> L ;                                         getline ( cin , buf ) ;
    cout << ” # R= ” << R << ” L= ” << L << endl ;
    cout << ” # Enter x0 , y0 , z0 , v0x , v0y , v0z : \ n” ;
    cin >> x0>>y0>>z0>>v0x>>v0y>>v0z ;                      getline ( cin , buf ) ;
    rxy = sqrt ( x0 * x0+y0 * y0 ) ;
    cout << ” # x0 = ” << x0
            << ” y0 = ” << y0
            << ” z0 = ” << z0
            << ” rxy= ” << rxy << endl ;
    cout << ” # v0x= ” << v0x
            << ” v0y= ” << v0y
            << ” v0z= ” << v0z << endl ;
    cout << ” # Enter t0 , t f , dt : \ n” ;
    cin >> t0 >> tf >> dt ;                                 getline ( cin , buf ) ;
    cout << ” # t 0= ” << t0 << ” t f = ” << tf
            << ” dt= ” << dt << endl ;
    i f (R      <= 0 . 0 ) { cerr << ”R<=0        \n” ; exit ( 1 ) ; }
    i f (L      <= 0 . 0 ) { cerr << ”L<=0        \n” ; exit ( 1 ) ; }
    i f ( z0 < 0 . 0 ) { cerr << ” z0<0           \n” ; exit ( 1 ) ; }
    i f ( z0 >           L ) { cerr << ” z0>L     \n” ; exit ( 1 ) ; }
    i f ( rxy >          R ) { cerr << ” rxy >R \n” ; exit ( 1 ) ; }
    i f ( v0x * v0x+v0y * v0y+v0z * v0z == 0 . 0 )
                             { cerr << ” v0=0     \n” ; exit ( 1 ) ; }
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    i = 0 ;
    nr = 0 ; nz = 0 ;
    t = t0 ;
    x = x0 ; y = y0 ; z = z0 ;
    vx = v0x ; vy = v0y ; vz = v0z ;
    R2 = R * R ;
    xc = 0 . 0 ; / / c e n t e r o f c i r c l e which i s t h e p r o j e c t i o n
    yc = 0 . 0 ; / / o f t h e c y l i n d e r on t h e xy plane
    ofstream myfile ( ” Cylinder3D . dat ” ) ;
    myfile . precision ( 1 7 ) ;
120                                              CHAPTER 2. KINEMATICS

/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    while ( t <= tf ) {
      myfile << setw (2 8) << t << ” ”
           << setw (2 8) << x << ” ”
           << setw (2 8) << y << ” ”
           << setw (2 8) << z << ” ”
           << setw (2 8) << vx << ” ”
           << setw (2 8) << vy << ” ”
           << setw (2 8) << vz << ’\n ’ ;
      i ++;
      t = t0 + i * dt ;
      x += vx * dt ;
      y += vy * dt ;
      z += vz * dt ;
      i f ( z <= 0.0 | | z > L ) { vz = −vz ; nz ++;}
      r2xy = x * x+y * y ;
      i f ( r2xy > R2 ) {
          reflectVonCircle ( vx , vy , x , y , xc , yc , R ) ;
          nr ++;
      }
    }
    myfile . close ( ) ;
    cout << ” # Number o f c o l l i s i o n s : \ n” ;
    cout << ” # nr= ” << nr << ” nz= ” << nz << endl ;
} / / main ( )
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / ============================================================
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void reflectVonCircle ( double& vx , double& vy ,
                   double& x , double& y ,
                   const          double& xc ,
                   const          double& yc ,
                   const          double& R ) {
    double theta , cth , sth , vr , vth ;

  theta = atan2 ( y−yc , x−xc ) ;
  cth   = cos ( theta ) ;
  sth   = sin ( theta ) ;

  vr     = vx * cth + vy * sth ;
  vth    = −vx * sth + vy * cth ;

  vx     = −vr * cth − vth * sth ; / / r e f l e c t vr −> −vr
  vy     = −vr * sth + vth * cth ;

  x       = xc      + R * cth ;      / / put x , y on t h e c i r c l e
  y       = yc      + R * sth ;
} / / reflectVonCircle ()
2.4. APPLICATIONS                                                                       121

    Note that the function atan2 is used for computing the angle theta.
This function, when called with two arguments atan2(y,x), returns the
angle θ = tan−1 (y/x) in radians. The correct quadrant of the circle where
(x, y) lies is chosen. The angle that we want to compute is given by
atan2(y-yc,x-xc). Then we apply equations (2.29) and (2.31) and in
the last two lines we enforce the particle to be at the point (xc +R cos θ, yc +
R sin θ), exactly on the circle.

                            t= 500.000000 (x,y,z)= (2.227212,0.469828,7.088600)




                       10

                       8
                   z   6

                       4

                       2

                       0

                                                                                   10
                                                                           5
                        -10                                           0
                                  -5                                           y
                                           0                     -5
                                       x           5
                                                           -10
                                                          10




Figure 2.26: The trajectory of a particle moving inside a cylinder with R = 10, L = 10,
 computed by the program Cylinder3D.cpp. We have chosen ⃗r0 = 1.0x̂ + 2.2ŷ + 3.1ẑ,
⃗v0 = 0.93x̂ − 0.89ŷ + 0.74ẑ, t0 = 0, tf = 500.0, δt = 0.01.


   A typical session is shown below:

> g++ Cylinder3D . cpp −o cl
> . / cl
# Enter R , L :
10.0 10.0
# R= 10 L= 10
# Enter x0 , y0 , z0 , v0x , v0y , v0z :
1 . 0 2.2 3 . 1    0.93 −0.89 0 . 7 4
# x0 = 1 y0 = 2.2 z0 = 3 . 1 rxy= 2.41661
# v0x= 0.93 v0y= −0.89 v0z= 0 . 7 4
# Enter t0 , t f , dt :
0.0 500.0 0.01
122                                                   CHAPTER 2. KINEMATICS

# t 0= 0 t f = 500 dt= 0.01
# Number o f c o l l i s i o n s :
# nr= 33 nz= 37

In order to plot the position and the velocity as a function of time, we
use the following gnuplot commands:

gnuplot > file=” Cylinder3D . dat ”
gnuplot > p l o t file using 1 : 2 with          lines    title    ” x ( t ) ” ,\
                  file using 1 : 3 with          lines    title    ” y ( t ) ” ,\
                  file using 1 : 4 with          lines    title    ” z( t )”
gnuplot > p l o t file using 1 : 5 with          lines    title    ” v_x ( t ) ” ,\
                  file using 1 : 6 with          lines    title    ” v_y ( t ) ” ,\
                  file using 1 : 7 with          lines    title    ” v_z ( t ) ”

We can√also compute the distance of the particle from the cylinder’s axis
r(t) = x(t)2 + y(t)2 as a function of time using the command:

gnuplot > p l o t file using 1 : ( s q r t ( $2 **2+ $3 * * 2 ) ) w l t ” r ( t ) ”

In order to plot the trajectory, together with the cylinder, we give the
commands:

gnuplot >   file=” Cylinder3D . dat ”
gnuplot >   L = 10 ; R = 10
gnuplot >   s e t urange [ 0 : 2 . 0 * pi ]
gnuplot >   s e t vrange [ 0 : L ]
gnuplot >   s e t parametric
gnuplot >   s p l o t file using 2 : 3 : 4 with lines notitle , \
                               R * c o s ( u ) , R * s i n ( u ) , v notitle

The command set parametric is necessary if one wants to make a para-
metric plot of a surface ⃗r(u, v) = x(u, v) x̂ + y(u, v) ŷ + z(u, v) ẑ. The cylin-
der (without the bases) is given by the parametric equations ⃗r(u, v) =
R cos u x̂ + R sin u ŷ + v ẑ with u ∈ [0, 2π), v ∈ [0, L].
    We can also animate the trajectory with the help of the gnuplot script
file Cylinder3D_animate.gnu. Copy the file from the accompanying soft-
ware to the current directory and give the gnuplot commands:

gnuplot > file=” Cylinder3D . dat ”
gnuplot > R =10; L =10; t0 =0; tf =500; dt=10
gnuplot > load ” Cylinder3D_animate . gnu”

The result is shown in figure 2.26.
2.4. APPLICATIONS                                                             123




Figure 2.27: A typical geometry of space near a wormhole. Two asymptotically
flat regions of space are connected through a “neck” which can be arranged to be of
small length compared to the distance of the wormhole mouths when traveled from the
outside space.


    The last example will be that of a simple model of a spacetime worm-
hole. This is a simple spacetime geometry which, in the framework of
the theory of general relativity, describes the connection of two distant
areas in space which are asymptotically flat. This means, that far enough
from the wormhole’s mouths, space is almost flat - free of gravity. Such
a geometry is depicted in figure 2.27. The distance traveled by someone
through the mouths could be much smaller than the distance traveled
outside the wormhole and, at least theoretically, traversable wormholes
could be used for interstellar/intergalactic traveling and/or communica-
tions between otherwise distant areas in the universe. Of course we
should note that such macroscopic and stable wormholes are not known
to be possible to exist in the framework of general relativity. One needs
an exotic type of matter with negative energy density which has never
been observed. Such exotic geometries may realize microscopically as
quantum fluctuations of spacetime and make the small scale structure of
the geometry²⁶ a “spacetime foam”.
    We will study a very simple model of the above geometry on the plane

  ²⁶See K.S. Thorne “Black Holes and Time Wraps: Einstein’s Outrageous Legacy”,
W.W. Norton, New York for a popular review of these concepts.
124                                                CHAPTER 2. KINEMATICS

                                            y


                                                                   v’
                   4                                           4         θ
      θ
              v
          3                    1                     1                       3 x




                   2                                           2




Figure 2.28: A simple model of the spacetime geometry of figure 2.27. The particle
moves on the whole plane except withing the two disks that have been removed. The
neck of the wormhole is modeled by the two circles x(θ) = ±d/2±R cos θ, y(θ) = R sin θ,
−π < θ ≤ π and has zero length since their points have been identified. There is a
given direction in this identification, so that points with the same θ are the same (you
can imagine how this happens by folding the plane across the y axis and then glue the
two circles together). The entrance of the particle through one mouth and exit through
the other is done as shown for the velocity vector ⃗v → ⃗v ′ .


with a particle moving freely in it²⁷. We take the two dimensional plane
and cut two equal disks of radius R with centers at distance d like in
figure 2.28. We identify the points on the two circles such that the point
1 of the left circle is the same as the point 1 on the right circle, the point 2
on the left with the point 2 on the right etc. The two circles are given by
the parametric equations x(θ) = d/2 + R cos θ, y(θ) = R sin θ, −π < θ ≤ π
for the right circle and x(θ) = −d/2 − R cos θ, y(θ) = R sin θ, −π < θ ≤ π
for the left. Points on the two circles with the same θ are identified.
A particle entering the wormhole from the left circle with velocity v is
immediately exiting from the right with velocity v ′ as shown in figure
2.28.
    Then we will do the following:

   ²⁷This idea can be found as an exercise in the excellent introductory general relativ-
ity textbook J. B. Hartle, “Gravity: An Introduction to Einstein’s General Relativity”,
Addison Wesley 2003, Ch. 7, Ex. 25.
2.4. APPLICATIONS                                                             125

  1. Write a program that computes the trajectory of a particle moving
     in the geometry of figure 2.28. We set the limits of motion to be
     −L/2 ≤ x ≤ L/2 and −L/2 ≤ y ≤ L/2. We will use periodic
     boundary conditions in order to define what happens when the
     particle attempts to move outside these limits. This means that
     we identify the x = −L/2 line with the x = +L/2 line as well
     as the y = −L/2 line with the y = +L/2 line. The user enters the
     parameters R, d and L as well as the initial conditions (x0 , y0 ), (v0 , ϕ)
     where ⃗v0 = v0 (cos ϕx̂ + sin ϕŷ). The user will also provide the time
     parameters tf and dt for motion in the time interval t ∈ [t0 = 0, tf ]
     with step dt.

  2. Plot the particle’s trajectory with (x0 , y0 ) = (0, −1), (v0 , ϕ) = (1, 10o )
     με tf = 40, dt = 0.05 in the geometry with L = 20, d = 5, R = 1.

  3. Find a closed trajectory which does not cross the boundaries |x| =
     L/2, |y| = L/2 and determine whether it is stable under small per-
     turbations of the initial conditions.

  4. Find other closed trajectories that go through the mouths of the
     wormhole and study their stability under small perturbations of
     the initial conditions.

  5. Add to the program the option to calculate the distance traveled by
     the particle. If the particle starts from (−x0 , 0) and moves in the +x
     direction to the (x0 , 0), x0 > R + d/2 position, draw the trajectory
     and calculate the distance traveled on paper. Then confirm your
     calculation from the numerical result coming from your program.

  6. Change the boundary conditions, so that the particle bounces off
     elastically at |x| = L/2, |y| = L/2 and replot all the trajectories
     mentioned above.

Define the right circle c1 by the parametric equations

              d
     x(θ) =     + R cos θ ,      y(θ) = R sin θ ,      −π < θ ≤ π ,        (2.32)
              2
and the left circle c2 by the parametric equations

            d
    x(θ) = − − R cos θ ,          y(θ) = R sin θ ,      −π < θ ≤ π .       (2.33)
            2
126                                                        CHAPTER 2. KINEMATICS

                                                  y


                    v’
                           ^                                              ^
                                                                          e
                           e’θ                                                θ
                                                                                          ^
                                                                                          er
              ^
              e’r        (x’,y’)                                  v               (x,y)

                     θ                                                        θ            x




Figure 2.29: The particle crossing the wormhole through the right circle c1 with
velocity ⃗v . It emerges from c2 with velocity ⃗v ′ . The unit vectors (êr , êθ ), (ê′r , ê′θ ) are
computed from the parametric equations of the two circles c1 and c2 .


    The particle’s position changes at time dt by

                                      ti = idt
                                      xi = xi−1 + vx dt
                                      yi = yi−1 + vy dt
                                                                                               (2.34)

for i = 1, 2, . . . for given (x0 , y0 ), t0 = 0 and as long as ti ≤ tf . If the
point (xi , yi ) is outside the boundaries |x| = L/2, |y| = L/2, we redefine
xi → xi ± L, yi → yi ± L in each case respectively. Points defined by
the same value of θ are identified, i.e. they represent the same points of
space. If the point (xi , yi ) crosses either one of the circles c1 or c2 , then
we take the particle out from the other circle.
   Crossing the circle c1 is determined by the relation
                                    (       )2
                                          d
                                     xi −      + yi2 ≤ R2 .                                    (2.35)
                                          2

The angle θ is calculated from the equation
                                    (         )
                                         y
                          θ = tan−1
                                          i
                                                ,                                              (2.36)
                                      xi − d2
2.4. APPLICATIONS                                                                127

and the point (xi , yi ) is mapped to the point (x′i , yi′ ) where
                               d
                        x′i = − − R cos θ ,               yi′ = yi ,           (2.37)
                               2
as can be seen in figure 2.29. For mapping ⃗v → ⃗v ′ , we first calculate the
vectors
                               }   { ′
   êr =  cos θ x̂ + sin θ ŷ       êr = − cos θ x̂ + sin θ ŷ
                                 →                                , (2.38)
   êθ = − sin θ x̂ + cos θ ŷ      ê′θ =  sin θ x̂ + cos θ ŷ
so that the velocity

                 ⃗v = vr êr + vθ êθ   →        ⃗v ′ = −vr ê′r + vθ ê′θ ,   (2.39)

where the radial components are vr = ⃗v · êr and vθ = ⃗v · êθ . Therefore,
the relations that give the “emerging” velocity ⃗v ′ are:

                          vr =  vx cos θ         +    vy sin θ
                          vθ = −vx sin θ         +    vy cos θ
                                                               .               (2.40)
                          vx′ = vr cos θ         +    vθ sin θ
                            ′
                          vy = −vr sin θ         +    vθ cos θ
     Similarly we calculate the case of entering from c2 and emerging from
c1 . The condition now is:
                            (        )2
                                   d
                              xi +      + yi2 ≤ R2 .                 (2.41)
                                   2
The angle θ is given by
                                               (              )
                                          −1         yi
                            θ = π − tan                   d
                                                                  ,            (2.42)
                                                   xi +   2

and the point (xi , yi ) is mapped to the point (x′i , yi′ ) where
                                 d
                         x′i =     + R cos θ ,          yi′ = yi .             (2.43)
                                 2
For mapping ⃗v → ⃗v ′ , we calculate the vectors
                               }     { ′
  êr = − cos θ x̂ + sin θ ŷ           êr =   cos θ x̂ + sin θ ŷ
                                  →       ′                         , (2.44)
  êθ =   sin θ x̂ + cos θ ŷ           êθ = − sin θ x̂ + cos θ ŷ
so that the velocity

                 ⃗v = vr êr + vθ êθ   →        ⃗v ′ = −vr ê′r + vθ ê′θ .   (2.45)
128                                                   CHAPTER 2. KINEMATICS

The emerging velocity ⃗v ′ is:

                        vr = −vx cos θ +              vy sin θ
                        vθ =   vx sin θ +             vy cos θ
                          ′                                    .      (2.46)
                        vx = −vr cos θ −              vθ sin θ
                        vy′ = −vr sin θ +             vθ cos θ

    Systematic errors are now coming from crossing the two mouths of the
wormhole. There are no systematic errors from crossing the boundaries
|x| = L/2, |y| = L/2 (why?). Try to think of ways to control those errors
and study them.
    The closed trajectories that we are looking for come from the initial
conditions
                          (x0 , y0 , v0 , ϕ) = (0, 0, 1, 0)        (2.47)
and they connect points 1 of figure 2.28. They are unstable, as can be
seen by taking ϕ → ϕ + ϵ.
   The closed trajectories that cross the wormhole and “wind” through
space can come from the initial conditions

                      (x0 , y0 , v0 , ϕ) = (−9, 0, 1, 0)
                      (x0 , y0 , v0 , ϕ) = (2.5, −3, 1, 90o )

and cross the points 3 → 3 and 2 → 2 → 4 → 4 respectively. They are
also unstable, as can be easily verified by using the program that you will
write. The full program is listed below:

/ / ============================================================
/ / F i l e Wormhole . cpp
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

# d e f i n e PI 3.1415926535897932

void   crossC1 (           double&    x,              double& y ,
                           double&   vx ,             double& vy ,
                 c o n s t double&   dt , c o n s t   double& R ,
                 c o n s t double&   d) ;
void   crossC2 (           double&    x,              double& y ,
                           double&   vx ,             double& vy ,
2.4. APPLICATIONS                                                                  129

                  c o n s t double& dt , c o n s t double&     R,
                  c o n s t double& d ) ;

i n t main ( ) {
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Declaration of v ar i ab l e s
    double Lx , Ly , L , R , d ;
    double x0 , y0 , v0 , theta ;
    double t0 , tf , dt ;
    double t , x , y , vx , vy ;
    double xc1 , yc1 , xc2 , yc2 , r1 , r2 ;
    int        i;
    string buf ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Ask u s e r f o r i n p u t :
    cout << ” # Enter L , d , R: \ n” ;
    cin >> L >> d >> R ;                                     getline ( cin , buf ) ;
    cout << ” # Enter ( x0 , y0 ) , v0 , t h e t a ( d e g r e e s ) : \ n” ;
    cin >> x0 >> y0 >> v0 >> theta ;                         getline ( cin , buf ) ;
    cout << ” # Enter t f , dt : \ n” ;
    cin >> tf >> dt ; getline ( cin , buf ) ;
    cout << ” # L= ” << L << ” d=                         ” << d
            << ” R= ” << R << endl ;
    cout << ” # x0= ” << x0 << ” y0=                      ” << y0        << endl ;
    cout << ” # v0= ” << v0 << ” t h e t a = ”
            << theta            << ” d e g r e e s ”                     << endl ;
    cout << ” # t f = ” << tf << ” dt=                    ” << dt        << endl ;
    i f ( L <= d +2.0* R ) { cerr <<”L <= d+2*R \n” ; exit ( 1 ) ; }
    i f ( d <=      2 . 0 * R ) { cerr <<”d <=         2*R \n” ; exit ( 1 ) ; }
    i f ( v0<=      0.0 ) { cerr <<”v0<=                 0 \n” ; exit ( 1 ) ; }
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
// Initialize
    theta = ( PI / 1 8 0 . 0 ) * theta ;
    i        = 0;
    t        = 0.0;
    x        = x0                         ; y        = y0 ;
    vx       = v0 * cos ( theta ) ; vy               = v0 * sin ( theta ) ;
    cout << ” # x0= ” << x0 << ” y0= ” << y0
            << ” v0x= ” << vx << ” v0y= ” << vy << endl ;
/ / Wormhole ’ s c e n t e r s :
    xc1      = 0 . 5 * d ; yc1           = 0.0;
    xc2      = −0.5*d ; yc2              = 0.0;
/ / Box l i m i t s c o o r d i n a t e s :
    Lx       = 0 . 5 * L ; Ly            = 0.5* L ;
/ / Test i f already inside cut region :
    r1       = sqrt ( ( x−xc1 ) * ( x−xc1 ) +(y−yc1 ) * ( y−yc1 ) ) ;
    r2       = sqrt ( ( x−xc2 ) * ( x−xc2 ) +(y−yc2 ) * ( y−yc2 ) ) ;
    i f ( r1<=              R ) { cerr <<” r 1 <=        R \n” ; exit ( 1 ) ; }
    i f ( r1<=              R ) { cerr <<” r2 <=         R \n” ; exit ( 1 ) ; }
130                                               CHAPTER 2. KINEMATICS

/ / T e s t i f o u t s i d e box l i m i t s :
    i f ( abs ( x ) >= Lx ) { cerr <<” | x | >=         Lx \n” ; exit ( 1 ) ; }
    i f ( abs ( y ) >= Ly ) { cerr <<” | y | >=         Ly \n” ; exit ( 1 ) ; }
    ofstream myfile ( ”Wormhole . dat ” ) ;
    myfile . precision ( 1 7 ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Compute :
    while ( t < tf ) {
        myfile << t << ” ”
                    << x << ” ” << y << ” ”
                    << vx << ” ” << vy << endl ;
        i++;
        t = i * dt ;
        x += vx * dt ; y += vy * dt ;
/ / T o r o i d a l boundary c o n d i t i o n s :
        i f ( x > Lx ) x = x − L ;
        i f ( x < −Lx ) x = x + L ;
        i f ( y > Ly ) y = y − L ;
        i f ( y < −Ly ) y = y + L ;
        r1       = sqrt ( ( x−xc1 ) * ( x−xc1 ) +(y−yc1 ) * ( y−yc1 ) ) ;
        r2       = sqrt ( ( x−xc2 ) * ( x−xc2 ) +(y−yc2 ) * ( y−yc2 ) ) ;
/ / N o t i c e : we pass r 1 as r a d i u s o f c i r c l e , not R
        if          ( r1 < R )
            crossC1 ( x , y , vx , vy , dt , r1 , d ) ;
        e l s e i f ( r2 < R )
            crossC2 ( x , y , vx , vy , dt , r2 , d ) ;
/ / s m a l l chance here t h a t s t i l l i n C1 or C2 , but OK s i n c e
/ / another dt−advance giv e n a t t h e beginning o f f o r −loop
    } / / while ( t <= t f )
} / / main ( )
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void crossC1 (                    double& x ,             double& y ,
                                  double& vx ,            double& vy ,
                        c o n s t double& dt , c o n s t double& R ,
                        c o n s t double& d ) {

    double vr , v0 , theta , xc , yc ;
    cout << ” # I n s i d e C1 : ( x , y , vx , vy , R)= ”
         << x << ” ” << y << ” ”
         << vx << ” ” << vy << ” ” <<R << endl ;
    xc    = 0.5* d ;                        / / c e n t e r o f C1
    yc    = 0.0;
    theta = atan2 ( y−yc , x−xc ) ;
    x     = −xc − R * cos ( theta ) ; / / new x−value , y i n v a r i a n t
/ / Velocity transformation :
    vr    = vx * cos ( theta )+vy * sin ( theta ) ;
    v0    = −vx * sin ( theta )+vy * cos ( theta ) ;
    vx    = vr * cos ( theta )+v0 * sin ( theta ) ;
    vy    = −vr * sin ( theta )+v0 * cos ( theta ) ;
2.4. APPLICATIONS                                                              131

/ / advance x , y , h o p e f u l l y o u t s i d e C2 :
    x      = x + vx * dt ;
    y      = y + vy * dt ;
    cout << ” # E x i t        C2 : ( x , y , vx , vy )= ”
          << x << ” ” << y << ” ”
          << vx << ” ” << vy << endl ;
} / / void c r o s s C 1 ( )
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void crossC2 (                 double& x ,               double& y ,
                               double& vx ,              double& vy ,
                     c o n s t double& dt , c o n s t double& R ,
                     c o n s t double& d ) {

    double vr , v0 , theta , xc , yc ;
    cout << ” # I n s i d e C2 : ( x , y , vx , vy , R)= ”
          << x << ” ” << y << ” ”
          << vx << ” ” << vy << ” ” <<R << endl ;
    xc     = −0.5*d ;                            / / c e n t e r o f C2
    yc     = 0.0;
    theta = PI−atan2 ( y−yc , x−xc ) ;
    x      = −xc + R * cos ( theta ) ; / / new x−value , y i n v a r i a n t
/ / Velocity transformation :
    vr     = −vx * cos ( theta )+vy * sin ( theta ) ;
    v0     = vx * sin ( theta )+vy * cos ( theta ) ;
    vx     = −vr * cos ( theta )−v0 * sin ( theta ) ;
    vy     = −vr * sin ( theta )+v0 * cos ( theta ) ;
/ / advance x , y , h o p e f u l l y o u t s i d e C1 :
    x      = x + vx * dt ;
    y      = y + vy * dt ;
    cout << ” # E x i t      C1 : ( x , y , vx , vy )= ”
          << x << ” ” << y << ” ”
          << vx << ” ” << vy << endl ;
} / / void c r o s s C 2 ( )

   It is easy to compile and run the program. See also the files Wormhole.csh
and Wormhole_animate.gnu of the accompanying software and run the
gnuplot commands:

gnuplot >   file = ”Wormhole . dat ”
gnuplot >   R =1; d =5; L=20;
gnuplot >   ! . / Wormhole . csh
gnuplot >   t0 =0; dt = 0 . 2 ; load ” Wormhole_animate . gnu”

You are now ready to answer the rest of the questions that we asked in
our list.
132                                         CHAPTER 2. KINEMATICS

2.5 Problems
 2.1 Change the program Circle.cpp so that it prints the number of full
     circles traversed by the particle.

2.2 Add all the necessary tests on the parameters entered by the user
    in the program Circle.cpp, so that the program is certain to run
    without problems. Do the same for the rest of the programs given
    in the same section.

2.3 A particle moves with constant angular velocity ω on a circle that
    has the origin of the coordinate system at its center. At time t0 = 0,
    the particle is at (x0 , y0 ). Write the program CircularMotion.cpp
    that will calculate the particle’s trajectory. The user should enter the
    parameters ω, x0 , y0 , t0 , tf , δt. The program should print the results
    like the program Circle.cpp does.

 2.4 Change the program SimplePendulum.cpp so that the user could
     enter a non zero initial velocity.

2.5 Study the k → 0 limit in the projectile motion given by equations
    (2.10). Expand e−kt = 1−kt+ 2!1 (kt)2 +. . . and keep the non vanish-
    ing terms as k → 0. Then keep the next order leading terms which
    have a smaller power of k. Program these relations in a file
    ProjectileSmallAirResistance.cpp. Consider the initial condi-
    tions ⃗v0 = x̂ + ŷ and calculate the range of the trajectory numerically
    by using the two programs
    ProjectileSmallAirResistance.cpp, ProjectileAirResistance.cpp.
    Determine the range of values of k for which the two results agree
    within 5% accuracy.

2.6 Write a program for a projectile which moves through a fluid with
    fluid resistance proportional to the square of the velocity. Compare
    the range of the trajectory with the one calculated by the program
    ProjectileAirResistance.cpp for the parameters shown in figure
    2.10.

 2.7 Change the program Lissajous.cpp so that the user can enter a
     different amplitude and initial phase in each direction. Study the
     case where the amplitudes are the same and the phase difference
     in the two directions are π/4, π/2, π, −π. Repeat by taking the am-
     plitude in the y direction to be twice as much the amplitude in the
     x direction.
2.5. PROBLEMS                                                             133

 2.8 Change the program ProjectileAirResistance.cpp, so that it can
     calculate also the k = 0 case.

 2.9 Change the program ProjectileAirResistance.cpp so that it can
     calculate the trajectory of the particle in three dimensional space.
     Plot the position coordinates and the velocity components as a func-
     tion of time. Plot the three dimensional trajectory using splot
     in gnuplot and animate the trajectory using the gnuplot script
     animate3D.gnu.

2.10 Change the program ChargeInB.cpp so that it can calculate the
     number of full revolutions that the projected particle’s position on
     the x − y plane makes during its motion.

2.11 Change the program box1D_1.cpp so that it prints the number of
     the particle’s collisions on the left wall, on the right wall and the
     total number of collisions to the stdout.

2.12 Do the same for the program box1D_2.cpp. Fill the table on page
     106 the number of calculated collisions and comment on the results.

2.13 Run the program box1D_1.cpp and choose L= 10, v0=1. Decrease
     the step dt up to the point that the particle stops to move. For
     which value of dt this happens? Increase v0=10,100. Until which
     value of dt the particle moves now? Why?

2.14 Change the float declarations to double in the program box1D_1.cpp.
     Make sure that all the constants that you use become double pre-
     cision (e.g. 1.0f changes to 1.0). Compare your results to those
     obtained in section 2.3.2. Repeat problem 2.13. What do you ob-
     serve?

2.15 Change the program box1D_1.cpp so that you can study non elastic
     collisions v ′ = −ev, 0 < e ≤ 1 with the walls.

2.16 Change the program box2D_1.cpp so that you can study inelastic
     collisions with the walls, such that vx′ = −evx , vy′ = −evy , 0 < e ≤ 1.

2.17 Use the method of calculating time in the programs box1D_4.cpp
     and box1D_5.cpp in order to produce the results in figure 2.21.

2.18 Particle falls freely moving in the vertical direction. It starts with
     zero velocity at height h. Upon reaching the ground, it bounces
     inelastically such that vy′ = −evy with 0 < e ≤ 1 a parameter. Write
134                                              CHAPTER 2. KINEMATICS

      the necessary program in order to study numerically the particle’s
      motion and study the cases e = 0.1, 0.5, 0.9, 1.0.

2.19 Generalize the program of the previous problem so that you can
     study the case ⃗v0 = v0x x̂. Animate the calculated trajectories.

2.20 Study the motion of a particle moving inside the box of figure 2.30.
     Count the number of collisions of the particle with the walls before
     it leaves the box.


                    Lx                                        a




                                            Ly


                             Figure 2.30: Problem 2.20.



2.21 Study the motion of the point particle on the “billiard table” of
     figure 2.31. Count the number of collisions with the walls before
     the particle enters into a hole. The program should print from
     which hole the particle left the table.
                         a                            a

                    a                                     a




                                                          Ly




                         a                           a    a
                    a


                                       Lx



                             Figure 2.31: Problem 2.21.



2.22 Write a program in order to study the motion of a particle in the
     box of figure 2.32. At the center of the box there is a disk on
     which the particle bounces off elastically (Hint: use the routine
     reflectVonCircle of the program Cylinder3D.cpp).
2.5. PROBLEMS                                                       135



                                                               Ly



                                       2R



                                      Lx



                       Figure 2.32: Problem 2.22.


                                       2R
                                      111
                                      000
                                      111
                                      000
                                      111
                                      000
                                      111
                                      000
                                      111
                                      000

                                111
                                000
                                111         111
                                            000                Ly
                                000
                                111
                                000
                                            111
                                            000
                                            111
                                            000
                           2R   111
                                000
                                111
                                000
                                            111
                                            000
                                            111
                                            000   2R
                                       2R
                                      111
                                      000
                                      111
                                      000
                                      111
                                      000
                                      111
                                      000
                                      111
                                      000

                                       2a


                                      Lx



                       Figure 2.33: Problem 2.23.


2.23 In the box of the previous problem, put four disks on which the
     particle bounces of elastically like in figure 2.33.

2.24 Consider the arrangement of figure 2.34. Each time the particle
     bounces elastically off a circle, the circle disappears. The game is
     over successfully if all the circles vanish. Each time the particle
     bounces off on the wall to the left, you lose a point. Try to find
     trajectories that minimize the number of lost points.

                                                         111
                                                         000
                                                         111
                                                         000
                                                         111
                                                         000
                                                         111
                                                         000
                                                         111
                                                         000
                                             111
                                             000
                                             111
                                             000
                                             111
                                             000
                                             111
                                             000
                                             111
                                             000
                                                               Ly
                                             111
                                             000   111
                                                   000
                                             111
                                             000
                                             111   111
                                                   000
                                             000
                                             111
                                             000
                                                   111
                                                   000
                                                   111
                                                   000
                                             111
                                             000   111
                                                   000

                                             111
                                             000
                                             111   111
                                                   000 111
                                                       000
                                             000
                                             111
                                             000
                                                   111
                                                   111
                                                   000
                                                       111
                                                   000 111
                                                       000
                                                       000
                                             111
                                             000
                                             111   111
                                                   000 111
                                                       000
                                             000   111
                                                   000 111
                                                       000




                                      Lx



                       Figure 2.34: Problem 2.24.
136   CHAPTER 2. KINEMATICS
Chapter 3

Logistic Map

Nonlinear differential equations model interesting dynamical systems in
physics, biology and other branches of science. In this chapter we per-
form a numerical study of the discrete logistic map as a “simple math-
ematical model with complex dynamical properties” [23] similar to the
ones encountered in more complicated and interesting dynamical sys-
tems. For certain values of the parameter of the map, one finds chaotic
behavior giving us an opportunity to touch on this very interesting topic
with important consequences in physical phenomena. Chaotic evolu-
tion restricts out ability for useful predictions in an otherwise fully deter-
ministic dynamical system: measurements using slightly different initial
conditions result in a distribution which is indistinguishable from the dis-
tribution coming from sampling a random process. This scientific field is
huge and active and we refer the reader to the bibliography for a more
complete introduction [23, 24, 25, 26, 27, 28, 29, 40].


3.1     Introduction
The most celebrated application of the logistic map comes from the study
of population growth in biology. One considers populations which re-
produce at fixed time intervals and whose generations do not overlap.
   The simplest (and most naive) model is the one that makes the rea-
sonable assumption that the rate of population growth dP (t)/dt of a
population P (t) is proportional to the current population:
                            dP (t)
                                   = kP (t) .                     (3.1)
                             dt
The general solution of the above equation is P (t) = P (0)ekt showing
an exponential population growth for k > 0 an decline for k < 0. It

                                     137
138                                               CHAPTER 3. LOGISTIC MAP

is obvious that this model is reasonable as long as the population is
small enough so that the interaction with its environment (adequate food,
diseases, predators etc) can be neglected. The simplest model that takes
into account some of the factors of the interaction with the environment
(e.g. starvation) is obtained by the introduction of a simple non linear
term in the equation so that

                            dP (t)
                                   = kP (t)(1 − bP (t)) .                       (3.2)
                             dt
The parameter k gives the maximum growth rate of the population and
b controls the ability of the species to maintain a certain population level.
The equation (3.2) can be discretized in time by assuming that each gen-
eration reproduces every δt and that the n-th generation has population
Pn = P (tn ) where tn = t0 + (n − 1)δt. Then P (tn+1 ) ≈ P (tn ) + δtP ′ (tn ) and
equation (3.1) becomes
                                 Pn+1 = rPn ,                                 (3.3)
where r = 1 + kδt. The solutions of the above equation are well ap-
proximated by Pn ∼ P0 ektn ∝ e(r−1)n so that we have population growth
when r > 1 and decline when r < 1. Equation (3.2) can be discretized
as follows:
                          Pn+1 = Pn (r − bPn ) .                  (3.4)
Defining xn = (b/r)Pn we obtain the logistic map

                                xn+1 = rxn (1 − xn ) .                          (3.5)

We define the functions

                  f (x) = rx(1 − x),          F (x, r) = rx(1 − x)              (3.6)

(their only difference is that, in the first one, r is considered as a given
parameter), so that

       xn+1 = f (xn ) = f (2) (xn−1 ) = . . . = f (n) (x1 ) = f (n+1) (x0 ) ,   (3.7)

where we use the notation f (1) (x) = f (x), f (2) (x) = f (f (x)), f (3) (x) =
f (f (f (x))), . . . for function composition. In what follows, the derivative
of f will be useful:

                                      ∂F (x, r)
                          f ′ (x) =             = r(1 − 2x) .                   (3.8)
                                        ∂x
3.2. FIXED POINTS AND 2N CYCLES                                                139

    Since we interpret xn to be the fraction of the population with respect
to its maximum value, we should have 0 ≤ xn ≤ 1 for each¹ n. The
function f (x) has one global maximum for x = 1/2 which is equal to
f (1/2) = r/4. Therefore, if r > 4, then f (1/2) > 1, which for an appro-
priate choice of x0 will lead to xn+1 = f (xn ) > 1 for some value of n.
Therefore, the interval of values of r which is of interest for our model
is
                                 0 < r ≤ 4.                           (3.9)
    The logistic map (3.5) may be viewed as a finite difference equation
and it is a one step inductive relation. Given an initial value x0 , a sequence
of values {x0 , x1 , . . . , xn , . . . } is produced. This will be referred² to as
the trajectory of x0 . In the following sections we will study the properties
of these trajectories as a function of the parameter r.
    The solutions of the logistic map are not known except in special
cases. For r = 2 we have
                                   1(                )
                            xn =      1 − (1 − x0 )2n ,                      (3.10)
                                   2
and for³ r = 4
                                                 1      √
                    xn = sin2 (2n πθ) ,     θ=     sin−1 x0 .                (3.11)
                                                 π
For r = 2, limn→∞ xn = 1/2 whereas for r = 4 we have periodic trajectories
resulting in rational θ and non periodic resulting in irrational θ. For other
values of r we have to resort to a numerical computation of the trajectories
of the logistic map.


3.2 Fixed Points and 2n Cycles
It is obvious that if the point x∗ is a solution of the equation x = f (x), then
xn = x∗ ⇒ xn+k = x∗ for every k ≥ 0. For the function f (x) = rx(1 − x)
we have two solutions

                       x∗1 = 0      and      x∗2 = 1 − 1/r .                 (3.12)
   ¹Note that if xn > 1 then xn+1 < 0, so that if we want xn ≥ 0 for each n, then we
should have xn ≤ 1 for each n.
   ²In the bibliography, the term “splinter of x0 ” is frequently used.
   ³E. Schröder, “Über iterierte Funktionen”, Math. Ann. 3 (1870) 296; E. Lorenz,
“The problem of deducing the climate from the governing equations”, Tellus 16 (1964)
1
140                                              CHAPTER 3. LOGISTIC MAP

We will see that for appropriate values of r, these solutions are attractors
of most of the trajectories. This means that for a range of values for the
initial point 0 ≤ x0 ≤ 1, the sequence {xn } approaches asymptotically one
of these points as n → ∞. Obviously the (measure zero) sets of initial
values {x0 } = {x∗1 } and {x0 } = {x∗2 } result in trajectories attracted by x∗1
and x∗2 respectively. In order to determine which one of the two values
is preferred, we need to study the stability of the fixed points x∗1 and x∗2 .
For this, assume that for some value of n, xn is infinitesimally close to
the fixed point x∗ so that

                                  xn = x∗ + ϵn
                                xn+1 = x∗ + ϵn+1 .                                (3.13)

Since

   xn+1 = f (xn ) = f (x∗ + ϵn ) ≈ f (x∗ ) + ϵn f ′ (x∗ ) = x∗ + ϵn f ′ (x∗ ) ,   (3.14)

where we used the Taylor expansion of the analytic function f (x∗ + ϵn )
about x∗ and the relation x∗ = f (x∗ ), we have that ϵn+1 = ϵn f ′ (x∗ ). Then
we obtain
                             ϵn+1
                                   = |f ′ (x∗ )| .                       (3.15)
                              ϵn
Therefore, if |f ′ (x∗ )| < 1 we obtain limn→∞ ϵn = 0 and the fixed point x∗ is
stable: the sequence {xn+k } approaches x∗ asymptotically. If |f ′ (x∗ )| > 1
then the sequence {xn+k } deviates away from x∗ and the fixed point is
unstable. The limiting case |f ′ (x∗ )| = 1 should be studied separately and
it indicates a change in the stability properties of the fixed point. In the
following discussion, these points will be shown to be bifurcation points.
    For the function f (x) = rx(1 − x) with f ′ (x) = r(1 − 2x) we have that
f (0) = r and f ′ (1 − 1/r) = 2 − r. Therefore, if r < 1 the point x∗1 = 0
  ′

is an attractor, whereas the point x∗2 = 1 − 1/r < 0 is irrelevant. When
r > 1, the point x∗1 = 0 results in |f ′ (x∗1 )| = r > 1, therefore x∗1 is unstable.
Any initial value x0 near x∗1 deviates from it. Since for 1 < r < 3 we have
that 0 ≤ |f ′ (x∗2 )| = |2 − r| < 1, the point x∗2 is an attractor. Any initial
value x0 ∈ (0, 1) approaches x∗2 = 1 − 1/r. When r = rc = 1 we have the
                                                               (1)

limiting case x∗1 = x∗2 = 0 and we say that at the critical value rc = 1 the
                                                                           (1)

fixed point x∗1 bifurcates to the two fixed points x∗1 and x∗2 .
    As r increases, the fixed points continue to bifurcate. Indeed, when
r = rc = 3 we have that f ′ (x∗2 ) = 2 − r = −1 and for r > rc the point
      (2)                                                              (2)

x∗2 becomes unstable. Consider the solution of the equation x = f (2) (x).
If 0 < x∗ < 1 is one of its solutions and for some n we have that xn = x∗ ,
3.2. FIXED POINTS AND 2N CYCLES                                                                       141

then xn+2 = xn+4 = . . . = xn+2k = . . . = x∗ and xn+1 = xn+3 = . . . =
xn+2k+1 = . . . = f (x∗ ) (therefore f (x∗ ) is also a solution). If 0 < x∗3 <
x∗4 < 1 are two such different solutions with x∗3 = f (x∗4 ), x∗4 = f (x∗3 ), then
the trajectory is periodic with period 2. The points x∗3 , x∗4 are such that
they are real solutions of the equation

                        f (2) (x) = r2 x(1 − x)(1 − rx(1 − x)) = x ,                               (3.16)

and at the same time they are not the solutions x∗1 = 0 x∗2 = 1 − 1/r of the
equation⁴ x = f (2) (x), the polynomial above can be written in the form
(see [24] for more details)
                     (     (      ))
                                1
                 x x− 1−             (Ax2 + Bx + C) = 0 .             (3.17)
                                r

By expanding the polynomials (3.16), (3.17) and comparing their coef-
ficients we conclude that A = −r3 , B = r2 (r + 1) and C = −r(r + 1).
The roots of the trinomial in (3.17) are determined by the discriminant
∆ = r2 (r + 1)(r − 3). For the values of r of interest (1 < r ≤ 4), the dis-
                                        (2)
criminant becomes positive when r > rc = 3 and we have two different
solutions
                             √
             x∗α = ((r + 1) ∓ r2 − 2r − 3)/(2r)      α = 3, 4 .       (3.18)
                 (2)
When r = rc we have one double root, therefore a unique fixed point.
     The study of the stability of the solutions of x = f (2) (x) requires
the same steps that led to the equation (3.15) and we determine if the
absolute value of f (2)′ (x) is greater, less or equal to one. By noting
that⁵ f (2)′ (x3 ) = f (2)′ (x4 ) = f ′ (x3 )f ′ (x4 ) = −r2 + 2r + 4, we see that for
                                                                         √
r = rc = 3, f (2)′ (x∗3 ) = f (2)′ (x∗4 ) = 1 and for r = rc = 1 + 6 ≈ √
        (2)                                                     (3)
                                                                               3.4495,
f (x3 ) =f (x4 ) = −1. For the intermediate values 3 < r < 1 + 6 the
  (2)′            (2)′

derivatives |f (2)′ (x∗α )| < 1 for α = 3, 4. Therefore, these points are stable
solutions of x = f (2) (x) and the points x∗1 , x∗2 bifurcate to x∗α , α = 1, 2, 3, 4
              (2)
for r = rc = 3. Almost all trajectories with initial points in the interval
[0, 1] are attracted by the periodic trajectory with period 2, the “2-cycle”
{x∗3 , x∗4 }.
    ⁴Because, if x∗ = f (x∗ ) ⇒ f (2) (x∗ ) = f (f (x∗ )) = f (x∗ ) = x∗ etc, the point x∗ is also
a solution of x∗ = f (n) (x∗ ).
    ⁵The chain rule dh(g(x))/dx = h′ (g(x))g ′ (x) gives that f (2)′ (x∗3 ) = df (f (x∗3 ))/dx =
f (f (x∗3 ))f ′ (x∗3 ) = f ′ (x∗4 )f ′ (x∗3 ) and similarly for f (2)′ (x∗4 ). We can prove by induction
  ′

that for the n solutions x∗n+1 , x∗n+2 , . . . , x∗2n that belong to the n-cycle of the equation x =
f (n) (x) we have that f (n)′ (xn+i ) = f ′ (xn+1 ) f ′ (xn+2 ) . . . f ′ (x2n ) for every i = 1, . . . , n.
142                                                            CHAPTER 3. LOGISTIC MAP

    Using similar arguments we find that the fixed points x∗α , α = 1, 2, 3, 4
                                                                           √
bifurcate to the eight fixed points x∗α , α = 1, . . . , 8 when r = rc = 1 + 6.
                                                                    (3)

These are real solutions of the equation that gives the 4-cycle x = f (4) (x).
For rc < r < rc ≈ 3.5441, the points x∗α , α = 5, . . . , 8 are a stable 4-
      (3)           (4)

cycle which is an attractor of almost all trajectories of the logistic map⁶.
                (4)       (5)
Similarly, for rc < r < rc the 16 fixed points of the equation x = f (8) (x)
                              (5)           (6)
give a stable 8-cycle, for rc < r < rc a stable 16-cycle etc⁷. This
is the phenomenon which is called period doubling which continues ad
                         (n)
infinitum. The points rc are getting closer to each other as n increases
                   (n)
so that limn→∞ rc = rc ≈ 3.56994567. As we will see, rc marks the onset
of the non-periodic, chaotic behavior of the trajectories of the logistic
map.

                                                             0.9
      0.14
                                                             0.8
      0.12
                                                             0.7
       0.1
                                                             0.6
      0.08
                                                             0.5
      0.06                                                   0.4
      0.04                                   r= 0.5          0.3
                                            r= 0.99
      0.02                                 r= 1/0.9          0.2
                                          r= 1/0.88
                                          r= 1/0.86
        0                                                    0.1
             0   20   40   60   80 100 120 140 160 180 200         0     10   20   30   40   50



Figure 3.1: (Left) Some trajectories of the logistic map with x0 = 0.1 and various
values of r. We can see the first bifurcation for rc = 1 from x∗1 = 0 to x∗2 = 1 − 1/r.
                                                                   (1)
                                              (2)             (3)
(Right) Trajectories of the logistic map for rc < r = 3.5 < rc . The three curves start
from three different initial points. After a transient period, depending on the initial
point, one obtains a periodic trajectory
                                    √    which is a 2-cycle. The horizontal lines are the
expected values x∗3,4 = ((r + 1) ∓ r2 − 2r − 3)/(2r) (see text).



   Computing the bifurcation points becomes quickly intractable and we
have to resort to a numerical computation of their values. Initially we will
write a program that computes trajectories of the logistic map for chosen
values of r and x0 . The program can be found in the file logistic.cpp
and is listed below:

    ⁶The points x∗α , α = 1, . . . , 4 are unstable fixed points and 2-cycle.
                      (n)               (n+1)
    ⁷Generally, for rc < r < rc               < rc ≈ 3.56994567 we have 2n fixed points of
                        n−1
the equation x = f (2 ) (x) and stable 2n−1 -cycles, which are attractors of almost all
trajectories.
3.2. FIXED POINTS AND 2N CYCLES                                           143


# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

i n t main ( ) {
    int         NSTEPS , i ;
    double r , x0 , x1 ;
    string buf ;
    / / −−−−− Input :
    cout << ” # Enter NSTEPS , r , x0 : \ n” ;
    cin >> NSTEPS             >> r >> x0 ; getline ( cin , buf ) ;
    cout << ” # NSTEPS = ” << NSTEPS << endl ;
    cout << ” # r               = ” << r   << endl ;
    cout << ” # x0              = ” << x0  << endl ;
    / / −−−−− I n i t i a l i z e :
    ofstream myfile ( ” l o g . dat ” ) ;
    myfile . precision ( 1 7 ) ;
    / / −−−−− C a l c u l a t e :
    myfile << 0 << x0 ;
    f o r ( i =1; i<=NSTEPS ; i++){
        x1 = r * x0 * (1.0 − x0 ) ;
        myfile << i << ” ” << x1 << ”\n” ;
        x0 = x1 ;
    }
    myfile . close ( ) ;
} / / main ( )

The program is compiled and run using the commands:

> g++ logistic . cpp −o l
> echo ” 100 0.5 0 . 1 ” | . / l

The command echo prints to the stdout the values of the parameters
NSTEPS=100, r=0.5 and x0=0.1. Its stdout is redirected to the stdin
of the command ./l by using a pipe via the symbol |, from which the
program reads their value and uses them in the calculation. The results
can be found in two columns in the file log.dat and can be plotted
using gnuplot. The plots are put in figure 3.1 and we can see the first
                                                 (1)       (2)
two bifurcations when r goes past the values rc and rc . Similarly, we
                                                                       (n−1)
can study trajectories which are 2n -cycles when r crosses the values rc     .

    Another way to depict the 2-cycles is by constructing the cobweb plots:
144                                               CHAPTER 3. LOGISTIC MAP

         0.7                                        0.8

         0.6                                        0.7

         0.5                                        0.6

                                                    0.5
         0.4
                                                    0.4
         0.3
                                                    0.3
         0.2
                                                    0.2
         0.1                                        0.1

          0                                           0
               0   0.2   0.4   0.6   0.8   1              0   0.2   0.4   0.6   0.8   1



Figure 3.2: Cobweb plots of the logistic map for r = 2.8 and 3.3. (Left) The left plot
is an example of a fixed point x∗ = f (x∗ ). The green line is y = f (x) and the blue line
is y = f (2) (x). The trajectory ends at the unique non zero intersection of the diagonal
and y = f (x) which is x∗2 = 1 − 1/r. The trajectory intersects the curve y = f (2) (x) at
the same point. y = f (2) (x) does not intersect the diagonal anywhere else. (Right) The
right plot shows an example of a 2-cycle. y = f (2) (x) intersects the diagonal at two
additional points determined by x∗3 and x∗4 . The trajectory ends up on the orthogonal
(x∗3 , x∗3 ), (x∗4 , x∗3 ), (x∗4 , x∗4 ), (x∗3 , x∗4 ).




We start from the point (x0 , 0) and we calculate the point (x0 , x1 ), where
x1 = f (x0 ). This point belongs on the curve y = f (x). The point (x0 , x1 ) is
then projected on the diagonal y = x and we obtain the point (x1 , x1 ). We
repeat n times obtaining the points (xn , xn+1 ) and (xn+1 , xn+1 ) on y = f (x)
and y = x respectively. The fixed points x∗ = f (x∗ ) are at the intersections
of these curves and, if they are attractors, the trajectories will converge
on them. If we have a 2n -cycle, we will observe a periodic trajectory
                                                                          n
going through points which are solutions to the equation x = f (2 ) (x).
This exercise can be done by using the following program, which can be
found in the file logistic1.cpp:

/ / ===========================================================
/ / D i s c r e t e L o g i s t i c Map : Cobweb diagram
/ / Map t h e t r a j e c t o r y i n 2d s pace ( plane )
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

i n t main ( ) {
3.2. FIXED POINTS AND 2N CYCLES                                                            145

                                                    0.9
         0.8
                                                    0.8
         0.7
                                                    0.7
         0.6
                                                    0.6
         0.5
                                                    0.5
         0.4                                        0.4
         0.3                                        0.3
         0.2                                        0.2
         0.1                                        0.1
          0                                          0
               0   0.2   0.4   0.6   0.8   1              0   0.2    0.4   0.6   0.8   1



Figure 3.3: (Left) A 4-cycle for r = 3.5. The blue curve is y = f (4) (x) which
intersects the diagonal at four points determined by xα , α = 5, 6, 7, 8. The four cycle
passes through these points. (Right) a non periodic orbit for r = 3.7 when the system
exhibits chaotic behavior.



    int         NSTEPS , i ;
    double r , x0 , x1 ;
    string buf ;
    / / −−−−− Input :
    cout << ” # Enter NSTEPS , r , x0 : \ n” ;
    cin >> NSTEPS             >> r >> x0 ;          getline ( cin , buf ) ;
    cout << ” # NSTEPS = ” << NSTEPS                << endl ;
    cout << ” # r               = ” << r            << endl ;
    cout << ” # x0              = ” << x0           << endl ;
    / / −−−−− I n i t i a l i z e :
    ofstream myfile ( ” t r j . dat ” ) ;
    myfile . precision ( 1 7 ) ;
    / / −−−−− C a l c u l a t e :
    myfile         << 0         << ” ” << x0 << ”   ” << 0          << ’\n ’ ;
    f o r ( i =1; i<=NSTEPS ; i++){
        x1 = r * x0 * (1.0 − x0 ) ;
        myfile << 2* i−3 << ” ” << x0 << ”          ” << x1 << ’\n ’ ;
        myfile << 2* i−2 << ” ” << x1 << ”          ” << x1 << ’\n ’ ;
        x0 = x1 ;
    }
    myfile . close ( ) ;
} / / main ( )

    Compiling and running this program is done exactly as in the case
of the program in logistic.cpp. We can plot the results using gnuplot.
The plot in figure 3.2 can be constructed using the commands:

gnuplot > s e t s i z e square
gnuplot > f ( x ) = r * x *(1.0 − x )
146                                            CHAPTER 3. LOGISTIC MAP

gnuplot > r = 3.3
gnuplot > p l o t ”<echo 50 3.3 0 . 2 | . / l ; c a t t r j . dat ” using 2:3 w l
gnuplot > r e p l o t f ( x ) , f ( f ( x ) ) , x

The plot command shown above, runs the program exactly as it is done
on the command line. This is accomplished by using the symbol <,
which reads the plot from the stdout of the command "echo 50 3.3
0.2|./l;cat trj.dat". Only the second command "echo trj.dat"
writes to the stdout, therefore the plot is constructed from the contents of
the file trj.dat. The following line adds the plots of the functions f (x),
f (2) (x) = f (f (x)) and of the diagonal y = x. Figures 3.2 and 3.3 show
examples of attractors which are fixed points, 2-cycles and 4-cycles. An
example of a non periodic trajectory is also shown, which exhibits chaotic
behavior which can happen when r > rc ≈ 3.56994567.


3.3 Bifurcation Diagrams
The bifurcations of the fixed points of the logistic map discussed in the
previous section can be conveniently shown on the “bifurcation diagram”.
We remind to the reader that the first bifurcations happen at the critical
values of r
                   rc(1) < rc(2) < rc(3) < . . . < rc(n) < . . . < rc ,     (3.19)
            (1)   (2)         (3)         √                             (n)
where rc = 1, rc = 3, rc = 1 + 6 and rc = limn→∞ rc ≈ 3.56994567.
                          we have 2n fixed points x∗α , α = 1, 2, ..., 2n of x =
        (n)       (n+1)
For rc < r < rc
f (x). By plotting these points x∗α (r) as a function of r we construct the
  (2n )

bifurcation diagram. These can be calculated numerically by using the
program bifurcate.cpp. In this program, the user selects the values of
r that she needs to study and for each one of them the program records
the point of the 2n−1 -cycles⁸ x∗α (r), α = 2n−1 + 1, 2n−1 + 2, . . . , 2n . This
is easily done by computing the logistic map several times until we are
sure that the trajectories reach the stable state. The parameter NTRANS
in the program determines the number of points that we throw away,
which should contain all the transient behavior. After NTRANS steps, the
program records NSTEPS points, where NSTEPS should be large enough
to cover all the points of the 2n−1 -cycles or depict a dense enough set of
values of the non periodic orbits. The program is listed below:

   ⁸If we want to be more precise, the bifurcation diagram contains also the unstable
points. What we really construct is the orbit diagram which contains only the stable
points.
3.3. BIFURCATION DIAGRAMS                                                                147


/ / ===========================================================
/ / B i f u r c a t i o n Diagram o f t h e L o g i s t i c Map
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

i n t main ( ) {
    c o n s t double rmin       =   2.5;
    c o n s t double rmax       =   4.0;
    c o n s t double NTRANS     =   500;    / / Number o f d i s c a r t e d s t e p s
    c o n s t double NSTEPS     =   100;    / / Number o f recorded s t e p s
    c o n s t double RSTEPS     =   2000;   / / Number o f v a l u e s o f r
    int i;
    double r , dr , x0 , x1 ;

    / / −−−−−− I n i t i a l i z e :
    dr           = ( rmax−rmin ) / RSTEPS ; / / Increment i n r
    ofstream myfile ( ” b i f . dat ” ) ;
    myfile . precision ( 1 7 ) ;
    / / −−−−−− C a l c u l a t e :
    r            = rmin ;
    while ( r <= rmax ) {
        x0       = 0.5;
        / / −−−− T r a n s i e n t s t e p s : s k i p
        f o r ( i =1; i<=NTRANS ; i++){
            x1 = r * x0 * (1.0 − x0 ) ;
            x0 = x1 ;
        }
        f o r ( i =1; i<=NSTEPS ; i++){
            x1 = r * x0 * (1.0 − x0 ) ;
            myfile << r << ” ” << x1 << ’\n ’ ;
            x0 = x1 ;
        }
        r += dr ;
    } / / while ( r <= rmax )
    myfile . close ( ) ;
} / / main ( )

   The program can be compiled and run using the commands:

> g++ bifurcate . cpp −o b
> ./ b;

The left plot of figure 3.4 can be constructed by the gnuplot commands:
148                                                               CHAPTER 3. LOGISTIC MAP

       1
                                                               0.52
      0.9
      0.8                                                     0.515

      0.7                                                      0.51

      0.6                                                     0.505
      0.5
                                                                0.5
      0.4
                                                              0.495
      0.3
                                                               0.49
      0.2
                                                              0.485
      0.1
       0                                                       0.48
            2.4   2.6   2.8   3   3.2   3.4   3.6   3.8   4      3.6295 3.63 3.6305 3.631 3.6315 3.632 3.6325 3.633 3.6335 3.634




Figure 3.4: (Left) The bifurcation diagram computed by the program bifurcate.cpp
for 2.5 < r < 4. Notice the first bifurcation points followed by intervals of chaotic, non-
periodic orbits interrupted by intermissions of stable periodic trajectories. The chaotic
trajectories take values in subsets of the interval √
                                                    (0, 1). For r = 4 they take values within
the whole (0, 1). One can see that for r = 1 + 8 ≈ 3.8284 we obtain a 3-cycle which
subsequently bifurcates to 3 · 2n -cycles. (Right) The diagram on the left is magnified in
a range of r showing the self-similarity of the diagram at all scales.




gnuplot > p l o t ” b i f . dat ” with dots

   We observe the fixed points and the 2n -cycles for r < rc . When r goes
past rc , the trajectories become non-periodic and exhibit chaotic behavior.
Chaotic behavior will be discussed more extensively in the next section.
For the time being, we note that if we measure the distance between the
                   (n+1)     (n)
points ∆r(n) = rc        − rc , we find that it decreases constantly with n so
that
                                ∆r(n)
                         lim          = δ ≈ 4.669 201 609 ,            (3.20)
                        n→∞ ∆r (n+1)

where δ is the Feigenbaum constant. An additional constant α, defined
by the quotient of the separation of adjacent elements ∆wn of period
doubled attractors from one double to the next ∆wn+1 , is
                                        ∆wn
                                    lim      = α ≈ 2.502 907 875 .                                                        (3.21)
                                   n→∞ ∆wn+1


It is √also interesting to note the appearance of a 3-cycle right after r =
1 + 8 ≈ 3.8284 > rc ! By using the theorem of Sharkovskii, Li and
Yorke⁹ showed that any one dimensional system has 3-cycles, therefore
it will have cycles of any length and chaotic trajectories. The stability of
   ⁹T.Y. Li, J.A. Yorke, “Period Three Implies Chaos”, American Mathematical Monthly
82 (1975) 985.
3.3. BIFURCATION DIAGRAMS                                                             149

the 3-cycle can be studied from the solutions of x = f (3) (x) in exactly the
same way that we did in equations (3.16) and (3.17) (see [24] for details).
Figure 3.5 magnifies a branch of the 3-cycle. By magnifying different
regions in the bifurcation plot, as shown in the right plot of figure 3.4, we
find similar shapes to the branching of the 3-cycle. Figure 3.4 shows that


                          0.52

                          0.51

                           0.5

                          0.49

                          0.48

                          0.47

                          0.46
                                 3.83   3.835   3.84   3.845   3.85

                                                                                       √
Figure 3.5: Magnification of one of the three branches of the 3-cycle for r > 1 + 8.
To the left, we observe the temporary halt of the chaotic behavior of the trajectory, which
comes back as shown in the plot to the right after an intermission of stable periodic
trajectories.



between intervals of chaotic behavior we obtain “windows” of periodic
trajectories. These are infinite but countable. It is also quite interesting
to note that if we magnify a branch withing these windows, we obtain a
diagram that is similar to the whole diagram! We say that the bifurcation
diagram exhibits self similarity. There are more interesting properties of
the bifurcation diagram and we refer the reader to the bibliography for
a more complete exposition.
    We close this section by mentioning that the qualitative properties
of the bifurcation diagram are the same for a whole class of functions.
Feigenbaum discovered that if one takes any function that is concave and
has a unique global maximum, its bifurcation diagram behaves qualita-
tively the same way as that of the logistic map. Examples of such func-
tions¹⁰ studied in the literature are g(x) = xer(1−x) , u(x) = r sin(πx) and
w(x) = b − x2 . The constants δ and α of equations (3.20) and (3.21)
are the same of all these mappings. The functions that result in chaotic
behavior are studied extensively in the literature and you can find a list
of those in [30].
   ¹⁰ The function x exp(r(1 − x)) has been used as a model for populations whose large
density is restricted by epidemics. The populations are always positive independently
of the (positive) initial conditions and the value of r.
150                                           CHAPTER 3. LOGISTIC MAP

3.4 The Newton-Raphson Method
In order to determine the bifurcation points, one has to solve the nonlin-
ear, polynomial, algebraic equations x = f (n) (x) and f (n)′ (x) = −1. For
this reason, one has to use an approximate numerical calculation of the
roots, and the simple Newton-Raphson method will prove to be a good
choice.
    Newton-Raphson’s method uses an initial guess x0 for the solution of
the equation g(x) = 0 and computes a sequence of points x1 , x2 , . . . , xn ,
xn+1 , . . . that presumably converges to one of the roots of the equation.
The computation stops at a finite n, when we decide that the desired level
of accuracy has been achieved. In order to understand how it works, we
assume that g(x) is an analytic function for all the values of x used in
the computation. Then, by Taylor expanding around xn we obtain
                 g(xn+1 ) = g(xn ) + (xn+1 − xn )g ′ (x) + . . . .       (3.22)
If we wish to have g(xn+1 ) ≈ 0, we choose
                                            g(xn )
                             xn+1 = xn −              .                  (3.23)
                                            g ′ (xn )
The equation above gives the Newton-Raphson method for one equation
g(x) = 0 of one variable x. Different choices for x0 will possibly lead to
different roots. When g ′ (x), g ′′ (x) are non zero at the root and g ′′′ (x) is
bounded, the convergence of the method is quadratic with the number
of iterations. This means that there is a neighborhood of the root α such
that the distance ∆xn+1 = xn+1 − α is ∆xn+1 ∝ (∆xn )2 . If the root α
has multiplicity larger than 1, convergence is slower. The proofs of these
statements are simple and can be found in [31].
      The Newton-Raphson method is simple to program and, most of the
times, sufficient for the solution of many problems. In the general case
it works well only close enough to a root. We should also keep in mind
that there are simple reasons for the method to fail. For example, when
g ′ (xn ) = 0 for some n, the method stops. For functions that tend to
0 as x → ±∞, it is easy to make a bad choice for x0 that does not
lead to convergence to a root. Sometimes it is a good idea to combine the
Newton-Raphson method with the bisection method. When the derivative
g ′ (x) diverges at the root we might get into trouble. For example, the
equation |x|ν = 0 with 0 < ν < 1/2, does not lead to a convergent
sequence. In some cases, we might enter into non-convergent cycles [8].
For some functions the basin of attraction of a root (the values of x0 that
will converge to the root) can be tiny. See problem 13.
3.4. THE NEWTON-RAPHSON METHOD                                         151

   As a test case of our program, consider the equation
                                     √
                            ϵ tan ϵ = ρ2 − ϵ2                       (3.24)

which results from the solution of Schrödinger’s equation for the en-
ergy spectrum of a quantum mechanical particle of mass m in a one
dimensional
    √        potential well √
                            of depth V0 and width L. The parameters
ϵ = mL2 E/(2ℏ) and ρ = mL2 V0 /(2ℏ). Given ρ, we solve for ϵ which
gives the energy E. The function g(x) and its derivative g ′ (x) are
                                     √
                  g(x) = x tan x − ρ2 − x2
                                x        x
                 g ′ (x) = √         +        + tan x .              (3.25)
                              ρ2 − x2 cos2 x

The program of the Newton-Raphson method for solving the equation
g(x) = 0 can be found in the file nr.cpp:

/ / ===========================================================
/ / Newton Raphson o f f u n c t i o n o f one v a r i a b l e
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

i n t main ( ) {
    c o n s t double rho = 1 5 . 0 ;
    c o n s t double eps = 1 . 0 e−6;
    const int         NMAX = 1000;
    double x0 , x1 , err , g , gp ;
    int        i;
    string buf ;
    / / −−−−− Input :
    cout << ” # Enter x0 : \ n” ;
    cin >> x0 ;         getline ( cin , buf ) ;
    err = 1 . 0 ;
    cout << ” i t e r              x                error   \n” ;
    cout << ”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\n” ;
    cout << 0       << ” ”    << x0       << ” ” << err << ’\n ’ ;

  cout . precision ( 1 7 ) ;
  f o r ( i =1; i<=NMAX ; i++){
      / / value of function g ( x ) :
      g      = x0 * tan ( x0 )−sqrt ( rho * rho−x0 * x0 ) ;
152                                                    CHAPTER 3. LOGISTIC MAP

      / / value of the d e r i v a t i v e g ’( x ) :
      gp = x0 / sqrt ( rho * rho−x0 * x0 )+x0 / ( cos ( x0 ) * cos ( x0 ) )+tan ( x0 ) ;
      x1 = x0 − g / gp ;
      err = abs ( x1−x0 ) ;
      cout << i << ” ” << x1 << ” ” << err << ’\n ’ ;
      i f ( err < eps ) break ;
      x0 = x1 ;
    }
} / / main ( )

    In the program listed above, the user is asked to set the initial point
x0 . We fix ρ = rho = 15. It is instructive to make the plot of the left and
right hand sides of (3.24) and make a graphical determination of the roots
from their intersections. Then we can make appropriate choices of the
initial point x0 . Using gnuplot, the plots are made with the commands:

gnuplot > g1 ( x ) = x * tan ( x )
gnuplot > g2 ( x ) = s q r t ( rho * rho−x * x )
gnuplot > p l o t [ 0 : 2 0 ] [ 0 : 2 0 ] g1 ( x ) , g2 ( x )


                          20



                          15



                          10



                           5

                                                            ε tanε
                                                         (ρ2-ε2)1/2
                           0
                               0        5         10         15       20
                                                  ε


Figure 3.6: Plots of the right and left hand sides of equation (3.24). The intersections
of the curves determine the solutions of the equation and their approximate graphical
estimation can serve as initial points x0 for the Newton-Raphson method.


The compilation and running of the program can be done as follows:

> g++ nr . cpp −o n
> echo ” 1 . 4 ” | . / n
# Enter x0 :
iter                   x                error
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
0 1.4                    1
3.4. THE NEWTON-RAPHSON METHOD                                                             153

1   1.5254292024457967         0.12542920244579681
2   1.5009739120496131         0.02445529039618366
3   1.48072070172022           0.02025321032939309
4   1.4731630533073483         0.0075576484128716537
5   1.4724779331237687         0.00068512018357957949
6   1.4724731072313519         4.8258924167932093e−06
7   1.4724731069952235         2.3612845012621619e−10

We conclude that one of the roots of the equation is ϵ ≈ 1.472473107.
The reader can compute more of these roots by following these steps by
herself.
    The method discussed above can be easily generalized to the case
of two equations. Suppose that we need to solve simultaneously two
algebraic equations g1 (x1 , x2 ) = 0 and g2 (x1 , x2 ) = 0. In order to compute
a sequence (x10 , x20 ), (x11 , x21 ), . . ., (x1n , x2n ), (x1(n+1) , x2(n+1) ), . . . that may
converge to a root of the above system of equations, we Taylor expand
the two functions around (x1n , x2n )
                                                                   ∂g1 (x1n , x2n )
      g1 (x1(n+1) , x2(n+1) ) = g1 (x1n , x2n ) + (x1(n+1) − x1n )
                                                                         ∂x1
                                                       ∂g1 (x1n , x2n )
                                + (x2(n+1) − x2n )                      + ...
                                                            ∂x2
                                                                   ∂g2 (x1n , x2n )
      g2 (x1(n+1) , x2(n+1) ) = g2 (x1n , x2n ) + (x1(n+1) − x1n )
                                                                         ∂x1
                                                       ∂g2 (x1n , x2n )
                                + (x2(n+1) − x2n )                      + . . . . (3.26)
                                                            ∂x2
Defining δx1 = (x1(n+1) − x1n ) and δx2 = (x2(n+1) − x2n ) and setting
g1 (x1(n+1) , x2(n+1) ) ≈ 0, g2 (x1(n+1) , x2(n+1) ) ≈ 0, we obtain
                                  ∂g1       ∂g1
                              δx1     + δx2     = −g1
                                  ∂x1       ∂x2
                                  ∂g2       ∂g2
                              δx1     + δx2     = −g2 .                                 (3.27)
                                  ∂x1       ∂x2
This is a linear 2 × 2 system of equations
                                A11 δx1 + A12 δx2 = b1
                                A21 δx1 + A22 δx2 = b2 ,                               (3.28)
where Aij = ∂gi /∂xj and bi = −gi , with i, j = 1, 2. Solving for δxi we
obtain
                                 x1(n+1) = x1n + δx1
                                 x2(n+1) = x2n + δx2 .                                 (3.29)
154                                              CHAPTER 3. LOGISTIC MAP

The iterations stop when δxi become small enough.

    As an example, consider the equations with g1 (x) = 2x2 − 3xy + y − 2,
g2 (x) = 3x + xy + y − 1. We have A11 = 4x − 3y, A12 = 1 − 3x, A21 = 3 + y,
A22 = 1 + x. The program can be found in the file nr2.cpp:

/ / ===========================================================
/ / Newton Raphson o f two f u n c t i o n s o f two v a r i a b l e s
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

void solve2x2 ( double A [ 2 ] [ 2 ] , double b [ 2 ] , double dx [ 2 ] ) ;

i n t main ( ) {
    c o n s t double eps = 1 . 0 e−6;
    const int         NMAX = 1000;
    double A [ 2 ] [ 2 ] , b [ 2 ] , dx [ 2 ] ;
    double x , y , err ;
    int        i;
    string buf ;
    / / −−−−− Input :
    cout << ” # Enter x0 , y0 : \ n” ;
    cin >> x >> y ;               getline ( cin , buf ) ;
    err = 1 . 0 ;
    cout << ” i t e r                x             y      error   \n” ;
    cout << ”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\n” ;
    cout << 0 << ” ” << x << ” ” << y << ” ” <<           err << ’\n ’ ;

  cout . precision ( 1 7 ) ;
  f o r ( i =1; i<=NMAX ; i++){
      b [ 0 ] = −(2.0* x * x −3.0* x * y + y − 2 . 0 ) ; / / −g1 ( x , y )
      b [ 1 ] = −(3.0* x +               x * y + y − 1 . 0 ) ; / / −g2 ( x , y )
      / / dg1 / dx                                    dg1 / dy
      A [ 0 ] [ 0 ] = 4 . 0 * x −3.0* y ; A [ 0 ] [ 1 ] = 1.0 −3.0* x ;
      / / dg2 / dx                                    dg2 / dy
      A [ 1 ] [ 0 ] = 3.0 +           y ; A [ 1 ] [ 1 ] = 1.0+           x;
      solve2x2 ( A , b , dx ) ;
      x += dx [ 0 ] ;
      y += dx [ 1 ] ;
      err = 0 . 5 * sqrt ( dx [ 0 ] * dx [ 0 ] + dx [ 1 ] * dx [ 1 ] ) ;
      cout << i << ” ” << x << ” ” << y << ” ” << err << endl ;
      i f ( err < eps ) break ;
  }
3.4. THE NEWTON-RAPHSON METHOD                                                        155

} / / main ( )
void solve2x2 ( double A [ 2 ] [ 2 ] , double b [ 2 ] , double dx [ 2 ] ) {
    double num0 , num1 , det ;

  num0        = A [ 1 ] [ 1 ] * b[0]       − A[0][1] * b [1];
  num1        = A[0][0] * b[1]             − A[1][0] * b[0];
  det         = A[0][0] * A [1][1] − A [0][1] * A [1][0];
  i f ( det   == 0 . 0 ) { cerr << ” s o l v e 2 x 2 : d e t =0\n” ; exit ( 1 ) ; }
  dx [ 0 ]    = num0 / det ;
  dx [ 1 ]    = num1 / det ;

} / / solve2x2 ( )

In order to guess the region where the real roots of the systems lie, we
make a 3-dimensional plot using gnuplot:

gnuplot > s e t i s o s a m p l e s 20
gnuplot > s e t hidden3d
gnuplot > s p l o t 2* x**2 −3*x * y+y −2 ,3* x+y * x+y −1 ,0

We plot the functions gi (x, y) together with the plane x = 0. The in-
tersection of the three surfaces determine the roots we are looking for.
Compiling and running the program can be done by using the com-
mands:

> g++ nr2 . cpp −o n
> echo 2.2 1 . 5 | . / n
# Enter x0 , y0 :
iter     x               y error
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
0 2.20000000 1.50000000 1.0000
1 0.76427104 0.26899383 0.9456
2 0.73939531 −0.68668275 0.4780
3 0.74744506 −0.71105605 1.2834 e−2
4 0.74735933 −0.71083147 1.2019 e−4
5 0.74735932 −0.71083145 1.2029 e−8
> echo 0 1 | . / n
 .................
5 −0.10899022 1.48928857 4.3461 e−12
> echo −5 0 | . / n
6 −6.13836909 −3.77845711 3.2165 e−13

The computation above leads to the roots (0.74735932, −0.71083145),
(−0.10899022, 1.48928857), (−6.13836909, −3.77845711).
   The Newton-Raphson method for many variables becomes hard quite
soon: One needs to calculate the functions as well as their derivatives,
156                                          CHAPTER 3. LOGISTIC MAP

which is prohibitively expensive for many problems. It is also hard to
determine the roots, since the method converges satisfactorily only very
close to the roots. We refer the reader to [8] for more information on
how one can deal with these problems.


3.5 Calculation of the Bifurcation Points
In order to determine the bifurcation points for r < rc we will solve
the algebraic equations x = f (k) (x) and f (k)′ (x) = −1. At these points,
k-cycles become unstable and 2k-cycles appear and are stable. This hap-
pens when r = rc , where k = 2n−2 . We will look for solutions (x∗α , rc )
                  (n)                                                  (n)

for α = k + 1, k + 2, . . . , 2k.
    We define the functions F (x, r) = f (x) = rx(1 − x) and F (k) (x, r) =
 (k)
f (x) as in equation (3.6). We will solve the algebraic equations:

                     g1 (x, r) = x − F (k) (x, r) = 0
                                 ∂F (k) (x, r)
                     g2 (x, r) =               + 1 = 0.               (3.30)
                                     ∂x
According to the discussion of the previous section, in order to calculate
the roots of these equations we have to solve the linear system (3.28),
where the coefficients are

                   b1 = −g1 (x, r) = −x + F (k) (x, r)
                                        ∂F (k) (x, r)
                   b2 = −g2 (x, r) = −                  −1
                                             ∂x
                        ∂g1 (x, r)         ∂F (k) (x, r)
                  A11 =            =1−
                           ∂x                    ∂x
                        ∂g1 (x, r)      ∂F (k) (x, r)
                  A12 =            =−
                           ∂r                ∂r
                        ∂g2 (x, r)   ∂ 2 F (k) (x, r)
                  A21 =            =
                           ∂x              ∂x2
                        ∂g2 (x, r)   ∂ 2 F (k) (x, r)
                  A22 =            =                  .               (3.31)
                           ∂r             ∂x∂r
The derivatives will be calculated approximately using finite differences

              ∂F (k) (x, r)   F (k) (x + ϵ, r) − F (k) (x − ϵ, r)
                            ≈
                  ∂x                           2ϵ
                 (k)
              ∂F (x, r)       F (x, r + ϵ) − F (k) (x, r − ϵ)
                                (k)
                            ≈                                     ,   (3.32)
                  ∂r                           2ϵ
3.5. CALCULATION OF THE BIFURCATION POINTS                                                              157

and similarly for the second derivatives
                         ∂F (k) (x+ 2ϵ ,r)          ∂F (k) (x− 2ϵ ,r)
∂ 2 F (k) (x, r)                             −
                 ≈             ∂x                         ∂x
      ∂x2                                    2 2ϵ
                               {                                                               }
                            1 F (k) (x + ϵ, r) − F (k) (x, r) F (k) (x, r) − F (k) (x − ϵ, r)
                   =                                                 −
                            ϵ                     ϵ                                    ϵ
                            1   {                                                        }
                   =              F (k)
                                        (x  + ϵ, r) − 2F    (k)
                                                                (x, r) + F (k)
                                                                               (x − ϵ, r)
                            ϵ2
                         ∂F (k) (x+ϵx ,r)      (k)
∂ 2 F (k) (x, r)                           − ∂F (x−ϵ  x ,r)

                 ≈              ∂r                 ∂r
     ∂x∂r                                 2ϵ
                              { (k) x
                          1       F (x + ϵx , r + ϵr ) − F (k) (x + ϵx , r − ϵr )
                   =
                         2ϵx                              2ϵr
                                                                                        }
                                   F (k) (x − ϵx , r + ϵr ) − F (k) (x − ϵx , r − ϵr )
                                −
                                                             2ϵr
                           1     {
                   =               F (k) (x + ϵx , r + ϵr ) − F (k) (x + ϵx , r − ϵr )
                         4ϵx ϵr
                                                                                       }
                                −F (k) (x − ϵx , r + ϵr ) + F (k) (x − ϵx , r − ϵr )       (3.33)

We are now ready to write the program for the Newton-Raphson method
like in the previous section. The only difference is the approximate cal-
culation of the derivatives using the relations above and the calculation
of the function F (k) (x, r) by a routine that will compose the function f (x)
k-times. The program can be found in the file bifurcationPoints.cpp:

/ / ===========================================================
//                b i f u r c a t i o n P o i n t s . cpp
/ / C a l c u l a t e b i f u r c a t i o n p o i n t s o f t h e d i s c r e t e l o g i s t i c map
/ / a t p e r i o d k by s o l v i n g t h e c o n d i t i o n
/ / g1 ( x , r ) = x − F( k , x , r )                 = 0
/ / g2 ( x , r ) = dF( k , x , r ) / dx+1 = 0
/ / determining when t h e Floquet m u l t i p l i e r bacomes 1
/ / F( k , x , r ) i t e r a t e s F( x , r ) = r * x * ( x−1) k t i m e s
/ / The e q u a t i o n s a r e s o l v e d by using a Newton−Raphson method
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
double F                  ( c o n s t i n t& k , c o n s t double& x , c o n s t double& r ) ;
double dFdx               ( c o n s t i n t& k , c o n s t double& x , c o n s t double& r ) ;
158                                                    CHAPTER 3. LOGISTIC MAP

double dFdr    ( c o n s t i n t& k , c o n s t double& x , c o n s t double& r ) ;
double d2Fdx2 ( c o n s t i n t& k , c o n s t double& x , c o n s t double& r ) ;
double d2Fdrdx ( c o n s t i n t& k , c o n s t double& x , c o n s t double& r ) ;
void solve2x2 ( double A [ 2 ] [ 2 ] , double b [ 2 ] , double dx [ 2 ] ) ;

i n t main ( ) {
    c o n s t double tol = 1 . 0 e −10;
    double r0 , x0 ;
    double A [ 2 ] [ 2 ] , B [ 2 ] , dX [ 2 ] ;
    double error ;
    i n t k , iter ;
    string buf ;

    / / −−−−−− Input :
    cout << ” # Enter k , r0 , x0 : \ n” ;
    cin >> k >> r0 >> x0 ;                                 getline ( cin , buf ) ;
    cout << ” # Period k= ”                                    << k << endl ;
    cout << ” # r0= ” << r0 << ” x0= ” << x0 << endl ;
    / / −−−−−− I n i t i a l i z e
    error = 1 . 0 ; / / i n i t i a l l a r g e v a l u e o f e r r o r > t o l
    iter =             0;
    cout . precision ( 1 7 ) ;
    while ( error > tol ) {
        / / −−−− C a l c u l a t e j a c o b i a n matri x
        A [ 0 ] [ 0 ] = 1 . 0 −dFdx ( k , x0 , r0 ) ;
        A [ 0 ] [ 1 ] = −dFdr              ( k , x0 , r0 ) ;
        A [ 1 ] [ 0 ] = d2Fdx2             ( k , x0 , r0 ) ;
        A [ 1 ] [ 1 ] = d2Fdrdx            ( k , x0 , r0 ) ;
        B[0]           = −x0 +           F ( k , x0 , r0 ) ;
        B[1]           = −dFdx             ( k , x0 , r0 ) −1.0;
        / / −−−− S o l v e a 2x2 l i n e a r system :
        solve2x2 ( A , B , dX ) ;
        x0           = x0 + dX [ 0 ] ;
        r0           = r0 + dX [ 1 ] ;
        error = 0 . 5 * sqrt ( dX [ 0 ] * dX [ 0 ] + dX [ 1 ] * dX [ 1 ] ) ;
        iter ++;
        cout <<iter
                    << ” x0= ” << x0
                    << ” r0= ” << r0
                    << ” e r r = ” << error << ’\n ’ ;
    } / / while ( e r r o r > t o l )
} / / main ( )
/ / ===========================================================
/ / Function F( k , x , r ) and i t s d e r i v a t i v e s
double F                  ( c o n s t i n t& k , c o n s t double& x , c o n s t double& r ) {
    double x0 ;
    int             i;
    x0 = x ;
    f o r ( i =1; i<=k ; i++) x0 = r * x0 *(1.0 − x0 ) ;
3.5. CALCULATION OF THE BIFURCATION POINTS                                                           159

    r e t u r n x0 ;
}
/ / −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double dFdx               ( c o n s t i n t& k , c o n s t double& x , c o n s t double& r ) {
    double eps ;
    eps           = 1 . 0 e−6*x ;
    r e t u r n ( F ( k , x+eps , r )−F ( k , x−eps , r ) ) / ( 2 . 0 * eps ) ;
}
/ / −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double dFdr               ( c o n s t i n t& k , c o n s t double& x , c o n s t double& r ) {
    double eps ;
    eps           = 1 . 0 e−6*r ;
    r e t u r n ( F ( k , x , r+eps )−F ( k , x , r−eps ) ) / ( 2 . 0 * eps ) ;
}
/ / −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double d2Fdx2 ( c o n s t i n t& k , c o n s t double& x , c o n s t double& r ) {
    double eps ;
    eps           = 1 . 0 e−6*x ;
    r e t u r n ( F ( k , x+eps , r ) −2.0*F ( k , x , r )+F ( k , x−eps , r ) ) / ( eps * eps ) ;
}
/ / −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double d2Fdrdx ( c o n s t i n t& k , c o n s t double& x , c o n s t double& r ) {
    double epsx , epsr ;
    epsx            = 1 . 0 e−6*x ;
    epsr            = 1 . 0 e−6*r ;
    r e t u r n ( F ( k , x+epsx , r+epsr )−F ( k , x+epsx , r−epsr )
                 −F ( k , x−epsx , r+epsr )+F ( k , x−epsx , r−epsr ) )
                  / ( 4 . 0 * epsx * epsr ) ;
}
/ / ===========================================================
void solve2x2 ( double A [ 2 ] [ 2 ] , double b [ 2 ] , double dx [ 2 ] ) {
    double num0 , num1 , det ;

    num0        = A [ 1 ] [ 1 ] * b[0]       − A[0][1] * b [1];
    num1        = A[0][0] * b[1]             − A[1][0] * b[0];
    det         = A[0][0] * A [1][1] − A [0][1] * A [1][0];
    i f ( det   == 0 . 0 ) { cerr << ” s o l v e 2 x 2 : d e t =0\n” ; exit ( 1 ) ; }
    dx [ 0 ]    = num0 / det ;
    dx [ 1 ]    = num1 / det ;

} / / solve2x2 ( )

Compiling and running the program can be done as follows:

>   g++ bifurcationPoints . cpp −o b
>   echo 2 3.5 0.5 | . / b
#   Enter k , r0 , x0 :
#   Per i od k=            2
160                                            CHAPTER 3. LOGISTIC MAP

# r0= 3.5000000000000 x0=         0.50000000000
1 x0= 0.4455758353187 r0=         3.38523275827      err=   6.35088e−2
2 x0= 0.4396562547624 r0=         3.45290970406      err=   3.39676e−2
3 x0= 0.4399593001407 r0=         3.44949859951      err=   1.71226 e−3
4 x0= 0.4399601690333 r0=         3.44948974267      err=   4.44967 e−6
5 x0= 0.4399601689937 r0=         3.44948974281      err=   7.22160 e−11
> echo 2 3.5 0.85 | . / b
 .................
4 x0= 0.8499377795512 r0=         3.44948974275 err= 1.85082e−11
> echo 4 3.5 0.5 | . / b
 .................
5 x0= 0.5235947861540 r0=         3.54409035953 err= 1.86318 e−11
> echo 4 3.5 0.35 | . / b
 .................
5 x0= 0.3632903374118 r0=         3.54409035955 err= 5.91653e−13

The above listing shows the points of the 2-cycle and some of the points
                                                                      (3)
of the 4-cycle. It is also possible to compare the calculated value rc =
                                       (3)   √
3.449490132 with the expected one rc = 1+ 6 ≈ 3.449489742. Improving
the accuracy of the calculation is left as an exercise for the reader who
has to control the systematic errors of the calculations and achieve better
                                   (4)
accuracy in the computation of rc .


3.6 Liapunov Exponents
We have seen that when r > rc ≈ 3.56994567, the trajectories of the lo-
gistic map become non periodic and exhibit chaotic behavior. Chaotic
behavior mostly means sensitivity of the evolution of a dynamical system
to the choice of initial conditions. More precisely, it means that two dif-
ferent trajectories constructed from infinitesimally close initial conditions,
diverge very fast from each other. This implies that there is a set of initial
conditions that densely cover subintervals of (0, 1) whose trajectories do
not approach arbitrarily close to any cycle of finite length.
    Assume that two trajectories have x0 , x̃0 as initial points and ∆x0 =
x0 − x̃0 . When the points xn , x̃n have a distance ∆xn = x̃n − xn that for
small enough n increases exponentially with n (the “time”), i.e.

                           ∆xn ∼ ∆x0 eλn ,         λ > 0,                     (3.34)

the system is most likely exhibiting chaotic behavior¹¹. The exponent λ
is called a Liapunov exponent. A useful equation for the calculation of λ
  ¹¹Sensitivity to the initial condition alone does not necessarily imply chaos. It is
necessary to have topological mixing and dense periodic orbits. Topological mixing
3.6. LIAPUNOV EXPONENTS                                                                   161

is
                                        1∑
                                              n−1
                                λ = lim       ln |f ′ (xk )| .                         (3.35)
                                    n→∞ n
                                          k=0

This relation can be easily proved by considering infinitesimal ϵ ≡ |∆x0 |
so that λ = lim lim n1 ln |∆xn |/ϵ. Then we obtain
                 n→∞ ϵ→0

       x̃1 = f (x̃0 ) = f (x0 + ϵ) ≈ f (x0 ) + ϵf ′ (x0 )
           = x1 + ϵf ′ (x0 ) ⇒
     ∆x1     x̃1 − x1
           =            ≈ f ′ (x0 )
      ϵ           ϵ

       x̃2 = f (x̃1 ) = f (x1 + ϵf ′ (x0 )) ≈ f (x1 ) + (ϵf ′ (x0 ))f ′ (x1 )
           = x2 + ϵf ′ (x0 )f ′ (x1 ) ⇒
     ∆x2     x̃2 − x2
           =            ≈ f ′ (x0 )f ′ (x1 )
      ϵ           ϵ

       x̃3 = f (x̃2 ) = f (x2 + ϵf ′ (x0 )f ′ (x1 )) ≈ f (x2 ) + (ϵf ′ (x0 )f ′ (x1 ))f ′ (x2 )
           = x3 + ϵf ′ (x0 )f ′ (x1 )f ′ (x2 ) ⇒
     ∆x3     x̃3 − x3
           =            ≈ f ′ (x0 )f ′ (x1 )f ′ (x2 ) .                                  (3.36)
      ϵ           ϵ
We can show by induction that |∆xn |/ϵ ≈ f ′ (x0 )f ′ (x1 )f ′ (x2 ) . . . f ′ (xn−1 )
and by taking the logarithm and the limits we can prove (3.35).
   A first attempt to calculate the Liapunov exponents could be made
by using the definition (3.34). We modify the program logistic.cpp so
that it calculates two trajectories whose initial distance is ϵ = epsilon:

/ / ===========================================================
/ / D i s c r e t e L o g i s t i c Map :
/ / Two t r a j e c t o r i e s with c l o s e i n i t i a l c o n d i t i o n s .
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;


means that every open set in phase space will evolve to a set that for large enough time
will have non zero intersection with any open set. Dense periodic orbits means that
every point in phase space lies infinitesimally close to a periodic orbit.
162                                               CHAPTER 3. LOGISTIC MAP


                1e+16
                1e+14
                1e+12
                1e+10
      |∆xn|/ε




                1e+08
                1e+06
                10000                                    ε = 10-15
                                                         ε = 10-12
                  100                                    ε = 10-10
                                                          ε = 10-8
                    1                                     ε = 10-6
                                                          ε = 10-4
                 0.01
                        0   20   40   60   80 100 120 140 160 180 200
                                                 n

Figure 3.7: A plot of |∆xn |/ϵ for the logistic map for r = 3.6, x0 = 0.2. Note the
convergence of the curves as ϵ → 0 and the approximate exponential behavior in this
limit. The two lines are fits to the equation (3.34) and give λ = 0.213(4) and λ = 0.217(6)
respectively.




i n t main ( ) {
    int      NSTEPS , i ;
    double r , x0 , x1 , x0t , x1t , epsilon ;
    string buf ;
    / / −−−−− Input :
    cout << ” # Enter NSTEPS , r , x0 , e p s i l o n : \ n” ;
    cin >> NSTEPS            >> r >> x0 >> epsilon ; getline ( cin , buf ) ;
    cout << ” # NSTEPS = ” << NSTEPS << endl ;
    cout << ” # r              = ” << r        << endl ;
    cout << ” # x0             = ” << x0       << endl ;
    cout << ” # e p s i l o n = ” << epsilon << endl ;

  x0t = x0+epsilon ;
  / / −−−−− I n i t i a l i z e :
  ofstream myfile ( ” l i a . dat ” ) ;
  myfile . precision ( 1 7 ) ;
  / / −−−−− C a l c u l a t e :
  myfile        << 1      << ” ”     << x0 << ” ” << x0t << ” ”
                << abs ( x0t−x0 ) / epsilon << ”\n” ;
  f o r ( i =2;i<=NSTEPS ; i++){
      x1 = r * x0 * (1.0 − x0 ) ;
3.6. LIAPUNOV EXPONENTS                                                 163

     x1t = r *      x0t * (1.0 − x0t ) ;
     myfile <<      i     << ” ”      << x1 << ” ” << x1t << ” ”
            <<      abs ( x1t−x1 ) / epsilon << ”\n” ;
     x0 = x1 ;      x0t = x1t ;
    }
    myfile . close ( ) ;
} / / main ( )

After running the program, the quantity |∆xn |/ϵ is found at the fourth
column of the file lia.dat. The curves of figure 3.7 can be constructed
by using the commands:

> g++ liapunov1 . cpp −o l
> gnuplot
gnuplot > s e t l o g s c a l e y
gnuplot > p l o t \
  ”<echo 200 3.6 0.2 1 e−15 | . / l ; c a t l i a . dat ” u 1 : 4 w l

The last line plots the stdout of the command "echo 200 3.6 0.2 1e-15
|./l;cat lia.dat", i.e. the contents of the file lia.dat produced after
running our program using the parameters NSTEPS = 200, r = 3.6, x0
= 0.2 and epsilon = 10−15 . The gnuplot command set logscale y,
puts the y axis in a logarithmic scale. Therefore an exponential function
is shown as a straight line and this is what we see in figure 3.7: The
points |∆xn |/ϵ tend to lie on a straight line as ϵ decreases. The slopes of
these lines are equal to the Liapunov exponent λ. Deviations from the
straight line behavior indicates corrections and systematic errors, as we
point out in figure 3.7. A different initial condition results in a slightly
different value of λ, and the true value can be estimated as the average
over several such choices. We estimate the error of our computation
from the standard error of the mean. The reader should perform such a
computation as an exercise.
    One can perform a fit of the points |∆xn |/ϵ to the exponential function
in the following way: Since |∆xn |/ϵ ∼ C exp(λn) ⇒ ln(|∆xn |/ϵ) = λn + c,
we can make a fit to a straight line instead. Using gnuplot, the relevant
commands are:

gnuplot > f i t [ 5 : 5 3 ] a * x+b \
          ”<echo 500 3.6 0.2 1 e−15 | . / l ; c a t l i a . dat ”\
          using 1 : ( l o g ( $4 ) ) via a , b
gnuplot > r e p l o t exp ( a * x+b )

The command shown above fits the data to the function a*x+b by taking
164                                                            CHAPTER 3. LOGISTIC MAP

the 1st column and the logarithm of the 4th column (using 1:(log($4)))
of the stdout of the command that we used for creating the previous plot.
We choose data for which 5 ≤ n ≤ 53 ([5:53]) and the fitting parameters
are a,b (via a,b). The second line, adds the fitted function to the plot.

                                  0.48

                                  0.46
      (1/n)Σk=NN+n-1 ln|f’(xk)|




                                  0.44

                                  0.42

                                   0.4

                                  0.38                           r=3.8 x0=0.20
                                                                 r=3.8 x0=0.35
                                  0.36                           r=3.8 x0=0.50
                                                                 r=3.8 x0=0.75
                                                                 r=3.8 x0=0.90
                                  0.34
                                         0   10000 20000 30000 40000 50000 60000 70000
                                                              n
                                                     ∑N +n−1
Figure 3.8: Plot of the sum (1/n)             ln |f ′ (xk )| as a function of n for the logistic
                                                       k=N
map with r = 3.8, N = 2000 for different initial conditions x0 = 0.20, 0.35, 0.50, 0.75, 0.90.
The different curves converge in the limit n → ∞ to λ = 0.4325(10).



    Now we are going to use equation (3.35) for calculating λ. This
equation is approximately correct when (a) we have already reached the
steady state and (b) in the large n limit. For this reason we should
study if we obtain a satisfactory convergence when we (a) “throw away”
a number of NTRANS steps, (b) calculate the sum (3.35) for increasing
NSTEPS= n (c) calculate the sum (3.35) for many values of the initial point
x0 . This has to be carefully repeated for all values of r since each factor
will contribute differently to the quality of the convergence: In regions
that manifest chaotic behavior (large λ) convergence will be slower. The
program can be found in the file liapunov2.cpp:

/ / ===========================================================
/ / D i s c r e t e L o g i s t i c Map :
/ / Liapunov exponent from sum_i l n | f ’ ( x _ i ) |
3.6. LIAPUNOV EXPONENTS                                                                    165

/ / NTRANS: number o f d i s c a r t e d i t e r a t i o n s i n order t o d i s c a r t
//                 t r a n s i e n t behaviour
/ / NSTEPS : number o f terms i n t h e sum
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;

i n t main ( ) {
    int      NTRANS , NSTEPS , i ;
    double r , x0 , x1 , sum ;
    string buf ;
    / / −−−−− Input :
    cout << ” # Enter NTRANS, NSTEPS ,            r,   x0 : \ n” ;
    cin    >> NTRANS >> NSTEPS >> r               >>      x0 ; getline ( cin , buf ) ;
    cout << ” # NTRANS = ” << NTRANS              <<   endl ;
    cout << ” # NSTEPS = ” << NSTEPS              <<   endl ;
    cout << ” # r              = ” << r           <<   endl ;
    cout << ” # x0             = ” << x0          <<   endl ;

    f o r ( i =1; i<=NTRANS ; i++){
        x1      = r * x0 * ( 1 . 0 − x0 ) ;
        x0      = x1 ;
    }
    sum         = log ( abs ( r * ( 1 . 0 − 2 . 0 * x0 ) ) ) ;
    / / −−−−− I n i t i a l i z e :
    ofstream myfile ( ” l i a . dat ” ) ;
    myfile . precision ( 1 7 ) ;
    / / −−−−− C a l c u l a t e :
    myfile         << 1     << ” ” << x0 << ” ” << sum         << ”\n” ;
    f o r ( i =2;i<=NSTEPS ; i++){
        x1      = r * x0 * (1.0 − x0 ) ;
        sum += log ( abs ( r * ( 1 . 0 − 2 . 0 * x1 ) ) ) ;
        myfile << i         << ” ” << x1 << ” ” << sum / i << ”\n” ;
        x0      = x1 ;
    }
    myfile . close ( ) ;
} / / main ( )

After NTRANS steps, the program calculates NSTEPS times the sum of the
terms ln |f ′ (xk )| = ln |r(1 − 2xk )|. At each step the sum divided by the
number of steps i is printed to the file lia.dat. Figure 3.6 shows the
results for r = 3.8. This is a point where the system exhibits strong
chaotic behavior and convergence is achieved after we compute a large
number of steps. Using NTRANS = 2 000 and NSTEPS ≈ 70 000 the achieved
166                                                        CHAPTER 3. LOGISTIC MAP

accuracy is about 0.2% with λ = 0.4325 ± 0.0010 ≡ 0.4325(10). The main
contribution to the error comes from the different paths followed by
each initial point chosen. The plot can be constructed with the gnuplot
commands:

> g++ liapunov2 . cpp −o         l
> gnuplot
gnuplot > p l o t \
 ”<echo 2000 70000 3.8           0.20    |./   l   ; cat   lia   . dat ”   u   1:3   w   l ,\
 ”<echo 2000 70000 3.8           0.35    |./   l   ; cat   lia   . dat ”   u   1:3   w   l ,\
 ”<echo 2000 70000 3.8           0.50    |./   l   ; cat   lia   . dat ”   u   1:3   w   l ,\
 ”<echo 2000 70000 3.8           0.7 5   |./   l   ; cat   lia   . dat ”   u   1:3   w   l ,\
 ”<echo 2000 70000 3.8           0.90    |./   l   ; cat   lia   . dat ”   u   1:3   w   l

The plot command runs the program using the parameters NTRANS =
2 000, NSTEPS = 70 000, r = 3.8 and x0 = 0.20, 0.35, 0.50, 0.75, 0.90 and
plots the results from the contents of the file lia.dat.
    In order to determine the regions of chaotic behavior we have to study
the dependence of the Liapunov exponent λ on the value of r. Using our
experience coming from the careful computation of λ before, we will run
the program for several values of r using the parameters NTRANS = 2 000,
NSTEPS = 60 000 from the initial point x0 = 0.2. This calculation gives
accuracy of the order of 1%. If we wish to measure λ carefully and
estimate the error of the results, we have to follow the steps described in
figures 3.7 and 3.8. The program can be found in the file liapunov3.cpp
and it is a simple modification of the previous program so that it can
perform the calculation for many values of r.

/ / ===========================================================
/ / D i s c r e t e L o g i s t i c Map :
/ / Liapunov exponent from sum_i l n | f ’ ( x _ i ) |
/ / C a l c u l a t i o n f o r r i n [ rmin , rmax ] with RSTEPS s t e p s
/ / RSTEPS : v a l u e s or r s t u d i e d : r=rmin +(rmax−rmin ) / RSTEPS
/ / NTRANS: number o f d i s c a r t e d i t e r a t i o n s i n order t o d i s c a r t
//                     t r a n s i e n t behaviour
/ / NSTEPS : number o f terms i n t h e sum
/ / x s t a r t : v a l u e o f i n i t i a l x0 f o r ev er y r
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
3.6. LIAPUNOV EXPONENTS                                              167


i n t main ( ) {
    c o n s t double rmin       = 2.5;
    c o n s t double rmax       = 4.0;
    c o n s t double xstart = 0 . 2 ;
    const int           RSTEPS = 1000;
    const int           NSTEPS = 60000;
    const int           NTRANS = 2000;
    int        i , ir ;
    double r , x0 , x1 , sum , dr ;
    string buf ;

    / / −−−−− I n i t i a l i z e :
    ofstream myfile ( ” l i a . dat ” ) ;
    myfile . precision ( 1 7 ) ;
    / / −−−−− C a l c u l a t e :
    dr              = ( rmax−rmin ) / ( RSTEPS −1) ;
    f o r ( ir = 0 ; ir < RSTEPS ; ir++){
        r           = rmin+ir * dr ;
        x0          = xstart ;
        f o r ( i = 1 ; i <= NTRANS ; i++){
            x1 = r * x0 * (1.0 − x0 ) ;
            x0 = x1 ;
        }
        sum         = log ( abs ( r * ( 1 . 0 − 2 . 0 * x0 ) ) ) ;
        / / Calculate :
        f o r ( i = 2 ; i <= NSTEPS ; i++){
            x1 = r * x0 * (1.0 − x0 ) ;
            sum+= log ( abs ( r * ( 1 . 0 − 2 . 0 * x1 ) ) ) ;
            x0 = x1 ;
        }
        myfile << r << ” ” << sum / NSTEPS << ’\n ’ ;
    } / / f o r ( i r =0; i r <RSTEPS ; i r ++)
    myfile . close ( ) ;
} / / main ( )

The program can be compiled and run using the commands:

> g++ liapunov3 . cpp −o l
> ./l &

The character & makes the program ./l to run in the background. This
is recommended for programs that run for a long time, so that the shell
returns the prompt to the user and the program continues to run even
after the shell is terminated.
    The data are saved in the file lia.dat and we can make the plot
shown in figure 3.7 using gnuplot:
168                                                       CHAPTER 3. LOGISTIC MAP



            0.6

            0.4

            0.2
      λ




               0

            -0.2

            -0.4

                   2.6        2.8          3    3.2        3.4   3.6   3.8   4
                                                      r

Figure 3.9: The Liapunov exponent λ of the logistic map calculated via equation
(3.35). Note the chaotic behavior that manifests for the values of r where λ > 0 and
the windows of stable k-cycles where λ < 0. Compare this plot with the bifurcation
diagram of figure 3.4. At the points where λ = 0 we have onset of chaos (or “edge of
chaos”) with manifestation of weak chaos (i.e. |∆xn | ∼ |∆x0 |nω ). At these points we
have transitions from stable k-cycles to strong chaos. We observe the onset of chaos for
the first time when r = rc ≈ 3.5699, at which point λ = 0 (for smaller r the plot seems
to touch the λ = 0 line, but in fact λ takes negative values with |λ| very small).




gnuplot > p l o t        ” l i a . dat ”   with lines notitle , 0 notitle

Now we can compare figure 3.9 with the bifurcation diagram shown in
figure 3.4. The intervals with λ < 0 correspond to stable k-cycles. The
intervals where λ > 0 correspond to manifestation of strong chaos. These
intervals are separated by points with λ = 0 where the system exhibits
weak chaos. This means that neighboring trajectories diverge from each
other with a power law |∆xn | ∼ |∆x0 |nω instead of an exponential, where
ω = 1/(1 − q) is a positive exponent that needs to be determined. The
parameter q is the one usually used in the literature. Strong chaos is
obtained in the q → 1 limit. For larger r, switching between chaotic and
stable periodic trajectories is observed each time λ changes sign. The
critical values of r can be computed with relatively high accuracy by
restricting the calculation to a small enough neighborhood of the critical
3.6. LIAPUNOV EXPONENTS                                                                         169

point. You can do this using the program listed above by setting the
parameters rmin and rmax.

         5                                                  5


         4                                                  4


         3                                                  3
  p(x)




                                                     p(x)
         2                                                  2


         1                                                  1


         0                                                  0
             0   0.2   0.4       0.6   0.8   1                  0   0.2   0.4       0.6   0.8   1
                             x                                                  x


Figure 3.10: The distribution functions p(x) of x of the logistic map for r = 3.59
(left) and 3.8 (right). The chaotic behavior appears to be weaker for r = 3.59, and this
is reflected on the value of the entropy. One sees that there exist intervals of x with
p(x) = 0 which become smaller and vanish as r gets close to 4. This distribution is very
hard to be distinguished from a truly random distribution.



    We can also study the chaotic properties of the trajectories of the
logistic map by computing the distribution p(x) of the values of x in
the interval (0, 1). After the transitional period, the distribution p(x)
for the k cycles will have support only at the points of the k cycles,
whereas for the chaotic regimes it will have support on subintervals of
(0, 1). The distribution function p(x) is independent for most of the initial
points of the trajectories. If one obtains a large number of points from
many trajectories of the logistic map, it will be practically impossible to
understand that these are produced by a deterministic rule. For this
reason, chaotic systems can be used for the production of pseudorandom
numbers, as we will see in chapter 11. By measuring the entropy, which is
a measure of disorder in a system, we can quantify the “randomness” of
the distribution. As we will see in chapter 12, it is given by the equation
                                    ∑
                             S=−        pk ln pk ,                    (3.37)
                                                 k

where pk is the probability of observing the state k. In our case, we can
make an approximate calculation of S by dividing the interval (0, 1) to
N subintervals of width ∆x. For given r we obtain a large number M
of values xn of the logistic map and we compute the histogram hk of
their distribution in the intervals (xk , xk + ∆x). The probability density
is obtained from the limit of pk = hk /(M ∆x) as M becomes large and ∆x
170                                                       CHAPTER 3. LOGISTIC MAP
                           ∑                            ∫1
small (large N ). Indeed, N       pk ∆x = 1 converges to 0 p(x) dx = 1. We
                   ∑          k=1
will define S = − N   k=1 pk ln pk ∆x.


                    5


                    4


                    3
             p(x)




                    2


                    1


                    0
                        0   0.1   0.2   0.3   0.4   0.5   0.6   0.7   0.8   0.9   1
                                                     x

Figure 3.11: The distribution p(x) of x for the logistic map for r = 4. We observe
strong chaotic behavior, p(x) has support over the whole interval (0, 1) and the entropy
is large. The solid line is the analytic form of the distribution p(x) = π −1 x−1/2 (1−x)−1/2
which is known for r = 4 [32]. This is the beta distribution for a = 1/2, b = 1/2.


    The program listed below calculates pk for chosen values of r, and
then the entropy S is calculated using (3.37). It is a simple modification
of the program in liapunov3.cpp where we add the parameter NHIST
counting the number of intervals N for the histograms. The probability
density is calculated in the array p[NHIST]. The program can be found
in the file entropy.cpp:

/ / ===========================================================
/ / D i s c r e t e L o g i s t i c Map :
/ / Liapunov exponent from sum_i l n | f ’ ( x _ i ) |
/ / C a l c u l a t i o n f o r r i n [ rmin , rmax ] with RSTEPS s t e p s
/ / RSTEPS : v a l u e s or r s t u d i e d : r=rmin +(rmax−rmin ) / RSTEPS
/ / NTRANS: number o f d i s c a r t e d i t e r a t i o n s i n order t o d i s c a r t
//                     t r a n s i e n t behaviour
/ / NSTEPS : number o f terms i n t h e sum
/ / x s t a r t : v a l u e o f i n i t i a l x0 f o r ev er y r
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
3.6. LIAPUNOV EXPONENTS                                                    171

# include <string >
# i n c l u d e <cmath>
using namespace std ;

i n t main ( ) {
    c o n s t double rmin          = 2.5;
    c o n s t double rmax          = 4.0;
    c o n s t double xstart = 0 . 2 ;
    const int            RSTEPS = 1000;
    const int            NHIST = 10000;
    const int            NTRANS = 2000;
    const int            NSTEPS = 5000000;
    c o n s t double xmin =0.0 , xmax = 1 . 0 ;
    int        i , ir , isum , n ;
    double r , x0 , x1 , sum , dr , dx ;
    double p [ NHIST ] , S ;
    string buf ;

  / / −−−−− I n i t i a l i z e :
  ofstream myfile ( ” entropy . dat ” ) ;
  myfile . precision ( 1 7 ) ;
  / / −−−−− C a l c u l a t e :
  f o r ( i =0;i<NHIST ; i++) p [ i ] = 0 . 0 ;
  dr = ( rmax−rmin ) / ( RSTEPS −1) ;
  dx = ( xmax−xmin ) / ( NHIST −1) ;
  f o r ( ir =0; ir<RSTEPS ; ir++){
      r = rmin+ir * dr ;
      x0= xstart ;
      f o r ( i =1; i<=NTRANS ; i++){
          x1 = r * x0 * (1.0 − x0 ) ;
          x0 = x1 ;
      }
      / / make histogram :
      n= i n t ( x0 / dx ) ; p [ n ] + = 1 . 0 ;
      f o r ( i =2;i<=NSTEPS ; i++){
          x1         = r * x0 * (1.0 − x0 ) ;
          n          = i n t ( x1 / dx ) ;
          p [ n ] += 1 . 0 ;
          x0         = x1 ;
      }
      / / p [ k ] i s now histogram o f x−v a l u e s .
      / / Normalize so t h a t sum_k p [ k ] * dx=1
      / / to get probability d i s t r i b u t i o n :
      f o r ( i =0; i < NHIST ; i++) p [ i ] /= ( NSTEPS * dx ) ;
      / / sum a l l non z e r o terms : p [ n ] * l o g ( p [ n ] ) * dx
      S = 0.0;
      f o r ( i =0; i < NHIST ; i++)
           i f (p [ i ] > 0.0)
               S −= p [ i ] * log ( p [ i ] ) * dx ;
172                                               CHAPTER 3. LOGISTIC MAP

      myfile << r << ” ” << S << ’\n ’ ;
  } / / f o r ( i r =0; i r <RSTEPS ; i r ++)
  myfile . close ( ) ;

    myfile . open ( ” e n t r o p y _ h i s t . dat ” ) ;
    myfile . precision ( 1 7 ) ;
    f o r ( n =0;n<NHIST ; n++){
        x0 = xmin + n * dx + 0 . 5 * dx ;
        myfile << r << ” ” << x0 << ” ” << p [ n ] << ’\n ’ ;
    }
    myfile . close ( ) ;
} / / main ( )



            0
           -1
           -2
           -3
           -4
      S




           -5
           -6
           -7
           -8
           -9
                3.5 3.55 3.6 3.65 3.7 3.75 3.8 3.85 3.9 3.95                  4
                                              r
                                      ∑
Figure 3.12: The entropy S = −           k pk ln pk ∆x for the logistic map as a function
of r. The vertical line is rc ≈ 3.56994567 which marks the beginning of chaos and the
horizontal is the corresponding entropy. The entropy is low for small values of r, where
we have the stable 2n cycles, and large in the chaotic regimes. S drops suddenly when
we pass√to a (temporary) periodic behavior interval. We clearly observe the 3-cycle for
r = 1 + 8 ≈ 3.8284 and the subsequent bifurcations that we observed in the bifurcation
diagram (figure 3.4) and the Liapunov exponent diagram (figure 3.9).



    For the calculation of the distribution functions and the entropy we
have to choose the parameters which control the systematic error. The
parameter NTRANS should be large enough so that the transitional behav-
ior will not contaminate our results. Our measurements must be checked
3.6. LIAPUNOV EXPONENTS                                                 173

for being independent of its value. The same should be done for the ini-
tial point xstart. The parameter NHIST controls the partitioning of the
interval (0, 1) and the width ∆x, so it should be large enough. The pa-
rameter NSTEPS is the number of “measurements” for each value of r and
it should be large enough in order to reduce the “noise” in pk . It is obvi-
ous that NSTEPS should be larger when ∆x becomes smaller. Appropriate
choices lead to the plots shown in figures 3.10 and 3.11 for r = 3.59, 3.58
and 4. We see that stronger chaotic behavior means a wider distribution
of the values of x.
    The entropy is shown in figure 3.12. The stable periodic trajectories
lead to small entropy, whereas the chaotic ones lead to large entropy.
There is a sudden increase in the value of the entropy at the beginning
of chaos at r = rc , which increases even further as the chaotic behavior
becomes stronger. During the intermissions of the chaotic behavior there
are sudden drops in the value of the entropy. It is quite instructive to
compare the entropy diagrams with the corresponding bifurcation dia-
grams (see figure 3.4) and the Liapunov exponent diagrams (see figure
3.9). The entropy is increasing until r reaches its maximum value 4, but
this is not done smoothly. By magnifying the corresponding areas in the
plot, we can see an infinite number of sudden drops in the entropy in
intervals of r that become more and more narrow.
174                                             CHAPTER 3. LOGISTIC MAP

3.7 Problems
Several of the programs that you need to write for solving the problems of
this chapter can be found in the Problems directory of the accompanying
software of this chapter.
 3.1 Confirm that the trajectories of the logistic map for r < 1 are falling
     off exponentially for large enough n.
      (a) Choose r = 0.5 and plot the trajectories for x0 = 0.1 − 0.9 with
          step 0.1 for n = 1, . . . , 1000. Put the y axis in a logarithmic
          scale. From the resulting curves discuss whether you obtain
          an exponential falloff.
      (b) Fit the points xn for n > 20 to the function c e−ax and deter-
          mine the fitting parameters a and c. How do these parameters
          depend on the initial point x0 ? You can use the following
          gnuplot commands for your calculation:

           gnuplot > ! g++ logistic . cpp −o l
           gnuplot > a = 0 . 7 ; c = 0 . 4 ;
           gnuplot > f i t [ 1 0 : ] c * exp(−a * x ) \
            ”<echo 1000 0.5 0 . 5 | . / l ; c a t l o g . dat ” via a , c
           gnuplot > p l o t c * exp(−a * x ) ,\
            ”<echo 1000 0.5 0 . 5 | . / l ; c a t l o g . dat ” w l

           As you can see, we set NSTEPS = 1000, r = 0.5, x0 = 0.5. By
           setting the limits [10:] to the fit command, the fit includes
           only the points xn ≥ 10, therefore avoiding the transitional
           period and the deviation from the exponential falloff for small
           n.
       (c) Repeat for r = 0.3 − 0.9 with step 0.1 and for r = 0.99, 0.999.
           As you will be approaching r = 1, you will need to discard
           more points from near the origin. You might also need to
           increase NSTEPS. You should always check graphically whether
           the fitted exponential function is a good fit to the points xn for
           large n. Construct a table for the values of a as a function of
           r.
      The solutions of the equation (3.3) is e(r−1)x . How is this related to
      the values that you computed in your table?
 3.2 Consider the logistic map for r = 2. Choose NSTEPS=100 and cal-
     culate the corresponding trajectories for x0=0.2, 0.3, 0.5, 0.7,
3.7. PROBLEMS                                                                                   175

    0.9. Plot them on the same graph. Calculate the fixed point x∗2
    and compare your result to the known value 1 − 1/r. Repeat for
    x0= 10−α for α = −1, −2, −5, −10, −20, −25. What do you conclude
    about the point x∗1 = 0?

3.3 Consider the logistic map for r = 2.9, 2.99, 2.999. Calculate the stable
    point x∗2 and compare your result to the known value 1 − 1/r. How
    large should NSTEPS be chosen each time? You may choose x0=0.3.

3.4 Consider the logistic map for r = 3.2. Take x0=0.3, 0.5, 0.9 and
    NSTEPS=300 and plot the resulting trajectories. Calculate the fixed
    points x∗3 and x∗4 by using the command tail log.dat. Increase
    NSTEPS and repeat so that you make sure that the trajectory has
    converged to the 2-cycle. Compare their values to the ones given
    by equation (3.18). Make the following plots:

    gnuplot > p l o t          \
     ”<echo 300 3.2            0 . 3 | . / l ; awk ’NR%2==0’ l o g . dat ”            w l
    gnuplot > r e p l o t      \
     ”<echo 300 3.2            0 . 3 | . / l ; awk ’NR%2==1’ l o g . dat ”            w l


    What do you observe?

3.5 Repeat the previous problem for r = 3.4494. How big should NSTEPS
    be chosen so that you obtain x∗3 and x∗4 with an accuracy of 6 sig-
    nificant digits?

3.6 Repeat the previous problem for r = 3.5 and 3.55. Choose NSTEPS =
    1000, x0 = 0.5. Show that the trajectories approach a 4-cycle and
    an 8-cycle respectively. Calculate the fixed points x∗5 -x∗8 and x∗9 -x∗16 .

3.7 Plot the functions f (x), f (2) (x), f (4) (x), x for given r on the same
    graph. Use the commands:

    gnuplot > s e t samples 1000
    gnuplot > f ( x ) = r * x*(1 −x )
    gnuplot > r =1; p l o t [ 0 : 1 ] x , f ( x ) , f ( f ( x ) ) , f ( f ( f ( f ( x ) ) ) )

                                                                 √
    The command r=1 sets the value of r. Take r = 2.5, 3, 3.2, 1+ 6, 3.5.
    Determine the fixed points and the k-cycles from the intersections
    of the plots with the diagonal y = x.
176                                         CHAPTER 3. LOGISTIC MAP

 3.8 Construct the cobweb plots of figures 3.2 and 3.4 for r = 2.8, 3.3
     and 3.5. Repeat by dropping from the plot an increasing number
     of initial points, so that in the end only the k-cycles will remain.
     Do the same for r = 3.55.

 3.9 Construct the bifurcation diagrams shown in figure 3.4.

3.10 Construct the bifurcation diagram of the logistic map for 3.840 < r <
     3.851 and for 0.458 < x < 0.523. Compute the first four bifurcation
     points with an accuracy of 5 significant digits by magnifying the
     appropriate parts of the plots. Take NTRANS=15000.

3.11 Construct the bifurcation diagram of the logistic map for 2.9 < r <
                                                            (n)
     3.57. Compute graphically the bifurcation points rc for n = 2, 3, 4,
     5, 6, 7, 8. Make sure that your results are stable against variations
     of the parameters NTRANS, NSTEPS as well as from the choice of
                                                        (n)
     branching point. From the known values of rc for n = 2, 3, and
     from the dependence of your results on the choices of NTRANS,
     NSTEPS, estimate the accuracy achieved by this graphical method.
                            (n)  (n−1)     (n+1)    (n)
     Compute the ratios (rc − rc       )/(rc     − rc ) and compare your
     results to equation (3.20).

3.12 Choose the values of ρ in equation (3.24) so that you obtain only
     one energy level. Compute the resulting value of the energy. When
     do we have three energy levels?

3.13 Consider the polynomial g(x) = x3 − 2x2 − 11x + 12. Find the roots
     obtained by the Newton-Raphson method when you choose x0 =
     2.35287527, 2.35284172, 2.35283735, 2.352836327, 2.352836323. What
     do you conclude concerning the basins of attraction of each root of
     the polynomial? Make a plot of the polynomial in a neighborhood
     of its roots and try other initial points that will converge to each
     one of the roots.

3.14 Use the Newton-Raphson method in order to compute the 4-cycle
     x∗5 , . . . , x∗8 of the logistic map. Use appropriate areas of the bifur-
     cation diagram so that you can choose the initial points correctly.
     Check that your result for rc is the same for all x∗α . Tune the
                                          (4)

     parameters chosen in your calculation on order to improve the ac-
     curacy of your measurements.

3.15 Repeat the previous problem for the 8-cycle x∗9 , . . . , x∗16 and rc .
                                                                        (5)
3.7. PROBLEMS                                                                        177

                      (n)                         (n)
                n    rc                 n rc
                2    3.0000000000 10 3.56994317604
                3    3.4494897429      11 3.569945137342
                4    3.544090360      12 3.5699455573912
                5    3.564407266      13 3.569945647353
                6    3.5687594195     14 3.5699456666199
                7    3.5696916098     15 3.5699456707464
                8    3.56989125938 16 3.56994567163008
                9    3.56993401837 17 3.5699456718193
                              rc = 3.56994567 . . .


Table 3.1: The values of rc(n) for the logistic map calculated for problem 17. rc(∞) ≡ rc
is taken from the bibliography.


3.16 Repeat the previous problem for the 16-cycle x∗17 , . . . , x∗32 and rc .
                                                                                    (6)


                                          (n)
3.17 Calculate the critical points rc for n = 3, . . . , 17 of the logistic map
     using the Newton-Raphson method. In order to achieve that, you
     should determine the bifurcation points graphically in the bifurca-
     tion diagram first and then choose the initial points in the Newton-
     Raphson method appropriately. The program in bifurcationPoints.cpp
     should read the parameters eps, epsx, epsr from the stdin so that
     they can be tuned for increasing n. If these parameters are too small
     the convergence will be unstable and if they are too large you will
     have large systematic errors. Using this method, try to reproduce
     table 3.1
3.18 Calculate the ratios ∆r(n) /∆r(n+1) of equation (3.20) using the re-
     sults of table 3.1. Calculate Feigenbaum’s constant and comment
     on the accuracy achieved by your calculation.
3.19 Estimate Feigenbaum’s constant δ and the critical value rc by as-
     suming that for large enough n, rc ≈ rc − Cδ −n . This behavior
                                        (n)

     is a result of equation (3.20). Fit the results of table 3.1 to this
     function and calculate δ and rc . This hypothesis is confirmed in
     figure 3.13 where we can observe the exponential convergence of
      (n)
     rc to rc . Construct the same plot using the parameters of your
     calculation.
     Hint: You can use the following gnuplot commands:
178                                                      CHAPTER 3. LOGISTIC MAP

      gnuplot >          nmin =2; nmax =17
      gnuplot >          r ( x )= rc−c * d **( − x )
      gnuplot >          f i t [ nmin : nmax ] r ( x )   ” r c r i t ” u 1 : 2 via rc , c , d
      gnuplot >          plot ” r c r i t ” , r(x)
      gnuplot >          p r i n t rc , d


      The file rcrit contains the values of table 3.1. You should vary the
      parameters nmin, nmax and repeat until you obtain a stable fit.

                             1
                                                                    C δ-n

                          0.01


                        0.0001
           rc(n) - rc




                        1e-06


                        1e-08


                        1e-10


                        1e-12
                                 2   4       6     8     10   12     14     16    18
                                                         n

Figure 3.13: Test of the relation rc(n) ≈ rc − Cδ −n discussed in problem 17. The
parameters used in the plot are approximately rc = 3.5699457, δ = 4.669196 and C =
12.292.




3.20 Use the Newton-Raphson method to calculate the first three bifur-√
     cation points after the appearance of the 3-cycle for r = 1 + 8.
     Choose one bifurcation point of the 3-cycle, one of the 6-cycle and
     one of the 12-cycle and magnify the bifurcation diagram in their
     neighborhood.

3.21 Consider the map describing the evolution of a population

                                         xn+1 = p(xn ) = xn er(1−xn ) .                     (3.38)

       (a) Plot the functions x, p(x), p(2) (x), p(4) (x) for r = 1.8, 2, 2.6, 2.67,
           2.689 for 0 < x < 8. For which values of r do you expect to
           obtain stable k-cycles?
3.7. PROBLEMS                                                               179

     (b) For the same values of r plot the trajectories with initial points
         x0 = 0.2, 0.5, 0.7. For each r make a separate plot.
      (c) Use the Newton-Raphson method in order to determine the
                  (n)
          points rc for n = 3, 4, 5 as well as the first two bifurcation
          points of the 3-cycle.
     (d) Construct the bifurcation diagram for 1.8 < r < 4. Determine
         the point marking the onset of chaos as well as the point where
         the 3-cycle starts. Magnify the diagram around a branch that
         you will choose.
      (e) Estimate Feigenbaum’s constant δ as in problem 17. Is your
          result compatible with the expectation of universality for the
          value of δ? Is the value of rc the same as that of the logistic
          map?

3.22 Consider the sine map:

                            xn+1 = s(xn ) = r sin(πxn ) .                (3.39)

      (a) Plot the functions x, s(x), s(2) (x), s(4) (x), s(8) (x) for r = 0.65,
          0.75, 0.84, 0.86, 0.88. Which values of r are expected to lead to
          stable k-cycles?
     (b) For the same values of r, plot the trajectories with initial points
         x0 = 0.2, 0.5, 0.7. Make one plot for each r.
      (c) Use the Newton-Raphson method in order to determine the
                  (n)
          points rc for n = 3, 4, 5 as well as the first two bifurcation
          points of the 3-cycle.
     (d) Construct the bifurcation diagram for 0.6 < r < 1. Within
         which limits do the values of x lie in? Repeat for 0.6 < r < 2.
         What do you observe? Determine the point marking the onset
         of chaos as well as the point where the 3-cycle starts. Magnify
         the diagram around a branch that you will choose.

3.23 Consider the map:
                                 xn+1 = 1 − rx2n .                       (3.40)

      (a) Construct the bifurcation diagram for 0 < r < 2. Within which
          limits do the values of x lie in? Determine the point marking
          the onset of chaos as well as the point where the 3-cycle starts.
          Magnify the diagram around a branch that you will choose.
180                                          CHAPTER 3. LOGISTIC MAP

      (b) Use the Newton-Raphson method in order to determine the
                  (n)
          points rc for n = 3, 4, 5 as well as the first two bifurcation
          points of the 3-cycle.
3.24 Consider the tent map:
                                        {
                                            rxn        0 ≤ xn ≤ 21
         xn+1 = r min{xn , 1 − xn } =                              .   (3.41)
                                            r(1 − xn ) 12 < xn ≤ 1
      Construct the bifurcation diagram for 0 < r < 2. Within which lim-
      its do the values of x lie in? On the same graph, plot the functions
      r/2, r − r2 /2.
      Magnify the diagram in the area 1.407 < r < 1.416 and 0.580 <
      x < 0.588. At which point do the two disconnected intervals within
      which xn take their values merge into one? Magnify the areas 1.0 <
      r < 1.1, 0.4998 < x < 0.5004 and 1.00 < r < 1.03, 0.4999998 < x <
      0.5000003 and determine the merging points of two disconnected
      intervals within which xn take their values.
3.25 Consider the Gauss map (or mouse map):

                                xn+1 = e−rxn + q .
                                              2
                                                                       (3.42)

      Construct the bifurcation diagram for −1 < q < 1 and r = 4.5, 4.9,
      7.5. Make your program to take as the initial point of the new
      trajectory to be the last one of the previous trajectory and choose
      x0 = 0 for q = −1. Repeat for x0 = 0.7, 0.5, −0.7. What do you
      observe? Note that as q is increased, we obtain bifurcations and
      “anti-bifurcations”.
3.26 Consider the circle map:

                     xn+1 = [xn + r − q sin(2πxn )]    mod 1 .         (3.43)

      (Make sure that your program keeps the values of xn so that 0 ≤
      xn < 1). Construct the bifurcation diagram for 0 < q < 2 and
      r = 1/3.
3.27 Use the program in liapunov.cpp in order to compute the distance
     between two trajectories of the logistic map for r = 3.6 that origi-
     nally are at a distance ∆x0 = 10−15 . Choose x0 = 0.1, 0.2, 0.3, 0.4,
     0.5, 0.6, 0.7, 0.8, 0.9, 0.99, 0.999 and calculate the Liapunov exponent
     by fitting to a straight line appropriately. Compute the mean value
     and the standard error of the mean.
3.7. PROBLEMS                                                            181

3.28 Calculate the Liapunov exponent for r = 3.58, 3.60, 3.65, 3.70, 3.80
     for the logistic map. Use both ways mentioned in the text. Choose
     at least 5 different initial points and calculate the mean and the
     standard error of the mean of your results. Compare the values of
     λ that you obtain with each method and comment.

                                                                   (n)
3.29 Compute the critical value rc numerically as the limit lim rc for
                                                             n→∞
     the logistic map with an accuracy of nine significant digits. Use the
     calculation of the Liapunov exponent λ given by equation (3.35).

3.30 Compute the values of r of the logistic map numerically for which
     we (a) enter a stable 3-cycle (b) reenter into the chaotic behavior.
     Do the calculation by computing the Liapunov exponent λ and
     compare your results with the ones obtained from the bifurcation
     diagram.

3.31 Calculate the Liapunov exponent using equation (3.35) for the fol-
     lowing maps:

           xn+1 = xn er(1−xn ) ,    1.8 < r < 4
           xn+1 = r sin(πxn ) ,     0.6 < r < 1
           xn+1 = 1 − rx2n ,       0<r<2
           xn+1 = e−rxn + q ,
                         2
                              r = 7.5, −1 < q < 1
                  [                  ]
                         1
           xn+1 = xn + − q sin(2πxn )    mod 1 , 0 < q < 2 ,(3.44)
                         3

     and construct the diagrams similar to the ones in figure 3.9. Com-
     pare your plots with the respective bifurcation diagrams (you may
     put both graphs on the same plot). Use two different initial points
     x0 = 0, 0.2 for the Gauss map (xn+1 = e−rxn + q) and observe the dif-
                                               2


     ferences. For the circle map (xn+1 = [xn + 1/3 − q sin(2πxn )] mod 1)
     study carefully the values 0 < q < 0.15.

3.32 Reproduce the plots in figures 3.10, 3.11 and 3.12. Compute the
     function p(x) for r = 3.68, 3.80, 3.93 and 3.98. Determine the
     points where you have stronger chaos by observing p(x) and the
     corresponding values of the entropy. Compute the entropy for
     r ∈ (3.95, 4.00) by taking RSTEPS=2000 and estimate the values of r
     where we enter to and exit from chaos. Compare your results with
     the computation of the Liapunov exponent.
182                                             CHAPTER 3. LOGISTIC MAP

3.33 Consider the Hénon map:

                                 xn+1 = yn + 1 − ax2n
                                 yn+1 = bxn                                    (3.45)

       (a) Construct the two bifurcation diagrams for xn and yn for b =
           0.3, 1.0 < a < 1.5. Check if the values a = 1.01, 1.4 that we will
           use below correspond to stable periodic trajectories or chaotic
           behavior.
       (b) Write a program in a file attractor.cpp which will take NINIT
           = NL × NL initial conditions (x0 (i), y0 (i)) i = 1, . . . ,NL on a
           NL×NL lattice of the square xm ≤ x0 ≤ xM , ym ≤ y0 ≤ yM .
           Each of the points (x0 (i), y0 (i)) will evolve according to equa-
           tion (3.45) for n = NSTEPS steps. The program will print the
           points (xn (i), yn (i)) to the stdout. Choose xm = ym = 0.6,
           xM = yM = 0.8, NL= 200.
       (c) Choose a = 1.01, b = 0.3 and plot the points (xn (i), yn (i)) for
           n = 0, 1, 2, 3, 10, 20, 30, 40, 60, 1000 on the same diagram.
       (d) Choose a = 1.4, b = 0.3 and plot the points (xn (i), yn (i)) for
           n = 0, . . . , 7 on the same diagram.
       (e) Choose a = 1.4, b = 0.3 and plot the points (xn (i), yn (i)) for
           n = 999 on the same diagram. Observe the Hénon strange
           attractor and its fractal properties. It is characterized by a
           Hausdorff¹² dimension dH = 1.261 ± 0.003. Then magnify the
           regions

                   {(x, y)| −1.290 < x < −1.270,         0.378 < y   < 0.384} ,
                   {(x, y)| 1.150 < x < −1.130,          0.366 < y   < 0.372} ,
                   {(x, y)|  0.108 < x < 0.114,          0.238 < y   < 0.241} ,
                   {(x, y)|  0.300 < x < 0.320,          0.204 < y   < 0.213} ,
                   {(x, y)|  1.076 < x < 1.084,          0.090 < y   < 0.096} ,
                   {(x, y)|  1.216 < x < 1.226,          0.032 < y   < 0.034} .

3.34 Consider the Duffing map:

                              xn+1 = yn
                              yn+1 = −bxn + ayn − yn3 .                        (3.46)
  ¹²D.A. Russel, J.D. Hanson, and E. Ott, “Dimension of strange attractors”, Phys. Rev.
Lett. 45 (1980) 1175. See “Hausdorff dimension” in Wikipedia.
3.7. PROBLEMS                                                                183

      (a) Construct the two bifurcation diagrams for xn and yn for b =
          0.3, 0 < a < √   2.78. Choose
                                  √     four different initial conditions
          (x0 , y0 ) = (±1/ 2, ±1/ 2). What do you observe?
     (b) Use the program attractor.cpp from problem 33 in order to
         study the attractor of the map for b = 0.3, a = 2.75.

3.35 Consider the Tinkerbell map:

                          xn+1 = x2n − yn2 + axn + byn
                          yn+1 = 2xn yn + cxn + dyn .                      (3.47)

      (a) Choose a = 0.9, b = −0.6013, c = 2.0, d = 0.50. Plot a trajectory
          on the plane by plotting the points (xn , yn ) for n = 0, . . . , 10 000
          with (x0 , y0 ) = (−0.72, −0.64).
     (b) Use the program attractor.cpp from problem 33 in order to
         study the attractor of the map for the values of the parameters
         a, b, c, d given above. Choose xm = −0.68, xM = −0.76, ym =
         −0.60, yM = −0.68, n = 10 000.
      (c) Repeat the previous question by taking d = 0.27.
184   CHAPTER 3. LOGISTIC MAP
Chapter 4

Motion of a Particle

In this chapter we will study the numerical solution of classical equations
of motion of one dimensional mechanical systems, e.g. a point particle
moving on the line, the simple pendulum etc. We will make an introduc-
tion to the numerical integration of ordinary differential equations with
initial conditions and in particular to the Euler and Runge-Kutta meth-
ods. We study in detail the examples of the damped harmonic oscillator
and of the damped pendulum under the influence of an external peri-
odic force. The latter system is nonlinear and exhibits interesting chaotic
behavior.


4.1     Numerical Integration of Newton’s Equa-
        tions
Consider the problem of the solution of the dynamical equations of mo-
tion of one particle under the influence of a dynamical field given by
Newton’s law. The equations can be written in the form

                                d2⃗x
                                     = ⃗a(t, ⃗x, ⃗v ) ,               (4.1)
                                dt2
where
                                    F⃗         d⃗x
                        ⃗a(t, ⃗x, ⃗v ) ≡  ⃗v =     .                (4.2)
                                   m           dt
From the numerical analysis point of view, the problems that we will dis-
cuss are initial value problems for ordinary differential equations where
the initial conditions

                         ⃗x(t0 ) = ⃗x0        ⃗v (t0 ) = ⃗v0 ,        (4.3)

                                           185
186                               CHAPTER 4. MOTION OF A PARTICLE

determine a unique solution ⃗x(t). The equations (4.1) are of second order
with respect to time and it is convenient to write them as a system of
twice as many first order equations:
                            d⃗x            d⃗v
                                = ⃗v           = ⃗a(t, ⃗x, ⃗v ) .            (4.4)
                            dt             dt
In particular, we will be interested in the study of the motion of a particle
moving on a line (1 dimension), therefore the above equations become
                 dx                    dv
                      =v                   = a(t, x, v)      1-dimension
                 dt                    dt
              x(t0 ) = x0              v(t0 ) = v0 .                         (4.5)

When the particle moves on the plane (2 dimensions) the equations of
motion become
           dx                  dvx
                = vx                 = ax (t, x, vx , y, vy ) 2-dimensions
           dt                   dt
           dy                  dvy
                = vy                 = ay (t, x, vx , y, vy )
           dt                   dt
         x(t0 ) = x0           vx (t0 ) = v0x
         y(t0 ) = y0           vy (t0 ) = v0y ,                              (4.6)


4.2 Prelude: Euler Methods
As a first attempt to tackle the problem, we will study a simple pendulum
of length l in a homogeneous gravitational field g (figure 4.1).       The
equations of motion are given by the differential equations

                                 d2 θ    g
                                    2
                                      = − sin θ
                                 dt       l
                                  dθ
                                      = ω,                                   (4.7)
                                  dt
which can be rewritten as a first order system of differential equations
                              dθ
                                 = ω
                              dt
                              dω     g
                                 = − sin θ                  ,                (4.8)
                              dt     l
The equations above need to be written in a discrete form appropriate
for a numerical solution with the aid of a computer. We split the interval
4.2. PRELUDE: EULER METHODS                                                 187




                                     θ
                                                l



                                                     00
                                                     11
                                                     00
                                                     11
                                                      0
                                                      1
                                                     00
                                                     11
                                                      0
                                                      1   m
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                      0
                                                      1
                                                          g

Figure 4.1: A simple pendulum of length l in a homogeneous gravitational field g.



of time of integration [ti , tf ] to N − 1 equal intervals¹ of width ∆t ≡ h,
where h = (tf − ti )/(N − 1). The derivatives are approximated by the
relations (xn+1 − xn )/∆t ≈ x′n , so that

                                 ωn+1 = ωn + αn ∆t
                                 θn+1 = θn + ωn ∆t .                       (4.9)

where α = −(g/l) sin θ is the angular acceleration. This is the so-called
Euler method. The error at each step is estimated to be of order (∆t)2 .
This is most easily seen by Taylor expanding around the point tn and
neglecting all terms starting from the second derivative and beyond².
What we are mostly interested in is in the total error of the estimate of the
functions we integrate for at time tf ! We expect that errors accumulate in
an additive way at each integration step, and since the number of steps is
N ∝ 1/∆t the total error should be ∝ (∆t)2 × (1/∆t) = ∆t. This is indeed
what happens, and we say that Euler’s method is a first order method.
Its range of applicability is limited and we only study it for academic
reasons. Euler’s method is asymmetric because it uses information only
from the beginning of the integration interval (t, t + ∆t). It can be put
in a more balanced form by using the velocity at the end of the interval
(t, t + ∆t). This way we obtain the Euler-Cromer method with a slightly

  ¹We have N discrete time points ti ≡ t1 , . . . , tN −1 , tN ≡ tf
  ²See appendix 4.7 for retails.
188                                     CHAPTER 4. MOTION OF A PARTICLE

                0.5
                                                                     50
                                                                   100
                                                                  1000
                0.4                                              10000
                                                                 50000
                                                                 80000
                0.3                                             100000
                                                                   θs(t)

                0.2


                0.1
            θ




                  0


                -0.1


                -0.2


                -0.3


                -0.4
                       0   1        2       3       4     5        6       7
                                                t



Figure 4.2: Convergence of Euler’s method for a simple pendulum with period
T ≈ 1.987(ω 2 = 10.0) for several values of the time step ∆t which is determined by the
number of integration steps Nt= 50−100, 000. The solution is given for θ0 = 0.2, ω0 = 0.0
and we compare it with the known solution for small angles with α(t) ≈ −(g/l) θ.



improved behavior, but which is still of first order

                                 ωn+1 = ωn + αn ∆t
                                 θn+1 = θn + ωn+1 ∆t .                           (4.10)

   An improved algorithm is the Euler–Verlet method which is of second
order and gives total error³ ∼ (∆t)2 . This is given by the equations

                           θn+1 = 2θn − θn−1 + αn (∆t)2
                                  θn+1 − θn−1
                             ωn =             .                                  (4.11)
                                      2∆t
    The price that we have to pay is that we have to use a two step
relation in order to advance the solution to the next step. This implies
that we have to carefully determine the initial conditions of the problem
which are given only at one given time ti . We make one Euler time step
backwards in order to define the value of θ0 . If the initial conditions are
θ1 = θ(ti ), ω1 = ω(ti ), then we define
                                                1
                               θ0 = θ1 − ω1 ∆t + α1 (∆t)2 .                      (4.12)
                                                2
   ³See appendix 4.7 for details.
4.2. PRELUDE: EULER METHODS                                                   189

               0.025
                                                                 50
                                                               100
                0.02                                          1000
                                                             10000
                                                             50000
               0.015                                         80000
                                                            100000
                                                               θs(t)
                0.01


               0.005


                   0
           θ




               -0.005


                -0.01


               -0.015


                -0.02


               -0.025
                        0   1    2      3       4     5        6       7
                                            t



Figure 4.3:      Convergence of the Euler-Cromer method, similarly to figure 4.2. We
observe a faster convergence compared to Euler’s method.



It is important that at this step the error introduced is not larger than
O(∆t2 ), otherwise it will spoil and eventually dominate the O(∆t2 ) total
error of the method introduced by the intermediate steps. At the last
step we also have to take

                                       θN − θN −1
                                ωN =              .                         (4.13)
                                          ∆t
Even though the method has smaller total error than the Euler method,
it becomes unstable for small enough ∆t due to roundoff errors. In
particular, the second equation in (4.11) gives the angular velocity as the
ratio of two small numbers. The problem is that the numerator is the
result of the subtraction of two almost equal numbers. For small enough
∆t, this difference has to be computed from the last digits of the finite
representation of the numbers θn+1 and θn in the computer memory. The
accuracy in the determination of (θn+1 − θn ) decreases until it eventually
becomes exactly zero. For the first equation of (4.11), the term αn ∆t2 is
smaller by a factor ∆t compared to the term αn ∆t in Euler’s method.
At some point, by decreasing ∆t, we obtain αn ∆t2 ≪ 2θn − θn−1 and
the accuracy of the method vanishes due to the finite representation of
real number in the memory of the computer. When the numbers αn ∆t2
and 2θn − θn−1 differ from each other by more that approximately sixteen
orders of magnitude, adding the first one to the second is equivalent to
190                               CHAPTER 4. MOTION OF A PARTICLE

                0.025
                                                                   50
                                                                 100
                 0.02                                           1000
                                                               10000
                                                               50000
                0.015                                          80000
                                                              100000
                                                                 θs(t)
                 0.01


                0.005


                    0
            θ




                -0.005


                 -0.01


                -0.015


                 -0.02


                -0.025
                         0   1    2      3       4      5        6       7
                                             t



Figure 4.4: Convergence of the Euler-Verlet method, similarly to figure 4.2. We
observe a faster convergence than Euler’s method, but the roundoff errors make the
results useless for Nt≳ 50, 000 (note what happens when Nt= 100, 000. Why?).



adding zero and the contribution of the acceleration vanishes⁴.
    Writing programs that implement the methods discussed so far is
quite simple. We will write a program that compares the results from
all three methods Euler, Euler–Cromer and Euler–Verlet. The main pro-
gram is mainly a user interface, and the computation is carried out by
three functions euler, euler_cromer and euler_verlet. The user must
provide the function accel(x) which gives the angular acceleration as a
function of x. The variable x in our problem corresponds to the angle
theta. For starters we take accel(x)= -10.0 * sin(x), the acceleration
of the simple pendulum.
    The data structure is very simple: Three double arrays T[P], X[P]
and V[P] store the times tn , the angles θn and the angular velocities ωn for
n = 1, . . . , Nt. The user determines the time interval for the integration
from ti = 0 to tf = Tfi and the number of discrete times Nt. The latter
should be less than P, the size of the arrays. She also provides the initial
conditions θ0 = Xin and ω0 = Vin. After this, we call the main integration
functions which take as input the initial conditions, the time interval of

    ⁴Numbers of type double have approximately sixteen significant digits. The accuracy
of the operations described above is determined by the number ϵ, which is the smallest
positive number such that 1 + ϵ > 1. For variables of type float, ϵ ≈ 1.2 × 10−7 and
for variables of type double ϵ ≈ 2.2 × 10−16 .
4.2. PRELUDE: EULER METHODS                                                       191

                 8
                                                                   50
                                                                  100
                 6                                               1000
                                                                10000
                                                                15000
                 4                                              18000
                                                                20000
                                                               100000
                 2


                 0


                 -2
            v




                 -4


                 -6


                 -8


                -10


                -12
                      0   1        2        3       4    5       6      7
                                                t



Figure 4.5: Convergence of Euler’s method for the simple pendulum like in figure
4.2 for θ0 = 3.0, ω0 = 0.0. The behavior of the angular velocity is shown and we notice
unstable behavior for Nt≲ 1, 000.



the integration and the number of discrete times Xin,Vin,Tfi,Nt. The
output of the routines is the arrays T,X,V which store the results for the
time, position and velocity respectively. The results are printed to the
files euler.dat, euler_cromer.dat and euler_verlet.dat.
   After setting the initial conditions and computing the time step ∆t ≡
h = Tfi/(Nt − 1), the integration in each of the functions is performed in
for loops which advance the solution by time ∆t. The results are stored
at each step in the arrays T,X,V. For example, the central part of the
program for Euler’s method is:

  T [0] = 0.0;
  X [ 0 ] = Xin ;
  V [ 0 ] = Vin ;
  h        = Tfi / ( Nt −1) ;
  f o r ( i =1; i<Nt ; i++){
      T [ i ] = T [ i−1]+h ;
      V [ i ] = V [ i−1]+accel ( X [ i −1]) * h ;
      X [ i ] = X [ i−1]+V [ i ] * h ;
  }

Some care has to be taken in the case of the Euler–Verlet method where
one has to initialize the first two steps, as well as take special care for the
last step for the velocity:
192                                        CHAPTER 4. MOTION OF A PARTICLE

                  8
                                                                                50
                                                                               100
                                                                              1000
                  6                                                          10000
                                                                             15000
                                                                             18000
                                                                             20000
                  4                                                         100000


                  2


                  0
              v




                  -2


                  -4


                  -6


                  -8
                       0     1         2        3         4         5         6         7
                                                     t



Figure 4.6: Convergence of Euler-Cromer’s method, like in figure 4.5. We observe a
faster convergence than for Euler’s method.




  T[0]          = 0.0;
  X[0]          = Xin ;
  V[0]          = Vin ;
  X0            = X [ 0 ] − V [ 0 ] * h + accel ( X [ 0 ] ) * h2 / 2 . 0 ;
  T[1]          = h;
  X[1]          = 2 . 0 * X [ 0 ] − X0  + accel ( X [ 0 ] ) * h2 ;
  f o r ( i =2;i<Nt ; i++){
       ..............
  }
  V [ Nt −1] = ( X [ Nt −1] − X [ Nt −2]) / h ;

The full program can be found in the file euler.cpp and is listed below:

/ / =========================================================
/ / Program t o i n t e g r a t e e q u a t i o n s o f motion f o r a c c e l e r a t i o n s
/ / which a r e f u n c t i o n s o f x with t h e method o f Euler ,
/ / Euler−Cromer and Euler−V e r l e t .
/ / The u s e r s e t s i n i t i a l c o n d i t i o n s and t h e f u n c t i o n s r e t u r n
/ / X[ t ] and V[ t ]=dX[ t ] / dt i n a r r a y s
/ / T [ 0 . . Nt −1] ,X [ 0 . . Nt −1] ,V [ 0 . . Nt −1]
/ / The u s e r p r o v i d e s number o f t i m e s Nt and t h e f i n a l
/ / time T f i . I n i t i a l time i s assumed t o be t _ i =0 and t h e
/ / i n t e g r a t i o n s t e p h = T f i / ( Nt −1)
/ / The u s e r programs a r e a l f u n c t i o n a c c e l ( x ) which g i v e s t h e
/ / a c c e l e r a t i o n dV( t ) / dt as f u n c t i o n o f X.
4.2. PRELUDE: EULER METHODS                                                                193

                 8
                                                                          50
                                                                         100
                                                                        1000
                 6                                                     10000
                                                                       15000
                                                                       18000
                                                                       20000
                 4                                                    100000


                 2


                 0
             v




                 -2


                 -4


                 -6


                 -8
                      0    1        2        3        4        5        6        7
                                                 t



Figure 4.7: Convergence of the Euler-Verlet method, similarly to figure 4.5. We
observe a faster convergence compared to Euler’s method but that the roundoff errors
make the results unstable for Nt≳ 18, 000. In this figure, float variables have been
used instead of double in order to enhance the effect.



/ / NOTE: T[ 0 ] = 0 T[ Nt −1] = T f i
/ / =========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
c o n s t i n t P = 110000;
double T [ P ] , X [ P ] , V [ P ] ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void euler                 ( c o n s t double& Xin , c o n s t double& Vin ,
                              c o n s t double& Tfi , c o n s t i n t           & Nt ) ;
void euler_cromer ( c o n s t double& Xin , c o n s t double& Vin ,
                              c o n s t double& Tfi , c o n s t i n t           & Nt ) ;
void euler_verlet ( c o n s t double& Xin , c o n s t double& Vin ,
                              c o n s t double& Tfi , c o n s t i n t           & Nt ) ;
double accel               ( c o n s t double& x ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    double Xin , Vin , Tfi ;
    int         Nt , i ;
    string buf ;
    / / The u s e r p r o v i d e s i n i t i a l c o n d i t i o n s X_0 , V_0
194                                    CHAPTER 4. MOTION OF A PARTICLE

    / / f i n a l time t _ f and Nt :
    cout << ” Enter X_0 , V_0 , t _ f , Nt ( t _ i =0) : \ n” ;
    cin >> Xin >> Vin >> Tfi >> Nt ; getline ( cin , buf ) ;
    / / This check i s n e c e s s a r y i n order t o avoid
    / / memory a c c e s s v i o l a t i o n s :
    i f ( Nt>=P ) { cerr << ” Error : Nt>=P\n” ; exit ( 1 ) ; }
    / / Xin= X[ 0 ] , Vin=V[ 0 ] , T[0]=0 and t h e r o u t i n e g i v e s
    / / e v o l u t i o n i n T [ 1 . . Nt −1] , X [ 1 . . Nt −1] , V [ 1 . . Nt −1]
    / / which we p r i n t i n a f i l e
    euler ( Xin , Vin , Tfi , Nt ) ;
    ofstream myfile ( ” e u l e r . dat ” ) ;
    myfile . precision ( 1 7 ) ;
    f o r ( i =0;i<Nt ; i++)
         / / Each l i n e i n f i l e has time , p o s i t i o n , v e l o c i t y :
        myfile << T [ i ] << ” ” << X [ i ] << ” ” << V [ i ] << endl ;
    myfile . close ( ) ; / / we c l o s e t h e stream t o be reused below
    / /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    / / We r e p e a t e v e r y t h i n g f o r each method
    euler_cromer ( Xin , Vin , Tfi , Nt ) ;
    myfile . open ( ” e u l e r _ c r o m e r . dat ” ) ;
    f o r ( i =0;i<Nt ; i++)
        myfile << T [ i ] << ” ” << X [ i ] << ” ” << V [ i ] << endl ;
    myfile . close ( ) ;
    / /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    euler_verlet ( Xin , Vin , Tfi , Nt ) ;
    myfile . open ( ” e u l e r _ v e r l e t . dat ” ) ;
    f o r ( i =0;i<Nt ; i++)
        myfile << T [ i ] << ” ” << X [ i ] << ” ” << V [ i ] << endl ;
    myfile . close ( ) ;
} / / main ( )
/ / =========================================================
/ / Function which r e t u r n s t h e v a l u e o f a c c e l e r a t i o n a t
/ / p o s i t i o n x used i n t h e i n t e g r a t i o n f u n c t i o n s
/ / e u l e r , e u l e r _ c r o m e r and e u l e r _ v e r l e t
/ / =========================================================
double accel ( c o n s t double& x ) {
    r e t u r n −10.0 * sin ( x ) ;
}
/ / =========================================================
/ / D r i v e r r o u t i n e f o r i n t e g r a t i n g e q u a t i o n s o f motion
/ / using t h e Euler method
/ / Input :
/ / Xin=X[ 0 ] , Vin=V[ 0 ] −− i n i t i a l c o n d i t i o n a t t =0 ,
/ / T f i t h e f i n a l time and Nt t h e number o f t i m e s
/ / Output :
/ / The a r r a y s T [ 0 . . Nt −1] , X [ 0 . . Nt −1] , V [ 0 . . Nt −1] which
/ / g i v e s x ( t _ k )=X[ k −1] , dx / dt ( t _ k )=V[ k −1] , t _ k=T[ k−1] k = 1 . . Nt
/ / where f o r k=1 we have t h e i n i t i a l c o n d i t i o n .
/ / =========================================================
4.2. PRELUDE: EULER METHODS                                                                    195

void euler                ( c o n s t double& Xin , c o n s t double& Vin ,
                            c o n s t double& Tfi , c o n s t i n t & Nt ) {
    int           i;
    double h ;
    / / I n i t i a l c o n d i t i o n s s e t here :
    T [0] = 0.0;
    X [ 0 ] = Xin ;
    V [ 0 ] = Vin ;
    / / h i s t h e time s t e p Dt
    h        = Tfi / ( Nt −1) ;
    f o r ( i =1; i<Nt ; i++){
        T [ i ] = T [ i−1]+h ;                  / / time advances by Dt=h
        X [ i ] = X [ i−1]+V [ i −1]* h ; / / advancement and s t o r a g e o f
        V [ i ] = V [ i−1]+accel ( X [ i −1]) * h ; / / p o s i t i o n and v e l o c i t y
    }
} / / euler ()
/ / =========================================================
/ / D r i v e r r o u t i n e f o r i n t e g r a t i n g e q u a t i o n s o f motion
/ / using t h e Euler−Cromer method
/ / Input :
/ / Xin=X[ 0 ] , Vin=V[ 0 ] −− i n i t i a l c o n d i t i o n a t t =0 ,
/ / T f i t h e f i n a l time and Nt t h e number o f t i m e s
/ / Output :
/ / The a r r a y s T [ 0 . . Nt −1] , X [ 0 . . Nt −1] , V [ 0 . . Nt −1] which
/ / g i v e s x ( t _ k )=X[ k −1] , dx / dt ( t _ k )=V[ k −1] , t _ k=T[ k−1] k = 1 . . Nt
/ / where f o r k=1 we have t h e i n i t i a l c o n d i t i o n .
/ / =========================================================
void euler_cromer ( c o n s t double& Xin , c o n s t double& Vin ,
                                  c o n s t double& Tfi , c o n s t i n t         & Nt ) {
    int           i;
    double h ;
    / / I n i t i a l c o n d i t i o n s s e t here :
    T [0] = 0.0;
    X [ 0 ] = Xin ;
    V [ 0 ] = Vin ;
    / / h i s t h e time s t e p Dt
    h        = Tfi / ( Nt −1) ;
    f o r ( i =1; i<Nt ; i++){
        T [ i ] = T [ i−1]+h ;
        V [ i ] = V [ i−1]+accel ( X [ i −1]) * h ;
        X [ i ] = X [ i−1]+V [ i ] * h ; / / note d i f f e r e n c e from Euler
    }

} / / euler_cromer ( )
/ / =========================================================
/ / D r i v e r r o u t i n e f o r i n t e g r a t i n g e q u a t i o n s o f motion
/ / using t h e Euler−V e r l e t method
/ / Input :
/ / Xin=X[ 0 ] , Vin=V[ 0 ] −− i n i t i a l c o n d i t i o n a t t =0 ,
196                                    CHAPTER 4. MOTION OF A PARTICLE

/ / T f i t h e f i n a l time and Nt t h e number o f t i m e s
/ / Output :
/ / The a r r a y s T [ 0 . . Nt −1] , X [ 0 . . Nt −1] , V [ 0 . . Nt −1] which
/ / g i v e s x ( t _ k )=X[ k −1] , dx / dt ( t _ k )=V[ k −1] , t _ k=T[ k−1] k = 1 . . Nt
/ / where f o r k=1 we have t h e i n i t i a l c o n d i t i o n .
/ / =========================================================
void euler_verlet ( c o n s t double& Xin , c o n s t double& Vin ,
                                  c o n s t double& Tfi , c o n s t i n t      & Nt ) {
    int           i;
    double h , h2 , X0 , o2h ;
    / / I n i t i a l c o n d i t i o n s s e t here :
    T[0]             = 0.0;
    X[0]             = Xin ;
    V[0]             = Vin ;
    h                = Tfi / ( Nt −1) ; / / time s t e p
    h2               = h*h ;                  / / time s t e p squared
    o2h              = 0.5/h ;                / / h/2
    / / We have t o i n i t i a l i z e one more s t e p :
    / / X0 c o rre s ponds t o ’X[ −1] ’
    X0               = X [ 0 ] − V [ 0 ] * h + accel ( X [ 0 ] ) * h2 / 2 . 0 ;
    T[1]             = h;
    X[1]             = 2 . 0 * X [ 0 ] − X0         + accel ( X [ 0 ] ) * h2 ;
    / / Now i s t a r t s from 2 :
    f o r ( i =2;i<Nt ; i++){
        T[i]         = T [ i−1] + h ;
        X[i]         = 2 . 0 * X [ i−1] − X [ i−2] + accel ( X [ i −1]) * h2 ;
        V [ i−1] = o2h * ( X [ i]− X [ i −2]) ;
    }
    / / we have one more s t e p f o r t h e v e l o c i t y :
    V [ Nt −1] = ( X [ Nt −1] − X [ Nt −2]) / h ;
} / / euler_verlet ()

Compiling the running the program can be done with the commands:

> g++ euler . cpp −o euler
> . / euler
Enter X_0 , V_0 , t_f , Nt ( t_i =0) :
0.2 0.0 6.0 1000
> l s euler * . dat
euler_cromer . dat euler . dat euler_verlet . dat
> head −n 5 euler . dat
0         0.20000 0
0.00600 0.20000 −0.01193
0.01201 0.19992 −0.02386
0.01801 0.19978 −0.03579
0.02402 0.19957 −0.04771

The last command shows the first 5 lines of the file euler.dat. We see
4.2. PRELUDE: EULER METHODS                                                         197

the data for the time, the position and the velocity stored in 3 columns.
We can graph the results using gnuplot:

gnuplot > p l o t ” e u l e r . dat ” using 1 : 2 with lines
gnuplot > p l o t ” e u l e r . dat ” using 1 : 3 with lines

These commands result in plotting the positions and the velocities as a
function of time respectively. We can add the results of all methods to
the last plot with the commands:

gnuplot > r e p l o t ” e u l e r _ c r o m e r . dat ” using 1 : 3 with lines
gnuplot > r e p l o t ” e u l e r _ v e r l e t . dat ” using 1 : 3 with lines

The results can be seen in figures 4.2–4.7. Euler’s method is unsta-
ble unless we take a quite small time step. The Euler–Cromer method
behaves impressively better. The results converge and remain constant
for Nt∼ 100, 000. The Euler–Verlet method converges much faster, but
roundoff errors kick in soon. This is more obvious in figure 4.7 where
the initial angular position is large⁵. For small angles we can compare
with the solution one obtains for the harmonic pendulum (sin(θ) ≈ θ):
                               g
                   α(θ) = − θ ≡ −Ω2 θ
                                l
                    θ(t) = θ0 cos(Ωt) + (ω0 /Ω) sin(Ωt)
                   ω(t) = ω0 cos(Ωt) − (θ0 Ω) sin(Ωt) .           (4.14)
In figures 4.2–4.4 we observe that the results agree with the above for-
mulas for the values of ∆t where the methods converge. This way we
can check our program for bugs. The plot of the functions above can be
done with the following gnuplot commands⁶:

gnuplot >   s e t dummy t
gnuplot >   omega2 = 10
gnuplot >   X0        = 0.2
gnuplot >   V0        = 0.0
gnuplot >   omega     = s q r t ( omega2 )
gnuplot >   x(t)      = X0 * c o s ( omega * t ) +( V0 / omega ) * s i n ( omega * t )
gnuplot >   v(t)      = V0 * c o s ( omega * t ) −(omega * X0 ) * s i n ( omega * t )
gnuplot >   plot x(t) , v(t)

    ⁵In this figure, roundoff errors are enhanced by using float variables instead of
double.
    ⁶The command set dummy t sets the independent variable for functions to be t
instead of x which is the default.
198                                CHAPTER 4. MOTION OF A PARTICLE

The results should not be compared only graphically since subtle differ-
ences can remain unnoticed. It is more desirable to plot the differences of
the theoretical values from the numerically computed ones which can be
done using the commands:

gnuplot > p l o t ” e u l e r . dat ” using 1 : ( $2−x ( $1 ) ) with lines
gnuplot > p l o t ” e u l e r . dat ” using 1 : ( $3−v ( $1 ) ) with lines

The command using 1:($2-x($1)) puts the values found in the first
column on the x axis and the value found in the second column minus
the value of the function x(t) for t equal to the value found in the first
column on the y axis. This way, we can make the plots shown in⁷ figures
4.11-4.14.


4.3 Runge–Kutta Methods
Euler’s method is a one step finite difference method of first order. First
order means that the total error introduced by the discretization of the
integration interval [ti , tf ] by N discrete times is of order ∼ O(h), where
h ≡ ∆t = (tf − ti )/N is the time step of the integration. In this section we
will discuss a generalization of this approach where the total error will
be of higher order in h. This is the class of Runge-Kutta methods which
are one step algorithms where the total discretization error is of order
∼ O(hp ). The local error introduced at each step is of order ∼ O(hp+1 )
leading after N = (tf − ti )/∆t steps to a maximum error of order

                                       tf − ti             1
      ∼ O(hp+1 ) × N = O(hp+1 ) ×              ∼ O(hp+1 ) × = O(hp ) .             (4.15)
                                         ∆t                h
In such a case we say that we have a Runge-Kutta method of pth order.
The price one has to pay for the increased accuracy is the evaluation of
the derivatives of the functions in more than one points in the interval
(t, t + ∆t).
     Let’s consider for simplicity the problem with only one unknown
function x(t) which evolves in time according to the differential equation:

                            dx
                               = f (t, x) .                  (4.16)
                            dt
Consider the first order method first. The most naive approach would
   ⁷A small modification is necessary in order to plot the absolute value of the differences.
4.3. RUNGE–KUTTA METHODS                                                          199

        x

                                          2

                                              01
                      11
                      00
                      1
                      00
                      11


                          tn               t n+1            t n+2

                                                                         t
                                  h

Figure 4.8: The geometry of the step of the Runge-Kutta method of 1st order given
by equation (4.17).



be to take the derivative to be given by the finite difference

        dx   xn+1 − xn
           ≈           = f (tn , xn ) ⇒ xn+1 = xn + hf (tn , xn ) .             (4.17)
        dt      ∆t

By Taylor expanding, we see that the error at each step is O(h2 ), therefore
the error after integrating from ti → tf is O(h). Indeed,

                               dx
 xn+1 = x(tn + h) = xn + h        (xn ) + O(h2 ) = xn + hf (tn , xn ) + O(h2 ) . (4.18)
                               dt
The geometry of the step is shown in figure 4.8. We start from point 1 and
by linearly extrapolating in the direction of the derivative k1 ≡ f (tn , xn )
we determine the point xn+1 .
    We can improve the method above by introducing an intermediate
point 2. This process is depicted in figure 4.9. We take the point 2
in the middle of the interval (tn , tn+1 ) by making a linear extrapolation
from xn in the direction of the derivative k1 ≡ f (tn , xn ). Then we use the
slope at point 2 as an estimator of the derivative within this interval, i.e.
k2 ≡ f (tn+1/2 , xn+1/2 ) = f (tn + h/2, xn + (h/2)k1 ). We use k2 to linearly
200                                  CHAPTER 4. MOTION OF A PARTICLE

        x
                                                               3

                                           2
                                                    k2

                                               01
                       11
                       00
                       1
                       00k
                       11        1




                            tn             t n+1/2             t n+1

                                                                       t
                                     h/2                 h/2

Figure 4.9: The geometry of an integration step of the 2nd order Runge-Kutta method
given by equation (4.19).



extrapolate from xn to xn+1 . Summarizing, we have that

                              k1 = f (tn , xn )
                                             h   h
                              k2 ≡ f (tn + , xn + k1 )
                                             2   2
                            xn+1 = xn + hk2 .                               (4.19)

For the procedure described above we have to evaluate f twice at each
step, thereby doubling the computational effort. The error at each step
(4.19) becomes ∼ O(h3 ), however, giving a total error of ∼ O(h2 ) ∼
O(1/N 2 ). So for given computational time, (4.19) is superior to (4.17).
    We can further improve the accuracy gain by using the Runge–Kutta
method of 4th order. In this case we have 4 evaluations of the derivative
f per step, but the total error becomes now ∼ O(h4 ) and the method is su-
perior to that of (4.19)⁸. The process followed is explained geometrically
in figure 4.10. We use 3 intermediate points for evolving the solution
from xn to xn+1 . Point 2 is determined by linearly extrapolating from xn
   ⁸Not always though! Higher order does not necessarily mean higher accuracy, al-
though this is true in the simple cases considered here.
4.3. RUNGE–KUTTA METHODS                                                           201

       x

                                             2
                                                  k2
                                             01
                                                                          k4

                      11
                      00
                      1                                               4
                      00k
                      11       1         3
                                                   k3




                          tn                 t n+1/2          t n+1

                                                                               t
                                   h/2                  h/2

Figure 4.10: The geometry of an integration step of the Runge-Kutta method of 4th
order given by equation (4.20).




to the midpoint of the interval (tn , tn+1 = tn + h) by using the direction
given by the derivative k1 ≡ f (tn , xn ), i.e. x2 = xn + (h/2)k1 . We calculate
the derivative k2 ≡ f (tn + h/2, xn + (h/2)k1 ) at the point 2 and we use it
in order to determine point 3, also located at the midpoint of the interval
(tn , tn+1 ). Then we calculate the derivative k3 ≡ f (tn + h/2, xn + (h/2)k2 )
at the point 3 and we use it to linearly extrapolate to the end of the in-
terval (tn , tn+1 ), thereby obtaining point 4, i.e. x4 = xn + hk3 . Then we
calculate the derivative k4 ≡ f (tn + h, xn + hk3 ) at the point 4, and we
use all four derivative k1 , k2 , k3 and k4 as estimators of the derivative of
the function in the interval (tn , tn+1 ). If each derivative contributes with
a particular weight in this estimate, the discretization error can become
202                             CHAPTER 4. MOTION OF A PARTICLE

∼ O(h5 ). Such a choice is



                    k1 = f (tn , xn )
                                   h      h
                    k2 = f (tn + , xn + k1 )
                                   2      2
                                   h      h
                    k3 = f (tn + , xn + k2 )
                                   2      2
                    k4 = f (tn + h, xn + h k3 )
                                 h
                  xn+1 = xn + (k1 + 2k2 + 2k3 + k4 ) .               (4.20)
                                 6



We note that the second term of the last equation takes an average of
the four derivatives with weights 1/6, 1/3, 1/3 and 1/6 respectively. A
generic small change in these values will increase the discretization error
to worse than h5 .

    We remind to the reader the fact that by decreasing h the discretization
errors decrease, but that roundoff errors will start showing up for small
enough h. Therefore, a careful determination of h that minimizes the
total error should be made by studying the dependence of the results as
a function of h.




4.3.1 A Program for the 4th Order Runge–Kutta


Consider the problem of the motion of a particle in one dimension. For
this, we have to integrate a system of two differential equations (4.5) for
two unknown functions of time x1 (t) ≡ x(t) and x2 (t) ≡ v(t) so that



                 dx1                      dx2
                     = f1 (t, x1 , x2 )       = f2 (t, x1 , x2 )     (4.21)
                  dt                       dt
4.3. RUNGE–KUTTA METHODS                                                      203

   In this case, equations (4.20) generalize to:
                  k11 = f1 (tn , x1,n , x2,n )
                  k21 = f2 (tn , x1,n , x2,n )
                                   h           h           h
                  k12 = f1 (tn + , x1,n + k11 , x2,n + k21 )
                                    2          2           2
                                   h           h           h
                  k22 = f2 (tn + , x1,n + k11 , x2,n + k21 )
                                    2          2           2
                                   h           h           h
                  k13 = f1 (tn + , x1,n + k12 , x2,n + k22 )
                                    2          2           2
                                   h           h           h
                  k23 = f2 (tn + , x1,n + k12 , x2,n + k22 )
                                    2          2           2
                  k14 = f1 (tn + h, x1,n + h k13 , x2,n + h k23 )
                  k24 = f2 (tn + h, x1,n + h k13 , x1,n + h k23 )
                                  h
               x1,n+1 = x1,n + (k11 + 2k12 + 2k13 + k14 )
                                  6
                                  h
               x2,n+1 = x1,n + (k21 + 2k22 + 2k23 + k24 ) .                 (4.22)
                                  6
    Programming this algorithm is quite simple. The main program is
an interface between the user and the driver routine of the integration.
The user enters the initial and final times ti = Ti and tf = Tf and the
number of discrete time points Nt. The initial conditions are x1 (ti ) = X10,
x2 (ti ) = X20. The main data structure consists of three global double ar-
rays T[P], X1[P], X2[P] which store the times ti ≡ t1 , t2 , . . . , tNt ≡ tf and
the corresponding values of the functions x1 (tk ) and x2 (tk ), k = 1, . . . , Nt.
The main program calls the driver routine RK(Ti,Tf,X10,X20,Nt) which
“drives” the heart of the program, the function RKSTEP(t,x1,x2,dt)
which performs one integration step using equations (4.22). RKSTEP
evolves the functions x1, x2 at time t by one step h = dt. The func-
tion RK stores the calculated values in the arrays T, X1 and X2 at each
step. When RK returns the control to the main program, all the results
are stored in T, X1 and X2, which are subsequently printed in the file
rk.dat. The full program is listed below and can be found in the file
rk.cpp:

/ / ========================================================
/ / Program t o s o l v e a 2 ODE system using Runge−Kutta Method
/ / User must supply d e r i v a t i v e s
/ / dx1 / dt= f 1 ( t , x1 , x2 ) dx2 / dt=f 2 ( t , x1 , x2 )
/ / as r e a l f u n c t i o n s
/ / Output i s w r i t t e n i n f i l e rk . dat
204                              CHAPTER 4. MOTION OF A PARTICLE

/ / ========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
c o n s t i n t P = 110000;
double T [ P ] , X1 [ P ] , X2 [ P ] ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
f1 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ) ;
double
f2 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ) ;
void
RK ( c o n s t double& Ti , c o n s t double& Tf , c o n s t double& X10 ,
      c o n s t double& X20 , c o n s t i n t & Nt ) ;
void
RKSTEP ( double& t , double& x1 , double& x2 ,
              c o n s t double& dt ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    double Ti , Tf , X10 , X20 ;
    int          Nt ;
    int            i;
    string buf ;

    / / Input :
    cout << ”Runge−Kutta Method f o r 2−ODEs I n t e g r a t i o n \n” ;
    cout << ” Enter Nt , Ti , TF , X10 , X20 : ”      << endl ;
    cin >> Nt >> Ti >> Tf >> X10 >> X20 ; getline ( cin , buf ) ;
    cout << ” Nt = ”                           << Nt << endl ;
    cout << ”Time : I n i t i a l Ti = ” << Ti
             << ” F i n a l Tf = ”             << Tf << endl ;
    cout << ”                      X1( Ti )= ” << X10
             << ” X2( Ti )= ”                  << X20 << endl ;
    i f ( Nt >= P ) { cerr << ” Error ! Nt >= P\n” ; exit ( 1 ) ; }
    / / Calculate :
    RK ( Ti , Tf , X10 , X20 , Nt ) ;
    / / Output :
    ofstream myfile ( ” rk . dat ” ) ;
    myfile . precision ( 1 7 ) ;
    f o r ( i =0;i<Nt ; i++)
        myfile << T [ i ] << ” ”
                   << X1 [ i ] << ” ”
                   << X2 [ i ] << ’\n ’ ;
    myfile . close ( ) ;
} / / main ( )
4.3. RUNGE–KUTTA METHODS                                                        205

/ / ========================================================
/ / The f u n c t i o n s f1 , f 2 ( t , x1 , x2 ) provided by t h e u s e r
/ / ========================================================
double
f1 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ) {
    r e t u r n x2 ;
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
f2 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ) {
    r e t u r n −10.0* x1 ; / / harmonic o s c i l l a t o r
}
/ / ========================================================
/ / RK( Ti , Tf , X10 , X20 , Nt ) i s t h e d r i v e r
/ / f o r t h e Runge−Kutta i n t e g r a t i o n r o u t i n e RKSTEP
/ / Input : I n i t i a l and f i n a l t i m e s Ti , Tf
//                 I n i t i a l v a l u e s a t t =Ti X10 , X20
//                Number o f s t e p s o f i n t e g r a t i o n : Nt−1
/ / Output : v a l u e s i n a r r a y s T[ Nt ] , X1 [ Nt ] , X2[ Nt ] where
/ / T[ 0 ]          = Ti X1 [ 0 ]           = X10 X2[ 0 ] = X20
//                            X1 [ k−1] = X1( a t t =T( k ) )
//                            X2[ k−1] = X2( a t t =T( k ) )
/ / T[ Nt −1] = Tf
/ / ========================================================
void
RK ( c o n s t double& Ti , c o n s t double& Tf , c o n s t double& X10 ,
      c o n s t double& X20 , c o n s t i n t            & Nt ) {
    double dt ;
    double TS , X1S , X2S ; / / time and X1 , X2 a t g i v e n s t e p
    int             i;
    / / I n i t i a l i z e variables :
    dt              = ( Tf−Ti ) / ( Nt −1) ;
    T [0]           = Ti ;
    X1 [ 0 ]        = X10 ;
    X2 [ 0 ]        = X20 ;
    TS              = Ti ;
    X1S             = X10 ;
    X2S             = X20 ;
    / / Make RK s t e p s : The arguments o f RKSTEP a r e
    / / r e p l a c e d with t h e new ones !
    f o r ( i =1; i<Nt ; i++){
        RKSTEP ( TS , X1S , X2S , dt ) ;
        T [ i ] = TS ;
        X1 [ i ] = X1S ;
        X2 [ i ] = X2S ;
    }
} / / RK( )
/ / ========================================================
/ / Function RKSTEP( t , x1 , x2 , dt )
206                                    CHAPTER 4. MOTION OF A PARTICLE

/ / Runge−Kutta I n t e g r a t i o n r o u t i n e o f ODE
/ / dx1 / dt= f 1 ( t , x1 , x2 ) dx2 / dt=f 2 ( t , x1 , x2 )
/ / User must supply d e r i v a t i v e f u n c t i o n s :
/ / r e a l f u n c t i o n f 1 ( t , x1 , x2 )
/ / r e a l f u n c t i o n f 2 ( t , x1 , x2 )
/ / Given i n i t i a l p o i n t ( t , x1 , x2 ) t h e r o u t i n e advances i t
/ / by time dt .
/ / Input : I n i t a l time t                  and f u n c t i o n v a l u e s x1 , x2
/ / Output : F i n a l time t +dt and f u n c t i o n v a l u e s x1 , x2
/ / C a r e f u l ! : v a l u e s o f t , x1 , x2 a r e o v e r w r i t t e n . . .
/ / ========================================================
void
RKSTEP ( double& t , double& x1 , double& x2 ,
              c o n s t double& dt ) {
    double k11 , k12 , k13 , k14 , k21 , k22 , k23 , k24 ;
    double h , h2 , h6 ;

  h =dt ;         / / h =dt , i n t e g r a t i o n s t e p
  h2 =0.5* h ; / / h2=h / 2
  h6 =h / 6 . 0 ; / / h6=h / 6

   k11=f1 ( t , x1 , x2 ) ;
   k21=f2 ( t , x1 , x2 ) ;
   k12=f1 ( t+h2 , x1+h2 * k11 , x2+h2 * k21 ) ;
   k22=f2 ( t+h2 , x1+h2 * k11 , x2+h2 * k21 ) ;
   k13=f1 ( t+h2 , x1+h2 * k12 , x2+h2 * k22 ) ;
   k23=f2 ( t+h2 , x1+h2 * k12 , x2+h2 * k22 ) ;
   k14=f1 ( t+h , x1+h * k13 , x2+h * k23 ) ;
   k24=f2 ( t+h , x1+h * k13 , x2+h * k23 ) ;

  t =t+h ;
  x1 =x1+h6 * ( k11 + 2 . 0 * ( k12+k13 )+k14 ) ;
  x2 =x2+h6 * ( k21 + 2 . 0 * ( k22+k23 )+k24 ) ;

} / / RKSTEP ( )




4.4 Comparison of the Methods
In this section we will check our programs for correctness and accuracy
w.r.t. discretization and roundoff errors. The simplest test is to check the
results against a known analytic solution of a simple model. This will
be done for the simple harmonic oscillator. We will change the functions
that compute the acceleration of the particle to give a = −ω 2 x. We will
take ω 2 = 10 (T ≈ 1.987). Therefore the relevant part of the program in
euler.cpp becomes
4.4. COMPARISON OF THE METHODS                                                          207

                   100
                                                                        50
                                                                       500
                                                                      5000
                                                                     50000
                     1



                   0.01



                  1e-04
             δx




                  1e-06



                  1e-08



                  1e-10



                  1e-12
                          0.1                        1                       10
                                                     t



Figure 4.11: The discrepancy of the numerical results of the Euler method from the
analytic solution for the simple harmonic oscillator. The parameters chosen are ω 2 = 10,
ti = 0, tf = 6, x(0) = 0.2, v(0) = 0 and the number of steps is N = 50, 500, 5, 000, 50, 000.
Observe that the error becomes approximately ten times smaller each time according to
the expectation of being of order ∼ O(∆t).




double accel ( c o n s t double& x ) {
  r e t u r n −10.0 * x ;
}

and that of the program in rk.cpp becomes

double
f2 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ) {
   r e t u r n −10.0* x1 ;
}

   The programs are run for a given time interval ti = 0 to tf = 6 with
the initial conditions x0 = 0.2, v0 = 0. The time step ∆t is varied by
varying the number of steps Nt-1. The computed numerical solution is
compared to the well known solution for the simple harmonic oscillator

                                 a(x) = −ω 2 x
                                xh (t) = x0 cos(ωt) + (v0 /ω) sin(ωt)
                                vh (t) = v0 cos(ωt) − (x0 ω) sin(ωt) ,               (4.23)

We study the deviation δx(t) = |x(t) − xh (t)| and δv(t) = |v(t) − vh (t)| as a
208                               CHAPTER 4. MOTION OF A PARTICLE

                   0.1
                                                                   50
                                                                  500
                                                                 5000
                  0.01                                          50000


                 0.001


                 1e-04


                 1e-05
            δx




                 1e-06


                 1e-07


                 1e-08


                 1e-09


                 1e-10
                         0.1                  1                          10
                                              t



Figure 4.12: Like in figure 4.11 for the Euler-Cromer method. The error becomes
approximately ten times smaller each time according to the expectation of being of order
∼ O(∆t).




function of the time step ∆t. The results are shown in figures 4.11–4.14.
We note that for the Euler method and the Euler–Cromer method, the
errors are of order O(∆t) as expected. However, the latter has smaller
errors compared to the first one. For the Euler–Verlet method, the error
turns out to be of order O(∆t2 ) whereas for the 4th order Runge–Kutta
is of order⁹ O(∆t4 ).
   Another way for checking the numerical results is by looking at a
conserved quantity, like the energy, momentum or angular momentum,
and study its deviation from its original value. In our case we study the
mechanical energy

                                  1      1
                               E = mv 2 + mω 2 x2                               (4.24)
                                  2      2

which is computed at each step. The deviation δE = |E − E0 | is shown
in figures 4.15–4.18.


   ⁹The reader should confirm these claims, initially by looking at the figures 4.11-4.14
and then by reproducing these results. A particular time t can be chosen and the errors
can be plotted against ∆t, ∆t2 and ∆t4 respectively.
4.5. THE FORCED DAMPED OSCILLATOR                                                                 209

                      1
                                                                                   50
                                                                                  500
                                                                                 5000
                                                                                50000
                    0.01



                   1e-04



                   1e-06
              δx




                   1e-08



                   1e-10



                   1e-12



                   1e-14
                           0.1                                1                          10
                                                              t



Figure 4.13: Like in figure 4.11 for the Euler-Verlet method. The error becomes
approximately 100 times smaller each time according to the expectation of being of
order ∼ O(∆t2 ).



4.5        The Forced Damped Oscillator
In this section we will study a simple harmonic oscillator subject to a
damping force proportional to its velocity and an external periodic driving
force, which for simplicity will be taken to have a sinusoidal dependence
in time,
                       d2 x    dx
                          2
                            +γ     + ω02 x = a0 sin ωt ,             (4.25)
                       dt       dt
where F (t) = ma0 sin ωt and ω is the angular frequency of the driving
force.
    Consider initially the system without the influence of the driving force,
i.e. with a0 = 0. The real solutions of the differential equation¹⁰ which
are finite for t → +∞ are given by
                             √                              √ 2 2
     x0 (t) = c1 e−(γ+           γ 2 −4ω02 )t/2
                                                  + c2 e−(γ− γ −4ω0 )t/2 ,   γ 2 − 4ω02 > 0 ,   (4.26)


                      x0 (t) = c1 e−γt/2 + c2 e−γt/2 t ,             γ 2 − 4ω02 = 0 ,           (4.27)

     ¹⁰These are easily obtained by substituting the ansatz x(t) = Ae−Ωt and solving for
Ω.
210                                   CHAPTER 4. MOTION OF A PARTICLE

                 0.01
                                                               50
                                                              500
                                                             5000
                1e-04                                       50000



                1e-06


                1e-08
           δx




                1e-10


                1e-12


                1e-14


                1e-16


                1e-18
                        0.1                 1                       10
                                            t



Figure 4.14: Like in figure 4.11 for the 4th order Runge–Kutta method. The error
becomes approximately 10−4 times smaller each time according to the expectation of
being of order ∼ O(∆t4 ). The roundoff errors become apparent for 50, 000 steps.


                             (√                )
                              −γt/2
      x0 (t) = c1 e      cos      −γ + 4ω0 t/2
                                    2    2

                                  (√             )
                        −γt/2
                  +c2 e       sin    −γ + 4ω0 t/2 ,
                                       2     2
                                                            γ 2 − 4ω02 < 0 .(4.28)

In the last case, the solution oscillates with an amplitude decreasing ex-
ponentially with time.
    In the a0 > 0 case, the general solution is obtained from the sum
of a special solution xs (t) and the solution of the homogeneous equation
x0 (t). A special solution can be obtained from the ansatz xs (t) = A sin ωt+
B cos ωt, which when substituted in (4.25) and solved for A and B we
find that
                            a0 [(ω02 − ω 2 ) cos ωt + γω sin ωt]
                   xs (t) =                                      ,     (4.29)
                                     (ω02 − ω 2 )2 + ω 2 γ 2
and
                              x(t) = x0 (t) + xs (t) .                 (4.30)
The solution x0 (t) decreases exponentially with time and eventually only
xs (t) remains. The only case where this is not true, is when we have
resonance without damping for ω = ω0 , γ = 0. In that case the solution
is
                                       a0
        x(t) = c1 cos ωt + c2 sin ωt + 2 (cos ωt + 2(ωt) sin ωt) . (4.31)
                                      4ω
4.5. THE FORCED DAMPED OSCILLATOR                                                 211

                1000
                                                                  50
                                                                 500
                                                                5000
                 100                                           50000



                  10


                   1
           δE




                  0.1


                 0.01


                0.001


                1e-04


                1e-05
                        0.1                   1                         10
                                              t



Figure 4.15:        Like in figure 4.11 for the case of mechanical energy for the Euler
method.




The first two terms are the same as that of the simple harmonic oscillator.
The last one increases the amplitude linearly with time, which is a result
of the influx of energy from the external force to the oscillator.
    Our program will be a simple modification of the program in rk.cpp.
The main routines RK(T0,TF,X10,X20,Nt) and RKSTEP(t,x1,x2,dt) re-
main as they are. We only change the user interface. The basic param-
eters ω0 , ω, γ, a0 are entered interactively by the user from the standard
input stdin. These parameters should be accessible also by the function
f2(t,x1,x2) and they are declared within the global scope. Another
point that needs our attention is the function f2(t,x1,x2) which now
takes the velocity v → x2 in its arguments:

double
f2 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ) {
   double a ;
   a = a_0 * cos ( omega * t ) ;
   r e t u r n −omega_02 * x1−gam * x2+a ;
}


The main program, found in the file dlo.cpp, is listed below. The func-
tions RK, RKSTEP are the same as in rk.cpp and should also be included
in the same file.
212                                CHAPTER 4. MOTION OF A PARTICLE

                  0.1
                                                                  50
                                                                 500
                                                                5000
                 0.01                                          50000


                0.001


                1e-04


                1e-05
           δE




                1e-06


                1e-07


                1e-08


                1e-09


                1e-10
                        0.1                   1                         10
                                              t



Figure 4.16:       Like in figure 4.11 for the case of mechanical energy for the Euler–
Cromer method.




/ / ========================================================
/ / Program t o s o l v e Damped Lin ea r O s c i l l a t o r
/ / using 4 th order Runge−Kutta Method
/ / Output i s w r i t t e n i n f i l e dlo . dat
/ / ========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
c o n s t i n t P = 110000;
double T [ P ] , X1 [ P ] , X2 [ P ] ;
double omega_0 , omega , gam , a_0 , omega_02 , omega2 ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
f1 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ) ;
double
f2 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ) ;
void
RK ( c o n s t double& Ti , c o n s t double& Tf , c o n s t double& X10 ,
      c o n s t double& X20 , c o n s t i n t    & Nt ) ;
void
RKSTEP ( double& t , double& x1 , double& x2 ,
              c o n s t double& dt ) ;
4.5. THE FORCED DAMPED OSCILLATOR                                                213

                    1
                                                                  50
                                                                 500
                                                                5000
                  0.01                                         50000



                 1e-04


                 1e-06
            δE




                 1e-08


                 1e-10


                 1e-12


                 1e-14


                 1e-16
                         0.1                 1                         10
                                             t



Figure 4.17: Like in figure 4.11 for the case of mechanical energy for the Euler–Verlet
method.



/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    double Ti , Tf , X10 , X20 ;
    double Energy ;
    int      Nt ;
    int        i;
    string buf ;

  / / Input :
  cout << ”Runge−Kutta Method f o r DLO I n t e g r a t i o n \n” ;
  cout << ” Enter omega_0 , omega , gamma , a_0 : \ n” ;
  cin >> omega_0 >> omega >> gam>> a_0 ; getline ( cin , buf ) ;
  omega_02 = omega_0 * omega_0 ;
  omega2      = omega * omega ;
  cout << ”omega_0= ” << omega_0
          << ” omega= ” << omega                 << endl ;
  cout << ”gamma=          ” << gamma
          << ” a_0=        ” << a_0              << endl ;
  cout << ” Enter Nt , Ti , TF , X10 , X20 : ”   << endl ;
  cin >> Nt >> Ti >> Tf >> X10 >> X20 ; getline ( cin , buf ) ;
  cout << ” Nt = ”                        << Nt << endl ;
  cout << ”Time : I n i t i a l Ti = ” << Ti
          << ” F i n a l Tf = ”           << Tf << endl ;
  cout << ”                  X1 ( Ti )= ” << X10
          << ” X2( Ti )= ”                << X20 << endl ;
  i f ( Nt >= P ) { cerr << ” Error ! Nt >= P\n” ; exit ( 1 ) ; }
  / / Calculate :
214                                CHAPTER 4. MOTION OF A PARTICLE

                  0.01
                                                                     50
                                                                    500
                                                                   5000
                                                                  50000
                 1e-04



                 1e-06



                 1e-08
            δE




                 1e-10



                 1e-12



                 1e-14



                 1e-16
                         0.1                    1                          10
                                                t



Figure 4.18: Like in figure 4.11 for the case of mechanical energy for the 4th order
Runge–Kutta method. Roundoff errors appear for large enough number of steps.




    RK ( Ti , Tf , X10 , X20 , Nt ) ;
    / / Output :
    ofstream myfile ( ” dlo . dat ” ) ;
    myfile . precision ( 1 7 ) ;
    myfile << ” # Damped Lin ea r O s c i l l a t o r − dlo \n” ;
    myfile << ” # omega_0= ” << omega_0 << ” omega= ” << omega
                << ”       gamma= ” << gam                 << ”      a_0= ” << a_0 << ←-
                     endl ;
    f o r ( i =0;i<Nt ; i++){
        Energy = 0 . 5 * X2 [ i ] * X2 [ i ] + 0 . 5 * omega_02 * X1 [ i ] * X1 [ i ] ;
        myfile << T [ i ] << ” ”
                   << X1 [ i ] << ” ”
                   << X2 [ i ] << ” ”
                   << Energy << ’\n ’ ;
    }
    myfile . close ( ) ;
} / / main ( )
/ / ========================================================
/ / The f u n c t i o n s f1 , f 2 ( t , x1 , x2 ) provided by t h e u s e r
/ / ========================================================
double
f1 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ) {
    r e t u r n x2 ;
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
4.5. THE FORCED DAMPED OSCILLATOR                                               215

f2 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ) {
   double a ;
   a = a_0 * cos ( omega * t ) ;
   r e t u r n −omega_02 * x1−gam * x2+a ;
}


                5
                                                                6.29
                                                                3.15
                4                                               1.57
                                                                0.32

                3


                2


                1


                0
            x




                -1


                -2


                -3


                -4


                -5
                     0        2       4          6          8          10
                                            t



Figure 4.19: The position as a function of time for the damped oscillator for several
values of γ and ω0 = 3.145.



   The results are shown in figures 4.19–4.22. Figure 4.19 shows the
transition from a damped motion for γ > 2ω0 to an oscillating motion
with damping amplitude for γ < 2ω0 . The exponential decrease of the
amplitude is shown in figure 4.21, whereas the dependence of the period
T from the damping coefficient γ is shown in figure 4.22. Motivated by
equation (4.28), written in the form
                                  ( )
                                    2π
                            4ω0 −
                              2
                                       = γ2 ,                   (4.32)
                                    T

we construct the plot in figure 4.22. The right hand side of the equation
is put on the horizontal axis, whereas the left hand side on the vertical.
Equation (4.32) predicts that both quantities are equal and all measure-
ments should lie on a particular line, the diagonal y = x. The period T
can be estimated from the time between two consecutive extrema of x(t)
or two consecutive zeros of the velocity v(t) (see figure 4.19).
    Finally it is important to study the trajectory of the system in phase
216                                      CHAPTER 4. MOTION OF A PARTICLE

          15
                                                     6.29
                                                     3.15
                                                     1.57
                                                     0.32
          10




           5




           0
      v




           -5




          -10




          -15
                -5   -4   -3   -2   -1   0   1   2   3      4   5
                                         x


Figure 4.20: The phase space trajectory for the damped oscillator for several values
of γ and ω0 = 3.145. Note the attractor at (x, v) = (0, 0) where all trajectories are
“attracted to” as t → +∞.



space. This can be seen¹¹ in figure 4.20. A point in this space is a state of
the system and a trajectory describes the evolution of the system’s states
in time. We see that all such trajectories end up as t → +∞ to the point
(0, 0), independently of the initial conditions. Such a point is an example
of a system’s attractor.
    Next, we add the external force and study the response of the system
to it. The system exhibits a transient behavior that depends on the initial
conditions. For large enough times it approaches a steady state that does
not depend on (almost all of) the initial conditions. This can be seen in
figure 4.23. This is easily understood for our system by looking at equa-
tions (4.26)–(4.28). We see that the steady state xs (t) becomes dominant
when the exponentials have damped away. xs (t) can be written in the
form

            x(t) = x0 (ω) cos(ωt + δ(ω))
                             a0                                               ωγ
           x0 (ω) = √ 2                      ,              tan δ(ω) =              .   (4.33)
                      (ω0 − ω 2 )2 + γ 2 ω 2                             ω2   − ω02
   ¹¹To be precise, phase space is the space of positions-momenta, but in our case the
difference is trivial.
4.6. THE FORCED DAMPED PENDULUM                                                     217

                   10
                                                                         1.0
                                                                         0.8
                                                                         0.6
                                                                         0.4
                                                                         0.2
                                                                         0.1



                    1
      Amplitude




                   0.1




                  0.01
                         0    5      10     15     20     25     30      35    40
                                                    t


Figure 4.21: The amplitude of oscillation for the damped oscillator for several
values of γ and ω0 = 3.145. Note the exponential damping of the amplitude with time.



These equations are verified in figure 4.24 where we study the depen-
dence of the amplitude x0 (ω) on the angular frequency of the driving
force. Finally we study the trajectory of the system in phase space. As
we can see in figure 4.20, this time the attractor is an ellipse, which is
a one dimensional curve instead of a zero dimensional point. For large
enough times, all trajectories approach their attractor asymptotically.


4.6               The Forced Damped Pendulum
In this section we will study a non-linear dynamical system which ex-
hibits interesting chaotic behavior. This is a simple model which, despite
its deterministic nature, the prediction of its future behavior becomes in-
tractable after a short period of time. Consider a simple pendulum in a
constant gravitational field whose motion is damped by a force propor-
tional to its velocity and it is under the influence of a vertical, harmonic
external driving force:

                             d2 θ    dθ
                                2
                                  + γ + ω02 sin θ = −2A cos ωt sin θ .          (4.34)
                             dt      dt
218                               CHAPTER 4. MOTION OF A PARTICLE




                         10
                     2
      4 ω0 - (2 π/T)
          2




                         1




                              1                             10
                                            γ2


Figure 4.22: The period of oscillation of the damped oscillator for several values of
γ and ω0 = 3.145. The axes are chosen so that equation (4.28) (2π/T )2 = 4ω02 − γ 2 can
be easily verified. The points in the plot are our measurements whereas the straight
line is the theoretical prediction, the diagonal y = x




In the equation above, θ is the angle of the pendulum with the vertical
axis, γ is the damping coefficient, ω02 = g/L is the pendulum’s natural
angular frequency, ω is the angular frequency of the driving force and
2A is the amplitude of the external angular acceleration caused by the
driving force.
    In the absence of the driving force, the damping coefficient drives the
system to the point (θ, θ̇) = (0, 0), which is an attractor for the system.
This continues to happen for small enough A, but for A > Ac the behavior
of the system becomes more complicated.
    The program that integrates the equations of motion of the system can
be obtained by making trivial changes to the program in the file dlo.cpp.
This changes are listed in detail below, but we note that X1 ↔ θ, X2 ↔ θ̇,
a_0 ↔ A. The final program can be found in the file fdp.cpp. It is listed
below, with the understanding that the commands in between the dots
are the same as in the programs found in the files dlo.cpp, rk.cpp.

/ / ========================================================
4.6. THE FORCED DAMPED PENDULUM                                                            219

               1
                                                                      x0=1 v0=0
                                                                      x0=0 v0=1
             0.8


             0.6


             0.4


             0.2
      x(t)




               0


             -0.2


             -0.4


             -0.6


             -0.8
                    0   10          20          30          40          50            60
                                                t


Figure 4.23: The period of oscillation for the forced damped oscillator for different
initial conditions. We have chosen ω0 = 3.145, ω = 2.0, γ = 0.5 and a0 = 1.0. We
note that after the transient behavior the system oscillates harmonically according to
the relation x(t) = x0 (ω) cos(ωt + δ).




/ / Program t o s o l v e Forced Damped Pendulum
/ / using 4 th order Runge−Kutta Method
/ / Output i s w r i t t e n i n f i l e fdp . dat
/ / ========================================================
   ................................
c o n s t i n t P = 1010000;
   ................................
        Energy = 0 . 5 * X2 [ i ] * X2 [ i ]+ omega_02 *(1.0 − cos ( X1 [ i ] ) ) ;
   ................................
double
f2 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ) {
    r e t u r n −(omega_02 +2.0* a_0 * cos ( omega * t ) ) * sin ( x1 )−gam * x2 ;
}
   ................................
void
RKSTEP ( double& t , double& x1 , double& x2 ,
              c o n s t double& dt ) {
   ................................
    c o n s t double pi = 3.14159265358979324;
    c o n s t double pi2= 6.28318530717958648;
    x1 =x1+h6 * ( k11 + 2 . 0 * ( k12+k13 )+k14 ) ;
220                                 CHAPTER 4. MOTION OF A PARTICLE

              0.7



              0.6



              0.5



              0.4
      x0(ω)




              0.3



              0.2



              0.1



               0
                    1   1.5    2       2.5      3     3.5      4      4.5      5
                                                ω


Figure 4.24:       The oscillation amplitude x0 (ω) as a function of ω for the forced
damped oscillator, where ω0 = 3.145, γ = 0.5 and a0 = 1.0. We observe a resonance
for ω ≈ ω0 . The points of the plot are our measurements and the line is the theoretical
prediction given by equation (4.33).



    x2 =x2+h6 * ( k21 + 2 . 0 * ( k22+k23 )+k24 ) ;
    i f ( x1 > pi ) x1 −= pi2 ;
    i f ( x1 < −pi ) x1 += pi2 ;
} / / RKSTEP ( )

The final lines in the program are added so that the angle is kept within
the interval [−π, π].
    In order to study the system’s properties we will set ω0 = 1, ω = 2,
and γ = 0.2 unless we explicitly state otherwise. The natural period
of the pendulum is T0 = 2π/ω0 = 2π ≈ 6.28318530717958648 whereas
that of the driving force is T = 2π/ω = π ≈ 3.14159265358979324. For
A < Ac , with Ac ≈ 0.18, the point (θ, θ̇) = (0, 0) is an attractor, which
means that the pendulum eventually stops at its stable equilibrium point.
For Ac < A < 0.71 the attractor is a closed curve, which means that
the pendulum at its steady state oscillates indefinitely without circling
through its unstable equilibrium point at θ = ±π. The period of motion
is found to be twice that of the driving force. For 0.72 < A < 0.79
the attractor is an open curve, because at its steady state the pendulum
crosses the θ = ±π point. The period of the motion becomes equal to
4.6. THE FORCED DAMPED PENDULUM                                                       221

            2


          1.5


            1


          0.5


            0


          -0.5
      v




           -1


          -1.5


           -2


          -2.5


           -3
             -0.8   -0.6   -0.4   -0.2   0       0.2   0.4   0.6   0.8   1
                                             x


Figure 4.25: A phase space trajectory of the forced damped oscillator with ω0 =
3.145, ω = 2.0, γ = 0.5 and a0 = 1.0. The harmonic oscillation which is the steady state
of the system is an ellipse, which is an attractor of all the phase space trajectories that
correspond to different initial conditions.



that of the driving force. For 0.79 < A ≲ 1.033 we have period doubling
for critical values of A, but the trajectory is still periodic. For even larger
values of A the system enters into a chaotic regime where the trajectories
are non periodic. For A ≈ 3.1 we find the system in a periodic steady
state again, whereas for A ≈ 3.8 – 4.448 we have period doubling. For
A ≈ 4.4489 we enter into a chaotic regime again etc. These results can
be seen in figures 4.27–4.29. The reader should construct the bifurcation
diagram of the system by solving problem 19 of this chapter.
    We can also use the so called Poincaré diagrams in order to study the
chaotic behavior of a system. These are obtained by placing a point in
phase space when the time is an integer multiple of the period of the
driving force. Then, if for example the period of the motion is equal
to that of the period of the driving force, the Poincaré diagram consists
of only one point. If the period of the motion is an n–multiple of the
period of the driving force then the Poincaré diagram consists of only
n points. Therefore, in the period doubling regime, the points of the
Poincaré diagram double at each period doubling point. In the chaotic
regime, the Poincaré diagram consists of an infinite number of points
222                                         CHAPTER 4. MOTION OF A PARTICLE

          0.4


          0.3


          0.2


          0.1


            0
      v




          -0.1


          -0.2


          -0.3


          -0.4
              -0.2   -0.15   -0.1   -0.05    0   0.05   0.1   0.15   0.2
                                             x


Figure 4.26: The trajectory shown in figure 4.25 for t > 100. The trajectory is
almost on top of an ellipse corresponding to the steady state motion of the system. This
ellipse is an attractor of the system.



which belong to sets that have interesting fractal structure. One way to
construct the Poincaré diagram numerically, is to process the data of the
output file fdp.dat using awk¹²:

awk −v o=$omega −v nt=$Nt −v tf=$TF \
 ’BEGIN{T =6.283185307179/ o ; dt=tf / nt ; } $1%T<dt { p r i n t $2 , $3 } ’\
 fdp . dat

where $omega, $Nt, $TF are the values of the angular frequency ω, the
number of points of time and the final time tf . We calculate the period T
and the time step dt in the program. Then we print those lines of the file
where the time is an integer multiple of the period¹³. This is accomplished
by the modulo operation $1 % T. The value of the expression $1 % T <
dt is true when the remainder of the division of the first column ($1) of
the file fdp.dat with the period T is smaller than dt. The results in the
   ¹²The command can be written in one line without the final \ of the first and second
lines.
   ¹³The accuracy of this condition is limited by dt, which makes the points in the
Poincaré diagram slightly fuzzy.
4.7. APPENDIX: ON THE EULER–VERLET METHOD                                                                   223

        2                                                    -1.4



      1.5
                                                             -1.6


        1
                                                             -1.8

      0.5
                                                              -2

        0

                                                             -2.2
      -0.5

                                                             -2.4
       -1


                                                             -2.6
      -1.5



       -2                                                    -2.8
             -2   -1.5   -1   -0.5   0   0.5   1   1.5   2          -4   -3   -2   -1   0   1   2   3   4

        3                                                    -0.5


      2.8
                                                              -1
      2.6


      2.4                                                    -1.5


      2.2
                                                              -2
        2


      1.8                                                    -2.5


      1.6
                                                              -3
      1.4


      1.2                                                    -3.5
             -4   -3     -2   -1     0   1     2   3     4          -4   -3   -2   -1   0   1   2   3   4




Figure 4.27:      A phase space trajectory of the forced damped pendulum. The
parameters chosen are ω0 = 1.0, ω = 2.0, γ = 0.2 and A = 0.60, 0.72, 0.85, 1.02. We
observe the phenomenon of period doubling.



chaotic regime are displayed in figure 4.30.
    We close this section by discussing another concept that helps us in
the analysis of the dynamical properties of the pendulum. This is the
concept of the basin of attraction which is the set of initial conditions in
phase space that lead the system to a specific attractor. Take for example
the case for A > 0.79 in the regime where the pendulum at its steady
state has a circular trajectory with a positive or negative direction. By
taking a large sample of initial conditions and recording the direction of
the resulting motion after the transient behavior, we obtain figure 4.31.


4.7               Appendix: On the Euler–Verlet Method
Equations (4.11) can be obtained from the Taylor expansion

                                  (∆t)2 ′′         (∆t)3 ′′′
  θ(t + ∆t) = θ(t) + (∆t)θ′ (t) +        θ (t) +          θ (t) + O((∆t)4 )
                                   2!               3!
                                       2                3
                                  (∆t)             (∆t)
  θ(t − ∆t) = θ(t) − (∆t)θ′ (t) +        θ′′ (t) −        θ′′′ (t) + O((∆t)4 ) .
                                    2!               3!
224                                                   CHAPTER 4. MOTION OF A PARTICLE

      -0.5                                                  -0.5




       -1                                                        -1




      -1.5                                                  -1.5




       -2                                                        -2




      -2.5                                                  -2.5




       -3                                                        -3




      -3.5                                                  -3.5
             -4   -3   -2   -1   0    1   2   3   4                   -4        -3        -2        -1       0       1       2       3       4

      -0.5                                                  5


                                                            4

       -1
                                                            3


                                                            2
      -1.5

                                                            1


       -2                                                   0


                                                            -1

      -2.5
                                                            -2


                                                            -3
       -3

                                                            -4


      -3.5                                                  -5
             -4   -3   -2   -1   0    1   2   3   4              -4        -3        -2        -1        0       1       2       3       4




Figure 4.28:        A phase space trajectory of the forced damped pendulum. The
parameters chosen are ω0 = 1.0, ω = 2.0, γ = 0.2 and A = 1.031, 1.033, 1.04, 1.4. We
observe the chaotic behavior of the system.



By adding and subtracting the above equations we obtain

                  θ(t + ∆t) + θ(t − ∆t) = 2θ(t) + (∆t)2 θ′′ (t) + O((∆t)4 )
                  θ(t + ∆t) − θ(t − ∆t) = 2(∆t)θ′ (t) + O((∆t)3 )                                                                                (4.35)

which give equations (4.11)

                   θ(t + ∆t) = 2θ(t) − θ(t − ∆t) + (∆t)2 α(t) + O((∆t)4 )
                               θ(t + ∆t) − θ(t − ∆t)
                        ω(t) =                       + O((∆t)2 )                                                                                 (4.36)
                                       2(∆t)
From the first equation and equations (4.9) we obtain:

                                     θ(t + ∆t) = θ(t) + ω(t)(∆t) + O((∆t)2 )                                                                     (4.37)

    When we perform a numerical integration, we are interested in the
total error accumulated after N − 1 integration steps. In this method,
these errors must be studied carefully:
   • The error in the velocity ω(t) does not accumulate because it is given
     by the difference of the positions θ(t + ∆t) − θ(t − ∆t).
4.7. APPENDIX: ON THE EULER–VERLET METHOD                                                                                              225

      3.2                                                                                 5


           3                                                                              4


                                                                                          3
      2.8

                                                                                          2
      2.6

                                                                                          1
      2.4
                                                                                          0
      2.2
                                                                                          -1

           2
                                                                                          -2

      1.8
                                                                                          -3

      1.6                                                                                 -4


      1.4                                                                                 -5
               -4        -3        -2        -1       0       1       2       3       4        -4   -3   -2   -1   0   1   2   3   4

     6                                                                                    8



                                                                                          6
     4

                                                                                          4

     2
                                                                                          2



     0                                                                                    0



                                                                                          -2
     -2

                                                                                          -4

     -4
                                                                                          -6



     -6                                                                                   -8
          -4        -3        -2        -1        0       1       2       3       4            -4   -3   -2   -1   0   1   2   3   4




Figure 4.29:       A phase space trajectory of the forced damped pendulum. The
parameters chosen are ω0 = 1.0, ω = 2.0, γ = 0.2 and A = 1.568, 3.8, 4.44, 4.5. We
observe the system exiting and reentering regimes of chaotic behavior.



   • The accumulation of the errors for the position is estimated as fol-
     lows: Assume that δθ(t) is the total accumulated error from the
     integration from time t0 to t. Then according to the expansions
     (4.36) the error for the first step is δθ(t0 + ∆t) = O((∆t)4 ). Then¹⁴

           θ(t0 + 2∆t) = 2θ(t0 + ∆t) − θ(t0 ) + ∆t2 α(t0 + ∆t) + O((∆t)4 ) ⇒
          δθ(t0 + 2∆t) = 2δθ(t0 + ∆t) − δθ(t0 ) + O((∆t)4 )
                       = 2O((∆t)4 ) − 0 + O((∆t)4 )
                       = 3O((∆t)4 ) .

      For the next steps we obtain

       θ(t0 + 3∆t) = 2θ(t0 + 2∆t) − θ(t0 + ∆t) + ∆t2 α(t0 + 2∆t) + O((∆t)4 ) ⇒
      δθ(t0 + 3∆t) = 2δθ(t0 + 2∆t) − δθ(t0 + ∆t) + O((∆t)4 )
                   = 6O((∆t)4 ) − O((∆t)4 ) + O((∆t)4 )
                   = 6O((∆t)4 ) ,

  ¹⁴Remember that the acceleration α(t) is given, therefore δα(t) = 0.
226                                                CHAPTER 4. MOTION OF A PARTICLE

      5                                                  8


      4
                                                         6

      3
                                                         4
      2

                                                         2
      1


      0                                                  0


      -1
                                                         -2

      -2
                                                         -4
      -3

                                                         -6
      -4


      -5                                                 -8
           -4   -3   -2   -1   0   1   2   3   4              -4   -3   -2   -1    0   1   2   3   4




Figure 4.30: A Poincaré diagram for the forced damped pendulum in its chaotic
regime. The parameters chosen are ω0 = 1.0, ω = 2.0, γ = 0.2 and A = 1.4, 4.5.


      8                                                  8



      6                                                  6



      4                                                  4



      2                                                  2



      0                                                  0



      -2                                                 -2



      -4                                                 -4



      -6                                                 -6



      -8                                                 -8
           -4   -3   -2   -1   0   1   2   3   4              -4   -3   -2   -1    0   1   2   3   4




Figure 4.31: Basin of attraction for the forced damped pendulum. The parameters
chosen are ω0 = 1.0, ω = 2.0, γ = 0.2 and A = 0.85, 1.4.



        θ(t0 + 4∆t) = 2θ(t0 + 3∆t) − θ(t0 + 2∆t) + ∆t2 α(t0 + 3∆t) + O((∆t)4 ) ⇒
       δθ(t0 + 4∆t) = 2δθ(t0 + 3∆t) − δθ(t0 + 2∆t) + O((∆t)4 )
                    = 12O((∆t)4 ) − 3O((∆t)4 ) + O((∆t)4 )
                    = 10O((∆t)4 ) .

       Then, inductively, if δθ(t0 + (n − 1)∆t) =                                 (n−1)n
                                                                                    2
                                                                                         O((∆t)4 ),    we obtain

        θ(t0 + n∆t) = 2θ(t0 + (n − 1)∆t) − θ(t0 + (n − 2)∆t) + ∆t2 α(t0 + (n − 1)∆t)
                      +O((∆t)4 ) ⇒
       δθ(t0 + n∆t) = 2δθ(t0 + (n − 1)∆t) − δθ(t0 + (n − 2)∆t) + O((∆t)4 )
                        (n − 1)n             (n − 2)(n − 1)
                    = 2          O((∆t)4 ) −                O((∆t)4 ) + O((∆t)4 )
                             2                     2
                      n(n + 1)
                    =          O((∆t)4 ) .
                           2
4.8. APPENDIX: 2ND ORDER RUNGE–KUTTA METHOD                                         227

      Finally

                             n(n + 1)              1
          δθ(t0 + n∆t) =              O((∆t)4 ) ∼     O((∆t)4 ) ∼ O((∆t)2 ) .
                                2                 ∆t2
                                                                        (4.38)


Therefore the total error is O((∆t)2 ).
   We also mention the Velocity Verlet method or the Leapfrog method.
In this case we use the velocity explicitly:

                                              1
                           θn+1 = θn + ωn ∆t + αn ∆t2
                                              2
                                        1
                          ωn+ 1 = ωn + αn ∆t
                              2         2
                                          1
                          ωn+1 = ωn+ 1 + αn+1 ∆t .                                (4.39)
                                      2   2

The last step uses the acceleration αn+1 which should depend only on
the position θn+1 and not on the velocity.
   The Verlet methods are popular in molecular dynamics simulations of
many body systems. One of their advantages is that the constraints of
the system of particles are easily encoded in the algorithm.



4.8      Appendix: 2nd order Runge–Kutta Method
In this appendix we will show how the choice of the intermediate point
2 in equation (4.17) reduces the error by a power of h. This choice is
special, since by choosing another point (e.g. t = tn + 0.4h) the result
would have not been the same. Indeed, from the relation

                                                    ∫    tn+1
                  dx
                     = f (t, x) ⇒ xn+1 = xn +                   f (t, x) dx .     (4.40)
                  dt                                    tn


By Taylor expanding around the point (tn+1/2 , xn+1/2 ) we obtain

                                                        df
      f (t, x) = f (tn+1/2 , xn+1/2 ) + (t − tn+1/2 )      (tn+1/2 ) + O(h2 ) .   (4.41)
                                                        dt
228                                   CHAPTER 4. MOTION OF A PARTICLE

Therefore
      ∫   tn+1
                 f (t, x) dx
       tn
                                                                            tn+1
                                              df           (t − tn+1/2 )2
      = f (tn+1/2 , xn+1/2 )(tn+1 − tn ) +       (tn+1/2 )
                                              dt                 2          tn
          +O(h )(tn+1 − tn )
                  2
                                          {                                   }
                                df          (tn+1 − tn+1/2 )2 (tn − tn+1/2 )2
      = f (tn+1/2 , xn+1/2 )h + (tn+1/2 )                    −
                                dt                 2                2
              2
       +O(h )h
                                          { 2           }
                                df          h     (−h)2
      = f (tn+1/2 , xn+1/2 )h + (tn+1/2 )      −           + O(h3 )
                                dt           2      2
      = f (tn+1/2 , xn+1/2 )h + O(h3 ) .                                 (4.42)

Note that for the vanishing of the O(h) term it is necessary to place the
intermediate point at time tn+1/2 .
    This is not a unique choice. This can be most easily seen by a different
analysis of the Taylor expansion. Expanding around the point (tn , xn )
we obtain

                                                                 2
                                            dxn 1             2 d xn
            xn+1 =        xn + (tn+1 − tn )     + (tn+1 − tn )      2
                                                                      + O(h3 )
                                             dt   2              dt
                                      h2 dfn
                      =   xn + hfn +          + O(h3 )
                                      2 ( dt               )
                                      h2 ∂fn ∂fn dxn
                      =   xn + hfn +            +            + O(h3 )
                                      2      ∂t    ∂x dt
                                       2
                                         (               )
                                      h ∂fn ∂fn
                      =   xn + hfn +            +      fn + O(h3 ) ,           (4.43)
                                      2      ∂t    ∂x

where we have set fn ≡ f (tn , xn ),        dxn
                                             dt
                                                  ≡   dx
                                                      dt
                                                         (xn )   etc. We define

                                 k1 = f (tn , xn ) = fn
                                 k2 = f (tn + ah, xn + bhk1 )
                               xn+1 = xn + h(c1 k1 + c2 k2 ) .                     (4.44)

and we will determine the conditions so that the terms O(h2 ) of the last
equation in the error are identical with those of equation (4.43). By
4.8. APPENDIX: 2ND ORDER RUNGE–KUTTA METHOD                               229

expanding k2 we obtain

        k2 = f (tn + ah, xn + bhk1 )
                                       ∂f
            = f (tn , xn + bhk1 ) + ha    (tn , xn + bhk1 ) + O(h2 )
                                       ∂t
                                 ∂f                ∂f
            = f (tn , xn ) + hbk1 (tn , xn ) + ha (tn , xn ) + O(h2 )
                       {         ∂x       }        ∂t
                            ∂fn       ∂fn
            = fn + h a          + bk1       + O(h2 )
                             ∂t       ∂x
                       {                  }
                            ∂fn       ∂fn
            = fn + h a          + bfn       + O(h2 )                    (4.45)
                             ∂t       ∂x

Substituting in (4.44) we obtain

    xn+1 = xn + h(c1 k1 + c2 k2 )
                  {                       (                   )          }
                                              ∂fn         ∂fn
         = x n + h c 1 fn + c 2 fn + c 2 h a        + bfn       + O(h )2
                                               ∂t         ∂x
                                      (                              )
                                   h2            ∂fn             ∂fn
         = xn + h(c1 + c2 )fn +          (2c2 a)     + (2c2 b)fn
                                   2              ∂t             ∂x
                   3
              +O(h ) .                                                   (4.46)

All we need is to choose

                               c1 + c2 = 1
                                  2c2 a = 1
                                  2c2 b = 1 .                           (4.47)

The choice c1 = 0, c2 = 1, a = b = 1/2 leads to equation (4.19). Some
other choices in the bibliography are c2 = 1/2 and c2 = 3/4.
230                          CHAPTER 4. MOTION OF A PARTICLE

4.9 Problems
 4.1 Prove that the total error in the Euler–Cromer method is of order
     ∆t.

4.2 Reproduce the results in figures 4.11–4.18

4.3 Improve your programs so that there is no accumulation of roundoff
    error in the calculation of time when h is very small for the methods
    Euler, Euler-Cromer, Euler-Verlet and Runge-Kutta. Repeat the
    analysis of the previous problem.

 4.4 Compare the results obtained from the Euler, Euler-Cromer, Euler-
     Verlet, Runge-Kutta methods for the following systems where the
     analytic solution is known:

      (a) Particle falling in a constant gravitational field. Consider the
          case v(0) = 0, m = 1, g = 10.
      (b) Particle falling in a constant gravitational field moving in a fluid
          from which exerts a force F = −kv on the particle. Consider
          the case v(0) = 0, m = 1, g = 10 k = 0.1, 1.0, 2.0. Calculate the
          limiting velocity of the particle numerically and compare the
          value obtained to the theoretical expectation.
       (c) Repeat for the case of a force of resistance of magnitude |F | =
           kv 2 .

4.5 Consider the damped harmonic oscillator

                             d2 x    dx
                                2
                                  +γ    + ω02 x = 0 .                (4.48)
                             dt      dt
      Take ω0 = 3.145, γ = 0.5 and calculate its mechanical energy as a
      function of time. Is it monotonic? Why? (show that d(E/m)/dt =
      −γv 2 ). Repeat for γ = 4, 5, 6, 7, 8. When is the system oscillating
      and when it’s not? Calculate numerically the critical value of γ
      for which the system passes from a non oscillating to an oscillating
      regime. Compare your results with the theoretical expectations.

4.6 Reproduce the results of figures 4.19–4.22.

 4.7 Reproduce the results of figures 4.23–4.26. Calculate the phase δ(ω)
     numerically and compare with equation (4.33).
4.9. PROBLEMS                                                          231

 4.8 Consider a simple model for a swing. Take the damped harmonic
     oscillator and a driving force which periodically exerts a momen-
     tary push with angular frequency ω. Define “momentary” to be an
     impulse given by the acceleration a0 by an appropriately small time
     interval ∆t. The acceleration is 0 for all other times. Calculate the
     amplitude x0 (ω) for ω0 = 3.145 and γ = 0.5.

 4.9 Consider a “half sine” driving force on a damped harmonic oscilla-
     tor                       {
                                 a0 cos ωt cos ωt > 0
                        a(t) =
                                 0         cos ωt ≤ 0
     Study the transient behavior of the system for several initial con-
     ditions and calculate its steady state motion for ω0 = 3.145 and
     γ = 0.5. Calculate the amplitude x0 (ω).

4.10 Consider the driving force on a damped oscillator given by

                          1 1         2            2
                 a(t) =    + cos ω +    cos 2ωt −     cos 4ωt
                          π 2        3π           15π
     Study the transient behavior of the system for several initial con-
     ditions and calculate its steady state motion for ω0 = 3.145 and
     γ = 0.5. Calculate the amplitude x0 (ω). Compare your results with
     those of the previous problem and comment about.

4.11 Write a program that simulates N identical, independent harmonic
     oscillators. Take N = 20 and choose random initial conditions for
     each one of them. Study their trajectories in phase space and check
     whether they cross each other. Comment on your results.

4.12 Place the N = 20 harmonic oscillators of the previous problem in
     a small square in phase space whose center is at the origin of the
     axes. Consider the evolution of the system in time. Does the shape
     of the rectangle change in time? Does the area change in time?
     Explain...

4.13 Repeat the previous problem when each oscillator is damped with
     γ = 0.5. Take ω0 = 3.145.

4.14 Consider the forced damped oscillator with ω = 2, ω0 = 1.0, γ = 0.2.
     Study the transient behavior of the system in the plots of θ(t), θ̇(t)
     for A = 0.1, 0.5, 0.79, 0.85, 1.03, 1.4.
232                                CHAPTER 4. MOTION OF A PARTICLE

4.15 Consider the forced damped pendulum with ω = 2, ω0 = 1.0, γ = 0.2
     and study the phase space trajectories for A = 0.1, 0.19, 0.21, 0.25,
     0.5, 0.71, 0.79, 0.85, 1.02, 1.031, 1.033, 1.05, 1.08, 1.1, 1.4, 1.8, 3.1,
     3.5, 3.8, 4.2, 4.42, 4.44, 4.445, 4.447, 4.4488. Consider both the
     transient behavior and the steady state motion.

4.16 Reproduce the results in figures 4.30.

4.17 Reproduce the results in figures 4.31.

4.18 Consider the forced damped oscillator with

                                ω0 = 1 ,    ω = 2,      γ = 0.2

      After the transient behavior, the motion of the system for A = 0.60,
      A = 0.75 and A = 0.85 is periodic. Measure the period of the
      motion with an accuracy of three significant digits and compare it
      with the natural period of the pendulum and with the period of
      the driving force. Take as initial conditions the following pairs:
      (θ0 , θ̇0 ) = (3.1, 0.0), (2.5, 0.0), (2.0, 0.0), (1.0, 0.0), (0.2, 0.0), (0.0, 1.0),
      (0.0, 3.0), (0.0, 6.0). Check if the period is independent of the initial
      conditions.

4.19 Consider the forced damped pendulum with

                                ω0 = 1 ,    ω = 2,      γ = 0.2

      Study the motion of the pendulum when the amplitude A takes
      values in the interval [0.2, 5.0]. Consider specific discrete values of
      A by splitting the interval above in subintervals of width equal to
      δA = 0.002. For each value of A, record in a file the value of A, the
      angular position and the angular velocity of the pendulum when
      tk = kπ with k = ktrans , ktrans + 1, ktrans + 2, . . . , kmax :

                                    A      θ(tk )      θ̇(tk )

      The choice of ktrans is made so that the transient behavior will be
      discarded and study only the steady state of the pendulum. You
      may take kmax = 500, ktrans = 400, ti = 0, tf = 500π, and split the
      intervals [tk , tk + π] to 50 subintervals. Choose θ0 = 3.1, θ̇0 = 0.

       (a) Construct the bifurcation diagram by plotting the points (A, θ(tk )).
       (b) Repeat by plotting the points (A, θ̇(tk )).
4.9. PROBLEMS                                                        233

    (c) Check whether your results depend on the choice of θ0 , θ̇0 .
        Repeat your analysis for θ0 = 0, θ̇0 = 1.
    (d) Study the onset of chaos: Take A ∈ [1.0000, 1.0400] with δA =
        0.0001 and A ∈ [4.4300, 4.4500] with δA = 0.0001 and compute
        with the given accuracy the value Ac where the system enters
        into the chaotic behavior regime.
    (e) The plot the points (θ(tk ), θ̇(tk )) for A = 1.034, 1.040, 1.080,
        1.400, 4.450, 4.600. Put 2000 points for each value of A and
        commend on the strength of the chaotic behavior of the pen-
        dulum.
234   CHAPTER 4. MOTION OF A PARTICLE
Chapter 5

Planar Motion

In this chapter we will study the motion of a particle moving on the
plane under the influence of a dynamical field. Special emphasis will be
given to the study of the motion in a central field, like in the problem
of planetary motion and scattering. We also study the motion of two
or more interacting particles moving on the plane, which requires the
solution of a larger number of dynamical equations. These problems
can be solved numerically by using Runge–Kutta integration methods,
therefore this chapter extends and applies the numerical methods studied
in the previous chapter.


5.1    Runge–Kutta for Planar Motion
In two dimensions, the initial value problem that we are interested in, is
solving the system of equations (4.6)

                 dx              dvx
                    = vx             = ax (t, x, vx , y, vy )
                 dt               dt
                 dy              dvy
                    = vy             = ay (t, x, vx , y, vy ) .      (5.1)
                 dt               dt
    The 4th order Runge-Kutta method can be programmed by making
small modifications of the program in the file rk.cpp. In order to facil-
itate the study of many different dynamical fields, for each field we put
the code of the respective acceleration in a different file. The code which
is common for all the forces, namely the user interface and the imple-
mentation of the Runge–Kutta method, will be put in the file rk2.cpp.
The program that computes the acceleration will be put in a file named
rk_XXX.cpp, where XXX is a string of characters that identifies the force.

                                   235
236                                           CHAPTER 5. PLANAR MOTION

For example, the file rk2_hoc.cpp contains the program computing the
acceleration of the simple harmonic oscillator, the file rk2_g.cpp the ac-
celeration of a constant gravitational field ⃗g = −g ŷ etc.
    Different force fields will require the use of one or more coupling con-
stants which need to be accessible to the code in the main program and
some subroutines. For this reason, we will provide two variables k1, k2
in the global scope which will be accessed by the acceleration functions
f3 and f4, the function energy and the main program where the user
will enter their. The initial conditions are stored in the variables X10
↔ x0 , X20 ↔ y0 , V10 ↔ vx0 , V20 ↔ vy0 , and the values of the functions
of time will be stored in the arrays X1[P] ↔ x(t), X2[P] ↔ y(t), V1[P]
↔ vx (t), V2[P] ↔ vy (t). The integration is performed by a call to the
function RK(Ti,Tf,X10,X20,V10,V20,Nt) The results are written to the
file rk2.dat. Each line in this file contains the time, position, velocity and
the total mechanical energy, where the energy is calculated by the func-
tion energy(t,x1,x2,v1,v2). The code for the function energy, which
is different for each force field, is written in the same file with the ac-
celeration. The code for the function RKSTEP(t,x1,x2,x3,x4,dt) should
be extended in order to integrate four instead of two functions. The full
code is listed below:

/ / ========================================================
/ / Program t o s o l v e a 4 ODE system using Runge−Kutta Method
/ / User must supply d e r i v a t i v e s
/ / dx1 / dt= f 1 ( t , x1 , x2 , x3 , x4 ) dx2 / dt=f 2 ( t , x1 , x2 , x3 , x4 )
/ / dx3 / dt=f 3 ( t , x1 , x2 , x3 , x4 ) dx4 / dt=f 4 ( t , x1 , x2 , x3 , x4 )
/ / as double f u n c t i o n s
/ / Output i s w r i t t e n i n f i l e rk2 . dat
/ / ========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
c o n s t i n t P = 1010000;
double T [ P ] , X1 [ P ] , X2 [ P ] , V1 [ P ] , V2 [ P ] ;
double k1 , k2 ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
f1 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) ;
double
5.1. RUNGE–KUTTA FOR PLANAR MOTION                                          237

f2 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) ;
double
f3 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) ;
double
f4 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) ;
double
energy
    ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) ;
void
RK ( c o n s t double& Ti , c o n s t double& Tf ,
      c o n s t double& X10 , c o n s t double& X20 ,
      c o n s t double& V10 , c o n s t double& V20 ,
      const int          & Nt ) ;
void
RKSTEP ( double& t ,
              double& x1 , double& x2 ,
              double& x3 , double& x4 ,
              const           double& dt ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    string buf ;
    double Ti , Tf , X10 , X20 , V10 , V20 ;
    int         Nt , i ;
    double E0 , EF , DE ;
    / / Input :
    cout << ”Runge−Kutta Method f o r 4−ODEs I n t e g r a t i o n \n” ;
    cout << ” Enter c o u p l i n g c o n s t a n t s : \ n” ;
    cin >> k1 >> k2 ; getline ( cin , buf ) ;
    cout << ” k1= ” << k1 << ” k2= ” << k2 << endl ;
    cout << ” Enter Nt , Ti , Tf , X10 , X20 , V10 , V20: \ n” ;
    cin >> Nt >> Ti >> Tf>> X10 >> X20 >> V10 >> V20 ;
    getline ( cin , buf ) ;
    cout << ” Nt = ” << Nt << endl ;
    cout << ”Time : I n i t i a l Ti = ” << Ti
             << ” F i n a l Tf= ”                << Tf << endl ;
    cout << ”                     X1 ( Ti )= ” << X10
             << ” X2( Ti )=”                     << X20 << endl ;
    cout << ”                     V1 ( Ti )= ” << V10
             << ” V2( Ti )=”                     << V20 << endl ;
    / / Calculate :
   RK ( Ti , Tf , X10 , X20 , V10 , V20 , Nt ) ;
    ofstream myfile ( ” rk2 . dat ” ) ;
    myfile . precision ( 1 7 ) ;
    f o r ( i =0;i<Nt ; i++)
        myfile << T [ i ] << ” ”
238                                              CHAPTER 5. PLANAR MOTION

                    << X1 [ i ] << ” ” << X2 [ i ] << ” ”
                    << V1 [ i ] << ” ” << V2 [ i ] << ” ”
                    << energy ( T [ i ] , X1 [ i ] , X2 [ i ] , V1 [ i ] , V2 [ i ] )
                    << endl ;
    myfile . close ( ) ;
    / / Rutherford s c a t t e r i n g a n g l e s :
    cout . precision ( 1 7 ) ;
    cout <<”v−a n g l e : ”<< atan2 ( V2 [ Nt −1] , V1 [ Nt −1]) << endl ;
    cout <<”b−a n g l e : ”<< 2 . 0 * atan ( k1 / ( V10 * V10 * X20 ) ) << endl ;
    E0=energy ( Ti                , X10         , X20          , V10          , V20   );
    EF=energy ( T [ Nt −1] , X1 [ Nt −1] , X2 [ Nt −1] , V1 [ Nt −1] , V2 [ Nt −1]) ;
    DE = abs ( 0 . 5 * ( EF−E0 ) / ( EF+E0 ) ) ;
    cout << ”E0 , EF , DE/ E= ” << E0
              << ” ”                         << EF
              << ” ”                         << DE << endl ;
} / / main ( )
/ / ========================================================
/ / The v e l o c i t y f u n c t i o n s f1 , f 2 ( t , x1 , x2 , v1 , v2 )
/ / ========================================================
double
f1 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) {
    r e t u r n v1 ;
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
f2 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) {
    r e t u r n v2 ;
}
/ / ========================================================
/ / RK( Ti , Tf , X10 , X20 , V10 , V20 , Nt ) i s t h e d r i v e r
/ / f o r t h e Runge−Kutta i n t e g r a t i o n r o u t i n e RKSTEP
/ / Input : I n i t i a l and f i n a l t i m e s Ti , Tf
//              I n i t i a l v a l u e s a t t =Ti X10 , X20 , V10 , V20
//              Number o f s t e p s o f i n t e g r a t i o n : Nt−1
//              S i z e o f a r r a y s T , X1 , X2 , V1 , V2
/ / Output : r e a l a r r a y s T[ Nt ] , X1 [ Nt ] , X2[ Nt ] ,
//                                              V1 [ Nt ] , V2[ Nt ] where
/ / T[ 0 ] = Ti X1 [ 0 ] = X10 X2[ 0 ] = X20 V1 [ 0 ] = V10 V2 [ 0 ] = V20
//                    X1 [ k ] = X1( a t t =T[ k ] ) X2[ k ] = X2( a t t =T[ k ] )
//                    V1 [ k ] = V1 ( a t t =T[ k ] ) V2[ k ] = V2( a t t =T[ k ] )
/ / T[ Nt −1]= Tf
/ / ========================================================
void
RK ( c o n s t double& Ti , c o n s t double& Tf ,
      c o n s t double& X10 , c o n s t double& X20 ,
      c o n s t double& V10 , c o n s t double& V20 ,
      const int            & Nt ) {
5.1. RUNGE–KUTTA FOR PLANAR MOTION                                                                  239


    double dt ;
    double TS , X1S , X2S ; / / v a l u e s o f time and X1 , X2 a t gi v e n s t e p
    double             V1S , V2S ;
    int i;
    // Initialize :
    dt            = ( Tf−Ti ) / ( Nt −1) ;
    T [ 0 ] = Ti ;
    X1 [ 0 ] = X10 ; X2 [ 0 ] = X20 ;
    V1 [ 0 ] = V10 ; V2 [ 0 ] = V20 ;
    TS            = Ti ;
    X1S           = X10 ; X2S          = X20 ;
    V1S           = V10 ; V2S          = V20 ;
    / / Make RK s t e p s : The arguments o f RKSTEP a r e
    / / r e p l a c e d with t h e new ones
    f o r ( i =1; i<Nt ; i++){
        RKSTEP ( TS , X1S , X2S , V1S , V2S , dt ) ;
        T [ i ] = TS ;
        X1 [ i ] = X1S ; X2 [ i ] = X2S ;
        V1 [ i ] = V1S ; V2 [ i ] = V2S ;
    }
} / / RK( )
/ / ========================================================
/ / S u b r o u t i n e RKSTEP( t , x1 , x2 , dt )
/ / Runge−Kutta I n t e g r a t i o n r o u t i n e o f ODE
/ / dx1 / dt= f 1 ( t , x1 , x2 , x3 , x4 ) dx2 / dt=f 2 ( t , x1 , x2 , x3 , x4 )
/ / dx3 / dt=f 3 ( t , x1 , x2 , x3 , x4 ) dx4 / dt=f 4 ( t , x1 , x2 , x3 , x4 )
/ / User must supply d e r i v a t i v e f u n c t i o n s :
/ / r e a l f u n c t i o n f 1 ( t , x1 , x2 , x3 , x4 )
/ / r e a l f u n c t i o n f 2 ( t , x1 , x2 , x3 , x4 )
/ / r e a l f u n c t i o n f 3 ( t , x1 , x2 , x3 , x4 )
/ / r e a l f u n c t i o n f 4 ( t , x1 , x2 , x3 , x4 )
/ / Given i n i t i a l p o i n t ( t , x1 , x2 ) t h e r o u t i n e advances i t
/ / by time dt .
/ / Input : I n i t a l time t                  and f u n c t i o n v a l u e s x1 , x2 , x3 , x4
/ / Output : F i n a l time t +dt and f u n c t i o n v a l u e s x1 , x2 , x3 , x4
/ / C a r e f u l : v a l u e s o f t , x1 , x2 , x3 , x4 a r e o v e r w r i t t e n . . .
/ / ========================================================
void
RKSTEP ( double& t ,
              double& x1 , double& x2 ,
              double& x3 , double& x4 ,
              const               double& dt ) {
    double k11 , k12 , k13 , k14 , k21 , k22 , k23 , k24 ;
    double k31 , k32 , k33 , k34 , k41 , k42 , k43 , k44 ;
    double h , h2 , h6 ;

   h =dt ;           / / h = dt , i n t e g r a t i o n s t e p
   h2 =0.5* h ;      / / h2 = h / 2
240                                              CHAPTER 5. PLANAR MOTION

  h6=h / 6 . 0 ;    / / h6 = h / 6

   k11=f1 ( t , x1 , x2 , x3 , x4 ) ;
   k21=f2 ( t , x1 , x2 , x3 , x4 ) ;
   k31=f3 ( t , x1 , x2 , x3 , x4 ) ;
   k41=f4 ( t , x1 , x2 , x3 , x4 ) ;

   k12=f1 ( t+h2 , x1+h2 * k11 , x2+h2 * k21 , x3+h2 * k31 , x4+h2 * k41 ) ;
   k22=f2 ( t+h2 , x1+h2 * k11 , x2+h2 * k21 , x3+h2 * k31 , x4+h2 * k41 ) ;
   k32=f3 ( t+h2 , x1+h2 * k11 , x2+h2 * k21 , x3+h2 * k31 , x4+h2 * k41 ) ;
   k42=f4 ( t+h2 , x1+h2 * k11 , x2+h2 * k21 , x3+h2 * k31 , x4+h2 * k41 ) ;

   k13=f1 ( t+h2 , x1+h2 * k12 , x2+h2 * k22 , x3+h2 * k32 , x4+h2 * k42 ) ;
   k23=f2 ( t+h2 , x1+h2 * k12 , x2+h2 * k22 , x3+h2 * k32 , x4+h2 * k42 ) ;
   k33=f3 ( t+h2 , x1+h2 * k12 , x2+h2 * k22 , x3+h2 * k32 , x4+h2 * k42 ) ;
   k43=f4 ( t+h2 , x1+h2 * k12 , x2+h2 * k22 , x3+h2 * k32 , x4+h2 * k42 ) ;

   k14=f1 ( t+h     , x1+h   * k13 , x2+h   * k23 , x3+h   * k33 , x4+h   * k43 ) ;
   k24=f2 ( t+h     , x1+h   * k13 , x2+h   * k23 , x3+h   * k33 , x4+h   * k43 ) ;
   k34=f3 ( t+h     , x1+h   * k13 , x2+h   * k23 , x3+h   * k33 , x4+h   * k43 ) ;
   k44=f4 ( t+h     , x1+h   * k13 , x2+h   * k23 , x3+h   * k33 , x4+h   * k43 ) ;

  t =t+h ;
  x1=x1+h6 * ( k11 + 2 . 0 * ( k12+k13 )+k14 ) ;
  x2=x2+h6 * ( k21 + 2 . 0 * ( k22+k23 )+k24 ) ;
  x3=x3+h6 * ( k31 + 2 . 0 * ( k32+k33 )+k34 ) ;
  x4=x4+h6 * ( k41 + 2 . 0 * ( k42+k43 )+k44 ) ;

} / / RKSTEP ( )



5.2 Projectile Motion
Consider a particle in the constant gravitational field near the surface of
the earth which moves with constant acceleration ⃗g = −g ŷ so that
                   x(t) = x0 + v0x t , y(t) = y0 + v0y t − 12 gt2
                   vx (t) = v0x      , vy (t) = v0y − gt                              (5.2)
                   ax (t) = 0        , ay (t) = −g
The particle moves on a parabolic trajectory that depends on the initial
conditions
                          ( )
                            v0y               1 g
              (y − y0 ) =         (x − x0 ) −    2
                                                    (x − x0 )2
                            v0x               2 v0x
                                            tan2 θ
                        = tan θ (x − x0 ) −        (x − x0 )2 ,   (5.3)
                                            4hmax
5.2. PROJECTILE MOTION                                                                                        241

where tan θ = v0y /v0x is the direction of the initial velocity and hmax is
the maximum height of the trajectory.

         0.25                                               0.06
                                             x(t)                                               y(t)

                                                            0.05
          0.2

                                                            0.04
         0.15
                                                            0.03
          0.1
                                                            0.02

         0.05
                                                            0.01

           0                                                       0
                0       0.05   0.1   0.15     0.2    0.25              0   0.05   0.1   0.15     0.2   0.25

          1.01                                                1
                                            vx(t)                                              vy(t)

         1.005                                              0.5


                1                                             0


         0.995                                              -0.5


          0.99                                               -1


         0.985                                              -1.5
                    0   0.05   0.1   0.15      0.2   0.25          0       0.05   0.1   0.15     0.2   0.25



Figure 5.1: Plots of x(t), y(t), vx (t), vy (t) for a projectile fired in a constant gravita-
tional field ⃗g = −10.0 ŷ with initial velocity ⃗v0 = x̂ + ŷ.



  The acceleration ax (t) = 0 ay (t) = −g (ax ↔ f3 , ay ↔ f4) and the
mechanical energy is coded in the file rk2_g.cpp:

/ / ========================================================
/ / The a c c e l e r a t i o n f u n c t i o n s f3 , f 4 ( t , x1 , x2 , v1 , v2 ) provided
/ / by t h e u s e r
/ / ========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
e x t e r n double k1 , k2 ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Free f a l l i n c o n s t a n t g r a v i t a t i o n a l f i e l d with
/ / g = −k2
double
f3 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
242                                                       CHAPTER 5. PLANAR MOTION

          0.06                                             1.8e-05
                                                                                        E(t)-E(0)
                                                           1.6e-05
          0.05
                                                           1.4e-05
          0.04                                             1.2e-05

          0.03                                              1e-05
      y




                                                            8e-06
          0.02
                                                            6e-06

          0.01                                              4e-06
                                                            2e-06
            0
                 0   0.05   0.1       0.15   0.2   0.25         0
                                  x                                  0   0.05   0.1   0.15     0.2   0.25



Figure 5.2: (Left) The parabolic trajectory of a projectile fired in a constant gravi-
tational field ⃗g = −10.0 ŷ with initial velocity ⃗v0 = x̂ + ŷ. (Right) The deviation of the
projectile’s energy from its initial value is due to numerical errors.




    c o n s t double& v1 , c o n s t double& v2 ) {
   return 0.0;      / / dx3 / dt=dv1 / dt=a1
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
f4 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
     c o n s t double& v1 , c o n s t double& v2 ) {
   r e t u r n −k1 ;      / / dx4 / dt=dv2 / dt=a2
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
energy
   ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
     c o n s t double& v1 , c o n s t double& v2 ) {
   r e t u r n 0 . 5 * ( v1 * v1+v2 * v2 ) + k1 * x2 ;
}

In order to calculate a projectile’s trajectory you may use the following
commands:

> g++ −O2 rk2 . cpp rk2_g . cpp −o rk2
> . / rk2
Runge−Kutta Method for 4−ODEs Integration
Enter coupling constants :
10.0 0.0
k1= 10 k2= 0
Enter Nt , Ti , Tf , X10 , X20 , V10 , V20 :
20000 0.0 0.2 0.0 0.0 1 . 0 1 . 0
Nt = 20000
Time : Initial Ti = 0 Final Tf= 0.2
             X1 ( Ti )= 0 X2 ( Ti ) =0
5.2. PROJECTILE MOTION                                                              243

              V1 ( Ti )= 1 V2 ( Ti ) =1

The analysis of the results contained in the file rk2.dat can be done using
gnuplot:

gnuplot >   s e t t e r m i n a l x11 1
gnuplot >   p l o t ” rk2 . dat ” using 1 : 2 with lines t i t l e   ”x ( t ) ”
gnuplot >   s e t t e r m i n a l x11 2
gnuplot >   p l o t ” rk2 . dat ” using 1 : 3 with lines t i t l e   ”y ( t ) ”
gnuplot >   s e t t e r m i n a l x11 3
gnuplot >   p l o t ” rk2 . dat ” using 1 : 4 with lines t i t l e   ” vx ( t ) ”
gnuplot >   s e t t e r m i n a l x11 4
gnuplot >   p l o t ” rk2 . dat ” using 1 : 5 with lines t i t l e   ” vy ( t ) ”
gnuplot >   s e t t e r m i n a l x11 5
gnuplot >   p l o t ” rk2 . dat ” using 1 : ( $6 −1.0) w lines t     ”E( t ) Ε−(0) ”
gnuplot >   s e t t e r m i n a l x11 6
gnuplot >   s e t s i z e square
gnuplot >   set t i t l e ” Trajectory ”
gnuplot >   p l o t ” rk2 . dat ” using 2:3 with lines notit

The results can be seen in figures 5.1 and 5.2. We note a small increase
in the mechanical energy which is due to the accumulation of numerical
errors.
    We can animate the trajectory by writing a script of gnuplot com-
mands in a file rk2_animate.gpl

icount = icount+skip
p l o t ”< c a t −n rk2 . dat ” \
    using 3 : ( $1<= icount ? $4 : 1 / 0 ) with lines notitle
# pause 1
i f ( icount < nlines ) r e r e a d

Before calling the script, the user must set the values of the variables
icount, skip and nlines. Each time gnuplot reads the script, it plots
icount number of lines from rk2.dat. Then the script is read again and
a new plot is made with skip lines more than the previous one, unless
icount < nlines. The plotted “file” "<cat -n rk2.dat" is the standard
output (stdout) of the command cat -n rk2.dat which prints to the
stdout the contents of the file rk2.dat line by line, together with the
line number. Therefore the plot command reads data which are the line
number, the time, the coordinate x, the coordinate y etc. The keyword
using in

  using 3 : ( $1<= icount ? $4 : 1 / 0 )
244                                      CHAPTER 5. PLANAR MOTION



instructs the plot command to use the 3rd column on the horizontal axis
and if the first column is less than icount ($1<= icount) put on the
vertical axis the value of the 4th column if the first column is less than
icount. Otherwise ($1 > icount) it prints an undefined number (1/0)
which makes gnuplot print nothing at all. You may also uncomment the
command pause if you want to make the animation slower. In order to
run the script from gnuplot, issue the commands

gnuplot >   icount = 10
gnuplot >   skip    = 200
gnuplot >   nlines = 20000
gnuplot >   load ” rk2_animate . gpl ”

    The scripts shown above can be found in the accompanying software.
More scripts can be found there that automate many of the boring pro-
cedures. The usage of two of these is explained below. The first one is
in the file rk2_animate.csh:

> . / rk2_animate . csh −h
Usage : rk2_animate . csh −t [ sleep time ] −d [ skip points ] <file >
Default file is rk2 . dat
Other options :
   −x : s e t lower value in xrange
   −X : s e t lower value in xrange
   −y : s e t lower value in yrange
   −Y : s e t lower value in yrange
   −r : automatic determination of x−y range
> . / rk2_animate . csh −r −d 500 rk2 . dat

The last line is a command that animates a trajectory read from the
file rk2.dat. Each animation frame contains 500 more points than the
previous one. The option -r calculates the plot range automatically. The
option -h prints a short help message.
   A more useful script is in the file rk2.csh.

> . / rk2 . csh −h
Usage : rk2 . csh −f <force > k1 k2 x10 x20 v10 v20 STEPS t0 tf
Other Options :
 −n Do not animate trajectory
Available forces ( value of <force >) :
1 : ax=−k1               ay= −k2 y            Harmonic oscillator
2 : ax= 0                ay= −k1              Free fall
5.2. PROJECTILE MOTION                                                   245

3 : ax= −k2         vx       ay= −k2       vy − k1   Free fall + \
                                                     air resistance ~ v
4 : ax= −k2 | v | vx         ay= −k2 | v | vy − k1   Free fall + \
                                                     air resistance ~ v^2
5 : ax= k1 * x1 / r^3        ay= k1 * x2 / r^3       Coulomb Force
....

The option -h prints operating instructions. A menu of forces is available,
and a choice can be made using the option -f. The rest of the command
line consists of the parameters read by the program in rk2.cpp, i.e. the
coupling constants k1, k2, the initial conditions x10, x20, v10, v20
and the integration parameters STEPS, t0 and tf. For example, the
commands

> rk2 . csh -f 2 -- 10.0 0.0 0.0 0.0 1 . 0 1 . 0 20000 0.0 0.2
> rk2 . csh -f 1 -- 16.0 1 . 0 0.0 1 . 0 1 . 0 0.0 20000 0.0 6.29
> rk2 . csh -f 5 -- 10.0 0.0 -10 0.2 1 0 . 0.0 20000 0.0 3.00

compute the trajectory of a particle in the constant gravitational field
discussed above, the trajectory of an anisotropic harmonic oscillator (k1
= ax = −ω12 x, k2 = ay = −ω22 y) and the scattering of a particle in a
Coulomb field – try them! I hope that you will have enough curiosity to
look “under the hood” of the scripts and try to modify them or create
new ones. Some advise to the lazy guys: If you need to program your
own force field follow the recipe: Write the code of your acceleration field
in a file named e.g. rk2_myforce.cpp as we did with rk2_g.cpp. Edit
the file rk2.csh and modify the line

s e t forcecode = ( hoc g vg v2g cb )

to

s e t forcecode = ( hoc g vg v2g cb myforce )

(the variable $forcecode may have more entries than the ones shown
above). Count the order of the string myforce, which is 6 in our case. In
order to access this force field from the command line, use the option -f
6:

> rk2 . csh −f 6 −− . . . . . . .

   Now, we will study the effect of the air resistance on the motion of the
projectile. For small velocities this is a force proportional to the velocity
246                                                  CHAPTER 5. PLANAR MOTION

F⃗r = −mk⃗v , therefore

                                       ax = −kvx
                                       ay = −kvy − g .                                          (5.4)

By taking
                                      v0x (          )
                       x(t) = x0 +          1 − e−kt
                                       k
                                      1(        g)(           ) g
                       y(t) = y0 +        v0y +       1 − e−kt − t
                                      k         k               k
                                     −kt
                      vx (t) = v0x e
                               (         g ) −kt g
                      vy (t) = v0y +         e − ,                                              (5.5)
                                         k          k
we obtain the motion of a particle with terminal velocity vy (+∞) = −g/k
(x(+∞) = const., y(+∞) ∼ t).
   The acceleration caused by the air resistance is programmed in the
file (k1 ↔ g, k2 ↔ k ) rk2_vg.cpp:

/ / ========================================================
/ / The a c c e l e r a t i o n f u n c t i o n s f3 , f 4 ( t , x1 , x2 , v1 , v2 ) provided
/ / by t h e u s e r
/ / ========================================================
/ / Free f a l l i n c o n s t a n t g r a v i t a t i o n a l f i l l e d with
/ / ax = −k2 vx               ay = −k2 vy − k1
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
e x t e r n double k1 , k2 ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
f3 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) {
    r e t u r n −k2 * v1 ;     / / dx3 / dt=dv1 / dt=a1
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
f4 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) {
    r e t u r n −k2 * v2−k1 ;       / / dx4 / dt=dv2 / dt=a2
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
5.2. PROJECTILE MOTION                                                                                   247

double
energy
  ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
    c o n s t double& v1 , c o n s t double& v2 ) {
  r e t u r n 0 . 5 * ( v1 * v1+v2 * v2 ) + k1 * x2 ;
}


   The results are shown in figure 5.3 where we see the effect of an in-
creasing air resistance on the particle trajectory. The effect of a resistance
force of the form F⃗r = −mkv 2 v̂ is shown in figure 5.4.

                                                              1.4
                                              0.0                                              0.0
          0.05                                0.2                                              0.2
                                              1.0             1.2                              1.0
                                              5.0                                              5.0
          0.04                               10.0              1                              10.0
                                             20.0                                             20.0
                                             30.0             0.8                             30.0
          0.03
      y




                                                          y




                                                              0.6
          0.02
                                                              0.4
          0.01
                                                              0.2

            0                                                  0
                 0   0.05   0.1       0.15          0.2             0   0.2   0.4       0.6   0.8    1
                                  x                                                 x



 Figure 5.3: The trajectory of a projectile moving in a constant gravitational field
⃗g = −10 ŷ with air resistance causing acceleration ⃗ar = −k⃗v for k = 0, 0.2, 1, 5, 10, 20, 30.
 The left plot has ⃗v (0) = x̂ + ŷ and the right plot has ⃗v (0) = 5x̂ + 5ŷ.




                                                              1.4
                                              0.0                                              0.0
          0.05                                0.2                                              0.2
                                              1.0             1.2                              1.0
                                              5.0                                              5.0
          0.04                               10.0              1                              10.0
                                             20.0                                             20.0
                                             30.0             0.8                             30.0
          0.03
      y




                                                          y




                                                              0.6
          0.02
                                                              0.4
          0.01
                                                              0.2

            0                                                  0
                 0   0.05   0.1       0.15          0.2             0   0.2   0.4       0.6   0.8    1
                                  x                                                 x



Figure 5.4: The trajectory of a projectile moving in a constant gravitational field ⃗g =
−10 ŷ with air resistance causing acceleration ⃗ar = −kv 2 v̂ for k = 0, 0.2, 1, 5, 10, 20, 30.
The left plot has ⃗v (0) = x̂ + ŷ and the right plot has ⃗v (0) = 5x̂ + 5ŷ.
248                                      CHAPTER 5. PLANAR MOTION

5.3 Planetary Motion
Consider the simple planetary model of a “sun” of mass M and a planet
“earth” at distance r from the sun and mass m such that m ≪ M . Ac-
cording to Newton’s law of gravity, the earth’s acceleration is
                                     GM         GM
                       ⃗a = ⃗g = −      2
                                          r̂ = − 3 ⃗r ,               (5.6)
                                      r          r
where G = 6.67 × 10−11 kgrm·sec2 , M = 1.99 × 1030 kgr, m = 5.99 × 1024 kgr.
                             3



When the hypothesis m ≪ M is not valid, the two body problem is
reduced to that of the one body problem with the mass replaced by the
reduced mass µ
                              1     1    1
                                 =    +    .
                              µ    m M
The force of gravity is a central force. This implies conservation of the
angular momentum L    ⃗ = ⃗r × p⃗ with respect to the center of the force,
which in turn implies that the motion is confined on one plane. We
choose the z axis so that
                        ⃗ = Lz k̂ = m(xvy − yvx )k̂ .
                        L                                              (5.7)
The force of gravity is conservative and the mechanical energy
                              1       GmM
                           E = mv 2 −                                 (5.8)
                              2        r
is conserved. If we choose the origin of the coordinate axes to be the
center of the force, the equations of motion (5.6) become
                                     GM
                             ax = −      x
                                      r3
                                     GM
                             ay   = − 3 y,                            (5.9)
                                      r
where r2 = x2 + y 2 . This is a system of two coupled differential equations
for the functions x(t), y(t). The trajectories are conic sections which are
either an ellipse (bound states - “planet”), a parabola (e.g. escape to
infinity when the particle starts moving with speed equal to the escape
velocity) or a hyperbola (e.g. scattering).
    Kepler’s third law of planetary motion states that the orbital period
T of a planet satisfies the equation
                                       4π 2 3
                               T2 =        a ,                       (5.10)
                                       GM
5.3. PLANETARY MOTION                                                                             249

where a is the semi-major axis of the elliptical trajectory. The eccentricity
is a measure of the deviation of the trajectory from being circular
                                  √
                                          b2
                              e= 1− 2 ,                               (5.11)
                                         a
where b is the semi-minor axis. The eccentricity is 0 for the circle and
tends to 1 as the ellipse becomes more and more elongated. The foci F1
and F2 are located at a distance ea from the center of the ellipse. They
have the property that for every point on the ellipse

                                       P F1 + P F2 = 2a .                                       (5.12)

   The acceleration given to the particle by Newton’s force of gravity is
programmed in the file rk2_cb.cpp:

/ / ========================================================
/ / The a c c e l e r a t i o n f u n c t i o n s f3 , f 4 ( t , x1 , x2 , v1 , v2 ) provided
/ / by t h e u s e r
/ / ========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
e x t e r n double k1 , k2 ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Motion i n Coulombic p o t e n t i a l :
/ / ax= k1 * x1 / r ^3 ay= k1 * x2 / r ^3
double
f3 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) {
    double r2 , r3 ;
    r2=x1 * x1+x2 * x2 ;
    r3=r2 * sqrt ( r2 ) ;
    i f ( r3 >0.0)
        r e t u r n k1 * x1 / r3 ; / / dx3 / dt=dv1 / dt=a1
    else
        return 0.0;
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
f4 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) {
    double r2 , r3 ;
    r2=x1 * x1+x2 * x2 ;
250                                            CHAPTER 5. PLANAR MOTION

  r3=r2 * sqrt ( r2 ) ;
  i f ( r3 >0.0 )
      r e t u r n k1 * x2 / r3 ; / / dx4 / dt=dv4 / dt=a4
  else
      return 0.0;
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
energy
   ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) {
   double r ;
   r=sqrt ( x1 * x1+x2 * x2 ) ;
    i f ( r > 0.0)
        r e t u r n 0 . 5 * ( v1 * v1+v2 * v2 ) + k1 / r ;
    else
        return 0.0;
}

We set k1= −GM and take special care to avoid hitting the center of the
force, the singular point at (0, 0). The same code can be used for the
electrostatic Coulomb field with k1= qQ/4πϵ0 m.
    At first we study trajectories which are bounded. We set GM = 10,
x(0) = 1.0, y(0) = 0, v0x = 0 and vary v0y . We measure the period T and
the length of the semi axes of the resulting ellipse. The results can be
found in table 5.1. Some of the trajectories are shown in figure 5.5. There

                               v0x     T /2         2a
                               3.2     1.030        2.049
                               3.4     1.281        2.370
                               3.6     1.682        2.841
                               3.8     2.396        3.597
                               4.0     3.927        5.000
                               4.1     5.514        6.270
                               4.2     8.665        8.475
                               4.3     16.931       13.245
                               4.3     28.088       18.561
                               4.38    42.652       24.522
                               4.40    61.359       31.250
                               4.42    99.526       43.141


Table 5.1:      The results for the period T and the length of the semi-major axis a of
the trajectory of planetary motion for GM = 10, x(0) = 1.0, y(0) = 0, v0y = 0.
5.3. PLANETARY MOTION                                                       251

we can see the dependence of the size of the ellipse on the period. Figure
5.6 confirms Kepler’s third law of planetary motion given by equation
(5.10).

           8
                                       1.68
           6                           2.40
                                       3.93
           4                           5.52
                                      16.95
           2

           0
      y




          -2

          -4

          -6

          -8
            -14 -12 -10 -8       -6   -4   -2   0    2
                                  x

Figure 5.5: Planetary trajectories for GM = 10, x(0) = 1.0, y(0) = 0, v0y = 0 and
v0x = 3.6, 3.8, 4.0, 4.1, 4.3. The numbers are the corresponding half periods.



    In order to confirm Kepler’s third law of planetary motion numeri-
cally, we take the logarithm of both sides of equation (5.10)
                                          ( 2)
                              3       1     4π
                       ln T = ln a + ln           .             (5.13)
                              2       2     GM
Therefore, the points (ln a, ln T ) lie on a straight line. Using a linear least
squares fit we calculate the slope and the intercept which should be equal
to 32 and 1/2 ln (4π 2 /GM ) respectively. This is left as an exercise.
    In the case where the initial velocity of the particle becomes larger
than the escape velocity ve , the particle escapes from the influence of the
gravitational field to infinity. The escape velocity corresponds to zero
mechanical energy, which gives
                                      2GM
                                  ve2 =     .                   (5.14)
                                        r
When GM = 10, x(0) = 1.0, y(0) = 0, we obtain ve ≈ 4.4721 . . .. The
numerical calculation of ve is left as an exercise.
252                                           CHAPTER 5. PLANAR MOTION


            100000


              10000


               1000
      T2




                 100


                  10


                    1
                        1          10          100        1000        10000
                                                    3
                                                a

Figure 5.6:   Kepler’s third law of planetary motion for GM = 10. The points are
the measurements taken from table 5.1. The solid line is the known analytic solution
(5.10).




5.4 Scattering

In this section we consider scattering of particles from a central potential¹.
We assume particles that follow unbounded trajectories that start from
infinity and move almost free from the influence of the force field towards
its center. When they approach the region of interaction they get deflected
and get off to infinity in a new direction. We say that the particles have
been scattered and that the angle between their original and final direction
is the scattering angle θ. Scattering problems are interesting because we
can infer to the properties of the scattering potential from the distribution
of the scattering angle. This approach is heavily used in today’s particle
accelerators for the study of fundamental interactions between elementary
particles.
   First we will discuss scattering of small hard spheres of radius r1 by


   ¹We refer the reader to [40], chapter 4.
5.4. SCATTERING                                                                  253


               1

              0.8

              0.6

              0.4

              0.2
      y




               0

            -0.2

            -0.4

            -0.6
                -0.8 -0.6 -0.4 -0.2 0 0.2 0.4 0.6 0.8 1
                                     x

Figure 5.7:     The spiral orbit of a particle moving under the influence of a central
force F = −k/r r̂.
      ⃗       3




other hard spheres or radius R2 . The interaction potential² is given by
                                    {
                                         0 r > R2 + r1
                          V (r) =                      ,                      (5.15)
                                        ∞ r < R2 + r1

where r is the distance between the center of r1 from the center of R2 .
Assume that the particles in the beam do not interact with each other
and that there is only one collision per scattering. Let J be the intensity
of the beam³ and A its cross sectional area. Assume that the target has
n particles per unit area. The cross sectional area of the interaction is
σ = π(r1 + R2 )2 where r1 and R2 are the radii of the scattered particles
and targets respectively (see figure (5.8)): All the spheres of the beam
which lie outside this area are not scattered by the particular target. The
total interaction cross section is

                                        Σ = nAσ,                              (5.16)

   ²The so called hard core potential.
   ³The number of particles crossing a surface perpendicular to the beam per unit time
and unit area.
254                                           CHAPTER 5. PLANAR MOTION
                                                              11
                                                              00
                                                              11
                                                              00
                                                              11
                                                              00
                                                              11
                                                              00




                                                             θ
                                                                           11
                                                                           00
                                                                           11
                                                                           00
                                                                           11
                                                                           00
                                                                           11
                                                1111111
                                                0000000                    00
                                                                           11
           00
           11                                  00
                                               11
                                                1111111
                                                0000000                    00
                                                                           11
                                                                           00
           00
           11                                  00
                                               11
                                                1111111
                                                0000000                    11
                                                                           00
           00
           11                                  00
                                               11
                                                1111111
                                                0000000                    11
                                                                           00
                                                1111111
                                                0000000
                                                1111111
                                                0000000
                                                1111111
                                                0000000
                                                              R2           11
                                                                           00
                                                                           11
                                                                           00
                                                                           11
                                                                           00
                                                1111111
                                                0000000                    11
                                                                           00
                                                1111111
                                                0000000                    11
                                                                           00
                                                1111111
                                                0000000                    11
                                                                           00
                                                1111111
                                                0000000                    11
                                                                           00
      r1   11
           00
           11
           00
           11
           00
                                                1111111
                                                0000000
                                                  11
                                                  00
                                                1111111
                                                0000000
                                                  11
                                                  00
                                                  11
                                                  00
                                                              11
                                                              00
                                                              11
                                                              00
                                                              11
                                                              00
                                                                   R+r
                                                                    2 1    11
                                                                           00
                                                                           11
                                                                           00
                                                                           11
                                                                           00
                                                                           11
                                                                           00
                                                                                σ
           11
           00                                     11
                                                  00          11
                                                              00           11
                                                                           00



           00
           11                                      00
                                                   11         00
                                                              11
           00
           11                                      00
                                                   11         00
                                                              11
           00
           11                                      00
                                                   11         00
                                                              11

Figure 5.8: Scattering of hard spheres. The scattering angle is θ. The cross sectional
area σ is shown to the right.



where nA is the total number of target spheres which lie within the beam.
On the average, the scattering rate is

                                  N = JΣ = JnAσ .                               (5.17)

The above equation is the definition of the total scattering cross section
σ of the interaction. The differential cross section σ(θ) is defined by the
relation
                           dN = JnAσ(θ) dΩ ,                       (5.18)
where dN is the number of particles per unit time scattered within the
solid angle dΩ. The total cross section is
             ∫          ∫                    ∫
      σtot =   σ(θ) dΩ = σ(θ) sin θ dθdϕ = 2π σ(θ) sin θ dθ .   (5.19)
                Ω

In the last relation we used the cylindrical symmetry of the interaction
with respect to the axis of the collision. Therefore
                                          1      dN
                                σ(θ) =                   .                      (5.20)
                                         nAJ 2π sin θ dθ
This relation can be used in experiments for the measurement of the
differential cross section by measuring the rate of detection of particles
within the space contained in between two cones defined by the angles
θ and θ + dθ. This is the relation that we will use in the numerical
calculation of σ(θ).
5.4. SCATTERING                                                              255

                                                                   vf




                  vi

        b                                             111
                                                      000
                                                      111
                                                      000
                                                               θ
                                                      111
                                                      000
                                                      111
                                                      000
                                                      111
                                                      000

      db
Figure 5.9: Beam particles passing through the ring 2πbdb are scattered within the
solid angle dΩ = 2πsinθ dθ.



   Generally, in order to calculate the differential cross section we shoot
a particle at a target as shown in figure 5.9. The scattering angle θ
depends on the impact parameter b. The part of the beam crossing the
ring of radius b(θ), thickness db and area 2πb db is scattered in angles
between θ and θ + dθ. Since there is only one particle at the target we
have that nA = 1. The number of particles per unit time crossing the
ring is J2πb db, therefore

                          2πb(θ) db = −2πσ(θ) sin θ dθ                     (5.21)

(the − sign is because as b increases, θ decreases). From the potential we
can calculate b(θ) and from b(θ) we can calculate σ(θ). Conversely, if we
measure σ(θ), we can calculate b(θ).

5.4.1       Rutherford Scattering
The scattering of a charged particle with charge q (“electron”) in a Coulomb
potential of a much heavier charge Q (“nucleus”) is called Rutherford
scattering. In this case, the interaction potential is given by
                                            1 Q
                                 V (r) =          ,                        (5.22)
                                           4πϵ0 r
which accelerates the particle with acceleration
                                      qQ r̂       ⃗r
                              ⃗a =            2
                                                ≡α 3.                      (5.23)
                                     4πϵ0 m r     r
256                                            CHAPTER 5. PLANAR MOTION

The energy of the particle is E = 12 mv 2 and the magnitude of its angular
momentum is l = mvb, where v ≡ |⃗v |. The dependence of the impact
parameter on the scattering angle is [40]

                                             α      θ
                                   b(θ) =       cot   .                            (5.24)
                                             v2     2
Using equation (5.21) we obtain

                                           α2 1       θ
                                σ(θ) =         4
                                                 sin−4 .                           (5.25)
                                           4 v        2
 Consider the scattering trajectories. The results for same charges are

          40

          35

          30

          25

          20

          15

          10

           5

           0
            -20      -15     -10      -5       0          5   10       15     20

Figure 5.10: Rutherford scattering trajectories. We set k1 ≡         qQ
                                                                   4πϵ0 m= 1 (see code in
the file rk2_cb.cpp) and b = 0.08, 0.015, 0.020, 0.035, 0.080, 0.120, 0.200, 0.240, 0.320,
0.450, 0.600, 1.500. The initial position of the particle is at x(0) = −50 and its initial
velocity is v = 3 in the x direction. The number of integration steps is 1000, the initial
time is 0 and the final time is 30.


shown in figure 5.10. A similar figure is obtained in the case of opposite
charges. In the latter case we have to take special care for small impact
parameters b < 0.2 where the scattering angle is ≈ 1. A large number
of integration steps is needed in order to obtain the desired accuracy. A
useful monitor of the accuracy of the calculation is the measurement of
5.4. SCATTERING                                                                   257

                    b       θn        θa        ∆E/E         Nt
                    0.008   2.9975    2.9978    2.8 10−9     5000
                    0.020   2.7846    2.7854    2.7 10−9     5000
                    0.030   2.6131    2.6142    2.5 10−9     5000
                    0.043   2.4016    2.4031    2.3 10−9     5000
                    0.056   2.2061    2.2079    2.0 10−9     5000
                    0.070   2.0152    2.0172    1.7 10−9     5000
                    0.089   1.7887    1.7909    1.4 10−9     5000
                    0.110   1.5786    1.5808    1.0 10−9     5000
                    0.130   1.4122    1.4144    0.8 10−9     5000
                    0.160   1.2119    1.2140    0.5 10−9     5000
                    0.200   1.0123    1.0142    0.3 10−9     5000
                    0.260   0.8061    0.8077    0.1 10−9     5000
                    0.360   0.5975    0.5987    2.9 10−11    5000
                    0.560   0.3909    0.3917    0.3 10−11    5000
                    1.160   0.1905    0.1910    5.3 10−14    5000


Table 5.2: Scattering angles of Rutherford scattering. We set k1 ≡     qQ
                                                                     4πϵ0 m= 1 (see file
rk2_cb.cpp) and study the resulting trajectories for the values of b shown in column
1. θn is the numerically calculated scattering angle and θa is the one calculated from
equation (5.24). The ratio ∆E/E shows the change in the particle’s energy due to
numerical errors. The last column is the number of integration steps. The particle’s
initial position is at x(0) = −50 and initial velocity ⃗v = 3x̂.



the energy of the particle which should be conserved. The results are
shown in table 5.2. We will now describe a method for calculating the
cross section by using equation (5.20). Alternatively we could have used
equation (5.21) and perform a numerical calculation of the derivatives.
This is left as an exercise for the reader. Our calculation is more like
an experiment. We place a “detector” that “detects” particles scattered
within angles θ and θ+δθ. For this reason we split the interval [0, π] in Nb
bins so that δθ = π/Nb . We perform “scattering experiments” by varying
b ∈ [bm , bM ] with step δb. Due to the symmetry of the problem we fix ϕ to
be a constant, therefore a given θ corresponds to a cone with an opening
angle θ and an apex at the center of scattering. For given b we measure
the scattering angle θ and record the number of particles per unit time
δN ∝ bδb. The latter is proportional to the area of the ring of radius
b. All we need now is the beam     ∑ intensity J which is the total number
of particles per unit time J ∝ i bδb (note than in the ratio δN /J the
proportionality constant and δb cancel) and the solid angle 2π sin(θ) δθ.
258                                                CHAPTER 5. PLANAR MOTION

                    b         θn         θa          ∆E/E            STEPS
                    0.020     2.793      2.785       0.02          1 000 000
                    0.030     2.620      2.614       8.2 10−3       300 000
                    0.043     2.405      2.403       7.2 10−4       150 000
                    0.070     2.019      2.017       3.2 10−7       150 000
                    0.089     1.793      1.791       8.2 10−7        60 000
                    0.110     1.583      1.581       1.2 10−6        30 000
                    0.130     1.417      1.414       9.4 10−7        20 000
                    0.160     1.216      1.214       6.0 10−5         5 000
                    0.200     1.016      1.014       4.1 10−6         5 000
                    0.260     0.8093     0.8077      2.2 10−7         5 000
                    0.360     0.6000     0.5987      7.6 10−9         5 000
                    0.560     0.3926     0.3917      1.2 10−10        5 000
                    1.160     0.1913     0.1910      2.9 10−13        5 000


Table 5.3: Rutherford scattering of opposite charges with           = −1. The table is
                                                                         qQ
                                                                       4πϵ0 m
similar to table 5.2. We observe the numerical difficulty for small impact parameters.


Finally we can easily use equation (5.19) in order to calculate the total
cross section σtot . The program that performs this calculation is in the file
scatter.cpp and it is a simple modification of the program in rk2.cpp:

/ / ========================================================
/ / Program t h a t computes s c a t t e r i n g c r o s s −s e c t i o n o f a c e n t r a l
/ / f o r c e on t h e plane . The u s e r should f i r s t check t h a t t h e
/ / parameters used , l e a d t o a f r e e s t a t e i n t h e end .
//       * * X20 i s t h e impact parameter b * *
/ / A 4 ODE system i s s o l v e d using Runge−Kutta Method
/ / User must supply d e r i v a t i v e s
/ / dx1 / dt= f 1 ( t , x1 , x2 , x3 , x4 ) dx2 / dt=f 2 ( t , x1 , x2 , x3 , x4 )
/ / dx3 / dt=f 3 ( t , x1 , x2 , x3 , x4 ) dx4 / dt=f 4 ( t , x1 , x2 , x3 , x4 )
/ / as r e a l ( 8 ) f u n c t i o n s
/ / Output i s w r i t t e n i n f i l e s c a t t e r . dat
/ / ========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
c o n s t i n t P = 1010000;
double T [ P ] , X1 [ P ] , X2 [ P ] , V1 [ P ] , V2 [ P ] ;
5.4. SCATTERING                                                                        259


                100


                  10


                   1
      σ(θ)




                 0.1


               0.01


              0.001
                       0      0.5        1        1.5        2        2.5        3
                                                   θ

Figure 5.11:      Differential cross section of the Rutherford scattering. The solid line
                                                    qQ
is the function (5.25) for α = 1, v = 3. We set 4πϵ  0m
                                                        = 1. The particle’s initial position
is x(0) = −50 and its initial velocity is ⃗v = 3x̂. We used 5000 integration steps, initial
time equal to 0 and final time equal to 30. The impact parameter varies between 0.02
and 1 with step equal to 0.0002.




double k1 , k2 ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
f1 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
     c o n s t double& v1 , c o n s t double& v2 ) ;
double
f2 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
     c o n s t double& v1 , c o n s t double& v2 ) ;
double
f3 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
     c o n s t double& v1 , c o n s t double& v2 ) ;
double
f4 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
     c o n s t double& v1 , c o n s t double& v2 ) ;
double
energy
   ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
     c o n s t double& v1 , c o n s t double& v2 ) ;
void
RK ( c o n s t double& Ti , c o n s t double& Tf ,
260                                          CHAPTER 5. PLANAR MOTION


                 10



                  1
      σ(θ)




                0.1



               0.01



             0.001
                      1                10                100               1000
                                                -4
                                            sin (θ/2)

Figure 5.12: Differential cross section of the Rutherford scattering like in figure 5.11.
The solid line is the function 1/(4 × 34 )x from which we can deduce the functional form
of σ(θ).




      c o n s t double& X10 , c o n s t double& X20 ,
      c o n s t double& V10 , c o n s t double& V20 ,
      const int          & Nt ) ;
void
RKSTEP ( double& t ,
             double& x1 , double& x2 ,
             double& x3 , double& x4 ,
              const           double& dt ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    string buf ;
    double Ti , Tf , X10 , X20 , V10 , V20 ;
    double X20F , dX20 ; / / max impact parameter and s t e p
    int         Nt , i ;
    c o n s t i n t Nbins =20;
    i n t index ;
    double angle , bins [ Nbins ] , Npart ;
    c o n s t double PI           =3.14159265358979324;
    c o n s t double rad2deg =180.0/ PI ;
    c o n s t double dangle =PI / Nbins ;
    double R , density , dOmega , sigma , sigmatot ;
5.4. SCATTERING                                                                           261

 / / Input :
 cout << ”Runge−Kutta Method f o r 4−ODEs I n t e g r a t i o n \n” ;
 cout << ” Enter c o u p l i n g c o n s t a n t s : \ n” ;
 cin >> k1 >> k2 ; getline ( cin , buf ) ;
 cout << ” k1= ” << k1 << ” k2= ” << k2 << endl ;
 cout << ” Enter Nt , Ti , Tf , X10 , X20 , V10 , V20: \ n” ;
 cin >> Nt >> Ti >> Tf>> X10 >> X20 >> V10 >> V20 ;
 getline ( cin , buf ) ;
 cout << ” Enter f i n a l impact parameter X20F and s t e p dX20: \ n” ;
 cin >> X20F >> dX20 ;
 cout << ” Nt = ” << Nt << endl ;
 cout << ”Time : I n i t i a l Ti = ” << Ti
           << ” F i n a l Tf= ”                   << Tf        << endl ;
 cout << ”                          X1 ( Ti )= ” << X10
           << ” X2( Ti )=”                        << X20 << endl ;
 cout << ”                          V1 ( Ti )= ” << V10
           << ” V2( Ti )=”                        << V20 << endl ;
 cout << ” Impact par X20F =” << X20F
           << ” dX20 =”                           << dX20 << endl ;
 ofstream myfile ( ” s c a t t e r . dat ” ) ;
 myfile . precision ( 1 7 ) ;
 f o r ( i =0;i<Nbins ; i++) bins [ i ] = 0 . 0 ;
 / / Calculate :
 Npart = 0 . 0 ;
 X20         = X20 + dX20 / 2 . 0 ; / / s t a r t s i n middle o f f i r s t i n t e r v a l
 while ( X20 < X20F ) {
     RK ( Ti , Tf , X10 , X20 , V10 , V20 , Nt ) ;
     / / Take a b s o l u t e v a l u e due t o symmetry :
     angle = abs ( atan2 ( V2 [ Nt −1] , V1 [ Nt −1]) ) ;
     / / Output : The f i n a l a n g l e . Check i f almost c o n s t a n t
     myfile << ”@ ” << X20 << ” ” << angle
                 << ” ” << abs ( atan2 ( V2 [ Nt −51] , V1 [ Nt −51]) )
                 << ” ” << k1 / ( V10 * V10 ) / tan ( angle / 2 . 0 ) << endl ;
     / / Update histogram :
     index               = i n t ( angle / dangle ) ;
     / / Number o f incoming p a r t i c l e s per u n i t time
     / / i s proportional to radius of ring
     / / o f r a d i u s X20 , t h e impact parameter :
     bins [ index ] += X20 ; / / db i s c a n c e l l e d from d e n s i t y
     Npart               += X20 ; / / <−− i . e . from here
     X20                 += dX20 ;
 } / / while ( X20 < X20F )
 / / Print scattering cross section :
 R                = X20 ;                       / / beam r a d i u s
 density          = Npart / ( PI * R * R ) ;    / / beam f l u x d e n s i t y J
 sigmatot = 0 . 0 ;                             / / t o t a l cross section
 f o r ( i =0;i<Nbins ; i++){
     angle           = ( i +0.5) * dangle ;
     dOmega          = 2 . 0 * PI * sin ( angle ) * dangle ; / / d ( S o l i d Angle )
262                                         CHAPTER 5. PLANAR MOTION

        sigma          = bins [ i ] / ( density * dOmega ) ;
        i f ( sigma >0.0)
            myfile << ” ds= ” << angle
                       << ” ”         << angle * rad2deg
                       << ” ”         << sigma << endl ;
        sigmatot += sigma * dOmega ;
    } / / f o r ( i =0; i <Nbins ; i ++)
    myfile << ” s i g m a t o t= ” << sigmatot << endl ;
    myfile . close ( ) ;
} / / main ( )


   The results are recorded in the file scatter.dat. An example session
that reproduces figures 5.11 and 5.12 is

> g++ scatter . cpp rk2_cb . cpp −o scatter
> . / scatter
Runge−Kutta Method for 4−ODEs Integration
Enter coupling constants :
1 . 0 0.0
k1= 1 k2= 0
Enter Nt , Ti , Tf , X10 , X20 , V10 , V20 :
5000 0 30 −50 0.02 3 0
Enter final impact parameter X20F and step dX20 :
1 0.0002
Nt = 5000
Time : Initial Ti = 0 Final Tf= 30
              X1 ( Ti )= −50 X2 ( Ti ) =0.02
              V1 ( Ti )= 3       V2 ( Ti ) =0
Impact par X20F =1 dX20 =0.0002


The results can be plotted with the gnuplot commands:

gnuplot > s e t l o g
gnuplot > p l o t [ : 1 0 0 0 ] ”<grep ds= s c a t t e r . dat ” \
 u ( ( s i n ( $2 / 2 ) ) **( −4) ) : ( $4 ) notit , \
                   ( 1 . / ( 4 . * 3 . * * 4 ) ) * x notit
gnuplot > unset l o g
gnuplot > s e t l o g y
gnuplot > p l o t [ : ] ”<grep ds= s c a t t e r . dat ” u 2:4 notit , \
 ( 1 . / ( 4 . * 3 . * * 4 ) ) * ( s i n ( x / 2 ) ) **( −4) notit


The results are in a very good agreement with the theoretical ones given
by (5.25). The next step will be to study other central potentials whose
solution is not known analytically.
5.4. SCATTERING                                                                                   263

5.4.2       More Scattering Potentials
Consider scattering from a force field
                                                      {   1
                                                               −    r
                                                                        r≤a
                     F⃗ = f (r) r̂ ,        f (r) =       r2       a3       .                   (5.26)
                                                          0             r>a

This is a very simple classical model of the scattering of a positron e+
by the hydrogen atom. The positron has positive charge +e and the
hydrogen atom consists of a positively charged proton with charge +e
in an electron cloud of opposite charge −e. We set the scales so that
me+ = 1 and e2 /4πϵ0 = 1. We will perform a numerical calculation of
b(θ), σ(θ) and σtot .
   The potential energy is given by

                                    dV (r)          1  r2   3
                       f (r) = −           ⇒ V (r) = + 2 −    .                                 (5.27)
                                     dr             r 2a   2a
where V (r) = 0 for r ≥ a. The program containing the calculation of the
acceleration caused by this force can be found in the file rk_hy.cpp:

/ / ========================================================
/ / The a c c e l e r a t i o n f u n c t i o n s f3 , f 4 ( t , x1 , x2 , v1 , v2 ) provided
/ / by t h e u s e r
/ / ========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
e x t e r n double k1 , k2 ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Motion i n hydrogen atom + p o s i t r o n :
/ / f ( r ) = 1 / r^2−r / k1^3
/ / ax= f ( r ) * x1 / r ay= f ( r ) * x2 / r
double
f3 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) {
    double r2 , r , fr ;
    r2=x1 * x1+x2 * x2 ;
    r =sqrt ( r2 ) ;
    i f ( r <= k1 && r2 > 0 . 0 )
        fr = 1 . 0 / r2−r / ( k1 * k1 * k1 ) ;
    else
        fr = 0 . 0 ;
264                                            CHAPTER 5. PLANAR MOTION


  i f ( fr > 0.0 && r > 0 . 0 )
      r e t u r n fr * x1 / r ; / / dx3 / dt=dv1 / dt=a1
  else
      return 0.0;

}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
f4 ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) {
   double r2 , r , fr ;
   r2=x1 * x1+x2 * x2 ;
   r =sqrt ( r2 ) ;
    i f ( r <= k1 && r2 > 0 . 0 )
        fr = 1 . 0 / r2−r / ( k1 * k1 * k1 ) ;
    else
        fr = 0 . 0 ;

  i f ( fr > 0.0 && r > 0 . 0 )
      r e t u r n fr * x2 / r ; / / dx4 / dt=dv2 / dt=a2
  else
      return 0.0;

}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double
energy
   ( c o n s t double& t , c o n s t double& x1 , c o n s t double& x2 ,
      c o n s t double& v1 , c o n s t double& v2 ) {
   double r , Vr ;
   r=sqrt ( x1 * x1+x2 * x2 ) ;
    i f ( r <= k1 && r > 0 . 0 )
        Vr = 1 / r + 0 . 5 * r * r / ( k1 * k1 * k1 ) − 1 . 5 / k1 ;
    else
        Vr = 0 . 0 ;
   r e t u r n 0 . 5 * ( v1 * v1+v2 * v2 ) + Vr ;
}

   The results are shown in figures 5.13–5.14. We find that σtot = πa2
(see problem 5.10).
   Another interesting dynamical field is given by the Yukawa potential.
This is a phenomenological model of nuclear interactions:
                                    e−r/a
                                    V (r) = k
                                          .                       (5.28)
                                      r
This field can also be used as a model of the effective interaction of
electrons in metals (Thomas–Fermi) or as the Debye potential in a classic
5.5. MORE PARTICLES                                                             265


            3.5
                                                            2.0
                                                            1.5
              3                                             1.0
                                                            0.5
            2.5                                            0.25
                                                          0.125
              2
      θ




            1.5

              1

            0.5

              0
                  0   0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9                 1
                                      b

Figure 5.13: The impact parameter b(θ) for the potential given by equation (5.27)
for different values of the initial velocity v. We set a = 1, x(0) = −5 and made 4000
integration steps from ti = 0 to tf = 40.



plasma. The resulting force is

                                                    e−r/a (     r)
                  F⃗ (r) = f (r) r̂ ,   f (r) = k           1 +               (5.29)
                                                     r2         a
The program of the resulting acceleration can be found in the file rk2_yu.cpp.
The results are shown in figures 5.15–5.16.


5.5       More Particles
In this section we will generalize the discussion of the previous para-
graphs in the case of a dynamical system with more degrees of freedom.
The number of dynamical equations that need to be solved depends on
the number of degrees of freedom and we have to write a program that
implements the 4th order Runge–Kutta method for an arbitrary number
of equations NEQ. We will explain how to allocate memory dynamically, in
which case the necessary memory storage space, which depends on NEQ,
is allocated at the time of running the program and not at compilation
time.
266                                               CHAPTER 5. PLANAR MOTION


               100
                                                                    2.0
                                                                    1.5
                                                                    1.0
                 10                                                 0.5
                                                                   0.25
                                                                  0.125
      σ(θ)




                   1



                0.1



               0.01
                       0      0.5       1       1.5        2      2.5        3       3.5
                                                      θ

Figure 5.14: The function σ(θ) for the potential given by equation (5.27) for different
values of the initial velocity v. We set a = 1, x(0) = −5 and the integration is performed
by making 4000 steps from ti = 0 to tf = 40.



   Until now, memory has been allocated statically. This means that
arrays have sizes which are known at compile time. For example, in
the program rk2.cpp the integer parameter P had a given value which
determined the size of all arrays using the declarations:

c o n s t i n t P = 1010000;
double T [ P ] , X1 [ P ] , X2 [ P ] , V1 [ P ] , V2 [ P ] ;

Changing P after compilation is impossible and if this becomes necessary
we have to edit the file, change the value of P and recompile. Dynamical
memory allocation allows us to read in Nt and NEQ at execution time and
then ask from the operating system to allocate the necessary memory.
The needed memory can be asked for at execution time by using the new
operator. Here is an example:

double * T ; / / D e c l a r e 1−Dim a r r a y s as p o i n t e r s
double * * X ; / / D e c l a r e 2−Dim a r r a y s as p o i n t e r s t o p o i n t e r s
i n t NEQ , Nt ; / / V a r i a b l e s o f a r r a y s i z e s
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
5.5. MORE PARTICLES                                                                          267


                  10
                                                             yu v= 4.0
                                                             cb v= 4.0
                                                            yu v=15.0
                    1                                       cb v=15.0

                  0.1
      θ




                0.01


              0.001


              1e-04
                        0       0.5        1         1.5        2        2.5         3
                                                      b

Figure 5.15:        The function b(θ) for the Yukawa scattering for several values of the
initial velocity v. We set a = 1, k = 1, x(0) = −50 and the integration is performed with
5000 steps from ti = 0 to tf = 30. The lines marked as cb are equation (5.24) of the
Rutherford scattering.




finit ( NEQ ) ; / / f u n c t i o n t h a t s e t s NEQ a t run time
cin >> Nt ; / / read Nt a t run time
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / a l l o c a t e s 1−Dim a r r a y o f Nt doubles
T = new double [ Nt ] ;
/ / a l l o c a t e s 1−Dim a r r a y o f Nt p o i n t e r s t o doubles
X = new double * [ Nt ] ;
/ / f o r each i , a l l o c a t e an a r r a y o f NEQ doubles a t X[ i ] :
f o r ( i n t i =0;i<Nt ; i++) X [ i ] = new double [ NEQ ] ;
.....
( compute with T [ Nt ] , X [ Nt ] [ NEQ ] )
.....
/ / r e t u r n a l l o c a t e d memory back t o t h e system :
d e l e t e [ ] T ; / / d e a l l o c a t e an a r r a y
/ / f o r each i , d e a l l o c a t e t h e a r r a y o f doubles X[ i ] [NEQ]
f o r ( i n t i =0;i<NEQ ; i++) d e l e t e [ ] X [ i ] ;
/ / and then d e a l l o c a t e t h e a r r a y o f p o i n t e r s t o doubles X[ Nt ] :
delete [] X ;
 .....................
void finit ( i n t& NEQ ) { / / f u n c t i o n t h a t s e t s v a l u e o f NEQ
    NEQ = 4 ;
268                                          CHAPTER 5. PLANAR MOTION


                  10
                                                              0.25
                                                               0.5
                      1                                        1.0
                                                               1.5
                  0.1                                          2.0

                 0.01
      θ




              0.001

              1e-04

              1e-05

              1e-06
                          0   0.5       1       1.5       2          2.5     3
                                                 b

Figure 5.16:      The function b(θ) for the Yukawa scattering for several values of the
range a of the force. We set v = 4.0, k = 1, x(0) = −50 and the integration is performed
with 5000 steps from ti = 0 to tf = 30.



}

    In this program, we should remember the fact that in C++, the name
T of an array T[Nt] is a pointer to T[0], which is denoted by &T[0]. This
is the address of the first element of the array in the memory. Therefore,
if the array is double T[Nt], then T is a pointer to a double: double *T.
Then T+i is a pointer to the address of the (i+1)-th element of the array
T[i] and

T+i = &T [ i ]

as well as

T [ i ] = * ( T+i )

We can use pointers with the same notation as we do with arrays: If we
declare a pointer to a double *T1, and assign T1=T, then T1[0], T1[1],
... are the same as T[0], T[1], .... For example, T1[0] = 2.0
assigns also T[0] and vice-versa. Conversely, we can declare a pointer to
5.5. MORE PARTICLES                                                  269

a double *T, as we do in our program, and make it point to a region in
the memory where we have reserved space for Nt doubles. This is what
the operator new does. It asks for the memory for Nt doubles and returns
a pointer to it. Then we assign this pointer to T:

double * T ;
T = new double [ Nt ] ;

Then we can use T[0], T[1], ..., T[Nt-1] as we do with ordinary
arrays.
   Two dimensional arrays are slightly trickier: For a two dimensional
array, double X[Nt][NEQ], X is a pointer to the value X[0][0], which is
&X[0][0]. Then X[i] is a pointer to the one dimensional array X[i][NEQ],
therefore X is a pointer to a pointer of a double!

X [ i ] [ jeq ] is :    double
X[i]            is :    double *
X               is :    double * *

Conversely, we can declare a double **X, and use the operator new to
return a pointer to an array of Nt pointers to doubles, and then for each
element of the array, use new to return a pointer to NEQ doubles:

double * * X
X          = new       double * [ Nt ] ;
X[0]       = new       double [ NEQ ] ;
X[1]       = new       double [ NEQ ] ;
...
X [ Nt −1] = new       double [ NEQ ] ;

Then we can use the notation T[i][jeq], i= 0, 1, ..., Nt-1 and jeq=
0, 1, ..., NEQ-1, as we do with statically defined arrays.
    The memory that we ask to be allocated dynamically is a finite re-
source that can easily be exhausted (heard of memory leaks?). Therefore,
we should be careful to return unused memory to the system, so that it
can be recycled. This should happen especially within functions that we
call many times, which allocate large memory dynamically. The operator
delete can be used to deallocate memory that has been allocated with the
operator new. For one dimensional arrays, this is particularly simple:

double * T ;
T = new double [ Nt ] ;
270                                                 CHAPTER 5. PLANAR MOTION

....
( use T [ i ] )
...
delete [] T;
...
( cannot use T after d e l e t e )

For “two dimensional arrays” that have been allocated as we described
above, first we have to delete the arrays pointed by X[i] for i=0, ... ,
Nt-1, and then the arrays of pointers pointed by X:

X = new double * [ Nt ] ;
f o r ( i n t i =0;i<Nt ; i++) X [ i ] = new double [ NEQ ] ;
. . . . use X [ i ] [ jeq ] . . . .
f o r ( i n t i =0;i<NEQ ; i++) d e l e t e [ ] X [ i ] ; / / d e l e t e a l l a r r a y s X[ i ]
delete [] X ;                                           / / d e l e t e array of pointers

    The main program will be written in the file rkA.cpp, whereas the
force-dependent part of the code will be written in files with names of
the form rkA_XXX.cpp. In the latter, the user must program a function
f(t,X,dXdt) which takes as input the time t and the values of the func-
tions X[NEQ] and outputs the values of their derivatives dXdt[NEQ] at time
t. The function finit(NEQ) sets the number of functions in f and it is
called once during the initialization phase of the program.
    The program in the file rkA.cpp is listed below:

/ / ========================================================
/ / Program t o s o l v e an ODE system using t h e
/ / 4 th order Runge−Kutta Method
/ / NEQ: Number o f e q u a t i o n s
/ / User s u p p l i e s two f u n c t i o n s :
/ / f ( t , x , xdot ) : with double t , x [NEQ] , xdot [NEQ] which
/ / gi ve n t h e time t and c u r r e n t v a l u e s o f f u n c t i o n s x [NEQ]
/ / i t r e t u r n s t h e v a l u e s o f d e r i v a t i v e s : xdot = dx / dt
/ / The v a l u e s o f two c o u p l i n g c o n s t a n t s k1 , k2 may be used
/ / i n f which a r e read i n t h e main program
/ / f i n i t (NEQ) : s e t s t h e v a l u e o f NEQ
//
/ / User I n t e r f a c e :
/ / double k1 , k2 : c o u p l i n g c o n s t a n t s i n g l o b a l scope
/ / Nt , Ti , Tf : Nt−1 i n t e g r a t i o n s t e p s , i n i t i a l / f i n a l time
/ / double X0[NEQ] : i n i t i a l c o n d i t i o n s
/ / Output :
/ / rkA . dat with Nt l i n e s c o n s i s t i n g o f : T[ Nt ] ,X[ Nt ] [NEQ]
/ / ========================================================
# i n c l u d e < iostream >
5.5. MORE PARTICLES                                                                              271

# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double * T ;             / / T[ Nt ]          s t o r e s the values of times
double * * X ;           / / X[ Nt ] [NEQ] s t o r e s t h e v a l u e s o f f u n c t i o n s
double k1 , k2 ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void RK ( c o n s t double& Ti , c o n s t double& Tf , double * X0 ,
                const int            & Nt , c o n s t i n t     & NEQ ) ;
void RKSTEP ( double& t ,                               double * x ,
                c o n s t double& dt , c o n s t i n t          & NEQ ) ;
/ / The f o l l o w i n g f u n c t i o n s a r e d e f i n e d i n rkA_XX . cpp :
void finit (               int       & NEQ ) ; / / S e t s number o f e q u a t i o n s
/ / D e r i v a t i v e and energy f u n c t i o n s :
void          f          ( c o n s t double& t , double * X , double * dXdt ) ;
double energy ( c o n s t double& t , double * X ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    string buf ;
    int             NEQ , Nt ;
    double * X0 ;
    double Ti , Tf ;
    / / Get number o f e q u a t i o n s and a l l o c a t e memory f o r X0 :
    finit ( NEQ ) ;
    X0 = new double [ NEQ ] ;
    / / Input :
    cout << ”Runge−Kutta Method f o r ODE I n t e g r a t i o n . \ n” ;
    cout << ”NEQ= ” << NEQ << endl ;
    cout << ” Enter c o u p l i n g c o n s t a n t s : \ n” ;
    cin >> k1 >> k2 ; getline ( cin , buf ) ;
    cout << ” k1= ” << k1 << ” k2= ” << k2 << endl ;
    cout << ” Enter Nt , Ti , Tf , X0: \ n” ;
    cin >>                      Nt>>Ti>>Tf ;
    f o r ( i n t i =0;i<NEQ ; i++) cin >> X0 [ i ] ; getline ( cin , buf ) ;
    cout << ” Nt = ” << Nt << endl ;
    cout << ”Time : I n i t i a l Ti =” << Ti << ” ”
              << ” F i n a l Tf=”                     << Tf << endl ;
    cout << ”                              X0 =” ;
    f o r ( i n t i =0;i<NEQ ; i++) cout << X0 [ i ] << ” ” ;
    cout << endl ;
    / / A l l o c a t e memory f o r data a r r a y s :
    T = new double [ Nt ] ;
    X = new double * [ Nt ] ;
    f o r ( i n t i =0;i<Nt ; i++) X [ i ] = new double [ NEQ ] ;
    / / The C a l c u l a t i o n :
    RK ( Ti , Tf , X0 , Nt , NEQ ) ;
272                                               CHAPTER 5. PLANAR MOTION

    / / Output :
    ofstream myfile ( ”rkA . dat ” ) ;
    myfile . precision ( 1 6 ) ;
    f o r ( i n t i =0;i<Nt ; i++){
        myfile          << T [ i ]        << ” ” ;
        f o r ( i n t jeq =0; jeq<NEQ ; jeq++)
            myfile << X [ i ] [ jeq ] << ” ” ;
        myfile          << energy ( T [ i ] , X [ i ] ) << ’\n ’ ;
    }
    myfile . close ( ) ;
    / /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    / / C l e a n i n g up dynamic memory : d e l e t e [ ] each a r r a y
    / / c r e a t e d with t h e new o p e r a t o r ( Not n e c e s s a r y i n t h i s
    / / program , i t i s done a t t h e end o f t h e program anyway )
    d e l e t e [ ] X0 ;
    delete [] T ;
    f o r ( i n t i =0;i<NEQ ; i++) d e l e t e [ ] X [ i ] ;
    delete [] X ;
} / / main ( )
/ / ========================================================
/ / D r i v e r o f t h e RKSTEP r o u t i n e
/ / ========================================================
void RK ( c o n s t double& Ti , c o n s t double& Tf , double * X0 ,
                const in t         & Nt , c o n s t i n t   & NEQ ) {
    double dt ;
    double TS ;
    double * XS ;

    XS            = new double [ NEQ ] ;
    / / I n i t i a l i z e variables :
    dt            = ( Tf−Ti ) / ( Nt −1) ;
    T [ 0 ] = Ti ;
    f o r ( i n t ieq =0; ieq<NEQ ; ieq++) X [ 0 ] [ ieq ]= X0 [ ieq ] ;
    TS            = Ti ;
    f o r ( i n t ieq =0; ieq<NEQ ; ieq++) XS [ ieq ]= X0 [ ieq ] ;
    / / Make RK s t e p s : The arguments o f RKSTEP a r e
    / / r e p l a c e d with t h e new ones
    f o r ( i n t i =1; i<Nt ; i++){
        RKSTEP ( TS , XS , dt , NEQ ) ;
        T [ i ] = TS ;
        f o r ( i n t ieq =0; ieq<NEQ ; ieq++) X [ i ] [ ieq ] = XS [ ieq ] ;
    }
    / / Clean up memory :
    d e l e t e [ ] XS ;
} / / RK( )
/ / ========================================================
/ / Function RKSTEP( t , X, dt )
/ / Runge−Kutta I n t e g r a t i o n r o u t i n e o f ODE
/ / ========================================================
5.5. MORE PARTICLES                                                                           273

void RKSTEP ( double& t , double * x , c o n s t double& dt ,
                                            const int  & NEQ ) {
  double tt ;
  double * k1 , * k2 , * k3 , * k4 , * xx ;
  double h , h2 , h6 ;

   k1   =   new   double [ NEQ ] ;
   k2   =   new   double [ NEQ ] ;
   k3   =   new   double [ NEQ ] ;
   k4   =   new   double [ NEQ ] ;
   xx   =   new   double [ NEQ ] ;

    h =dt ;            / / h =dt , i n t e g r a t i o n s t e p
    h2 =0.5* h ;       / / h2=h / 2
    h6=h / 6 . 0 ;     / / h6=h / 6
    / / 1 st step :
    f ( t , x , k1 ) ;
    / / 2nd s t e p :
    f o r ( i n t ieq =0; ieq<NEQ ; ieq++)
        xx [ ieq ] = x [ ieq ] + h2 * k1 [ ieq ] ;
    tt =t+h2 ;
    f ( tt , xx , k2 ) ;
    / / 3rd s t e p :
    f o r ( i n t ieq =0; ieq<NEQ ; ieq++)
        xx [ ieq ] = x [ ieq ] + h2 * k2 [ ieq ] ;
    tt =t+h2 ;
    f ( tt , xx , k3 ) ;
    / / 4 th s t e p :
    f o r ( i n t ieq =0; ieq<NEQ ; ieq++)
        xx [ ieq ] = x [ ieq ] + h * k3 [ ieq ] ;
    tt=t+h ;
    f ( tt , xx , k4 ) ;
    / / Update :
    t += h ;
    f o r ( i n t ieq =0; ieq<NEQ ; ieq++)
        x [ ieq ] += h6 * ( k1 [ ieq ] + 2 . 0 * ( k2 [ ieq ]+ k3 [ ieq ] ) +k4 [ ieq ] ) ;
    / / Clean up memory :
    d e l e t e [ ] k1 ;
    d e l e t e [ ] k2 ;
    d e l e t e [ ] k3 ;
    d e l e t e [ ] k4 ;
    d e l e t e [ ] xx ;
} / / RKSTEP ( )

    Consider three particles of equal mass exerting a force of gravitational
attraction on each other⁴ like the ones shown in figure 5.17. The forces

    ⁴The same program can be used for three equal charges exerting an electrostatic
force on each other, which can be either attractive or repulsive.
274                                         CHAPTER 5. PLANAR MOTION




Figure 5.17: Three particles of equal mass interact via their mutual gravitational
attraction. The problem is solved numerically using the program in the files rkA.cpp,
rkA_3pcb.cpp. The same program can be used in order to study the motion of three
equal charges under the influence of their attractive or repulsive electrostatic force.



exerting on each other are given by
                                mk1
                          F⃗ij = 3 ⃗rij ,    i, j = 1, 2, 3 ,                 (5.30)
                                 rij

where k1 = −Gm and the equations of motion become (i = 1, 2, 3)

                    dxi               dvix       ∑ 3
                                                         xi − xj
                        = vix              = k1              3
                    dt                 dt       j=1,j̸=i
                                                            rij

                    dyi               dviy       ∑ 3
                                                         yi − yj
                        = viy              = k1                  ,            (5.31)
                    dt                 dt       j=1,j̸=i
                                                            rij3

where rij2 = (xi − xj )2 + (yi − yj )2 . The total energy of the system is

                             1                  ∑3
                                                       k1
                        E/m = (v12 + v22 ) +               .                  (5.32)
                             2               i,j=1,j<i
                                                       rij


The relations shown above are programmed in the file rkA_3pcb.cpp
listed below:
5.5. MORE PARTICLES                                                                      275

# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
e x t e r n double k1 , k2 ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / S e t s number o f e q u a t i o n s :
void finit ( i n t& NEQ ) {
    NEQ = 1 2 ;
}
/ / ===============================
/ / Three p a r t i c l e s o f t h e same
/ / mass on t h e plane i n t e r a c t i n g
/ / v i a Coulombic f o r c e
/ / ===============================
void f ( c o n s t double& t , double * X , double * dXdt ) {
    double x11 , x12 , x21 , x22 , x31 , x32 ;
    double v11 , v12 , v21 , v22 , v31 , v32 ;
    double r12 , r13 , r23 ;
    / /−−−−−−−−−−−−−−−−
    x11 = X [ 0 ] ; x21 = X [ 4 ] ; x31 = X [ 8 ] ;
    x12 = X [ 1 ] ; x22 = X [ 5 ] ; x32 = X [ 9 ] ;
    v11 = X [ 2 ] ; v21 = X [ 6 ] ; v31 = X [ 1 0 ] ;
    v12 = X [ 3 ] ; v22 = X [ 7 ] ; v32 = X [ 1 1 ] ;
    / /−−−−−−−−−−−−−−−−
    r12 = pow ( ( x11−x21 ) * ( x11−x21 ) +( x12−x22 ) * ( x12−x22 ) , − 3 . 0 / 2 . 0 ) ;
    r13 = pow ( ( x11−x31 ) * ( x11−x31 ) +( x12−x32 ) * ( x12−x32 ) , − 3 . 0 / 2 . 0 ) ;
    r23 = pow ( ( x21−x31 ) * ( x21−x31 ) +( x22−x32 ) * ( x22−x32 ) , − 3 . 0 / 2 . 0 ) ;
    / /−−−−−−−−−−−−−−−−
    dXdt [ 0 ] = v11 ;
    dXdt [ 1 ] = v12 ;
    dXdt [ 2 ] = k1 * ( x11−x21 ) * r12+k1 * ( x11−x31 ) * r13 ; / / a11=dv11 / dt
    dXdt [ 3 ] = k1 * ( x12−x22 ) * r12+k1 * ( x12−x32 ) * r13 ; / / a12=dv12 / dt
    / /−−−−−−−−−−−−−−−−
    dXdt [ 4 ] = v21 ;
    dXdt [ 5 ] = v22 ;
    dXdt [ 6 ] = k1 * ( x21−x11 ) * r12+k1 * ( x21−x31 ) * r23 ; / / a21=dv21 / dt
    dXdt [ 7 ] = k1 * ( x22−x12 ) * r12+k1 * ( x22−x32 ) * r23 ; / / a22=dv22 / dt
    / /−−−−−−−−−−−−−−−−
    dXdt [ 8 ] = v31 ;
    dXdt [ 9 ] = v32 ;
    dXdt [ 1 0 ] = k1 * ( x31−x11 ) * r13+k1 * ( x31−x21 ) * r23 ; / / a31=dv31 / dt
    dXdt [ 1 1 ] = k1 * ( x32−x12 ) * r13+k1 * ( x32−x22 ) * r23 ; / / a32=dv32 / dt
}
/ / ===============================
double energy ( c o n s t double& t , double * X ) {
276                                          CHAPTER 5. PLANAR MOTION

    double x11 , x12 , x21 , x22 , x31 , x32 ;
    double v11 , v12 , v21 , v22 , v31 , v32 ;
    double r12 , r13 , r23 ;
    double e ;
    / /−−−−−−−−−−−−−−−−
    x11 = X [ 0 ] ; x21 = X [ 4 ] ; x31 = X [ 8 ] ;
    x12 = X [ 1 ] ; x22 = X [ 5 ] ; x32 = X [ 9 ] ;
    v11 = X [ 2 ] ; v21 = X [ 6 ] ; v31 = X [ 1 0 ] ;
    v12 = X [ 3 ] ; v22 = X [ 7 ] ; v32 = X [ 1 1 ] ;
    / /−−−−−−−−−−−−−−−−
    r12 = pow ( ( x11−x21 ) * ( x11−x21 ) +( x12−x22 ) * ( x12−x22 ) , −0.5) ;
    r13 = pow ( ( x11−x31 ) * ( x11−x31 ) +( x12−x32 ) * ( x12−x32 ) , −0.5) ;
    r23 = pow ( ( x21−x31 ) * ( x21−x31 ) +( x22−x32 ) * ( x22−x32 ) , −0.5) ;
    / /−−−−−−−−−−−−−−−−
    e    = 0 . 5 * ( v11 * v11+v12 * v12+v21 * v21+v22 * v22+v31 * v31+v32 * v32 ) ;
    e += k1 * ( r12+r13+r23 ) ;
    return e ;
}

In order to run the program and see the results, look at the commands
in the shell script in the file rkA_3pcb.csh. In order to run the script use
the command

> rkA_3pcb . csh −0.5 4000 1 . 5 −1 0 . 1 1 0 1 −0.1 −1 0 0.05 1 0 −1

 which will run the program setting k1 = −0.5, ⃗r1 (0) = −x̂+0.1ŷ, ⃗v1 (0) = x̂,
⃗r2 (0) = x̂ − 0.1ŷ, ⃗v2 (0) = −x̂, ⃗r3 (0) = 0.05x̂ + ŷ, ⃗v3 (0) = −ŷ, Nt= 4000 and
 tf = 1.5.
5.6. PROBLEMS                                                             277

5.6    Problems
5.1 Reproduce the results shown in figures 5.3 and 5.4. Compare your
    results to the known analytic solution.
5.2 Write a program for the force on a charged particle in a constant
    magnetic field B ⃗ = B k̂ and compute its trajectory for ⃗v (0) = v0x x̂ +
    v0y ŷ. Set x(0) = 1, y(0) = 0, v0y = 0 and calculate the resulting
    radius of the trajectory. Plot the relation between the radius and
    v0x . Compare your results to the known analytic solution. (assume
    non relativistic motion)
5.3 Consider the anisotropic harmonic oscillator ax = −ω12 x, ay = −ω22 y.
    Construct the Lissajous curves by setting x(0) = 0, y(0) = 1, vx (0) =
    1, vy (0) = 0, tf = 2π, ω22 = 1, ω12 = 1, 2, 4, 9, 16, . . .. What happens
    when ω12 ̸= nω22 ?
5.4 Reproduce the results displayed in table 5.1 and figures 5.5 and 5.6.
    Plot ln a vs ln T and calculate the slope of the resulting straight line
    by using the linear least squares method. Is it what you expect?
    Calculate the intercept and compare your result with the expected
    one.
5.5 Calculate the angular momentum with respect to the center of the
    force at each integration step of the planetary motion and check
    whether it is conserved. Show analytically that conservation of
    angular momentum implies that the position vector sweeps areas at
    constant rate.
5.6 Calculate the escape velocity of a planet ve for GM = 10.0, y(0) = 0.0,
    x0 = x(0) = 1 using the following steps: First show that v02 =
    −GM (1/a) + ve2 . Then set vx (0) = 0, vy (0) = v0 . Vary vy (0) = v0 and
    measure the resulting semi-major axis a. Determine the intercept
    of the resulting straight line in order to calculate ve .
5.7 Repeat the previous problem for x0 = 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5,
    4.0. From the ve = f (1/x0 ) plot confirm the relation (5.14).
5.8 Check that for the bound trajectory of a planet with GM = 10.0,
    x(0) = 1, y(0) = 0.0, vx (0) = 0 , vy (0) = 4 you obtain that F1 P +
    F2 P = 2a for each point P of the trajectory. The point F1 is the
    center of the force. After determining the semi-major axis a nu-
    merically, the point F2 will be taken symmetric to F1 with respect
    to the center of the ellipse.
278                                      CHAPTER 5. PLANAR MOTION

 5.9 Consider the planetary motion studied in the previous problem.
     Apply a momentary push in the tangential direction after the planet
     has completed 1/4 of its elliptical orbit. How stable is the particle
     trajectory (i.e. what is the dependence of the trajectory on the
     magnitude and the duration of the push?)? Repeat the problem
     when the push is in the vertical direction.

5.10 Consider the scattering potential of the positron-hydrogen system
     given by equation (5.26). Plot the functions f (r) and V (r) for
     different values of a. Calculate the total cross section σtot numerically
     and show that it is equal to πa2 .

5.11 Consider the Morse potential of diatomic molecules:

                      V (r) = D (exp(−2αr) − 2 exp(−αr))               (5.33)

      where D, α > 0. Compute the solutions of the problem numerically
      in one dimension and compare them to the known analytic solutions
      when E < 0:
                   {     √                   √               }
                1    D − D(D − |E|) sin(αt 2|E|/m + C)
         x(t) = ln                                         ,     (5.34)
                α                     |E|

      where the integration constant as a function of the initial position
      and energy is given by
                                   [              ]
                                     D  − |E|eαx0
                         C = sin−1 √                .              (5.35)
                                       D(D − |E|)

      We obtain
           √ a periodic motion with an energy dependent period =
      (π/α) 2m/|E|. For E > 0 we obtain
                   {√                  √              }
                1     D(D + E) cosh(αt 2E/m + C) − D
         x(t) = ln                                         (5.36)
                α                   |E|

      whereas for E = 0
                                    {                    }
                              1         1 Dα2
                        x(t) = ln         +   (t + C)2       .         (5.37)
                              α         2   m
      In these equations, the integration constant C is given by a different
      relation and not by equation (5.35). Compute the motion in phase
      space (x, ẋ) and study the transition from open to closed trajectories.
5.6. PROBLEMS                                                              279

5.12 Consider the effective potential term Vef f (r) = l2 /2mr2 (l ≡ |L|)
                                                                       ⃗ in
     the previous problem. Plot the function Vtot (r) = V (r) + Vef f (r) for
     D = 20, α = 1, m = 1, l = 1, and of course for r > 0. Determine the
     equilibrium position and the ionization energy.
     Calculate the solutions x(t), y(t), y(x), r(t) on the plane for E > 0,
     E = 0, and E < 0 numerically. In the E < 0 case consider the
     scattering problem and calculate the functions b(θ), σ(θ) and the
     total cross section σtot .
5.13 Consider the potential of the molecular model given by the force
     F⃗ (r) = f (r) r̂ where f (r) = 24(2/r13 − 1/r7 ). Calculate the potential
     V (r) and plot the function Vtot (r) = V (r) + Vef f (r). Determine the
     equilibrium position and the ionization energy.
     Consider the problem of scattering and calculate b(θ), σ(θ) and σtot
     numerically. How much do your results depend on the minimum
     scattering angle?
5.14 Compute the trajectories of a particle under the influence of a force
     F⃗ = −k/r3 r̂. Determine appropriate initial conditions that give a
     spiral trajectory.
5.15 Compute the total cross section σtot for the Rutherford scattering
     both analytically and numerically. What happens to your numerical
     results as you vary the integration limits?
5.16 Write a program that computes the trajectory of a particle that
     moves on the plane in the static electric field of N static point
     charges.
5.17 Solve the three body problem described in the text in the case of
     three different electric charges by making the appropriate changes
     to the program in the file rkA_3cb.cpp.
5.18 Two charged particles of equal mass and charge are moving on the
     xy plane in a constant magnetic field B  ⃗ = B ẑ. Solve the equations of
     motion using a 4th order Runge–Kutta Method. Plot the resulting
     trajectories for the initial conditions that you will choose.
5.19 Three particles of equal mass m are connected by identical springs.
     The springs’ spring constant is equal to k and their equilibrium
     length is equal to l. The particles move without friction on a hori-
     zontal plane. Solve the equations of motion of the system numeri-
     cally by using a 4th order Runge–Kutta Method. Plot the resulting
280                                         CHAPTER 5. PLANAR MOTION

      trajectories for the initial conditions that you will choose. (Hint:
      Look in the files rkA_3hoc.cpp, rkA_3hoc.csh.)




Figure 5.18:     Two identical particles are attached to thin weightless rods of length
l and they are connected by an ideal weightless spring with spring constant k and
equilibrium length l. The rods are hinged to the ceiling at points whose distance is l.
(Problem 5.20).



5.20 Two identical particles are attached to thin weightless rods of length
     l and they are connected by an ideal weightless spring with spring
     constant k and equilibrium length l. The rods are hinged to the
     ceiling at points whose distance is l (see figure 5.18). Compute
     the Lagrangian of the system and the equations of motion for the
     degrees of freedom θ1 and θ2 . Solve these equations numerically
     by using a 4th order Runge–Kutta method. Plot the positions of
     the particles in a Cartesian coordinate system and the resulting tra-
     jectory. Study the normal modes for small angles θ1 ≲ 0.1 and
     compute the deviation of the solutions from the small oscillation
     approximation as the angles become larger. (Hint: Look in the files
     rk_cpend.cpp, rk_cpend.csh)

5.21 Repeat the previous problem when the hinges of the rods slide
     without friction on the x axis.

5.22 Repeat problem 5.20 by adding a third pendulum to the right at
     distance l.
Chapter 6

Motion in Space

In this chapter we will study the motion of a particle in space (three
dimensions). We will also discuss the case of the relativistic motion,
which is important if one wants to consider the motion of particles moving
with speeds comparable to the speed of light. This will be an opportunity
to use an adaptive stepsize Runge-Kutta method for the numerical solution
of the equations of motion. We will use the open source code rksuite¹
available at the Netlib² repository. Netlib is an open source, high quality
repository for numerical analysis software. The software it contains is
used by many researchers in their high performance computing programs
and it is a good investment of time to learn how to use it. Most of it
is code written in Fortran and, in order to use it, you should learn how
to link a program written in C++ with functions written in a different
programming language.
   The main technical skill that you will develop in this chapter is looking
for solutions to your numerical problems provided by software written
by others. It is important to be able to locate the optimal solution to your
problem, find the relevant functions, read the software’s documentation
carefully and filter out the necessary information in order to call and link
the functions to your program.



   ¹R.W. Brankin, I. Gladwell, and L.F. Shampine, RKSUITE: a suite of Runge-Kutta
codes for the initial value problem for ODEs, Softreport 92-S1, Department of Mathe-
matics, Southern Methodist University, Dallas, Texas, U.S.A, 1992.
   ²www.netlib.org


                                       281
282                                   CHAPTER 6. MOTION IN SPACE

6.1 Adaptive Stepsize Control for RK Methods
The three dimensional equation of motion of a particle is an initial value
problem given by the equations (4.6)

               dx               dvx
                  = vx              = ax (t, x, vx , y, vy , z, vz )
               dt                dt
               dy               dvz
                  = vy              = ay (t, x, vx , y, vy , z, vz )
               dt                dt
               dz               dvz
                  = vz              = az (t, x, vx , y, vy , z, vz ) .   (6.1)
               dt                dt
    For its numerical solution we will use an adaptive stepsize Runge–
Kutta algorithm for increased performance and accuracy. Adaptive step-
size is used in cases where one needs to minimize computational effort
for given accuracy goal. The method frequently changes the time step
during the integration process, so that it is set to be large through smooth
intervals and small when there are abrupt changes in the values of the
functions. This is achieved by exercising error control, either by monitor-
ing a conserved quantity or by computing the same solution using two
different methods. In our case, two Runge-Kutta methods are used, one
of order p and one of order p + 1, and the difference of the results is used
as an estimate of the truncation error. If the error needs to be reduced,
the step size is reduced and if it is satisfactorily small the step size is
increased. For the details we refer the reader to [33]. Our goal is not to
analyze and understand the details of the algorithm, but to learn how to
find and use appropriate and high quality code written by others.


6.1.1 The rksuite Suite of RK Codes
The link http://www.netlib.org/ode/ reads

lib  rksuite
alg  Runge−Kutta
for  initial value problem for first order ordinary ←-
   differential
     equations . A suite of codes for solving IVPs in ODEs . A
     choice of RK methods , is available . Includes an error
     assessment facility and a sophisticated stiffness checker .
     Template programs and example results provided .
     Supersedes RKF 45 , DDERKF , D02PAF .
ref RKSUITE , Softreport 92−S 1 , Dept of Math , SMU , Dallas , ←-
   Texas
6.1. ADAPTIVE STEPSIZE CONTROL FOR RK METHODS                                  283

by   R . W . Brankin ( NAG ) , I . Gladwell and L . F . Shampine ( SMU )
lang Fortran
prec double

There, we learn that the package provides code for Runge–Kutta methods,
whose source is open and written in the Fortran language. We also learn
that the code is written for double precision variables, which is suitable
for our problem. Last, but not least, we are also happy to learn that it is
written by highly reputable people! We download³ the files rksuite.f,
rksuite.doc, details.doc, templates, readme.
    In order to link the subroutines provided by the suite to our pro-
gram we need to read the documentation carefully. In the general case,
documentation is available on the web (html, pdf, ...), bundled files with
names like README and INSTALL, in whole directories with names like
doc/, online help in man and/or info pages and, finally, in good old fash-
ioned printed manuals. Good quality software is also well documented
inside the source code files, something that is true for the software at
hand.
    In order to link the suite’s subroutines to our program we need the
following basic information:

   • INPUT DATA: This is the necessary information that the program
     needs in order to perform the calculation. In our case, the mini-
     mal such information is the initial conditions, the integration time
     interval and the number of integration steps. The user should also
     provide the functions on the right hand side of (6.1). It might also
     be necessary to provide information about the desired accuracy goal,
     the scale of the problem, the hardware etc.

   • OUTPUT DATA: This is the information on how we obtain the
     results of the calculation for further analysis. Information whether
     the calculation was successful and error free could also be provided.

   • WORKSPACE: This is information on how we provide the necessary
     memory space used in the intermediate calculations. Such space
     needs to be provided by the user in programming languages where
     dynamical memory allocation is not possible, like in Fortran 77,
     and the size of workspace depends on the parameters of the calling
     program.

   ³For the convenience of the reader, these files can be found bundled in the accom-
panied software in a subdirectory rksuite.
284                                                 CHAPTER 6. MOTION IN SPACE

   It is easy to install the software. All the necessary code is in one file
rksuite.f. The file rksuite.doc⁴ contains the documentation. There we
read that we need to inform the program about the hardware dependent
accuracy of floating point numbers. We need to set the values of three
variables:

...
RKSUITE requires three environmental constants OUTCH , MCHEPS ,
DWARF . When you use RKSUITE , you may need to know their
values . You can obtain them by calling the subroutine ENVIRN
in the suite :

      CALL ENVIRN ( OUTCH , MCHPES , DWARF )

returns values

      OUTCH      − INTEGER
                      Standard output channel on the machine being used .
   MCHEPS − DOUBLE PRECISION
                      The unit of roundoff , that is , the largest
                      positive number such that 1 . 0 D0 + MCHEPS = 1 . 0 D 0 .
   DWARF − DOUBLE PRECISION
                      The smallest positive number on the machine being
                      used .
...
* * * * * * * * * * * * * * * * * * * * * * * * * * Installation Details * * * * * * * * * * * *

 All machine−dependent aspects of the suite have been
 isolated in the subroutine ENVIRN in the rksuite . f file .
...

The variables OUTCH, MCHEPS, DWARF are defined in the subroutine ENVIRN.
They are given generic default values but the programmer is free to
change them by editing ENVIRN. We should identify the routine in the file
rksuite.f and read the comments in it⁵:

...
        SUBROUTINE ENVIRN ( OUTCH , MCHEPS , DWARF )
...
C The f o l l o w i n g s i x s t a t e m e n t s a r e t o be Commented out
C a f t e r v e r i f i c a t i o n t h a t t h e machine and i n s t a l l a t i o n
C dependent q u a n t i t i e s a r e s p e c i f i e d c o r r e c t l y .
...
        WRITE ( * , * ) ’ Before using RKSUITE , you must v e r i f y t h a t t h e     ’

   ⁴This is a simple text file which you can read with the command less rksuite.doc
or with emacs.
   ⁵These are lines that begin with a C, as this is old fixed format Fortran code.
6.1. ADAPTIVE STEPSIZE CONTROL FOR RK METHODS                                                                     285

         WRITE ( *   ,*)   ’   machine− and i n s t a l l a t i o n −dependent q u a n t i t i e s            ’
         WRITE ( *   ,*)   ’   s p e c i f i e d i n t h e s u b r o u t i n e ENVIRN a r e c o r r e c t ,   ’
         WRITE ( *   ,*)   ’   and then Comment t h e s e WRITE s t a t e m e n t s and t h e                 ’
         WRITE ( *   ,*)   ’   STOP s t a t e m e n t out o f ENVIRN .                                        ’
         STOP
...
C The f o l l o w i n g v a l u e s a r e a p p r o p r i a t e t o IEEE
C a r i t h m e t i c with t h e t y p i c a l standard output channel .
C
        OUTCH = 6
        MCHEPS = 1 . 1 1 D−16
        DWARF = 2.23 D−308

All we need to do is to comment out the WRITE and STOP commands since
we will keep the default values of the OUTCH, MCHEPS, DWARF variables:

...
C        WRITE ( *   ,*)   ’   Before using RKSUITE , you must v e r i f y t h a t t h e                      ’
C        WRITE ( *   ,*)   ’   machine− and i n s t a l l a t i o n −dependent q u a n t i t i e s            ’
C        WRITE ( *   ,*)   ’   s p e c i f i e d i n t h e s u b r o u t i n e ENVIRN a r e c o r r e c t ,   ’
C        WRITE ( *   ,*)   ’   and then Comment t h e s e WRITE s t a t e m e n t s and t h e                 ’
C        WRITE ( *   ,*)   ’   STOP s t a t e m e n t out o f ENVIRN .                                        ’
C        STOP
...

   In order to check whether the default values are satisfactory, we can
use the C++ template numeric_limits, which is part of the C++ Standard
Library. In the file numericLimits.cpp, we write a small test program⁶:

# i n c l u d e < iostream >
# include <limits >
using namespace std ;

i n t main ( ) {
    double MCHEPS , DWARF ;

      MCHEPS = numeric_limits <double > : : epsilon ( ) ;
      DWARF = numeric_limits <double > : : min      () ;
      cout << ”MCHEPS = ” << MCHEPS / 2 . 0 << endl ;
      cout << ”DWARF = ” << DWARF            << endl ;
}

We compile and run the above program as follows:

> g++ numericLimits . cpp −o n
> ./n
MCHEPS = 1.11022 e−16

    ⁶The file in the accompanying software, shows you how to compute numeric limits
for several types of variables.
286                                       CHAPTER 6. MOTION IN SPACE

DWARF    = 2.22507 e−308

We conclude that our choices are satisfactory.
    Next, we need to learn how to use the subroutines in the suite. By
carefully reading rksuite.doc we learn the following: The interface to the
adaptive stepsize Runge–Kutta algorithm is the routine UT (UT = “Usual
Task”). The routine can use a 2nd-3rd (RK23) order Runge-Kutta pair
for error control (METHOD=1), a 4th-5th (RK45) order pair (METHOD=2) or
a 7th-8th (RK78) order pair (METHOD=3). We will set METHOD=2 (RK45).
The routine SETUP must be called before UT for initialization. The user
should provide a function F that calculates the derivatives of the functions
we integrate for, i.e. the right hand side of 6.1.
    The fastest way to learn how to use the above routines is “by exam-
ple”. The suite include a templates package which can be unpacked by
executing the commands in the file templates using the sh shell:

> sh templates
tmpl1 . out
tmpl1a . f
...

The file tmpl1a.f contains the solution of the simple harmonic oscillator
and has many explanatory comments in it. The code is in Fortran,
but it is not so hard to read. You may compile it and run it with the
commands:

> cd rksuite / templates
> g f o r t r a n tmpl1a . f . . / rksuite . f −o example1
> . / example1

We encourage the reader to study it carefully, run it and test its results.


6.1.2 Interfacing C++ Programs with Fortran
Next, we have to learn how to link the Fortran code in rksuite.f to a
C++ program. There is a lot of relevant information that you can find
with a simple search in the web, we will concentrate on what is relevant
to the program that we need to write. The first thing that we need to
learn is how to call a function written in Fortran from a C++ program. A
simple “Hello World” program can teach us how to do it. Suppose that
a Fortran function/subroutine HELLO() is coded in a file helloF.f90:
6.1. ADAPTIVE STEPSIZE CONTROL FOR RK METHODS                                     287


SUBROUTINE      HELLO ( )

 PRINT * , ’ H e l l o World ! ’

END SUBROUTINE HELLO

Then, we write in the file hello.cpp:

# i n c l u d e < iostream >
using namespace std ;
e x t e r n ”C” void hello_ ( ) ;
i n t main ( ) {
    hello_ ( ) ;
}

The first thing that we notice is that we call the function by lowering all
letters in its name: HELLO → hello. In Fortran, lowercase and uppercase
letters are equivalent, and the compiler creates names with lowercase
letters only. Next, we find that we need to append an underscore _ to
the function’s name⁷: hello → hello_. The Fortran function needs to
be declared in the “"C" language linkage”:

e x t e r n ”C” void   hello_ ( ) ;

This is something one has to do both for functions written in Fortran, as
well as for functions written in plain old C⁸.
   In order to compile and run the code we have to run the commands:

> g f o r t r a n −c helloF . f90
> g++ hello . cpp helloF . o −o hello −lgfortran
> . / hello
 Hello World !

Compilation is done in two steps: We first need to compile the Fortran
program using the Fortran compiler⁹ gfortran. The flag -c forces the
   ⁷Read your compiler’s manual, there could be options that you can use at compile
time so that you can avoid it. But the advice is to stick with this convention, so that
your code will be portable and ... long lived!
   ⁸Language linkage encapsulates the set of requirements necessary in order to link
with a function written in another programming language, and it should be done for all
function types, names and variable names. There could be linkage to other program-
ming languages, but only the C and C++ linkage is guaranteed to be available.
   ⁹Available for free download from gcc.gnu.org/fortran/. On debian based Linux
288                                      CHAPTER 6. MOTION IN SPACE

compiler to perform compilation but not linking. It produces an ob-
ject file, whose extension is .o, helloF.o. These are files which contain
compiled code in non-readable text form, but they are not autonomous
executable programs. The functions that they contain, can be linked to
other compiled programs that call them. In the second step, g++ is called
to compile the C++ source code in hello.cpp and link it to the functions
in helloF.o. The flag -lgfortran is necessary in order to link to the
standard Fortran functions. If you use a different compiler, you should
read its manual in order to find the correct linking options.
    Another subtle point that needs to be considered is that, in Fortran,
variables are passed to functions by reference and not by value. Therefore,
we have to pass variables as pointers or as reference to variables. For
example, the following Fortran function¹⁰

REAL ( 8 ) FUNCTION SQUAREMYDOUBLE ( X )
 REAL( 8 ) x

 X = 2.0* X
 SQUAREMYDOUBLE = X * X

END        FUNCTION SQUAREMYDOUBLE

must be declared and called as:

e x t e r n ”C” double squaremydouble_ ( double& x ) ;
...
    double x , x2 ;
   x2 = squaremydouble_ ( x ) ;

For example, by modifying the hello.cpp program as

# i n c l u d e < iostream >
using namespace std ;
e x t e r n ”C” void       hello_ ( ) ;
e x t e r n ”C” double squaremydouble_ ( double& x ) ;
i n t main ( ) {
    double x , x2 ;
    hello_ ( ) ;
    x = 2.0;
    x2 = squaremydouble_ ( x ) ;

systems, install with sudo apt-get install gfortran.
   ¹⁰A Fortran function returns the value stored in a variable with the same name as
the name of the function, here SQUAREMYDOUBLE.
6.1. ADAPTIVE STEPSIZE CONTROL FOR RK METHODS                                   289

    cout << ” x   = ”              << 2.0 << endl ;
    cout << ”2 x = ”               << x   << endl ;
    cout << ” (2 x ) * ( 2 x ) = ” << x2 << endl ;
}

we obtain the output:

> g f o r t r a n −c helloF . f90 ;
> g++ hello . cpp helloF . o −o hello −lgfortran
> . / hello
  Hello World !
x     = 2
2 x = 4
(2 x ) * ( 2 x ) = 16

Notice that the value of x is modified in the calling program.
    The final issue that we will consider, it how to pass arrays to Fortran
functions. One dimensional arrays are quite easy to handle. In order to
pass an array double v[N] to a Fortran function, we only need to declare
it and pass it as one of its arguments. If the Fortran program is

r e a l ( 8 ) f u n c t i o n make_array1 ( v , N )
  integer          N
  real (8) v(N)
  . . . compute v ( 1 ) . . . v ( N ) . . .
end           f u n c t i o n make_array1

then the corresponding C++ program should be:

c o n s t i n t N =4;
e x t e r n ”C” double make_array1_ ( double v [ N ] , c o n s t i n t& N ) ;
i n t main ( ) {
    double v [ N ] , x ;
    ...
   x = make_array1_ ( v , N ) ;
    . . . use v [ 0 ] . . . v [ N−1] . . .
}

The only point we need to stress is that the array real(8) v(N) is indexed
from 1 to N in the Fortran program, whereas the array double v[N] is
indexed from 0 to N-1 in the C++ program. The correspondence of the
values stored in memory is v(1) → v[0], ... , v(i) → v[i-1], ... v(N)
→ v[N-1].
   Two dimensional arrays need more attention. In C++, arrays are in
row-major mode, whereas in Fortran in column-major mode. The contents
290                                                 CHAPTER 6. MOTION IN SPACE

of a two dimensional array are stored linearly in memory. In C++, the
elements of an array double A[N][M] are stored in the sequence A[0][0],
A[0][1], A[0][2], ... , A[0][M-1], A[1][0], A[1][1], ... ,
A[1][M-1], ... A[N-1][M-1]. In Fortran, the elements of an array
real(8) A(N,M) are stored in the sequence A(1,1), A(2,1), A(3,1),
... , A(1,M), A(2,1), A(2,2), ... , A(2,M), ... , A(N,M).
Therefore, when we pass an array from the C++ program to a Fortran
function, we have to keep in mind that the Fortran function will use it
with its indices transposed. For example, if the Fortran code defines

    A(i , j) = i + j/10.0

which results into A(i,j) = i.j in decimal notation¹¹ (e.g. A(2,3)=
2.3), then the value of A[i][j] will be (j+1).(i+1) (e.g. A[2][3] =
4.3, A[2][1] = 2.3)!
   All of the above are summarized in the Fortran program in the file
CandFortranF.f90:

r e a l ( 8 ) f u n c t i o n make_array1 ( v , N )
  i m p l i c i t none
  integer N , i
  real (8) v(N)

 do i =1 , N
  v(i) = i
 end do

 make_array1 = −11.0 ! a r e t u r n v a l u e

end f u n c t i o n make_array1
!−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
r e a l ( 8 ) f u n c t i o n make_array2 ( A , N , M )
  i m p l i c i t none
  integer N , M , i , j
  r e a l ( 8 ) A ( M , N ) ! C a r e f u l : N and M a r e i n t e r c h a n g e d ! !

 do i =1 , M
  do j =1 , N
  !A( i , j ) = i . j , e . g . A( 2 , 3 ) =2.3
   A(i , j) = i + j/10.0
  end do
 end do


   ¹¹Of course, we assume i,j<10.
6.1. ADAPTIVE STEPSIZE CONTROL FOR RK METHODS                                        291

    make_array2 = −22.0 ! a r e t u r n v a l u e

end f u n c t i o n make_array2

and the C++ program in the file CandFortranC.cpp:

# include      < iostream >
# include      < fstream >
# include      <cstdlib >
# include      <string >
# include      <cmath>

using namespace std ;

c o n s t i n t N =4 , M =3;
e x t e r n ”C” {
    double make_array1_ ( double v [ N ]                  , c o n s t i n t& N ) ;
    double make_array2_ ( double A [ N ] [ M ] , c o n s t i n t& N ,
                                   c o n s t i n t& M ) ;
}
i n t main ( ) {
    double A [ N ] [ M ] , v [ N ] ;
    double x ;

     / / Make a 1D a r r a y using a f o r t r a n f u n c t i o n :
     x = make_array1_ ( v , N ) ;
     cout << ” 1D a r r a y : Return v a l u e x= ” << x << endl ;
     f o r ( i n t i =0;i<N ; i++)
         cout << v [ i ] << ” ” ;
     cout << ”\n−−−−−−−−−−−−−−−−−−−−−−−−−\n” ;
     / / Make an 2D a r r a y using a f o r t r a n f u n c t i o n :
     x = make_array2_ ( A , N , M ) ;
     cout << ”2D a r r a y : Return v a l u e x= ” << x << endl ;
     f o r ( i n t i =0;i<N ; i++){
         f o r ( i n t j =0;j<M ; j++)         / /A i s . . . transposed !
             / / A[ i ] [ j ] = ( j +1) . ( i +1) , e . g . A[ 1 ] [ 2 ] = 3 . 1
             cout << A [ i ] [ j ] << ” ” ;
         cout << ’\n ’ ;
     }
}

Note that the array A[N][M] is defined as A(M,N) in the Fortran function,
and the roles of N and M are interchanged. You can run the code and see
the output with the commands:

> g f o r t r a n −c CandFortranF . f90
> g++ CandFortranC . cpp CandFortranF . o −o CandFortran −lgfortran
292                                        CHAPTER 6. MOTION IN SPACE

> . / CandFortran
1D array : Return value x= −11
1 2 3 4
−−−−−−−−−−−−−−−−−−−−−−−−−
2D array : Return value x= −22
 1.1 2.1 3.1
1 . 2 2.2 3.2
1 . 3 2.3 3.3
1 . 4 2.4 3.4

Note that the values of the array A(M,N) are transposed when printed as
rows in the C++ program.

6.1.3 The rksuite Driver
After we become wise enough, we can write the driver for the integration
routine UT (called by ut_ from our C++ program), which can be found
in the file rk3.cpp:

/ / ========================================================
/ / Program t o s o l v e a 6 ODE system using Runge−Kutta Method
/ / Output i s w r i t t e n i n f i l e rk3 . dat
/ / ========================================================
/ / Compile with t h e commands :
/ / g f o r t r a n −c r k s u i t e / r k s u i t e . f ;
/ / g++ rk3 . cpp rk3_g . cpp r k s u i t e . o −o rk3 −l g f o r t r a n
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
# i n c l u d e ” rk3 . h”
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double k1 , k2 , k3 , k4 ;
double energy ( c o n s t double& t , double * Y ) ;
void f ( double& t , double * Y , double * YP ) ;
e x t e r n ”C” {
    void setup_ ( c o n s t i n t& NEQ ,
                        double& TSTART , double * YSTART , double& TEND ,
                        double& TOL              , double * THRES ,
                        c o n s t i n t& METHOD , c o n s t char& TASK ,
                        bool & ERRASS , double& HSTART , double * WORK ,
                        c o n s t i n t& LENWRK ,             bool& MESSAGE ) ;
    void ut_ ( void f ( double& t , double * Y , double * YP ) ,
                     double& TWANT , double& TGOT , double * YGOT ,
                     double * YPGOT , double * YMAX , double * WORK ,
6.1. ADAPTIVE STEPSIZE CONTROL FOR RK METHODS                                      293

                      i n t& UFLAG ) ;
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    string buf ;
    double T0 , TF , X10 , X20 , X30 , V10 , V20 , V30 ;
    double t , dt , tstep ;
    int           STEPS , i ;
    / / rksuite variables :
    double TOL , THRES [ NEQ ] , WORK [ LENWRK ] , HSTART ;
    double Y [ NEQ ] , YMAX [ NEQ ] , YP [ NEQ ] , YSTART [ NEQ ] ;
    bool          ERRASS , MESSAGE ;
    int           UFLAG ;
    c o n s t char TASK = ’U’ ;
    / / Input :
    cout << ”Runge−Kutta Method f o r 6−ODEs I n t e g r a t i o n \n” ;
    cout << ” Enter c o u p l i n g c o n s t a n t s k1 , k2 , k3 , k4 : \ n” ;
    cin >> k1 >> k2 >> k3 >> k4 ; getline ( cin , buf ) ;
    cout << ” Enter STEPS , T0 , TF , X10 , X20 , X30 , V10 , V20 , V30: \ n” ;
    cin >> STEPS >> T0 >> TF
             >> X10         >> X20 >> X30
             >> V10         >> V20 >> V30 ; getline ( cin , buf ) ;
    cout << ”No . S t e p s= ” << STEPS << endl ;
    cout << ”Time : I n i t i a l T0 =” << T0
             << ” F i n a l TF=”              << TF << endl ;
    cout << ”                       X1 (T0)=” << X10
             << ” X2(T0)=”                    << X20
             << ” X3(T0)=”                    << X30 << endl ;
    cout << ”                       V1 (T0)=” << V10
             << ” V2(T0)=”                    << V20
             << ” V3(T0)=”                    << V30 << endl ;
    / / I n i t i a l Conditions :
   dt                 = ( TF−T0 ) / STEPS ;
    YSTART [ 0 ] = X10 ;
    YSTART [ 1 ] = X20 ;
    YSTART [ 2 ] = X30 ;
    YSTART [ 3 ] = V10 ;
    YSTART [ 4 ] = V20 ;
    YSTART [ 5 ] = V30 ;
    / / S e t c o n t r o l parameters :
    TOL = 5.0 e−6;
    f o r ( i = 0 ; i < NEQ ; i++)
        THRES [ i ] = 1 . 0 e −10;
    MESSAGE = t r u e ;
    ERRASS = f a l s e ;
    HSTART = 0 . 0 ;
    // Initialization :
    setup_ ( NEQ , T0 , YSTART , TF , TOL , THRES , METHOD , TASK ,
                  ERRASS , HSTART , WORK , LENWRK , MESSAGE ) ;
294                                        CHAPTER 6. MOTION IN SPACE

    ofstream myfile ( ” rk3 . dat ” ) ;
    myfile . precision ( 1 6 ) ;
    myfile << T0<< ” ”
                << YSTART [ 0 ] << ” ” << YSTART [ 1 ] << ” ”
                << YSTART [ 2 ] << ” ” << YSTART [ 3 ] << ” ”
                << YSTART [ 4 ] << ” ” << YSTART [ 5 ] << ” ”
                << energy ( T0 , YSTART ) << ’\n ’ ;
    / / The c a l c u l a t i o n :
    f o r ( i =1; i<=STEPS ; i++){
        t = T0 + i * dt ;
        ut_ ( f , t , tstep , Y , YP , YMAX , WORK , UFLAG ) ;
        i f ( UFLAG > 2) break ; / / e r r o r : break t h e loop and e x i t
        myfile << tstep << ” ”
                   << Y [ 0 ] << ” ” << Y [ 1 ] << ” ”
                   << Y [ 2 ] << ” ” << Y [ 3 ] << ” ”
                   << Y [ 4 ] << ” ” << Y [ 5 ] << ” ”
                   << energy ( T0 , Y ) << ’\n ’ ;
    }
    myfile . close ( ) ;
} / / main ( )


    All common parameters and variables are declared in an include file
rk3.h. This is done so that they are accessible by the function f which
calculates the derivatives:

c o n s t i n t NEQ     = 6;
c o n s t i n t LENWRK = 32* NEQ ;
c o n s t i n t METHOD = 2 ;
e x t e r n double k1 , k2 , k3 , k4 ;


The number of differential equations is set equal to NEQ=6. The integra-
tion method is set by the choice METHOD=2. The variable LENWRK sets the
size of the workspace needed by the suite for the intermediate calcula-
tions.
    The declaration of functions needs some care. The functions energy()
and f() are defined in the C++ program and are declared in the global
scope (the function f() will also be passed on to the Fortran function UT).
The functions setup_() and ut_() are defined in the Fortran program
in the file rksuite.f as SETUP() and UT(). Therefore, they are declared
within the extern "C" language linkage, defined using lowercase letters
and an underscore is appended to their names. All arguments are passed
by reference. Scalar doubles are passed as references to double&, the
double precision arrays are declared to be pointers double *, the Fortran
logical variables are declared to be references to bool&, and the Fortran
6.1. ADAPTIVE STEPSIZE CONTROL FOR RK METHODS                                      295

character* variables¹² as simple references to char&.
    The main program starts with the user interface. The initial state of
the particle is stored in the array YSTART in the positions 0 . . . 5. The
first three positions are the coordinates of the initial position and the last
three the components of the initial velocity. Then, we set some vari-
ables that determine the behavior of the integration program (see the
file rksuite.doc for details) and call the subroutine SETUP. The main
integration loop is:

  f o r ( i =1; i<=STEPS ; i++){
      t = T0 + i * dt ;
      ut_ ( f , t , tstep , Y , YP , YMAX , WORK , UFLAG ) ;
      i f ( UFLAG > 2) break ; / / e r r o r : break t h e loop and e x i t
      myfile << . . . << energy ( T0 , Y ) << ’\n ’ ;
  }

The function f calculates the derivatives and it will be programmed by
us later. The variable t stores the desired moment of time at which we
want to calculate the functions. Because of the adaptive stepsize, it can
be different than the one returned by the Fortran subroutine UT. The
actual value of time that the next step lands¹³ on is tstep. The array Y
stores the values of the functions. We choose the data structure to be
such that x= Y[0], y= Y[1], z= Y[2] and vx = Y[3], vy = Y[4], vz = Y([5]
(the same sequence as in the array YSTART). The function energy(t,Y)
returns the value of the mechanical energy of the particle and its code
will be written in the same file as that of f. Finally, the variable UFLAG
indicates the error status of the calculation by UT and if UFLAG> 2 we end
the calculation.
   Our test code will be on the study of the motion of a projectile in a
constant gravitational field, subject also to the influence of a dissipative
force F⃗r = −mk⃗v . The program is in the file rk3_g.cpp. We choose the
parameters k1 and k2 so that ⃗g = -k1 k̂ and k = k2.

# include   < iostream >
# include   < fstream >
# include   <cstdlib >
# include   <string >
# include   <cmath>
# include   ” rk3 . h”

  ¹²The Fortran program uses only their first character, so we don’t need to use strings.
  ¹³When UGLAG ≤ 2, tstep=t and we will not worry about them being different with
our program.
296                                      CHAPTER 6. MOTION IN SPACE

using namespace std ;
void f ( double& t , double * Y , double * YP ) {
   double x1 , x2 , x3 , v1 , v2 , v3 ;
   x1 = Y [ 0 ] ; v1 = Y [ 3 ] ;
   x2 = Y [ 1 ] ; v2 = Y [ 4 ] ;
   x3 = Y [ 2 ] ; v3 = Y [ 5 ] ;
    // Velocities :               d x _ i / dt = v _ i
   YP [ 0 ] = v1 ;
   YP [ 1 ] = v2 ;
   YP [ 2 ] = v3 ;
    / / A c c e l e r a t i o n : dv_i / dt = a _ i
   YP [ 3 ] = −k2 * v1 ;
   YP [ 4 ] = −k2 * v2 ;
   YP [ 5 ] = −k2 * v3−k1 ;
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double energy ( c o n s t double& t , double * Y ) {
   double e ;
   double x1 , x2 , x3 , v1 , v2 , v3 ;
   x1 = Y [ 0 ] ; v1 = Y [ 3 ] ;
   x2 = Y [ 1 ] ; v2 = Y [ 4 ] ;
   x3 = Y [ 2 ] ; v3 = Y [ 5 ] ;
    / / Kinetic             Energy :
   e = 0 . 5 * ( v1 * v1+v2 * v2+v3 * v3 ) ;
    / / P o t e n t i a l Energy :
   e += k1 * x3 ;

    return e ;
}


For convenience we “translated” the values in the array Y[NEQ] into user-
friendly variable names. If the file rksuite.f is in the directory rksuite/,
then the compilation, running and visualization of the results can be done
with the commands:

> gfortran −c rksuite / rksuite . f
> g++ rk3 . cpp rk3_g . cpp rksuite . o −o rk3 −lgfortran
> . / rk3
Runge−Kutta Method for 6−ODEs Integration
Enter coupling constants k1 , k2 , k3 , k4 :
10 0 0 0
Enter STEPS , T0 , TF , X10 , X20 , X30 , V10 , V20 , V30 :
10000 0 3 0 0 0 1 1 1
No . Steps= 10000
Time : Initial T0 =0 Final TF=3
             X1 ( T0 ) =0 X2 ( T0 ) =0 X3 ( T0 ) =0
             V1 ( T0 ) =1 V2 ( T0 ) =1 V3 ( T0 ) =1
6.2. MOTION OF A PARTICLE IN AN EM FIELD                                               297

> gnuplot
gnuplot > p l o t ” rk3 . dat ” using 1 : 2 with lines t i t l e ” x1 ( t ) ”
gnuplot > p l o t ” rk3 . dat ” using 1 : 3 with lines t i t l e ” x2 ( t ) ”
gnuplot > p l o t ” rk3 . dat ” using 1 : 4 with lines t i t l e ” x3 ( t ) ”
gnuplot > p l o t ” rk3 . dat ” using 1 : 5 with lines t i t l e ” v1 ( t ) ”
gnuplot > p l o t ” rk3 . dat ” using 1 : 6 with lines t i t l e ” v2 ( t ) ”
gnuplot > p l o t ” rk3 . dat ” using 1 : 7 with lines t i t l e ” v3 ( t ) ”
gnuplot > p l o t ” rk3 . dat ” using 1 : 8 with lines t i t l e ”E( t ) ”
gnuplot > s e t t i t l e ” t r a j e c t o r y ”
gnuplot > s p l o t ” rk3 . dat ” using 2 : 3 : 4 with lines notitle

All the above commands can be executed together using the shell script in
the file rk3.csh. The script uses the animation script rk3_animate.csh.
The following command executes all the commands shown above:

. / rk3 . csh −f 1 −− 10 0 . 0 0 0 0 0 1 1 1 10000 0 3




6.2 Motion of a Particle in an EM Field
In this section we study the non-relativistic motion of a charged particle
in an electromagnetic (EM) field. The particle is under the influence of
the Lorentz force:
                                  ⃗ + ⃗v × B)
                           F⃗ = q(E         ⃗ .                     (6.2)
                                          ⃗ = Ex x̂ + Ey ŷ + Ez ẑ, B
Consider the constant EM field of the form E                          ⃗ = B ẑ.
The components of the acceleration of the particle are:

                            ax = (qEx /m) + (qB/m)vy
                            ay = (qEy /m) − (qB/m)vx
                            az = (qEz /m) .                                           (6.3)

This field is programmed in the file rk3_B.cpp. We set k1 = qB/m, k2
= qEx /m, k3 = qEy /m and k4 = qEz /m:

/ / ========================================================
//       P a r t i c l e i n c o n s t a n t magnetic and e l e c t r i c f i e l d
/ / q B/m = k1 z                  q E /m = k2 x + k3 y + k4 z
/ / ========================================================
# i n c l u d e ” s r . h”
void f ( double& t , double * Y , double * YP ) {
    double x1 , x2 , x3 , v1 , v2 , v3 , p1 , p2 , p3 ;
    x1 = Y [ 0 ] ; p1 = Y [ 3 ] ;
298                                           CHAPTER 6. MOTION IN SPACE

    x2 = Y [ 1 ] ; p2 = Y [ 4 ] ;
    x3 = Y [ 2 ] ; p3 = Y [ 5 ] ;
    velocity ( p1 , p2 , p3 , v1 , v2 , v3 ) ;
    / / now we can use a l l x1 , x2 , x3 , p1 , p2 , p3 , v1 , v2 , v3
    YP [ 0 ] = v1 ;
    YP [ 1 ] = v2 ;
    YP [ 2 ] = v3 ;
    / / Acceleration :
    YP [ 3 ] = k2 + k1 * v2 ;
    YP [ 4 ] = k3 − k1 * v1 ;
    YP [ 5 ] = k4 ;
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double energy ( c o n s t double& t , double * Y ) {
   double e ;
   double x1 , x2 , x3 , v1 , v2 , v3 , p1 , p2 , p3 , psq ;
   x1 = Y [ 0 ] ; p1 = Y [ 3 ] ;
   x2 = Y [ 1 ] ; p2 = Y [ 4 ] ;
   x3 = Y [ 2 ] ; p3 = Y [ 5 ] ;
   psq= p1 * p1+p2 * p2+p3 * p3 ;
    / / Kinetic           Energy :
   e = sqrt ( 1 . 0 + psq ) −1.0;
    / / P o t e n t i a l Energy / m_0
   e += − k2 * x1 − k3 * x2 − k4 * x3 ;

    return e ;
}

We can also study space-dependent fields in the same way. The fields
must satisfy Maxwell’s equations. We can study the confinement of a
                                                           ⃗ = By ŷ + Bz ẑ
particle in a region of space by a magnetic field by taking B
with qBy /m = −k2 y, qBz /m = k1 + k2 z and qBy /m = k3 z, qBz /m =
k1 + k2 y. Note that ∇
                     ⃗ ·B⃗ = 0. You may also want to calculate the current
density from the equation ∇  ⃗ ×B⃗ = µ0⃗j.
    The results are shown in figures 6.1–6.4.


6.3 Relativistic Motion
Consider a particle of non zero rest mass moving with speed comparable
to the speed of light. In this case, it is necessary to study its motion using
the equations of motion given by special relativity¹⁴. In the equations

   ¹⁴Of course for lower speeds, the special relativity equations of motion are a better ap-
proximation to the particle’s motion, but the corrections to the non relativistic equations
of motion are negligible.
6.3. RELATIVISTIC MOTION                                                               299


                 3



                 2



                 1



                 0
                 1
                                                                        1


                             2                            0
                        x
                                                                y

                                          3 -1




Figure 6.1: The trajectory of a charged particle in a constant magnetic field B⃗ = B ẑ,
where qB/m = 1.0, ⃗v (0) = 1.0ŷ + 0.1ẑ, ⃗r(0) = 1.0x̂. The integration of the equations of
motion is performed using the RK45 method from t0 = 0 to tf = 40 with 1000 steps.



below we√ set c = 1. The particle’s rest mass is m0 > 0, its mass is
m = m0 / 1 √ − v 2 (where v < 1), its momentum is p⃗ = m⃗v and its energy
is E = m = p2 + m20 . Then the equations of motion in a dynamic field
F⃗ are given by:
                                  d⃗p
                                      = F⃗ .                         (6.4)
                                  dt
In order to write a system of first order equations, we use the relations
                                    p⃗   p⃗       p⃗
                             ⃗v =      =    =√         .                             (6.5)
                                    m    E     p + m20
                                                2


Using ⃗v = d⃗r/dt we obtain
                  dx      (px /m0 )                  d(px /m0 )   Fx
                     = √              ,                         =
                  dt     1 + (p/m0 )2                   dt        m0
                  dy      (py /m0 )                  d(py /m0 )   Fy
                     = √              ,                         =
                  dt     1 + (p/m0 )2                   dt        m0
                  dz      (pz /m0 )                  d(pz /m0 )   Fz
                     = √              ,                         =    ,               (6.6)
                  dt     1 + (p/m0 )2                   dt        m0
300                                                CHAPTER 6. MOTION IN SPACE



                  z


              4


              3


              2


              1


              0-5                                                               1
                       -4                                                  2
                            -3                                        3
                                 -2                              4
                                      -1                     5         x
                            y              0             6
                                               1
                                                   2 7




Figure 6.2: The trajectory of a charged particle in a constant magnetic field B⃗ = B ẑ,
 where qB/m = 1.0 and a constant electric field E      ⃗ = Ex x̂+Ey ŷ με qEx /m = qEy /m = 0.1.
⃗v (0) = 1.0ŷ + 0.1ẑ, ⃗r(0) = 1.0x̂. The integration of the equations of motion is performed
 using the RK45 method from t0 = 0 to tf = 40 with 1000 steps. Each axis is on a
 different scale.



which is a system of first order differential equations for the functions
(x(t), y(t), z(t), (px /m0 )(t), (py /m0 )(t), (pz /m0 )(t)). Given the initial con-
ditions (x(0), y(0), z(0), (px /m0 )(0), (py /m0 )(0), (pz /m0 )(0)) their solution
is unique and it can be computed numerically using the 4th-5th order
Runge–Kutta method according to the discussion of the previous section.
By using the relations
                                    vx                      (px /m0 )
                      (px /m0 ) = √                 vx = √
                                   1 − v2                  1 + (p/m0 )2
                                    vy                      (py /m0 )
                      (py /m0 ) = √                 vy = √
                                   1 − v2                  1 + (p/m0 )2
                                    vz                      (pz /m0 )
                      (pz /m0 ) = √                 vz = √              ,
                                   1 − v2                  1 + (p/m0 )2
                                                                                        (6.7)
we can use the initial conditions (x(0), y(0), z(0), vx (0), vy (0), vz (0)) in-
stead. Similarly, from the solutions (x(t), y(t), z(t), (px /m0 )(t), (py /m0 )(t),
6.3. RELATIVISTIC MOTION                                                          301




                 z

           100


             0


          -100
                                                                             3
                                                                     2
          -200 0                                                 1
                     1                                       0           y
                          2
                                  3                     -1
                              x       4
                                           5
                                                 6 -2




Figure 6.3: The trajectory of a charged particle in a magnetic field B⃗ = By ŷ + Bz ẑ
with qBy /m = −0.02y, qBz /m = 1 + 0.02z, ⃗v (0) = 1.0ŷ + 0.1ẑ, ⃗r(0) = 1.0x̂. The
integration of the equations of motion is performed using the RK45 method from t0 = 0
to tf = 500 with 10000 steps. Each axis is on a different scale.



(pz /m0 )(t)) we can calculate (x(t), y(t), z(t), vx (t), vy (t), vz (t)). We always
have to check that

                         v 2 = (vx )2 + (vy )2 + (vz )2 < 1 .                    (6.8)

Since half of the functions that we integrate for are the momentum instead
of the velocity components, we need to make some modifications to the
program in the file rk3.cpp. The main program can be found in the file
sr.cpp:

/ / ========================================================
/ / Program t o s o l v e a 6 ODE system using Runge−Kutta Method
/ / Output i s w r i t t e n i n f i l e s r . dat
/ / ========================================================
/ / Compile with t h e commands :
/ / g f o r t r a n −c r k s u i t e / r k s u i t e . f
/ / g++ s r . cpp sr_B . cpp r k s u i t e . o −o rk3 −l g f o r t r a n
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# i n c l u d e ” s r . h”
double k1 , k2 , k3 , k4 ;
302                                          CHAPTER 6. MOTION IN SPACE


                        z


                   2


                   1


                   0


                  -1


                  -21


            y           0


                            -1 -2        0        1     2       3
                                    -1
                                              x




Figure 6.4: The trajectory of a charged particle in a magnetic field B⃗ = By ŷ + Bz ẑ
with qBy /m = 0.08z, qBz /m = 1.4 + 0.08y, ⃗v (0) = 1.0ŷ + 0.1ẑ, ⃗r(0) = 1.0x̂. The
integration of the equations of motion is performed using the RK45 method from t0 = 0
to tf = 3000 with 40000 steps. Each axis is on a different scale.




e x t e r n ”C” {
    void setup_ ( c o n s t i n t& NEQ ,
                      double& TSTART , double * YSTART , double& TEND ,
                      double& TOL         , double * THRES ,
                      c o n s t i n t& METHOD , c o n s t char& TASK ,
                      bool & ERRASS , double& HSTART , double * WORK ,
                      c o n s t i n t& LENWRK ,           bool& MESSAGE ) ;
    void ut_ ( void f ( double& t , double * Y , double * YP ) ,
                  double& TWANT , double& TGOT , double * YGOT ,
                  double * YPGOT , double * YMAX , double * WORK ,
                  i n t& UFLAG ) ;
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    string buf ;
    double T0 , TF , X10 , X20 , X30 , V10 , V20 , V30 ;
    double P10 , P20 , P30 ;
    double P1 , P2 , P3 , V1 , V2 , V3 ;
    double t , dt , tstep ;
    int       STEPS , i ;
    / / rksuite variables :
6.3. RELATIVISTIC MOTION                                                        303

 double TOL , THRES [ NEQ ] , WORK [ LENWRK ] , HSTART ;
 double Y [ NEQ ] , YMAX [ NEQ ] , YP [ NEQ ] , YSTART [ NEQ ] ;
 bool          ERRASS , MESSAGE ;
 int           UFLAG ;
 c o n s t char TASK = ’U’ ;
 / / Input :
 cout << ”Runge−Kutta Method f o r 6−ODEs I n t e g r a t i o n \n” ;
 cout << ” S p e c i a l R e l a t i v i s t i c P a r t i c l e : \ n” ;
 cout << ” Enter c o u p l i n g c o n s t a n t s k1 , k2 , k3 , k4 : \ n” ;
 cin >> k1 >> k2 >> k3 >> k4 ; getline ( cin , buf ) ;
 cout << ” Enter STEPS , T0 , TF , X10 , X20 , X30 , V10 , V20 , V30: \ n” ;
 cin >> STEPS >> T0 >> TF
          >> X10         >> X20 >> X30
          >> V10         >> V20 >> V30 ; getline ( cin , buf ) ;
 momentum ( V10 , V20 , V30 , P10 , P20 , P30 ) ;
 cout << ”No . S t e p s= ” << STEPS << endl ;
 cout << ”Time : I n i t i a l T0 =” << T0
          << ” F i n a l TF=”                   << TF << endl ;
 cout << ”                       X1 (T0)=” << X10
          << ” X2(T0)=”                         << X20
          << ” X3(T0)=”                         << X30 << endl ;
 cout << ”                       V1 (T0)=” << V10
          << ” V2(T0)=”                         << V20
          << ” V3(T0)=”                         << V30 << endl ;
 cout << ”                       P1 (T0)=” << P10
          << ” P2 (T0)=”                        << P20
          << ” P3 (T0)=”                        << P30 << endl ;
 / / I n i t i a l Conditions :
 dt                = ( TF−T0 ) / STEPS ;
 YSTART [ 0 ] = X10 ;
 YSTART [ 1 ] = X20 ;
 YSTART [ 2 ] = X30 ;
 YSTART [ 3 ] = P10 ;
 YSTART [ 4 ] = P20 ;
 YSTART [ 5 ] = P30 ;
 / / S e t c o n t r o l parameters :
 TOL = 5.0 e−6;
 f o r ( i = 0 ; i < NEQ ; i++)
     THRES [ i ] = 1 . 0 e −10;
 MESSAGE = t r u e ;
 ERRASS = f a l s e ;
 HSTART = 0 . 0 ;
 // Initialization :
 setup_ ( NEQ , T0 , YSTART , TF , TOL , THRES , METHOD , TASK ,
               ERRASS , HSTART , WORK , LENWRK , MESSAGE ) ;
 ofstream myfile ( ” s r . dat ” ) ;
 myfile . precision ( 1 6 ) ;
 myfile << T0                    << ” ”
               << YSTART [ 0 ] << ” ” << YSTART [ 1 ] << ” ”
304                                       CHAPTER 6. MOTION IN SPACE

                << YSTART [ 2 ] << ” ”
                << V1                 << ” ” << V2                   << ” ”
                << V3                 << ” ”
                << energy ( T0 , YSTART )                            << ” ”
                << YSTART [ 3 ] << ” ” << YSTART [ 4 ] << ” ”
                << YSTART [ 5 ] << ’\n ’ ;
    / / The c a l c u l a t i o n :
    f o r ( i =1; i<=STEPS ; i++){
        t = T0 + i * dt ;
        ut_ ( f , t , tstep , Y , YP , YMAX , WORK , UFLAG ) ;
        i f ( UFLAG > 2) break ; / / e r r o r : break t h e loop and e x i t
        velocity ( Y [ 3 ] , Y [ 4 ] , Y [ 5 ] , V1 , V2 , V3 ) ;
        myfile << tstep << ” ”
                   << Y [ 0 ] << ” ” << Y [ 1 ] << ” ”
                   << Y [ 2 ] << ” ”
                   << V1            << ” ” << V2            << ” ”
                   << V3            << ” ”
                   << energy ( T0 , Y )                     << ” ”
                   << Y [ 3 ] << ” ” << Y [ 4 ] << ” ”
                   << Y [ 5 ] << ” ” << ’\n ’ ;
    }
    myfile . close ( ) ;
} / / main ( )
/ / ========================================================
/ / momentum −> v e l o c i t y t r a n s f o r m a t i o n
/ / ========================================================
void velocity ( c o n s t double& p1 , c o n s t double& p2 ,
                        c o n s t double& p3 ,
                                    double& v1 ,                double& v2 ,
                                    double& v3 ) {
    double psq ;
    psq = p1 * p1+p2 * p2+p3 * p3 ;

  v1   = p1 / sqrt ( 1 . 0 + psq ) ;
  v2   = p2 / sqrt ( 1 . 0 + psq ) ;
  v3   = p3 / sqrt ( 1 . 0 + psq ) ;
}
/ / ========================================================
/ / v e l o c i t y −> momentum t r a n s f o r m a t i o n
/ / ========================================================
void momentum ( c o n s t double& v1 , c o n s t double& v2 ,
                       c o n s t double& v3 ,
                                 double& p1 ,               double& p2 ,
                                 double& p3 ) {
    double vsq ;
    vsq = v1 * v1+v2 * v2+v3 * v3 ;
    i f ( vsq >= 1 . 0 ) { cerr << ”momentum : vsq >=1\n” ; exit ( 1 ) ; }
    p1 = v1 / sqrt (1.0 − vsq ) ;
    p2 = v2 / sqrt (1.0 − vsq ) ;
6.3. RELATIVISTIC MOTION                                               305

    p3   = v3 / sqrt (1.0 − vsq ) ;


}

The functions momentum and velocity compute the transformations (6.7).
In the function momentum we check whether the condition (6.8) is satis-
fied. These functions are also used in the function F that computes the
derivatives of the functions.
   Common declarations are now in an include file sr.h:

# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
c o n s t i n t NEQ         = 6;
c o n s t i n t LENWRK = 32* NEQ ;
c o n s t i n t METHOD = 2 ;
e x t e r n double k1 , k2 , k3 , k4 ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double energy ( c o n s t double& t ,            double * Y ) ;
void          f ( double& t , double * Y ,       double * YP ) ;
void velocity ( c o n s t double& p1 , c o n s t double& p2 ,
                       c o n s t double& p3 ,
                                 double& v1 ,    double& v2 ,
                                 double& v3 ) ;
void momentum ( c o n s t double& v1 , c o n s t double& v2 ,
                       c o n s t double& v3 ,
                                 double& p1 ,    double& p2 ,
                                 double& p3 ) ;

   The test drive of the above program is the well known relativistic
motion of a charged particle in a constant EM field. The acceleration of
the particle is given by equations (6.3). The relativistic kinetic energy of
the particle is
                  (             )      (√                  )
                        1
             T = √           − 1 m0 =      1 + (p/m0 )2 − 1 m0         (6.9)
                      1 − v2
These relations are programmed in the file sr_B.cpp. The contents of
the file sr_B.cpp are:
306                                            CHAPTER 6. MOTION IN SPACE

/ / ========================================================
//       P a r t i c l e i n c o n s t a n t Magnetic and e l e c t r i c f i e l d
/ / q B/m = k1 z                  q E /m = k2 x + k3 y + k4 z
/ / ========================================================
# i n c l u d e ” s r . h”
void f ( double& t , double * Y , double * YP ) {
    double x1 , x2 , x3 , v1 , v2 , v3 , p1 , p2 , p3 ;
    x1 = Y [ 0 ] ; p1 = Y [ 3 ] ;
    x2 = Y [ 1 ] ; p2 = Y [ 4 ] ;
    x3 = Y [ 2 ] ; p3 = Y [ 5 ] ;
    velocity ( p1 , p2 , p3 , v1 , v2 , v3 ) ;
    / / now we can use a l l x1 , x2 , x3 , p1 , p2 , p3 , v1 , v2 , v3
    YP [ 0 ] = v1 ;
    YP [ 1 ] = v2 ;
    YP [ 2 ] = v3 ;
    / / Acceleration :
    YP [ 3 ] = k2 + k1 * v2 ;
    YP [ 4 ] = k3 − k1 * v1 ;
    YP [ 5 ] = k4 ;
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double energy ( c o n s t double& t , double * Y ) {
    double e ;
    double x1 , x2 , x3 , v1 , v2 , v3 , p1 , p2 , p3 , psq ;
    x1 = Y [ 0 ] ; p1 = Y [ 3 ] ;
    x2 = Y [ 1 ] ; p2 = Y [ 4 ] ;
    x3 = Y [ 2 ] ; p3 = Y [ 5 ] ;
    psq= p1 * p1+p2 * p2+p3 * p3 ;
    / / Kinetic            Energy :
    e = sqrt ( 1 . 0 + psq ) −1.0;
    / / P o t e n t i a l Energy / m_0
    e += − k2 * x1 − k3 * x2 − k4 * x3 ;

    return e ;
}

The results are shown in figures 6.5–6.6.
   Now we can study a more interesting problem. Consider a simple
model of the Van Allen radiation belt. Assume that the electrons are
moving within the Earth’s magnetic field which is modeled after a mag-
netic dipole field of the form:
                                    (        )3 [                   ]
                                        RE            ˆ            ˆ
                          ⃗ = B0
                          B                         3(d · r̂) r̂ − d ,                (6.10)
                                         r

where d⃗ = ddˆ is the magnetic dipole moment of the Earth’s magnetic
field and ⃗r = rr̂. The parameter values are approximately equal to B0 =
6.3. RELATIVISTIC MOTION                                                               307




                             z

                         2
                       1.6
                       1.2
                       0.8
                       0.4                                      0.4
                         0
                                                          0 y
                                  1.2
                                   x         1.6 -0.4



Figure 6.5:        The trajectory of a relativistic charged particle in a magnetic field
⃗
B = Bz ẑ with qBz /m0 = 10.0, ⃗v (0) = 0.95ŷ + 0.10ẑ, ⃗r(0) = 1.0x̂. The integration is
performed by using the RK45 method from t0 = 0 to tf = 20 with 1000 steps. Each
axis is on a different scale.



3.5 × 10−5 T , r ∼ 2RE , where RE is the radius of the Earth. The typical
energy of the moving √  particles is ∼ 1 MeV
                                          √ which corresponds to velocities
of magnitude v/c = E − m0 /E ≈ 1 − 0.5122 /1 = 0.86. We choose
                            2      2

the coordinate axes so that dˆ = ẑ and we measure distance in RE units¹⁵.
Then we obtain:
                                           3xz
                                 Bx = B0
                                            r5
                                           3yz
                                 By   = B0 5
                                           (r         )
                                              3zz   1
                                 Bz   = B0        − 3                               (6.11)
                                               r5  r

The magnetic dipole field is programmed in the file sr_Bd.cpp:

/ / ========================================================

   ¹⁵Since c = 1, the unit of time is the time that the light needs to travel distance equal
to RE in the vacuum.
308                                          CHAPTER 6. MOTION IN SPACE


           0.4

           0.3

           0.2

           0.1

             0

          -0.1

          -0.2

          -0.3

          -0.4
                 0.9   1   1.1 1.2 1.3 1.4 1.5 1.6 1.7

Figure 6.6: Projection of the trajectory of a relativistic charged particle in a magnetic
     ⃗ = Bz ẑ with qBz /m0 = 10.0, on the xy plane. ⃗v (0) = 0.95ŷ + 0.10ẑ, ⃗r(0) = 1.0x̂.
field B
The integration is performed by using the RK45 method from t0 = 0 to tf = 20 with
1000 steps. Each axis is on a different scale.




//       P a r t i c l e i n Magnetic d i p o l e f i e l d :
/ / q B_1 /m = k1 (3 x1 x3 ) / r ^5
/ / q B_2 /m = k1 (3 x2 x3 ) / r ^5
/ / q B_3 /m = k1 [ ( 3 x3 x3 ) / r ^5 −1/ r ^3]
/ / ========================================================
# i n c l u d e ” s r . h”
void f ( double& t , double * Y , double * YP ) {
    double x1 , x2 , x3 , v1 , v2 , v3 , p1 , p2 , p3 ;
    double B1 , B2 , B3 ;
    double r , r5 , r3 ;
    x1 = Y [ 0 ] ; p1 = Y [ 3 ] ;
    x2 = Y [ 1 ] ; p2 = Y [ 4 ] ;
    x3 = Y [ 2 ] ; p3 = Y [ 5 ] ;
    velocity ( p1 , p2 , p3 , v1 , v2 , v3 ) ;
    / / now we can use a l l x1 , x2 , x3 , p1 , p2 , p3 , v1 , v2 , v3
    YP [ 0 ]        = v1 ;
    YP [ 1 ]        = v2 ;
    YP [ 2 ]        = v3 ;
    / / Acceleration :
    r               = sqrt ( x1 * x1+x2 * x2+x3 * x3 ) ;
    r3              = r*r*r ;
6.3. RELATIVISTIC MOTION                                                      309




                     z

           100
                80
                60
                40
                20                                                      0.4
                0                                               0
                                1.2                                 y
                                 x                   1.6 -0.4



Figure 6.7:                                                     ⃗
                  The influence of an additional electric field q E/m0 = 1.0ẑ on the
trajectory shown in figure 6.5.




  r5            = r * r * r3 ;
  if ( r >      0.0) {
     B1         = k1 * ( 3 . 0 * x1 * x3 ) / r5 ;
     B2         = k1 * ( 3 . 0 * x2 * x3 ) / r5 ;
     B3         = k1 * ( ( 3 . 0 * x3 * x3 ) / r5 −1/ r3 ) ;
     YP [ 3 ]   = v2 * B3−v3 * B2 ;
     YP [ 4 ]   = v3 * B1−v1 * B3 ;
     YP [ 5 ]   = v1 * B2−v2 * B1 ;
  } else {
     YP [ 3 ]   = 0.0;
     YP [ 4 ]   = 0.0;
     YP [ 5 ]   = 0.0;
  }
}
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double energy ( c o n s t double& t , double * Y ) {
   double e ;
   double x1 , x2 , x3 , v1 , v2 , v3 , p1 , p2 , p3 , psq ;
   x1 = Y [ 0 ] ; p1 = Y [ 3 ] ;
   x2 = Y [ 1 ] ; p2 = Y [ 4 ] ;
   x3 = Y [ 2 ] ; p3 = Y [ 5 ] ;
   psq= p1 * p1+p2 * p2+p3 * p3 ;
    / / Kinetic    Energy :
310                                           CHAPTER 6. MOTION IN SPACE

     e   = sqrt ( 1 . 0 + psq ) −1.0;

     return e ;
}




                   2
                 1.6
                 1.2
                 0.8
                 0.4
                   0
              0.004
                     0
                  -0.004
                    -0.008                                      0.02
                                                    0.012 0.016
                      -0.012 0          0.004 0.008



Figure 6.8: The trajectory of a charged particle in a magnetic dipole field given by
equation (6.11). We used B0 = 1000, ⃗r = 0.02x̂ + 2.00ẑ, ⃗v = −0.99999ẑ. The integration
was done from t0 = 0 to tf = 5 in 10000 steps.


    The results are shown in figure 6.8. The parameters have been exag-
gerated in order to achieve an aesthetically pleasant result. In reality, the
electrons are moving in very thin spirals and the reader is encouraged to
use more realistic values for the parameters ⃗v0 , B0 , ⃗r0 . The problem of
why the effect is not seen near the equator is left as an exercise.


6.4 Problems
    6.1 Compute the trajectory of a projectile moving in space in a con-
        stant gravitational field and under the influence of an air resistance
        proportional to the square of its speed.
    6.2 Two point charges are moving with non relativistic speeds in a
                               ⃗ = B ẑ. Assume that their interaction is
        constant magnetic field B
6.4. PROBLEMS                                                            311

    given by the Coulomb force only. Write a program that computes
    their trajectory numerically using the RK45 method.

6.3 Write a program that computes the trajectory of the anisotropic
    harmonic oscillator F⃗ = −kx xx̂ −ky y ŷ −kz z ẑ. Compute the three
    dimensional Lissajous curves which
                                    √ appear for     √ appropriate√values
    of the angular frequencies ωx = kx /m, ωy = ky /m, ωz = kz /m.

6.4 Two particles of mass M are at the fixed positions ⃗r1 = aẑ and
    ⃗r2 = −aẑ. A third particle of mass m interacts with them via a
     Newtonian gravitational force and moves at non relativistic speeds.
     Compute the particle’s trajectory and find initial conditions that
     result in a planar motion.

6.5 Solve problem 5.19 of page 279 using the RK45 method. Choose ini-
    tial conditions so that the system executes only translational motion.
    Next, choose initial conditions so that the system executes small vi-
    brations and its center of mass remains stationary. Find the normal
    modes of the system and choose appropriate initial conditions that
    put the system in each one of them.

6.6 Solve the previous problem by putting the system in a box |x| ≤ L
    and |y| ≤ L.

6.7 Solve the problem 5.20 in page 280 by using the RK45 method.

6.8 Solve the problem 5.21 in page 280 by using the RK45 method.

6.9 The electric field of an electric dipole p⃗ = pẑ is given by:

                          E⃗ = Eρ ρ̂ + Ez ẑ
                                1 3p sin θ cos θ
                          Eρ =
                               4πϵ0         r3
                                1 p(3 cos2 θ − 1)
                          Ez =                                        (6.12)
                               4πϵ0          r3
                   √
    where ρ = x2 + y 2 = r sin θ, Ex = Eρ cos ϕ, Ey = Eρ sin ϕ and
    (r, θ, ϕ) are the polar coordinates of the point where the electric field
    is calculated. Calculate the trajectory of a test charge moving in this
    field at non relativistic speeds. Calculate the deviation between the
    relativistic and the non relativistic trajectories when the initial speed
    is 0.01c, 0.1c, 0.5c, 0.9c respectively (ignore radiation effects).
312                                   CHAPTER 6. MOTION IN SPACE

6.10 Consider a linear charge distribution with constant linear charge
     density λ. The electric field is given by

                               ⃗ = Eρ ρ̂ =    1 2λ
                               E                    ρ̂
                                             4πϵ0 ρ
      Calculate the trajectories of two equal negative test charges that
      move at non relativistic speeds in this field. Consider only the
      electrostatic Coulomb forces and ignore anything else.

6.11 Consider a linear charge distribution on four straight lines parallel
     to the z axis. The linear charge density is λ and it is constant. The
     four straight lines intersect the xy plane at the points (0, 0), (0, a),
     (a, 0), (a, a). Calculate the trajectory of a non relativistic charge
     in this field. Next, compute the relativistic trajectories (ignore all
     radiation effects).

6.12 Three particles of mass m interact via their Newtonian gravitational
     force. Compute their (non relativistic) trajectories in space.

6.13 There is a C++ “translation” of rksuite. Download it from netlib
     .org/ ode/ rksuite and teach yourself how to use it. The docu-
     mentation is not as explicit as for the Fortran version, part of it is in
     the source code file rksuite.cpp. You can teach yourself how to use
     it by reading the example file RksuiteTest.cpp and the methods of
     the class RKSUITE in the file rksuite.h. Write a program to study
     the motion of the non relativistic electron in a constant magnetic
     field. Then repeat for the relativistic electron.
Chapter 7

Electrostatics

In this chapter we will study the electric field generated by a static charge
distribution. First we will compute the electric field lines and the equipo-
tential surfaces of the electric field generated by a static point charge dis-
tribution on the plane. Then we will study the electric field generated by
a continuous charge distribution on the plane. This requires the numer-
ical solution of an elliptic boundary value problem which will be done
using successive over-relaxation (SOR) methods.



7.1      Electrostatic Field of Point Charges
Consider N point charges Qi which are located at fixed positions on the
plane given by their position vectors ⃗ri , i = 1, . . . , N . The electric field is
given by Coulomb’s law

                                      1 ∑ Qi
                                           N
                            ⃗ r) =
                            E(⃗                            ρ̂i                     (7.1)
                                     4πϵ0 i=1 |⃗r − ⃗ri |2

where ρ̂i = (⃗r − ⃗ri )/|⃗r − ⃗ri | is the unit vector in the direction of ⃗r − ⃗ri . The
components of the field are

                            1 ∑
                                 N
                                           Qi (x − xi )
               Ex (x, y) =
                           4πϵ0 i=1 ((x − xi )2 + (y − yi )2 )3/2

                                 1 ∑
                                      N
                                                Qi (y − yi )
                Ey (x, y) =                                            ,           (7.2)
                                4πϵ0 i=1 ((x − xi )2 + (y − yi )2 )3/2

                                          313
314                                         CHAPTER 7. ELECTROSTATICS

   The electrostatic potential at ⃗r is

                                  1 ∑
                                       N
                                                      Qi
             V (⃗r) = V (x, y) =                                        ,         (7.3)
                                 4πϵ0 i=1 ((x − xi )2 + (y − yi )2 )1/2

and we have that
                                 ⃗ r) = −∇V
                                 E(⃗     ⃗ (⃗r) .                                 (7.4)
    The electric field lines are the integral curves of the vector field E,   ⃗ i.e.
the curves whose tangent lines at each point are parallel to the electric
field at that point. The magnitude of the electric field is proportional to
the density of the field lines (the number of field lines per perpendicular
                                                  ∫
area). This means that the electric flux ΦE = S E      ⃗ · dA
                                                           ⃗ through a surface
S is proportional to the number of field lines that cross the surface.
Electric field lines of point charge distributions start from positive charges
(sources), end in negative charges (sinks) or extend to infinity.
    The equipotential surfaces are the loci of the points of space where
the electrostatic potential takes fixed values. Τhey are closed surfaces.
Equation (7.4) tells us that a strong electric field at a point is equivalent to
a strong spatial variation of the electric potential at this point, i.e. to dense
equipotential surfaces. The direction of the electric field is perpendicular
to the equipotential surfaces at each point¹, which is the direction of
the strongest spatial variation of V , and it points in the direction of
decreasing V . The planar cross sections of the equipotential surfaces are
closed curves which are called equipotential lines.
    The computer cannot solve a problem in the continuum and we have
to consider a finite discretization of a field line. A continuous curve is
approximated by a large but finite number of small line segments. The
basic idea is illustrated in figure 7.1: The small line segment ∆l is taken
in the direction of the electric field and we obtain
                                    Ex                    Ey
                         ∆x = ∆l       ,       ∆y = ∆l       ,                    (7.5)
                                    E                     E
                  √
where E ≡ |E|⃗ = Ex2 + Ey2 .
   In order to calculate the equipotential lines we use the property that
they are perpendicular to the electric field at each point. Therefore, if
(∆x, ∆y) is in the tangential direction of a field line, then (−∆y, ∆x) is
    ¹Since for every small displacement d⃗r along an equipotential surface the potential
stays constant (dV = 0), we have that 0 = dV = ∇V    ⃗ · d⃗r = −E ⃗ · d⃗r, which implies
E ⊥ d⃗r.
⃗
7.1. ELECTROSTATIC FIELD OF POINT CHARGES                                      315


        y                              E
                                                       Ey


                       ∆l
                                 ∆y

                            ∆x             Ex




                                                                      x
Figure 7.1: The electric field is tangent at each point of an electric field line and
perpendicular to an equipotential line. By approximating the continuous curve by the
line segment ∆l, we have that ∆y/∆x = Ey /Ex .



in the perpendicular direction since (∆x, ∆y) · (−∆y, ∆x) = −∆x∆y +
∆y∆x = 0. Therefore the equations that give the equipotential lines are
                                   Ey                   Ex
                      ∆x = −∆l        ,      ∆y = ∆l       .                  (7.6)
                                   E                    E
    The algorithm that will allow us to perform an approximate calcula-
tion of the electric field lines and the equipotential lines is the following:
Choose an initial point that belongs to the (unique) line that you want to
draw. The electric field can be calculated from the known electric charge
distribution and equation (7.2). By using a small enough step ∆l we
move in the direction (∆x, ∆y) to the new position

                         x → x + ∆x ,      y → y + ∆y ,                       (7.7)

where we use equations (7.5) or (7.6). The procedure is repeated until
the drawing is finished. The programmer sets a criterion for that, e.g.
when the field line steps out of the drawing area or approaches a charge
closer than a minimum distance.
316                                        CHAPTER 7. ELECTROSTATICS

7.2 The Program – Appetizer and ... Desert
The hurried, but slightly experienced reader may skip the details of this
section and go directly to section 7.4. There she can find the final form
of the program and brief usage instructions.
    In order to program the algorithm described in the previous section,
we will separate the algorithmic procedures into four different but well
defined tasks:

   • Main program: The data structure, which is given by the position of
     the charges stored in the arrays X[P], Y[P] and the charges stored
     in the array Q[P], is defined. It also contains the user interface
     which consists of reading data entered by the user, like the number
     of charges N, their positions and magnitude. Then the calculation
     of a group of field or equipotential lines is performed by calling the
     routines eline or epotline respectively.

   • void function eline(xin,yin,X,Y,Q,N): Calculates the electric
     field line passing through the point xin,yin. On entry, the user
     inputs the point xin,yin and the data N, X[N], Y[N], Q[N]. On
     exit, the function prints to the stdout the coordinates of the ap-
     proximate electric field line. The line extends up to a point that is
     either too close to one of the point charges or until the line leaves
     the drawing area². It calls the functions efield for the calculation
     of the electric field and mdist for the calculation of the minimum
     and maximum distance of a point on the field line from all the point
     charges.

   • void function epotline(xin,yin,X,Y,Q,N): Calculates the equipo-
     tential line passing through the point xin,yin. On entry, the user
     inputs the point xin,yin and the data N, X[N], Y[N], Q[N]. On exit,
     the function prints to the stdout the coordinates of the approximate
     equipotential line. The function stops calculating an equipotential
     line when it comes back close enough to the original point³ xin,yin
     or when it leaves the drawing area. It calls the functions efield
     for the calculation of the electric field and mdist for the calculation
     of the minimum and maximum distance of a point on the equipo-
     tential line from all the point charges.

  ²Remember that field lines start at sources, end at sinks or extend to infinity.
  ³Remember that the equipotential lines are closed.
7.2. THE PROGRAM – APPETIZER AND ... DESERT                          317

   • void function efield(x0,y0,X,Y,Q,N,Ex,Ey): Calculates the elec-
     tric field Ex, Ey at position x0, y0. On entry, the user provides
     the number of charges N, the position of charges X[N], Y[N], the
     charges Q[N] and the position x0, y0. On exit, the routine provides
     the values Ex, Ey.

   • void function mdist(x0,y0,X,Y,N,rmin,rmax): Calculates the max-
     imum and minimum distance of the point x0, y0 from all charges
     located at X[N], Y[N]. On entry, the user provides the number of
     charges N, the position of charges X[N], Y[N] and the point x0, y0.
     On exit, the routine provides the minimum and maximum distances
     rmin,rmax.

   In the main program, the variables N, X[N], Y[N] and Q[N] must
be set. These can be hard coded by the programmer or entered by the
user interactively. The first choice is coded in the program listed below,
which can be found in the file ELines.cpp. We list a simple version of
the main() function below:

i n t main ( ) {
    string buf ;
    const int      P = 20; / / max number o f c h a r g e s
    double         X[P] , Y[P] , Q[P ];
    int            N;
    / /−−−−−−−−−−−−− SET CHARGE DISTRIBUTION −−−−
   N       = 2;
   X[0] = 1.0;
   Y [0] = 0.0;
   Q[0] = 1.0;
   X [ 1 ] = −1.0;
   Y [1] = 0.0;
   Q [ 1 ] = −1.0;

    / /−−−−−−−−−−−−− DRAWING LINES                −−−−−−−−−−−−−
    eline ( 0 . 0 , 0 . 5 , X , Y , Q , N ) ;
    eline ( 0 . 0 , 1 . 0 , X , Y , Q , N ) ;
    eline ( 0 . 0 , 1 . 5 , X , Y , Q , N ) ;
    eline ( 0 . 0 , 2 . 0 , X , Y , Q , N ) ;
    eline ( 0 . 0 , − 0 . 5 , X , Y , Q , N ) ;
    eline ( 0 . 0 , − 1 . 0 , X , Y , Q , N ) ;
    eline ( 0 . 0 , − 1 . 5 , X , Y , Q , N ) ;
    eline ( 0 . 0 , − 2 . 0 , X , Y , Q , N ) ;
} / / main ( )

The statements
318                                             CHAPTER 7. ELECTROSTATICS


  N       = 2;
  X[0]    = 1.0;
  Y[0]    = 0.0;
  Q[0]    = 1.0;
  X[1]    = −1.0;
  Y[1]    = 0.0;
  Q[1]    = −1.0;

define two opposite charges Q[0]= -Q[1]= 1.0 located at (1, 0) and (−1, 0)
respectively. The next lines call the function eline in order to perform the
calculation of 8 field lines passing through the points (0, ±1/2), (0, ±1),
(0, ±3/2), (0, ±2):

  eline ( 0 . 0 , 0 . 5 , X , Y , Q , N ) ;
  eline ( 0 . 0 , 1 . 0 , X , Y , Q , N ) ;
  eline ( 0 . 0 , 1 . 5 , X , Y , Q , N ) ;
  eline ( 0 . 0 , 2 . 0 , X , Y , Q , N ) ;
  eline ( 0 . 0 , − 0 . 5 , X , Y , Q , N ) ;
  eline ( 0 . 0 , − 1 . 0 , X , Y , Q , N ) ;
  eline ( 0 . 0 , − 1 . 5 , X , Y , Q , N ) ;
  eline ( 0 . 0 , − 2 . 0 , X , Y , Q , N ) ;

These commands print the coordinates of the field lines to the stdout
and the user can analyze them further.
    The program for calculating the equipotential lines is quite similar.
The calls to the function eline are substituted by calls to epotline.
    For the program to be complete, we must program the functions
eline, efield, mdist. This will be done later, and you can find the
full code in the file ELines.cpp. For the moment, let’s copy the main
program⁴ listed above into the file Elines.cpp and compile and run it
with the commands:

> g++ ELines . cpp −o el
> . / el > el . out

The stdout of the program is redirected to the file el.out. We can plot
the results with gnuplot:

gnuplot > plot ” e l . out ” with dots

The result is shown in figure 7.2.

  ⁴See the file ELines_version0.cpp.
7.2. THE PROGRAM – APPETIZER AND ... DESERT                                     319


            2

          1.5

            1

          0.5

            0

         -0.5

           -1

         -1.5

           -2
             -1.5       -1       -0.5        0        0.5        1        1.5

Figure 7.2: Some electric field lines of the electric field of two opposite charges
calculated by the program ELines.cpp (version 1!).




    Let’s modify the program so that the user can enter the charge dis-
tribution, as well as the number and position of the field lines that she
wants to draw, interactively. The part of the code that we need to change
is:

  / /−−−−−−−−−−−−− SET CHARGE DISTRIBUTION −−−−
  cout << ” # Enter number o f c h a r g e s : ”              << endl ;
  cin >> N ;                                    getline ( cin , buf ) ;
  cout << ” # N= ”                 << N                       << endl ;
  f o r ( i =0;i<N ; i++){
      cout << ” # Charge : ” << i+1                           << endl ;
      cout << ” # P o s i t i o n and charge : (X, Y , Q) : ” << endl ;
      cin >> X [ i ] >> Y [ i ] >> Q [ i ] ;    getline ( cin , buf ) ;
      cout <<               ” # (X, Y)= ”
              << X [ i ] << ” ”
              << Y [ i ] << ” Q= ”
              << Q [ i ]                                      << endl ;
  }


The first line asks the user to enter the number of charges in the distri-
bution. It proceeds with reading it from the stdin and prints the result
320                                               CHAPTER 7. ELECTROSTATICS

to the stdout. The following loop reads the positions and charges and
stores them at the position i of the arrays X[i], Y[i], Q[i]. The results
are printed to the stdout so that the user can check the values read by
the program.
    The drawing of the field lines is now done by modifying the code so
that:

    / /−−−−−−−−−−−−− DRAWING LINES −−−−−−−−−−−−−
    cout << ” # How many l i n e s t o draw?\n” ;
    cin >> draw ;                                         getline ( cin , buf ) ;
    f o r ( i =1; i<=draw ; i++){
        cout << ” # I n i t i a l p o i n t ( x0 , y0 ) : \ n” ;
        cin >> x0 >> y0 ;                                 getline ( cin , buf ) ;
        eline ( x0 , y0 , X , Y , Q , N ) ;
    }

   As a test case, we run the program for one charge q = 1.0 located at
the origin and we draw one field line passing through the point (0.1, 0.1).

> g++ ELines . cpp −o el
> . / el
# Enter number of charges :
1
# N= 1
# Charge : 1
# Position and charge : ( X , Y , Q ) :
0.0 0.0 1 . 0
# ( X , Y )= 0 0 Q= 1
# How many lines to draw ?
1
# Initial point ( x 0 , y 0) :
0.1 0.1
0.10000000000000001 0.10000000000000001
0.092928932188134528 0.092928932188134528
0.08585786437626905 0.08585786437626905
....

For charge distributions with a large number of point charges, use an
editor to record the charges, their positions and the points where the field
lines should go through.

2                               N : Number of Charges
  1 . 0 0.0 1 . 0               ( X , Y , Q ) : Position and charge
−1.0 0.0 −1.0                   ( X , Y , Q ) : Position and charge
8                               Number of lines to draw
7.2. THE PROGRAM – APPETIZER AND ... DESERT                                         321

0.0    0.5                     x0 ,y 0:   Initial     point    of   line
0.0    1.0                     x0 ,y 0:   Initial     point    of   line
0.0    1.5                     x0 ,y 0:   Initial     point    of   line
0.0    2.0                     x0 ,y 0:   Initial     point    of   line
0.0   −0.5                     x0 ,y 0:   Initial     point    of   line
0.0   −1.0                     x0 ,y 0:   Initial     point    of   line
0.0   −1.5                     x0 ,y 0:   Initial     point    of   line
0.0   −2.0                     x0 ,y 0:   Initial     point    of   line

If the data listed above is written into a file, e.g. Input, then the com-
mand

. / el < Input > el . out

reads the data from the file Input and redirects the data printed to the
stdout to the file el.out. This way you can create a “library” of charge
distributions and the field lines of their respective electric fields. The
main() function (version 2) is listed below:

i n t main ( ) {
    string buf ;
    const int              P = 20; / / max number o f c h a r g e s
    double                 X[P] , Y[P] , Q[P ];
    int                    N;
    int                    i , j , draw ;
    double                 x0 , y0 ;
    / /−−−−−−−−−−−−− SET CHARGE DISTRIBUTION −−−−
    cout << ” # Enter number o f c h a r g e s : ”                   << endl ;
    cin >> N ;                                            getline ( cin , buf ) ;
    cout << ” # N= ”                        << N                     << endl ;
    f o r ( i =0;i<N ; i++){
        cout << ” # Charge : ” << i+1                                << endl ;
        cout << ” # P o s i t i o n and charge : (X, Y , Q) : ” << endl ;
        cin >> X [ i ] >> Y [ i ] >> Q [ i ] ;            getline ( cin , buf ) ;
        cout <<                    ” # (X, Y)= ”
                << X [ i ] << ” ”
                << Y [ i ] << ” Q= ”
                << Q [ i ]                                           << endl ;
   }
    / /−−−−−−−−−−−−− DRAWING LINES −−−−−−−−−−−−−
    cout << ” # How many l i n e s t o draw?\n” ;
    cin >> draw ;                                         getline ( cin , buf ) ;
    f o r ( i =1; i<=draw ; i++){
        cout << ” # I n i t i a l p o i n t ( x0 , y0 ) : \ n” ;
        cin >> x0 >> y0 ;                                 getline ( cin , buf ) ;
        eline ( x0 , y0 , X , Y , Q , N ) ;
   }
322                                             CHAPTER 7. ELECTROSTATICS

}

    If you did the exercises described above, you should have already
realized that in order to draw a nice representative picture of the electric
field can be time consuming. For field lines, one can use simple physical
intuition in order to automate the procedure. For distances close enough
to a point charge the electric field is approximately isotropic. The number
of field lines crossing a small enough curve which contains only the
charge is proportional to the charge (Gauss’s law). Therefore we can
draw a small circle centered around each charge and choose initial points
isotropically distributed on the circle as initial points of the field lines.
The code listed below (version 3) implements the idea for charges that
are equal in magnitude. For charges different in magnitude, the program
is left as an exercise to the reader.

i n t main ( ) {
    string buf ;
    c o n s t double PI = 2 . 0 * atan2 ( 1 . 0 , 0 . 0 ) ;
    const int               P = 20; / / max number o f c h a r g e s
    double                  X[P] , Y[P] , Q[P ];
    int                     N;
    int                     i , j , nd ;
    double                  x0 , y0 , theta ;
    / /−−−−−−−−−−−−− SET CHARGE DISTRIBUTION −−−−
    cout << ” # Enter number o f c h a r g e s : ”                 << endl ;
    cin >> N ;                                          getline ( cin , buf ) ;
    cout << ” # N= ”                       << N                    << endl ;
    f o r ( i =0;i<N ; i++){
        cout << ” # Charge : ” << i+1                              << endl ;
        cout << ” # P o s i t i o n and charge : (X, Y , Q) : ” << endl ;
        cin >> X [ i ] >> Y [ i ] >> Q [ i ] ;          getline ( cin , buf ) ;
        cout <<                     ” # (X, Y)= ”
                 << X [ i ] << ” ”
                 << Y [ i ] << ” Q= ”
                 << Q [ i ]                                        << endl ;
   }
    / /−−−−−−−−−−−−− DRAWING LINES −−−−−−−−−−−−−
    / / We draw 2*nd f i e l d l i n e s around each charge
   nd = 6 ;
    f o r ( i =0;i<N ; i++)
        f o r ( j =1; j <=(2* nd ) ; j++){
            theta = ( PI / nd ) * j ;
            x0        = X [ i ] + 0 . 1 * cos ( theta ) ;
            y0        = Y [ i ] + 0 . 1 * sin ( theta ) ;
            eline ( x0 , y0 , X , Y , Q , N ) ;
        }
7.2. THE PROGRAM – APPETIZER AND ... DESERT                                    323

}

    We set the number of field lines around each charge to be equal to
12 (nd=6). The initial points are taken on the circle whose center is
(X[i],Y[i]) and its radius is 0.1. The 2*nd points are determined by
the angle theta=(PI/nd)*j.
    We record the data of a charge distribution in a file, e.g. Input. We list
the example of four equal charges qi = ±1 below, located at the vertices
of a square:

4                  N : Number of charges
 1 1     −1        ( X , Y , Q ) : Position and   charge
−1 1      1        ( X , Y , Q ) : Position and   charge
 1 −1     1        ( X , Y , Q ) : Position and   charge
−1 −1    −1        ( X , Y , Q ) : Position and   charge

Then we give the commands:

> g++ ELines . cpp −o el
> . / el < Input > el . out
> gnuplot
gnuplot > p l o t ” e l . out ” with dots

The results are shown in figures 7.3 and 7.4. The reader should deter-
mine the charge distributions that generate those fields and reproduce
the figures as an exercise.
   For the computation of the equipotential lines we can work in a similar
way. We will follow a quick and dirty way which will not produce an
accurate picture of the electric field and choose the initial points evenly
spaced on an square lattice. For a better choice see problem 5. The
function main() from the file EPotential.cpp is listed below:

i n t main ( ) {
    string buf ;
    const int            P = 20; / / max number o f c h a r g e s
    double               X[P] , Y[P] , Q[P ];
    int                  N;
    int                  i , j , nd ;
    double               x0 , y0 , rmin , rmax , L ;
    / /−−−−−−−−−−−−− SET CHARGE DISTRIBUTION −−−−
    cout << ” # Enter number o f c h a r g e s : ”              << endl ;
    cin >> N ;                                       getline ( cin , buf ) ;
    cout << ” # N= ”                  << N                      << endl ;
    f o r ( i =0;i<N ; i++){
324                                                                          CHAPTER 7. ELECTROSTATICS

                                            4

                                            3

                                            2

                                            1

                                            0

                                            -1

                                            -2

                                            -3

                                            -4
                                                 -4   -3   -2   -1   0   1   2         3    4

       4                                                                         4

       3                                                                         3

       2                                                                         2

       1                                                                         1

       0                                                                         0

      -1                                                                         -1

      -2                                                                         -2

      -3                                                                         -3

      -4                                                                         -4
           -4   -3    -2   -1   0   1   2         3    4                              -4   -3   -2   -1   0   1   2   3   4



Figure 7.3: Field lines of a static charge distribution of point charges generated by
the program ELines.cpp.




      cout           <<    ” # Charge : ” << i+1                           << endl ;
      cout           <<    ” # P o s i t i o n and charge : (X, Y , Q) : ” << endl ;
      cin            >>    X [ i ] >> Y [ i ] >> Q [ i ] ;   getline ( cin , buf ) ;
      cout           <<                  ” # (X, Y)= ”
                     <<    X [ i ] << ” ”
                     <<    Y [ i ] << ” Q= ”
                     <<    Q[i]                                            << endl ;
  }
  / /−−−−−−−−−−−−− DRAWING LINES −−−−−−−−−−−−−
  / / We draw l i n e s p a s s i n g through an e q u a l l y
  / / spaced l a t t i c e o f N=(2*nd+1) x ( 2 * nd+1) p o i n t s
  / / i n t h e square −L<= x <= L , −L<= y <= L .
  nd = 6 ; L = 1 . 0 ;
  f o r ( i=−nd ; i<nd ; i++)
      f o r ( j=−nd ; j<=nd ; j++){
          x0 = i * ( L / nd ) ;
          y0 = j * ( L / nd ) ;
          cout << ” # @ ”
                  << i << ” ” << j<< ” ” << L / nd                 << ” ”
                  << x0<< ” ” << y0                                << endl ;
          mdist ( x0 , y0 , X , Y , N , rmin , rmax ) ;
          / / we avoid g e t t i n g t o o c l o s e t o a charge :
          i f ( rmin > L / ( nd * 1 0 ) ) epotline ( x0 , y0 , X , Y , Q , N ) ;
7.3. THE PROGRAM – MAIN DISH                                                                        325

          4                                            4

          3                                            3

          2                                            2

          1                                            1

          0                                            0

          -1                                           -1

          -2                                           -2

          -3                                           -3

          -4                                           -4
               -4   -3   -2   -1   0   1   2   3   4        -4   -3   -2   -1   0   1   2   3   4



Figure 7.4: Field lines of a static charge distribution of point charges generated by
the program ELines.cpp.



      }
}

    The first and second part of the code is identical to the previous one.
In the third part we call the function epotline for drawing an equipo-
tential line for each initial point. The initial points are on a square lattice
with (2*nd+1)*(2*nd+1)= 81 points (nd=4). The lattice extends within
the limits set by the square (1, 1), (−1, 1), (−1, −1), (1, −1) (L=1.0). For
each point (x0,y0) we calculate the equipotential line that passes through
it. We check that this point is not too close to one of the charges by call-
ing the function mdist. The call determines the minimum distance rmin
of the point from all the charges which should be larger than L/(nd*10).
You can run the program with the commands:

> g++ EPotential . cpp −o ep
> . / ep < Input > ep . out
> gnuplot
gnuplot > p l o t ” ep . out ” with dots

Some of the results are shown in figure 7.5.


7.3             The Program – Main Dish
In this section we look under the hood and give the details of the inner
parts of the program: The functions eline and epotline that calculate
the field and equipotential lines, the function efield that calculates the
electric field at a point and the function mdist that calculates the mini-
mum and maximum distances of a point from the point charges.
326                                                                 CHAPTER 7. ELECTROSTATICS

                                    1.5

                                       1

                                    0.5

                                       0

                                   -0.5

                                       -1

                                   -1.5
                                            -2 -1.5 -1 -0.5   0   0.5    1    1.5   2

                                                                        10
       3

       2
                                                                         5
       1

       0                                                                 0

       -1
                                                                         -5
       -2

       -3
                                                                        -10
            -3   -2   -1   0   1   2         3                             -10          -5   0   5   10



Figure 7.5: Equipotential lines of the electric field generated by a point charge distri-
bution on the plane calculated by the program in EPotential.cpp. Beware: the density
of the lines is not correctly calculated and it is not proportional to the magnitude of the
electric field. See problem 7.5.



    The function eline is called by the statement:

            eline ( x0 , y0 , X , Y , Q , N ) ;

The input to the routine is the initial point (x0,y0), the number of
charges N, the positions of the charges (X[N],Y[N]) and the charges Q[N].
The routine needs some parameters in order to draw the field line. These
are “hard coded”, i.e. set to fixed values by the programmer that cannot
be changed by the user that calls the routine in her program. One of
them is the step ∆l of equation (7.5) which sets the discretization step
of the field line. It also sets the minimum distance of approaching to
a charge equal to 2∆l. The size of the drawing area of the curve is set
by the parameter max_dist=20.0. We should also provide a check in
the program that checks whether the electric field is zero, in which case
the result of the calculation in equation (7.5) becomes indeterminate. By
taking ∆l > 0, the motion is in the direction of the electric field, which
ends on a negative charge or outside the drawing area (why?). In order
to draw the line in both directions, set ∆l < 0 and repeat the calculation.
7.3. THE PROGRAM – MAIN DISH                                                              327

     The code is listed below:

void
eline ( double            xin , double yin ,
           double *          X , double *      Y , double *          Q , const int N) {
  c o n s t double        step          =0.01;
  c o n s t double        max_dist =20.0;
  int                     i , direction ;
  double                  x0 , y0 ;
  double                  rmin , rmax , r , dx , dy , dl ;
  double                  Ex , Ey , E ;

    cout . precision ( 1 7 ) ;
    f o r ( direction=−1;direction <=1; direction +=2){
        dl = direction * step ;
        x0 = xin ;
        y0 = yin ;
        dx = 0 . 0 ;
        dy = 0 . 0 ;
        mdist ( x0 , y0 , X , Y , N , rmin , rmax ) ;
        while ( rmin > ( 2 . 0 * step ) && rmax < max_dist ) {
            cout << x0 << ” ” << y0 << ’\n ’ ;
            / / We e v a l u a t e t h e E−f i e l d a t t h e midpoint :
            / / This r e d u c e s s y s t e m a t i c e r r o r s
            efield ( x0 +0.5* dx , y0 +0.5* dy , X , Y , Q , N , Ex , Ey ) ;
            E = sqrt ( Ex * Ex+Ey * Ey ) ;
            i f ( E <= 1 . 0 e−10 ) break ;
            dx = dl * Ex / E ;
            dy = dl * Ey / E ;
            x0 = x0 + dx ;
            y0 = y0 + dy ;
            mdist ( x0 , y0 , X , Y , N , rmin , rmax ) ;
        } / / while ( rmin > ( 2 . 0 * s t e p ) && rmax < max_dist )
    } / / f o r ( d i r e c t i o n =−1; d i r e c t i o n <=1; d i r e c t i o n +=2)
}

    In the first part of the code we have the variable declarations. We note
that the values of the parameters step and max_dist are “hard coded”
into our program and the user cannot change them:

    c o n s t double step     =0.01;
    c o n s t double max_dist =20.0;

Their values should be the result of a careful study by the programmer
since they determine the accuracy of the calculation.
   The outmost loop
328                                           CHAPTER 7. ELECTROSTATICS


  f o r ( direction=−1;direction <=1; direction +=2){
      dl = direction * step ;
      ...
  }

sets the direction of motion on the field line (i.e. the sign of ∆l). The
loop is executed twice with direction taking the two values −1 and 1.
    The commands x0 = xin, y0 = yin define the initial point on the
field line. (x0, y0) is the current point on the field line which is printed
to the stdout. The variables (dx, dy) set the step (x0, y0) → (x0+dx,
y0+dy). The drawing of the field line is done in the inner loop

      mdist ( x0 , y0 , X , Y , N , rmin , rmax ) ;
      while ( rmin > ( 2 . 0 * step ) && rmax < max_dist ) {
        cout << x0 << ” ” << y0 << ’\n ’ ;
        ...
        mdist ( x0 , y0 , X , Y , N , rmin , rmax ) ;
      }

which is executed provided that the logical expression (rmin > (2.0*step)
&& rmax < max_dist) is true This happens as long as the current point is
at a distance greater than 2.0*step and the maximum distance from all
charges is less than max_dist⁵. The minimum and maximum distances
are calculated by calling the function mdist.
    The electric field, needed in equation (7.5), is calculated by a call to
efield(x0+0.5*dx,y0+0.5*dy,X,Y,Q,N,Ex,Ey). The first two arguments
give the point at which we want to calculate the electric field, which is
chosen to be the midpoint (x0+dx/2,y0+dy/2) instead of (x0,y0). This
improves the stability and the accuracy of the algorithm.
    Equation (7.5) is coded in the commands

        E    =   sqrt ( Ex * Ex+Ey * Ey ) ;
        dx   =   dl * Ex / E ;
        dy   =   dl * Ey / E ;
        x0   =   x0 + dx ;
        y0   =   y0 + dy ;

   We also perform checks for the cases E=0.0 and dx=dy=0.0:

        i f ( E <= 1 . 0 e−10 ) break ;

  ⁵The choice is not unique of course, you may also try e.g. rmin < max_dist.
7.3. THE PROGRAM – MAIN DISH                                                         329

When the magnitude of the electric field becomes too small we stop the
calculation by exiting the loop with the command break. The reader can
improve the code by adding more checks of singular cases.
    The function epotline is programmed in a similar way. The main()
function is listed below:

i n t main ( ) {
    string buf ;
    const int                P = 20; / / max number o f c h a r g e s
    double                   X[P] , Y[P] , Q[P ];
    int                      N;
    int                      i , j , nd ;
    double                   x0 , y0 , rmin , rmax , L ;
    / /−−−−−−−−−−−−− SET CHARGE DISTRIBUTION −−−−
    cout << ” # Enter number o f c h a r g e s : ”                    << endl ;
    cin >> N ;                                            getline ( cin , buf ) ;
    cout << ” # N= ”                       << N                       << endl ;
    f o r ( i =0;i<N ; i++){
        cout << ” # Charge : ” << i+1                                 << endl ;
        cout << ” # P o s i t i o n and charge : (X, Y , Q) : ” << endl ;
        cin >> X [ i ] >> Y [ i ] >> Q [ i ] ;            getline ( cin , buf ) ;
        cout <<                      ” # (X, Y)= ”
                  << X [ i ] << ” ”
                  << Y [ i ] << ” Q= ”
                  << Q [ i ]                                          << endl ;
   }
    / /−−−−−−−−−−−−− DRAWING LINES −−−−−−−−−−−−−
    / / We draw l i n e s p a s s i n g through an e q u a l l y
    / / spaced l a t t i c e o f N=(2*nd+1) x ( 2 * nd+1) p o i n t s
    / / i n t h e square −L<= x <= L , −L<= y <= L .
   nd = 6 ; L = 1 . 0 ;
    f o r ( i=−nd ; i<nd ; i++)
        f o r ( j=−nd ; j<=nd ; j++){
            x0 = i * ( L / nd ) ;
            y0 = j * ( L / nd ) ;
            cout << ” # @ ”
                    << i << ” ” << j<< ” ” << L / nd                 << ” ”
                    << x0<< ” ” << y0                                << endl ;
            mdist ( x0 , y0 , X , Y , N , rmin , rmax ) ;
            / / we avoid g e t t i n g t o o c l o s e t o a charge :
            i f ( rmin > L / ( nd * 1 0 ) ) epotline ( x0 , y0 , X , Y , Q , N ) ;
        }
}

   The differences are minor: The equipotential lines are closed curves,
therefore we only need to transverse them in one direction. The criterion
for ending the calculation is to approach the initial point close enough
330                                            CHAPTER 7. ELECTROSTATICS

or leave the drawing area:

  while ( r > ( 0 . 9 * dl ) && r < max_dist ) {
    ...
  }

    The values of dx, dy are calculated according to equation (7.6):

      dx = dl * Ey / E ;
      dy = −dl * Ex / E ;

    The function efield is an application of equations⁶ (7.2):

void
efield ( double        x0 , double       y0 ,
            double *    X , double *      Y , double *   Q , const int N ,
            double& Ex , double& Ey ) {
  int         i;
  double r3 , xi , yi ;
  Ex = 0 . 0 ;
  Ey = 0 . 0 ;
  f o r ( i =0;i<N ; i++){
      xi = x0−X [ i ] ;
      yi = y0−Y [ i ] ;
      r3 = pow ( xi * xi+yi * yi , − 1 . 5 ) ;
      Ex = Ex + Q [ i ] * xi * r3 ;
      Ey = Ey + Q [ i ] * yi * r3 ;
  }
}

    Finally, the function mdist calculates the minimum and maximum
distance rmin and rmax of a point (x0,y0) from all the point charges in
the distribution:

void
mdist ( double           x0 , double        y0 ,
            double *       X , double *      Y,            const in t N ,
            double& rmin , double&        rmax ) {
  int         i;
  double r ;
  rmax = 0 . 0 ;
  rmin = 1 0 0 0 . 0 ;
  f o r ( i =0;i<N ; i++){

   ⁶You may improve the program by checking whether ri = 0.
7.4. THE PROGRAM - CONCLUSION                                                              331

        r = sqrt ( ( x0−X [ i ] ) * ( x0−X [ i ] ) + ( y0−Y [ i ] ) * ( y0−Y [ i ] ) ) ;
        i f ( r > rmax ) rmax = r ;
        i f ( r < rmin ) rmin = r ;
    }
}

The initial value of rmin depends of the limits of the drawing area (why?).


7.4         The Program - Conclusion
In this section we list the programs discussed in the previous sections and
provide short usage information for compiling, running and analyzing
your results. You can jump into this section without reading the previous
ones and go back to them if you need to clarify some points that you
find hard to understand.
    First we list the contents of the file ELines.cpp:

# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void
eline ( double xin , double yin ,
              double *    X , double *      Y , double * Q , c o n s t i n t N ) ;
void
efield ( double          x0 , double       y0 ,
              double *    X , double *      Y , double * Q , c o n s t i n t N ,
              double& Ex , double& Ey ) ;
void
mdist ( double           x0 , double       y0 ,
              double *    X , double *      Y,               const int N ,
              double& rm , double& rM ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    string buf ;
    c o n s t double PI = 2 . 0 * atan2 ( 1 . 0 , 0 . 0 ) ;
    const int            P = 20; / / max number o f c h a r g e s
    double               X[P] , Y[P] , Q[P ];
    int                  N;
    int                  i , j , nd ;
    double               x0 , y0 , theta ;
    / /−−−−−−−−−−−−− SET CHARGE DISTRIBUTION −−−−
332                                               CHAPTER 7. ELECTROSTATICS

    cout << ” # Enter number o f c h a r g e s : ”                    << endl ;
    cin >> N ;                                             getline ( cin , buf ) ;
    cout << ” # N= ”                       << N                       << endl ;
    f o r ( i =0;i<N ; i++){
        cout << ” # Charge : ” << i+1                                 << endl ;
        cout << ” # P o s i t i o n and charge : (X, Y , Q) : ” << endl ;
        cin >> X [ i ] >> Y [ i ] >> Q [ i ] ;             getline ( cin , buf ) ;
        cout <<                   ” # (X, Y)= ”
                 << X [ i ] << ” ”
                 << Y [ i ] << ” Q= ”
                 << Q [ i ]                                           << endl ;
    }
    / /−−−−−−−−−−−−− DRAWING LINES −−−−−−−−−−−−−
    / / We draw 2*nd f i e l d l i n e s around each charge
    nd = 6 ;
    f o r ( i =0;i<N ; i++)
        f o r ( j =1; j <=(2* nd ) ; j++){
            theta = ( PI / nd ) * j ;
            x0        = X [ i ] + 0 . 1 * cos ( theta ) ;
            y0        = Y [ i ] + 0 . 1 * sin ( theta ) ;
            eline ( x0 , y0 , X , Y , Q , N ) ;
        }
} / / main ( )
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void
eline ( double xin , double yin ,
              double *       X , double *       Y , double * Q , c o n s t i n t N ) {
    c o n s t double step               =0.01;
    c o n s t double max_dist =20.0;
    int                   i , direction ;
    double                x0 , y0 ;
    double                rmin , rmax , r , dx , dy , dl ;
    double                Ex , Ey , E ;

  cout . precision ( 1 7 ) ;
  f o r ( direction=−1;direction <=1; direction +=2){
      dl = direction * step ;
      x0 = xin ;
      y0 = yin ;
      dx = 0 . 0 ;
      dy = 0 . 0 ;
      mdist ( x0 , y0 , X , Y , N , rmin , rmax ) ;
      while ( rmin > ( 2 . 0 * step ) && rmax < max_dist ) {
          cout << x0 << ” ” << y0 << ’\n ’ ;
          / / We e v a l u a t e t h e E−f i e l d a t t h e midpoint :
          / / This r e d u c e s s y s t e m a t i c e r r o r s
          efield ( x0 +0.5* dx , y0 +0.5* dy , X , Y , Q , N , Ex , Ey ) ;
          E = sqrt ( Ex * Ex+Ey * Ey ) ;
          i f ( E <= 1 . 0 e−10 ) break ;
7.4. THE PROGRAM - CONCLUSION                                                                  333

            dx = dl * Ex / E ;
            dy = dl * Ey / E ;
            x0 = x0 + dx ;
            y0 = y0 + dy ;
            mdist ( x0 , y0 , X , Y , N , rmin , rmax ) ;
        } / / while ( rmin > ( 2 . 0 * s t e p ) && rmax < max_dist )
    } / / f o r ( d i r e c t i o n =−1; d i r e c t i o n <=1; d i r e c t i o n +=2)
} / / eline ()
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void
efield ( double                 x0 , double           y0 ,
              double *            X , double *          Y , double * Q , c o n s t i n t N ,
              double& Ex , double& Ey ) {
    int           i;
    double r3 , xi , yi ;
    Ex = 0 . 0 ;
    Ey = 0 . 0 ;
    f o r ( i =0;i<N ; i++){
        xi = x0−X [ i ] ;
        yi = y0−Y [ i ] ;
        r3 = pow ( xi * xi+yi * yi , − 1 . 5 ) ;
        Ex = Ex + Q [ i ] * xi * r3 ;
        Ey = Ey + Q [ i ] * yi * r3 ;
    }
} / / efield ()
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void
mdist ( double                      x0 , double              y0 ,
              double *                X , double *            Y,               const int N ,
              double& rmin , double& rmax ) {
    int           i;
    double r ;
    rmax = 0 . 0 ;
    rmin = 1 0 0 0 . 0 ;
    f o r ( i =0;i<N ; i++){
        r = sqrt ( ( x0−X [ i ] ) * ( x0−X [ i ] ) + ( y0−Y [ i ] ) * ( y0−Y [ i ] ) ) ;
        i f ( r > rmax ) rmax = r ;
        i f ( r < rmin ) rmin = r ;
    }
} / / mdist ( )

    Then we list the contents of the file EPotential.cpp:

# include     < iostream >
# include     < fstream >
# include     <cstdlib >
# include     <string >
# include     <cmath>
334                                               CHAPTER 7. ELECTROSTATICS

using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void
epotline ( double xin , double yin ,
                  double *        X , double *     Y , double * Q , c o n s t i n t N ) ;
void
efield ( double                  x0 , double      y0 ,
                  double *        X , double *     Y , double * Q , c o n s t i n t N ,
                  double& Ex , double& Ey ) ;
void
mdist           ( double         x0 , double      y0 ,
                  double *        X , double *     Y,                const int N ,
                  double& rm , double& rM ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    string buf ;
    const int                P = 20; / / max number o f c h a r g e s
    double                   X[P] , Y[P] , Q[P ];
    int                      N;
    int                      i , j , nd ;
    double                   x0 , y0 , rmin , rmax , L ;
    / /−−−−−−−−−−−−− SET CHARGE DISTRIBUTION −−−−
    cout << ” # Enter number o f c h a r g e s : ”                    << endl ;
    cin >> N ;                                             getline ( cin , buf ) ;
    cout << ” # N= ”                       << N                       << endl ;
    f o r ( i =0;i<N ; i++){
        cout << ” # Charge : ” << i+1                                 << endl ;
        cout << ” # P o s i t i o n and charge : (X, Y , Q) : ” << endl ;
        cin >> X [ i ] >> Y [ i ] >> Q [ i ] ;             getline ( cin , buf ) ;
        cout <<                      ” # (X, Y)= ”
                  << X [ i ] << ” ”
                  << Y [ i ] << ” Q= ”
                  << Q [ i ]                                          << endl ;
   }
    / /−−−−−−−−−−−−− DRAWING LINES −−−−−−−−−−−−−
    / / We draw l i n e s p a s s i n g through an e q u a l l y
    / / spaced l a t t i c e o f N=(2*nd+1) x ( 2 * nd+1) p o i n t s
    / / i n t h e square −L<= x <= L , −L<= y <= L .
   nd = 6 ; L = 1 . 0 ;
    f o r ( i=−nd ; i<nd ; i++)
        f o r ( j=−nd ; j<=nd ; j++){
            x0 = i * ( L / nd ) ;
            y0 = j * ( L / nd ) ;
            cout << ” # @ ”
                    << i << ” ” << j<< ” ” << L / nd                 << ” ”
                    << x0<< ” ” << y0                                << endl ;
            mdist ( x0 , y0 , X , Y , N , rmin , rmax ) ;
            / / we avoid g e t t i n g t o o c l o s e t o a charge :
            i f ( rmin > L / ( nd * 1 0 ) ) epotline ( x0 , y0 , X , Y , Q , N ) ;
7.4. THE PROGRAM - CONCLUSION                                                 335

       }
} / / main ( )
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void
epotline ( double xin , double yin ,
               double * X , double * Y , double * Q , c o n s t i n t N ) {
    c o n s t double step            =0.02;
    c o n s t double max_dist =20.0;
    int                i;
    double             x0 , y0 ;
    double             r , dx , dy , dl ;
    double             Ex , Ey , E ;

    cout . precision ( 1 7 ) ;
    dl = step ;
    x0 = xin ;
    y0 = yin ;
    dx = 0 . 0 ;
    dy = 0 . 0 ;
    r = step ;
    while ( r > ( 0 . 9 * dl ) && r < max_dist ) {
        cout << x0 << ” ” << y0 << ’\n ’ ;
        / / We e v a l u a t e t h e E−f i e l d a t t h e midpoint :
        / / This r e d u c e s s y s t e m a t i c e r r o r s
        efield ( x0 +0.5* dx , y0 +0.5* dy , X , Y , Q , N , Ex , Ey ) ;
        E = sqrt ( Ex * Ex+Ey * Ey ) ;
        i f ( E <= 1 . 0 e−10 ) break ;
        dx = dl * Ey / E ;
        dy = −dl * Ex / E ;
        x0 = x0 + dx ;
        y0 = y0 + dy ;
        r = sqrt ( ( x0−xin ) * ( x0−xin ) +( y0−yin ) * ( y0−yin ) ) ;
    } / / while ( )
} / / epotline ()
...

where ... are the functions efield and mdist which are identical to the
ones in the file ELines.cpp.
   In order to compile the program use the commands:

> g++ ELines . cpp     −o el
> g++ EPotential . cpp −o ep

Then, edit a file and name it e.g. Input and write the data that define a
charge distribution. For example:

4                  N : Number of charges
336                                           CHAPTER 7. ELECTROSTATICS

 1 1    −1        (X , Y , Q) :   Position   and   charge
−1 1     1        (X , Y , Q) :   Position   and   charge
 1 −1    1        (X , Y , Q) :   Position   and   charge
−1 −1   −1        (X , Y , Q) :   Position   and   charge

The results are obtained with the commands:

> . / el < Input > el . dat
> . / ep < Input > ep . dat
> gnuplot
gnuplot > p l o t ” e l . dat ” with dots
gnuplot > p l o t ” ep . dat ” with dots

   Have fun!


7.5 Electrostatic Field in the Vacuum
Consider a time independent electric field in an area of space which is
empty of electric charge. Maxwell’s equations are reduced to Gauss’s law
                                    ∂Ex ∂Ey ∂Ez
                   ∇
                   ⃗ · E(x,
                       ⃗    y, z) =     +    +    = 0,                (7.8)
                                     ∂x   ∂y   ∂z
together with the equation that defines the electrostatic potential⁷

                           ⃗
                           E(x, y, z) = −∇V
                                         ⃗ (x, y, z) .                (7.9)

Equations (7.8) and (7.9) give the Laplace equation for the function
V (x, y, z):
                                 ∂2V   ∂ 2V   ∂ 2V
                ∇2 V (x, y, z) =     +      +      = 0.       (7.10)
                                 ∂x2   ∂y 2   ∂z 2
    The solution of the equation above is a boundary value problem: We
are looking for the potential V (x, y, z) in a region of space S bounded
by a closed surface ∂S. When the potential is known on ∂S the solution
to (7.10) is unique and the potential and the electric field is determined
everywhere in S.
    For simplicity consider the problem confined on a plane, therefore
V = V (x, y). In this case the last term in equation (7.10) vanishes, the
region S is a compact subset of the plane and ∂S is a closed curve.
    For the numerical solution of the problem, we approximate S by a
discrete, square lattice. The potential is defined on the N sites of the
   ⁷Equivalent to the equation ∇
                               ⃗ ×E
                                  ⃗ = 0.
7.5. ELECTROSTATIC FIELD IN THE VACUUM                                                                             337

lattice. We take S to be bounded by a square with sides of length l. The
distance between the nearest lattice √points is called the lattice constant
a. Then l = (L − 1)a, where L = N is the number of lattice points
on each side of the square. The continuous solution is approximated by
the solution on the lattice, and the approximation becomes exact in the
N → ∞ and a → 0 limits, so that the length l = (L−1)a remains constant.
The curve ∂S is approximated by the lattice sites that are located on the
perimeter of the square and the loci in the square where the potential
takes constant values. This is a simple model of a set of conducting
surfaces (points where V = const. ̸= 0) in a compact region whose
boundary is grounded (points where V = 0). An example is depicted in
figure 7.6.



                111
                000
                000111
                   000
                   000 11001100 11001100 11001100 11001100111
                                                          000
                                                          000111
                                                             000    11001100 11001100 11001100111
                                                                                              000000
                                                                                                 111000
                                                                                                    111 11001100
                111111                                    111000111
                                                             111000
                                                                000
                                                                111                           000
                                                                                              111000
                                                                                                 111000
                                                                                                    111
                000
                111                                                                                     1100
                000
                111                                                                                     1100
                111
                000                                                                                     0011
                111
                000                                                                                     0011
                000
                111                               11001100                   11001100                   11001100
                000
                111
                000
                111                               1100                       1100                       1100
                000
                111                               1100                       1100                       1100
                111
                000                               0011                       0011                       0011
                111
                000                               0011                       0011                       0011
                111
                000                               0011                       0011                       0011
                000
                111                                                                                     1100
                000
                111                                                                                     11001100
                000
                111
                111000
                000111 0011 0011 0011 0011000                111111
                                                          111000000
                                                                000 0011 0011 0011000
                                                                111                           111000
                                                                                                 111000
                                                                                                    111 0011
Figure 7.6: A lattice which corresponds to a cross section of two parallel conducting
planes inside a grounded cubic box. The black lattice sites are the points of constant,
fixed potential whereas the white ones are sites in the vacuum.




   In order to derive a finite difference equation which approximates
equation (7.10), we Taylor expand around a point (x, y) according to the
338                                       CHAPTER 7. ELECTROSTATICS

equations:
                                      ∂V      1 ∂ 2V
           V (x + δx, y) = V (x, y) +    δx +       2
                                                      (δx)2 + . . .
                                      ∂x      2 ∂x
                                      ∂V      1 ∂ 2V
           V (x − δx, y) = V (x, y) −    δx +         (δx)2 + . . .
                                      ∂x      2 ∂x2
                                      ∂V      1 ∂ 2V
           V (x, y + δy) = V (x, y) +    δy +         (δy)2 + . . .
                                      ∂y      2 ∂y 2
                                      ∂V      1 ∂2V
           V (x, y − δy) = V (x, y) −    δy +         (δy)2 + . . . .
                                      ∂y      2 ∂y 2
By summing both sides of the above equations, taking δx = δy and
ignoring the terms implied by . . ., we obtain
             V (x + δx, y) + V (x − δx, y) + V (x, y + δy) + V (x, y − δy)
                                       ∂ 2V   ∂ 2V
                  = 4V (x, y) + (δx)2 ( 2 +         ) + ...
                                       ∂x      ∂y 2
                  ≈ 4V (x, y) ,                                            (7.11)
The second term in the second line was eliminated by using equation
(7.10).
    We map the coordinates of the lattice points to integers (i, j) such that
xi = (i−1)a and yj = (j −1)a where i, j = 1, . . . , L. By taking δx = δy = a
so that xi ± δx = xi ± a = (i − 1 ± 1)a = xi±1 and yj ± δy = yj ± a =
(j − 1 ± 1)a = yj±1 , equation (7.11) becomes:
             1
   V (i, j) = (V (i − 1, j) + V (i + 1, j) + V (i, j − 1) + V (i, j + 1)) . (7.12)
             4
The equation above states that the potential at the position (i, j) is the
arithmetic mean of the potential of the nearest neighbors. We will de-
scribe an algorithm which belongs to the class of “successive overrelax-
ation methods” (SOR) whose basic steps are:
  1. Set the size L of the square lattice.
  2. Flag the sites that correspond to “conductors”, i.e. the sites where
     the potential remains fixed to the boundary conditions values.
  3. Choose an initial trial function for V (x, y) on the vacuum sites. Of
     course it is not the solution we are looking for. A good choice will
     lead to fast convergence of the algorithm to the true solution. A
     bad choice may lead to slow convergence, no convergence or even
     convergence to the wrong solution. In our case the problem is easy
     and the simple choice V (x, y) = 0 will do.
7.5. ELECTROSTATIC FIELD IN THE VACUUM                                     339

  4. Sweep the lattice and enforce equation (7.12) on each visited vacuum
     site. This defines the new value of the potential at this site.

  5. Sweep the lattice repeatedly until two successive sweeps result in a
     very small change in the function V (x, y).
A careful study of the above algorithm requires to test different criteria of
“very small change” and test that different choices of the initial function
V (x, y) result in the same solution.
    We write a program that implements this algorithm in the case of a
system which is the projection of two parallel conducting planes inside
a grounded cubic box on the plane. The lattice is depicted in figure 7.6,
where the black dots correspond to the conductors. All the points of
the box have V = 0 and the two conductors are at constant potential
V1 and V2 respectively. The user enters the values V1 and V2 , the lattice
size L and the required accuracy interactively. The latter is determined
by a small number ϵ. The convergence criterion that we set is that the
maximum difference between the values of the potential between two
successive sweeps should be less than ϵ.
    The data structure is very simple. We use an array double V[L][L]
in order to store the values of the potential at each lattice site. A logical
array bool isConductor[L][L] flags each site as a “conductor site” (=
true) or as a “vacuum site” (=false). Both arrays are put in the global
scope and are accessible by all functions.
    The main program reads in the data entered by the user and then
calls three functions:
  1. initialize_lattice(V1,V2):
     The routine needs at its input the values of the potential V1 and V2
     on the left and right plate respectively. On exit it provides the initial
     values of the potential V[L][L] and the flags isConductor[L][L].
     The geometry of the setting is hard coded and the user needs to
     change this function each time that she wants to study a different
     geometry.
  2. laplace(epsilon):
     This is the heart of the program. On entry we provide the desired
     accuracy epsilon. On exit we obtain the final solution V[L][L].
     This function calculates the arithmetic mean of the potential of the
     nearest neighbors Vav and the value V[i][j]=Vav is changed im-
     mediately⁸. The maximum change in the new value of the potential
  ⁸A different choice would have been to store the value Vav in a temporary array
340                                                   CHAPTER 7. ELECTROSTATICS

       Vav from the old one V[i][j] is stored in the variable error. When
       error becomes smaller than epsilon we assume that convergence
       has been achieved.

   3. print_results():
      This function prints the potential V[L][L] to the file data. Each line
      contains the integers i, j and the value of the potential V[i][j].
      We note that each time that the index i changes, the function prints
      an extra empty line. This is done so that the output can be read
      easily by the three dimensional plotting function splot of gnuplot.

The full program is listed below:

// ************************************************************
/ / PROGRAM LAPLACE_EM
/ / Computes t h e e l e c t r o s t a t i c p o t e n t i a l around c o n d u c t o r s .
/ / The computation i s performed on a square l a t t i c e o f l i n e a r
/ / dimension L . A r e l a x a t i o n method i s used t o converge t o t h e
/ / s o l u t i o n o f Laplace e q u a t i o n f o r t h e p o t e n t i a l .
/ / DATA STRUCTURE:
/ / double V[ L ] [ L ] : Value o f t h e p o t e n t i a l on t h e l a t t i c e s i t e s
/ / bool i s C o n d u c t o r [ L ] [ L ] : I f t r u e      s i t e has f i x e d p o t e n t i a l
//                                           I f f a l s e s i t e i s empty s p a ce
/ / double e p s i l o n : Determines t h e a c c u r a c y o f t h e s o l u t i o n
/ / The maximum d i f f e r e n c e o f t h e p o t e n t i a l on each s i t e
/ / between two c o n s e c u t i v e sweeps should be l e s s than e p s i l o n .
/ / PROGRAM STRUCTURE
/ / main program :
/ / . Data Input
/ / . c a l l f u n c t i o n s f o r i n i t i a l i z a t i o n , computation and
//         printing of r e s u l t s
//         function i n i t i a l i z e _ l a t t i c e :
/ / . I n i t i l i z a t i o n o f V[ L ] [ L ] and i s C o n d u c t o r [ L ] [ L ]
//         function laplace :
/ / . S o l v e s l a p l a c e e q u a t i o n using a r e l a x a t i o n method
//         function print_results :
/ / . P r i n t s r e s u l t s f o r V[ L ] [ L ] i n a f i l e . Uses format
//         c o m p a t i b l e with s p l o t o f gnuplot .
// ************************************************************
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>

Vnew[i][j]. After the sweep, the potential V[i][j]=Vnew[i][j] is changed to the new
values. Which method do you expect to have better convergence properties? Try...
7.5. ELECTROSTATIC FIELD IN THE VACUUM                                                                   341

using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
const i n t L = 31;
bool     isConductor [ L ] [ L ] ;
double V                [L][L ];
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void initialize_lattice ( c o n s t double& V1 , c o n s t double& V2 ) ;
void laplace                   ( c o n s t double& epsilon ) ;
void print_results             () ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    string buf ;
    double V1 , V2 , epsilon ;

   cout       << ” Enter V1 , V2 : ”                                  << endl ;
   cin        >> V1 >> V2 ;                             getline ( cin , buf ) ;
   cout       << ” Enter e p s i l o n : ”                            << endl ;
   cin        >> epsilon ;                              getline ( cin , buf ) ;
   cout       << ” S t a r t i n g Laplace : ”                        << endl ;
   cout       << ” Grid S i z e = ”                         << L << endl ;
   cout       << ” Conductors s e t a t V1= ” << V1
              << ” V2= ”                                    << V2 << endl ;
    cout << ” R e l a x i n g with a c c u r a c y e p s i l o n = ”
              << epsilon << endl ;
     / / The a r r a y s V and i s C o n d u c t o r a r e i n i t i a l i z e d
    initialize_lattice ( V1 , V2 ) ;
     / / On entry , V , i s C o n d u c t o r i s i n i t i a l i z e d .
     / / On e x i t t h e r o u t i n e g i v e s t h e s o l u t i o n V
    laplace ( epsilon ) ;
     / / We p r i n t V i n a f i l e .
    print_results ( ) ;
} / / main ( )
// ************************************************************
/ / function i n i t i a l i z e _ l a t t i c e
/ / I n i t i a l i z e s a r r a y s V[ L ] [ L ] and i s C o n d u c t o r [ L ] [ L ] .
/ / V[ L ] [ L]= 0.0 and i s C o n d u c t o r [ L ] [ L]= f a l s e by d e f a u l t
/ / i s C o n d u c t o r [ i ] [ j ]= t r u e on boundary o f l a t t i c e where V=0
/ / i s C o n d u c t o r [ i ] [ j ]= t r u e on s i t e s with i = L/3+1 ,5 <= j <= L−5
/ / i s C o n d u c t o r [ i ] [ j ]= t r u e on s i t e s with i =2*L/3+1 ,5 <= j <= L−5
/ / V[ i ] [ j ] = V1 on a l l s i t e s with i = L/3+1 ,5 <= j <= L−5
/ / V[ i ] [ j ] = V2 on a l l s i t e s with i =2*L/3+1 ,5 <= j <= L−5
/ / V[ i ] [ j ] = 0 on boundary ( i =1 ,L and j =1 ,L)
/ / V[ i ] [ j ] = 0 on i n t e r i o r s i t e s with i s C o n d u c t o r [ i ] [ j ]= f a l s e
/ / INPUT :
/ / i n t e g e r L : Linear s i z e of l a t t i c e
/ / double V1 , V2 : Values o f p o t e n t i a l on i n t e r i o r c o n d u c t o r s
/ / OUTPUT:
/ / double V[ L ] [ L ] : Array provided by u s e r . Values o f p o t e n t i a l
/ / bool          isConductor [L ] [ L ] : I f true            s i t e has f i x e d p o t e n t i a l
342                                                CHAPTER 7. ELECTROSTATICS

//                                I f f a l s e s i t e i s empty sp a c e
// ************************************************************
void initialize_lattice ( c o n s t double& V1 , c o n s t double& V2 ) {

     / / I n i t i a l i z e t o 0 and f a l s e ( d e f a u l t v a l u e s f o r
     / / boundary and i n t e r i o r s i t e s ) .
    f o r ( i n t i =0;i<L ; i++)
         f o r ( i n t j =0;j<L ; j++){
             V                    [i ][ j ] = 0.0;
             isConductor [ i ] [ j ] = f a l s e ;
         }
     / / We s e t t h e boundary t o be a conductor : (V=0 by d e f a u l t )
    f o r ( i n t i =0;i<L ; i++){
         isConductor [0 ] [ i ] = t r u e ;
         isConductor [ i ] [ 0 ] = t r u e ;
         isConductor [ L −1][ i ] = t r u e ;
         isConductor [ i ] [ L−1] = t r u e ;
    }
     / / We s e t two c o n d u c t o r s a t g iven p o t e n t i a l V1 and V2
    f o r ( i n t i =4; i<L−5;i++){
         V                    [ L / 3 ] [ i ] = V1 ;
         isConductor [ L / 3 ] [ i ] = t r u e ;
         V                    [ 2 * L / 3 ] [ i ] = V2 ;
         isConductor [ 2 * L / 3 ] [ i ] = t r u e ;
    }
} / / i n i t i a l i z e _ l a t t i c e ()
// ************************************************************
/ / function laplace
/ / Uses a r e l a x a t i o n method t o compute t h e s o l u t i o n o f t h e
/ / Laplace e q u a t i o n f o r t h e e l e c t r o s t a t i c p o t e n t i a l on a
/ / 2 dimensional s q u a r e l a t t i c e o f l i n e a r s i z e L .
/ / At eve ry sweep o f t h e l a t t i c e we compute t h e a v e r a g e
/ / Vav o f t h e p o t e n t i a l a t each s i t e ( i , j ) and we immediately
/ / update V[ i ] [ j ]
/ / The computation c o n t i n u e s u n t i l Max | Vav−V[ i ] [ j ] | < e p s i l o n
/ / INPUT :
/ / i n t e g e r L : Lin e ar s i z e o f l a t t i c e
/ / double V[ L ] [ L ] : Value o f t h e p o t e n t i a l a t each s i t e
/ / bool           isConductor [L ] [ L ] : I f true               potential is fixed
//                                                      If  false  p o t e n t i a l i s updated
/ / double e p s i l o n : i f Max | Vav−V[ i ] [ j ] | < e p s i l o n r e t u r n t o
/ / callingprogram .
/ / OUTPUT:
/ / double V[ L ] [ L ] : The computed s o l u t i o n f o r t h e p o t e n t i a l
// ************************************************************
void laplace                                  ( c o n s t double& epsilon ) {
    int            icount ;
    double Vav , error , dV ;
7.6. RESULTS                                                                                                343

    icount = 0 ;
    while ( icount < 10000) {
        icount ++;
        error = 0 . 0 ;
        f o r ( i n t i = 1 ; i<L −1;i++){
            f o r ( i n t j = 1 ; j<L −1;j++){
                 / / We change V only f o r non c o n d u c t o r s :
                 i f ( ! isConductor [ i ] [ j ] ) {
                     Vav = 0 . 2 5 * ( V [ i −1][ j ]+ V [ i + 1 ] [ j ]+ V [ i ] [ j−1]+V [ i ] [ j + 1 ] ) ;
                     dV = abs ( V [ i ] [ j]−Vav ) ;
                     i f ( error < dV ) error = dV ; / / maximum e r r o r
                     V [ i ] [ j ] = Vav ;
                } / / i f ( ! isConductor [ i ] [ j ] )
            } / / f o r ( i n t j = 1 ; j <L−1; j ++)
        } / / f o r ( i n t i = 1 ; i <L−1; i ++)
        cout << icount << ” e r r = ” << error << endl ;
        i f ( error < epsilon ) r e t u r n ;
    } / / while ( i c o u n t < 10000)
    cerr << ” Warning : l a p l a c e did not converge . \ n” ;
} / / laplace ()
// ************************************************************
/ / function print_results
/ / P r i n t s t h e a r r a y V[ L ] [ L ] i n f i l e ” data ”
/ / The format o f t h e output i s a p p r o p r i a t e f o r t h e s p l o t
/ / f u n c t i o n o f gnuplot : Each time i changes an empty l i n e
/ / i s printed .
// ************************************************************
void print_results ( ) {
    ofstream myfile ( ” data ” ) ;
    myfile . precision ( 1 6 ) ;
    f o r ( i n t i = 0 ; i < L ; i++){
        f o r ( i n t j = 0 ; j < L ; j++){
            myfile << i+1 << ” ” << j+1 << ” ” << V [ i ] [ j ] << endl ;
        }
        / / p r i n t empty l i n e f o r gnuplot , s e p a r a t e i s o l i n e s :
        myfile             << ” ”                                                        << endl ;
    }
    myfile . close ( ) ;
} / / print_results ()




7.6        Results
The program in the previous section is written in the file LaplaceEq.cpp.
Compiling and running is done with the commands:
344                                         CHAPTER 7. ELECTROSTATICS

> g++ LaplaceEq . cpp −o lf
> . / lf
Enter V1 , V2 :
100 −100
Enter epsilon :
0.01
Starting Laplace :
Grid Size= 31
Conductors s e t at V1= 100 V2= −100
Relaxing with accuracy epsilon= 0.01
1     err= 33.3333
2     err= 14.8148
3     err= 9.87654
..............
110 err= 0.0106861
111 err= 0.0101182
112 err= 0.00958049

In the example above, the program performs 112 sweeps until the error
becomes 0.00958 < 0.01. The results are stored in the file data. We can
make a three dimensional plot of the function V (i, j) with the gnuplot
commands:

gnuplot >   s e t pm3d
gnuplot >   s e t hidden3d
gnuplot >   s e t s i z e ratio 1
gnuplot >   s p l o t ” data ” with lines

The results are shown in figure 7.7


7.7 Poisson Equation
This section contains a short discussion of the case where the space is
filled with a continuous static charge distribution given by the charge
density function ρ(⃗r). In this case the Laplace equation becomes the
Poisson equation:

                           ∂ 2V   ∂ 2V   ∂2V
                  ∇2 V =        +      +      = −4πρ(x, y, z)          (7.13)
                           ∂x2    ∂y 2   ∂z 2

   The equation on the lattice becomes

           1
 V (i, j) = (V (i−1, j)+V (i+1, j)+V (i, j −1)+V (i, j +1)+ ρ̃(i, j)) , (7.14)
           4
7.7. POISSON EQUATION                                                                               345


                                                                                   "data"



                                                                                             100

            100                                                                              50

             50                                                                              0

              0
                                                                                             -50
             -50
                                                                                             -100
            -100

                                                                                        35
                                                                                   30
                                                                              25
                   0                                                     20
                       5                                            15
                           10
                                15                             10
                                     20
                                          25               5
                                               30
                                                    35 0




Figure 7.7: The solution of the equation (7.10) computed by the program
LaplaceEq.cpp for L= 31, V1=100, V2=-100, epsilon=0.01.



where⁹ ρ̃(i, j) = 4πa2 ρ(i, j).
   The program in the file PoissonEq.cpp solves equation (7.14) for a
uniform charge distribution (figure 7.10), where we have set a = 1. The
reader is asked to reproduce this figure together with figures 7.8 and
7.9.

# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
const i n t L = 51;
bool          isConductor [ L ] [ L ] ;
double V                    [L][L ];
double rho                  [L][L ];
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void initialize_lattice ( c o n s t double& V1 , c o n s t double& V2 ,
                                      c o n s t double& V3 , c o n s t double& V4 ,
                   ∫       ∑                     ∑                 ∑
     ⁹Since Q = ρdA ≈ i,j ρa2 = (1/4π) i,j ρ̃. Therefore i,j ρ̃ ≈ 4πQ.
346                                                     CHAPTER 7. ELECTROSTATICS


                                                                                            "data"



                     800                                                              800
                     700                                                              700
                     600                                                              600
                     500                                                              500
                     400                                                              400
                     300                                                              300
                     200                                                              200
                     100                                                              100
                       0                                                              0




                           0   10 20
                                                                            50   60
                                     30                           30   40
                                          40 50              20
                                                  600   10




Figure 7.8: The solution of the equation (7.13) by the program in the file Poisson.cpp
for L= 51, V= 0 on the boundary and the charge 4πQ = 1000 all concentrated at one
point.




                                     c o n s t double& Q ) ;
void laplace                       ( c o n s t double& epsilon ) ;
void print_results                 () ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    string buf ;
    double V1 , V2 , V3 , V4 , Q , epsilon ;

  cout <<    ” Enter V1 , V2 , V3 , V4 : ”                        << endl ;
  cin  >>    V1 >> V2 >> V3 >> V4 ; getline ( cin , buf ) ;
  cout <<    ” Enter 4* PI *Q: ” ;
  cin  >>    Q;                                   getline ( cin , buf ) ;
  cout <<    ” Enter e p s i l o n : ”                            << endl ;
  cin  >>    epsilon ;                            getline ( cin , buf ) ;
  cout <<    ” S t a r t i n g Laplace : ”                        << endl ;
  cout <<    ” Grid S i z e = ”                      << L << endl ;
  cout <<    ” Conductors s e t a t V1= ” << V1
       <<    ” V2= ”                                 << V2
       <<    ” V3= ”                                 << V3
       <<    ” V4= ”                                 << V4
       <<    ” Q = ”                                 << Q << endl ;
  cout <<    ” R e l a x i n g with a c c u r a c y e p s i l o n = ”
7.7. POISSON EQUATION                                                                                     347


                                                                                                 "data"



                                                                                           350
                    350
                                                                                           300
                    300
                                                                                           250
                    250
                    200                                                                    200

                    150                                                                    150
                    100                                                                    100
                     50                                                                    50
                      0                                                                    0




                          0                                                           60
                              10                                                 50
                                   20                                       40
                                        30                             30
                                             40                   20
                                                  50         10
                                                       600




Figure 7.9: The solution of equation (7.13) by the program in the file Poisson.cpp
for L= 51, V= 0 on the boundary and the charge 4πQ = 1000 uniformly distributed in
a small square with sides made of 10 lattice sites.




         << epsilon << endl ;

  initialize_lattice ( V1 , V2 , V3 , V4 , Q ) ;

  laplace ( epsilon ) ;

  print_results ( ) ;

} / / main ( )
// ************************************************************
void initialize_lattice ( c o n s t double& V1 , c o n s t double& V2 ,
                                       c o n s t double& V3 , c o n s t double& V4 ,
                                       c o n s t double& Q ) {
    int           L1 , L2 ;
    double Area ;
    / / I n i t i a l i z e t o 0 and . FALSE ( d e f a u l t v a l u e s
    / / f o r boundary and i n t e r i o r s i t e s ) .
    f o r ( i n t i =0;i<L ; i++)
        f o r ( i n t j =0;j<L ; j++){
            V                  [i ][ j ] = 0.0;
            isConductor [ i ] [ j ] = f a l s e ;
            rho                [i ][ j ] = 0.0;
348                                                           CHAPTER 7. ELECTROSTATICS


                                                                                                  "data"



                                                                                             80
                      80                                                                     70
                      70                                                                     60
                      60                                                                     50
                      50
                                                                                             40
                      40
                      30                                                                     30
                      20                                                                     20
                      10                                                                     10
                       0                                                                     0



                           0                                                            60
                               10                                                  50
                                    20                                        40
                                         30                              30
                                              40                    20
                                                   50          10
                                                        600




Figure 7.10: The solution of equation (7.13) by the program in the file Poisson.cpp
for L= 51, V= 0 on the boundary and the charge 4πQ = 1000 uniformly distributed on
all internal lattice sites.




      }
  / / We s e t t h e boundary t o be a conductor : (V=0 by d e f a u l t )
  f o r ( i n t i =0;i<L ; i++){
      isConductor [0 ] [ i ] = t r u e ;
      isConductor [ i ] [ 0 ] = t r u e ;
      isConductor [ L −1][ i ] = t r u e ;
      isConductor [ i ] [ L−1] = t r u e ;
      V               [0 ] [ i ] = V1 ;
      V               [ i ] [ L−1] = V2 ;
      V               [ L −1][ i ] = V3 ;
      V               [ i ] [ 0 ] = V4 ;
  }
  / / We s e t t h e p o i n t s with non−z e r o charge
  / / A uniform d i s t r i b u t i o n a t a c e n t e r square
  L1 = ( L / 2 ) − 5 ;
  L2 = ( L / 2 ) + 5 ;
  i f ( L1< 0) { cerr <<” Array out o f bounds . L1< 0\n” ; exit ( 1 ) ; }
  i f ( L2>=L ) { cerr <<” Array out o f bounds . L2>=0\n” ; exit ( 1 ) ; }
  Area = ( L2−L1 +1) * ( L2−L1 +1) ;

  f o r ( i n t i=L1 ; i<=L2 ; i++)
      f o r ( i n t j=L1 ; j<=L2 ; j++)
7.7. POISSON EQUATION                                                                                 349

          rho [ i ] [ j ] = Q / Area ;

} / / i n i t i a l i z e _ l a t t i c e ()
// ************************************************************
void laplace                                 ( c o n s t double& epsilon ) {
    int           icount ;
    double Vav , error , dV ;

    icount = 0 ;
    while ( icount < 10000) {
        icount ++;
        error = 0 . 0 ;
        f o r ( i n t i = 1 ; i<L −1;i++){
            f o r ( i n t j = 1 ; j<L −1;j++){
                / / We change V only f o r non c o n d u c t o r s :
                i f ( ! isConductor [ i ] [ j ] ) {
                    Vav = 0 . 2 5 * ( V [ i −1][ j ]+ V [ i + 1 ] [ j ]+ V [ i ] [ j−1]+V [ i ] [ j +1]
                                      +rho [ i ] [ j ] ) ;
                    dV = abs ( V [ i ] [ j]−Vav ) ;
                    i f ( error < dV ) error = dV ; / / maximum e r r o r
                    V [ i ] [ j ] = Vav ;
                } / / i f ( ! isConductor [ i ] [ j ] )
            } / / f o r ( i n t j = 1 ; j <L−1; j ++)
        } / / f o r ( i n t i = 1 ; i <L−1; i ++)
        cout << icount << ” e r r = ” << error << endl ;
        i f ( error < epsilon ) r e t u r n ;
    } / / while ( i c o u n t < 10000)
    cerr << ” Warning : l a p l a c e did not converge . \ n” ;
} / / laplace ()
// ************************************************************
void print_results ( ) {
    ofstream myfile ( ” data ” ) ;
    myfile . precision ( 1 6 ) ;
    f o r ( i n t i = 0 ; i < L ; i++){
        f o r ( i n t j = 0 ; j < L ; j++){
            myfile << i+1 << ” ” << j+1 << ” ” << V [ i ] [ j ] << endl ;
        }
        / / p r i n t empty l i n e f o r gnuplot , s e p a r a t e i s o l i n e s :
        myfile            << ” ”                                                        << endl ;
    }
    myfile . close ( ) ;
} / / print_results ()

    In the bibliography the algorithm described above is called the Gauss–
Seidel method. In this method, the right hand side of equation (7.14)
uses the updated values of the potential in the calculation of V (i, j) and
V (i, j) is immediately updated. In contrast, the Jacobi method uses the
old values of the potential in the right hand side of (7.14) and the new
350                                          CHAPTER 7. ELECTROSTATICS

value computed is stored in order to be used in the next sweep. The
Gauss–Seidel method is superior to the Jacobi method as far as speed of
convergence is concerned. We can generalize Jacobi’s method by defining
the residual Ri,j of equation (7.14)

Ri,j = V (i + 1, j) + V (i − 1, j) + V (i, j + 1) + V (i, j − 1) − 4V (i, j) + ρ̃(i, j) ,
                                                                                (7.15)
which vanishes when V (i, j) is a solution of equation (7.14). Then, using
Ri,j , Jacobi’s method can be formulated as

                                                        1 (n)
                         V (n+1) (i, j) = V (n) (i, j) + Ri,j ,                  (7.16)
                                                        4
where the quantities with index (n) refer to the values of the potential
during the n-th sweep. The successive overrelaxation (SOR) method is
given by:
                                                   ω (n)
                    V (n+1) (i, j) = V (n) (i, j) + Ri,j .        (7.17)
                                                   4
When ω < 1 we have “underrelaxation” and we obtain slower conver-
gence than the Jacobi method. When 1 < ω < 2 we have “overrelaxation”
and an appropriate choice of ω can lead to an improvement compared
to the Jacobi method. When ω > 2 SOR diverges. Further study of the
SOR methods is left as an exercise to the reader.
7.8. PROBLEMS                                                          351

7.8    Problems
 7.1 Reproduce the figures with the electric field lines and equipotential
     lines shown in section 7.2.

7.2 Take the charge distributions that you used in the previous prob-
    lems, make all the charges to be positive and remake the figures of
    the field lines and the equipotential lines. Then repeat by taking
    half of the charges to be twice in magnitude than the others.

7.3 The program ELines.cpp gets stuck when you apply it on a charge
    distribution of four equal charges located at the vertices of a square.
    How can you correct this pathology?

 7.4 Make the necessary changes to the program in the file ELines.cpp so
     that the number of field lines starting near a charge q is proportional
     to q.

7.5 Improve the program in EPotential.cpp so that the equipotential
    lines are drawn with a density proportional to the magnitude of the
    electric field.
    Hint:

      (a) Write a subroutine that calculates the potential V (x, y) at the
          point (x, y).
      (b) From each point charge draw a line in the radial direction and
          calculate the potential on points that are at small distance ∆l
          from each other.
      (c) Calculate the maximum/minimum value of the potential Vmax /Vmin
          and use them in order to choose the values of the potential
          on the equipotential lines that you plan to draw. If e.g. you
          choose to draw 5 equipotential lines, take δV = (Vmax − Vmin )/4
          and Vi = Vmin + iδV i = 0, . . . , 4.
      (d) Repeat the second step. When the potential at a point takes
          approximately one of the values Vi chosen in the previous step,
          draw an equipotential line from that point.

7.6 Compute the electric potential using the program in the file LaplaceEq.
    cpp for

      (a) L= 31, V1=100, V2=100
      (b) L= 31, V1=100, V2=0
352                                   CHAPTER 7. ELECTROSTATICS

      and construct the corresponding plot for V (i, j).

 7.7 Compute the electric potential using the program in the file LaplaceEq.
     cpp for

      (a) V1=100, V2=100
      (b) V1=100, V2=100
       (c) V1=100, V2=0

      for L=31,61,121,241,501 and construct the corresponding plot for
      V (i, j). Vary epsilon=0.1, 0.01, 0.001, 0.0001, 0.00001,
      0.000001. What is the dependence of the number of sweeps N
      on epsilon? Make the plot of N (epsilon). Put the points and
      curves of N (epsilon) for all values of L on the same plot.

 7.8 Compute the electrostatic potential of a square conductor when the
     potential on each side is V1, V2, V3, V4. Repeat what you did in
     the previous problem for

      (a) V1=10, V2=5, V3=10, V4= 5
      (b) V1=10, V2=0, V3=0, V4= -10
       (c) V1=10, V2=0, V3=0, V4= 0

 7.9 Compute the electrostatic potential of a system of square conductors
     where the one is inside the other as shown in figure 7.11. The side
     of each conductor has L1, L2 sites respectively and the value of the
     potential is V1,V2 respectively. Take L2= L1/5 and repeat the steps
     in the previous problem for V1=10, V2=-10 and L1= 25, 50, 100,
     200.

7.10 Perform a numerical computation of the capacitance C = Q/V of
     the system of conductors of the previous problem when V1 = V ,
     V2 = −V . In order to calculate the charge Q, compute the surface
     charge density σ using the equation

                                         En
                                    σ=      ,
                                         4π
      where En is the perpendicular component of the electric field on
      the surface. Use the approximation

                                           δV
                                  En = −      ,
                                           δr
7.8. PROBLEMS                                                                                                      353
                111
                000
                000111
                   000
                   000 11001100 11001100 11001100 11001100111
                                                          000
                                                          000111
                                                             000    11001100 11001100 11001100111
                                                                                              000000
                                                                                                 111000
                                                                                                    111 11001100
                111111                                    111000111
                                                             111000
                                                                000
                                                                111                           000
                                                                                              111000
                                                                                                 111000
                                                                                                    111
                000
                111                                                                                     1100
                000
                111                                                                                     1100
                111
                000                                                                                     0011
                111
                000                                                                                     0011
                000
                111                               11001100000
                                                          111000
                                                             111000
                                                                111 0011 1100                           11001100
                000
                111                                                          1100
                000
                111                               1100                       1100                       1100
                000
                111                               1100                       1100                       1100
                111
                000                               0011                       0011                       0011
                111
                000                               0011000 111000
                                                             111000
                                                                111 0011 0011                           0011
                111
                000                                                                                     0011
                000
                111                                                                                     1100
                000
                111                                                                                     11001100
                000
                111
                111000
                000111 0011 0011 0011 0011000                111111
                                                          111000000
                                                                000 0011 0011 0011000
                                                                111                           111000
                                                                                                 111000
                                                                                                    111 0011
          Figure 7.11: The square conductors described in problem 7.9.



     where δV is the potential difference between a point on the con-
     ductor and its nearest neighbor. By integrating (i.e. summing)
     you can estimate the total charge on each conductor. If these are
     opposite and their absolute value is Q, then the capacitance can be
     calculated from the equation C = Q/V . Perform the calculation
     described above for V = 10 and L1=25, 75.

7.11 In the system of the previous problem compute the function Q(V ).
     Verify that the capacitance is independent of V . Use L1=25,50, V1=
     -V2 =1, 2, 5, 10, 15, 20, 25.

7.12 Reproduce figures 7.8, 7.9 and 7.10. Compare the result of the first
     case with the known solution of a point charge in empty space.

7.13 Introduce the lattice spacing a in the corresponding equations in the
     program in the file PoissonEq.cpp. Set the length of each side to be
     l = 1 and print the results in the file data as (xi , yi , V (xi , yi )) instead
     of (i, j, V (i, j)). Take L=51,101,151,201,251 and plot V (x, y) in the
     square 0 < x < 1, 0 < y < 1. Study the convergence of the solutions
     by plotting the section V (x, 1/2) for each L.

7.14 Write a program that implements the SOR algorithm given by equa-
354                                 CHAPTER 7. ELECTROSTATICS

      tion (7.16) for the problem solved in LaplaceEq.cpp. Compare the
      speed of convergence of SOR with that of the Gauss-Seidel method
      for L = 51, ω = 1.0, 0.9, 0.8, 0.6, 0.4, 0.2. What happens when
      ω > 1?

7.15 Write a program that implements the SOR algorithm given by equa-
     tion (7.16) for the problem solved in PoissonEq.cpp. Compare the
     speed of convergence of SOR with that of the Gauss-Seidel method
     for L = 51, ω = 1.0, 0.9, 0.8, 0.6, 0.4, 0.2. What happens when
     ω > 1?
Chapter 8

Diffusion Equation

8.1      Introduction
The diffusion equation is related to the study of random walks. Consider
a particle moving on a line (one dimension) performing a random walk.
The motion is stochastic and the kernel
                                      K(x, x0 ; t) ,                                (8.1)
is interpreted as the probability density to observe the particle at position
x at time t if the particle is at x0 at t = 0. The equation that determines
K(x, x0 ; t) is
                       ∂K(x, x0 ; t)      ∂ 2 K(x, x0 ; t)
                                     =D                    ,            (8.2)
                            ∂t                 ∂x2
which is the diffusion equation. The coefficient D depends on the details
of the system that is studied. For example, for the Brownian motion of
a dust particle in a fluid which moves under the influence of random
collisions with the fluid particles, we have that D = kT /γ, where T is
the (absolute) temperature of the fluid, γ is the friction coefficient¹ of the
particle in the fluid and k is the Boltzmann constant.
    Usually the initial conditions are chosen so that at t = 0 the particle
is localized at one point x0 , i.e.²
                              K(x, x0 ; 0) = δ(x − x0 ) .                          (8.3)
    ¹For a spherical particle of radius R in a Newtonian liquid with viscosity η we have
that γ = 6πηR.
    ² δ(x − x0 ) is the Dirac delta “function”. It can be defined from the requirement
                                            ∫ +∞
that for every function f (x) we have that −∞ f (x)δ(x − x0 ) dx = f (x0 ). Obviously we
                ∫ +∞
also have that −∞ δ(x − x0 ) dx = 1. Intuitively one can think of it as a function that is
almost zero everywhere except in an infinitesimal neighborhood of x0 .


                                          355
356                                              CHAPTER 8. DIFFUSION EQUATION

    The interpretation of K(x, x0 ; t) as a probability density implies that
for every t we should have that³
                         ∫ +∞
                               K(x, x0 ; t) dx = 1 .                   (8.4)
                                          −∞

It is not obvious that this relation can be imposed for every instant of
time. Even if K(x, x0 ; t) is normalized so that (8.4) holds for t = 0, the
time evolution of K(x, x0 ; t) is governed by equation (8.2) which can spoil
equation (8.4) at later times.
    If we impose equation (8.4) at t = 0, then it will hold at all times if
                             ∫
                          d +∞
                                    K(x, x0 ; t)dx = 0 .               (8.5)
                         dt −∞
                                                d
                                                     ∫ +∞                              ∫ +∞   ∂K(x,x0 ;t)
By taking into account that                     dt    −∞
                                                             K(x, x0 ; t)dx =            −∞      ∂t
                                                                                                          dx   and
       ∂K(x,x0 ;t)        ∂ 2 K(x,x   0 ;t)
that      ∂t
                     =D       ∂x2
                                              we obtain
               ∫   +∞                                        ∫   +∞         (                 )
          d                                           ∂K(x, x0 ; t)   ∂
                           K(x, x0 ; t)dx = D                                                     dx
          dt    −∞                             −∞        ∂x           ∂x
                                ∂K(x, x0 ; t)         ∂K(x, x0 ; t)
                           =D                      −D                                                   . (8.6)
                                      ∂x      x→+∞       ∂x                                    x→−∞

The above equation tells us that for functions for which the right hand
side vanishes, the normalization condition will be valid for all t > 0.
   A careful analysis of equation (8.2) gives that the asymptotic behavior
of K(x, x0 ; t) for small times is
                                                          |x−x0 |2
                                                     e−     4Dt      ∑
                                                                     ∞
                           K(x, x0 ; t) ∼                                  ai (x, x0 )ti .                     (8.7)
                                                          td/2       i=0

This relation shows that diffusion is isotropic (the same in all directions)
and that the probability of detecting the particle drops exponentially with
the distance squared from the initial position of the particle. This relation
cannot hold for all times, since for large enough times the probability of
detecting the particle will be the same everywhere⁴.
   ³Alternatively, if K(x, x0 ; t) is interpreted as e.g. the mass density of a drop of ink
                                                                 ∫ +∞
of mass mink inside a transparent liquid, we will have that −∞ K(x, x0 ; t) dx = mink
and K(x, x0 ; 0) = mink δ(x − x0 ).
   ⁴Remember the analogy of an ink drop diffusing in a transparent liquid. After long
enough time, the ink is homogeneously dissolved in the liquid.
8.2. HEAT CONDUCTION IN A THIN ROD                                              357

   The return probability of the particle to its initial position is
                                              1 ∑
                                                ∞
                 PR (t) = K(x0 , x0 ; t) ∼                ai (x0 , x0 )ti .    (8.8)
                                             td/2   i=0

The above relation defines the spectral dimension d of space. d = 1 in our
case.
    The expectation value of the distance squared of the particle at time
t is easily calculated⁵
                                ∫ +∞
       ⟨r ⟩ = ⟨(x − x0 ) ⟩(t) =
         2              2
                                     (x − x0 )2 K(x, x0 ; t) dx ∼ 2Dt . (8.9)
                                −∞

This equation is very important. It tells us that the random walk (Brow-
nian motion) is not a classical motion but it can only be given a stochastic
description: A classical particle moving with constant velocity v so that
x − x0 ∼ vt results in r2 ∼ t2 .
   In the following sections we take⁶ D = 1 and define
                          u(x, t) ≡ K(x − x0 , x0 ; t) .                      (8.10)


8.2 Heat Conduction in a Thin Rod
Consider a thin rod of length L and let T (x, t) be the temperature dis-
tribution within the rod at time t. The two ends of the rod are kept at
constant temperature T (0, t) = T (L, t) = T0 . If the initial temperature
distribution in the rod is T (x, 0), then the temperature distribution at all
times is determined by the diffusion equation
                           ∂T (x, t)     ∂ 2 T (x, t)
                                     =α               ,               (8.11)
                              ∂t             ∂x2
where α = k/(cp ρ) is the thermal diffusivity, k is the thermal conductivity,
ρ is the density and cp is the specific heat of the rod.
    Define                                    2
                                    T (xL, Lα t) − T0
                         u(x, t) =                      ,             (8.12)
                                           T0
where x ∈ [0, 1]. The function u(x, t), giving the fraction of the tempera-
ture difference to the temperature at the ends of the rod, is dimensionless
and
                            u(0, t) = u(1, t) = 0 .                   (8.13)
   ∫∞
  ⁵ 0 dr rn e−r /4Dt = 2n Γ( n+1
               2                      n+1
                                       2 .
                              2 )(Dt)
  ⁶According to equation (8.2) this amounts to taking t → Dt.
358                                CHAPTER 8. DIFFUSION EQUATION

These are called Dirichlet boundary conditions⁷.
  Equation (8.11) becomes

                               ∂u(x, t)   ∂ 2 u(x, t)
                                        =                                    (8.14)
                                 ∂t           ∂x2
   Equation (8.6) becomes
                     ∫
                   d 1             ∂u                    ∂u
                       u(x, t)dx =                   −                       (8.15)
                  dt 0             ∂x          x=1       ∂x   x=0

   The relation above cannot be equal to zero at all times due to the
boundary conditions (8.13). This can be easily understood with an ex-
ample. Suppose that
                          u(x, 0) = sin(πx) ,                  (8.16)
then it is easy to confirm that the boundary conditions are satisfied and
that the function
                         u(x, t) = sin(πx)e−π t ,
                                             2
                                                                  (8.17)
is the solution to the diffusion equation. It is easy to see that
                           ∫ 1
                                          2
                               u(x, t)dx = e−π t
                                               2


                            0             π
drops exponentially with time and that
                        ∫
                      d 1
                            u(x, t)dx = −2πe−π t ,
                                              2

                      dt 0

which is in agreement with equations (8.15).
   The exponential drop of the magnitude of u(x, t) is in agreement with
the expectation that the rod will have constant temperature at long times,
which will be equal to the temperature at its ends (limt→+∞ u(x, t) = 0).


8.3 Discretization
The numerical solution of equation (8.14) will be computed in the interval
x ∈ [0, 1] for t ∈ [0, tf ]. The problem will be defined on a two dimensional
discrete lattice and the differential equation will be approximated by finite
difference equations.
   ⁷If the derivative ∂u/∂x was given as a boundary condition instead, then we would
have Neumann boundary conditions.
8.3. DISCRETIZATION                                                         359

   The lattice is defined by Nx spatial points xi ∈ [0, 1]

                     xi = 0 + (i − 1)∆x i = 1, . . . , Nx ,               (8.18)

where the Nx − 1 intervals have the same width
                                          1−0
                                  ∆x =           ,                        (8.19)
                                          Nx − 1
and by the Nt time points tj ∈ [0, tf ]

                     tj = 0 + (j − 1)∆t         j = 1, . . . , Nt ,       (8.20)

where the Nt − 1 time intervals have the same duration
                                          tf − 0
                                   ∆t =          .                        (8.21)
                                          Nt − 1
We note that the ends of the intervals correspond to

                  x1 = 0 ,    xNx = 1 ,       t1 = 0 ,    tNt = tf .      (8.22)

The function u(x, t) is approximated by its values on the Nx × Nt lattice

                                  ui,j ≡ u(xi , tj ) .                    (8.23)

The derivatives are replaced by the finite differences

      ∂u(x, t)   u(xi , tj + ∆t) − u(xi , tj )   1
               ≈                               ≡    (ui,j+1 − ui,j ) ,    (8.24)
        ∂t                   ∆t                  ∆t

         ∂ 2 u(x, t)   u(xi + ∆x, tj ) − 2u(xi , tj ) + u(xi − ∆x, tj )
                2
                     ≈
             ∂x                           (∆x)2
                         1
                     ≡       (ui+1,j − 2ui,j + ui−1,j ) .                 (8.25)
                       (∆x)2

By equating both sides of the above relations according to (8.14), we
obtain the dynamic evolution of ui,j in time
                                   ∆t
                ui,j+1 = ui,j +         (ui+1,j − 2ui,j + ui−1,j ) .      (8.26)
                                  (∆x)2
This is a one step iterative relation in time. This is very convenient,
because one does not need to store the values ui,j for all j in the computer
memory.
360                                     CHAPTER 8. DIFFUSION EQUATION

   The second term (the “second derivative”) in (8.26) contains only the
nearest neighbors ui±1,j of the lattice point ui,j at a given time slice tj .
Therefore it can be used for all i = 2, . . . , Nx − 1. The relations (8.26)
are not needed for the points i = 1 and i = Nx since the values u1,j =
uNx ,j = 0 are kept constant.
   The parameter
                                    ∆t
                                                                      (8.27)
                                  (∆x)2
determines the time evolution in the algorithm. It is called the Courant
parameter and in order to have a time evolution without instabilities it
is necessary to have
                               ∆t      1
                                   2
                                     < .                          (8.28)
                              (∆x)     2
This condition will be checked in our analysis empirically.



                                                                  "d.dat"

                                                                                         1
                                                                                         0.9
                 1                                                                       0.8
               0.9                                                                       0.7
               0.8                                                                       0.6
               0.7                                                                       0.5
      u(x,t)   0.6                                                                       0.4
               0.5                                                                       0.3
               0.4                                                                       0.2
               0.3                                                                       0.1
               0.2                                                                       0
               0.1
                 0
                                                                                     1
                                                                               0.8
                 0 0.05                                                  0.6
                        0.1 0.15                                   0.4           x
                                  0.2 0.25                  0.2
                                t          0.3 0.35
                                                    0.4 0




               Figure 8.1: The function u(x, t) for Nx=10, Nt=100, tf= 0.4.




8.4 The Program
The fact that equation (8.26) is a one time step iterative relation, leads to
a substantial simplification of the structure of the program. Because of
this, at each time step, it is sufficient to store the values of the second term
(the “second derivative”) in one array. This array will be used in order
8.4. THE PROGRAM                                                                       361

to update the values of ui,j . Therefore we will define only two arrays in
order to store the values ui,j and ∆t/(∆x)2 (ui+1,j − 2ui,j + ui−1,j ) at time
tj .
     In the program listed below, the names of these arrays are u[P] and
d2udx2[P]. Some care must be exercised because of the array indexing
in C++. The data is stored in the array positions u[0] ... u[Nx-1] and
d2udx2[0] ... d2udx2[Nx-1] and the parameter P is taken large enough
so that Nx is always smaller than P.
     The user enters the Nx = Nx, Nt =Nt and tf =tf interactively. The
values of ∆x, ∆t and ∆t/∆x2 = courant are calculated during the ini-
tialization.
     On exit, we obtain the results in the file d.dat which contains (tj , xi , ui,j )
in three columns. When a time slice is printed, the program prints an
empty line so that the output is easily read by the three dimensional
plotting function splot of gnuplot.
     The program is in the file diffusion.cpp and is listed below:

/ / =======================================================
/ / 1−dimensional D i f f u s i o n Equation with simple
/ / D i r i c h l e t boundary c o n d i t i o n s u ( 0 , t )=u ( 1 , t ) =0
/ / 0<= x <= 1 and 0<= t <= t f
//
/ / We s e t i n i t i a l c o n d i t i o n u ( x , t =0) t h a t s a t i s f i e s
/ / t h e gi ve n boundary c o n d i t i o n s .
/ / Nx i s t h e number o f p o i n t s i n s p a t i a l l a t t i c e :
/ / x = 0 + i * dx , i = 0 , . . . , Nx−1 and dx = (1 −0) / ( Nx−1)
/ / Nt i s t h e number o f p o i n t s i n temporal l a t t i c e :
/ / t = 0 + j * dt , j = 0 , . . . , Nt−1 and dt = ( t f −0) / ( Nt −1)
//
/ / u(x , 0 ) = sin ( pi * x ) t e s t e d against a n a l y t i c a l solution
/ / u ( x , t ) = s i n ( p i * x ) * exp(− p i * p i * t )
//
/ / =======================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    const int           P = 100000;
    c o n s t double PI = 2 . 0 * atan2 ( 1 . 0 , 0 . 0 ) ;
    double u [ P ] , d2udx2 [ P ] ;
    double t , x , dx , dt , tf , courant ;
362                               CHAPTER 8. DIFFUSION EQUATION

 int           Nx , Nt , i , j ;
 string buf ;
 / / Input :
 cout << ” # Enter : Nx , Nt , t f : ( P= ” << P
             << ” Nx must be < P ) ”                       << endl ;
 cin         >> Nx >> Nt >> tf ;                getline ( cin , buf ) ;
 i f ( Nx >= P ) { cerr << ”Nx >= P\n” ;                   exit ( 1 ) ; }
 i f ( Nx <= 3) { cerr << ”Nx <= 3\n” ;                    exit ( 1 ) ; }
 i f ( Nt <= 2) { cerr << ”Nx <= 2\n” ;                    exit ( 1 ) ; }
 // Initialize :
 dx           = 1 . 0 / ( Nx −1) ;
 dt           = tf / ( Nt −1) ;
 courant= dt / ( dx * dx ) ;
 cout << ” # 1d D i f f u s i o n Equation : 0<=x <=1 , 0<=t <= t f \n” ;
 cout << ” # dx= ” << dx << ” dx= ” << dt
             << ” t f = ” << tf                                  << endl ;
 cout << ” # Nx= ” << Nx << ” Nt= ” << Nt << endl ;
 cout << ” # Courant Number= ” << courant << endl ;
 i f ( courant > 0 . 5 ) cout << ” # WARNING: c o u r a n t > 0.5\n” ;
 ofstream myfile ( ”d . dat ” ) ;
 myfile . precision ( 1 7 ) ;
 / /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
 / / I n i t i a l c o n d i t i o n a t t =0
 / / u(x , 0 ) = sin ( pi x )
 f o r ( i =0;i<Nx ; i++){
     x           = i * dx ;
     u[i]        = sin ( PI * x ) ;
 }
 u [0        ] = 0.0;
 u [ Nx −1] = 0 . 0 ;
 f o r ( i =0;i<Nx ; i++){
     x           = i * dx ;
     myfile << 0.0 << ” ” << x << ” ” << u [ i ] << ’\n ’ ;
 }
 myfile          << ” \n” ;
 / /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
 / / C a l c u l a t e time e v o l u t i o n :
 f o r ( j =1; j<Nt ; j++){
     t = j * dt ;
     / / Second d e r i v a t i v e :
     f o r ( i =1; i<Nx −1;i++)
         d2udx2 [ i ] = courant * ( u [ i +1] −2.0* u [ i ]+ u [ i −1]) ;
     / / Update :
     f o r ( i =1; i<Nx −1;i++)
         u[i]            += d2udx2 [ i ] ;
     f o r ( i =0;i<Nx ; i++){
         x                = i * dx ;
         myfile << t << ” ” << x << ” ” << u [ i ] << ’\n ’ ;
     }
8.5. RESULTS                                                           363

        myfile         << ” \n” ;
    } / / f o r ( j =1; j <Nt ; j ++)
    myfile . close ( ) ;
} / / main ( )




8.5 Results
The compilation and running of the program can be done with the com-
mands:

>   g++ diffusion . cpp −o d
>   echo ” 10 100 0.4 ” | . / d
#   Enter : Nx , Nt , t f : ( P= 100000 Nx must be < P )
#   1d D i f f u s i o n Equation : 0<=x <=1 , 0<=t <= t f
#   dx= 0 . 1 1 1 1 1 1 dx= 0.0040404 t f = 0.4
#   Nx= 10 Nt= 100
#   Courant Number= 0.327273

The input to the program ./d is read from the stdin and it is given by
the stdout of the command echo through a pipe, as shown in the second
line in the listing above. The lines that follow are the standard output
stdout of the program.
    The three dimensional plot of the function u(x, t) can be made with
the gnuplot commands:

gnuplot >      s e t pm3d
gnuplot >      s e t hidden3d
gnuplot >      s p l o t ”d . dat ” with lines
gnuplot >      unset pm3d

In order to make the plot of u(x, t) for a fixed value of t we first note that
an empty line in the file d.dat marks a change in time. The following
awk program counts the empty lines of d.dat and prints only the lines
when the number of empty lines that have been encountered so far is
equal to 3. The counter n=0, 1, ..., Nt-1 determines the value of
tj = tn−1 . We save the results in the file tj which can be plotted with
gnuplot. We repeat as many times as we wish:

> awk ’NF<3{n++}n==3 { p r i n t } ’ d . dat > tj
gnuplot > p l o t ” t j ” using 2:3 with lines
364                                  CHAPTER 8. DIFFUSION EQUATION

The above task can be completed without creating the intermediate file
tj by using the awk filter within gnuplot. For example, the commands

gnuplot >    ! echo   ”10 800 2” | . / d
gnuplot >    plot     ”<awk ’NF<3{n++}n==3 { p r i n t } ’      d . dat ”   u   2:3   w   l
gnuplot >    replot   ”<awk ’NF<3{n++}n==6 { p r i n t } ’      d . dat ”   u   2:3   w   l
gnuplot >    replot   ”<awk ’NF<3{n++}n==10 { p r i n t } ’     d . dat ”   u   2:3   w   l
gnuplot >    replot   ”<awk ’NF<3{n++}n==20 { p r i n t } ’     d . dat ”   u   2:3   w   l
gnuplot >    replot   ”<awk ’NF<3{n++}n==30 { p r i n t } ’     d . dat ”   u   2:3   w   l
gnuplot >    replot   ”<awk ’NF<3{n++}n==50 { p r i n t } ’     d . dat ”   u   2:3   w   l
gnuplot >    replot   ”<awk ’NF<3{n++}n==100{ p r i n t } ’     d . dat ”   u   2:3   w   l

run the program for Nx=10, Nt=800, tf= 2 and construct the plot in
figure 8.2
            ✂
            ✁✡
            ✁✠
            ✁✟
      ✕✎
      ✔     ✁✞
      ✓✒
      ✑     ✁✝
      ✏✎
      ✍✌
      ☞☛    ✁✆
            ✁☎
            ✁✄
            ✁✂

                           ✁✄            ✁✆               ✁✞         ✁✠               ✂
                                                ✖

Figure 8.2: The function u(x, t) for Nx=10, Nt=800, tf= 2 for different values of
the time tj . We take j = 4, 7, 11, 21, 31, 51, 101 and observe that the function u(x, t)
decreases then j increases.


   It is instructive to compare the results with the known solution u(x, t) =
sin(πx)e−π t . We compute the relative error
            2




                                   ui,j − u(xi , tj )
                                                      ,
                                         ui,j
which can be done within gnuplot with the commands:
8.6. DIFFUSION ON THE CIRCLE                                                            365

gnuplot >       du ( x , y , z ) = ( z − s i n ( pi * x ) * exp(−pi * pi * y ) ) / z
gnuplot >       p l o t ”<awk ’NF<3{n++}n==2 ’ d . dat ” u 2 : ( du ( $2 , $1 , $3 ) )
gnuplot >       p l o t ”<awk ’NF<3{n++}n==6 ’ d . dat ” u 2 : ( du ( $2 , $1 , $3 ) )
gnuplot >       p l o t ”<awk ’NF<3{n++}n==20 ’ d . dat ” u 2 : ( du ( $2 , $1 , $3 ) )
gnuplot >       p l o t ”<awk ’NF<3{n++}n==200’ d . dat ” u 2 : ( du ( $2 , $1 , $3 ) )
gnuplot >       p l o t ”<awk ’NF<3{n++}n==600’ d . dat ” u 2 : ( du ( $2 , $1 , $3 ) )
gnuplot >       p l o t ”<awk ’NF<3{n++}n==780’ d . dat ” u 2 : ( du ( $2 , $1 , $3 ) )


                  ✁✂




      ☛✒         ✁ ✂
      ☛☛
      ☞
      ☞✑
      ✎✏✍
      ✌☞
      ☛
                ✁ ✂




            ✁     ✂
                       ✁✂   ✁✄      ✁☎              ✁✆      ✁✝      ✁✞   ✁✟   ✁✠   ✁✡
                                                           ✓

Figure 8.3: The absolute value of the relative error of the numerical computation
for Nx=10, Nt=800, tf= 2 for different times tj . We take j = 3, 7, 21, 201, 601, 781 and
observe that the relative error increases with j.



The results can be seen in figure 8.3.


8.6         Diffusion on the Circle
In order to study the kernel K(x, x0 ; t) for the diffusion, or random walk,
problem, we should impose the normalization condition (8.4) for all
times. In the case of the function u(x, t) defined for x ∈ [0, 1] the re-
lation becomes              ∫                1
                                                 u(x, t) dx = 1 .                  (8.29)
                                         0

In order to maintain this relation at all times, it is necessary that the
right hand side of equation (8.15) is equal to 0. One way to impose
this condition is to study the diffusion problem on the circle. If we
366                                     CHAPTER 8. DIFFUSION EQUATION

parametrize the circle using the variable x ∈ [0, 1], then the points x = 0
and x = 1 are identified and we obtain
                                                 ∂u(0, t)   ∂u(1, t)
                     u(0, t) = u(1, t) ,                  =          .        (8.30)
                                                   ∂x         ∂x
The second relation in the above equations makes the right hand side
                                                   ∫1
of equation (8.15) to vanish. Therefore if 0 u(x, 0) dx = 1, we obtain
∫1
 0
   u(x, t) dx = 1, ∀t > 0.
    Using the above assumptions, the discretization of the differential
equation is done exactly as in the problem of heat conduction. Instead
of keeping the values u(0, t) = u(1, t) = 0, we apply equation (8.26) also
for the points x1 , xNx . In order to take into account the cyclic topology
we take
                                     ∆t
                    u1,j+1 = u1,j +       (u2,j − 2u1,j + uNx ,j ) ,    (8.31)
                                    (∆x)2
and
                                    ∆t
               uNx ,j+1 = ui,j +         (u1,j − 2uNx ,j + uNx −1,j ) , (8.32)
                                   (∆x)2
since the neighbor to the right of the point xNx is the point x1 and the
neighbor to the left of the point x1 is the point xNx . For the rest of the
points i = 2, . . . , Nx − 1 equation (8.26) is applied normally.
    The program that implements the problem described above can be
found in the file diffusionS1.cpp. At a given time tj , the boundary
conditions (8.30) are enforced in the lines

      f o r ( i =0;i<Nx ; i++){
          nnr = i +1;
          i f ( nnr > Nx −1) nnr = 0 ;
          nnl = i −1;
          i f ( nnl <      0) nnl = Nx −1;
          d2udx2 [ i ] = courant * ( u [ nnr ] −2.0* u [ i ]+ u [ nnl ] ) ;
      }

    The initial conditions at t = 0 are chosen so that the particle is located
at xNx /2 . For each instant of time we perform measurements in order to
verify the equations (8.4) and (8.9) and the fact that limt→+∞ u(x, t) =
const.                     ∑ x
    The variable prob = N     i=1 ui,j and we should check that its value is
conserved and is always equal to 1.
                         ∑ x
    The variable r2 = N    i=1 (xi − xNx /2 ) ui,j is a discrete estimator of the
                                             2

expectation value of the distance squared from the initial position. For
small enough times it should follow the law given by equation (8.9).
8.6. DIFFUSION ON THE CIRCLE                                                           367

    These variables are written to the file e.dat together with the values
uNx /2,j , uNx /4,j and u1,j . The latter are measured in order to check if for
large enough times they obtain the same constant value according to the
expectation limt→+∞ u(x, t) = const.
    The full code is listed below:

/ / =======================================================
/ / 1−dimensional D i f f u s i o n Equation with
/ / p e r i o d i c boundary c o n d i t i o n s u ( 0 , t )=u ( 1 , t )
/ / 0<= x <= 1 and 0<= t <= t f
//
/ / We s e t i n i t i a l c o n d i t i o n u ( x , t =0) t h a t s a t i s f i e s
/ / t h e gi ve n boundary c o n d i t i o n s .
/ / Nx i s t h e number o f p o i n t s i n s p a t i a l l a t t i c e :
/ / x = 0 + i * dx , i = 0 , . . . , Nx−1 and dx = (1 −0) / ( Nx−1)
/ / Nt i s t h e number o f p o i n t s i n temporal l a t t i c e :
/ / t = 0 + j * dt , j = 0 , . . . , Nt−1 and dt = ( t f −0) / ( Nt −1)
//
/ / u ( x , 0 ) = \ d e l t a _ {x , 0 . 5 }
//
/ / =======================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    const int             P = 100000;
    c o n s t double PI = 2 . 0 * atan2 ( 1 . 0 , 0 . 0 ) ;
    double u [ P ] , d2udx2 [ P ] ;
    double t , x , dx , dt , tf , courant ;
    double prob , r2 , x0 ;
    int         Nx , Nt , i , j , nnl , nnr ;
    string buf ;
    / / Input :
    cout << ” # Enter : Nx , Nt , t f : ( P= ” << P
               << ” Nx must be < P ) ”                        << endl ;
    cin        >> Nx >> Nt >> tf ;               getline ( cin , buf ) ;
    i f ( Nx >= P ) { cerr << ”Nx >= P\n” ;                    exit ( 1 ) ; }
    i f ( Nx <= 3) { cerr << ”Nx <= 3\n” ;                     exit ( 1 ) ; }
    i f ( Nt <= 2) { cerr << ”Nx <= 2\n” ;                     exit ( 1 ) ; }
    // Initialize :
    dx          = 1 . 0 / ( Nx −1) ;
    dt          = tf / ( Nt −1) ;
    courant= dt / ( dx * dx ) ;
368                                   CHAPTER 8. DIFFUSION EQUATION

 cout        << ” # 1d D i f f u s i o n Equation : 0<=x <=1 , 0<=t <= t f \n” ;
 cout        << ” # dx= ” << dx << ” dx= ” << dt
             << ” t f = ” << tf                                          << endl ;
 cout << ” # Nx= ” << Nx << ” Nt= ” << Nt << endl ;
 cout << ” # Courant Number= ” << courant << endl ;
 i f ( courant > 0 . 5 ) cout << ” # WARNING: c o u r a n t > 0.5\n” ;
 ofstream myfile ( ”d . dat ” ) ;
 myfile . precision ( 1 7 ) ;
 ofstream efile ( ” e . dat ” ) ;
 efile . precision ( 1 7 ) ;
 / /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
 / / I n i t i a l c o n d i t i o n a t t =0
 f o r ( i =0;i<Nx ; i++){
     x            = i * dx ;
     u[i]         = 0.0;
 }
 u [ Nx /2 −1] = 1 . 0 ;
 f o r ( i =0;i<Nx ; i++){
     x           = i * dx ;
     myfile << 0.0 << ” ” << x << ” ” << u [ i ] << ’\n ’ ;
 }
 myfile          << ” \n” ;
 / /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
 / / C a l c u l a t e time e v o l u t i o n :
 f o r ( j =1; j<Nt ; j++){
     t = j * dt ;
     / / Second d e r i v a t i v e :
     f o r ( i =0;i<Nx ; i++){
         nnr = i +1;
         i f ( nnr > Nx −1) nnr = 0 ;
         nnl = i −1;
         i f ( nnl <          0) nnl = Nx −1;
         d2udx2 [ i ] = courant * ( u [ nnr ] −2.0* u [ i ]+ u [ nnl ] ) ;
     }
     / / Update :
     prob = 0 . 0 ;
     r2        = 0.0;
     x0        = ( ( Nx / 2 ) −1) * dx ; / / o r i g i n a l p o s i t i o n
     f o r ( i =0;i<Nx ; i++){
         x        = i * dx ;
         u [ i ] += d2udx2 [ i ] ;
         prob += u [ i ] ;
         r2      += u [ i ] * ( x−x0 ) * ( x−x0 ) ;
     }
     f o r ( i =0;i<Nx ; i++){
         x                = i * dx ;
         myfile << t << ” ” << x << ” ” << u [ i ] << ’\n ’ ;
     }
     myfile          << ” \n” ;
8.7. ANALYSIS                                                                     369

      efile            << ”pu ”
                       << t               <<   ” ” << prob          << ” ”
                       << r2              <<   ” ”
                       << u [ Nx /2 −1]   <<   ” ” << u [ Nx /4 −1] << ” ”
                       << u [ 0 ]         <<   ’\n ’ ;
    } / / f o r ( j =1; j <Nt ; j ++)
    myfile . close ( ) ;
    efile . close ( ) ;
} / / main ( )




8.7       Analysis
For each moment of time, the program writes the following quantities to
the file e.dat:
                                  ∑
                                  Nx
                             Uj =    ui,j                       (8.33)
                                                   i=1

which is an estimator of (8.29) and we expect to obtain Uj = 1 for all j,

                                           ∑
                                           Nx
                                ⟨r ⟩j =
                                   2
                                                 ui,j (xi − xNx /2 )2          (8.34)
                                           i=1


which is an estimator of (8.9) for which we expect to obtain

                                           ⟨r2 ⟩j ∼ 2tj ,                      (8.35)

for small times as well as the values of uNx /2,j , uNx /4,j , u1,j .
    The values of tj , Uj , ⟨r2 ⟩j , uNx /2,j , uNx /4,j , u1,j are found in columns 2,
3, 4, 5, 6 and 7 respectively of the file e.dat. The gnuplot commands

gnuplot > ! g++ diffusionS1 . cpp −o d
gnuplot > ! echo ” 10 100 0.4 ” | . / d

compile and run the program within gnuplot. They set Nx = 10, Nt =
100, tf = 0.4, ∆x ≈ 0.111, ∆t ≈ 4.0404, ∆t/∆x2 ≈ 0.327. The gnuplot
commands

gnuplot > p l o t     ” e . dat ” u 2:5 w l
gnuplot > r e p l o t ” e . dat ” u 2:6 w l
gnuplot > r e p l o t ” e . dat ” u 2 : 7 w l
370                                          CHAPTER 8. DIFFUSION EQUATION

       ✁✝✂                                                                          ✠✡☛☞✌✂
                                                                                    ✠✡☛☞✌✄
                                                                                       ✠✡✝
        ✁✝

       ✁ ✆

       ✁ ☎

       ✁ ✄

       ✁ ✂



                      ✁ ✞        ✁✝         ✁✝✞        ✁✂        ✁✂✞           ✁✟        ✁✟✞   ✁✄

Figure 8.4: The functions uNx /2,j , uNx /4,j , u1,j are given as a function of tj for
Nx = 10, Nt = 100, tf = 0.4. We observe that for large times they are consistent with
uniform diffusion.



construct the plot in figure 8.4. We observe that for large times we obtain
uniform diffusion.
   The relation Uj = 1 can be easily confirmed by inspecting the values
recorded in the file e.dat.
   The asymptotic relation ⟨r2 ⟩j ∼ 2tj can be confirmed with the com-
mands

gnuplot > p l o t [ : ] [ : 0 . 1 1 ] ” e . dat ” u 2 : 4 , 2 * x

which construct the plot in figure 8.5.
  Finally we make a plot of the function u(x, t) with the commands

gnuplot >     ! echo ” 10 100 0.16 ” | . / d
gnuplot >     s e t pm3d
gnuplot >     s p l o t [ 0 : 0 . 1 6 ] [ 0 : 1 ] [ 0 : 1 ] ”d . dat ” w l
gnuplot >     s p l o t [ 0 : 0 . 1 6 ] [ 0 : 1 ] [ 0 : . 2 ] ”d . dat ” w l

and the result is shown in figure 8.6.
8.7. ANALYSIS                                                                             371




        ✁✝


      ✁ ✆


      ✁ ☎


      ✁ ✄


      ✁ ✂

                                                                   ✠✡☛☞✌✍✎✏
                                                                       ✂✍
                    ✁ ✞       ✁✝      ✁✝✞       ✁✂       ✁✂✞      ✁✟       ✁✟✞       ✁✄

Figure 8.5: The expectation value ⟨r2 ⟩j as a function of tj for Nx = 10, Nt = 100,
tf = 0.4. For small values of tj we obtain ⟨r2 ⟩j ≈ 2tj . The solid line is the straight line
2t.
372                                                       CHAPTER 8. DIFFUSION EQUATION




                                                                                                         ✝
        ✝                                                                                                    ✁✆
       ✁✆                                                                                                    ✁☎
       ✁☎
                                                                                                             ✁✄
       ✁✄
       ✁✂                                                                                                    ✁✂


                                                                                                     ✝
                ✁ ✂ ✁ ✄                                                                         ✁✆
                        ✁ ☎ ✁ ✆                                                           ✁☎
                                                                                  ✁✄
                                            ✁✝ ✁✝✂                         ✁✂
                                                   ✁✝✄ ✁✝☎
                                                                                                         ✆✂✝
                                                                                                         ✆✂✡✠
       ✆✂✝                                                                                               ✆✂✡✟
                                                                                                         ✆✂✡✞
      ✆✂✡☛                                                                                               ✆✂✡✝
                                                                                                         ✆✂✡
       ✆✂✡                                                                                               ✆✂✆✠
                                                                                                         ✆✂✆✟
      ✆✂✆☛                                                                                               ✆✂✆✞
                                                                                                         ✆✂✆✝
        ✆                                                                                                ✆


                                                                                                     ✡
            ✆                                                                                  ✆✂✠
                ✆✂✆✝                                                                     ✆✂✟
                       ✆✂✆✞
                              ✆✂✆✟                                               ✆✂✞
                                     ✆✂✆✠
                                            ✆✂✡                            ✆✂✝
                                                  ✆✂✡✝                                 ✁✂✁✄☎
                                                         ✆✂✡✞          ✆
                                                                ✆✂✡✟

Figure 8.6: The function u(x, t) for Nx = 10, Nt = 100, tf = 0.16. The second plot
differs only in the scale of the z axis so that we can easily see the details of the diffusion
away from the point x0 ≡ xNx /2 = x5 .
8.8. PROBLEMS                                                          373

8.8 Problems
8.1 Reproduce the results in figure 8.3.
8.2 The temperature distribution u(x, t) in a thin rod satisfies equation
    (8.14) together with the boundary conditions (8.13) at the ends
    x = 0, 1. The initial temperature distribution at t = 0 is given by
    the function                 {
                                   0.5 x ∈ [x1 , x2 ]
                       u(x, 0) =                       ,
                                   0.3 x ∈/ [x1 , x2 ]
    where x1 = 0.25 and x2 = 0.75.
     (a) Calculate the temperature distribution u(x, tf ) for tf = 0.0001,
         0.001, 0.01, 0.05. Take Nx = 100 and Nt = 1000. Do the same
         for tf = 0.1 by choosing appropriate Nx and keeping Nt = 1000.
         Plot the functions u(x, tf ) in the same plot.
     (b) Calculate the maximum value of the temperature graphically
         for tf = 0.0001, 0.001, 0.01, 0.05, 0.1, 0.15, 0.25. Take Nx = 100
         and choose an appropriate value for the corresponding Nt .
     (c) Calculate the time at which the temperature of the rod becomes
         everywhere less than 0.1.
    Hint: Make your program print only the final temperature distri-
    bution u(x, tf ).
8.3 The temperature distribution u(x, t) in a thin rod satisfies the equa-
    tion
                                ∂u     ∂ 2u
                                   =α 2.
                                ∂t     ∂x
    The temperature at the ends of the rod is u(0, t) = u(1, t) = 0, and
    when t = 0
                         {     [        ( )]
                           0.5 1 − cos 2πxb
                                                 0≤x<b
               u(x, 0) =                                    .
                           0                     b≤x≤1
     (a) Calculate the temperature distribution u(x, tf ) for α = 0.5, b =
         0.09 and for tf = 0.0001, 0.001, 0.01, by taking Nx = 300, Nt =
         1000. Do the same for tf = 0.05 by choosing appropriate Nx .
         Plot the functions u(x, tf ) in the same plot.
     (b) Using the same parameters, calculate the time evolution of the
         values of the temperature distribution at the points x1 = 0.05,
         x2 = 0.50 and x3 = 0.95 for 0 ≤ t ≤ 0.05. Plot the functions
         u(x1,2,3 , t) in the same plot.
374                              CHAPTER 8. DIFFUSION EQUATION

      (c) Calculate the temperature distribution u(x, tf ) for b = 0.09 and
          α = 5, 2, 1 for tf = 0.001. Plot the functions u(x, tf ) in the
          same plot. Comment on the effect of the parameter α on your
          results.

 8.4 The temperature distribution u(x, t) in a thin rod of length L satisfies
     equation
                         ∂u         ∂2u     4      ∂u
                             = D(x) 2 − D(x) ,
                          ∂t        ∂x      L      ∂x
     where D(x) = ae−4x/L is the x-dependent thermal diffusivity. The
     temperature of the rod at its ends is such that u(0, t) = u(L, t) = 0,
     and at time t = 0, the temperature distribution is

                             u(x, 0) = Ce−(x−L/2)
                                                  2 /σ 2
                                                           .

      (a) Write a program where the user enters the parameters L, a, C,
          σ, Nx , Nt and tf interactively. On exit, the program calculates
          u(x, tf ) and writes the points (xi , u(xi , tf )) in two columns to a
          file d.dat.
      (b) Run the program for L = 4, a = 0.2, C = 1, σ = 1/2, Nx = 400,
          Nt = 20000 and calculate u(x, tf ) for tf = 0.05, 1.0, 5.0. Plot the
          functions u(x, tf ) in the same plot.
      (c) Using the same parameters, calculate the time evolution of the
          temperature distribution at the points x1 = 1 and x2 = 2 for
          0 ≤ t ≤ 5. Plot the functions u(x1,2 , t) in the same plot.

 8.5 Reproduce the results shown in figures 8.4 and 8.5.
Chapter 9

The Anharmonic Oscillator

In this chapter we will use matrix methods in order to compute the
quantum mechanical energy spectrum of the anharmonic oscillator. This
problem cannot be solved exactly and one has to resort to perturbative or
other approximation methods. We will approach this problem numeri-
cally by representing the Hamiltonian H as a real symmetric matrix in an
appropriately chosen basis of the Hilbert space H of quantum mechani-
cal states. The energy spectrum is obtained from the eigenvalues of this
matrix and the numerical problem reduces to that of the diagonalization
of a real symmetric matrix. Since the Hamiltonian is represented in H
by an infinite size matrix, we have to restrict ourselves to a finite dimen-
sional subspace HN of dimension N . In this space the Hamiltonian is
represented by an N × N real symmetric matrix. The eigenvalues of this
matrix will be calculated numerically using standard methods and the
energy eigenvalues will be obtained in the N → ∞ limit.
    For the calculation of the eigenvalues we will use software that is
found in the well known library Lapack which contains high quality,
freely available, linear algebra software. Part of the goals of this chapter
is to show to the reader how to link her programs with software libraries.
In order to solve the same problem using Mathematica or Matlab see [42]
and [43] respectively.


9.1     Introduction
The Hamiltonian of the harmonic oscillator is given by

                                  p2  1
                           H0 =      + mω 2 x2 .                       (9.1)
                                  2m 2

                                    375
376                  CHAPTER 9. THE ANHARMONIC OSCILLATOR
                                              √              √
Define the position and momentum scales x0 = ℏ/(mω), p0 = ℏmω so
that we can express the above equation using dimensionless terms:
                                 (        )2         (        )2
                        H0   1       p           1       x
                           =                   +                   .    (9.2)
                        ℏω   2       p0          2       x0

If we take the units of energy, distance and momentum to be ℏω, x0 and
p0 , then we obtain
                                   1      1
                             H0 = p2 + x2 ,                       (9.3)
                                   2      2
where H0 , p and x are now dimensionless. The operator H0 can be
diagonalized with the help of the creation and annihilation operators a
and a† , defined by the relations:

                       1                            i
                   x = √ (a† + a)              p = √ (a† − a) ,         (9.4)
                        2                             2
or
                     1                  1
                 a = √ (x + ip)    a† = √ (x − ip) ,                    (9.5)
                      2                  2
which obey the commutation relation

                                 [a, a† ] = 1 ,                         (9.6)

which leads to
                                              1
                               H0 = a† a +      .                        (9.7)
                                              2
The eigenstates |n⟩, n = 0, 1, 2, . . . of H0 span the Hilbert space of states
H and satisfy the relations
             √                              √
    a† |n⟩ = n + 1 |n + 1⟩        a |n⟩ = n |n − 1⟩       a |0⟩ = 0 ,    (9.8)

therefore
                              a† a |n⟩ = n |n⟩ ,                        (9.9)
and
                                                   1
                     H0 |n⟩ = En |n⟩ ,           En = n +
                                                      .            (9.10)
                                                   2
The position representation of the eigenstates |n⟩ is given by the wave-
functions:
                                      1
                                           e−x /2 Hn (x) ,
                                              2
                ψn (x) = ⟨x|n⟩ = √      √                          (9.11)
                                   2n n! π
where Hn (x) are the Hermite polynomials.
9.2. CALCULATION OF THE EIGENVALUES OF HN M (λ)                               377

   From equations (9.4) and (9.8) we obtain
                            1 √                    1 √
         xnm = ⟨n| x |m⟩ = √ m + 1 δn,m+1 + √ m δn,m−1                      (9.12)
                              2                     2
                           1 √
                         =      n + m + 1 δ|n−m|,1                          (9.13)
                           2
                             i √                   i √
         pnm = ⟨n| p |m⟩ = √ m + 1 δn,m+1 − √ m δn,m−1 .                    (9.14)
                              2                     2
   From the above equations we can easily calculate the Hamiltonian of
the anharmonic oscillator

                             H(λ) = H0 + λx4 .                              (9.15)

The matrix elements of H in this representation are:

           Hnm (λ) ≡ ⟨n| H(λ) |m⟩ = ⟨n| H0 |m⟩ + λ⟨n| x4 |m⟩                (9.16)
                                         1
                                  = (n + )δn,m + λ(x4 )nm                   (9.17)
                                         2
where (x4 )nm can be calculated from equation (9.12):
                                  ∑
                                  ∞
                       4
                    (x )nm =                   xni1 xi1 i2 xi2 i3 xi3 m .   (9.18)
                               i1 ,i2 ,i3 =0


This relation computes the matrix elements of the matrix x4 from the
matrix product of x with itself.
   The problem of the calculation of the energy spectrum has now been
reduced to the problem of calculating the eigenvalues of the matrix Hnm .


9.2     Calculation of the Eigenvalues of Hnm(λ)
We start by choosing the dimension N of the subspace HN of the Hilbert
space of states H. We will restrict ourselves to states within this subspace
and we will use the N dimensional representation matrices of x, H0 and
H(λ) in HN . For example, when N = 4 we obtain
                                                  
                               0 √12 0         0
                            √1                0 
                            2 0         1
                                              √    
                      x=   0 1         0
                                                   
                                                 3                    (9.19)
                                       √        2 
                                           3
                               0 0         2
                                               0
378                   CHAPTER 9. THE ANHARMONIC OSCILLATOR

                                             1
                                                
                                         0 0 02
                                      0 3 0 0 
                                H0 =    2
                                      0 0 5 0 
                                                                                    (9.20)
                                           2
                                       0 0 0 27
                           1        3λ                   3λ
                                                          √
                                                                                 
                                +                 0                    0
                            2         4                     2         √
                                                                                
                               0         3
                                           + 15λ           0      3        3
                                                                             λ   
               H(λ) =                                                           
                                          2    4                           2
                               3λ                    5                             (9.21)
                      
                                √           0             + 27λ        0         
                                 2         √          2      4

                                0         3 32 λ           0      7
                                                                  2
                                                                      +    15λ
                                                                            4

    Our goal is to write a program that calculates the eigenvalues En (N, λ)
of the N × N matrix Hnm (λ). Instead of reinventing the wheel, we will
use ready made routines that calculate eigenvalues and eigenvectors of
matrices found in the Lapack library. This library can be found in the
high quality numerical software repository Netlib and more specifically
at http://www.netlib.org/lapack/. Documentation can be found at
http://www.netlib.org/lapack/lug/, but it is also easily accessible on-
line by a Google search or by using the man pages¹. The programs have
been written in the Fortran programming language, therefore the reader
should review the discussion in Section 6.1.2.
    As inexperienced users we will first look for driver routines that per-
form a diagonalization process. Since our task is to diagonalize a real
symmetric matrix, we pick the subroutine² DSYEV (D = double precision,
SY = symmetric, EV = eigenvalues with optional eigenvectors). If the
documentation of the library is installed in our system, we may use the
Linux man pages for accessing it:³

> man dsyev

   From this page we learn how to use this subroutine:

SUBROUTINE DSYEV ( JOBZ , UPLO , N , A , LDA , W , WORK , LWORK , INFO )
 CHARACTER     JOBZ , UPLO
 INTEGER       INFO , LDA , LWORK , N
 DOUBLE        PRECISION A ( LDA , * ) , W ( * ) , WORK ( * )

   ¹The library can be easily installed in many Linux distributions. For example in
Ubuntu or other Debian like systems you may use the command apt-get install
liblapack3 liblapack-doc liblapack-dev.
   ²A function of type void in Fortran, is called a subroutine.
   ³A Google search “dsyev” will easily take you to the same page.
9.2. CALCULATION OF THE EIGENVALUES OF HN M (λ)                         379


ARGUMENTS
 JOBZ ( input ) CHARACTER * 1
       = ’ N ’ : Compute eigenvalues only ;
       = ’ V ’ : Compute eigenvalues and eigenvectors .

 UPLO      ( input ) CHARACTER * 1
           = ’ U ’ : Upper triangle of A is stored ;
           = ’ L ’ : Lower triangle of A is stored .

 N         ( input ) INTEGER
           The order of the matrix A .    N >= 0 .

 A         ( input / output ) DOUBLE PRECISION array , dimension ( LDA , N←-
       )
           On entry , the symmetric matrix A . If UPLO = ’ U ’ , the
           leading N−by−N upper triangular part of A contains the
           upper triangular part of the matrix A . If UPLO = ’ L ’ ,
           the leading N−by−N lower triangular part of A contains
           the lower triangular part of the matrix A . On exit , if
           JOBZ = ’ V ’ , then if INFO = 0 , A contains
           the orthonormal eigenvectors of the matrix A . If
           JOBZ = ’ N ’ , then on exit the lower triangle ( if UPLO = ’L←-
                ’)
           or the upper triangle ( if UPLO = ’U ’ ) of A , including the
           diagonal , is destroyed .
 LDA       ( input ) INTEGER
           The leading dimension of the array A . LDA >= max ( 1 , N ) .

 W         ( output ) DOUBLE PRECISION array , dimension ( N )
           If INFO = 0 , the eigenvalues in ascending order .

 WORK      ( workspace / output ) DOUBLE PRECISION array , dimension
           ( LWORK ) .
           On exit , if INFO = 0 , WORK ( 1 ) returns the optimal LWORK .

 LWORK ( input ) INTEGER
       The length of the array WORK . LWORK >= max ( 1 , 3 * N←-
           −1) .
       For optimal efficiency , LWORK >= ( NB +2) * N , where NB is
       the blocksize for DSYTRD returned by ILAENV .

           If LWORK = −1 , then a workspace query is assumed ; the
           routine only calculates the optimal size of the WORK
           array , returns this value as the first entry of the
           WORK array , and no error message related to LWORK is
           issued by XERBLA .

 INFO      ( output ) INTEGER
380                  CHAPTER 9. THE ANHARMONIC OSCILLATOR

        = 0 : successful exit
        < 0 : if INFO = −i , the i−th argument had an illegal ←-
            value
        > 0 : if INFO = i , the algorithm failed to converge ; ←-
            i
        off−diagonal elements of an intermediate tridiagonal
        form did not converge to zero .

These originally cryptic pages contain all the necessary information and
the reader should familiarize herself with its format. For a quick and
dirty use of the routine, all we need to know is the types and usage of its
arguments. These are classified as “input”, “output” and “working space”
variables (some are in more than one classes). Input is the necessary data
that the routine needs in order to perform the computation. Output is
where the results of the computation are stored. And working space
is the memory provided by the user to the routine in order to store
intermediate results.
    From the information above we learn that the matrix to be diagonal-
ized is A which is a rectangular matrix with the number of its rows and
columns ≤ N . The number of rows LDA (LDA= “leading dimension of
A”) can be larger than N is which case DSYEV will diagonalize the upper
left N×N part of the matrix⁴. In our program we define a large matrix
A[LDA][LDA] and diagonalize a smaller submatrix A[N][N]. This way we
can study many values of N using the same matrix. The subroutine can
be used in two ways:

   • If JOBZ='N', it calculates only the eigenvalues of the matrix A[N][N]
     and stores them in the array W[N], sorted in ascending order. We
     have to be careful because, upon return, the routine destroys the
     lower (UPLO='U') or upper (UPLO='L') triangular part of A. Be careful:
     the documentation says the opposite, but I hope that you remember
     from the discussion in Section 6.1.2 that Fortran arrays are trans-
     posed from the point of view of C++! Since A is symmetric, only
     this part is needed by DSYEV. If we need to reuse the matrix A, we
     have to make a backup copy before the call to DSYEV.

   • If JOBZ='V', it calculates both the eigenvalues and the eigenvectors
     of the matrix A[N][N]. The eigenvalues are stored in the array W[N]
     as before, whereas the corresponding eigenvectors in the columns
     of the matrix A[N][N]. The eigenvectors are stored in the rows of

   ⁴The number LDA is necessary because the matrix element A(i,j) is found after
i+(LDA-1)*j memory positions from A(1,1).
9.2. CALCULATION OF THE EIGENVALUES OF HN M (λ)                          381

     A[N][N], i.e. the n-th eigenvector corresponding to the eigenvalue
     λn =W[n-1] is v=A[n-1]. The eigenvectors are normalized to unity,
          ∑N −1
     i.e.   m=0 v[m]*v[m]= 1. The matrix A[N][N] is destroyed after the
     call to DSYEV and if we need it we have to make a backup copy
     before the call.

The reader should also familiarize herself with the use of the workspace
array WORK. This is memory space given to the routine for all its interme-
diate calculations. Determining the size of this array needs some care.
This is given by LWORK and if performance is an issue the reader should
read the documentation carefully for its optimal determination. We will
make the simple choice LWORK=3*LDA-1. The variable INFO is used as a
flag which informs the user whether the calculation was successful, in
which case its value is set to 0. In our case, if INFO takes a non zero
value, the program will abort the calculation.
    Before using the program in a complicated calculation, it is necessary
to test its use in a simple, easily controlled problem. We will familiarize
ourselves with the use of DSYEV by writing the following program:

# include   < iostream >
# include   < fstream >
# include   <cstdlib >
# include   <string >
# include   <cmath>

using namespace std ;

/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
const int P                = 100; / / P=LDA
c o n s t i n t LWORK = 3* P −1;
double A [ P ] [ P ] , W [ P ] , WORK [ LWORK ] ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
e x t e r n ”C” void
dsyev_ ( c o n s t char& JOBZ , c o n s t char& UPLO ,
            const in t &               N,
            double          A [ P ] [ P ] , c o n s t i n t & LDA ,
            double          W       [P] ,
            double          WORK [ P ] ,
            c o n s t i n t & LWORK ,                 i n t & INFO ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    int        N;
    int        i ,j;
    int        LDA , INFO ;
    char       JOBZ , UPLO ;
382                         CHAPTER 9. THE ANHARMONIC OSCILLATOR

   string buf ;
   / / D e f i n e t h e * * symmetric * * ma tr ix t o be d i a g o n a l i z e d
   / / The s u b r o u t i n e us es t h e upper t r i a n g u l a r p a r t
   / / (UPLO= ’U ’ ) i n t h e *FORTRAN* column−major mode ,
   / / t h e r e f o r e i n C++ , we need t o d e f i n e i t s * lower *
   / / triangular part !
   N = 4 ; / / an N x N mat r ix
   A [0][0]= −7.7;
   A [1][0]= 2.1; A [1][1]= 8.3;
   A [2][0]= −3.7; A [2][1]= −16.; A [2][2]= −12.;
   A [3][0]= 4 . 4 ; A [3][1]= 4.6; A [3][2]= −1.04; A [3][3]= −3.7;

    / / We p r i n t t h e matrix A b e f o r e c a l l i n g DSYEV s i n c e
    / / i t i s destroyed a f t e r the c a l l .
    f o r ( i =0;i<N ; i++)
        f o r ( j =0;j<=i ; j++)
            cout << ”A( ”               << i+1 << ” , ” << j+1 << ” )=”
                     << A [ i ] [ j ] << endl ;
    / / We ask f o r e i g e n v a l u e s AND e i g e n v e c t o r s ( JOBZ= ’V ’ )
    JOBZ= ’V ’ ; UPLO= ’U’ ;
    cout << ”COMPUTING WITH DSYEV: ”                             << endl ;
    / / LDA: Leading dimension o f A = number o f rows o f
    / / f u l l array
    LDA = P ;
    dsyev_ ( JOBZ , UPLO , N , A , LDA , W , WORK , LWORK , INFO ) ;
    cout << ”DSYEV: DONE. CHECKING NOW: ” << endl ;
    i f ( INFO != 0) { cerr << ”DSYEV f a i l e d . INFO= ”
                                      << INFO << endl ; exit ( 1 ) ; }
    / / P r i n t r e s u l t s : W( I ) has t h e e i g e n v a l u e s :
    cout << ”DSYEV: DONE . : ”                                   << endl ;
    cout << ”EIGENVALUES OF MATRIX: ”                            << endl ;
    cout . precision ( 1 7 ) ;
    f o r ( i =0;i<N ; i++)
        cout << ”LAMBDA( ”<< i+1
                 << ” )=”             << W [ i ]                 << endl ;
    / / E i g e n v e c t o r s a r e i n s t o r e d i n t h e rows o f A:
    cout << ”EIGENVECTORS OF MATRIX: ”                           << endl ;
    f o r ( i =0;i<N ; i++){
        cout << ”EIGENVECTOR ”                        << i+1
                 << ” FOR EIGENVALUE ” << W [ i ] << endl ;
        f o r ( j =0;j<N ; j++)
            cout << ”V_” << i+1                       << ” ( ” << j+1
                     << ” )= ” << A [ i ] [ j ]                  << endl ;
    }
} / / main ( )


   The next step is to compile and link the program. In order to link
the program to Lapack we have to instruct the linker ld where to find the
9.2. CALCULATION OF THE EIGENVALUES OF HN M (λ)                                   383

libraries Lapack and BLAS⁵ and link them to our program. A library
contains compiled software in archives of object files. The convention for
their names in a Unix environment is to start with the string “lib” fol-
lowed by the name of the library and a .a or .so extension. For example,
in our case the files we are interested in have the names liblapack.so and
libblas.so which can be searched in the file system by the commands:

> l o c a t e libblas
> l o c a t e liblapack

In order to see the files that they contain we give the commands⁶:

> ar −t / usr / lib / libblas . so
> ar −t / usr / lib / liblapack . so

In the commands shown above you may have to substitute /usr/lib
with the path appropriate for your system. If the program is in the file
test.cpp, the compilation/linking command is:

> g++ test . cpp −o test −L / usr / lib −llapack −lblas

The option -L/usr/lib instructs the linker to look for libraries in the
/usr/lib directory⁷, whereas the options -llapack -lblas instructs the
linker to look for any unresolved symbols (i.e. names of external func-
tions and subroutines not coded in our program) first in the library
liblapack.a and then in the library libblas.a.
    The command shown above produces the executable file test which,
when run, produces the result:

EIGENVALUES OF MATRIX :
LAMBDA ( 1 ) =−21.411990695806409
LAMBDA ( 2 ) =−9.9339436575643028
LAMBDA ( 3 ) =−2.5576560809720039
LAMBDA ( 4 )= 18.803590434342716
EIGENVECTORS OF MATRIX :
EIGENVECTOR 1 FOR EIGENVALUE −21.411990695806409

    ⁵The library BLAS contains the basic linear algebra subroutines used by Lapack. In
some versions of the library, one has to only link to Lapack ignoring the link BLAS but
in some other version, linking to BLAS is necessary.
    ⁶If the .so files don’t exist in your system, try ar -t /usr/lib/libblas.a etc.
    ⁷This is not necessary in our case, since /usr/lib is in the path that ld searches
anyway. This option is useful for libraries located in non conventional paths.
384                   CHAPTER 9. THE ANHARMONIC OSCILLATOR

V _ 1 ( 1 ) = −0.19784566233322534
V _ 1 ( 2 )= −0.4647986784623277
V _ 1 ( 3 )= −0.85469100929950759
V _ 1 ( 4 )=   0.1196769026094445
EIGENVECTOR 2 FOR EIGENVALUE −9.9339436575643028
V _ 2 ( 1 )=   0.82441241087467854
V _ 2 ( 2 )= −0.13242939824916203
V _ 2 ( 3 )= −0.19107651157591365
V _ 2 ( 4 )= −0.51603914386327754
EIGENVECTOR 3 FOR EIGENVALUE −2.5576560809720039
V _ 3 ( 1 )=   0.50268419698022238
V _ 3 ( 2 )= −0.24778437244453691
V _ 3 ( 3 )=   0.13285333709059657
V _ 3 ( 4 )=   0.81747262565942114
EIGENVECTOR 4 FOR EIGENVALUE 18.803590434342716
V _ 4 ( 1 )=   0.16884865648881003
V _ 4 ( 2 )=   0.83965918547426488
V _ 4 ( 3 )= −0.46405068276047351
V _ 4 ( 4 )=   0.22609632301334964

We are now ready to tackle the problem of computing the energy spec-
trum of the anharmonic oscillator. The main program contains the user
interface where the basic parameters for the calculation are read from the
stdin. The user can specify the dimension DIM ≡ N of HN and the cou-
pling constant λ. Then the program computes the eigenvalues En (N, λ)
of the N × N matrix Hnm (λ), which represents the action of the operator
H(λ) in the { |n⟩}n=0,1,...,N −1 representation in HN . The tasks are allocated
to the subroutines calculate_X4, calculate_evs and calculate_H. The
subroutine calculate_X4 calculates the N × N matrix (x4 )nm . First, the
matrix xnm is calculated and then (x4 )nm is obtained by computing its
fourth power. The matrix (x4 )nm can also be calculated analytically and
this is left as an exercise to the reader. The subroutine calculate_H calcu-
lates the matrix Hnm (λ) using the result for (x4 )nm given by calculate_X4.
Finally the eigenvalues are calculated in the subroutine calculate_evs
by a call to DSYEV, which are returned to the main program for printing
to the stdout. The program is listed below and can be found in the file
anharmonic.cpp:

# include   < iostream >
# include   < fstream >
# include   <cstdlib >
# include   <string >
# include   <cmath>

using namespace std ;
9.2. CALCULATION OF THE EIGENVALUES OF HN M (λ)                               385


/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
const int P                 = 1000; / / P=LDA
c o n s t i n t LWORK = 3* P −1;
int            DIM ;
double         H [ P ] [ P ] , X [ P ] [ P ] , X4 [ P ] [ P ] ;
double         E [ P ] , WORK [ LWORK ] ;
double          lambda ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
e x t e r n ”C” void
dsyev_ ( c o n s t char& JOBZ , c o n s t char& UPLO ,
            const in t &                 N,
            double            H [ P ] [ P ] , c o n s t i n t & LDA ,
            double            E       [P] ,
            double            WORK [ P ] ,
            c o n s t i n t & LWORK ,                   i n t & INFO ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void calculate_X4 ( ) ;
void calculate_evs ( ) ;
void calculate_H ( ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    string buf ;

  cout   <<   ” # Enter H i l b e r t Space dimension : \ n” ;
  cin    >>   DIM ;                                 getline ( cin , buf ) ;
  cout   <<   ” # Enter lambda : \ n” ;
  cin    >>   lambda ;                              getline ( cin , buf ) ;
  cout   <<   ” # lambda= ” << lambda                          << endl ;
  cout   <<   ” # ########################################\n” ;
  cout   <<   ” # Energy spectrum o f anharmonic o s c i l l a t o r \n” ;
  cout   <<   ” # using matrix methods . \ n” ;
  cout   <<   ” # H i l b e r t Space Dimension DIM = ”<<DIM<< endl ;
  cout   <<   ” # lambda c o u p l i n g = ” << lambda         << endl ;
  cout   <<   ” # ########################################\n” ;
  cout   <<   ” # Output : DIM lambda E_0 E_1 . . . . E_{N−1} \n” ;
  cout   <<   ” # −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\n” ;

    cout . precision ( 1 5 ) ;
    / / C a l c u l a t e X^4 o p e r a t o r :
    calculate_X4 ( ) ;
    / / Calculate eigenvalues :
    calculate_evs ( ) ;
    cout . precision ( 1 7 ) ;
    cout << ”EV ” << DIM << ” ” << lambda << ” ” ;
    f o r ( i n t n =0;n<DIM ; n++) cout << E [ n ] << ” ” ;
    cout << endl ;
} / / main ( )
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
386                          CHAPTER 9. THE ANHARMONIC OSCILLATOR

void calculate_evs ( ) {
  i n t INFO ;
  c o n s t char JOBZ= ’V ’ , UPLO= ’U’ ;

    calculate_H ( ) ;
    dsyev_ ( JOBZ , UPLO , DIM , H , P , E , WORK , LWORK , INFO ) ;
    i f ( INFO != 0) {
        cerr << ” dsyev f a i l e d . INFO= ” << INFO << endl ;
        exit ( 1 ) ;
    }
    cout << ” # * * * * * * * * * * * * * * * * * EVEC * * * * * * * * * * * * * * * * * \ n” ;
    f o r ( i n t n =0;n<DIM ; n++){
        cout         << ” # EVEC ” << lambda << ” ” ;
        f o r ( i n t m =0;m<DIM ; m++)
            cout << H [ n ] [ m ]     << ” ” ;
        cout         <<                     ’\n ’ ;
    }
} / / calculate_evs ()
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void calculate_H ( ) {
    double X2 [ P ] [ P ] ;

   f o r ( i n t n =0;n<DIM ; n++){
       f o r ( i n t m =0;m<DIM ; m++)
           H [ n ] [ m ] = lambda * X4 [ n ] [ m ] ;
       H [ n ] [ n]+= n + 0 . 5 ;
   }

    cout << ” # * * * * * * * * * * * * * * * * * H    * * * * * * * * * * * * * * * * * \ n” ;
    f o r ( i n t n =0;n<DIM ; n++){
        cout         << ” # HH ” ;
        f o r ( i n t m =0;m<DIM ; m++)
            cout << H [ n ] [ m ] << ” ” ;
        cout         << ’\n ’ ;
    }
    cout << ” # * * * * * * * * * * * * * * * * * H    * * * * * * * * * * * * * * * * * \ n” ;
} / / calculate_H ()
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void calculate_X4 ( ) {
    double X2 [ P ] [ P ] ;
    c o n s t double isqrt2 = 1 . 0 / sqrt ( 2 . 0 ) ;

   f o r ( i n t n =0;n<DIM ; n++)
       f o r ( i n t m =0;m<DIM ; m++)
           X [ n ] [ m ]=0.0;

   f o r ( i n t n =0;n<DIM ; n++){
       i n t m=n −1;
       i f ( m>=0) X [ n ] [ m ] = isqrt2 * sqrt ( double ( m +1) ) ;
9.3. RESULTS                                                                          387

      m       =n +1;
      i f ( m<DIM ) X [ n ] [ m ] = isqrt2 * sqrt ( double ( m               ));
    }
    / / X2 = X . X
    for (          i n t n =0;n<DIM ; n++)
       f o r ( i n t m =0;m<DIM ; m++){
           X2 [ n ] [ m ] = 0 . 0 ;
           f o r ( i n t k =0;k<DIM ; k++)
               X2 [ n ] [ m ] += X [ n ] [ k ] * X [ k ] [ m ] ;
       }
    / / X4 = X2 . X2
    for (          i n t n =0;n<DIM ; n++)
       f o r ( i n t m =0;m<DIM ; m++){
           X4 [ n ] [ m ] = 0 . 0 ;
           f o r ( i n t k =0;k<DIM ; k++)
               X4 [ n ] [ m ] += X2 [ n ] [ k ] * X2 [ k ] [ m ] ;
       }
} / / calculate_X4 ()



                                                           n=0
                             0.8
                                                                     λ=0.9
                                                                     λ=0.2
                           0.75

                             0.7
                     En




                           0.65

                             0.6

                           0.55

                             0.5
                                   0      0.1       0.2       0.3    0.4       0.5
                                                           1/N

Figure 9.1: The ground state energy E0 (λ) for λ = 0.2, 0.9 is calculated in the large N
limit of the eigenvalues E0 (N, λ). Convergence is satisfactory for relatively small values
of N and it is slightly faster for λ = 0.2 than it is for λ = 0.9.




9.3         Results
Compiling and running the program can be done with the commands:

> g++ −O2 anharmonic . cpp −o an −llapack −lblas
> . / an
388                               CHAPTER 9. THE ANHARMONIC OSCILLATOR

                                                           n=9
                           140
                                                                         λ=0.9
                           120                                           λ=0.2

                           100

                            80
                     En

                            60

                            40

                            20

                              0
                                  0    0.02    0.04    0.06 0.08        0.1      0.12   0.14
                                                           1/N

Figure 9.2: The 9th excited state E9 (λ) for λ = 0.2, 0.9 is given by the large N limit
of the eigenvalues E9 (N, λ).



# Enter H i l b e r t Space dimension :
4
# Enter lambda :
0.0
.....
# ***************** H                    *****************
# HH 0.5 0 0 0
# HH 0 1 . 5 0 0
# HH 0 0 2.5 0
# HH 0 0 0 3.5
# ***************** H                    *****************
# * * * * * * * * * * * * * * * * * EVEC * * * * * * * * * * * * * * * * *
# EVEC 0 1 0 0 0
# EVEC 0 0 1 0 0
# EVEC 0 0 0 1 0
# EVEC 0 0 0 0 1
EV 4 0 0.5 1 . 5 2.5 3.5


In the above program we used N = 4 and λ = 0. The λ = 0 choice leads
us to the simple harmonic oscillator and we obtain the expected solutions:
Hnm = (n + 1/2)δn,m , E
                      ∑n 3= (n + 1/2) and the eigenstates (eigenvectors of
Hnm ) |n⟩λ=0 = |n⟩ = m=0 δn,m |m⟩. Similar results can be obtained for
larger N .
   For non zero values of λ, the finite N calculation contains systematic
errors from neglecting all the matrix elements Hnm (λ) for n ≥ N or
m ≥ N . Our program calculates the eigenvalues En (N, λ) of the finite
9.3. RESULTS                                                                        389

                                               n = 20
                        500
                                                           λ=0.9
                        450                                λ=0.2
                        400
                        350
                        300
                   En



                        250
                        200
                        150
                        100
                         50
                          0
                           0.01 0.015 0.02 0.025 0.03 0.035 0.04 0.045 0.05
                                                 1/N


Figure 9.3: The 20th excited state E20 (λ) for λ = 0.2, 0.9 is given by the large N
limit of the eigenvalues E20 (N, λ). Convergence has not been achieved for the displayed
values of N ≤ 80.


matrix Hnm (λ), m, n = 0, . . . , N − 1 and one expects that

                               En (λ) = lim En (N, λ) ,                          (9.22)
                                           N →∞

where
                               H(λ) |n⟩λ = En (λ) |n⟩λ ,                         (9.23)
is the true n-th level eigenvalue of the Hamiltonian H(λ). In practice
the limit 9.22 for given λ and n is calculated by computing En (N, λ)
numerically for increasing values of N . If convergence to a desired level
of accuracy is achieved for the accessible values of N , then the approached
limit is taken as an approximation to En (λ). This process is shown
graphically in figures 9.1-9.3 for λ = 0.2, 0.9. Convergence is satisfactory
for quite small N for n = 0, 9 but larger values of N are needed for n = 20.
Increasing the value of n for fixed λ makes the use of larger values of N
necessary. Similarly for a given energy level n, increasing λ also makes
the use of larger values of N necessary. A session that computes this
limit for the ground level energy E0 (λ = 0.9) is shown below⁸:

> tcsh
> g++ −O2 anharmonic . cpp −llapack −lblas −o an
> f o r e a c h N (4 8 12 16 24 32)
f o r e a c h ? ( echo $N ; echo 0 . 9 ) | . / an >> data
f o r e a c h ? end

   ⁸The foreach loop construct is special to the tcsh shell. This is why an explicit tcsh
command is shown. For other shells use their corresponding syntax.
390                   CHAPTER 9. THE ANHARMONIC OSCILLATOR

> grep ^ EV data | awk ’{ p r i n t $2 , $4 } ’
4 0.711467845686790
8 0.786328966767866
12 0.785237674919165
16 0.784964461939594
24 0.785032515135677
32 0.785031492177730
> gnuplot
gnuplot > plot ”<grep ^EV data | awk ’{ p r i n t 1 / $2 , $4 } ’ ”

Further automation of this process can be found in the shell script file
anharmonic.csh in the accompanying software. We note the large N
convergence of E0 (N, 0.9) and that we can take E0 (0.9) ≈ 0.78503. For
higher accuracy, a computation using larger N will be necessary.
   We can also compute the expectation values ⟨A⟩n (λ) of an operator
A = A(p, q) when the anharmonic oscillator is in a state |n⟩λ :

                            ⟨A⟩n (λ) = λ ⟨n| A |n⟩λ .                          (9.24)

In practice, the expectation value will be computed from the limit

             ⟨A⟩n (λ) = lim ⟨A⟩n (N, λ) ≡ lim           N,λ ⟨n| A |n⟩N,λ   ,   (9.25)
                         N →∞                    N →∞

where |n⟩N,λ are the eigenvectors of the finite N × N matrix Hnm (λ) com-
puted numerically by DSYEV. These are determined by their components
cm (N, λ), where
                                 ∑
                                 N −1
                        |n⟩N,λ =      cm (N, λ) |m⟩ ,             (9.26)
                                       m=0

which are stored in the columns of the array H after the call to DSYEV:

                               cm (N, λ) = H[n][m] .                           (9.27)

Substituting equation (9.26) to (9.24) we obtain

                                ∑
                                N −1
                  ⟨A⟩n (λ) =             c∗m (N, λ)cm′ (N, λ)Amm′ ,            (9.28)
                               m,m′ =0


and we can use (9.27) for the computation of the sum.
     As an application, consider the expectation values of the operators
x2 , x4 and p2 . Taking                √ ⟨x⟩n = ⟨p⟩n = 0, √
                      √into account that                   we obtain the
uncertainties ∆xn ≡ ⟨x ⟩n − ⟨x⟩n = ⟨x ⟩n and ∆pn = ⟨p2 ⟩n . Their
                          2        2       2

product should satisfy Heisenberg’s uncertainty relation ∆xn · ∆pn ≳ 1/2.
9.3. RESULTS                                                                                           391

                 10
                                                                                    ∆X ∆P
                                                                                   <X2>1/2
                                                                                   <P2>1/2


                  8




                  6




                  4




                  2




                  0
                      0   0.01     0.02   0.03   0.04         0.05   0.06   0.07       0.08   0.09
                                                        1/N



Figure 9.4: The expectation values ⟨x2 ⟩1/2      2 1/2
                                        n (λ), ⟨p ⟩n (λ) and the product of un-
certainties ∆xn · ∆pn for n = 9 and λ = 0.5 calculated from the large N limits of
     1/2            1/2
⟨x2 ⟩n (N, λ), ⟨p2 ⟩n (N, λ).


The results are shown in table 9.1 and in figures 9.4-9.5. The calculation
is left as an exercise to the reader.
    The physics of the anharmonic oscillator can be better understood by
studying the large λ limit. As shown in figure 9.5, the term λx4 dominates
in this limit and the expectation value ⟨x2 ⟩n (λ) decreases. This means
that states that confine the oscillator to a smaller range of x are favored.
This, using the uncertainty principle, implies that the typical momentum
of the oscillator also increases in magnitude. This is confirmed in figure
9.5 where we observe the expectation value ⟨p2 ⟩n (λ) to increase with λ.
In order to understand quantitatively these competing effects we will use
a scaling argument due to Symanzik. We redefine x → λ−1/6 x, p → λ1/6 p
in the Hamiltonian H(λ) = p2 /2 + x2 /2 + λx4 and for large enough λ we
obtain⁹ the asymptotic behavior

                             H(λ) ∼ λ1/3 h(1) ,                      λ → ∞,                          (9.29)

where h(λ) = p2 /2+λx4 is the Hamiltonian of the anharmonic “oscillator”
with ω = 0. Since the operator h(1) is independent of λ, the energy
spectrum will have the asymptotic behavior

                                 En (λ) ∼ Cn λ1/3 ,                  λ → ∞.                          (9.30)

   ⁹For x → λ−1/6 x, H → λ1/3 (p2 /2 + λ−2/3 x2 /2 + x4 ), therefore in the limit λ → ∞ the
second term vanishes and we obtain equation (9.29).
392                       CHAPTER 9. THE ANHARMONIC OSCILLATOR


                 14



                 12



                 10



                 8                                             ∆X ∆P
                                                              <P2>1/2
                                                              <X2>1/2

                 6



                 4



                 2



                 0
                      0         20        40       60    80             100
                                               λ



Figure 9.5: The expectation values ⟨x2 ⟩1/2      2 1/2
                                        n (λ), ⟨p ⟩n (λ) and the product of uncer-
tainties ∆xn · ∆pn for n = 9.


In reference [44] it is shown that for λ > 100 we have that
                 (                                                      )
    E0 (λ) = λ1/3 0.667 986 259 18 + 0.143 67λ−2/3 − 0.0088λ−4/3 + . . . ,
                                                                        (9.31)
with an accuracy better than one part in 106 . For large values of n, the
authors obtain the asymptotic behavior
                                (     )4/3
                                    1
           En (λ) ∼ Cλ    1/3
                                 n+        ,       λ → ∞,n → ∞,               (9.32)
                                    2

where C = 34/3 π 2 /Γ(1/4)8/3 ≈ 1.376 507 40. This relation is tested in figure
9.6 where we observe good agreement with our calculations.


9.4 The Double Well Potential
We can also use matrix methods in order to calculate the energy spectrum
of a particle in a double well potential given by the Hamiltonian:

                                          p2 x2   x4
                                     H=     −   +λ .                          (9.33)
                                          2   2   4
The equilibrium points of the classical motion are located at the minima:

                                        1           1
                                x0 = ± √ , Vmin = − .                         (9.34)
                                         λ         4λ
9.4. THE DOUBLE WELL POTENTIAL                                                     393

                    λ = 0.5                     λ = 2.0
 n    ⟨x ⟩ 2
                      ⟨p ⟩
                        2
                             ∆x · ∆p     ⟨x ⟩
                                           2
                                                  ⟨p2 ⟩ ∆x · ∆p
 0 0.305814        0.826297 0.502686   0.21223 1.19801 0.504236
 1 0.801251         2.83212    1.5064 0.540792 4.21023  1.50893
 2  1.15544         5.38489  2.49438 0.761156 8.15146   2.49089
 3  1.46752         8.28203  3.48627 0.958233 12.6504   3.48166
 4  1.75094          11.4547  4.47845  1.13698   17.596 4.47285
 5  2.01407         14.8603   5.47079  1.30291 22.9179  5.46443
 6    2.2617        18.4697    6.4632  1.45905 28.5683  6.45619
 7 2.49696          22.2616  7.45562   1.60735 34.5124  7.44805
 8  2.72198         26.2196  8.44804    1.74919 40.7234 8.43998
 9 2.93836          30.3306  9.44045   1.88558 47.1801  9.43194


Table 9.1: The expectation values ⟨x2 ⟩, ⟨p2 ⟩, ∆x · ∆p for the√
                                                               anharmonic oscillator for
      √ |n⟩, n = 0, . . . , 9. We observe a decrease of ∆x = ⟨x ⟩ and an increase of
the states                                                        2

∆p = ⟨p ⟩ as λ is increased. The product ∆x · ∆p seems to remain very close to the
           2

values (n + 1/2) of the harmonic oscillator for both values of λ.


 When the well is very deep, then for the lowest energy levels the potential
can be well approximated by that of a harmonic oscillator with angular
frequency ω 2 = V ′′ (x0 ), therefore
                                             1
                                Emin ≈ Vmin + ω .                               (9.35)
                                             2
In this case the tunneling effect is very weak and the energy levels are
arranged in almost degenerate pairs. The corresponding eigenstates are
symmetric and antisymmetric linear combinations of states localized near
the left and right minima of the potential. For example, for the two lowest
energy levels we expect that
                                                  ∆
                                 E0,1 ≈ Emin ±      ,                           (9.36)
                                                  2
where ∆ ≪ |Emin | and
                            |+⟩ + |−⟩                   |+⟩ − |−⟩
                   |0⟩λ ≈      √      ,        |1⟩λ ≈      √      ,             (9.37)
                                 2                           2
where the states |+⟩ and |−⟩ are localized to the left and right well of
the potential respectively (see also figure 10.4 of chapter 10).
   We will use equations (9.12) in order to calculate the Hamiltonian
(9.33). We need to make very small modifications to the code in the file
                                       Table 9.2:   Numerical calculation of the energy levels of the anharmonic oscillator given in reference [44].
                                         λ                E0                E1                 E2                 E3                  E4
                                         0.002      0.501 489 66      1.507 419 39       2.519 202 12       3.536 744 13        4.559 955 56
CHAPTER 9. THE ANHARMONIC OSCILLATOR




                                         0.006      0.504 409 71      1.521 805 65       2.555 972 30       3.606 186 33        4.671 800 37
                                         0.01       0.507 256 20      1.535 648 28       2.590 845 80       3.671 094 94        4.774 913 12
                                         0.05       0.532 642 75      1.653 436 01       2.873 979 63       4.176 338 91        5.549 297 81
                                         0.1        0.559 146 33      1.769 502 64       3.138 624 31       4.628 882 81        6.220 300 90
                                         0.3        0.637 991 78      2.094 641 99       3.844 782 65       5.796 573 63        7.911 752 73
                                         0.5        0.696 175 82      2.324 406 35       4.327 524 98       6.578 401 95        9.028 778 72
                                         0.7        0.743 903 50      2.509 228 10       4.710 328 10       7.193 265 28        9.902 610 70
                                         1          0.803 770 65      2.737 892 27       5.179 291 69       7.942 403 99        10.963 5831
                                         2          0.951 568 47      3.292 867 82       6.303 880 57       9.727 323 19         13.481 2759
                                         50         2.499 708 77      8.915 096 36        17.436 9921       27.192 6458         37.938 5022
                                         200        3.930 931 34      14.059 2268         27.551 4347       43.005 2709         60.033 9933
                                         1000       3.694 220 85      23.972 2061         47.017 3387        73.419 1140         102.516 157
                                         8000       13.366 9076        47.890 7687       93.960 6046         146.745 512         204.922 711
                                         20000       18.137 2291      64.986 6757        127.508 839         199.145 124        278.100 238
                                         λ                E5                E6                 E7                 E8
                                         0.002      5.588 750 05      6.623 044 60       7.662 759 33       8.707 817 30
                                         0.006      5.752 230 87      6.846 948 47       7.955 470 29       9.077 353 66
                                         0.01       5.901 026 67      7.048 326 88       8.215 837 81       9.402 692 31
                                         0.05       6.984 963 10      8.477 397 34        10.021 9318        11.614 7761
                                         0.1        7.899 767 23      9.657 839 99        11.487 3156       13.378 9698
                                         0.3        10.166 4889        12.544 2587        15.032 7713       17.622 4482
                                         0.5         11.648 7207       14.417 6692       17.320 4242        20.345 1931
                                         0.7        12.803 9297       15.873 6836        19.094 5183        22.452 9996
                                         1          14.203 1394       17.634 0492        21.236 4362        24.994 9457
                                         2           17.514 1324      21.790 9564        26.286 1250        30.979 8830
                                         50          49.516 4187      61.820 3488         74.772 8290       88.314 3280
394
                                         200        78.385 6232        97.891 3315        118.427 830       139.900 400
                                         1000        133.876 891       167.212 258       202.311 200        239.011 580
                                         8000       267.628 498       334.284 478        404.468 350         477.855 700
                                         20000      363.201 843       453.664 875        548.916 140        648.515 330
9.4. THE DOUBLE WELL POTENTIAL                                             395

                             1.41
                                                                 n=1
                                                                 n=2
                                                                 n=5
                            1.405                                n=9
                                                                n=20
                                                                   C

                              1.4
     En λ-1/3 (n+1/2)-4/3




                            1.395



                             1.39



                            1.385



                             1.38



                            1.375
                                    0   500   1000       1500      2000
                                                     λ


Figure 9.6: Test of the asymptotic relation (9.32).         The vertical axis is
En λ−1/3 (n + 1/2)−4/3 where for large enough n and λ should approach the value
C = 34/3 π 2 /Γ(1/4)8/3 ≈ 1.376 507 40 (horizontal line).



anharmonic.cpp. We will only add a routine that calculates the matrices
pnm . The resulting program can be found in the file doublewell.cpp:

/ / ========================================================
// H              : Hamiltonian o p e r a t o r H0+( lambda / 4 ) *X^4
/ / H0            : Hamiltonian H0=1/2 P^2 −1/2 X^2
/ / X, X2 , X4 : P o s i t i o n o p e r a t o r and i t s powers
/ / iP            : i P operator
/ / P2            : P^2 = −( i P ) ( i P ) o p e r a t o r
// E              : Energy e i g e n v a l u e s
/ / WORK          : Workspace f o r l a p a c k r o u t i n e DSYEV
/ / ========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>

using namespace std ;

/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
const int P      = 1000; / / P=LDA
396                            CHAPTER 9. THE ANHARMONIC OSCILLATOR


                        1.5                              λ=0.2
                                                         λ=0.1
                          1
                        0.5
                          0
                 V(x)
                        -0.5
                         -1
                        -1.5
                         -2
                        -2.5
                                 -4   -2        0        2        4
                                                x

Figure 9.7: The potential energy V (x) for the double well potential for λ = 0.1, 0.2.


c o n s t i n t LWORK = 3* P −1;
int            DIM ;
double         H [ P ] [ P ] , H0 [ P ] [ P ] ;
double         X [ P ] [ P ] , X2 [ P ] [ P ] , X4 [ P ] [ P ] ;
double         iP [ P ] [ P ] , P2 [ P ] [ P ] ;
double         E [ P ] , WORK [ LWORK ] ;
double          lambda ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
e x t e r n ”C” void
dsyev_ ( c o n s t char& JOBZ , c o n s t char& UPLO ,
            const int &                 N,
            double           H [ P ] [ P ] , c o n s t i n t & LDA ,
            double           E       [P] ,
            double           WORK [ P ] ,
            c o n s t i n t & LWORK ,                  i n t & INFO ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void calculate_ops ( ) ;
void calculate_evs ( ) ;
void calculate_H ( ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    string buf ;

  cout   <<   ” # Enter H i l b e r t Space dimension : \ n” ;
  cin    >>   DIM ;                                  getline ( cin , buf ) ;
  cout   <<   ” # Enter lambda : \ n” ;
  cin    >>   lambda ;                               getline ( cin , buf ) ;
  cout   <<   ” # lambda= ” << lambda                                << endl ;
  cout   <<   ” # ########################################\n” ;
  cout   <<   ” # Energy l e v e l s o f double w e l l p o t e n t i a l \n” ;
9.4. THE DOUBLE WELL POTENTIAL                                                                        397

   cout    <<   ”#   using matrix methods . \ n” ;
   cout    <<   ”#    H i l b e r t Space Dimension DIM = ”<<DIM<< endl ;
   cout    <<   ”#   lambda c o u p l i n g = ” << lambda       << endl ;
   cout    <<   ”#   ########################################\n” ;
   cout    <<   ”#   Output : DIM lambda E_0 E_1 . . . . E_{N−1} \n” ;
   cout    <<   ”#   −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\n” ;

    cout . precision ( 1 5 ) ;
    / / Calculate operators :
    calculate_ops ( ) ;
    / / Calculate eigenvalues :
    calculate_evs ( ) ;
    cout . precision ( 1 7 ) ;
    cout << ”EV ” << DIM << ” ” << lambda << ” ” ;
    f o r ( i n t n =0;n<DIM ; n++) cout << E [ n ] << ” ” ;
    cout << endl ;
} / / main ( )
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void calculate_evs ( ) {
    i n t INFO ;
    c o n s t char JOBZ= ’V ’ , UPLO= ’U’ ;

    calculate_H ( ) ;
    dsyev_ ( JOBZ , UPLO , DIM , H , P , E , WORK , LWORK , INFO ) ;
    i f ( INFO != 0) {
        cerr << ” dsyev f a i l e d . INFO= ” << INFO << endl ;
        exit ( 1 ) ;
    }
    cout << ” # * * * * * * * * * * * * * * * * * EVEC * * * * * * * * * * * * * * * * * \ n” ;
    f o r ( i n t n =0;n<DIM ; n++){
        cout         << ” # EVEC ” << lambda << ” ” ;
        f o r ( i n t m =0;m<DIM ; m++)
            cout << H [ n ] [ m ]     << ” ” ;
        cout         <<                     ’\n ’ ;
    }
} / / calculate_evs ()
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void calculate_H ( ) {
    double X2 [ P ] [ P ] ;

   f o r ( i n t n =0;n<DIM ; n++)
       f o r ( i n t m =0;m<DIM ; m++)
           H [ n ] [ m ] = H0 [ n ] [ m ] + 0.2 5 * lambda * X4 [ n ] [ m ] ;

   cout << ” # * * * * * * * * * * * * * * * * * H         * * * * * * * * * * * * * * * * * \ n” ;
   f o r ( i n t n =0;n<DIM ; n++){
       cout         << ” # HH ” ;
       f o r ( i n t m =0;m<DIM ; m++)
           cout << H [ n ] [ m ] << ” ” ;
398                              CHAPTER 9. THE ANHARMONIC OSCILLATOR

       cout      << ’\n ’ ;
    }
    cout << ” # * * * * * * * * * * * * * * * * * H    * * * * * * * * * * * * * * * * * \ n” ;
} / / calculate_H ()
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void calculate_ops ( ) {
    double X2 [ P ] [ P ] ;
    c o n s t double isqrt2 = 1 . 0 / sqrt ( 2 . 0 ) ;

   f o r ( i n t n =0;n<DIM ; n++)
       f o r ( i n t m =0;m<DIM ; m++){
           X [ n ] [ m ] = 0 . 0 ; iP [ n ] [ m ] = 0 . 0 ;
       }

   f o r ( i n t n =0;n<DIM ; n++){
       i n t m=n −1;
       i f ( m>=0 ) X [ n ] [ m ] = isqrt2 * sqrt ( double ( m +1) ) ;
       i f ( m>=0 ) iP [ n ] [ m ] = −isqrt2 * sqrt ( double ( m +1) ) ;
       m        =n +1;
       i f ( m<DIM ) X [ n ] [ m ] = isqrt2 * sqrt ( double ( m ) ) ;
       i f ( m<DIM ) iP [ n ] [ m ] = isqrt2 * sqrt ( double ( m ) ) ;
   }
   / / X2 = X . X
   for (           i n t n =0;n<DIM ; n++)
       f o r ( i n t m =0;m<DIM ; m++){
           X2 [ n ] [ m ] = 0 . 0 ;
           f o r ( i n t k =0;k<DIM ; k++)
               X2 [ n ] [ m ] += X [ n ] [ k ] * X [ k ] [ m ] ;
       }
   / / X4 = X2 . X2
   for (           i n t n =0;n<DIM ; n++)
       f o r ( i n t m =0;m<DIM ; m++){
           X4 [ n ] [ m ] = 0 . 0 ;
           f o r ( i n t k =0;k<DIM ; k++)
               X4 [ n ] [ m ] += X2 [ n ] [ k ] * X2 [ k ] [ m ] ;
       }
   / / P2 =−i P . i P
   for (           i n t n =0;n<DIM ; n++)
       f o r ( i n t m =0;m<DIM ; m++){
           P2 [ n ] [ m ] = 0 . 0 ;
           f o r ( i n t k =0;k<DIM ; k++)
               P2 [ n ] [ m ] −= iP [ n ] [ k ] * iP [ k ] [ m ] ;
       }
   / / Hamiltonian :
   for (           i n t n =0;n<DIM ; n++)
       f o r ( i n t m =0;m<DIM ; m++)
           H0 [ n ] [ m ] = 0 . 5 * ( P2 [ n ] [ m]−X2 [ n ] [ m ] ) ;

} / / calculate_ops ()
9.4. THE DOUBLE WELL POTENTIAL                                               399

   Where is the particle’s favorite place when it is in the states |+⟩ and
|−⟩? The answer to this question is obtained from the study of the
expectation value of the position operator ⟨x⟩ in each one of them. We
know that when the particle is in one of the energy eigenstates, then we
have that
                        ⟨x⟩n (λ) = λ ⟨n| x |n⟩λ = 0                  (9.38)
because the potential V (x) = V (−x) is even. Therefore

     ⟨x⟩± (λ) = ⟨±| x |±⟩
                 1
              = √ (λ ⟨0| x |0⟩λ ± λ ⟨1| x |0⟩λ ± λ ⟨0| x |1⟩λ + λ ⟨1| x |0⟩λ )
                  2
                  √
              = ± 2⟨1| x |0⟩λ ,                                             (9.39)

where in the last line we used the relation (9.38) λ ⟨0| x |0⟩λ = λ ⟨1| x |1⟩λ =
0 and that the amplitudes λ ⟨1| x |0⟩λ = λ ⟨0| x |1⟩λ . Also¹⁰ we have that
                                                    ∑∞ (0)
λ ⟨1| x |0⟩λ > 0. Therefore, if we have that |0⟩λ =    m=0 cm |m⟩ and |1⟩λ =
∑∞ (1)
   m=0 cm |m⟩, we obtain

                                   √    ∑
                                        ∞
                                                     (1)
                     ⟨x⟩± (λ) = ± 2              c(0)
                                                  m cm′ Xmm′ .             (9.40)
                                       m,m′ =0


Given that for finite N , the subroutine DSYEV returns approximations to
                (n)
the coefficients cm in the columns of the matrix H[DIM][DIM] so that
 (n)
cm ≈ H[n][m], you
                √ may compare the value of ⟨x⟩± (λ) with the classical
values x0 = ±1/ λ as λ is increased.




  ¹⁰You may convince yourselves by looking at the wave functions in figures 10.4 of
chapter 10 and by computing the relevant integrals.
400                      CHAPTER 9. THE ANHARMONIC OSCILLATOR




               1




             0.01




           0.0001
      ∆n




           1e-06




           1e-08




           1e-10                                                        n=0
                                                                        n=6
                                                                       n=30
                      0.01           0.1            1             10            100
                                                λ


Figure 9.8: Calculation of the difference of the energy levels ∆n = En+1 − En for
n = 0, 6, 30 for the double well potential from the program doublewell.cpp. The
difference vanishes√as the well becomes deeper with decreasing λ. The states |±⟩ =
( |n + 1⟩λ ± |n⟩λ )/ 2 are more and more localized to the right or left well respectively.
9.5. PROBLEMS                                                       401

9.5   Problems
9.1 Calculate the matrix H(λ) for N = 2, 3 analytically. Calculate its
    eigenvalues for N = 2. Compare your results with the numerical
    values that you obtain from your program.

9.2 Add the necessary code to the program in the file test.cpp so
    that it checks that the eigenvectors satisfy their defining relations
    A vi = λi vi and that they form an orthonormal basis vi · vj = δij .

9.3 Calculate E5 (λ) and E9 (λ) for λ = 0.8, 1.2 with an accuracy better
    than 0.01%.

9.4 For how large n can you calculate En (λ) for λ = 1 with an accuracy
    better than 2% when N = 64?

9.5 Calculate E3 (λ) and E12 (λ) for 0 ≤ λ ≤ 4 with step δλ = 0.2 by
    achieving accuracy better than 0.01%. How large should N be taken
    in each case?

9.6 Calculate the expression that gives the matrix elements of the oper-
    ator x4 in the |n⟩ representation analytically. Modify the program
    in anharmonic.cpp in order to incorporate your calculation. Verify
    that the results are the same and test if it has an effect in the to-
    tal computation time with and without calculating the eigenvalues
    and eigenvectors of the Hamiltonian. Compute in each case the de-
    pendence of the cpu time on N by computing the exponent (cpu
    time)∼ N a for N = 40 − 1000.

9.7 Modify the code in the file anharmonic.cpp so that the arrays H,
    X, X4, E, WORK are dynamically allocated and their dimension is
    determined by the variable DIM read by the program interactively.

9.8 Make an attempt to reproduce the results of Hioe and Montroll [44]
    given in table 9.2 for n = 3 and n = 5. What is the largest value of
    λ that you can study given your computational resources?

9.9 Make an attempt to reproduce the results of Hioe and Montroll [44]
    given by equation (9.31). Calculate the ground state energy E0 for
    200 < λ < 20000 and then fit your results to a function of the form
    λ1/3 (a + bλ−2/3 + cλ−4/3 ). What is the accuracy in the calculation
    of the coefficients a, b and c and how good is the agreement with
    equation (9.31)?
402                   CHAPTER 9. THE ANHARMONIC OSCILLATOR

9.10 Modify the code in the file anharmonic.cpp so that it calculates the
     expectation values ⟨x2 ⟩n (N, λ), ⟨p2 ⟩n (N, λ) and the corresponding
     products ∆x · ∆p.
     (Hint: See the file anharmonicOBS.cpp.)

9.11 Reproduce the results shown in figure 9.4. Repeat your calculation
     for λ = 2.0, 10.0, 100.0. Repeat your calculations for n = 20.

9.12 Reproduce the results shown in figure 9.5. Repeat your calculations
     for n = 20.

9.13 Reproduce the results shown in figure 9.6. Repeat your calculation
     for n = 3, 7, 12, 18, 24.

9.14 Write a program that calculates the energy levels of the anharmonic
     oscillator
                                    1       1
                       H(λ, µ) = p2 + x2 + λx4 + µx6 .                     (9.41)
                                    2       2
     Calculate En (λ) for n = 0, 3, 8, 20, λ = 0.2 and µ = 0.2, 0.5, 1.0, 2.0, 10.0.

9.15 Modify the program of the previous problem so that it calculates the
     expectation values ⟨x2 ⟩n (N, λ), ⟨p2 ⟩n (N, λ) and the products ∆x · ∆p.
     Calculate the expectation values ⟨x2 ⟩n (λ), ⟨p2 ⟩n (λ) and ∆x · ∆p for
     n = 0, 3, 8, 20, λ = 0.2 and µ = 0.2, 0.5, 1.0, 2.0, 10.0.

9.16 Use the program doublewell.cpp in order to calculate the energy
     level pairs En , En+1 for n = 0, 4, 20 and λ = 0.2, 0.1, 0.05, 0.02. Cal-
     culate the difference ∆n = En+1 − En and comment on your results.

9.17 Define the energy values
                                        (     )
                                      1     1
                               ϵn = − + n +     .
                                     4λ     2

      Compare the results for En , En+1 of the previous problem with ϵn −
      ∆n /2 and ϵn + ∆n /2 respectively. Explain your results.

9.18 Modify the program doublewell.cpp, so that it calculates the ex-
     pectation values ⟨x⟩± (λ) given by equation
                                        √        (9.40). Compare ⟨x⟩± (λ)
     with the classical values x0 = ±1/ λ for λ = 0.2, 0.1, 0.05, 0.02, 0.01.
                                                               √
9.19 Repeat the previous problem when the states |±⟩ = (1/ 2)( |n⟩λ ±
     |n + 1⟩λ ) for n = 6 and n = 30.
9.5. PROBLEMS                                                        403

9.20 For the simple harmonic oscillator, the energy levels are equidis-
     tant, i.e. ∆n = En+1 − En = 1, (∆n+2 − ∆n )/∆n = 0. Calculate these
     quantities for the anharmonic oscillator and the double well poten-
     tial for λ = 1, 10, 100, 1000 and n = 0, 8, 20. What do you conclude
     from your results?
404   CHAPTER 9. THE ANHARMONIC OSCILLATOR
Chapter 10

Time Independent Schrödinger
Equation

In this chapter, we will study the time independent Schrödinger equation
for a non relativistic particle of mass m, without spin, moving in one
dimension, in a static potential V (x). We will only study bound states.
The solutions in this case yield the discrete energy spectrum {En } as well
as the corresponding eigenstates of the Hamiltonian {ψn (x)} in position
representation.
    From a numerical analysis point of view, the problem consists of
solving for the eigensystem of a differential equation with boundary con-
ditions. Part of the solution is the energy eigenvalue which also needs to
be determined.
    As an exercise, we will use two different methods, one that can be
applied to a particle in an infinite well with V (x) = V (−x), and one that
can be applied to more general cases. The first method is introduced
only for educational purposes and the reader may skip section 10.2 to
go directly to section 10.3.



10.1 Introduction
The wave functions ψ(x), which are the position representation of the
energy eigenstates, satisfy the Schrödinger equation

                       ℏ2 ∂ 2 ψ(x)
                   −               + V (x)ψ(x) = Eψ(x) ,             (10.1)
                       2m ∂x2

                                    405
406                            CHAPTER 10. SCHRÖDINGER EQUATION

with the normalization condition
                            ∫ +∞
                    ⟨ψ|ψ⟩ =      ψ ∗ (x)ψ(x) dx = 1 .                            (10.2)
                                       −∞

The Hamiltonian operator is given in position representation by

                                        ℏ2 ∂ 2
                              Ĥ = −           + V (x̂) ,                        (10.3)
                                        2m ∂x2

and it is Hermitian, i.e. Ĥ † = Ĥ. Equation (10.1) is an eigenvalue
problem
                           Ĥψ(x) = Eψ(x) ,                     (10.4)
which, for bound states, has as solutions a discrete set of real functions
ψn∗ (x) = ψn (x) such that Ĥψn (x) = En ψn (x). The numbers E0 ≤ E1 ≤
E2 ≤ . . . are real and they are the (bound) energy spectrum of the particle
in the potential¹ V (x). The minimum energy E0 is called the ground
state energy and the corresponding ground state is given by a non trivial
function ψ0 (x). According to the Heisenberg uncertainty principle, in this
state the uncertainties in momentum ∆p > 0 and position ∆x > 0 so that
∆p · ∆x ≥ ℏ/2.
     The eigenstates ψn (x) form an orthonormal basis
                                   ∫   +∞
                     ⟨ψn |ψm ⟩ =            ψn∗ (x)ψm (x) dx = δn,m .            (10.5)
                                   ∞

so that any (square integrable) wave function ϕ(x) which represents the
state |ϕ⟩ is given by the linear combination

                                            ∑
                                            ∞
                                ϕ(x) =            cn ψn (x) .                    (10.6)
                                            n=0

                                   ∫ +∞
The amplitudes cn = ⟨ψn |ϕ⟩ = −∞ ψn∗ (x)ϕ(x) dx are complex numbers
that give the probability pn = |cn |2 to measure energy En in the state |ϕ⟩.
   For any state |ϕ⟩ the function

                            pϕ (x) = |ϕ(x)|2 = ϕ∗ (x)ϕ(x)                        (10.7)
    ¹The fact that the energy spectrum of the particle is bounded from below depends
on the form of the potential. We assume that V (x) is such that E0 is finite. Also, in one
dimension, the energy spectrum of a particle for reasonable potentials is non degenerate
(see, however, S. Kar, R. Parwani, arXiv:0706.1135.)
10.1. INTRODUCTION                                                                   407

is the probability density of finding the particle at position x, i.e. the
probability of detecting the particle in the interval [x1 , x2 ] is given by
                            ∫ x2             ∫ x2
        Pϕ (x1 < x < x2 ) =      pϕ (x) dx =      ϕ∗ (x)ϕ(x) dx .         (10.8)
                                  x1                x1

The normalization condition (10.2) reflects the conservation of probabil-
ity (independent of time, respected by the time dependent Schrödinger
equation) and the completeness (in this case the certainty that the particle
will be observed somewhere on the x axis).
    The classical observables A(x, p) of this quantum mechanical system
are functions of the position and the momentum and their quantum
mechanical versions are given by operators Â(x̂, p̂). Their expectation
values when the system in a state |ϕ⟩ are given by
                                    ∫ +∞
               ⟨Â⟩ϕ = ⟨ϕ| Â |ϕ⟩ =      ϕ∗ (x)Â(x̂, p̂)ϕ(x) dx .   (10.9)
                                          −∞

   From a numerical point of view, the eigenvalue problem (10.1) re-
quires the solution of an ordinary second order differential equation.
There are certain differences in this problem compared to the ones stud-
ied in previous sections:
   • Instead of an initial value problem (i.e. the values of the function
     and its derivative are given at one point), we have a boundary
     value problem (values of the function or its derivative given at two
     different points).
   • The eigenvalue (energy) is unknown and should be determined as
     part of the solution.
As an introduction to such classes of problems, we will present some
simple methods which are special to one dimension.
   For the numerical solution of the above equation we renormalize x, the
function ψ(x) and the parameters so that we deal only with dimensionless
quantities. Equation (10.1) is rewritten as:
                  d2        2m
                      ψ(x) + 2 (E − V (x))ψ(x) = 0 .          (10.10)
                 dx 2        ℏ
Then we choose a length scale L which is defined by the parameters of
the problem² and we redefine x̃ = x/L. We define ψ̃(x̃) = ψ(x) ψ̃ ′ (x̃) =
   ²There are m, ℏ and the coupling constants in the function V (x). The range of the
potential will determine L in some problems and it is given explicitly in potential wells.
In potentials of real physical systems, however, this is also determined by the coupling
constants.
408                             CHAPTER 10. SCHRÖDINGER EQUATION

dψ(x)/dx̃ = L dψ(x)/dx and we obtain

                        ′′      2mL2
                      ψ̃ (x̃) +      (E − V (x̃L))ψ̃(x̃) = 0 .                  (10.11)
                                 ℏ2
We define v(x̃) = 2mL2 V (x)/ℏ2 = 2mL2 V (x̃L)/ℏ2 , ϵ = 2mL2 E/ℏ2 and
change notation to x̃ → x, ψ̃ → ψ. We obtain
                              ψ ′′ (x) = −(ϵ − v(x))ψ(x) .                      (10.12)
The solutions of equation (10.1) can be obtained from those of equation
(10.12) by using the following “dictionary”³:
              x           ℏ2                  ℏ2
           x→    , E=         ϵ ,    V (x) =      v(x/L) .     (10.13)
             L           2mL2                2mL2
The dimensionless momentum is defined as p̃ = −i∂/∂ x̃ = −iL∂/∂x and
we obtain
                                       L
                                  p̃ = p .                     (10.14)
                                       ℏ
The commutation relation [x, p] = iℏ becomes [x̃, p̃] = i. The kinetic
           p2
energy T =      is given by
           2m
                            ℏ2 2        ℏ2 ∂ 2
                             T =
                               p̃ =  −            ,                             (10.15)
                          2mL2         2mL2 ∂ x̃2
and the Hamiltonian H = T + V
                                       (            )
              ℏ2 ( 2         )    ℏ2       ∂2
        H=         p̃ + v(x̃) =         − 2 + v(x̃) .                           (10.16)
            2mL2                 2mL2     ∂ x̃
In what follows, we will omit the tilde above the symbols and write x
instead of x̃.


10.2 The Infinite Potential Well
The simplest model for studying the qualitative features of bound states
is the infinite potential well of width L where a particle is confined within
the interval [−L/2, L/2]:
                                  {
                                     0    |x| < 1
                          v(x) =                                    (10.17)
                                     +∞ |x| ≥ 1
    ³If we normalize the solutions ψ̃(x̃) of equation (10.12) according to the relation
∫ +∞ ∗                                                    √
 −∞
      ψ̃ (x̃)ψ̃(x̃)dx̃ = 1, we should also take ψ(x) = (1/ L)ψ̃(x/L) in order to be prop-
                    ∫ +∞
erly normalized −∞ ψ ∗ (x)ψ(x)dx = 1.
10.2. THE INFINITE POTENTIAL WELL                                                       409

              v                  v                        v




                                v0                        v0




      −1          +1     −1            +1      −1     −a +a    +1                 x

   Figure 10.1: The potentials given by equations (10.17), (10.26) and (10.27).



The length scale chosen here is L/2 and the dimensionless variable x
corresponds to x/(L/2) when x is measured in length units.
   The solution of (10.12) can be easily computed. Due to the symmetry

                                     v(−x) = v(x) ,                                (10.18)
of the potential, the solutions have well defined parity. This property will
be crucial to the method used below. The method discussed in the next
section can also be used on non even potentials.
    The solutions are divided into two categories, one with even parity
           (+)          (+)
ψn (x) ≡ ψn (−x) = ψn (x) for n = 1, 3, 5, 7, . . . and one with odd parity
             (−)          (−)
ψn (x) ≡ −ψn (−x) = ψn (x) for n = 2, 4, 6, 8, . . ..
               {
                   (+)
                 ψn (x) = cos ( nπ
                                 2
                                   x) |x| < 1 n = 1, 3, 5, 7, . . .
     ψn (x) =      (−)                                              (10.19)
                 ψn (x) = sin ( 2 x) |x| < 1 n = 2, 4, 6, 8, . . .
                                nπ



where                                       ( nπ )2
                                     ϵn =             ,                            (10.20)
                                              2
                                                               ∫1
and the normalization has been chosen so that⁴                 −1
                                                                    (ψn (x))2 dx = 1.

    ⁴According to the dictionary mentioned in the previous section, for a potential
well where x ∈ [−L/2, L/2] the dimensionless position variable has been chosen to be
                                 ℏ2        ℏ2 π 2 2      (+)      √
x/(L/2) ∈ [−1, 1]. Then En = 2m(L/2)2 ϵn = 2mL2 n   and ψn (x) = 2/L cos (nπx/L),
  (−)      √
ψn (x) = 2/L sin (nπx/L). Note that ϵn = p2n according to equations (10.13) and
(10.14).
410                                       CHAPTER 10. SCHRÖDINGER EQUATION

  The solutions can be found by using the parity of the wave functions.
We note that for the positive parity solutions

                                    ψn(+) (0) = A                               ψn(+) ′ (0) = 0 ,                         (10.21)

whereas for the negative parity solutions

                                    ψn(−) (0) = 0                        ψn(−) ′ (0) = A .                                (10.22)

The constant A depends on the normalization of the wave function.
Therefore we can set A = 1 originally and then renormalize the wave
function so that equation (10.2) is satisfied. If the energy is known, the
relations (10.21) and (10.22) can be taken as initial conditions in relation
(10.12). By using a Runge–Kutta algorithm we can evolve the solution
towards x = ±1. The problem is that the energy ϵ is unknown. If the en-
ergy is not allowed by the quantum theory we will find that the boundary
conditions
                               ψn(±) (±1) = 0                       (10.23)
are violated. As we approach the correct value of the energy, we obtain
 (±)
ψn (±1) → 0.
           1                                                                        1
                                                   i= 0                                                                     i= 0
                                                   i= 1                                                                     i= 5
                                                   i= 2                                                                   i= 10
                                                   i= 3                                                                   i= 20
         0.8                                       i= 5                           0.01                                    i= 29
                                                 i= 12



         0.6                                                                    0.0001
                                                              |ψi(x)-ψn=0(x)|
 ψi(x)




         0.4                                                                     1e-06




         0.2                                                                     1e-08




           0                                                                     1e-10




         -0.2                                                                    1e-12
                0   0.2   0.4       0.6    0.8            1                              0   0.2    0.4       0.6   0.8            1
                                x                                                                         x




Figure 10.2: Convergence of the solution ψi (x) of (10.12) with the potential (10.17)
as a function of the number of iterations i in the program well.cpp. Initially energy
= 2.0 and parity = 1. After 29 iterations the solution converges to the ground state
ψ1 (x) = cos (πx/2) with energy ϵ = (π/2)2 and with relative accuracy ∼ 10−9 . The
bottom plot shows the error as a function of the number of iterations in a logarithmic
scale. For i ≡iter = 1,2,3,5,10,12,20 we obtain energy = 2.4, 2.6, 2.4, 2.4625,
2.46875, 2.4673828125.


         Therefore we follow the steps described below:
         • We choose an initial value for the energy ϵ that is lower than the one
           we are looking for. We can use estimates from known solutions of
10.2. THE INFINITE POTENTIAL WELL                                            411

     similar looking potential wells or simply start from a value slightly
     higher than the absolute minimum of the potential.

   • We choose the parity of the solution and we set initial conditions
     according to equations (10.21) and (10.22).

   • We evolve the solutions using a 4th order Runge-Kutta method
     from ⁵ x = 0 to x = +1.

   • If equation (10.23) is not satisfied, we increase the energy by δϵ and
     we repeat.
                          (±)
   • We repeat until ψn (1) changes sign. Then we lower the energy by
     δϵ = −δϵ/2.
                                           (±)
   • The process is ended when |ψn (1)| < δ for appropriately chosen
     small δ.
   For the evolution of the solution from x = 0 to x = 1 we use the 4th
order Runge-Kutta method programmed in the file rk.cpp of chapter 4.
We copy the function RKSTEP in a local file rk.cpp. The integration of
(10.12) can by done by using the function ϕ(x) ≡ ψ ′ (x)

                           ψ ′ (x) = ϕ(x)
                           ϕ′ (x) = (v(x) − ϵ)ψ(x) ,                      (10.24)

with the initial conditions

                ψ(0) = 1 ,       ϕ(0) ≡ ψ ′ (0) = 0 even parity
                ψ(0) = 0 ,       ϕ(0) ≡ ψ ′ (0) = 1 odd parity .          (10.25)

We use the notation ψ(x) → psi, ϕ(x) → psip. The functions f1 and f2
correspond to the right hand side of (10.24). They are the derivatives of
ψ(x) and ϕ(x) respectively and f1=psip, f2=(V-energy)*psi. The code
of f1 and f2 is put in a different file so that we can easily reuse the code
for many different potentials v(x). The file wellInfSq.cpp contains the
necessary program for the potential of equation (10.17):

/ / ===========================================================
/ / f i l e : w e l l I n f S q . cpp
//
/ / Functions used i n RKSTEP f u n c t i o n . Here :

  ⁵The function in [−1, 0) is determined by the parity of the solution.
412                          CHAPTER 10. SCHRÖDINGER EQUATION

/ / f1 = psip ( x ) = psi ( x ) ’
/ / f 2 = p s i p ( x ) ’= p s i ( x ) ’ ’
//
/ / A l l one has t o s e t i s V , t h e p o t e n t i a l
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
e x t e r n double energy ;
/ /−−−−−−−− t r i v i a l f u n c t i o n : d e r i v a t i v e o f p s i
double
f1 ( c o n s t double& x , c o n s t double& psi , c o n s t double& psip ) {
    r e t u r n psip ;
}
/ / ===========================================================
/ /−−−−−−−− t h e second d e r i v a t i v e o f wavefunction :
/ / p s i p ( x ) ’ = p s i ( x ) ’ ’ = −(E−V) p s i ( x )
double
f2 ( c o n s t double& x , c o n s t double& psi , c o n s t double& psip ) {
    double V ;
    / /−−−−−−− p o t e n t i a l , s e t here :
    V = 0.0;
    / /−−−−−−− S c h r o e d i n g e r eq : RHS
    r e t u r n ( V−energy ) * psi ;
}

    We stress that the energy ϵ = energy is put in the global scope so that
it can be accessed by the main program.
    The main program is in the file well.cpp. The user enters the pa-
rameters (energy, parity, Nx) and the loop

  while ( iter < 10000) {
    ....
    i f ( abs ( psinew )  <= epsilon ) break ;
    i f ( psinew * psiold < 0.0      ) de = −0.5* de ;
    energy        += de ;
    ....
  }

exits when ψ(1) =psinew has an absolute value which is less than epsilon,
i.e. when the condition (10.23) is satisfied to the desired accuracy. The
value of the energy increases up to the point where the sign of the wave
function at x = 1 changes (psinew*psiold< 0). Then the value of the
energy is overestimated and we change the sign of the step de and re-
10.2. THE INFINITE POTENTIAL WELL                                                                   413

duce its magnitude by a half. The algorithm described on page 410 is
implemented inside the loop. After exiting the loop, the energy has been
determined with the desired accuracy and the rest of the program stores
the solution in the array psifinal(STEPS). The results are written to the
file psi.dat. Note how the variable parity is used so that both cases
parity= ±1 can be studied. The full program is listed below:

/ / ===========================================================
/ / f i l e : w e l l . cpp
//
/ / Computation o f energy e i g e n v a l u e s and e i g e n f u n c t i o n s
/ / o f a p a r t i c l e i n an i n f i n i t e w e l l with V(−x )=V( x )
//
/ / Input : energy : i n i t i a l guess f o r energy
//                  p a r i t y : d e s i r e d p a r i t y o f s o l u t i o n (+/ − 1 )
//                 Nx−1 : Number o f RK4 s t e p s from x=0 t o x=1
/ / Output : energy : energy e i g e n v a l u e
//                  p s i . dat : f i n a l p s i [ x ]
//                  a l l . dat : a l l        psi [ x ] for t r i a l energies
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
c o n s t i n t P = 10000;
double energy ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void
RKSTEP ( double& t ,                            double& x1 ,
                  double& x2 ,
                  const                         double& dt ) ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    double dx , x , epsilon , de ;
    double psi , psip , psinew , psiold ;
    double array_psifinal [ 2 * P + 1 ] , array_xstep [ 2 * P + 1 ] ;
    double * psifinal = array_psifinal+P ;
    double * xstep                 = array_xstep                +P ;
    / / p s i f i n a l p o i n t s t o ( a r r a y _ p s i f i n a l +P ) and one can
    / / use p s i f i n a l [−P ] . . . p s i f i n a l [ P ] . S i m i l a r l y f o r x s t e p
    int           parity , Nx , iter , i , node ;
    string buf ;
    / /−−−−−− Input :
    cout << ” Enter energy , p a r i t y , Nx: \ n” ;
414                             CHAPTER 10. SCHRÖDINGER EQUATION

 cin >> energy >> parity >> Nx ;                          getline ( cin , buf ) ;
 i f ( Nx > P ) { cerr << ”Nx>P\n” ; exit ( 1 ) ; }
 i f ( parity > 0) parity= 1 ;
 else                     parity=−1;
 cout << ” # #######################################\n” ;
 cout << ” # E s t a r t = ” << energy
           << ” p a r i t y = ” << parity << endl ;
 dx              = 1 . 0 / ( Nx −1) ;
 epsilon = 1 . 0 e−6;
 cout << ” # Nx= ”                     << Nx         << ” dx = ” << dx
           << ” eps= ”                 << epsilon << endl ;
 cout << ” # #######################################\n” ;
 / /−−−−−− C a l c u l a t e :
 ofstream myfile ( ” a l l . dat ” ) ;
 myfile . precision ( 1 7 ) ;
 cout . precision ( 1 7 ) ;
 iter            = 0;
 psiold          = 0.0;
 psinew          = 1.0;
 de              = 0 . 1 * abs ( energy ) ;
 while ( iter < 10000) {
     / / I n i t i a l c o n d i t i o n s a t x=0
     x           = 0.0;
     i f ( parity == 1 ) {
         psi = 1 . 0 ;
         psip = 0 . 0 ;
     } else {
         psi = 0 . 0 ;
         psip = 1 . 0 ;
     }
     myfile         << iter << ” ” << energy << ” ”
                    << x             << ” ” << psi        << ” ”
                    << psip << endl ;
     / / Use Runge−Kutta t o forward t o x=1
     f o r ( i =2;i<=Nx ; i++){
         x = ( i−2) * dx ;
         RKSTEP ( x , psi , psip , dx ) ;
         myfile << iter << ” ” << energy << ” ”
                    << x             << ” ” << psi        << ” ”
                    << psip << endl ;
     }
     psinew = psi ;
     cout           << iter << ” ” << energy << ” ”
                    << de            << ” ” << psinew << endl ;
     / / Stop i f v a l u e o f p s i c l o s e t o 0
     i f ( abs ( psinew )            <= epsilon ) break ;
     / / Change d i r e c t i o n o f energy s e a r c h :
     i f ( psinew * psiold < 0.0                   ) de = −0.5* de ;
     energy         += de ;
10.2. THE INFINITE POTENTIAL WELL                                                    415

        psiold             = psinew ;
        iter ++;
    } / / while ( i t e r < 10000)
    myfile . close ( ) ;
    / / We found t h e s o l u t i o n :
    / / c a l c u l a t e i t once again and s t o r e i t
    i f ( parity           == 1 ) {
        psi                = 1.0;
        psip               = 0.0;
        node               = 0 ; / / count number o f nodes o f f u n c t i o n
    } else {
        psi                = 0.0;
        psip               = 1.0;
        node               = 1;
    }
    x                      = 0.0;
    xstep           [0] = x ;
    psifinal [ 0 ] = psi ; / / a r r a y t h a t s t o r e s p s i ( x )
    psiold                 = 0.0;
    / / Use Runge−Kutta t o move t o x=1
    f o r ( i=2 ; i<=Nx ; i++ ) {
        x                           = ( i−2) * dx ;
        RKSTEP ( x , psi , psip , dx ) ;
        xstep           [ i−1]      = x;
        psifinal [ i−1]             = psi ;
        / / Use p a r i t y t o compute p s i (−x )
        xstep           [1−i ]      = −x ;
        psifinal [1−i ]             = psi * parity ;
        / / Determine z e r o e s o f p s i ( x ) :
        / / p s i should not be z e r o w i t h i n e p s i l o n :
        i f ( abs ( psi )           > 2 . 0 * epsilon ) {
            i f ( psi * psiold < 0 . 0 ) node += 2 ;
            psiold                  = psi ;
        }
    } / / f o r ( i =2; i <=Nx ; i ++)
    node ++;
    / / print final solution :
    myfile . open ( ” p s i . dat ” ) ;
    cout             << ” F i n a l r e s u l t : E= ” << energy
                     << ” n= ”                          << node
                     << ” p a r i t y = ”               << parity        << endl ;
    myfile           << ” # E= ”                        << energy
                     << ” n= ”                          << node
                     << ” p a r i t y = ”               << parity        << endl ;
    f o r ( i=−(Nx −1) ; i<=(Nx −1) ; i++)
        myfile << xstep               [i]               << ” ”
                     << psifinal [ i ]                                   << endl ;
    myfile . close ( ) ;
} / / main ( )
416                             CHAPTER 10. SCHRÖDINGER EQUATION

The compilation and running of the program can be done with the com-
mands

> g++ well . cpp wellInfSq . cpp rk . cpp −o well
> . / well
Enter energy , parity , Nx :
2.0 1 400
# #######################################
# Estart= 2 parity= 1
# Nx= 400 dx = 0.00250627 eps= 1e−06
# #######################################
0 2                0.200000000         0.155943694
1 2.2000000000 0.200000000             0.087444801
.....
28 2.4674072265 1.220703125e−05 −1.950054368e−06
29 2.4674011230 −6.103515625e−06 −7.246215909e−09
Final result : E= 2.4674011230468746 n= 1 parity= 1

The energy is determined to be ϵ =2.467401123 which can be compared
to the exact value ϵ = (π/2)2 ≈ 2.467401100. The fractional error is
∼ 10−8 . The convergence can be studied graphically in figure 10.2.
   The calculation of the excited states is done by changing the parity and
by choosing the initial energy slightly higher than the one determined in
the previous step⁶. The results are in table 10.1. The agreement with the
exact result ϵn = (nπ/2)2 is excellent.
   We close this section with two more examples. First, we study a
potential well with triangular shape at its bottom
                                 {
                                    v0 |x| |x| < 1
                          v(x) =                                    (10.26)
                                    +∞ |x| > 1

and then a double well potential with
                            
                             v0      |x| < a
                     v(x) =      0 a < |x| < 1                                    (10.27)
                            
                                +∞    1 < |x|

where the parameters v0 , a are positive numbers. A qualitative plot of
these functions is shown in figure 10.1.
   For the triangular potential we take v0 = 10, whereas for the double
well potential v0 = 100 and a = 0.3. The code in wellInfSq.cpp is appro-
priately modified and saved in the files wellInfTr.cpp and wellInfDbl.cpp
   ⁶Careful: if the energy levels are too close, we should keep the initial energy constant
and change the sign of parity.
10.2. THE INFINITE POTENTIAL WELL                                                    417




    n       (nπ/2)2             Square            Triangular  Double Well
     1   2.467401100         2.467401123        5.248626709 15.294378662
     2   9.869604401         9.869604492        14.760107422 15.350024414
     3   22.2066099          22.2066040          27.0690216   59.1908203
     4     39.47841            39.47839            44.51092     59.96887
     5    61.6850275          61.6850242         66.6384315   111.3247375
    6      88.82643            88.82661            93.84588    126.37628
     7   120.902653           120.902664         125.878830   150.745215
     8     157.91367           157.91382          162.92569    194.07578
     9    199.859489          199.859490         204.845026    235.017471
    10     246.74011           246.74060          251.74813    275.67383
    11   298.555533           298.555554         303.545814   331.428306
    12     355.3057            355.3064            360.3107     388.7444


Table 10.1: Energy eigenvalues for the square, triangular and double well potentials
(equations (10.17), (10.26) with v0 = 10 and equation (10.27) with v0 = 100, a = 0.3).
The agreement of the results for the square potential with the exact ones is excellent.
For the other potentials, we note that as we move further from the bottom of the well
we obtain energy levels very close to those of the square well: The particle does not feel
the influence of the details at the bottom of the well. For the double well potential we
obtain E1 ≈ E2 and E3 ≈ E4 according to the analysis on page 418.
418                             CHAPTER 10. SCHRÖDINGER EQUATION

respectively. All we have to do is to change the line computing the value
of the potential in the function f2. For example the file wellInfTr.cpp
contains the code

  / /−−−−−−− p o t e n t i a l , s e t here :
  V = 10.0 * abs ( x ) ;

whereas the file wellInfDbl.cpp contains the code

  / /−−−−−−− p o t e n t i a l , s e t here :
  i f ( abs ( x ) <= 0 . 3 )
      V = 100.0;
  else
      V = 0.0;

The analysis is performed in exactly the same way and the results are
shown in table 10.1. Note that, for large enough n, the energy levels of
all the potentials that we studied above tend to have identical values.
This happens because, when the particle has energy much larger than v0 ,
the details of the potential at the bottom do not influence its dynamical
properties very much. For the triangular potential, the energy levels have
higher values than the corresponding ones of the square potential. This
happens because, on the average, the potential energy is higher and the
potential tends to confine the particle to a smaller region (∆x is decreased,
therefore ∆p is increased). This can be seen in figure 10.3 where the wave
functions of the particle in each of the two potentials are compared.
    Similar observations can be made for the double well potential. More-
over, we note the approximately degenerate energy levels, something
which is expected for potentials of this form. This can be understood
in √terms of the localized states given √ by the wave functions ψ+ (x) =
(1/ 2)(ψ1 (x) + ψ2 (x)) and ψ− (x) = (1/ 2)(ψ1 (x) − ψ2 (x)). The first one
represents a state where the particle is localized in the left well and the
second one in the right. This is shown in figure 10.4. As v0 → +∞ the
two wells decouple and the wave functions ψ± (x) become equal to the en-
ergy eigenstate wave functions of two particles in separate infinite square
wells of width 1 − a with energy eigenvalues ϵ+,1 = ϵ−,1 = (π/(1 − a))2 .
The difference of ϵ1 and ϵ2 from these two values is due to the finite v0
(see problem 4).
    We will now discuss the limitations of this method. First, the method
can be used only on potential wells that are even, i.e. v(x) = v(−x). We
used this assumption in equations (10.21) and (10.22) giving the initial
conditions for states of well defined parity. When the potential is even,
10.3. BOUND STATES                                                                                                  419

                   1.2                                                  1.5
                                                 Square                                               Square
                                                Triangle                                             Triangle

                     1
                                                                          1


                   0.8
                                                                        0.5


                   0.6
           ψ1(x)




                                                               ψ2(x)
                                                                          0

                   0.4


                                                                        -0.5
                   0.2


                                                                         -1
                     0



                   -0.2                                                 -1.5
                          -1   -0.5   0   0.5              1                   -1   -0.5   0   0.5              1
                                      x                                                    x

                     1                                                  1.5
                                                 Square                                               Square
                                                Triangle                                             Triangle


                                                                          1
                   0.5



                                                                        0.5

                     0
           ψ3(x)




                                                               ψ4(x)
                                                                          0


                   -0.5

                                                                        -0.5



                    -1
                                                                         -1




                   -1.5                                                 -1.5
                          -1   -0.5   0   0.5              1                   -1   -0.5   0   0.5              1
                                      x                                                    x

                   1.5                                                  1.5
                                                 Square                                               Square
                                                Triangle                                             Triangle


                     1                                                    1




                   0.5                                                  0.5
                                                               ψ12(x)
           ψ8(x)




                     0                                                    0




                   -0.5                                                 -0.5




                    -1                                                   -1




                   -1.5                                                 -1.5
                          -1   -0.5   0   0.5              1                   -1   -0.5   0   0.5              1
                                      x                                                    x




Figure 10.3: The wave functions of the energy eigenstates of the infinite square and
triangular well potentials for n = 1, 2, 3, 4, 8, 12 given by equations (10.17) and (10.26)
with v0 = 10. We observe the influence of the shape of the potential on the wave
functions with small n, while for n ≥ 8 the influence becomes weaker.




the energy eigenstates have definite parity. The other problem can be
understood by solving problem 4: When v(0) ≫ ϵ, the wave function is
almost zero around x = 0 and the integration from x = 0 to x = 1 will be
dominated by numerical errors. The same is true when the particle has
to go through high potential barriers.


    This method can also we used on potential wells that are not infinite.
In that case we can add infinite walls at points that are far enough so
that the wave function is practically zero there. Then the influence of
this artificial wall will be negligible (see problem 3).
420                                    CHAPTER 10. SCHRÖDINGER EQUATION
                  2                                             2
                                               ψ+(x)                                       ψ-(x)
                                               ψ1(x)                                       ψ1(x)
                                               ψ2(x)                                       ψ2(x)
                1.5                                            1.5



                  1                                             1



                0.5                                            0.5



                  0                                             0



                -0.5                                       -0.5



                 -1                                             -1



                -1.5                                       -1.5
                       -1   -0.5   0     0.5           1             -1   -0.5   0   0.5           1
                                   x                                             x

                  2                                             2
                                               ψ+(x)                                       ψ-(x)
                                               ψ3(x)                                       ψ3(x)
                                               ψ4(x)                                       ψ4(x)
                1.5                                            1.5


                  1                                             1


                0.5                                            0.5


                  0                                             0


                -0.5                                       -0.5


                 -1                                             -1


                -1.5                                       -1.5


                 -2                                             -2
                       -1   -0.5   0     0.5           1             -1   -0.5   0   0.5           1
                                   x                                             x

                1.5                                            1.5
                                               ψ+(x)                                       ψ-(x)
                                               ψ5(x)                                       ψ5(x)
                                               ψ6(x)                                       ψ6(x)

                  1                                             1




                0.5                                            0.5




                  0                                             0




                -0.5                                       -0.5




                 -1                                             -1




                -1.5                                       -1.5
                       -1   -0.5   0     0.5           1             -1   -0.5   0   0.5           1
                                   x                                             x




                                                           √
Figure 10.4: The functions ψ± (x) = (1/ 2)(ψn (x) ± ψn+1 (x)) for n = 1, 3, 5 for the
double well potential (equation (10.27) with v0 = 100, a = 0.3) are plotted using bold red
lines. We observe that the more degenerate the states, the stronger the localization of the
particle to the left or right well. The other plots are those of the energy eigenfunctions
for n = 1, 2, 3, 4, 5, 6.



10.3 Bound States
A serious problem with the method discussed in the previous section is
that it is numerically unstable. You should have already realized that if
you tried to solve problem 3. In that problem, when the walls are moved
further than |x| = 3, the convergence of the algorithm becomes harder.
You can understand this by realizing that in the integration process the
solution is evolved from the classically allowed into the classically forbid-
den region so that an oscillating solution changes into an exponentially
damped one. But as |x| → +∞ there are two solutions, one that is phys-
ically acceptable ψ(x) ∼ e−k|x| and one that is diverging ψ(x) ∼ e+k|x|
which is not acceptable due to (10.2). Therefore, in order to achieve con-
vergence to the physically acceptable solution, the energy has to be finely
tuned, especially when we integrate towards large |x|. For this reason it
is preferable to integrate from the exponentially damped region towards
10.3. BOUND STATES                                                                    421




Figure 10.5: Integration of Schrödinger’s equation by the use of the algorithm of
section 10.3. The wave functions and their derivatives are given small trial values
at xmin and xmax which are in the classically forbidden regions of x. The point xm
is calculated from the equation v(xm ) = ϵ. The wave functions are evolved to xm
according to (10.24) and we obtain the solutions ψ (+) (x) and ψ (−) (x). We renormalize
ψ (−) (x) so that ψ (+) (xm ) = ψ (−) (xm ) and we vary the energy until the derivatives
ψ (+)′ (xm ) ≈ ψ (−)′ (xm ).



the oscillating region. The idea is to start integrating from these regions
and try to match the solutions and their derivatives at appropriately cho-
sen matching points. The matching is achieved at a point xm by trying
to determine the value of the energy that sets the ratio

                    ψ (+)′ (xm )/ψ (+) (xm ) − ψ (−)′ (xm )/ψ (−) (xm )
          f (ϵ) =                                                                (10.28)
                    ψ (+)′ (xm )/ψ (+) (xm ) + ψ (−)′ (xm )/ψ (−) (xm )

equal to zero, within the attainable numerical accuracy. It is desirable to
choose a point xm within the classical region (ϵ > v(x)) and usually we
pick a turning point ϵ = v(x). By renormalizing ψ (±) (x) we can always set
ψ (+) (xm ) = ψ (−) (xm ), therefore f (ϵ) ≪ 1 means that ψ (+)′ (xm ) ≈ ψ (−)′ (xm ).
The denominator of (10.28) sets the scale of the desired accuracy⁷ The
idea is depicted in figure 10.5. The algorithm is the following:

   • Choose the integration interval [xmin,xmax].
   ⁷If we are unlucky enough to pick a point where ψ ′ (xm ) = 0, this criterion will fail.
422                         CHAPTER 10. SCHRÖDINGER EQUATION

  • Choose the initial conditions ψ (−) (xmin), ψ (−)′ (xmin), ψ (+) (xmax),
    ψ (+)′ (xmax). This choice depends on the potential v(x). Usually
    we take xmin and xmax deep enough in the classically forbidden
    region and choose the values ψ (−) (xmin), ψ (+) (xmax) to be zero or
    exponentially small (e.g. ∼ e−k|x| , k 2 = v(x)−ϵ). The corresponding
    values of the derivatives ψ (−)′ (xmin), ψ (+)′ (xmax) are also taken to be
    small. The arbitrary normalization of ψ(x) allows these initial val-
    ues to be chosen in a crude way. The relative sign of the derivatives
    at large |x| (determined e.g. by the parity of the wave function for
    even potentials) is also taken care by the renormalization of ψ (−) (x)
    when applying the matching condition. For an infinite well, the
    points xmin,xmax are the ones where the potential becomes infinite
    and ψ (−) (xmin) = ψ (+) (xmax) = 0.

  • Choose the initial value of the energy ϵ and of the energy variation
    step δϵ.

  • Calculate xm from the initial value of the energy and the solution of
    v(x) = ϵ. Choose the solution that is at the left most side⁸.

  • Evolve the equations (10.24) from xmin to xm and obtain the solu-
    tions ψ (−) (x),ψ (−)′ (x).

  • Evolve the equations (10.24) from xmax to xm and obtain the solu-
    tions ψ (+) (x),ψ (+)′ (x).
                                     (                     )
  • Renormalize ψ (−) (x) → ψ (−) (x) ψ (+) (xm)/ψ (−) (xm) , so that ψ (+) (xm) =
    ψ (−) (xm).

  • Compute the ratio f (ϵ) of equation (10.28).

  • If |f (ϵ)| < δ for appropriately chosen δ > 0, the calculation ends.
    The result for the energy eigenvalue and eigenfunction is considered
    to be determined with adequate accuracy and we may proceed with
    the analysis of the results.

  • If f (ϵ) changes sign it means that we have crossed the energy eigen-
    value. Reverse the direction of search by taking δϵ → −δϵ/2.

  • Change the energy ϵ → ϵ+δϵ and repeat by going back to the fourth
    step.
  ⁸Note that this point changes when we vary ϵ
10.3. BOUND STATES                                                            423

When we exit the above loop, the current wave function is a good ap-
proximation to the eigenfunction ψn (x) corresponding to the eigenvalue
ϵn . We normalize the wave function according to equation (10.2) and we
calculate the expectation values according to (10.9). It is also interest-
ing to determine the number of nodes⁹ n0 of the wave function which is
related to n by n = n0 + 1.
     Our program needs to implement the Runge–Kutta algorithm. We use
the function RKSTEP (see page 203) which performs a 4th order Runge–
Kutta step. Its code is copied to the file rk.cpp.
     The potential v(x) is coded in the function V(x). The boundary con-
ditions are programmed in the function boundary(xmin, xmax, psixmin,
psipxmin, psixmax, psipxmax) which returns the values of psixmin =
ψ (−) (xmin), psipxmin = ψ (−)′ (xmin), psixmax = ψ (+) (xmax), psipxmax =
ψ (−)′ (xmax) to the calling program. These functions are put in a separate
file for each potential that we want to study. The name of the file is
related to the form of the potential, e.g. we choose schInfSq.cpp for the
infinite potential well of (10.17). The same file contains the code for the
functions f1, f2:

/ / ===========================================================
/ / f i l e : s c h I n f S q . cpp
/ / ===========================================================
/ /−−−−− p o t e n t i a l :
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
e x t e r n double energy ;
/ /−−−−−−−−
double V ( c o n s t double& x ) {
    return 0.0;
} / / V( )
/ /−−−−−−−− boundary c o n d i t i o n s :
void
boundary ( c o n s t double& xmin , c o n s t double& xmax                ,
                                double& psixmin ,     double& psipxmin ,
                                double& psixmax ,     double& psipxmax ) {
    / / f o r i n f i n i t e square w e l l we s e t p s i =0 a t boundary
    / / and p s i p =+/−1
    psixmin = 0 . 0 ;

   ⁹The number of points x for which ψ(x) = 0 and xmin < x < xmax. The relation
n = n0 + 1 sets ϵ1 to be the ground state for which n0 = 0.
424                               CHAPTER 10. SCHRÖDINGER EQUATION

  psipxmin = 1 . 0 ;
  psixmax = 0 . 0 ;
  psipxmax = −1.0;
  / / I n i t i a l v a l u e s a t xmin and xmax
}
/ /−−−−−−−− t r i v i a l f u n c t i o n : d e r i v a t i v e o f p s i
double
f1 ( c o n s t double& x , c o n s t double& psi , c o n s t double& psip ) {
    r e t u r n psip ;
}
/ /−−−−−−−− t h e second d e r i v a t i v e o f wavefunction :
/ / p s i p ( x ) ’ = p s i ( x ) ’ ’ = −(E−V) p s i ( x )
double
f2 ( c o n s t double& x , c o n s t double& psi , c o n s t double& psip ) {
    / /−−−−−−− S c h r o e d i n g e r eq : RHS
    r e t u r n ( V ( x )−energy ) * psi ;
}


We note that if the potential becomes infinite for x < xmin and/or x >xmax,
then this will be determined by the boundary conditions at xmin and/or
xmax.
   The main program is in the file sch.cpp. The code is listed below
and it includes the function integrate(psi, dx, Nx) used for the nor-
malization of the wave function. It performs a numerical integration of
the square of a function whose values psi[i] i=0,...,Nx-1 are given
at an odd number of Nx equally spaced points by a distance dx using
Simpson’s rule.

/ / ===========================================================
//
/ / F i l e : sch . cpp
//
/ / I n t e g r a t e 1d S c h r o d i n g e r e q u a t i o n from xmin t o xmax .
/ / Determine energy e i g e n v a l u e and e i g e n f u n c t i o n by matching
/ / e v o l v i n g s o l u t i o n s from xmin and from xmax a t a p o i n t xm.
/ / Mathing done by e q u a t i n g v a l u e s o f f u n c t i o n s and t h e i r
/ / d e r i v a t i v e s a t xm. The p o i n t xm chosen a t t h e l e f t most
/ / t u r n i n g p o i n t o f t h e p o t e n t i a l a t any gi v e n v a l u e o f t h e
/ / energy . The p o t e n t i a l and boundary c o n d i t i o n s chosen i n
// different file .
/ / −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/ / Input : energy : T r i a l v a l u e o f energy
//                  de : energy s t e p , i f matching f a i l s de −> e+de , i f
//                        l o g d e r i v a t i v e changes s i g n     de −> −de / 2
//                  xmin , xmax , Nx
/ / −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
10.3. BOUND STATES                                                                              425

/ / Output : F i n a l v a l u e o f energy , number o f nodes o f
//          wavefunction i n s t d o u t
//          F i n a l e i g e n f u n c t i o n i n f i l e p s i . dat
//          A l l t r i a l f u n c t i o n s and e n e r g i e s i n f i l e a l l . dat
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
c o n s t i n t P = 20001;
double energy ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
double V ( c o n s t double& x                                                          );
double integrate ( double * psi ,
                     c o n s t double& dx           , const int         & Nx            );
void
boundary ( c o n s t double& xmin , c o n s t double& xmax                               ,
                                 double& psixmin ,             double& psipxmin ,
                                 double& psixmax ,             double& psipxmax ) ;
void
RKSTEP (                         double& t                 ,   double& x1 ,
                                 double& x2                ,
                     c o n s t double& dt                                               );
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
i n t main ( ) {
    i n t Nx , NxL , NxR ;
    double psi [ P ] , psip [ P ] ;
    double dx ;
    double xmin , xmax , xm ; / / l e f t / r i g h t / matching p o i n t s
    double psixmin , psipxmin , psixmax , psipxmax ;
    double psileft , psiright , psistep , psinorm ;
    double psipleft , psipright , psipstep ;
    double de , epsilon ;
    double matchlogd , matchold , psiold , norm , x ;
    int          iter , i , imatch , nodes ;
    string buf ;
    / / Input :
    cout << ” # Enter energy , de , xmin , xmax , Nx: \ n” ;
    cin >> energy >>de>>xmin >>xmax >>Nx ; getline ( cin , buf ) ;
    / / need even i n t e r v a l s f o r n o r m a l i z a t i o n i n t e g r a t i o n :
    i f ( Nx       %2 == 0) Nx ++;
    i f ( Nx       >P        ) { cerr << ” Error : Nx > P                \n” ; exit ( 1 ) ; }
    i f ( xmin>=xmax ) { cerr << ” Error : xmin>=xmax\n” ; exit ( 1 ) ; }
    dx             = ( xmax−xmin ) / ( Nx −1) ;
    epsilon = 1 . 0 e−6;
    boundary ( xmin , xmax , psixmin , psipxmin , psixmax , psipxmax ) ;
426                            CHAPTER 10. SCHRÖDINGER EQUATION

 cout      <<” # #######################################\n” ;
 cout      <<” # E s t a r t = ”<< energy <<” de= ”<< de << ”\n” ;
 cout      <<” # Nx= ” << Nx <<” eps= ” << epsilon << ”\n” ;
 cout      <<” # xmin= ”<< xmin << ”xmax= ”<< xmax
           <<” dx= ”          << dx                                   << ”\n” ;
 cout <<” # p s i ( xmin )= ”<< psixmin
           <<” p s i p ( xmin )= ”<< psipxmin                         << ”\n” ;
 cout <<” # p s i ( xmax )= ”<< psixmax
           <<” p s i p ( xmax )= ”<< psipxmax                         << ”\n” ;
 cout <<” # #######################################\n” ;
 / / Calculate :
 ofstream myfile ( ” a l l . dat ” ) ;
 myfile . precision ( 1 7 ) ;
 cout . precision ( 1 7 ) ;
 matchold           = 0.0;
 f o r ( iter =1; iter <=10000; iter ++){
     / / Determine matching p o i n t a t t u r n i n g p o i n t from t h e l e f t :
     imatch=−1;
     f o r ( i =0;i<Nx ; i++){
         x = xmin + i * dx ;
         i f ( imatch < 0 && ( energy−V ( x ) ) > 0 . 0 ) imatch = i ;
     }
     i f ( imatch < 100 | | imatch >= Nx −100) imatch = Nx /5 −1;
     xm              = xmin + imatch * dx ;
     NxL             = imatch +1;
     NxR             = Nx−imatch ;
     / / Evolve wavefunction from t h e l e f t :
     psi [ 0 ] = psixmin ;
     psip [ 0 ] = psipxmin ;
     psistep         = psixmin ;
     psipstep = psipxmin ;
     f o r ( i =1; i<NxL ; i++){
         x           = xmin +(i−1) * dx ; / / t h i s i s x b e f o r e t h e s t e p
         RKSTEP ( x , psistep , psipstep , dx ) ;
         psi [ i ] = psistep ;
         psip [ i ] = psipstep ;
     }
     / / use t h i s t o normalize e i g e n f u n c t i o n t o match a t xm
     psinorm         = psistep ;
     psipleft = psipstep ;
     / / Evolve wavefunction from t h e r i g h t :
     psi [ Nx −1]= psixmax ;
     psip [ Nx −1]= psipxmax ;
     psistep         = psixmax ;
     psipstep = psipxmax ;
     f o r ( i =1; i<NxR ; i++){
         x           = xmax −(i−1) * dx ;
         RKSTEP ( x , psistep , psipstep ,−dx ) ;
         psi [ Nx−i−1] = psistep ;
10.3. BOUND STATES                                                           427

         psip [ Nx−i−1] = psipstep ;
     }
     psinorm            = psistep / psinorm ;
     psipright = psipstep ;
     / / Renormalize p s i l so t h a t p s i l (xm)= p s i r (xm)
     f o r ( i =0;i<NxL −1;i++){
         psi [ i ] *= psinorm ;
         psip [ i ] *= psinorm ;
     }
     psipleft *= psinorm ;
     / / print current solution :
     f o r ( i =0;i<Nx ; i++){
         x = xmin + i * dx ;
         myfile << iter <<” ”<<energy <<” ”
                       << x          <<” ”<<psi [ i]<< ” ”
                       <<psip [ i ]                     <<”\n” ;
     }
     / / matching using d e r i v a t i v e s :
     / / C a r e f u l : t h i s can f a i l i f p s i ’ (xm) = 0
     / / ( use a l s o | de | < 1 e−6 c r i t e r i o n )
     matchlogd =
         ( psipright−psipleft ) / ( abs ( psipright )+abs ( psipleft ) ) ;
     cout << ” # i t e r , energy , de , xm, logd : ”
               << iter               << ” ”
               << energy             << ” ”
               << de                 << ” ”
               << xm                 << ” ”
               << matchlogd << ”\n” ;
     / / break c o n d i t i o n :
     i f ( abs ( matchlogd )<=epsilon | |
           abs ( de / energy ) < 1 . 0 e−12           ) break ;
     i f ( matchlogd * matchold < 0.0 ) de = −0.5* de ;
     energy            += de ;
     matchold = matchlogd ;
 } / / f o r ( i t e r =1; i t e r <=10000; i t e r ++)
 myfile . close ( ) ;
 / /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
 / / S o l u t i o n has been found and now i t i s s t o r e d :
 norm = integrate ( psi , dx , Nx ) ;
 norm = 1 . 0 / sqrt ( norm ) ;
 / / f o r ( i =0; i <Nx ; i ++) p s i [ i ] *= norm ;
 / / Count number o f z e r o e s , add one and g e t energy l e v e l :
 nodes = 1 ;
 psiold = psi [ 0 ] ;
 f o r ( i =1; i<Nx −1;i++)
     i f ( abs ( psi [ i ] )          > epsilon ) {
         i f ( psiold * psi [ i ] < 0.0             ) nodes ++;
         psiold = psi [ i ] ;
     }
428                                  CHAPTER 10. SCHRÖDINGER EQUATION

    / / Print final solution :
    myfile . open ( ” p s i . dat ” ) ;
    cout << ” F i n a l r e s u l t : E= ” << energy
              << ” n= ”                               << nodes
              << ” norm= ”                            << norm         << endl ;
    i f ( abs ( matchlogd ) > epsilon )
        cout << ” F i n a l r e s u l t : SOS : logd > e p s i l o n . logd= ”
                  << matchlogd                                        << endl ;
    myfile << ” # E= ”                                << energy
                  << ” n= ”                           << nodes
                  << ” norm = ”                       << norm         << endl ;
    f o r ( i =0;i<Nx ; i++){
        x = xmin + i * dx ;
        myfile << x << ” ”                          << psi [ i ] << ”\n” ;
    }
    myfile . close ( ) ;
} / / main ( )
/ / ========================================================
/ / Simpson ’ s r u l e t o i n t e g r a t e p s i ( x ) * p s i ( x ) f o r proper
/ / n o r m a l i z a t i o n . For n i n t e r v a l s o f width dx ( n even )
/ / Simpson ’ s r u l e i s :
/ / i n t ( f ( x ) dx ) =
/ / ( dx / 3 ) * ( f ( x_0 ) +4 f ( x_1 ) +2 f ( x_2 ) + . . . + 4 f ( x_ {n−1})+ f ( x_n ) )
//
/ / Input :          D i s c r e t e v a l u e s o f f u n c t i o n p s i [ Nx ] , Nx i s odd
//                   I n t e g r a t i o n s t e p dx
/ / Returns : I n t e g r a l ( p s i ( x ) p s i ( x ) dx )
/ / ========================================================
double integrate ( double * psi ,
                     c o n s t double& dx , c o n s t i n t& Nx ) {
    double Integral ;
    int           i;
    / / z e r o t h order p o i n t :
    i                  = 0;
    Integral = psi [ i ] * psi [ i ] ;
    / / odd order p o i n t s :
    f o r ( i =1; i<=Nx −2;i+=2) Integral += 4 . 0 * psi [ i ] * psi [ i ] ;
    / / even order p o i n t s :
    f o r ( i =2;i<=Nx −3;i+=2) Integral += 2 . 0 * psi [ i ] * psi [ i ] ;
    / / l a s t point :
    i                  = Nx −1;
    Integral += psi [ i ] * psi [ i ] ;
    / / measure n o r m a l i z a t i o n :
    Integral *= dx / 3 . 0 ;

    r e t u r n Integral ;
} / / integrate ()

The reproduction of the results of the previous section for the infinite
10.3. BOUND STATES                                                                           429

potential well is left as an exercise. The compilation and running of the
program can be done with the commands:

> g++ sch . cpp schInfSq . cpp rk . cpp −o s
> ./s
# Enter energy , de , xmin , xmax , Nx :
1 0.5 −1 1 2000
# #######################################
# Estart=          1       de=        0.5
# Nx=              2001 eps= 1 e−06
# xmin=          −1        xmax= 1 dx= 0.001
# p s i ( xmin )= 0        p s i p ( xmin )= 1
# p s i ( xmax )= 0        p s i p ( xmax )= −1
# #######################################
# i t e r , energy , de , xm, logd : 1 1.0000 0.500         −0.601 −0.9748
# i t e r , energy , de , xm, logd : 2 1.5000 0.500         −0.601 −0.6412
.....
# i t e r , energy , de , xm, logd : 30 2.4674 −3.815E−6 −0.601 −1.0E−6
# i t e r , energy , de , xm, logd : 31 2.4674 1 . 9 0 7E−6 −0.601 2 . 7E−7
Final result : E= 2.467401504516602 n= 1 norm = 1.5707965025



We set xmin= -1, xmax = 1, Nx= 2000 and ϵ = 1, δϵ = 0.5. The energy
of the ground state is found to be ϵ1 = 2.4674015045166016. The wave
function is stored in the file psi.dat and can be plotted with the gnuplot
command

gnuplot > p l o t ” p s i . dat ” using 1 : 2 with lines



The functions computed during the iterations of the algorithm are stored
in the file all.dat. The first column is the iteration number (here we
have iter = 0, ... 31) and we can easily filter each one of them with
the commands

gnuplot >   plot     ”<awk   ’ $1 ==1’   all   . dat ”   using   3:4   w   l   t   ” i t e r =1”
gnuplot >   replot   ”<awk   ’ $1 ==2’   all   . dat ”   using   3:4   w   l   t   ” i t e r =2”
gnuplot >   replot   ”<awk   ’ $1 ==3’   all   . dat ”   using   3:4   w   l   t   ” i t e r =3”
gnuplot >   replot   ”<awk   ’ $1 ==4’   all   . dat ”   using   3:4   w   l   t   ” i t e r =4”
.....



which reproduce figure 10.6.
430                               CHAPTER 10. SCHRÖDINGER EQUATION

                   1
                                                             iter=1
                  0.9                                        iter=2
                                                             iter=3
                  0.8                                        iter=4
                  0.7
                  0.6
           ψ(x)


                  0.5
                  0.4
                  0.3
                  0.2
                  0.1
                   0
                        -1          -0.5        0             0.5      1
                                                x

Figure 10.6: The convergence of the solutions to the solution of Schrödinger’s equa-
tion for the ground state of the infinite potential well according to the discussion on
page 429.




10.4 Measurements
The action of an operator Â(x̂, p̂) on a state |ψ⟩ can be easily calculated
in the position representation by its action on the corresponding wave
function ψ(x). The action of the operators

                                                             ∂
                        x̂ψ(x) = xψ(x)        p̂ψ(x) = −i       ψ(x)         (10.29)
                                                             ∂x

yield¹⁰
                                                        ∂
                             Â(x̂, p̂)ψ(x) = A(x, −i      )ψ(x) .           (10.30)
                                                        ∂x
Using equation (10.9) we can calculate the expectation value ⟨A⟩ of the
operator A when the system is at the state |ψ⟩. Interesting examples
are the observables “position” x, “position squared” x2 , “momentum”
p, “momentum squared” p2 , “kinetic energy” T , “potential energy” V ,
“energy” or “Hamiltonian” H = T + V whose expectation values are

  ¹⁰We do not consider ordering problems of operators formed by products of non
commuting operators, e.g. xp2 .
10.4. MEASUREMENTS                                                       431

given by the relations
                     ∫   +∞
            ⟨x⟩ =             ψ ∗ (x) x ψ(x) dx
                      −∞
                     ∫ +∞
           ⟨x2 ⟩ =         ψ ∗ (x) x2 ψ(x) dx
                      −∞
                     ∫ +∞          (        )
                             ∗           ∂
            ⟨p⟩ =          ψ (x) −i           ψ(x) dx
                      −∞                 ∂x
                     ∫ +∞          (        )
                             ∗          ∂2
           ⟨p2 ⟩ =         ψ (x) − 2 ψ(x) dx
                      −∞                ∂x
                           ∫ +∞            (      )
                       ℏ 2
                                     ∗         ∂2
            ⟨T ⟩ =                 ψ (x) − 2 ψ(x) dx
                     2mL2 −∞                  ∂x
                           ∫ +∞
                       ℏ 2
           ⟨V ⟩ =                  ψ ∗ (x) v(x) ψ(x) dx
                     2mL2 −∞
                           ∫ +∞            (            )
                       ℏ2            ∗         ∂2
           ⟨H⟩ =                   ψ (x) − 2 + v(x) ψ(x) dx .        (10.31)
                     2mL2 −∞                  ∂x

We remind the reader that we used the dimensionless x, p as well as
equations (10.15) and (10.16). Especially interesting are the “uncertain-
ties” ∆x2 = ⟨x2 ⟩ − ⟨x⟩2 , ∆p2 = ⟨p2 ⟩ − ⟨p⟩2 that satisfy the inequality
(“Heisenberg’s uncertainty relation”)

                                                  1
                                  ∆x · ∆p ≥         .                (10.32)
                                                  2
In the previous section we described how to calculate numerically the
eigenfunctions of the Hamiltonian. If Ĥψ(x) = Eψ(x), we obtain that
⟨H⟩ = (1/2mL2 )ϵ. Other operators need a numerical approximation for
the calculation of their expectation values. If the values of the wave
function are given at N equally spaced points x1 , x2 , . . . , xN , then we
obtain
                       ∂ψ(xi )   ψ(xi+1 ) − ψ(xi−1 )
                               ≈                                      (10.33)
                         ∂x              2h
where h = xi+1 − xi and

                  ∂ 2 ψ(xi )   ψ(xi+1 ) − 2ψ(xi ) + ψ(xi−1 )
                        2
                             ≈                               .       (10.34)
                     ∂x                     h2
Both equations entail an error of the order of O(h2 ). Special care should
be taken at the endpoints of the interval [x1 , xN ]. As a first approach we
432                          CHAPTER 10. SCHRÖDINGER EQUATION

will use the naive approximations¹¹

                        ∂ψ(x1 )   ψ(x2 ) − ψ(x1 )
                                ≈
                          ∂x             h
                        ∂ψ(xN )   ψ(xN ) − ψ(xN −1 )
                                ≈                                         (10.35)
                          ∂x               h
and
                 ∂ 2 ψ(x1 )   ψ(x3 ) − 2ψ(x2 ) + ψ(x1 )
                       2
                            ≈
                    ∂x                   h2
                  2
                ∂ ψ(xN )      ψ(xN ) − 2ψ(xN −1 ) + ψ(xN −2 )
                            ≈                                 .           (10.36)
                    ∂x2                     h2
The relevant program that calculates ⟨x⟩, ⟨x2 ⟩, ⟨p⟩, ⟨p2 ⟩, ∆x, ∆p can be
found in the file observables.cpp and is listed below:

/ / ===========================================================
//
/ / F i l e o b s e r v a b l e s . cpp
/ / Compile : g++ o b s e r v a b l e s . cpp −o o
/ / Usage :           . / o < p s i . dat >
//
/ / Read i n a f i l e with a wavefunction i n t h e format o f p s i . dat :
/ / # E= <energy > . . . .
/ / x1 p s i ( x1 )
/ / x2 p s i ( x2 )
// . . . . . . . . . . . .
//
/ / Outputs e x p e c t a t i o n v a l u e s :
/ / n o r m a l i z a t i o n Energy <x> <p> <x^2> <p^2> Dx Dp DxDp
/ / where Dx = s q r t ( < x^2>−<x >^2) Dp = s q r t ( <p^2>−<p>^2)
/ / DxDp = Dx * Dp
//
/ / ===========================================================
# i n c l u d e < iostream >
# i n c l u d e < fstream >
# include <cstdlib >
# include <string >
# i n c l u d e <cmath>
using namespace std ;
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

   ¹¹See the files observables.cpp, Derivatives.nb of the accompanying software.
There you can find formulas that have errors of O(h2 ). In the examples discussed
below, the influence of the O(h) error on the results is approximately at the fourth
significant digit.
10.4. MEASUREMENTS                                                             433

double integrate ( double * psi ,
            c o n s t double& dx , const int & Nx    );
/ /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

i n t main ( i n t argc , char * * argv ) {
    c o n s t i n t P = 50000;
    int         Nx , i ;
    double xstep [ P ] , psi [ P ] , obs [ P ] ;
    double xav , pav , x2av , p2av , Dx , Dp , DxDp , energy , h , norm ;
    string buf ;
    char        * psifile ;

  i f ( argc != 2) {
      cerr << ” Usage : ” << argv [ 0 ] << ” < fi l e n a m e >\n” ;
      exit ( 1 ) ;
  }
  psifile = argv [ 1 ] ;
  ifstream ifile ( psifile ) ;
  i f ( ! ifile ) {
      cerr << ” Error r e a d i n g from f i l e ” << psifile << endl ;
      exit ( 1 ) ;
  }
  cout << ” # r e a d i n g wavefunction from f i l e : ”
             << psifile << endl ;
  ifile >> buf >> buf >> energy ; getline ( ifile , buf ) ;
  / /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
  / / Input data : p s i [ x ]
  Nx = 0 ;
  while ( ifile >> xstep [ Nx ] >> psi [ Nx ] ) {
      Nx ++;
      i f ( Nx == P ) { cerr << ”Too many p o i n t s \n” ; exit ( 1 ) ; }
  }
  i f ( Nx % 2 == 0) Nx−−;
  h = ( xstep [ Nx−1]−xstep [ 0 ] ) / ( Nx −1) ;
  / /−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
  / / Calculate :
  / /−−−−−−−−−− norm :
  f o r ( i =0;i<Nx ; i++) obs [ i ] = psi [ i ] * psi [ i ] ;
  norm= integrate ( obs , h , Nx ) ;
  / /−−−−−−−−−− <x> :
  f o r ( i =0;i<Nx ; i++) obs [ i ] = psi [ i ] * psi [ i ] * xstep [ i ] ;
  xav = integrate ( obs , h , Nx ) / norm ;
  / /−−−−−−−−−− <p > / i :
  obs [ 0 ] = psi [ 0 ] * ( psi [1] − psi [ 0 ] ) / h ;
  f o r ( i =1; i<Nx −1;i++)
      obs [ i ] = psi [ i ] * ( psi [ i+1]−psi [ i −1]) / ( 2 . 0 * h ) ;
  obs [ Nx −1]=psi [ Nx − 1 ] * ( psi [ Nx−1]−psi [ Nx −2]) / h ;
  pav = −integrate ( obs , h , Nx ) / norm ;
  / /−−−−−−−−−− <x ^2 >:
434                                  CHAPTER 10. SCHRÖDINGER EQUATION

   f o r ( i =0;i<Nx ; i++) obs [ i ] = psi [ i ] * psi [ i ] * xstep [ i ] * xstep [ i ] ;
   x2av= integrate ( obs , h , Nx ) / norm ;
   / /−−−−−−−−−− <p^2 >:
   obs [ 0 ] = psi [ 0 ] * ( psi [2] −2.0* psi [ 1 ] + psi [ 0 ] ) / ( h * h ) ;
   f o r ( i =1; i<Nx −1;i++)
       obs [ i ] = psi [ i ] * ( psi [ i +1] −2.0* psi [ i ]+ psi [ i −1]) / ( h * h ) ;
   obs [ Nx −1] = psi [ Nx −1] *
           ( psi [ Nx −1] −2.0* psi [ Nx−2]+psi [ Nx −3]) / ( h * h ) ;
   p2av= −integrate ( obs , h , Nx ) / norm ;
   / /−−−−−−−−−− Dx
   Dx = sqrt ( x2av − xav * xav ) ;
   / /−−−−−−−−−− Dp
   Dp = sqrt ( p2av − pav * pav ) ;
   / /−−−−−−−−−− Dx . Dp
   DxDp = Dx * Dp ;
   / / Print results :
   cout . precision ( 1 7 ) ;
   cout << ” # norm E <x> <p > / i <x^2> <p^2> Dx Dp DxDp\n” ;
   cout << norm            << ” ”
             << energy << ” ”
             << xav        << ” ”
             << pav        << ” ”
             << x2av       << ” ”
             << p2av       << ” ”
             << Dx         << ” ”
             << Dp         << ” ”
             << DxDp       << endl ;

} / / main ( )
/ / ========================================================
/ / Simpson ’ s r u l e t o i n t e g r a t e p s i ( x ) .
/ / For n i n t e r v a l s o f width dx ( n even )
/ / Simpson ’ s r u l e i s :
/ / i n t ( f ( x ) dx ) =
/ / ( dx / 3 ) * ( f ( x_0 ) +4 f ( x_1 ) +2 f ( x_2 ) + . . . + 4 f ( x_ {n−1})+ f ( x_n ) )
//
/ / Input :          D i s c r e t e v a l u e s o f f u n c t i o n p s i [ Nx ] , Nx i s odd
//                   I n t e g r a t i o n s t e p dx
/ / Returns : I n t e g r a l ( p s i ( x ) dx )
/ / ========================================================
double integrate ( double * psi ,
                     c o n s t double& dx , c o n s t i n t& Nx ) {
    double Integral ;
    int           i;
    / / z e r o t h order p o i n t :
    i                  = 0;
    Integral = psi [ i ] ;
    / / odd order p o i n t s :
    f o r ( i =1; i<=Nx −2;i+=2) Integral += 4 . 0 * psi [ i ] ;
10.4. MEASUREMENTS                                                            435

  / / even order p o i n t s :
  f o r ( i =2;i<=Nx −3;i+=2) Integral += 2 . 0 * psi [ i ] ;
  / / l a s t point :
  i              = Nx −1;
  Integral += psi [ i ] ;
  / / measure n o r m a l i z a t i o n :
  Integral *= dx / 3 . 0 ;

    r e t u r n Integral ;
} / / integrate ()

The program needs to read in the wave function at the points x0 , . . . , xNx−1
in the format produced by the program in sch.cpp. The first line should
have the energy written at the 3rd column, whereas from the 2nd line
and on there should be two columns with the (xi , ψ(xi )) pairs. It is not
necessary to have the wave function properly normalized, the program
will take care of it. If this data is stored in a file psi.dat, then the
program can be used by running the commands

> g++ observables . cpp −o obs
> . / obs psi . dat

The program prints the normalization constant of ψ(x), the value of the
energy¹², ⟨x⟩, ⟨x2 ⟩, ⟨p⟩/i, ⟨p2 ⟩, ∆x, ∆p and ∆x · ∆p to the stdout.
    Some details about the program: In order to read in the data from
the file psi.dat we use the variables argc and argv. These contain
the information on the number of arguments and the arguments of the
command line. If the command line comprises of n words, then argc=n.
These words are stored in an array of C-style strings argv[0], argv[1], ...
, argv[argc-1]. The first argument argv[0] is the name of the program,
therefore the lines

  i f ( argc != 2) {
      cerr << ” Usage : ” << argv [ 0 ] << ”        < fi l e n a m e >\n” ;
      exit ( 1 ) ;
  }

check if there are two arguments on the command line, including the
path to the executable file. If not, it prints an error message containing
the name of the program and exits:


  ¹²The one read from the file. It is not calculated from the data.
436                            CHAPTER 10. SCHRÖDINGER EQUATION

> ./o
Usage : . / o   <filename >

The variables argc and argv must be declared as arguments to the main()
function:

i n t main ( i n t argc , char * * argv ) {
      .....
}

The variable argv is an array of C-style strings¹³, i.e. and array of an
array of characters and can be declared as a pointer to a pointer to char.
   The statements

  ifstream ifile ( ” p s i . dat ” ) ;
  i f ( ! ifile ) { exit ( 1 ) ; }

attempt to open a file psi.dat for input and, if this fails, the program is
terminated.
    The statements

  Nx = 0 ;
  while ( ifile >> xstep [ Nx ] >> psi [ Nx ] ) { Nx ++;}

read in a pair of doubles and store them in the arrays xstep and psi.
The loop terminates when it reaches the end of file or when it fails to
read input that can be converted to two doubles. In the end, Nx stores
the number of pairs read into the arrays.
   The rest of the commands are applications of equations (10.33), (10.34),
(10.35) and (10.36) to the formulas (10.31) and the reader is asked to
study them carefully. The program uses the function integrate in order
to perform the necessary integrals.


10.5 The Anharmonic Oscillator - Again...
In the previous chapter 9 we studied the quantum mechanical harmonic
and anharmonic oscillator in the representation of the energy eigenstates
   ¹³A C-style string, not to be confused with variables declared as string, is an array
of “null terminated” characters. This means that the sequence of characters ends with
the character '\0'. Functions that treat such objects, detect the end of the string using
this convention.
10.5. THE ANHARMONIC OSCILLATOR - AGAIN...                                         437

of the harmonic oscillator |n⟩. In this section we will revisit the problem
by using the position representation. We will calculate the eigenfunctions
ψn,λ (x) that diagonalize the Hamiltonian (9.15),
                                               √ which are the solutions
of the Schrödinger equation. By setting L = ℏ/mω in equation (10.13),
equation (10.12) becomes

                              ψ ′′ (x) = −(ϵ − v(x))ψ(x) ,                     (10.37)

where v(x) = x2 + 2λx4 . For λ = 0 we obtain the harmonic oscillator with
                                                   (      )
                     1       −x2 /2                     1
        ψn (x) = √       √ e        Hn (x) , ϵn = 2 n +     ,     (10.38)
                   2n n! π                              2
where Hn (x) are the Hermite polynomials.
    We start with the simple harmonic oscillator where the exact solution
is known. The potential and the initial conditions are programmed in
the file schHOC.cpp. The changes that we need to make concern the
functions V(x), boundary(xmin, xmax, psixmin, psipxmin, psixmax,
psipxmax):

/ / ===========================================================
/ / f i l e : schHOC . cpp
................
double V ( c o n s t double& x ) {
    return x*x ;
}
/ /−−−−−−−− boundary c o n d i t i o n s :
void
boundary ( c o n s t double& xmin , c o n s t double& xmax     ,
                         double& psixmin ,    double& psipxmin ,
                         double& psixmax ,    double& psipxmax ) {

  psixmin     = exp ( −0.5* xmin * xmin ) ;
  psipxmin    = −xmin * psixmin ;
  psixmax     = exp ( −0.5* xmax * xmax ) ;
  psipxmax    = −xmax * psixmax ;
}
...............

    The code omitted at the dots is identical to the one discussed in
the previous section. The initial conditions are inspired by the asymp-
totic behavior of the solutions to Schrödinger’s¹⁴ equation ψ0 (x) ∼ e−x /2 ,
                                                                        2




   ¹⁴In fact ψn (x) ∼ xn e−x /2 which we neglect. This does not influence the results for
                          2


the values of n studied here. Examine if this is necessary for larger values of n.
438                                                        CHAPTER 10. SCHRÖDINGER EQUATION

ψn′ (x) ∼ −xψn (x). You are encouraged to test the influence of other
choices on the results. The results are depicted in figure 10.7 where, be-

              0.8                                                                             3e-11
                                                                ε0=1
              0.7                                                                           2.5e-11
                                                                                              2e-11
              0.6
                                                                                            1.5e-11
              0.5                                                                             1e-11




                                                                                   ∆ψ0(x)
      ψ0(x)




              0.4                                                                             5e-12

              0.3                                                                                 0
                                                                                             -5e-12
              0.2
                                                                                             -1e-11
              0.1                                                                           -1.5e-11
                0                                                                            -2e-11
                     -6        -4        -2        0       2           4       6                       -6    -4        -2    0       2       4       6
                                                   x                                                                         x

              0.6                                                                           1.2e-07
                                                               ε0=19
                                                                                              1e-07
              0.4
                                                                                              8e-08
                                                                                              6e-08
              0.2
                                                                                              4e-08
                                                                                   ∆ψ9(x)
      ψ9(x)




                0                                                                             2e-08
                                                                                                  0
              -0.2
                                                                                             -2e-08
                                                                                             -4e-08
              -0.4
                                                                                             -6e-08
              -0.6                                                                           -8e-08
                     -8   -6        -4        -2   0   2         4         6   8                       -8   -6    -4    -2   0   2       4       6   8
                                                   x                                                                         x



Figure 10.7: The eigenfunctions ψ0 (x), ψ9 (x) calculated by the program in sch.cpp,
schHOC.cpp. The plot to the right shows the difference of the results from the known
values (10.38).


sides the qualitative agreement, their difference from the known values
(10.38) is also shown. This difference turns out to be of the order of
10−11 –10−7 . The values of the energy ϵn for n ≤ 14 are in agreement with
(10.38) with relative accuracy better than 10−9 .
   Then we calculate the expectation values ⟨x⟩, ⟨x2 ⟩, ⟨p⟩, ⟨p2 ⟩, ∆x and
∆p. These are easily calculated
                        √         using equations (9.4)  √ and (9.8). We see
that ⟨x⟩ = ⟨n| (a† + a)/ 2 |n⟩ = 0, ⟨p⟩ = ⟨n| i(a† − a)/ 2 |n⟩ = 0, whereas
                                                 (       )
                             1 †        †              1
           ⟨x ⟩ = ⟨p ⟩ = ⟨n| (a a + aa ) |n⟩ = n +
              2     2
                                                           .          (10.39)
                             2                         2

The program observables.cpp calculates ⟨x⟩ = 0 with accuracy ∼ 10−6
and ⟨p⟩ = 0 with accuracy ∼ 10−11 . The expectation values ⟨x2 ⟩, ⟨p2 ⟩ are
shown in table 10.2.
    Next, the calculation is repeated for the anharmonic oscillator for λ =
0.5, 2.0. We copy the file schHOC.cpp to schUOC.cpp and change the
potential in the function V(x):
10.5. THE ANHARMONIC OSCILLATOR - AGAIN...                                       439

                  n      ⟨x2 ⟩       ⟨p2 ⟩    ∆x · ∆p
                  0 0.500000000   0.4999977 0.4999989
                  1  1.500000284  1.4999883  1.4999943
                  2  2.499999747  2.4999711  2.4999854
                  3  3.499999676  3.4999441  3.4999719
                  4  4.499999607 4.4999082   4.4999539
                  5 5.499999520 5.4998633    5.4999314
                  6 6.499999060 6.4998098    6.4999044
                  7  7.499999642  7.4995484   7.4997740
                  8  8.499999715 8.4994203   8.4997100
                  9  9.499999837  9.4992762 9.4996380
                 10 10.500000012 10.4991160 10.4995580
                 11 11.499999542 11.4994042 11.4997019
                 12 12.499999610 12.4992961 12.4996479
                 13 13.499999705 13.4991791 13.4995894
                 14 14.499999835 14.4990529 14.4995264


Table 10.2: The expectation values ⟨x