0% found this document useful (0 votes)
22 views80 pages

Numerical Python in Astronomy and Astrophysics A Practical Guide To Astrophysical Problem Solving Undergraduate Lecture Notes in Physics 1st Ed 2021 Wolfram Schmidt Download

The document is a guide titled 'Numerical Python in Astronomy and Astrophysics' by Wolfram Schmidt and Marcel Völschow, aimed at teaching undergraduate students how to solve astrophysical problems using Python. It emphasizes the importance of programming in modern astrophysics and provides practical examples and exercises to enhance understanding of numerical computation and data analysis. The book is part of the Undergraduate Lecture Notes in Physics series, which aims to offer clear and engaging resources for physics education.

Uploaded by

parwalrumayi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views80 pages

Numerical Python in Astronomy and Astrophysics A Practical Guide To Astrophysical Problem Solving Undergraduate Lecture Notes in Physics 1st Ed 2021 Wolfram Schmidt Download

The document is a guide titled 'Numerical Python in Astronomy and Astrophysics' by Wolfram Schmidt and Marcel Völschow, aimed at teaching undergraduate students how to solve astrophysical problems using Python. It emphasizes the importance of programming in modern astrophysics and provides practical examples and exercises to enhance understanding of numerical computation and data analysis. The book is part of the Undergraduate Lecture Notes in Physics series, which aims to offer clear and engaging resources for physics education.

Uploaded by

parwalrumayi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 80

Numerical Python In Astronomy And Astrophysics A

Practical Guide To Astrophysical Problem Solving


Undergraduate Lecture Notes In Physics 1st Ed
2021 Wolfram Schmidt download
https://ebookbell.com/product/numerical-python-in-astronomy-and-
astrophysics-a-practical-guide-to-astrophysical-problem-solving-
undergraduate-lecture-notes-in-physics-1st-ed-2021-wolfram-
schmidt-33555710

Explore and download more ebooks at ebookbell.com


Here are some recommended products that we believe you will be
interested in. You can click the link to download.

Numerical Python In Astronomy And Astrophysics A Practical Guide To


Astrophysical Problem Solving Wolfram Schmidt Marcel Vlschow

https://ebookbell.com/product/numerical-python-in-astronomy-and-
astrophysics-a-practical-guide-to-astrophysical-problem-solving-
wolfram-schmidt-marcel-vlschow-33555706

Mathematical Modeling The Life Sciences Numerical Recipes In Python


And Matlab N G Cogan

https://ebookbell.com/product/mathematical-modeling-the-life-sciences-
numerical-recipes-in-python-and-matlab-n-g-cogan-44875372

Analog Circuit Simulators For Integrated Circuit Designers Numerical


Recipes In Python Mikael Sahrling

https://ebookbell.com/product/analog-circuit-simulators-for-
integrated-circuit-designers-numerical-recipes-in-python-mikael-
sahrling-23843882

Creditrisk Modelling Theoretical Foundations Diagnostic Tools


Practical Examples And Numerical Recipes In Python 1st Ed 2018 Bolder

https://ebookbell.com/product/creditrisk-modelling-theoretical-
foundations-diagnostic-tools-practical-examples-and-numerical-recipes-
in-python-1st-ed-2018-bolder-54550698
Numerical Computing With Python Harness The Power Of Python To Analyze
And Find Hidden Patterns In The Data 1st Edition Pratap Dangeti Allen
Yu Claire Chung Aldrin Yim Theodore Petrou

https://ebookbell.com/product/numerical-computing-with-python-harness-
the-power-of-python-to-analyze-and-find-hidden-patterns-in-the-
data-1st-edition-pratap-dangeti-allen-yu-claire-chung-aldrin-yim-
theodore-petrou-7351196

Numerical Methods In Physics With Python 2nd Edition 2nd Alex Gezerlis

https://ebookbell.com/product/numerical-methods-in-physics-with-
python-2nd-edition-2nd-alex-gezerlis-51984566

Numerical Methods In Engineering With Python Kiusalaas Jaan

https://ebookbell.com/product/numerical-methods-in-engineering-with-
python-kiusalaas-jaan-22004446

Numerical Methods In Engineering With Python Jaan Kiusalaas

https://ebookbell.com/product/numerical-methods-in-engineering-with-
python-jaan-kiusalaas-2284648

Numerical Methods In Engineering With Python 2nd Ed Jaan Kiusalaas

https://ebookbell.com/product/numerical-methods-in-engineering-with-
python-2nd-ed-jaan-kiusalaas-4104826
Undergraduate Lecture Notes in Physics

Wolfram Schmidt
Marcel Völschow

Numerical
Python in
Astronomy and
Astrophysics
A Practical Guide to Astrophysical
Problem Solving
Undergraduate Lecture Notes in Physics

Series Editors
Neil Ashby, University of Colorado, Boulder, CO, USA
William Brantley, Department of Physics, Furman University, Greenville, SC, USA
Matthew Deady, Physics Program, Bard College, Annandale-on-Hudson, NY, USA
Michael Fowler, Department of Physics, University of Virginia, Charlottesville,
VA, USA
Morten Hjorth-Jensen, Department of Physics, University of Oslo, Oslo, Norway
Michael Inglis, Department of Physical Sciences, SUNY Suffolk County
Community College, Selden, NY, USA
Barry Luokkala , Department of Physics, Carnegie Mellon University, Pittsburgh,
PA, USA
Undergraduate Lecture Notes in Physics (ULNP) publishes authoritative texts
covering topics throughout pure and applied physics. Each title in the series is
suitable as a basis for undergraduate instruction, typically containing practice
problems, worked examples, chapter summaries, and suggestions for further reading.
ULNP titles must provide at least one of the following:
• An exceptionally clear and concise treatment of a standard undergraduate
subject.
• A solid undergraduate-level introduction to a graduate, advanced, or
non-standard subject.
• A novel perspective or an unusual approach to teaching a subject.
ULNP especially encourages new, original, and idiosyncratic approaches to physics
teaching at the undergraduate level.
The purpose of ULNP is to provide intriguing, absorbing books that will continue
to be the reader’s preferred reference throughout their academic career.

More information about this series at http://www.springer.com/series/8917


Wolfram Schmidt Marcel Völschow

Numerical Python
in Astronomy
and Astrophysics
A Practical Guide to Astrophysical Problem
Solving

123
Wolfram Schmidt Marcel Völschow
Hamburg Observatory Hamburg University of Applied Sciences
University of Hamburg Hamburg, Germany
Hamburg, Germany

ISSN 2192-4791 ISSN 2192-4805 (electronic)


Undergraduate Lecture Notes in Physics
ISBN 978-3-030-70346-2 ISBN 978-3-030-70347-9 (eBook)
https://doi.org/10.1007/978-3-030-70347-9
© Springer Nature Switzerland AG 2021
This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part
of the material is concerned, specifically the rights of translation, reprinting, reuse of illustrations,
recitation, broadcasting, reproduction on microfilms or in any other physical way, and transmission
or information storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar
methodology now known or hereafter developed.
The use of general descriptive names, registered names, trademarks, service marks, etc. in this
publication does not imply, even in the absence of a specific statement, that such names are exempt from
the relevant protective laws and regulations and therefore free for general use.
The publisher, the authors and the editors are safe to assume that the advice and information in this
book are believed to be true and accurate at the date of publication. Neither the publisher nor the
authors or the editors give a warranty, expressed or implied, with respect to the material contained
herein or for any errors or omissions that may have been made. The publisher remains neutral with regard
to jurisdictional claims in published maps and institutional affiliations.

This Springer imprint is published by the registered company Springer Nature Switzerland AG
The registered company address is: Gewerbestrasse 11, 6330 Cham, Switzerland
Preface

Over the last decades the work of astronomers and astrophysicists has undergone
great changes. Making observations is an essential part of astronomy, but most
researchers do not operate instruments directly any longer. Most of the time they
receive huge amounts of data from remote or even space-bound telescopes and
make heavy use of computing power to filter, process, and analyse these data. This
requires sophisticated algorithms and, these days, increasingly utilizes machine
learning. On the theoretical side of astrophysics, making important discoveries just
with pencil and paper belongs to the past (with the occasional exception from the
rule). Scientific questions in contemporary astrophysics are often too complex to
allow for analytic solutions. As a consequence, numerical computations with a great
wealth of physical details play a major role in research now. Back-of-the-envelope
calculations still serve their purpose to guide researchers, but at the end of the day it
is hardly possible to make progress without writing and running code on computers
to gain a deeper understanding of the physical processes behind observed
phenomena.
In this regard, it is surprising that the education of students at the undergraduate
level is still largely focused on traditional ways of problem solving. It is often
argued that being able to program comes along the way, for example, when students
engage with their research project for a Bachelor’s thesis. It is said that problems in
introductory courses can be solved mostly with analytic techniques, and there is no
need to bother students with programming languages. However, we are convinced
that there is a great deal of computer-based problem solving that can be done right
from the beginning. As a result, connections to contemporary science can be made
earlier and more lively. One of the obvious merits of becoming acquainted with a
programming language is that you can learn how to address a question by devel-
oping and implementing an algorithm that provides the answer.
There are two major avenues toward learning a programming language. One
follows the systematic teaching model, where the language is laid out in all details
and you are guided step by step through its elements and concepts. Surely, this is
the preferable method if you want to master a programming language. For the
beginner, however, this can become tiresome and confusing, especially since the

v
vi Preface

relevance of most of the stuff you learn becomes clear only later (if at all). The
alternative approach is to learn mainly from examples, to grasp the language in an
intuitive way and to gradually pick up what you need to know for practical
applications. We believe that Python is quite suitable for this approach. Of course,
there is always a downside. This textbook is far from covering everything there is to
know about Python. We focus on numerical computation and data analysis and
make use of libraries geared toward these applications.
Problem solving is an art that requires a lot of practice. The worked-out
examples in this book revolve around basic concepts and problems encountered in
undergraduate courses introducing astronomy and astrophysics. The complete
source code is provided on the web via uhh.de/phy-hs-pybook. We briefly reca-
pitulate essential formulas and basic knowledge, but our recaps are by no means
intended to replace lecture courses and textbooks on astronomy and astrophysics.
This is highlighted by frequently referring to introductory textbooks for further
reading. Our book is mainly intended for readers who want to learn Python from
scratch. In the beginning, code examples are explained in detail, and exercises start
at a rather elementary level. As topics become more advanced, you are invited to
work on problems that require a certain amount of effort, time, and innovative
thinking. If you have already experience with programming and know some
Python, you can concentrate on topics you are interested in. Our objective is that
examples as well as exercises not only help you in understanding and using Python
but also offer intriguing applications in astronomy and astrophysics.

Hamburg, Germany Wolfram Schmidt


December 2020 Marcel Völschow
Acknowledgements

This book was inspired by introductory courses on astronomy and astrophysics at


the University of Hamburg. We incorporated Python on the fly into problem classes
accompanying the lectures. We thank Robi Banerjee, Jochen Liske, and Francesco
de Gasperin for supporting this learning concept, and we are very grateful for the
enthusiasm and feedback of many students. Special thanks goes to Bastian R.
Brückner, Henrik Edler, Philipp Grete, and Caroline Heneka for reading and
commenting the manuscript. Moreover, we thank Bastian R. Brückner for drawing
numerous illustrative figures that are invaluable for explaining important concepts
in the book.

vii
Contents

1 Python Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 Using Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Understanding Expressions and Assignments . . . . . . . . . . . . . . . . 3
1.3 Control Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.4 Working with Modules and Objects . . . . . . . . . . . . . . . . . . . . . . . 14
2 Computing and Displaying Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.1 Spherical Astronomy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.1.1 Declination of the Sun . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.1.2 Diurnal Arc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.1.3 Observation of Celestial Objects . . . . . . . . . . . . . . . . . . . . 35
2.2 Kepler’s Laws of Planetary Motion . . . . . . . . . . . . . . . . . . . . . . . 42
2.3 Tidal Forces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3 Functions and Numerical Methods . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.1 Blackbody Radiation and Stellar Properties . . . . . . . . . . . . . . . . . 55
3.1.1 Stefan–Boltzmann Law . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.1.2 Planck Spectrum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
3.2 Physics of Stellar Atmospheres . . . . . . . . . . . . . . . . . . . . . . . . . . 77
3.2.1 Thermal Excitation and Ionization . . . . . . . . . . . . . . . . . . 78
3.2.2 The Balmer Jump . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.3 Planetary Ephemerides . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
4 Solving Differential Equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
4.1 Numerical Integration of Initial Value Problems . . . . . . . . . . . . . . 105
4.1.1 First Order Differential Equations . . . . . . . . . . . . . . . . . . . 105
4.1.2 Second Order Differential Equations . . . . . . . . . . . . . . . . . 116
4.2 Radial Fall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
4.3 Orbital Mechanics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
4.4 Galaxy Collisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151

ix
x Contents

4.5 Stellar Clusters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167


4.6 Expansion of the Universe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
5 Astronomical Data Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
5.1 Spectral Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
5.2 Transit Light Curves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
5.3 Survey Data Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
5.4 Image Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
5.5 Machine Learning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
5.5.1 Image Classification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
5.5.2 Spectral Classification . . . . . . . . . . . . . . . . . . . . . . . . . . . 216

Appendix A: Object-Oriented Programming in a Nutshell . . . . . . . . . . . 225


Appendix B: Making Python Faster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
Chapter 1
Python Basics

Abstract This chapter explains basic programming concepts. After an overview of


common Python distributions, we show how to use Python as a simple calculator. As
a first step toward programming, variables and expressions are introduced. The arith-
metic series and Fibonacci numbers illustrate the concepts of iteration and branching.
We conclude this chapter with a program for the computation of a planet’s orbital
velocity around the Sun, using constants and functions from libraries and giving a
small glimpse at objects in Python.

1.1 Using Python

There is quite a variety of Python installations. Depending on the operating system


of your computer, you might have some basic Python preinstalled. Typically, this is
the case on Linux computers. However, you might find it rather cumbersome to use,
especially if you are not well experienced with writing source code in elementary
text editors and executing the code on the command line. What is more, installing
additional packages typically requires administrative privileges. If you work, for
example, in a computer lab it is likely that you do not have the necessary access rights.
Apart from that, Python version 2.x (that is major version 2 with some subversion
x) is still in use, while this book is based on version 3.x.
Especially as a beginner, you will probably find it convenient to work with a a GUI
(graphical user interface). Two popular choices for Python programming are Spyder
and Jupyter. Spyder (www.spyder-ide.org) is a classical IDE (integrated development
environment) which allows you to edit code, execute it and view the output in different
frames. Jupyter (jupyter.org) can be operated via an arbitrary web browser. It allows
you to run an interactive Python session with input and output cells (basically, just
like the console-based ipython). Apart from input cells for typing Python source
code, there are so-called markdown cells for writing headers and explanatory text.
This allows you to use formatting similar to elementary HTML for webpages. A
valuable feature is the incorporation of LaTeX to display mathematical expressions.
The examples in this book can be downloaded as Jupyter notebooks and Python
source code in zipped archives from uhh.de/phy-hs-pybook.
© Springer Nature Switzerland AG 2021 1
W. Schmidt and M. Völschow, Numerical Python in Astronomy and Astrophysics,
Undergraduate Lecture Notes in Physics,
https://doi.org/10.1007/978-3-030-70347-9_1
2 1 Python Basics

Since it depends on your personal preferences which software suits you best, we do
not presume a particular GUI or Python distribution here. If you choose to work with
Spyder or Jupyter, online documentation and tutorials will help you to install the soft-
ware and to get started (browse the official documentation under docs.spyder-ide.org
and jupyter-notebook.readthedocs.io/en/stable). For a comprehensive guideline, see
also [1, appendices A and B]. A powerful all-in-one solution is Anaconda, a Python
distribution and package manager that can be installed under Windows, macOS or
Linux by any user (see docs.anaconda.com for more information). Anaconda pro-
vides a largely autonomous environment with all required components and libraries
on a per-user basis. Of course, this comes at the cost of large resource consumption
(in particular, watch your available disk space).
As a first step, check if you can run the traditional “Hello, World!” example with
your favorite Python installation. Being astronomers, we use a slightly modified
version:
1 print("Hello, Universe!")
In this book Python source code is listed in frames with lines numbered on the left (in
the above example, there is just one line). Although these line numbers are not part
of the source code (that’s why they are shown outside of the frame), they are useful
for referring to particular parts of a code example. You might be able to display line
numbers in your code editor (in Jupyter notebooks, for example, line numbering can
be switched on and off in the View menu), but you should not confuse these numbers
with the line numbers used in this book. Usually we will continue the numbering
over several frames if the displayed pieces of code are related to each other, but we
also frequently reset line numbers to 1 when a new program starts or a new idea is
introduced. Whenever you encounter a code line with number 1 it should alert you:
at this point something new begins.
After executing the print statement in line 1 above, you should see somewhere on
your screen the output1

