Scientific Computing Using Python - PHYS:4905 - Fall 2018

Lecture #03 - 8/28/2018 - Prof. Kaaret


Scripts/Programs

The textbook does loops before scripts, but as soon as you do more than one line of Python, it is a lot easier to use a script rather than the command line.

Before we start with the editor, check what directory you are in by typing pwd on the command line.  pwd stands for print working directory.

The left pane in Spyder is usually set up as the editor pane.  If you open a new file, Spyder will automatically insert the template that we edited in lecture 1.  Make sure that you have the lines that make Python 2 act like Python 3.  You might want to add a line to import numpy in your favored style.

Now enter a line

print ("Hello world!")

then save the file with the file name 'test1.py'.  While you are saving, check that the directory matches the directory that you found with pwd on the command line.

Go back to the command line and type

run test1

Your script or program should print out Hello World!
Congratulations, you're now a programmer.

The editor in Spyder has some useful Python-specific features.  Go to the editor and type

= 7*8

and then move off the line.  A red circle with a white x in it should appear.  Move you cursor over the circle and a popup window with a message that you have a syntax error should appear.  The editor is giving you advance warning that Python will complain about your code. Now hit the green triangle above the editor pane.  This is another way to run the program.  You should get a message in the console pane that it is running your program followed by a message that you have a syntax error and tells you which line has the error.  Sometimes an error on a previous line can cause Python to find a syntax error.  So, if Python tells you that you have an error on a line of your code and you can't figure out what it is, look at the previous line.

Now remove the line with the syntax error and write a new line

x = np.arange(-3, 15, 2)

Then run the script.  You have created an array x with a bunch of values.  If you want to inspect those values, you can go to Spyder's upper right pane and click on the 'Variable explorer' tab.  If you double click on the Value box, you'll be rewarded with a pop-up window where you can inspect and modify the array contents.


Good Programming Practice

Comments - A good programmer includes lots of comments in her code.  Comments are useful to other people trying to read your code and they are also useful when you try to read your own code a few months or more after you have written it.  You might even consider writing the comments before you write the code.  That way you'll have to lay out your thinking before you start coding.

Python has two ways to write comments.  Python will consider any text following a # to be a comment. You can include comments on the same line as code

g = 9.8 # [m/s^2]  gravitational acceleration at the Earth's surface

or have whole lines that are comments.

# gravitational acceleration at the Earth's surface
g = 9.8 # [m/s^2]

When doing computations with physical quantities, it is good to always specify the units of any numbers with a comment.

The second way to write a comment is to use """.  All of the lines until the next """ will be considered a comment.

""""
This is a program to calculate the trajectory of a object in the Earth's gravitational field. The program takes as input the initial velocity of the object specified as a speed and angle. It calculates the distance that the object will travel before returning to Earth.
Units are in SI.
"""

Small pieces - Your program is more likely to work correctly if you break it up into small pieces.  Test each new piece of your code to make sure that it does what you want.  Input test case parameters for which you know the answer or can at least recognize grossly incorrect answers.  Inspect variables at each step using print statements or the Variable explorer. 

Comment your variable definitions - People sometimes comment the steps of their code, but forgot to provide comments about the inputs to the procedures or about how variables are used.  The textbook suggests using long, descriptive variable names.  This is useful if you have large blocks of code, but I try to break my code into small pieces and then provide a comment where each variable is defined.  The choice is up to you

initial_speed = 12.0 # [m/s]

or

v0 = 12.0 # [m/s] initial speed

The disadvantage of using short variable names is that you may occasionally re-use the same name, which will mess things up.  This happens most often with loop or index variables like i and j.

Comment other people's code - If you find yourself using other people's code, the first thing to do is to go through it and add comments if it is not well commented.  This will help you understand the code now, when you are trying to use it, and in the future, if you need to use it again.  You will do this in the homework assignment for this lecture.

Conditional execution

The if statement lets you run different code depending on the values of variables in your program. Let's write a short program to play a simplified version of the dice game Craps.  You roll two dice.  If the sum of the two dice is 7 or 11 then you will win.  If it is 2, 3, or 12 then you lose.  For any other value, you roll again.  Copy the following into you editor window, save as craps.py, and run

# play simplified Craps
# this code is not properly commented
d1 = np.random.randint(1,7)
d2 = np.random.randint(1,7)
s = d1+d2
if ((s == 7) or (s == 11)) :
  print('Roll is '+str(d1)+' and '+str(d2)+'.  You win!')
elif ((s == 2) or (s == 3) or (s == 12)) :
  print('Roll is '+str(d1)+' and '+str(d2)+'.  You lose.')
else :
  print('Roll is '+str(d1)+' and '+str(d2)+'.  Roll again.')

Note the colon at the end of the if statement.  A colon is required for all Python statements that control program execution. 

How does Python know which statements to execute if the condition is true?  Python relies completely on the indentation.  The first line after the if statement must be indented by at least one space.  That line and any other lines with the same indentation will be executed if the condition in the if statement is true.  The first line with the same indentation as the if statement is either elifelse, or marks the end of the if statment.  The Python standard is to indent by four spaces.  I prefer to use two spaces because I find it more readable for very nested code.

If the 'then' part of an if statement is very short, you can put it on the same line as the if statement.

if ((s == 7) or (s == 11)) : print('Roll is '+str(d1)+' and '+str(d2)+'.  You win!')


