The use of loops in python can reduce recursive tasks to a few lines of code. While numpy operations are useful for enacting large numbers of mathematical operations, loops can be used to facilitate the use of large numbers of other operations on data types suchs as:
- dictionaries
- lists
- NumPy arrays
In this tutorial, the use of loops, facilitated by the use of for
and while
statements, on these data types will be illustrated.
from periodic_table_20 import periodic_table_20
# periodic_table_20 = pt.create()
if periodic_table_20["Li"]["melting_point"] < 700 and periodic_table_20["Li"]["boiling_point"] > 700:
print("Lithium is liquid at 700 K")
else:
print("Lithium is not liquid at 700 K.")
Recall that perioidic_table_20
is a dictionary of dictionaries, containing the mass, group, period, block, melting point, and boiling point of the first twenty elements of the periodic table.
In the example above, we have used Boolean logic statements to determine whether one element, lithium, is a liquid at 700 K. What if we wanted to determine which of the first twenty elements of the periodic table were liquid at a certain temperature? Would we have to write the above code for twenty different elements?
Thankfully not. This task becomes fairly simple with the use of a loop.
for element in periodic_table_20: # loop through the first twenty elements
if periodic_table_20[element]["melting_point"] < 700 and periodic_table_20[element]["boiling_point"] > 700:
print(element, "is liquid at 700 K")
else:
print(element, "is not liquid at 700 K.")
From this we have determined that Li, Na, S, and K are liquid at 700 K, whilst the other sixteen elements are not. But how does the loop enable us to see this? To allow us to observe what is happening, we will use
for element in periodic_table_20: # loop through the first twenty elements
print(element)
This prints out the symbols of the elements, which are the keys of the periodic_table_20 dictionary. In the above code, the element
variable recursively takes on the value of the keys of the periodic_table_20 dictionary, such that
1) The variable element
becomes "H"
2) The value of element
is printed, "H"
3) The variable element
becomes "He"
4) The value of element
is printed, "He"
...
37) The value of element
becomes "K"
38) The value of element
is printed, "K"
39) The value of element
becomes "Ca"
40) The value of element
is printed, "Ca"
To illustrated this further, the value of the variable element
is:
element
The value of the variable element
is now "Ca", the last key in our periodic_table_20 dictionary. Similarly to flow controls, we can visualise loops using flow charts, such as the one below:
We give the for
loop a collection (a dictionary) and it recursively loops through running the indented code until there are no more items (keys) left in the collection (dictionary).
Now that we have shown that the for
loop allows us to recursively access the keys of the periodic_table_20 dictionary, we can explain how we determined which elements were liquid at 700 K. The line
if periodic_table_20[element]["melting_point"] < 700 and periodic_table_20[element]["boiling_point"] > 700:
accesses the dictionary containing the information for the value of the variable element
and extracts the respective melting and boiling points. Using this information the if/else
statement determines whether the element is a liquid at 700 K.
The code used previously prints out twenty lines informing us if an element is liquid at 700 K. This requires us to read twenty lines. A more efficient way of obtaining which elements are liquid at 700 K is to store the information in a list.
liquid = []
not_liquid = []
for element in periodic_table_20: # loop through the first twenty elements
if periodic_table_20[element]["melting_point"] < 700 and periodic_table_20[element]["boiling_point"] > 700:
liquid.append(element) # if the element is a liquid append to the liquid list
else:
not_liquid.append(element) # if the element is not a liquid append to the not_liquid list
print("The following elements are liquid at 700 K:", liquid)
print("The following elements are not liquid at 700 K", not_liquid)
This allows us to obtain the information require without reading twenty individual lines. However, if we were asked which elements are liquid at a different temperature, say 1000 K, we would be required to change four numbers (the two logic statements and the two print statements). A more efficient method would be to specify the temperature outside of the for
loop, such that
liquid = []
not_liquid = []
temperature = 1000
for element in periodic_table_20: # loop through the first twenty elements
if periodic_table_20[element]["melting_point"] < temperature and periodic_table_20[element]["boiling_point"] > temperature:
liquid.append(element) # if the element is a liquid append to the liquid list
else:
not_liquid.append(element) # if the element is not a liquid append to the not_liquid list
print("The following elements are liquid at {} K:".format(temperature), liquid)
print("The following elements are not liquid at {} K".format(temperature), not_liquid)
We can see that Li, Na, Mg, Al, and K are liquid at 1000 K, and we only required changing one number.
Compound loops used in combination with lists and NumPy arrays
More often than not, in chemistry we will be asked to find properties at different temperatures, say every 100 K between 200 K and 1000 K. Can loops help us determine which elements are liquid at different temperatures? Yes, loops can be compounded in such a way that is useful here.
import numpy as np
temperatures = np.linspace(200,1000,9) # Create an array of temperatures to probe
for temperature in temperatures: # loop through the temperatures
liquid = [] # create a list to store liquid elements at a given temperature
for element in periodic_table_20: # loop through elements
if periodic_table_20[element]["melting_point"] < temperature and periodic_table_20[element]["boiling_point"] > temperature:
liquid.append(element) # if an element is a liquid then append it to the liquid list
print("The following elements are liquid at {} K:".format(temperature), liquid) # print the elements liquid at given temperature
Note in the above code, the non-liquid data elements are not stored. This is because the only relevant information are the elements that are liquid at a given temperature. The np.linspace(200,1100,100)
function creates a NumPy array of values from 200 to 1000 which has 9 values that are equally separated. What values are the variables temperature
and element
taking in the compound loops above?
1) The variable temperature
takes the value 200.
2) The variable liquid
is assigned to an empty list.
3) The variable element
is assigned "H", and determined whether it is a liquid at 200 K.
4) The variable element
is assigned "He", and determined whether it is a liquid at 200 K.
...
41) The variable element
is assigned "K", and determined whether it is a liquid at 200 K.
42) The variable element
is assigned "Ca", and determined whether it is a liquid at 200 K.
43) The liquid
variable is printed.
44) The variable temperature
takes the value 300.
45) The variable liquid
is assigned to an empty list.
46) The variable element
is assigned "H", and determined whether it is a liquid at 300 K.
47) The variable element
is assigned "He", and determined whether it is a liquid at 300 K.
...
The outer loop is only "run through" once, whilst the inner loop is "run through" an amount of times equal to that of the length of the first loop. To more easily observe this consider the following example which uses a list (that bahaves the same as a NumPy array), where there are only two temperatures (600 K and 1000 K)
temperatures = [600, 1000]
for temperature in temperatures: # loop through the temperatures
for element in periodic_table_20: # loop through the first twenty elements
print("temperature =", temperature, " ", "element =", element)
Compound loops can be understood using flowcharts again. Recall in the previous flowchart that if the next item in the list existed, then the indented code is ran. However, now the indented code also includes a for
loop. Therefore the flowchart becomes
where the dotted box contains the single indented code. Each time we cross the dotted line the second collection is reset so that when we enter the dotted box the next time "the next item in the second collection" is the first item. In the code above the first collection is the temperatures list and the second collection is the periodic_table_20 dictionary.
Compound loops can have any number of levels. The three level compound loop below illustrates this
first_list = ["First item in the first list", "Second item in the first list"]
second_list = ["First item in the second list", "Second item in the second list"]
third_list = ["First item in the third list", "Second item in the third list"]
for first in first_list: # loop through first_list
for second in second_list: # loop through second_list
for third in third_list: # loop through third_list
print("first =", first, "/ second =", second, "/ third =", third) # print the values of each variable
Take a minute to understand how the above three leveled compound list assigns variables.
Exercise: Use compound loops to determine which elements are gaseous at temperatures between 100 K and 500 K in intervals of 50 K.
### Write your code here
While loops
The particle in a box is a well known quantum mechanical problem with well known solutions, namely
$$ \begin{align} \Psi(x) = \sqrt{\frac{2}{L}} \sin\left(\frac{n\pi x}{L} \right). \end{align} $$Here $n$ is the principle quantum number and $L$ is the length of the box. The first three solutions to the particle in a box problem, where $L = 1$, can be plotted using either a for
loop or a while
loop with the plot_wavefunction function. The plot_wavefunction function takes two arguments, the principle quantum number and the length of the list. First consider the use of a for
loop.
An aside: plotting will be discussed further in the simple plotting tutorial. For the purposes of this tutorial, consider plot_wavefunction as a function that plots curves and plt.show() a function that prints the graph to screen.
from wavefunction import plot_wavefunction
import matplotlib.pyplot as plt
n = [1,2,3] # the values of n we wish to plot
L = 1 # set length of the box
for N in n:
plot_wavefunction(N, L) # plots each curve recursively
plt.show() # prints the graph to screen
The same plot can be created using a while
loop
L = 1 # set length of box
n = 1 # set initial principle quantum number
while n < 4:
plot_wavefunction(n, L) # plots each curve recursively
n += 1 # increase the value of n by 1.
plt.show() # prints the graph to screen
What is the process occurring in the while
loop above?
1) The variable L is assigned value 1.
2) The variable n is assigned value 1.
3) 1 < 4 is evaluated to True
so the indented code is ran.
4) The curve for n=1 is plotted
5) The variable n is assigned value 2 (n = n + 1, where n is 1)
6) 2 < 4 is evaluated to True
so the indented code is ran.
7) The curve for n=2 is plotted
8) The variable n is assigned value 3 (n = n + 1, where n is 2)
9) 3 < 4 is evaluated to True
so the indented code is ran.
10) The curve for n=3 is plotted
11) The variable n is assigned value 4 (n = n + 1, where n is 3)
12) 4 < 4 is evaluated to False
and the while
loop is terminated
13) The graph is printed to screen.
Warning:
while
loops can be very dangerous! If the variable n is not increased by one each time then this loop could run infinitely as there is never a termination step. It is recommended to always use afor
loop instead of awhile
loop.
Exercise: Use a while
loop in combination with an if
statement to plot the solutions to the particle in a box problem for n greater than 4 and less than 8, with $L=3$, using the plot_wavefunction function.
### Write your code here.