Hello, Universe!

The quotes in the source code are not shown in the output. They are used to signify
that the enclosed characters form a string. As you might have guessed, the print()
function puts the string specified in parentheses on the screen (more precisely, in a
window or frame that is used by Python for output).2

1 How to execute Python code depends on the software you are using (consult the documentation).
In a notebook, for example, all you need to do is to simultaneously press the enter and shift keys of
your keyboard in the cell containing the code.
2 Enclosing the string in parentheses is obligatory in Python 3. You may find versions of “Hello,

World!” without parentheses on the web, which work only with Python 2.
1.2 Understanding Expressions and Assignments 3

1.2 Understanding Expressions and Assignments

Apart from printing messages on the screen, which is not particularly exciting by
itself, Python can be used as a scientific calculator. Let us begin right away with an
example from astronomy. Suppose we want to calculate the velocity at which Earth
is moving along its orbit around the Sun. For simplicity, we treat the orbit as circular
(in fact, it is elliptical with a small eccentricity of 0.017). From the laws of circular
motion it follows that we can simply calculate the velocity as the circumference 2π r
of the orbit divided by the period P, which happens to be one year for Earth. After
having looked up the value of π, the orbital radius r (i.e. the distance to the Sun) in
km, and the length of a year in seconds,3 we type
1 2*3.14159*1.496e8/3.156e7
and, once evaluated by Python, we obtain

29.783388086185045

for the orbital velocity in km/s. Line 1 is an example for a Python expression con-
sisting of literal numbers and the arithmetic operators * and / for multiplication
and division, respectively. The factor of two in the formula for the circumference
is simply written as the integer 2, while the number π is approximately expressed
in fixed-point decimal notation as 3.14159.4 The radius r = 1.496 × 108 km is
expressed as 1.496e8, which is a so-called floating point literal . The character
e followed by an integer indicates the exponent of the leading digit in the decimal
system. In this case, e8 corresponds to the factor 108 . Negative exponents are indi-
cated by a minus sign after e. For example, 10−3 can be expressed as 1.0e-3 or
just 1e-3 (inserting + for positive exponents is optional).
Of course, there is much more to Python than evaluating literal expressions like
a calculator. To get an idea how this works, we turn the example shown above into a
little Python program:
1 radius = 1.496e8 # orbital radius in km
2 period = 3.156e7 # orbital period in s
3
4 # calculate orbital velocity
5 velocity = 2*3.14159*radius/period
Lines 1, 2, and 5 are examples for assignments. Each assignment binds the value of
the expression on the right-hand side of the equality sign = to a name on the left-hand
side. A value with a name that can be used to refer to that value is in essence what is

3 Strictlyspeaking, the time needed by Earth to complete one revolution around the Sun is the
sidereal year, which has about 365.256 d. One day has 86400 s.
4 In many programming languages, integers such as 2 are treated differently than floating point

numbers. For example, using 2.0 instead of the integer 2 in a division might produce a different
result. In Python 3, it is usually not necessary to make this distinction. Alas, Python 2 behaves
differently in this respect.
4 1 Python Basics

called a variable in Python.5 In line 5, the variables radius and period are used
to compute the orbital velocity of Earth from the formula

2π r
v= (1.1)
P
and the result is in turn assigned to the variable velocity. Any text between the
hash character # and the end of a line is not Python code but a comment explaining
the code to someone other than the programmer (once in a while, however, even
programmers might be grateful for being reminded in comments about code details
in long and complex programs). For example, the comments in line 1 and 2 provide
some information about the physical meaning (radius and period of an orbit) and
specify the units that are used (km and s). Line 4 comments on what is going on in
the following line.
Now, if you execute the code listed above, you might find it surprising that there
is no output whatsoever. Actually, the orbital velocity is computed by Python, but
assignments do not produce output. To see the value of the velocity, we can append
the print statement
6 print(velocity)
to the program (since this line depends on code lines 1–5 above, we continue the
numbering and will keep doing so until an entirely new program starts), which results
in the output6

29.783388086185045

This is the same value we obtained with the calculator example at the beginning of
this section.
However, we can do a lot better than that by using further Python features. First
of all, it is good practice to print the result of a program much in the same way as,
hopefully, you would write the result of a handwritten calculation: It should be stated
that the result is a velocity in units of km/s. This can be achieved quite easily by using
string literals as in the very first example in Sect. 1.1:
7 print("orbital velocity =", velocity, "km/s")
producing the output

orbital velocity = 29.783388086185045 km/s

5 The concept of a variable in Python is different from variables in programming languages such as
C, where variables have a fixed data type and can be declared without assigning a value. Basically, a
variable in C is a placeholder in memory whose size is determined by the data type. Python variables
are objects that are much more versatile.
6 In interactive Python, just writing the variable name in the final line of a cell would also result in

its value being displayed in the output.


1.2 Understanding Expressions and Assignments 5

It is important to distinguish between the word ‘velocity’ appearing in the string


"orbital velocity =" on the one hand and the variable velocity sepa-
rated by commas on the other hand. In the output produced by print the two strings
are concatenated with the value of the variable. Using such a print statement may
seem overly complicated because we know, of course, that the program computes
the orbital velocity and, since the radius is given in km and the period in seconds, the
resulting velocity will be in units of km/s. However, the meaning of a numerical value
without any additional information might not be obvious at all in complex, real-world
programs producing a multitude of results. For this reason, we shall adhere to the
practice of precisely outputting results throughout this book. The simpler version
shown in line 6 may come in useful if a program does not work as expected and you
want to check intermediate results.
An important issue in numerical computations is the precision of the result. By
default, Python displays a floating point value with machine precision (i.e. the maxi-
mal precision that is supported by the way a computer stores numbers in memory and
performs operations on them). However, not all of the digits are necessarily signifi-
cant. In our example, we computed the orbital velocity from parameters (the radius
and the period) with only four significant digits, corresponding to a relative error
of the order 10−4 . Although Python performs arithmetical operations with machine
precision, the inaccuracy of our data introduces a much larger error. Consequently,
it is pointless to display the result with machine precision. Insignificant digits can be
discarded in the output by appropriately formatting the value:
8 print("orbital velocity = {:5.2f} km/s".format(velocity))

Let us see how this works:


• The method format() inserts the value of the variable in parentheses into the
preceding string (mind the dot in between). You will learn more about methods in
Sect. 1.4.
• The placeholder {:5.2f} controls where and in which format the value of the
variable velocity is inserted. The format specifier 5.2f after the colon :
indicates that the value is to be displayed in fixed-point notation with 5 digits
altogether (including the decimal point) and 2 digits after the decimal point. The
colon before the format specifier is actually not superfluous. It is needed if several
variables are formatted in one print statement (examples will follow later).
Indeed, the output now reads

orbital velocity = 29.78 km/s

Optionally, the total number of digits in the formatting command can be omitted.
Python will then just fill in the leading digits before the decimal point (try it; also
change the figures in the command and try to understand what happens). A fixed
number of digits can be useful, for example, when printing tabulated data.
As the term variable indicates, the value of a variable can be changed in subsequent
lines of the program by assigning a new value. For example, you might want to
6 1 Python Basics

calculate the orbital velocity of a hypothetical planet at ten times the distance of
the Earth from the Sun, i.e. r = 1.496 × 109 km. To that end, we could start with
the assignment radius=1.496e9. Alternatively, we can make use of the of the
current value based on the assignment in line 1 and do the following:
9 radius = 10*radius
10 print("new orbital radius = {:.3e} km".format(radius))
Although an assignment may appear as the equivalent of a mathematical equality, it is
of crucial importance to understand that it is not. Transcribing line 9 into the algebraic
equation r = 10r is nonsense because one would obtain 1 = 10 after dividing through
r , which is obviously a contradiction. Keep in mind:

The assignment operator = in Python means set to, not is equal to.

The code in line 9 thus encompasses three steps:


(a) Take the value currently assigned to radius,
(b) multiply this value by ten
(c) and reassign the result to radius.
Checking this with the print statement in line 10, we find that the new value of the
variable radius is indeed 10 times larger than the original value from line 1:

new orbital radius = 1.496e+09 km

The radius is displayed in exponential notation with three digits after the decimal
point, which is enabled by the formatting type e in place of f in the placeholder
{:.3e} for the radius (check what happens if you use type f in line 10). You must
also be aware that repeatedly executing the assignment radius = 10*radius
in interactive Python increases the radius again and again by a factor of 10, which is
possibly not what you might want. However, repeated operation on the same variable
is done on purpose in iterative constructions called loops (see Sect. 1.3).
After having defined a new radius, it would not be correct to go straight to the
computation of the orbital velocity since the period of the orbit changes, too. The
relation between period and radius is given by Kepler’s third law of planetary motion,
which will be covered in more detail in Sect. 2.2. For a planet in a circular orbit around
the Sun, this relation can be expressed as7

4π2 3
P2 = r , (1.2)
GM

7 Hereit is assumed that the mass of the planet is negligible compared to the mass of the Sun. For
the general formulation of Kepler’s third law see Sect. 2.2.
1.2 Understanding Expressions and Assignments 7

where M=1.989 × 1030 kg is the mass of the Sun and G=6.674 × 10−11 N kg−2 m2
is the gravitational constant. To calculate P for given r , we rewrite this equation in
the form
P = 2π (G M)−1/2 r 3/2 .

This formula can be easily turned into Python code by using the exponentiation
operator ** for calculating the power of an expression:
11 # calculate period in s from radius in km (Kepler’s third law)
12 period = 2*3.14159 * (6.674e-11*1.989e30)**(-1/2) * \
13 (1e3*radius)**(3/2)
14 # print period in yr
15 print("new orbital period = {:.1f} yr".format(period/3.156e7))
16
17 velocity = 2*3.14159*radius/period
18 print("new orbital velocity = {:.2f} km/s".format(velocity))

The results are

new orbital period = 31.6 yr


new orbital velocity = 9.42 km/s

Hence, it would take more than thirty years for the planet to complete its orbit around
the Sun, as its orbital velocity is only about one third of Earth’s velocity. Actually,
these parameters are quite close to those of the planet Saturn in the solar system.
The backslash character \ in line 12 is used to continue an expression that does not
fit into a single line in the following line (there is no limitation on the length of a
line in Python, but code can become cumbersome to read if too much is squeezed
into a single line). An important lesson taught by the code listed above is that you
always need to be aware of physical units when performing numerical calculations.
Since the radius is specified in km, we obtain the orbital velocity in km/s. However,
the mass of the Sun and the gravitational constants in the expression for the orbital
period in lines 12–13 are defined in SI units. For the units to be compatible, we
need to convert the radius from km to m. This is the reason for the factor 103 in the
expression (1e3*radius)**(3/2). Of course, this does not change the value of
the variable radius itself. To avoid confusion, it is stated in the comment in line 11
which units are assumed. Another unit conversion is applied when the resulting period
is printed in units of a year in line 15, where the expression period/3.156e7 is
evaluated and inserted into the output string via format. As you may recall from
the beginning of this section, a year has 3.156 × 107 s.
Wrong unit conversion is a common source of error, which may have severe con-
sequences. A famous example is the loss of NASA’s Mars Climate Orbiter due to
the inconsistent use of metric and imperial units in the software of the spacecraft.8
As a result, more than $100 million were quite literally burned on Mars. It is there-
fore extremely important to be clear about the units of all physical quantities in a

8 See mars.jpl.nasa.gov/msp98/orbiter/.
8 1 Python Basics

program. Apart from the simple, but hardly foolproof approach of using explicit con-
version factors and indicating units in comments, you will learn different strategies
for ensuring the consistency of units in this book.

1.3 Control Structures

The computation of the orbital velocity of Earth in the previous section is a very
simple example for the implementation of a numerical algorithm in Python.9 It
involves the following steps:
1. Initialisation of all data needed to perform the following computation.
2. An exactly defined sequence of computational rules (usually based on mathe-
matical formulas), unambiguously producing a result in a finite number of steps
given the input from step 1.
3. Output of the result.
In our example, the definition of the variables radius and period provides the
input, the expression for the orbital velocity is a computational rule, and the result
assigned to the variable velocity is printed as output.
A common generalization of this simple scheme is the repeated execution of the
same computational rule in a sequence of steps, where the outcome of one step is
used as input for the next step. This is called iteration and will be explained in the
remainder of this section. The independent application of the same operations to
multiple elements of data is important when working with arrays, which will be
introduced in Chap. 2.
Iteration requires a control structure for repeating the execution of a block of
statements a given number of times or until a certain condition is met and the iteration
terminates. Such a structure is called a loop. For example, let us consider the problem
of summing up the first 100 natural numbers (this is a special case of an arithmetic
series, in which each term differs by the previous one by a constant):


n
sn ≡ k = 1 + 2 + 3 + ... + n. (1.3)
k=1

9 The term algorithm derives from the astronomer and mathematician al-Khwarizmi whose name
was transcribed to Algoritmi in Latin (cf. [2] if you are interested in the historical background).
al-Khwarizmi worked at the House of Wisdom, a famous library in Bagdad in the early 9th century.
Not only was he the founder of the branch of mathematics that became later known as algebra, he
also introduced the decimal system including the digit 0 in a book which was preserved until the
modern era only in a Latin translation under the title Algoritmi de numero Indorum (this refers to
the origin of the number zero in India). The digit 0 is quintessential to the binary system used on
all modern computers.
1.3 Control Structures 9

Fig. 1.1 Illustration of the Initialization


computation of the sum s100 sum=0
defined by Eq. (1.3) via a
for loop. The box on the Iteration
top of the figure contains the k=1 sum=0+1 = 1
initialization statement prior
to the loop (sum is set to k=2 sum=1+2 = 3
zero). The middle box shows
k=3 sum=3+3 = 6
iterations of sum in the body

...

...

...
of the for loop with the
counter k, resulting in the k=99 sum=4851+99 = 4950
sum shown at the bottom.
The arrows indicate how k=100 sum=4950+100 = 5050
values from one iteration are
Result
used in the next iteration.
sum=5050
Values of the loop counter
are shown in red

where n = 100. In Python, we can perform the summation using a for loop:
1 sum = 0 # initialization
2 n = 100 # number of iterations
3
4 for k in range(1,n+1): # k running from 1 to n
5 sum = sum + k # iteration of sum
6
7 print("Sum =", sum)
The result is

Sum = 5050

The keywords for and in indicate that the loop counter k runs through all integers
defined by range(1,n+1), which means the sequence 1, 2, 3, . . . , n in mathe-
matical notation. It is a potential source of confusion that Python includes the start
value 1, but excludes the stop value n+1 in range(1,n+1).10
The indented block of code following the colon is executed subsequently for each
value of the loop counter. You need to be very careful about indentations in Python!
They must be identical for all statements in a block, i.e. you are not allowed to use
more or less white space or mix tabs and white spaces. We recommend to use one tab
per indentation. The block ends with the first non-indented statement. In the example
above, only line 5 is indented, so this line constitutes the body of the loop, which
adds the value of the loop counter to the variable sum. The initial value of sum must
be defined prior to the loop (see line 1). Figure 1.1 illustrates how the variables are
iterated in the loop.

10 Thereis a reason for the stop value being excluded. The default start value is 0 and range(n)
simply spans the n integers 0, 1, 2, . . . , n − 1.
10 1 Python Basics

Actually, our Python program computes the sum exactly in the way intended by
the teacher of nine-year old Carl Friedrich Gauss11 in school, just by summing up the
numbers from 1 to 100. However, Gauss realized that there is a completely different
solution to the problem and he came up with the correct answer much faster than
expected by his teacher, while his fellow students were still tediously adding up
numbers. The general formula discovered by Gauss is (the proof can be found in any
introductory calculus textbook or on the web):


n
n(n − 1)
sn = k= . (1.4)
k=1
2

We leave it as an exercise to check with Python that this formula yields the same
value as direct summation.
A slightly more demanding example is the calculation of the Fibonacci sequence12
using the recursion formula