Testing the equality of floats - Sometime you will run into issues when you are trying to check if two floating point numbers are equal. Try

(0.1+0.1+0.1) == 0.3

You get false, while you expect that you should get true.  This is because Python uses binary to represent floating point numbers and the binary representation of 0.1 is an infinitely repeating string of bits (binary digits).  It is better to use inequalities when comparing floats.  If you really need to check for equality, do it to some level of accuracy, e.g.

ftol = 1E-6 # tolerance when comparing two floats for equality
abs((0.1+0.1+0.1) - 0.3) < ftol

It is better to specify the tolerance is specified as a fraction of the value,

ftol = 1E-6 # tolerance when comparing two floats for equality
s, v = 0
.1+0.1+0.1, 0.3
a
bs(s-v) < v*ftol


Loops

For loops - Go to your editor window and type

# find squares from 1 to 9 and their sum
s = 0
for x in np.arange(1, 10) :
  print(' The square of ', x, ' is ', x**2)
  s = s + x**2
print("We're done, s = "+str(s))

Now save and run the program.  The for statement makes a loop, note the colon at the end.  The variable x is assigned, in turn, to each value produced by the arange(10) function call, which are the integers from 1 to 9.  The statements in the body of the loop are executed for each new value of x.

To determine which statements are in the body of the loop and should be executed multiple times, Python relies completely on indentation.  The first line after the for statement must be indented by at least one space.  All of the following lines in the body of the loop must have the same indentation.  The first line with the same indentation as the for statement marks the end of the loop body.

If the body of a loop is very short, you can put it on the same line as the for statement.

for x in np.arange(1, 10) : s = s + x**2


While loops -
Sometimes you need to repeat lines of code, but with variables that don't increment in a simple fashion.  For that you use a while loop.  Let's write a bit of code to do a random walk, starting at a displacement of 0 and ending when the magnitude of the displacement reaches 5.  The following code should do the job

# do a random walk with steps of -1, 0, 1 up to a specified maximum displacement
maxd = 5 # maximum displacement

n = 0 # n is the number of steps taken, start at 0

d = 0 # d is the current displacement, also start at 0

while abs(d) < maxd : # loop while the magnitude of the displacement is less than maxd

  d = d + np.random.randint(-1,2) # add a random step (-1, 0, or +1) to displacement

  n = n + 1 # incremement the step counter

  print('At step '+str(n)+' position is '+str(d))

print('It took '+str(n)+' steps to reach a displacement of '+str(d))

Now let's try a much larger maximum displacement, set maxd = 1000 and run the code again.  The code takes a while to run, so get let's stop it.  To stop the code move into the console window and type Ctrl-C.  You should get a long list of messages that end with 'KeyboardInterrupt'.
Most of the time in the loop is taken by the print statement.  Let's "comment out" the print statement by putting a # in front of it.  The # can go either just before print or at the start of the line.  I prefer to place the # just before print so that the indentation stays the same.  Now run the code.  Without the print, it executes quickly.


Breaking out of loops - You can exit a loop, either for or while, when a special condition is met by using a break statement.  For example, if you don't want to let the random walk above run too long, you could add a line after the where you increment the step counter
  if (n > 10000) : break
This will exit the while loop if you reach 10,000 steps.

User input

The input function enables a program to ask for input from the user.  Note that Python 2 and 3 differ in their input functions.  Make sure that your programs include the line
input = raw_input
to make input work in the Python 3 manner.  The input function will then print out the text given in the argument and return the text typed in by the user as a string.  You then convert the string to the form that you need using a function like int or float.
Modify the random walk program by commenting out the line where a value for maxd is assigned and replacing it with 

maxd = int(input("Enter maximum displacement "))

Now when you  run the program, it will ask you for the maximum displacement.


Array operations

When using Python and NumPy in particular, it is best to avoid using for loops whenever possible.  Your code will likely run faster if you can avoid using a loop.  NumPy allows operations on whole arrays.  The loop that we wrote at the beginning of the class could be re-written as

s = np.sum(np.arange(1, 10)**2)

This is shorter to write and runs much faster.

Array operations require the arrays to have the same shape.  If you do an operation with a float and an array, the float is 'broadcast' to have the same shape as the array meaning an array is constructed with the same shape and each value set to the float.  In this context, floats or integers are sometimes called 'scalars'.

Most array operation operate separately on each element of the array.  For example,

a = np.array([1.0, 2.0, 3.0])
b = np.array([3.0, 2.0, 0.5])
a * b

produces an array with the same number of elements with a and b with each element equal to the product of the two corresponding elements in a and  b.

NumPy also includes functions for standard vector and matrix math.  The dot product of two vectors is

np.dot(a, b)

The product of a matrix times a vector is
v = np.array(np.diag([1,2,3]))
np.dot(v,a)


Assignment

The remainder of today's class will be devoted to working through chapter 3 of the textbook where all of these topics are covered.  As you read the chapter,  enter the commands in the purple highlights into Spyder and see what you get.  When you are done with the chapter, do the third assignment which will be due at the start of class on Thursday, August 30.  Also, please do the reading for 8/30 before class on Thursday.

HW #3 is due at the beginning of class on Thursday, August 30.
https://homepage.physics.uiowa.edu/~pkaaret/2018f_p4905/hw03.html