Fn+1 = Fn + Fn−1 for n ≥ 1, (1.5)

with the first two elements


F1 = 1 , F0 = 0 . (1.6)

The meaning of Eq. (1.5) is that any Fibonacci number is the sum of the two preceding
ones, starting from 0 and 1. The following Python program computes and prints the
Fibonacci numbers F1 , F2 , . . . , F10 (or as many as you like):
1 # how many numbers are computed
2 n_max = 10
3
4 # initialize variables
5 F_prev = 0 # 0. number
6 F = 1 # 1. number
7
8 # compute sequence of Fibonacci numbers
9 for n in range(1,n_max+1):
10 print("{:d}. Fibonacci number = {:d}".format(n,F))
11
12 # next number is sum of F and the previous number
13 F_next = F + F_prev
14

11 German mathematician, physicist, and astronomer who is known for the Gauss theorem, the

normal distribution, and many other import contributions to algebra, number theory, and geometry.
12 Named after Leonardo de Pisa, also known as Fibonacci, who introduced the sequence to European

mathematics in the early 13th century. However, the Fibonacci sequence was already known to
ancient Greeks. It was used to describe growth processes and there is a remarkable relation to the
golden ratio.
1.3 Control Structures 11

15 # prepare next iteration


16 F_prev = F # first reset F_prev
17 F = F_next # then assign next number to F
The three variables F_prev, F, and F_next correspond to Fn−1 , Fn , and Fn+1 ,
respectively. The sequence is initialized in lines 5 and 6 (definition of F0 and F1 ).
The recursion formula (1.5) is implemented in line 13. Without lines 16 and 17,
however, the same value (corresponding to F0 + F1 ) would be assigned again and
again to F_next. For the next iteration, we need to re-assign the values of F (Fn )
and F_next (Fn+1 ) to F_prev (Fn−1 ) and F (Fn ), respectively. The loop counter
n merely controls how many iterations are executed. Figure 1.2 shows a schematic
view of the algorithm (you can follow the values of the variables in the course of the
iteration by inserting a simple print statement into the loop). The output produced
by the program is13

1. Fibonacci number = 1
2. Fibonacci number = 1
3. Fibonacci number = 2
4. Fibonacci number = 3
5. Fibonacci number = 5
6. Fibonacci number = 8
7. Fibonacci number = 13
8. Fibonacci number = 21
9. Fibonacci number = 34
10. Fibonacci number = 55

Since two variables are printed, we need two format fields where the values of the
variables are inserted (see line 10). As an alternative to using format(), the same
output can be produced by means of a formatted string literal (also called f-string)14 :
print(f"{n:d}. Fibonacci number = {F:d}")
Here, the variable names are put directly into the string. The curly braces indicate
that the values assigned to the names n and F are to be inserted in the format defined
after the colons (in this example, as integers with arbitrary number of digits). This is a
convenient shorthand notation. Nevertheless, we mostly use format() in this book
because the syntax maintains a clear distinction between variables and expressions
on the one hand and formatted strings on the other hand. If you are more inclined to
f-strings, make use of them as you please.
Suppose we would like to know all Fibonacci numbers smaller than, say, 1000.
We can formally write this as Fn < 1000. Since it is not obvious how many Fibonacci
numbers exist in this range, we need a control structure that repeats a block of code

13 As you can see from Fig. 1.2, F11 is computed as final value of F_next. But it is not used. You
can try to modify the program such that only 9 iterations are needed to print the Fibonacci sequence
up to F10 .
14 This feature was introduced with Python 3.6.
12 1 Python Basics

Fig. 1.2 Illustration of the Initialization


recursive computation of the F_prev=0 F=1
Fibonacci sequence (see
Eq. 1.5). In each iteration of Iteration
the loop, the sum of n=1 F_prev=0 F=1 F_next=0+1 = 1
F_prev and F is assigned to
the variable F_prev. The n=2 F_prev=1 F=1 F_next=1+1 = 2
resulting number is shown in
n=3 F_prev=1 F=2 F_next=1+2 = 3
the rightmost column. For

...

...

...

...

...
the next iteration, this
number is re-assigned to F, n=9 F_prev=21 F=34 F_next=21+34 = 55
and the value of F to
F_prev, as indicated by the n=10 F_prev=34 F=55 F_next=34+55 = 89
arrows
Result
F=55

as long as a certain condition is fulfilled. In such a case, it is preferable to work with


a while loop. This type of loop enables us to modify our program such that all
Fibonacci numbers smaller than 1000 are computed, without knowing the required
number of iterations:
1 # initialize variables
2 F_prev = 0 # 0. number
3 n,F = 1,1 # 1. number
4
5 # compute sequence of Fibonacci numbers smaller than 1000
6 while F < 1000:
7 print("{:d}. Fibonacci number = {:d}".format(n,F))
8
9 # next number is sum of F and the previous number
10 F_next = F + F_prev
11
12 # prepare next iteration
13 F_prev = F # first reset F_prev
14 F = F_next # then assign next number to F
15 n += 1 # increment counter
The resulting numbers are:

1. Fibonacci number = 1
2. Fibonacci number = 1
3. Fibonacci number = 2
4. Fibonacci number = 3
5. Fibonacci number = 5
6. Fibonacci number = 8
7. Fibonacci number = 13
1.3 Control Structures 13

8. Fibonacci number = 21
9. Fibonacci number = 34
10. Fibonacci number = 55
11. Fibonacci number = 89
12. Fibonacci number = 144
13. Fibonacci number = 233
14. Fibonacci number = 377
15. Fibonacci number = 610
16. Fibonacci number = 987

Of course, the first ten numbers are identical to the numbers from our previous
example. If you make changes to a program, always check that you are able to
reproduce known results!
The loop header in line 6 of the above listing literally means: Perform the following
block of code while the value of F is smaller than 1000. The expression F<1000 is
an example of a Boolean (or logical) expression. The operator < compares the two
operands F and 1000 and evaluates to True if the numerical value of F is smaller
than 1000. Otherwise, the expression evaluates to False and the loop terminates.
Anything that is either True or False is said to be of Boolean type. In Python, it
is possible to define Boolean variables.
A while loop does not come with a counter. To keep track of how many Fibonacci
numbers are computed (in other words the index n of the sequence Fn ), we initialize
the counter n along with F in the multiple assignment in line 3. This is equivalent to
n = 1
F = 1
Python allows you to assign multiple values separated by commas to multiple vari-
ables (also separated by commas) in a single statement, where the ordering on the
left corresponds to the ordering on the right. We will make rarely use of this feature.
While it is useful in some cases (for example, to swap variables15 or for functions
returning multiple values), multiple assignments are rather difficult to read and prone
to errors, particularly if variables are interdependent.
While the loop counter of a for loop is automatically incremented, we need to
explicitly increase our counter in the example above at the end of each iteration. In
line 15, we use the operator += to increment n in steps of one, which is equivalent
to the assignment n=n+1 (there are similar operators -=, *=, etc. for the other basic
arithmetic operations).
Let us try to be even smarter and count how many even and odd Fibonacci numbers
below a given limit exist. This requires branching, i.e. one block of code will be
executed if some condition is met and an alternative block if not (such blocks are
also called clauses). This is exactly the meaning of the if and else statements
in the following example:

15Another application in our Fibonacci program would be the merging of lines 13 and 14 into the
multiple assignment F_prev,F = F,F_next.
14 1 Python Basics

1 # initialize variables
2 F_prev = 0 # 0. number
3 F = 1 # 1. number
4 n_even = 0
5 n_odd = 0
6
7 # compute sequence of Fibonacci numbers smaller than 1000
8 while F < 1000:
9 # next number is sum of F and the previous number
10 F_next = F + F_prev
11
12 # prepare next iteration
13 F_prev = F # first reset F_prev
14 F = F_next # then assign next number to F
15
16 # test if F is even (divisible by two) or odd
17 if F%2 == 0:
18 n_even += 1
19 else:
20 n_odd += 1
21
22 print("Found {:d} even and {:d} odd Fibonacci numbers".\
23 format(n_even,n_odd))
Instead of a single counter, we need two counters here, n_even for even Fibonacci
numbers and n_odd for the odd ones. The problem is to increment n_even if the
value of F is an even number. To that end the modulo operator % is applied to get
the remainder of division by two. If the remainder is zero, then the number is even.
This is tested with the comparison operator == in the Boolean expression following
the keyword if in line 17. If this expression evaluates to True, then the counter
for even numbers is incremented (line 18). If the condition is False, the else
branch is entered and the counter for odd numbers is incremented (line 20). You
must not confuse the operator ==, which compares variables or expressions without
changing them, with the assignment operator =, which sets the value of a variable.
The program reports (we do not bother to print the individual numbers again):

Found 5 even and 11 odd Fibonacci numbers

Altogether, there are 5 + 11 = 16 numbers. You may check that this is in agreement
with the listed numbers.

1.4 Working with Modules and Objects

Python offers a collection of useful tools in the Python Standard Library (see
docs.python.org/3/library). Functions such as print() are part of the Standard
Library. They are called built-in functions. Apart from that, many more optional
1.4 Working with Modules and Objects 15

libraries (also called packages) are available. Depending on the Python distribution
you use, you will find that some libraries are included and can be imported as shown
below, while you might need to install others.16 Python libraries have a hierarchical
modular structure. This means that you do not necessarily have to load a complete
library, but you can access some part of a library, which can be a module, a submod-
ule (i.e. a module within a module) or even individual names defined in a module.
To get started, it will be sufficient to consider a module as a collection of definitions.
By importing a module, you can use variables, functions, and classes (see below)
defined in the module.
For example, important physical constants and conversion factors are defined
in the constants module of the SciPy library (for more information, see
www.scipy.org/about.html). A module can be loaded with the import command:
1 import scipy.constants
To view an alphabetically ordered list of all names defined in this module, you can
invoke dir(scipy.constants) (this works only after a module is imported).
By scrolling through the list, you might notice the entry
’gravitational_constant’. As the name suggests, this is the gravitational
constant G. Try
2 print(scipy.constants.gravitational_constant)
which displays the value of G in SI units:

6.67408e-11

The same value is obtained via scipy.constants.G. Even so, an identifier


composed of a library name in conjunction with a module and a variable name is
rather cumbersome to use in programs. Alternatively, a module can be accessed via
an alias:
3 import scipy.constants as const
4
5 print(const.G)
also displays the value of G. Here, const is a user-defined nickname for
scipy.constants.
It is also possible to import names from a module directly into the global name-
space of Python. The variables we have defined so far all belong to the global name-
space. The syntax is as follows:
6 from scipy.constants import G
7
8 print(G)

16 See,
for example, packaging.python.org/tutorials/installing-packages
and docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-pkgs.html.
16 1 Python Basics

In this case, only G is imported, while in the examples above all names from
scipy.constants are made available. Importing names via the keyword from
should be used with care, because they can easily conflict with names used in assign-
ments elsewhere. Python does not treat this as an error. Consequently, you might
accidentally overwrite a module variable such as G with some other value.
By using constants from Python libraries, we can perform computations without
looking up physical constants on the web or in textbooks and inserting them as literals
in the code. Let us return to the example of a planet at 10 times the distance of Earth
from the Sun, i.e. r = 10 au (see Sect. 1.2). Here is an improved version of the code
for the computation of the orbital period and velocity:
1 from math import pi,sqrt
2 from astropy.constants import M_sun
3 from scipy.constants import G,au,year
4
5 print("1 au =", au, "m")
6 print("1 yr =", year, "s")
7
8 radius = 10*au
9 print("\nradial distance = {:.1f} au".format(radius/au))
10
11 # Kepler’s third law
12 period = 2*pi * sqrt(radius**3/(G*M_sun.value))
13 print("orbital period = {:.4f} yr".format(period/year))
14
15 velocity = 2*pi * radius/period # velocity in m/s
16 print("orbital velocity = {:.2f} km/s".format(1e-3*velocity))

The output of this program is

1 au = 149597870691.0 m
1 yr = 31536000.0 s

radial distance = 10.0 au


orbital period = 31.6450 yr
orbital velocity = 9.42 km/s

We utilize the value of π and the square-root function defined in the math module,
which is part of the standard library. The function sqrt() imported from math is
called in line 12 with the expression radius**3/(G*M_sun.value) as argu-
ment. This means that the number resulting from the evaluation of this expression is
passed as input to sqrt(), which executes an algorithm to compute the square root
of that number. The result returned by the function and is then multiplied with 2*pi
to obtain the orbital period. Moreover, we use constants and conversion factors from
the SciPy and Astropy libraries. For instance, au is one astronomical unit in m and
year is one year in s. The values are printed in lines 5 and 6. These conversion
factors enable us to conveniently define the radius in astronomical units (line 8) and,
after apply Kepler’s third law in SI units, to print the resulting orbital period in years
(lines 12 and 13). When printing the radius in line 9, the newline character ’\n’
at the beginning of the string inserts a blank line. Other than in Sect. 1.2, the orbital
1.4 Working with Modules and Objects 17

velocity assigned to velocity is in m/s. So we need to multiply by a factor of 10−3


to obtain the velocity in units of km/s in the final print statement.
In contrast to the gravitational constant G, which is simply a floating point number,
the mass of the Sun defined in astropy.constants is a more complex object.
In computer science, the term object has a specific meaning and refers to the object-
oriented programming (OOP) paradigm. You can go a long way in Python without
bothering about object-oriented programming. Nevertheless, you will find it helpful
if you are aware of a few basic facts:

1. Everything in Python is an object.


2. An object contains a particular kind of data.
3. Objects have methods to manipulate the object’s data in a controlled way.
4. A method can change an object or create a new object.

This implies that G is also an object, albeit a rather simple one. If you print M_sun,
you will find quite a bit more information in there, such as the uncertainty of the
value and its physical unit:

Name = Solar mass


Value = 1.9884754153381438e+30
Uncertainty = 9.236140093538353e+25
Unit = kg
Reference = IAU 2015 Resolution B 3 + CODATA 2014

Particular data items are called object attributes. For example, the value of the solar
mass is an attribute of M_sun. You can fetch an attribute by joining the names of the
object and the attribute with a dot. We refer to the attribute value in line 12 to obtain
a pure number that can be combined with other numbers in an arithmetic expression.
To list attributes belonging to an object, you can use dir(), just like for modules,
or search the documentation. Attributes and methods are defined in classes. While
objects belonging to the same class may contain different data, they have the same
attributes and methods. For example, M_earth from astropy.constants has
a value attribute just like M_sun, but the value behind this attribute is Earth’s mass
instead of the mass of the Sun. Both objects belong to the class Quantity. You can
take a glimpse behind the curtain in Appendix A, where you are briefly introduced
to writing your own classes.
Since everything in Python is an object, so is a string. Now you are able to better
understand the meaning of format() being a method. It is a method allowing you
to insert formatted numbers into a string.17 While methods are relatives of Python
functions, a method always has to be called in conjunction with a particular object.
In the print statements in lines 9, 13, and 16, the objects are string literals. The

17 Sincestrings are immutable objects, the method does not change the original string with place-
holders. It creates a new string object with the formatted numbers inserted.
18 1 Python Basics

syntax is similar to accessing object attributes, except for the arguments enclosed in
parentheses (here, the variables holding the numbers to be inserted). In general, you
can call methods on names referring to objects – in other words, Python variables.
This will be covered in more detail in the next chapter.
Chapter 2
Computing and Displaying Data

Abstract NumPy arrays are the workhorses of numerics in Python, extending it by


remarkable numerical capabilities. For example, they can be used just like simple
variables to evaluate an arithmetic expression for many different values without pro-
gramming a loop. In the first section, we combine the power of NumPy and Astropy
and compute the positions of objects on the celestial sphere. Moreover, we introduce
Matplotlib to produce plots from array data. Further applications are shown in the
context of Kepler’s laws and tidal forces, for example, printing formatted tables and
plotting vector maps.

2.1 Spherical Astronomy

In astronomy, the positions of stars are specified by directions on the sky, i.e. two
angular coordinates. The radial distance of the star from Earth would be the third
coordinate, but distances are not known for all astronomical objects. As long as
distances do not matter, all astronomical objects can be projected in radial directions
onto a sphere with Earth at its center (the size of the sphere does not matter, but you
can think of it as a distant spherical surface). This is the so-called celestial sphere.1
For an observer on Earth, the position of astronomical objects depends on geo-
graphical latitude and longitude and varies with the time of day. To specify positions
independent of the observer, angular coordinates with respect to fixed reference direc-
tions are used. In the equatorial coordinate system, one reference direction is given
by Earth’s rotation axis (or, equivalently, the orientation of the equatorial plane). The
orientation of the rotation axis is fixed because of angular momentum conservation.2
The angular distance of a star from the equatorial plane is called declination and
denoted by δ. The other reference direction is defined by the intersection between

1 In ancient and medieval times, it was thought that there is actually a physical sphere with the
stars attached to it and Earth at its center. This is known as geocentric world view. The celestial
sphere in modern astronomy is merely a useful mathematical construction with no physical meaning
whatsoever.
2 This is not exactly true since other bodies in the solar system cause perturbations, but changes are

sufficiently small over a human’s lifetime.

© Springer Nature Switzerland AG 2021 19


W. Schmidt and M. Völschow, Numerical Python in Astronomy and Astrophysics,
Undergraduate Lecture Notes in Physics,
https://doi.org/10.1007/978-3-030-70347-9_2
20 2 Computing and Displaying Data

Fig. 2.1 Celestial sphere north


with coordinates α (right celestial pole
ascension) and δ
(declination) of a stellar
object. Earth’s orbital plane
(ecliptic) intersects the
sphere along the red circle,
which is inclined by the autumnal
angle 0 (obliquity) with equinox 
respect to the celestial
equator. The celestial
equator is the outward
projection of Earth’s equator
celestia
onto the celestial sphere. The
intersection points of the
0 l equator
vernal 
ecliptic
ecliptic and the celestial
equator are the two equinox
equinoxes

s outh
c e l e s t ial p o l e

the equatorial plane and the plane of Earth’s orbital motion around the Sun. The fixed
orientation of the orbital plane, which is called ecliptic, is also a consequence of angu-
lar momentum conservation (in this case the angular momentum of orbital motion).
The second coordinate in the equatorial system, which is called right ascension α, is
the angle measured from one of the two points where the celestial sphere is pierced
by the line of intersection of the equatorial an orbital planes. The zero point for the
right ascension is known as vernal equinox, the opposite point as autumnal equinox.
If all of this sounds rather complicated, it will become clear from the illustration in
Fig. 2.1. See also [3, Sect. 2.5].

2.1.1 Declination of the Sun

While the declination of stars is constant, the position of the Sun changes in the
equatorial system over the period of a year. This is a consequence of the inclination
of Earth’s rotation axis with respect to the direction perpendicular to the ecliptic,
which is equal to 0 = 23.44◦ . The angle 0 is called obliquity of the ecliptic. The
annual variation of the declination of the Sun is approximately given by3
  
360◦
δ = − arcsin sin 0 cos (N + 10) (2.1)
365.24

3 See en.wikipedia.org/wiki/Position_of_the_Sun.
2.1 Spherical Astronomy 21

where N is the difference in days starting from 1st January. So the first day of the year
corresponds to N = 0, and the last to N = 364 (unless it is a leap year). The fraction
360◦ /365.24 equals the change in the angular position of Earth per day, assuming a
circular orbit. This is just the angular velocity ω of Earth’s orbital motion around the
Sun in units of degrees per day.4
The Sun has zero declination at the equinoxes (intersection points of celestial
equator and ecliptic) and reaches ±0 at the solstices, where the rotation axis of
the Earth is inclined towards or away from the Sun. The exact dates vary somewhat
from year to year. In 2020, for instance, equinoxes were on 20th March and 22nd
September and solstices on 20th June and 21st December (we neglect the exact times
in the following). In Exercise 2.2 you are asked to determine the corresponding values
of N . For example, the 20th of June is the 172nd day of the year 2020. Counting
from zero, we thus expect the maximum of the declination δ = 0 (first solstice) for
N = 171. Let us see if this is consistent with the approximation (2.1). The following
Python code computes the declination δ based on this formula for a given value of N :

1 import math
2
3 N = 171 # day of 1st solstice
4 omega = 2*math.pi/365.24 # angular velocity in rad/day
5 ecl = math.radians(23.44) # obliquity of the ecliptic
6
7 # approximate expression for declination of the Sun
8 delta = -math.asin(math.sin(ecl)*math.cos(omega*(N+10)))
9 print("declination = {:.2f} deg".format(math.degrees(delta)))

The result

declination = 23.43 deg

is close to the expected value of 23.44◦ . To implement Eq. (2.1), we use the sine,
cosine, and arcsine functions from the math library. The arguments of these
functions must be specified in radians. While the angular velocity is simply given
by 2π/365.24 rad/d (see line 4), 0 is converted into radians with the help of
math.radians() in line 5. Both values are assigned to variables, which allows
us to reuse them in subsequent parts of the program. Since the inverse function
math.asin() returns an angle in radians, we need to convert delta into degrees
when printing the result in line 9 (‘deg’ is short for degrees).
To calculate the declination for the second solstice and also for the equinoxes,
we need to evaluate the code in line 8 for the corresponding values of N . If you
put the code listed above into a Python script, you can change the value assigned to
the variable N and simply re-run the script. While this is certainly doable for a few
different values, it would become too tedious for many values (we will get to that
soon enough). Ideally, we would like to compute the Sun’s declination for several

4 The angular velocity in radians per unit time appears as factor 2π/P in Eq. (1.1).
22 2 Computing and Displaying Data

days at once. This can be done by using data structures know as arrays. An array is
an ordered collection of data elements of the same type. Here is as an example:
10 import numpy as np
11
12 # equinoxes and solstices in 2020
13 N = np.array([79, 171, 265, 355])
In contrast to other programming languages, arrays are not native to Python. They
are defined in the module numpy (the library name is also written as NumPy, see
www.numpy.org), which is imported under the alias np in line 10. The function
np.array() takes a list of values in brackets and, if possible, creates an array
with these values as elements. Like an array, a list is also an ordered collection
of data elements. In this book, we will rarely make use of lists (see, for example,
Sect. 5.5). They are more flexible than NumPy arrays, but flexibility comes at the
cost of efficiency. This is demonstrated in more detail in Appendix B.1. On top
of that, NumPy offers a large toolbox of numerical methods which are specifically
implemented to work with arrays.5 The array returned by np.array() is assigned
to the variable N (mark the difference between single value versus array in lines 3
and 13, respectively). Its main properties can be displayed by the following print
statements:
14 print(N)
15 print(N.size)
16 print(N.dtype)
which produces the output

[ 79 171 265 355]


4
int64

From this we see that N has four elements (the number of elements is obtained with
the .size attribute), which are the integers 79, 171, 256, and 355. The data type
can be displayed with the .dtype attribute (by default, 64-bit integers are used for
literals without decimal point).
How can we work with the values in an array? For example, N[0] refers to the
first element of the array, which is the number 79. Referring to a single element of
an array via an integer in brackets, which specifies the position of the element in the
array, is called indexing. The first element has index 0, the second element index 1
and so on (remember, this is Python’s way of counting). You can also index elements
from the end of the array. The last element has index −1, the element before the last
one has index −2, etc. So, for the array defined above,
17 print(N[1])
18 print(N[-3])

5 See also [1] for a comprehensive introduction to arrays.


2.1 Spherical Astronomy 23

outputs

171
171

Do you see why the value 171 is printed in both cases? Vary the indices and see for
yourself what you get. Before proceeding, let us summarize the defining properties
of an array:

Every element of an array must have the same data type. Each element is
identified by its index.

Having defined N as an array, we could calculate the declination of the Sun on day
171 (the first solstice) by copying the code from line 8 and replacing N by N[1]in the
expression for delta. Of course, this would not bring us any closer to calculating
the declination of the Sun for all four days at once. With NumPy, it can be done as
follows.
19 delta = -np.arcsin(math.sin(ecl) * np.cos(omega*(N+10)))
20 print(np.degrees(delta))
In short, the expression in line 19 is evaluated for each element of the array N and
the results are stored in a new array that is assigned to delta. The four elements of
delta are the values of the declination for the two equinoxes and solstices:

[ -0.9055077 23.43035419 -0.41950731 -23.43978827]

Not perfect (the declination at equinoxes should be zero), but reasonably close. We
use only an approximate formula after all.
To get a better idea of how the code in line 19 works, we expand it into several
steps and use a temporary array called tmp for intermediate results of the calculation:

21 # add 10 to each element of N


22 tmp = N+10
23 print(tmp)
24 print(tmp.dtype)
25
26 # multipy by omega
27 tmp = omega*tmp
28 print(tmp)
29 print(tmp.dtype)
30
31 # calculate the cosine of each element in the resulting array
32 # and multipy with the sine of the obliquity
33 tmp = math.sin(ecl)*np.cos(tmp)
24 2 Computing and Displaying Data

34 print(tmp)
35
36 # calculate the negative arcsine of each element
37 delta = -np.arcsin(tmp)
38 print(np.degrees(delta))

As you can see, it is possible to perform arithmetic operations on arrays. For


operators such as + and *, the operands must be (see also Fig. 2.2)
• either an array and a single number,
• or two arrays of identical shape (for arrays with only one index this amounts to
the same number of elements).
For example, we make use of the first option in line 22, where the number 10 is added
to each element of the array N. The resulting integers are assigned element-wise to
the array tmp:

[ 89 181 275 365]


int64

The next step is an element-wise multiplication with omega (Earth’s angular velocity
defined in line 4). Since the value of omega is a floating point number, the tmp array
is automatically converted from data type integer to float:

[1.53105764 3.11372396 4.73079608 6.27905661]


float64

Now we have the angular positions of Earth on its orbit, from which the vertical
distances of the Sun from the celestial equator can be computed. In line 33, the
NumPy function np.cos() is used to compute the cosine of each value in the tmp
array, while math.sin() can take only a single-valued argument, which is ecl
(the obliquity of the ecliptic). The product is

[ 0.01580343 -0.39763404 0.00732172 0.39778512]

and, after computing the arcsine of each element with np.arcsin, we finally get
the declinations:

[ -0.9055077 23.43035419 -0.41950731 -23.43978827]

While doing things step by step is helpful for beginners, combining all these steps
into the single statement shown in line 19 is extremely useful for the more experienced
programmer. Starting with the code for a single day (see line 8), the only modification
that has to be made is that the math module has to be replaced by numpy whenever
the argument of a function is an array. However, there is small pitfall. By comparing
the code examples carefully, you might notice that the identifiers for the arcsine
function read math.asin() and np.arcsin() in lines 8 and 19, respectively.
2.1 Spherical Astronomy 25

array = array + number array = array + array


a = b + c a = b + c

a[0] = b[0] + c a[0] = b[0] + c[0]


a[1] = b[1] + c a[1] = b[1] + c[1]
a[2] = b[2] + c a[2] = b[2] + c[2]
...

...

...

...

...
a[n-1] = b[n-1] + c a[n-1] = b[n-1] + c[n-1]

Fig. 2.2 Illustration of basic NumPy operations. Adding a number (variable) to an array, means
that the same number is added to each element in the array (left). If two arrays of size n are added,
the operator + is applied element-wise (right)

A likely mistake is to replace math.asin() by np.asin(), which would cause


Python to throw the following error message:

AttributeError: module ’numpy’ has no attribute ’asin’

Since math and numpy are independent modules, you cannot expect that the naming
of mathematical functions is always consistent.
Printing an array, results in all elements of the array being displayed in some
default format. Now, suppose we want to format the elements nicely as we did at the
beginning of this section before introducing arrays. Formatted printing of a particular
element of an array is of course possible by indexing the element. For example,
39 print("declination = {:.2f} deg".
40 format(math.degrees(delta[1])))
produces the same output as line 9 (where delta is a simple variable):

declination = 23.43 deg

To display all elements in a formatted table, we need to loop through the array.
Actually, we have already worked with such loops, for example, in line 19. Loops of
this type are called implicit. The following example shows an explicit for loop:
41 for val in delta:
42 print("declination = {:6.2f} deg".
43 format(math.degrees(val)))
The loop starts with the first element in the array delta, assigns its value to the
variable val, which is the loop variable (similar to the loop counter introduced in
Sect. 1.3), and then executes the loop body. The loop in the example above encom-
passes only a single print statement. After executing this statement, the loop contin-
ues with the next element and so on until the end of the array (the highest index) is
reached:
26 2 Computing and Displaying Data

declination = -0.91 deg


declination = 23.43 deg
declination = -0.42 deg
declination = -23.44 deg

However, the output is not really satisfactory yet. While repeatedly printing
declination is redundant, important information for understanding the data is
missing. In particular, the days to which these values refer are not specified. A bet-
ter way of printing related data in arrays is, of course, a table. In order to print the
days and the corresponding declinations, we need to simultaneously iterate through
the elements of N and delta. One solution is to define a counter with the help of
Python’s enumerate() function:
44 print("i day delta [deg]")
45 for i,val in enumerate(delta):
46 print("{1:d} {2:3d} {0:8.2f}".\
47 format(math.degrees(val),i,N[i]))
Compared to the for loops discussed in Sect. 1.3, the range of the counter i is
implicitly given by the size of an array: It counts through all elements of delta
and, at the same time, enables us to reference the elements of N sequentially in the
loop body. Execution of the loop produces the following table:

i day delta [deg]


0 79 -0.91
1 171 23.43
2 265 -0.42
3 355 -23.44

Here, the arguments of format() are explicitly ordered. The placeholder {1:d} in
line 46 indicates that the second argument (index 1 before the colon) is to be inserted
as integer at this position. The next placeholder refers to the third argument (index 2
before the colon) and the last one to the first argument. The format specifiers ensure
sufficient space between the columns of numbers (experiment with the settings). The
header with labels for the different columns is printed in line 44 (obviously, this has
to be done only once before the loop begins).
Surely, instead of enumerating delta, you could just as well enumerate N. Is
it possible to write a loop that simultaneously iterates both arrays without using
an explicit counter? Actually, this is the purpose of the zip() function, which
aggregates elements with the same index from two or more arrays of equal length.
In this case, the loop variable is a tuple containing one element from each array.
We will take a closer look at tuples below. All you need to know for the moment is
that the tuple row in the following code example contains one element of N and the
corresponding element of delta, forming one row of the table we want to print.
Tuple elements are indexed like array elements, so row[0] refers to the day and
row[1] to the declination for that day.
2.1 Spherical Astronomy 27

48 print("day delta [deg]")


49 for row in zip(N,delta):
50 print("{0:3d} {1:8.2f}".
51 format(row[0],math.degrees(row[1])))
Apart from the index column, we obtain the same output as above:

day delta [deg]


79 -0.91
171 23.43
265 -0.42
355 -23.44

If you replace lines 50–51 by the unformatted print statement print(row), you
will get:

(79, -0.01580409076383853)
(171, 0.40893682550286947)
(265, -0.007321783769611206)
(355, -0.4091014813515704)

While brackets are used for lists and arrays, tuples are enclosed by parentheses.
The most important difference is that tuples are immutable, i.e. it is not possible
to add, change or remove elements. For example, the tuples shown above are fixed
pairs of numbers, similar to coordinates (x, y) for points in a plane. Suppose you
want to change day 355 to 364. While it is possible to modify array N by setting
N[3] = 364, you are not allowed to assign a value to an individual element in a
tuple, such as row[0]. You can only overwrite the whole tuple by a new one (this
is what happens in the loop above).

2.1.2 Diurnal Arc

From the viewpoint of an observer on Earth, the apparent motion of an object on


the celestial sphere follows an arc above the horizon, which is called diurnal arc
(see Fig. 2.3). The time-dependent horizontal position of the object is measured by its
hour angle h. An hour angle of 24h corresponds to a full circle of 360◦ parallel to the
celestial equator (an example is the complete red circle in Fig. 2.3). For this reason,
h is can be equivalently expressed in degrees or radians. However, as we will see
below, an hour angle of 1h is not equivalent to a time difference of one solar hour. By
definition the hour angle is zero when the object reaches the highest altitude above
the horizon (see also Exercise 2.4 and Sect. 2.1.3). The hour angle corresponding to
the setting time, when the object just vanishes beneath the horizon, is given by6

6 See [3, Sect. 2.6] if you are interested in how this equation comes about.
28 2 Computing and Displaying Data

le

po

est rth
ial
cel no

ce
les
tial

mer
hrise E

r
ato

idian
qu
le
tia
N S

ls
ce
hset
W

le
po
s ti o u th
s

al
le
ce

Fig. 2.3 Diurnal arc of a star moving around the celestial sphere (thick red circle) in the horizontal
system (see Sect. 2.1.3) of an observer at latitude φ (the horizontal plane is shown in grey). Since the
equatorial plane is inclined by the angle 90◦ − φ against the horizontal plane, the upper culmination
of the star at the meridian is given by amax = 90◦ − φ + δ, where δ is the declination. In the co-
rotating system, the star rises at hour angle h rise , reaches its highest altitude when it crosses the
meridian at h = 0, and sets at the horizon at h set = −h rise

cos h set = − tan δ tan φ , (2.2)

where δ is the declination of the object (see Sect. 2.1) and φ the latitude of the
observer’s position on Earth. As a consequence, the variable T = 2h set measures the
so-called sidereal time for which the object is in principle visible on the sky (stars
are of course outshined by the Sun during daytime). It is also known as length of the
diurnal arc.
For example, let us consider the star Betelgeuse in the constellation of Orion.
It is a red giant that is among the brightest stars on the sky. Its declination can be
readily found with the help of astropy.coordinates, which offers a function
that searches the name of an object in online databases:
1 from astropy.coordinates import SkyCoord, EarthLocation
2
3 betelgeuse = SkyCoord.from_name(’Betelgeuse’)
4 print(betelgeuse)
When you are confronted with the output for the first time, it might require a little
bit of deciphering:

<SkyCoord (ICRS): (ra, dec) in deg


(88.79293899, 7.407064)>
2.1 Spherical Astronomy 29

This tells us that the right ascension (ra) and declination (dec) of the object named
Betelgeuse were found to be 88.79◦ and 7.41◦ , respectively.7 The variable
betelgeuse defined in line 3 represents not only an astronomical object; it is
a Python object, more specifically an object belonging to the class SkyCoord (see
Sect. 1.4 for objects in a nutshell). The attribute dec allows us to directly reference
the declination:
5 delta = betelgeuse.dec
6 print(delta)
The declination is conveniently printed in degrees (d), arc minutes (m) and arc sec-
onds (s), which is the preferred format to express angular coordinates in astronomy:
7d24m25.4304s

i.e. δ ≈ +07◦ 24 25 , where 1 = (1/60)◦ and 1 = (1/60) .


Suppose we want to determine the length of Betelgeuse’s diurnal arc as seen from
Hamburg Observatory (φ ≈ +53◦ 28 49 ). In addition to the star’s declination,
we need the position of the observer. The counterpart of SkyCoord for celestial
coordinates is EarthLocation (also imported in line 1), which allows us to set
the geographical latitude and longitude of a location on Earth:
7 import astropy.units as u
8
9 # geographical position of the observer
10 obs = EarthLocation(lat=53*u.deg+28*u.arcmin+49*u.arcsec,
11 lon=10*u.deg+14*u.arcmin+23*u.arcsec)
12
13 # get latitude
14 phi = obs.lat
In the expressions above, u.deg is equivalent to 1◦ , u.arcmin is 1 , and u.arcsec
is 1 . The units module from astropy implements rules to carry out computa-
tions in physical and astronomical unit systems. You will learn more about AstroPy
units in Sect. 3.1.1.
Next we compute h with the help of trigonometric functions from the math
module:
15 import math
16
17 h = math.acos(-math.tan(delta.radian) * math.tan(phi.radian))
It is necessary to convert the angles δ and φ to radians before applying the tangent
function math.tan(). With Astropy coordinates, all we need to do is to use the
radian attribute of an angle.8 To obtain T in hours, it is important to keep in mind

7 ICRS means International Celestial Reference System.


8 You could also work with the SkyCoord object defined in line 3 and use
betelgeuse.dec.radian as argument of math.tan(). betelgeuse.dec is an
Angle object. So there are objects within objects. However, the function math.radians() for
converting from degrees to radians is not compatible with Angle objects.
30 2 Computing and Displaying Data

that an angle of 360◦ (one full rotation of Earth) corresponds to a sidereal day,
which is about 4 min shorter than a solar day. As explained in [3, Sect. 2.13], this
is a consequence of the orbital motion of Earth. The conversion is made easy by the
units module (see also Exercise 2.5 for a poor man’s calculation):
18 T = (math.degrees(2*h)/360)*u.sday
19 print("T = {:.2f}".format(T.to(u.h)))
First T is defined in sidereal days (u.sday), which is equivalent to 24h or 360◦ .
Then we convert to solar hours (u.h) by applying the method to() in line 19. The
result is

T = 13.31 h

If it were not for the Sun, Betelgeuse could be seen 13 h at the Observatory. Of course,
the star will be visible only during the overlap between this period and the night,
which depends on the date. We will return to this question in the following section.
The diurnal arc of the Sun plays a central role in our daily life, as it determines the
period of daylight. In Sect. 2.1.1, we introduced an approximation for the declination
δ of the Sun. By substituting the expression (2.1) for δ into Eq. (2.2), we can
compute how the day length varies over the year. First we need to compute δ for N
ranging from 0 to 364. Using NumPy, this is very easy. In the following example, the
expression np.arange(365) fills an array with the sequence of integers starting
from 0 up to the largest number smaller than 365, which is 364.9 Apart from that, the
code works analogous to the NumPy-based computation for equinoxes and solstices
in Sect. 2.1.1. Since a new task begins here, the line numbering is reset to 1, although
we make use of previous assignments (an example is the latitude phi). In other
words, you would need to add pieces from above to make the following code work
as an autonomous program (you might want to try this).
1 import numpy as np
2
3 N = np.arange(365) # array with elements 0,1,2,...,364
4 omega = 2*math.pi/365.24 # Earth’s angular velocity in rad/day
5 ecl = math.radians(23.44) # obliquity of the ecliptic
6
7 # calculate declination of the Sun for all days of the year
8 delta = -np.arcsin(math.sin(ecl) * np.cos(omega*(N+10)))

Now we can compute the day length T for all values in the array delta using
functions from the numpy module (compare to the code example for Betelgeuse and
check which changes have been made):

9 Just
like range() in for loops, the general form is np.arange(start, stop, step),
where a start value different from 0 and a step other than 1 can be specified as optional arguments.
2.1 Spherical Astronomy 31

9 # calculate day length in solar hours


10 h = np.arccos(-np.tan(delta) * math.tan(phi.radian))
11 T = (np.degrees(2*h)/360) * u.sday.to(u.h)
Here, phi is still the latitude of Hamburg Observatory defined above. Of course, T
is now an array with 365 elements. Since we want the day length in solar hours, we
multiply right away with u.sday.to(u.h), which is the length of a sidereal day
in solar hours.
When dealing with large data sets (i.e. more than a few values), it is most of the
time preferable to extract some statistics or to display the data in graphical form. To
show the annual variation of the day length, producing a plot of T versus N is the
obvious thing to do. The Python library matplotlib (see matplotlib.org) provides
a module called pyplot for plotting data in arrays:
12 import matplotlib.pyplot as plt
13 %matplotlib inline
14
15 plt.plot(N, T)
16 plt.xlabel("Day")
17 plt.ylabel("Day length [hr]")
18 plt.savefig("day_length.pdf")
The function plt.plot(), where plt is a commonly used alias for
matplotlib.pyplot, produces a plot showing data points (x, y) given by the
arrays N (x axis) and T (y axis). By default, the points are joined by lines to produce a
continuous graph. Axes labels are added in lines 16 and 17. The plot is then saved to
a file called day_length.pdf in PDF format. The location of the file depends on
the directory in which you started your Python session. You can specify full path if
you want to store the plot somewhere else). You can also use other graphics formats,
such as PNG or JPG, by specifying the corresponding extension in the filename (e.g.
day_length.png).10 In line 13, you can see a so-called magic command (indi-
cated by % at the beginning of the line). It enables inline viewing of plots in IPython
and Jupyter notebooks.11
The graph can be seen as solid line in Fig. 2.4 (the dot-dashed line will be added
below). As expected, the day length is short in January, reaches a maximum at the
first solstice (N = 171) and then decreases until the second solstice is reached at
N = 355. The minimal and maximal day length can be inferred with the help of
min() and max() methods for NumPy arrays12 :
19 print("Minimum day length = {:5.2f} h".format(T.min()))
20 print("Maximum day length = {:5.2f} h".format(T.max()))

10 PDF has the advantage of containing the plot as a vector graphics: The number of pixels is not
fixed and, as a result, lines and fonts appear smooth even when viewed at higher graphical resolution.
11 Depending on your Python environment, it might be necessary to add the line plt.show() at

the bottom.
12 Functions such as np.arange() or np.tan() are called with an array as argument, whereas

min() and max() are methods called on a specific object (here, the array T).
32 2 Computing and Displaying Data

Fig. 2.4 Annual variation of the day length in Hamburg following from an approximate Eq. (2.1)
for the declination of the Sun

We get

Minimum day length = 7.20 h


Maximum day length = 16.73 h

The difference between minimal and maximal day length increases with latitude.
Beyond the polar circles (φ = ±66◦ 33 ), the day length varies between 0 and 24 h.
An example is Longyearbyen located at φ = +78◦ 13 on the Norwegian island
Spitsbergen in the far North. As we only need to know φ within an arc minute
(accuracy is limited by the approximate declination anyway), a full specification of
the geographical position using EarthLocation would rather overdo it. Instead
we simply use 1 = (1/60)◦ and immediately convert into radians:
21 phi = math.radians(78+13/60) # latitude of Longyearbyen
22
23 h = np.arccos(-np.tan(delta)*math.tan(phi))
24 T = (np.degrees(2*h)/360) * u.sday.to(u.h)
When you execute this code, you will get a

RuntimeWarning: invalid value encountered in arccos

It turns out that Python is able to handle this, but we should nevertheless try to
understand what is wrong here. Remember that the range of the declination of the
Sun is −0 ≤ δ ≤ 0 . Considering Eq. (2.2), you can convince yourself that the
right-hand side becomes smaller than −1 or greater than 1 if |φ| ≥ 90◦ − 0 , i.e. if
the location is in the polar regions. In this case, Eq. (2.2) has no solution because
2.1 Spherical Astronomy 33

the arccosine is undefined if the absolute value of its argument is greater than unity.
This corresponds to the polar night or polar day during which the Sun never rises or
sets. This can be fixed by setting cos h set equal to ±1 whenever the right-hand side
of Eq. (2.2) falls outside of the interval [−1, 1]. Using Numpy, this is easily achieved
by means of the np.clip() function:
24 tmp = np.clip(-np.tan(delta)*math.tan(phi), -1.0, 1.0)
25 h = np.arccos(tmp)
26 T = (np.degrees(2*h)/360) * u.sday.to(u.h)
Assigning the clipped right-hand side of Eq. (2.2) to a temporary array is only
intended to highlight this step. We leave it as a little exercise for you to combine
lines 24 and 25 into a single line of code and to produce and view the resulting graph
for the day length. As expected, you will find that people on Longyearbyen have to
cope with a polar night (all day dark) during winter, and a polar day lasting 24 h in
summer.
Having computed the day length for Hamburg and Longyearbyen, it would be
instructive to compare the graphs in a single plot. Obviously, we need the data for
both locations at the same time, but in the example above the data for Hamburg
were overwritten by the computation for Longyearbyen. A straightforward way of
resolving this problem would be to use differently named array, but in Python there
is a more elegant and convenient alternative. Apart from arrays in which items
are referenced by index, data can be collected in a Python dictionary. Similar to a
dictionary in the conventional sense, data items in a dictionary are referenced by
keywords rather than a numerical index. The data items of the dictionary can be just
anything, including arrays. Let us set up a dictionary associating locations with their
latitudes:
27 phi = { ’Hamburg’ : obs.lat.radian,
28 ’Longyearbyen’ : math.radians(78 + 13/60) }
In Python, a dictionary is defined by pairs of keywords and items enclosed in curly
braces. Each keyword, which has to be a string (e.g. ’Hamburg’), is separated
by a colon from the corresponding item (the expression obs.lat.radian in the
case of Hamburg) followed by a comma. How are individual items accessed? For
example,
29 print(phi[’Hamburg’])
prints the the latitude of Hamburg in radians. The syntax is similar to accessing
array elements, except for the key word instead of an index. Adding new items to a
dictionary is very easy. For example, the following assignments add New York and
Bangkok to our dictionary:
30 phi[’New York’] = math.radians(40 + 43/60)
31 phi[’Bangkok’] = math.radians(13 + 45/60)
Indeed, the dictionary now has four items, which can be checked by printing
len(phi).
34 2 Computing and Displaying Data

The following code prints all items, computes the day length for each location,
and combines them in a single plot:
32 for key in phi:
33 print(key + ": {:.2f} deg".format(math.degrees(phi[key])))
34
35 h = np.arccos(np.clip(-np.tan(delta)*math.tan(phi[key]),
36 -1.0, 1.0))
37 T = (np.degrees(2*h)/360) * u.sday.to(u.h)
38
39 plt.plot(N, T, label=key)
40
41 plt.xlabel("Day")
42 plt.xlim(0,364)
43 plt.ylabel("Day length [hr]")
44 plt.ylim(0,24)
45 plt.legend(loc=’upper right’)
46 plt.savefig("daylength.pdf")

The graphical output for the places

Hamburg: 53.48 deg


Longyearbyen: 78.22 deg
New York: 40.72 deg
Bangkok: 13.75 deg

can be seen in Fig. 2.5. As expected, the day length in Longyearbyen varies between
0 and 24 h, while people in Bangkok, which is in the tropics, experience a day length
around 12 h over the whole year. The day length in the temperate zones increases by
several hours from winter to summer.

Fig. 2.5 Annual variation of the day length at different places in the world
2.1 Spherical Astronomy 35

To understand how this output is produced, let us go through the code step by
step:
1. The code begins with a for loop iterating the dictionary phi. At first glance, this
looks exactly like a loop through an array (see Sect. 2.1.1). However, there is an
important difference. When iterating an array, the loop variable runs through the
elements of the array. In contrast, the loop variable key runs through keywords,
not the dictionary items themselves. Since the keyword is the analogue of the
index, this loop resembles more an enumeration. The items are referenced by
phi[key] in the loop body.
2. In line 33, the + operator concatenates two strings. The first string is a keyword,
i.e. the name of a location, the second string is a formatted latitude.
3. Lines 35 to 37 correspond to lines 24–26 with the noticeable difference that
phi[key] instead of phi refers to a particular latitude.
4. The last statement in the loop body (line 39) adds the graph for the current array
T, which changes with each iteration, to the plot. This means that plt.plot()
called inside a loop does not produce several plots, but accumulates graphs within
a single plot. The optional argument label=key sets the graph’s label to the
keyword. The labels are used in the legend of the plot (see below).
5. Once the loop is finished, the plot is configured by the statements in lines 41–45:
Axes are labeled, their range is limited by plt.xlim() and plt.ylim(),
and labels for the different graphs are shown in a legend in the upper right corner
of the plot.
6. Finally, the plot is saved to a PDF file. This will overwrite the previously saved
file, unless you choose a different file name.
If you are unsure about any of the steps explained above, make changes to the code
and see for yourself what happens and whether it meets your expectations.

2.1.3 Observation of Celestial Objects

While it is important to be able to specify the positions of celestial objects in a


coordinate system that is independent of time and the observer’s location, at the
end of the day you want to know where on the sky you can find the object. To that
end, the so-called horizontal coordinate system is used, which is based on an imag-
inary plane that is oriented tangential to the surface of Earth at the location of the
observer. The angular position measured in normal direction from the horizon is the
altitude a, and the angular separation from some reference direction (usually, the
North direction) parallel to the horizon is the azimuth of the object.13 This is why
the horizontal system also goes under the name of alt-azimuth system. The module
astropy.coordinates offers a powerful framework for working with celestial

13 The azimuth measured from North corresponds to the compass direction.


36 2 Computing and Displaying Data

coordinates (for more information, see docs.astropy.org/en/stable/coordinates). Sim-


ilar to SkyCoord for coordinates in the equatorial system, the alt-azimuth system
is represented by the class AltAz. In this section, we will utilize AltAz to infer
the time of observability of the star Betelgeuse. In the course of doing so, we will
touch upon some advanced aspects of Python. If you find it too complicated at this
point, you can skip over this section and return later if you like.
To begin with, we define once more the position of the observer (see also
Sect. 2.1.2). You are invited to adjust all settings to your own location and time.
1 import astropy.units as u
2 from astropy.coordinates import \
3 SkyCoord, EarthLocation, AltAz, get_sun
4
5 # geographical position of the observer
6 obs = EarthLocation(lat=53*u.deg+28*u.arcmin+49*u.arcsec,
7 lon=10*u.deg+14*u.arcmin+23*u.arcsec)
8
9 # get latitude
10 phi = obs.lat

Astropy also has a module to define time in different formats.14 By default, Time()
sets the coordinated universal time (UTC).15 To define, for example, noon in the
CEST time zone (two hours ahead of UTC) on July 31st, 2020, we shift the time by
an offset of two hours:
11 from astropy.time import Time
12
13 utc_shift = 2*u.hour # CEST time zone (+2h)
14
15 noon_cest = Time("2020-07-31 12:00:00") - utc_shift
Printing noon_cest shows the UTC time corresponding to 12am CEST. The shift
to UTC is necessary because AltAz expects UTC time.
With time and location, we can define our horizontal coordinate system. We want
to follow the star’s position over a full 24 h period and determine the time window
for observation during night. Since altitude and azimuth are time dependent, we
need to create a sequence of frames covering a whole day (frame is synonymous to
coordinate system):
16 import numpy as np
17
18 # time array covering next 24 hours in steps of 5 min
19 elapsed = np.arange(0, 24*60, 5)*u.min
20 time = noon_cest + elapsed
21

14 See
docs.astropy.org/en/stable/time.
15 Thecoordinated universal time (UTC) is an international standard for time. It is close (within a
second) to the universal time that is related to Earth’s rotation relative to distant celestial objects.
2.1 Spherical Astronomy 37

22 # sequence of horizontal frames


23 frame_local_24h = AltAz(obstime=time, location=obs)
In lines 19–20, a time sequence is created, starting from noon (CEST) in steps of
five minutes covering an interval of 24 h. Let us look at this in more detail. First
np.arange() creates an array of numbers (0, 5, 10, . . .). Calling
type(np.arange(0, 24*60, 5))
informs us that the type of the object returned by np.arange() is

numpy.ndarray

What is the type of an object? It is just the class to which the object belongs.
Do not confuse this with the data type of the array (i.e. the type of its elements;
see Sect. 2.1.1). As we shall see, the initially created NumPy array undergoes quite
a metamorphosis. To define the time elapsed since noon in minutes, the array is
multiplied with u.min. While multiplication with a number does not affect the
type,
type(elapsed)
returns

astropy.units.quantity.Quantity

As mentioned in Sect. 1.4, quantities with units are instances of the Quantity
class, which is defined in the submodule astropy.units.quantity. On the
other hand, when printing elapsed, you will probably conclude that it pretty much
looks like an array. Can we confirm this? The function isinstance() tells you if
something belongs to a certain class (this is what instance means). While an object
is of course an instance of the class defining its type,16 it can also belong to other
classes. Indeed,
isinstance(elapsed, np.ndarray)
yields True, i.e. elapsed is an array of sorts. Astropy supports arrays with units,
which are a subclass of NumPy arrays. A subclass can extend attributes and methods
of an existing base class, here numpy.ndarray. This is known as inheritance.
Now you might guess that time is also an array, created by adding a fixed value
to the elements of elapsed (see line 20). But no,
isinstance(time, np.ndarray)
returns

16 You can check this with isinstance(elapsed, u.quantity.Quantity). It is impor-


tant to correctly reference the class in your namespace. Since we imported astropy.units using
the alias u, we need to use the name u.quantity.Quantity. However, the function type()
always returns the class in the generic module namespace.
38 2 Computing and Displaying Data

False

Without going into too much detail, time has some array-like features, but it is not
derived from NumPy. And it has its own way of treating units (basically, it replaces
the notion of units by time formats). In general, it cannot be used in place of an array,
such as elapsed. The reason we need it is to create frames by means of AltAz()
(see line 23).
After this little detour to classes and inheritance, we retrieve Betelgeuse’s coordi-
nates as shown in Sect. 2.1.2 and then transform it to the observer’s horizontal frame
for the times listed in time.
28 # star we want to observe
29 betelgeuse = SkyCoord.from_name(’Betelgeuse’)
30
31 betelgeuse_local = betelgeuse.transform_to(frame_local_24h)

The method transform_to() turns the declination and right ascension of the
star into altitudes and azimuths for the time sequence of frames defined in line 23
above. Modern telescopes are controlled by software, making it relatively easy for the
observer to direct a telescope to a specific celestial object. Basically, the software uses
something like Astropy’s transform_to() and moves the telescope accordingly.
Historical instruments, such as the 1 m reflector shown in Fig. 2.6, are a different
matter. They are operated manually and the observer needs to know the position of
an object on the sky.
To determine the phases of daylight, we need to determine the Sun’s position in
the same frames. Since the position of the Sun changes not only in the horizontal,
but also in the equatorial coordinate system, Astropy offers a special function for the
Sun:
32 # time-dependent coordinates of the Sun in equatorial system
33 sun = get_sun(time)
34
35 sun_local = sun.transform_to(frame_local_24h)

This completes the preparation of the data.


Now let us plot the altitude of Betelgeuse and the Sun for the chosen time interval
and location:
36 import matplotlib.pyplot as plt
37 %matplotlib inline
38
39 elapsed_night = elapsed[np.where(sun_local.alt < 0)]
40 betelgeuse_night = \
41 betelgeuse_local.alt[np.where(sun_local.alt < 0)]
42
43 plt.plot(elapsed.to(u.h), sun_local.alt,
44 color=’orange’, label=’Sun’)
45 plt.plot(elapsed.to(u.h), betelgeuse_local.alt,
46 color=’red’, linestyle=’:’,
2.1 Spherical Astronomy 39

Fig. 2.6 Hamburg Observatory’s 1 m reflector. When the instrument was commissioned in 1911, it
was the fourth largest reflector worldwide. In the first half of the 20th century, the astronomer Walter
Baade used the telescope to observe a great number of star clusters, gas nebulae, and galaxies. For
further information, see www.physik.uni-hamburg.de/en/hs/outreach/historical/instruments.html
(Image credit: Markus Tiemann, Martiem Fotografie)

47 label=’Betelgeuse (daylight)’)
48 plt.plot(elapsed_night.to(u.h), betelgeuse_night,
49 color=’red’, label=’Betelgeuse (night)’)
50
51 plt.xlabel(’Time from noon [h]’)
52 plt.xlim(0, 24)
53 plt.xticks(np.arange(13)*2)
54 plt.ylim(0, 60)
55 plt.ylabel(’Altitude [deg]’)
56 plt.legend(loc=’upper center’)
57 plt.savefig("Betelgeuse_obs_window.pdf")
Let us begin with the plot statement in lines 43–44. We plot the altitude of the Sun
(sun_local.alt) as a function of the time elapsed since noon in hours. Rather
than using default colors, we set the line color to orange (color=’orange’).
The graph for the altitude of Betelgeuse has two components. We use a dotted line
(linestyle=’:’) in red to plot the altitude over the full 24 hour interval (lines
45–47). Since the star is only observable during night, the dotted line is overplotted
by a solid line for those times where the altitude of the Sun is negative, i.e. below
the horizon—that is basically the definition of night. How do we do that? You find
the answer in lines 39–41, where the expression
40 2 Computing and Displaying Data

Fig. 2.7 Altitude of the Sun and the star Betelgeuse as seen from Hamburg Observatory on July
31st, 2020

np.where(sun_local.alt < 0)
appears like an index in brackets. The function np.where() identifies those ele-
ments of sun_local.alt which are less than zero and returns their indices
(remember that array elements are identified by their indices). These indices in turn
can be applied to select the corresponding elements in elapsed and
betelgeuse_local.alt, producing masked arrays. This is equivalent
to looping through the arrays, where any element elapsed[i] and
betelgeuse_local.alt[i] for which sun_local.alt[i] is not
smaller than zero (Sun above the horizon) is removed. In Exercise 2.4, you will
learn how np.where() can be utilized to choose between elements of two arrays
depending on a condition. This can be regarded as the array version of branching.
The result can be seen in Fig. 2.7. Since objects with negative altitude are invisible
for the observer, only positive values are shown (see line 54). Moreover, the tick labels
for time axis are explicitly set with plt.xticks() in line 53. Night is roughly
between 9 pm and 6 am (18 h counted from noon on the previous day).17 Betelgeuse
rises around 4 o’clock in the morning and there only two hours left before sunrise.
This is the interval for which the solid red line plotted in lines 48–49 is visible in
the plot. Actually, the observation window is even narrower. Dawn is rather long
at a latitude of 53◦ . The period of complete darkness, the so-called astronomical
night, is defined by δ ≤ −18◦ . Although Betelgeuse is a very bright star, Hamburg
is definitely not the optimal place to observe the star in summer (see Exercise 2.7).

17 You might be surprised that the Sun does not reach its highest altitude at noon. One obvious

reason is that summer time shifts noon (12 pm) by one hour. Moreover, depending on the longitude
of the observer, time zones are not perfectly aligned with the Sun’s culmination.
Discovering Diverse Content Through
Random Scribd Documents
CHAPTER I.
On the Road to Kabul.

The start and the wherefore. Unsettled condition of


Afghanistan. Departure from Peshawur. Jumrûd Fort and
the Watch-tower, The Afghan guard. The Khyber defile.
Eccentricities of Rosinante. Lunch at Ali Musjid. Pathan
villages. Pathans, their appearance and customs. Arrival at
Landi Kotal Serai. The Shenwari country. Caravan of
Traders. Dakka. Dangers of the Kabul River, Mussaks.
Camp at Bassawal. Chahardeh. Mountain road by the river.
Distant view of Jelalabad.
It was with no small amount of pleasurable excitement that I
donned the Afghan turban, and with Sir Salter (then Mr.) Pyne and
two other English engineers, started from Peshawur for Kabul to
enter the service of the Amîr.
I had made the acquaintance of Mr. Pyne in London, where I was
holding a medical appointment. He had returned to England, after
his first short visit to Kabul, with orders from the Amîr to buy
machinery, procure engineering assistants, and engage the services
of an English surgeon.
I gathered from his yarns that, for Europeans at the present day, life
among the Afghans was likely to be a somewhat different thing from
what it was a few years ago.
In the reigns of Dost Mahomed and Shere Ali it was simply an
impossibility for a European to take up a permanent residence in
Afghanistan; in fact, except for occasional political missions, none
was allowed to enter the country.
We do, indeed, hear of one or two, travelling in disguise, who
managed to gather valuable facts concerning the country and its
inhabitants, but we learn from their narratives that the hardships
they were forced to undergo were appalling. For ages it has been a
proverb among the natives of India that he who goes to Kabul
carries his life in his hand. They say, “Trust a cobra, but never an
Afghan;” and there is no denying the fact that the people of
Afghanistan have had the credit from time immemorial of being a
turbulent nation of highway robbers and murderers. If there were
any chance of plunder they spared not even their co-religionists,
and, being fanatical Mahomedans, they were particularly “down” on
any unfortunate traveller suspected of being a Feringhi and an
infidel.
A busy professional life following upon the engrossing studies of
Hospital and University, had given me neither time nor any particular
inducement to read about Afghanistan, so that when I left England I
knew very little about the country. However, on reaching India I
found plenty of people ready enough to enlighten me.
I heard, from officers who had been on active service in Afghanistan
in 1880, of the treacherous and vindictive nature of the people; of
the danger when they were in Kabul of walking in the town except in
a party of six or seven; of the men who, even taking this precaution,
had been stabbed. I heard, too, a great deal about the assassination
of the British envoy in Kabul, Sir Louis Cavagnari, in 1879; of the
highway dangers of the two hundred mile ride from the British
frontier to Kabul, and, remembering that we were about to trust our
lives absolutely for some years to the good faith of these proverbially
treacherous Afghans, it struck me we were in for an experience that
was likely to be exciting.
What actually happened I will relate.
We were all ready to start from Peshawur one day
in March, 1889. The Amîr’s agent, a stout and Departure from
Peshawur.
genial old Afghan, named Abdul Khalik Khan, had
provided us with turbans, tents, and horses; we had received
permits from the Government to cross the frontier, and our baggage
was being loaded on the pack-horses when a telegram arrived
directing us to await further orders. We were informed that there
was fighting among the Pathans in the Khyber, and we were to
postpone our departure till it was over. This seemed a healthy
commencement.
Three days afterwards, however, we were allowed to proceed. The
first day’s march was short, simply from the cantonment across the
dusty Peshawur plain to Jumrûd fort: about nine miles. The fort,
originally built by the Sikhs in 1837, has been repaired and
strengthened by the British, who now hold it. It is said, however, to
be of no very great value: one reason being because of the
possibility of its water supply being cut off at any time by the Afghan
hillmen.
The servants, with the pack-horses and tents, took up their quarters
in the courtyard, but we four accompanied the officer in charge up
to his rooms in the watch-tower. From here we had an extensive
view over the Peshawur valley. The entry to the Khyber was about
three miles off to the west. We had left the cantonment early in the
afternoon, and soon after our arrival it became dark. We dined, and
were thinking of turning in to prepare for our long hot ride on the
morrow, when we found, instead, that we should have to turn out.
The fort was not an hotel, and had no sleeping accommodation to
offer us. I looked at Pyne. The baggage was down there in the
courtyard, somewhere in the dark, and our bedding with it. Should
we——? No! we would roll up our coats for pillows, throw our ulsters
over us, and sleep on the platform outside the tower. We were proud
to do it. But—the expression “bed and board” appealed to my
feelings ever afterwards.
We had an early breakfast.
In the morning we found the guard of Afghan cavalry waiting for us
in the travellers’ caravansary near the fort. There were about forty
troopers—“the Amîr’s tag-rag,” as the British subalterns
disrespectfully called them.
They were rough-looking men, dressed more or less alike, with
turbans, tunics, trousers, and long boots. Each had a carbine slung
over his shoulder and a sword at his side. A cloak or a rug was rolled
up in front of the saddle and a couple of saddle bags strapped
behind. They carried no tents. I cannot say they looked smart, but
they looked useful. Of the individual men some were rather Jewish
in type, good-looking fellows—these were Afghans; and one or two
had high cheek-bones and small eyes—they were Hazaras. All were
very sunburnt, and very few wore beards. This last fact surprised
me; I had thought that Mahomedans never shaved the beard.
It is, however, not at all an uncommon thing for soldiers and officers
in the Afghan army to shave all but the moustache; but I learnt that
in a Kabul court of law, when it is necessary in swearing to lay the
hand upon the beard, that a soldier’s oath is not taken: he has no
beard to swear by.
The baggage was sent off under a guard of about
a dozen troopers. We followed with the rest and The Khyber Pass.
entered the gorge of the Khyber. It is a holiday trip
now-a-days to ride or drive into the Pass. You obtain a permit from
the Frontier Political Officer, and are provided with a guard of two
native cavalrymen, who conduct you through the Pass as far as
Landi Kotal. This is allowed, however, on only two days in the week,
Mondays and Thursdays—the Koffla, or merchant days. The Khyber
Pathans have entered into an agreement with the Government that
for the payment of a certain subsidy they will keep the Pass open on
those two days: will forbear to rob travellers and merchants.
Doubtless it is an act of great self-denial on their part, but they keep
faith.
Riding along the Pass one sees posted at intervals, on rock or peak,
the Pathan sentry keeping guard. He is a fine-looking man, as he
stands silently in his robes: tall, with black beard and moustache. His
head may be shaven or his long hair hang in ringlets over his
shoulders. He wears a little skull cap with, may be, a blue turban
wound carelessly round it: a loose vest reaching the knee is confined
at the waist by the ample folds of the cummerbund, or waist shawl.
In this is thrust a pistol or two and a big ugly-looking knife. The
short trousers of cotton, reaching half-way down the leg, are loose
and not confined at the ankle like the townsman’s “pyjamas.” On the
feet he wears the Afghan shoe with curved up toe: the ornamental
chapli or sandal of leather: or one neatly made of straw. Draped with
classical beauty around the shoulders is the large blue cotton lûngi,
or cloak. If the morning is cold the sheepskin postîn is worn, the
sleeves of which reach to the elbow. If it rain the postîn is reversed,
and the wool being outside shoots the wet off. The next day’s sun
dries it.
The rifle he has may be an old English musket, a Martini-Henry or a
native jezail, but, whatever it be, in the Pathan’s hands it is deadly.
The scenery in the Khyber is rugged and wild, the only vegetation
being stunted bushes and trees at the bottom of the gorge. The
rocky cliffs rise precipitously on either side, and gradually closing in,
are, at a little distance from the entry, not more than three or four
hundred feet apart. The road at one time leads by the stream at the
bottom of the gorge, and later creeping up the mountain it winds in
and out round the spurs or fissures half-way up the face of the cliff.
It is a good broad road, made, and kept in excellent repair, by the
British. Nevertheless, I was far from happy: my mare, accustomed to
a town, was frightened by the rocks, the sharp turns, and the
precipices, and desired to escape somewhere, anywhere—and there
was no parapet.
By-and-bye, however, we descended and were in a
stony valley, for the Pass varies in width from ten Eccentricities of
Rosinante.
or twelve feet to over a hundred yards. Mr. Pyne
suggested a canter. A canter! I knew the mare by this time, and I
had on only a hunting bit. Off we went. Pyne had a good horse, a
Kataghani that had been given him in Kabul, but we swept ahead,
my bony mare and I, much to Pyne’s disgust—and mine, for I
couldn’t hold her. Roads! what were roads to her? Away she went
straight up the valley, and such a valley! The ground was covered
with pebbles and big stones, and cut up by dry water-courses wide
and narrow. The narrower gulleys she cleared at a bound, the wider
she went headlong into and out of before I had time to hope
anything. I soon was far ahead of the guard, only the Captain
managed to keep somewhere in my wake, shouting, “Khubardar,”
“Take care!” I yearned to khubardar with a great yearn, for in
addition to the danger of breaking my neck was that of being shot.
Sawing at the reins did not check her, and at last I flung myself
back, caught the cantle of the saddle with my right hand, and jerked
at the curb. I was tossed in the air at every stride, and my loaded
revolver thumped my hip at each bound, but her speed diminished,
and at last she gave in and stopped, panting and snorting. Then the
Captain came clattering up, and I was obliged to turn the mare
round and round or she would have been off again. The Captain
smiled and said, “Khob asp,” “It is a good horse.”
“Bally,” I said, which means “Yes.”
We adjusted the saddle and waited till the others came up. Pyne
remonstrated with me and told me I ought not to have done such a
thing, it was not safe! He viewed it as a piece of eccentricity on my
part.
About eight miles from Jumrûd, and where the defile is narrow and
precipitous, is the Ali Musjid fort. This is built on a high, nearly
isolated, rocky hill to the left or south of the road. The small Musjid,
or Mosque, from which the place takes its name, stands by the
stream at the bottom of the defile. It was erected, according to
tradition, by the Caliph Ali. The fort, which is called the key of the
Khyber, has at different times been in possession of Afghans and
British. We hold it now. The last man we dislodged was General
Gholam Hyder Khan, Orak zai, who was then in the service of Amîr
Yakûb Khan. He is now Commander-in-Chief of the Amîr’s army in
Kabul and Southern Afghanistan. He is a big stout man, about six
feet three inches in height. When I saw him in Kabul he did not
seem to bear any malice on account of his defeat. There is another
General Gholam Hyder, a short man, who is Commander-in-Chief in
Turkestan, and of whom I shall have occasion to speak hereafter.
At Ali Musjid we sat by the banks of the streamlet and hungrily
munched cold chicken and bread; for Mr. Pyne had suggested at
breakfast our tucking something into our holsters in case of
necessity: he had been there before.
Beyond Ali Musjid the narrow defile extended some distance, and
then gradually widening out we found ourselves on an elevated
plateau or table-land, bounded by not very high hills. The plain was
some miles in extent, and we saw Pathan villages dotted here and
there, with cornfields surrounding them. The villages were fortified.
They were square, surrounded by a high wall with one heavy gate,
and with a tower at one or all four corners. The houses or huts were
arranged inside in a row against the wall, and being flat roofed and
the outer wall loopholed there was at once a “banquette” ready for
use in case the village should be attacked.
The mountains and valleys of the Khyber range and of the other
Indian frontier mountains are inhabited by these semi-independent
Afghans called, collectively, Pathans or Pukhtana. There are many
learned and careful men among the Government frontier officers
who are at present investigating the origin and descent of the
Pathan tribes.
The Khyberi Pathan whom I have described as the
“guard” of the Pass is a fair type of the rest. The Pathans; their
Appearance and
men are quarrelsome, are inveterate thieves, but Customs.
are good fighters. Many of them enter the British
service and make excellent soldiers. They are divided into a great
number of different tribes, all speaking the same language, Pukhtu,
or Pushtu, and bound by the same code of unwritten law, the
Pukhtanwali. The neighbouring tribes, however, are jealous of one
another and rarely intermarry. There is the vendetta, or law of
retaliation, among them, and almost always an ancient feud exists
between neighbouring villages. The women, unlike the Mahomedan
townswomen, are not closely veiled; the head is covered by a blue
or white cotton shawl, which, when a stranger approaches, is drawn
across the lower part of the face. They wear a long dark-blue robe
reaching midway between knee and ankle, decorated on the breast
and at the hem with designs in red. The feet are generally bare, and
the loose trousers are drawn tight at the ankle. Their black hair
hangs in two long plaits, the points being fastened with a knot of
many-coloured silks.
When one considers the nature of these mountaineers—hereditary
highway robbers and fighters, crack shots, agile and active, and
when one observes the unlimited possibility they have among rocks,
valleys, and passes of surprising a hostile army and of escaping
themselves—the advantage of a “subsidy” becomes apparent.
At the distant or west extremity of the plateau, where we saw the
Pathan villages, is the Landi Kotal serai. An ordinary caravansary in
Afghanistan is a loopholed enclosure with one gate, and is very like
the forts or villages I have described. At Landi Kotal, in addition to
the native serai, is one built by the Government. It is strongly
fortified, with bastion, embrasure, and banquette, and any part of
the enclosure commanded by the adjoining hills is protected by a
curtain or traverse.
Hot, tired, and thirsty, we four rode into the fort, and were received
by the British officer in charge. The Afghan guard took up their
quarters in the native serai outside. Good as the road was it had
seemed an endless journey. Winding in and out in the heat we had
seemed to make but little progress, and the unaccustomed weight of
the turban and the dragging of the heavy revolver added
considerably to our fatigue; but the march, after all, was not more
than five-and-twenty miles.
This time there was ample accommodation for us, and after an
excellent dinner, the last I had in British territory for many a long
month, we turned in.
After Landi Kotal, the Khyber narrows up. We
wound in and out round the fissures and water The Shenwaris:
Caravan of
channels in the face of the mountain, and climbed Traders.
up and down as before; but presently the guard
unslung their carbines and closed in round us. It was the Shenwari
country we were now traversing, and these Pathans, even by the
Amîr’s soldiers, are considered dangerous; for what says the
proverb, “A snake, a Shenwari, and a scorpion, have never a heart to
tame.” The Amîr had, however, partly subjugated them even then,
and a tower of skulls stood on a hill outside Kabul.
Then we came to a series of small circular dusty valleys surrounded
by rocky mountains. There was nothing green, and the heat was
very great, it seemed to be focussed from the rocks. Further on we
caught up with a caravan of travelling merchants with their camels
and pack-horses.
These men belong almost entirely to a tribe of Afghans called
Lohani. They come from the mountains about Ghazni. In the autumn
they travel down to India with their merchandise and go about by
rail and steamer to Bombay, Karachi, Burma, and other places for
the purposes of trade. In the spring they go northward to Kabul,
Herat, and Bokhara. Under the present Amîr they can travel in
Afghanistan without much danger, but in the reigns of Shere Ali and
Dost Mahomed they had practically to fight their way.
They go by the name of Povindia, from the Persian word Parwinda,
“a bale of merchandise.” When I was in Turkestan I became
acquainted with one of these men. He was a white bearded old
Afghan who had been, he told me, to China, Moscow, and even to
Paris. He tried to sell me a small nickel-plated Smith and Wesson
revolver.
We rode by the caravan of traders and reached Dakka, on the banks
of the Kabul river. This is the first station belonging to the Amîr. The
Colonel commanding came out to receive us, and conducted us to a
tent on the bank, where we sat and drank tea. We were much
interested in watching some Afghans swimming down the river
buoyed up by inflated skins—“mussaks.” Grasping the skin in their
arms they steered with their legs, the force of the current carrying
them rapidly along. Two men took a donkey across. They made a
raft by lashing four or five skins to some small branches; and tying
the donkey’s legs together, they heaved him sideways on to the raft.
Clinging to the skins they pushed off, and, striking out with the legs,
they were carried across in a diagonal direction. By-and-bye some
men floated by on a rough raft made of logs. They were taking the
wood to India for sale.
The river here, though not very deep, is dangerous, on account of
the diverse currents.
In the centre, to the depth of three or four feet, the current runs
rapidly down the river; deeper it either runs up the river or goes
much slower than the surface water.
A few years later I was travelling past here, one hot summer, with
Mr. Arthur Collins, recently geologist to the Amîr, and we determined
to bathe. Mr. Collins, who was a strong swimmer, swam out into the
middle: I paddled near the bank where the current was sweeping
strongly up stream. Mr. Collins, out in the middle, was suddenly
turned head over heels and sucked under. He could not get to the
surface, and, therefore, swam under water, happily in the right
direction, and he came up very exhausted near the bank.
After resting, we rode on through some hot pebbly
valleys, with no sign of vegetation, until we Camp at
Bassawal.
reached Bassawal, where we camped. The tents
were put up, sentries posted, and the servants lit wood fires to
prepare dinner. It soon became dark, for the twilight is very short.
We were advised to have no light in our tent, lest the tribes near
might take a shot at us; and we dined in the dark. It was the first
night I had ever spent in a tent, and to me it seemed a mad thing to
go to bed under such circumstances. I remember another night I
spent near here some years afterwards, but that I will speak of later.
On this occasion the night passed quietly.
The next morning they woke us before daybreak. The cook had lit a
fire and prepared breakfast—fried eggs, tinned tongue, and tea. As
soon as we were dressed the tents were struck, and while we were
breakfasting the baggage was loaded up. We had camp chairs and a
little portable iron table, but its legs became bent, and our
enamelled iron plates had a way of slipping off, so that we generally
used a mule trunk instead. The baggage was sent off, and we sat on
the ground and smoked. Starting about an hour afterwards, we rode
along through fertile valleys with cornfields in them: here water for
irrigation could be obtained. In March the corn was a foot high. Then
we rode across a large plain covered with a coarse grass. It was not
cultivated because of the impossibility of obtaining water. We
camped further on in the Chahardeh valley, which was partly
cultivated and partly covered with the coarse grass. The tents were
put up near a clump of trees, where there was a well. Unfortunately,
there was also the tomb of some man of importance, and other
graves, near the well. The water we had from it tasted very musty
and disagreeable. Next day we went through other cultivated valleys
to the mountains again. The river here made a curve to the south,
and the mountains came close up to the bank. The road, cut out of
the face of the mountain, ran sometimes level with the bank,
sometimes a hundred feet or more above it. It was much pleasanter
than the Khyber Pass, for to the north (our right) there was the
broad Kabul river, with cultivated fields on its northern bank, and
though the scorching heat of the sun was reflected from the rocks
there was a cool breeze blowing. I thought it was a wonderfully
good road for native make, but I found, on enquiry, that it had been
made by the British during the Afghan war.
After rounding a shoulder of the mountain, where the road was high
above the river, we could see in the distance the Jelalabad Plain and
the walled city of Jelalabad. However, it was a long way off and we
had to ride some hours before we reached it.
When on a journey in Afghanistan it is not usual to trot or canter, in
fact, the natives never trot. They ride at a quick shuffling walk: the
horse’s near-side feet go forward together, and his off-side feet
together—a camel’s walk. It is an artificial pace, but very restful.
There was a shorter route which we could have
taken from Bassawal, avoiding Jelalabad altogether, Advantages of
Cultivation.
but it was mostly over pebbly hills and desert
plains, and was exceeding hot. From Dacca we had kept fairly close
to, though not actually in sight of, the Kabul river. It makes a vast
difference to one’s comfort in a tropical or semi-tropical country to
travel through cultivated land where, if only at intervals, there is
something green to be seen. Few things are more fatiguing than the
glare of a desert and the reflected heat from pebbles and rocks; we,
therefore, chose the longer but pleasanter route.
CHAPTER II.
Arrival at Kabul.

Arrival at Jelalabad. Reception by the Governor. The


Palace. The Town. The Plain. Quarters in the Guest
Pavilion. The friendly Khan. Tattang and the gunpowder
factory. The Royal gardens at Nimla. The Suffêd Koh
mountains. Arboreal distribution in Afghanistan.
Gundamuk. Assassination of Cavagnari: details of the plot.
The “Red bridge.” Commencement of mountainous ascent
to Kabul. Jigdilik. Massacre of British in 1837. Former
dangers of the valley of Katasang. Enterprising peasants.
Tomb in the Sei Baba valley. Burial customs. The Lataband
Pass and the Iron Cage. Distant view of Kabul. The Amîr’s
projected road at Lataband. The approach to Kabul. The
Lahore Gate.
We arrived at Jelalabad about the middle of the afternoon. The town
is fortified; surrounded by a high wall, with bastions and loopholes;
and is in a good state of repair. We entered one of the massive
gates, rode through the bazaars to the Palace. The bazaars, like
those of Kabul, are roughly roofed over to keep out the glare of the
sun.
The Governor of Jelalabad received us in the Palace gardens: seats
were placed in the shade: fans were waved by the page boys to
keep off the flies; and a crowd of people stood around. Sweets were
brought—chiefly sugared almonds—then tea and cigarettes, and
bouquets of flowers.
We rested for a while, and as we smoked the Governor made the
usual polite Oriental speeches. Then he invited us to see the interior
of the Palace. It is a large white building, standing in the midst of
well laid out gardens, in which are many varieties of Eastern and
European fruit-trees and flowers. The Palace was semi-European in
its internal decoration. It was unfinished at this time. There was a
large central hall with a domed roof, and smaller rooms at the side:
a separate enclosure was built for the ladies of the harem: near by
were kitchens, rooms for the Afghan bath, and a Guest house or
pavilion in a garden of its own.
The town of Jelalabad is between ninety and a
hundred miles from the Indian frontier town Jelalabad.
Peshawur, and contains, in the summer, a
population of from three to four thousand inhabitants. There is one
chief bazaar or street with shops. The other streets are very narrow.
Though much smaller it resembles in style the city of Kabul, which I
will describe presently.
The spot was chosen by Bâber Bâdshah, the Tartar king, founder of
the Mogul dynasty of Afghanistan and India. He laid out some
gardens here, but the town of Jelalabad was built by his grandson,
Jelaluddin Shah, also called Akbar, in 1560 a.d., just about the time
when Queen Elizabeth came to the throne. The place is interesting
to us from the famous defence of Sir Robert Sale during the first
Afghan war, when he held the town from November, 1841, to April,
1842.
The river which runs near the town is here broad and rapid, though
shallow and with low banks. All along the river for miles the plain is
marshy and overgrown with reeds. In the summer when the swamp
is more or less dried up, one rides through the reeds rather than
keep to the glare and heat of the road. The plain of Jelalabad, nearly
two thousand feet above the sea, is about twenty miles long, that is,
from east to west, and four or five miles wide. Wherever it can be
irrigated from the Kabul river it is delightfully fertile, but everywhere
else it is hot barren desert. The climate of Jelalabad is much more
tropical than that of Kabul—more resembling the climate of Central
India; and in the winter the nomadic Afghans of the hills in the Kabul
province pack their belongings on donkeys or bullocks, and with
their whole families move down to Jelalabad, so that the winter
population of the town is enormously greater than that of the
summer.
Palm trees and oranges grow out in the gardens: pomegranates and
grapes in great quantities; and there are many kinds of tropical as
well as sub-tropical flowers. His Highness the Amîr had an idea a
short time ago of establishing a tea plantation here. It is doubtful,
however, whether it would be successful, for in the summer there is
the dust storm and the scorching wind—the simûm.
After taking leave of the Governor we were shown into the Guest
pavilion in its enclosed garden. Here arrangements had been made
for us to spend the night. On the north side, where the pavilion
overlooks the Kabul river, was a stone colonnade or verandah with
pillars. A sentry was stationed here and also at the gate of the
garden. One of the Khans had asked permission to entertain us at
dinner, and with Afghan hospitality he provided also for the guard,
servants, and horses. He did not dine with us but came in afterwards
for a chat. I noticed that in spite of being a Mahomedan he did not
refuse a cigarette and some whiskey. This gentleman we were told
had considerable power in the neighbourhood of Gundamuk, and we
were advised, in case it should ever be necessary to escape from
Kabul, to remember his friendliness; for though Gundamuk is a long
way from Kabul, one could ride there in a day.
Next day we had a gallop through the fertile part of the valley. I had
changed my mare for a steadier horse and my mind was peaceful.
Away to the south it was stony and bare, and in the distance we
could see the snow-capped range of the Suffêd Koh or White
Mountains. We did not go very many miles, but put up at the village
of Tattang. Some of the villages are built entirely as forts, resembling
those in the Khyber district. In others there is a similar but smaller
fort, which is occupied by the Malek or some rich man with his
immediate retainers; the other houses, flat topped and built of sun-
dried bricks, are clumped irregularly together near the fort. But the
windows, for safety and to ensure privacy, generally open into a
walled garden or yard, so that even these have the appearance of
being fortified. The villages are surrounded by orchards and fields.
At Tattang the Amîr has a gunpowder factory, and
the superintendent showed us over it. The Gunpowder
Factory at
machinery is of wood, roughly made, and is Tattang.
worked by water power. The water is obtained
from a stream rising in the Suffêd Koh mountains, and is led by
broad channels to the water wheels. Along the channels, and indeed
along most of the irrigation canals that one sees in the country, are
planted poplars or willows; these protect the canal banks from
injury, and possibly lessen by their shade the rapid evaporation of
water that takes place in a dry hot climate. The gunpowder is not for
sale, and severe penalties are inflicted on those detected selling or
stealing any.
The following day we left the cultivated part of the valley and rode
through a stony desert and over pebbly mountains to Nimla.
Contrasted with the pleasant ride through the fields of the day
before, the heat and glare were most oppressive. The Nimla valley
is, however, an oasis in the desert. In it there is a very beautiful
garden enclosed within a high wall. It was made by Shah Jehangir
about 1610 a.d., and has been repaired by the present Amîr. One can
see the garden a great way off, the deep green of its cypress trees
being a striking piece of colour among the blue greys and reds of
the mountainous barren landscape. There is an avenue of these
trees about one hundred feet wide, and between them, from one
end of the garden to the other, rushes a broad stream with three
cascades artificially made and enclosed within a stone embankment.
The water is brought from a stream rising in the Suffêd Koh
mountains, and rushes on to join the Surkhâb, a branch of the Kabul
river.
At one end of the avenue is a pavilion surrounded by flowers. Here
we put up for the night. Soldiers were sent off to the nearest villages
to buy provisions, and our Hindustani cook, having dug a shallow
hole in the ground in which to build his wood fire, placed a couple of
stones on each side to support his pots, and sent us an excellent
dinner of soup, roast fowl, and custard pudding.
We started off early next morning. Leaving the
Nimla valley we had a rough road, often no more The Suffêd Koh,
or White
than a dry watercourse which led up over rocky Mountains.
mountains and across stony plains for many miles.
As we were travelling westward, on our left hand, that is to the
south, could be seen the great range of mountains called the Suffêd
Koh, on the other side of which is the Kurram valley, now occupied
by the British. This range forms the southern boundary of the Kabul
province, and extending from the Khyber mountains had been on
our left the whole way. Our route, however, had been somewhat
north-west, for we had kept fairly close to although not on the banks
of the Kabul river, but at Jelalabad we branched off from the river
south-west, and came much closer to the Suffêd Koh.
This range, unlike the other mountains we saw, is covered with great
forests of trees. In the whole country the arboreal distribution is
peculiar. The forests are confined entirely to the main ranges of
mountains and their immediate offshoots. The more distant
prolongations are bare and rocky. I remember once in travelling from
Turkestan to Kabul, everyone stopped and stared, for there on a
mountain a solitary tree could be seen; it looked most extraordinary.
In the valleys there are poplars and willows, which have been
planted by the peasants for use afterwards as roofing beams, and
there are orchards of fruit-trees, but I never saw a forest, a wood,
nor even a spinney. The species of tree on those mountains where
they are to be found, varies, of course, according to the height you
find them growing. For instance, high up, there are the cone-bearing
trees, the various kinds of pine and fir. Then come the yew and the
hazel, the walnut and the oak. Lower down—to 3,000 feet—are wild
olives, acacias, and mimosas. On the terminal ridges you find simply
shrubs and herbs.
We passed Gundamuk, where in May, 1879, the “Treaty of Peace”
was signed by the reigning Amîr Yakoub and by Sir Louis Cavagnari.
Four months later, in September, Cavagnari, while British Resident in
Kabul, was assassinated with the connivance of the same Amîr. I
heard the whole plot of the assassination when I was in Kabul.
The story was this. Cavagnari had been holding Durbars, giving
judgment in cases of dispute brought to him by the natives, and had
been distributing money freely, till the Sirdars, coming to Amîr
Yakoub, said, “No longer is the Amîr King of Afghanistan, Cavagnari
is King.” Yakoub therefore took counsel with his Sirdars as to the
best course to adopt. They said, “To-morrow the Herati regiments
come for their pay—send them to Cavagnari.” It was crafty advice—
they knew the hot fiery nature of the Heratis. The following day,
when the troops appeared, unarmed, as is the custom on these
occasions, Amîr Yakoub sent word, “Go to Cavagnari—he is your
King.” Off rushed the soldiers tumultuously, knowing the Englishman
had been lavish with money. The Sikh sentry at the Residency Gate,
seeing a great crowd rushing to the Bala Hissar, challenged them.
The excited shouts of the crowd being no answer, he fired. At once
their peaceable though noisy excitement changed to anger, and they
retaliated with a shower of stones. The Residency guard were called
out, some of the Afghans rushed back for their rifles, and soon all
were furiously fighting, though no one but Yakoub and his Sirdars
knew why. Messages were sent to Amîr Yakoub, and the answer he
returned was, “If God will, I am making preparations.” The end was
the massacre of the British Envoy and all with him.
About ten miles beyond Gundamuk was Surkh pul,
or “The Red Bridge.” This is an ancient brick bridge Commencement
of Ascent to
built over the river Surkâb, which runs into the Kabul.
Kabul river near Jelalabad. The bridge is built high
up at a wild looking gorge between precipitous red mountains, and
the river comes roaring out into the valley. The water of the river is
reddish, or dark-brown, from the colour of the mud in suspension;
however, the Afghans said it was good water, and while we sat in the
shade of a fakir’s hut there, the servants boiled some of the water
and gave us tea. Then we crossed the bridge and rode on again.
From here, almost to the Kabul valley, the road is through a very
wild and desolate mountainous region; you gradually rise higher and
higher, to nearly 8,000 feet, but just before you reach Kabul,
descend some 2,000 feet, the valley of Kabul being 6,000 feet above
the sea. It is, of course, a very great deal colder in this region than
in Jelalabad; in fact, while the harvest is being reaped in Jelalabad,
the corn at Gundamuk, only twenty-five miles further on, is but an
inch or two above the ground. It would, perhaps, be more accurate
to say that the ascent commences at Nimla. We rode some miles
between two ranges of hills—the long narrow valley being cut across
by spurs from the mountains; then climbed a very long steep ascent,
with precipitous walls of rock on either side, and descended a
narrow winding gorge which appeared to have been once the bed of
a river. On either side of this gorge there was brushwood growing,
some stunted holly trees, and what looked like twisted boxwood
trees. Then we climbed the mountain, on the top of which is the
Jigdilik serai. This is 6,200 feet high, and the scenery from the serai
is the abomination of desolation—range after range of barren
mountains. It felt bitterly cold up there, after the heat we had been
through.
They found us a room over the gateway of the serai, lit a blazing
wood fire, and we stayed there till the next day. In the first Afghan
war in 1837, during the winter retreat of the British army, of the
5,000 soldiers and 11,000 camp followers who left Kabul, only 300
reached Jigdilik, and of these only one, Dr. Brydon, reached
Jelalabad, the others were shot down by the Afghans, or died of cold
and exposure.
The village of Jigdilik is not on the hill where the serai is situated,
but in the valley at the foot. Here three gorges meet. One was the
road by which the ill-fated army came in their retreat from Kabul
through the Khurd Kabul Pass. We took another road to the north-
west. We climbed up and down over steep mountains and through
narrow defiles hemmed in by bare rocks. In the valleys it was rare to
see anything but stones, rocks, and pebbles. There was one valley at
Katasung where there was a little stream with grass growing by it.
This valley, a short time ago, was very dangerous to travel through
on account of the highway robberies and murders of a tribe living
near. It is safer now, for the Amîr has killed some of them,
imprisoned others, and dispersed the rest. We camped at Sei Baba,
a narrow valley of pebbles, with a small stream trickling through it.
An enterprising peasant, finding water there, had picked all the
pebbles off a narrow strip of ground, piled them in a ring round his
field, led the water by a trench to it, and had planted some corn. He,
however, was nowhere to be seen, nor was there any house or hut
there.
We occasionally came across these patches among
the mountains wherever there was a trickle of Irrigation
Terraces.
water to be obtained. Sometimes they were more
extensive than this one, and, if made on the slope of the mountain,
the ground was carefully dug and built up into terraces, so that
irrigation was possible. In the middle of the Sei Baba valley was a
tomb with a low wall all round it, and a solitary tree was growing by.
On the tomb were placed two or three pairs of horns of the wild
goat. This is done as a mark of great respect. Every passer by, too,
throws a stone on a heap by the grave, and strokes his beard while
he mutters a prayer. The heap of stones, or “tsalai,” is supposed to
be piled only over the graves of holy men or martyrs; but they are
heaped over any grave that happens to be apart from others, and by
the wayside. The peasants, not knowing, assume it is the grave of a
holy man. The custom is said by some to originate by imitation from
an act of Mahomed, in which the form but not the spirit of the
ceremony, has been retained; for Mahomed, fleeing for refuge to
Mecca from Medina, threw stones at the city and cursed it. By
others, these heaps of stones are supposed to be representative of
the Buddhist funeral pillars, the custom having remained extant
since the days when Buddhism was the dominant religion of the
people inhabiting this country. The latter seems the more likely
explanation.
By the side of some of these tombs a small shrine, “ziyârat,” is built.
If the tomb is that of a known holy man, the passer by, in addition
to adding a stone and saying his prayer, calls upon the name of the
saint, and tears a small piece of rag off his garment which he hangs
on the nearest bush or tree. The shred is to remind the holy man
that the wearer has prayed him to intercede on his behalf with the
prophet Mahomed. On the grave, too, is generally planted a pole
with an open hand, cut out of zinc or tin, fixed on the top. If the
deceased has fallen in battle a red rag is fixed on the pole as well.
What the open hand pointing to the sky represents I never heard.
When we arrived at Sei Baba we found that a party of peasants on
the tramp had halted there—one of their number died just as we
arrived. Seeing that we had a cavalcade of horsemen and much
baggage, and there being no village nearer than seven or eight
miles, they came to us to beg a little calico for a winding sheet. It
struck me that ten yards, the amount they asked for, was rather
much for that purpose. Possibly they thought the living men required
it quite as much as the dead man.
Next day we had a high and stony range of
mountains to climb—the Lataband Pass, nearly The Iron Cage.
eight thousand feet above the sea. This part of the
journey between Lataband and Chinár, with the winding rocky road
curving high up round the spurs or plunging into narrow ravines,
always seems to me the wildest and most weird of all. The
mountains are so huge and rocky, the ravines so precipitous, and the
silence so appalling. A few years ago the Pass was dangerous not
only in itself—the road in one place runs on a ledge of rock
overhanging a seemingly bottomless precipice—but it was infested
with Afghan highway robbers. Being comparatively near the capital
this was particularly exasperating to the Amîr. Finding ordinary
punishments of no avail he determined to make an example of the
next man apprehended. As we were riding along we could see fixed
on one of the highest peaks something that looked in the distance
like a flagstaff. The road winding on we drew nearer, and saw it was
not a flag, it was too globular, and it did not move in the wind. When
we got right under the peak we saw it was a great iron cage fixed on
the top of a mast. The robber had been made an example of. There
was nothing left in the cage but his bones. I never heard of there
being any more highway robbery or murder near here.
From this pass you get the first view of Kabul. In the distance it
seems a beautiful place, and after the long desolate march the sight
of it lying in the green Kabul valley is delightful. We reached the foot
of the mountains, rode some miles along a stony and barren plain till
we reached a village called Butkhak, where we camped. The next
day the cultivated part of the Kabul valley lay before us. First were
the fields surrounding Butkhak, then we crossed a small dilapidated
brick bridge over the Logar river, which runs north to join the Kabul
river. We had quite lost sight of our old friend the Kabul river since
we left Jelalabad: he was away somewhere to the north of us,
cutting a path for himself among the mountains. The Amîr has spent
several thousands of pounds—or rather lacs of rupees—in trying to
make a road in the course of the river from Kabul to Jelalabad, but it
was found quite impracticable among the mountains in the Lataband
and Chinár district. The object, of course, was to avoid the climb
over the Lataband Pass. I have never been the route through the
Khurd Kabul Pass to Jigdilik, but I have heard that the road is not
very good.
After crossing the Logar bridge we mounted a range of low pebbly
hills, which run irregularly east across the valley, cutting it in two.
From the elevated ground we could see on our left a large reed
grown marsh surrounded by meadow land, which ran right up to the
foot of the mountains, forming the south boundary of the valley. We
were much nearer to the southern than to the northern limit. The
mountains curved round in front of us and we could see the gap or
gorge between the Asmai and Shere Derwaza mountains. From this
the Kabul river emerged and took its course in a north-easterly
direction across the valley.
On the south bank of the river near the gorge and
at the foot of the Shere Derwaza lay the city. The Approach to
Jutting out north-east from the Shere Derwaza into Kabul.
the valley, about a mile south of the gorge, was the
spur of the Bala Hissar, and the city seemed, as it were, to be tucked
into the corner between the Shere Derwaza, its Bala Hissar spur, and
the Asmai mountain. On our right, about a mile and a half north of
the city, was the Sherpur cantonment or fortification, backed by two
low hills—the Bemaru heights.
We descended the elevated ground, from which we had a birds-eye
view of the valley, and found ourselves riding along excellent roads
fringed with poplar trees. The cultivated fields separated by irrigation
channels lay to the left of us. On the right were the pebbly hills we
had crossed lower down, continued irregularly west. On the last hill
nearest the town, “Siah Sang,” was a strong fort, built by the British
when Lord Roberts was in Kabul. It is called Fort Roberts.
We rode along the avenues of poplar and plane trees right up to the
Bala Hissar spur. In the time of the Amîr Shere Ali, on the high
ground of the spur stood the royal residence and the fort, and when
Yakoub was Amîr this was the Residency where Cavagnari lived. It is
now almost all in ruins or demolished. The gateway stands, and a
part of the old palace. This is used as a prison for women, political
prisoners, Hazaras, and others. The wall and the moat exist, and
inside, some rough barracks have been built for a few troops. The
native fort on the higher ground of the Bala Hissar seems to be in
good repair. I have never been inside. It is used as a magazine for
powder.
We passed the Bala Hissar, leaving it on our left, and the road led
through a plantation of willows extending from the Bala Hissar some
distance north, skirting the east suburb of the city. The willows in
the plantation were arranged in rows about ten yards apart with a
water trench or ditch under each row of trees, and the shaded space
between was green with grass—an unusual sight in Afghanistan. The
trees were planted by Amîr Shere Ali, whose idea was to camp his
soldiers here in the summer without tents. The willow branches are
used now to make charcoal for gunpowder.
We entered the gate of the city called the Lahore Gate. It was rather
dilapidated, but looked as though it might once have been strong.
There were heavy wooden doors studded with iron, and large
loopholes in the upper brickwork of the gate which were guarded by
brick hoods open below, a species of machicoulis gallery. Possibly
the loopholes were once used for the purpose of pouring boiling
water on the heads of an attacking enemy.
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.

More than just a book-buying platform, we strive to be a bridge


connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.

Join us on a journey of knowledge exploration, passion nurturing, and


personal growth every day!

ebookbell.com

You might also like