Python is a powerful programming language that bears many similarities with matlab, C and fortran. The following crash course will take you through some of the key features we will use in ME 249.
The python software installed on your computer contains many libraries, the main ones used in ME 249 are:
The constant $\pi$ is available from all three libraries (math, numpy, scipy). Here I don't give a shorthand name to math, to illustrate how import works with or without as.
The print command here takes a string "pi = %1.15f" where %1.15f signals the print command that a floating number of the form $$ \underbrace{x}_{1}.\underbrace{abcdefghijklmno}_{15} $$ is expected. This number is passed onto the print command via %math.pi.
In [1]:
import math
print("pi = %1.15f" %math.pi)
print("pi = %1.15e" %math.pi)
import numpy as np
import scipy as scp
print(" numpy pi = %1.15f" %np.pi)
print(" scipy pi = %1.15f" %scp.pi)
A few things you should know about python 3:
In [2]:
print("1+2 = ", 1+2)
print("1.0+2 = ", 1.0+2)
print("1.0+2.0 = ", 1.0+2.0)
print("4/2 = ", 4/2)
print("4//2 = ", 4//2)
print("8//3 = ", 8//3)
print("8/3 = ", 8/3)
print("Integer of 8/3 = ", int(8/3))
print("(2.5,3.0) =", 2.5+3.0j)
print("2^4 = ", 2**4)
print("2.0^4 = ", 2.**4)
print("2.0^4 = ",pow(2.0,4))
a = 10.
a *= 9.
print("a = 10. then a *= 9.=",a)
You may find all mathematical functions here </FONT>: https://docs.python.org/3.5/library/math.html</FONT>.
In [3]:
print("e^1=",math.exp(1.))
print("e^(-infinity)=",math.exp(-math.inf))
print("log(e)=", math.log(math.e))
print("log_10(1000.)=",math.log10(1000.))
a = math.cos(math.pi/4.)
print("a = cos(pi/4) = %1.8f" %a)
print("arcos(a)*4./pi = ",math.acos(a)*4./math.pi)
In [4]:
print("1 equal 2:",1==2)
print("1 non-equal 2:",1!=2)
print("1 > 2:",1>2)
print("1 < 2:",1<2)
print("10.==sqrt(100.):",10.==math.sqrt(100.))
In [5]:
a = 0
if a > 0:
a -= 1
elif a == 0:
a = 1
print(a)
Let's take a pause here to discuss if, while, for statements. The indentation at the line following if a>0: is critical. It means that all the lines with such indentation following if a>0: are part of the actions needed if a>0 = True. Try the following cells using a = 1 and if a=4. Note also the role of the boolean operators and and or. Note also that each if, while, for statements need to end with : to signal that the following indented lines are part of the statement.
In [6]:
a = 4
b = 0
if a > 0 and a < 4:
a += 1
b = 3
else:
a = 0
b = 1
print(a,b)
In [7]:
a = 4
b = 0
if a > 0 or a < 4:
a += 1
b = 3
else:
a = 0
b = 1
print(a,b)
A key element of scientific computing is the ability to loop or iterate. You have two options: for and while:
In [8]:
for i in range(0,5,1):
print(i)
In [9]:
for i in range(5):
print(i)
In [10]:
for i in range(3,5):
print(i)
In [11]:
for i in range(5,2,-1):
print(i)
In [12]:
a = 0
while a <=5 :
print(a)
a += 1
print("final a=",a)
Matrices are central to CFD as we will see in future problems. The library or module numpy contains all the definitions and operators necessary for matrix operations.
You may set a matrix/vector to zero, unity or the values you may choose using numpy functions zeros, ones, and array. Please note:
In [13]:
import numpy as np
n = 10
a = np.zeros(n)
print("a = ",a)
m = 3
b = np.ones((m,n))
print("b = ",b)
c = np.array([1, 2, 3, 4])
print("c = ",c)
d = np.array([[1, 2], [3, 4]], dtype = np.complex)
print("d = ",d)
In [14]:
a = np.ones((2,2), dtype = 'float64')
for j in range(2):
for i in range(2):
a[i,j] *= np.float64(math.pi/(i+j+1))
print(a)
print("a[0,0] =",a[0,0])
Any programming language has a quirk or two, that may baffle/annoy you. May be it is only me, but I find the equal sign in python dangerous. Here is why. First we define an array $$ a_i = 2^i,\;i=0,\ldots,9 $$
In [15]:
n = 10
a = np.zeros(n, dtype = np.float)
for i in range(n):
a[i] = 2.**i
print("a = ",a)
Now, I want to modify the last element a[n-1] but in a different array to keep my initial array intact (something quite common in CFD).
In [16]:
b = a
b[n-1] -= 500.
print("a = ",a)
print("b = ",b)
Both my arrays have been changed!!! The same is not true for simple variables:
In [17]:
a = 1.
b = a
b += 1.
print("a=",a)
print("b=",b)
The fix for arrays is to use np.copy:
In [18]:
n = 10
a = np.zeros(n)
for i in range(n):
a[i] = 2.**i
b = np.copy(a)
b[n-1] -= 500.
print("a = ",a)
print("b = ",b)
Note that when you perform an operation on all the elements of your array, the problem of linking your old array and new array disappears:
In [19]:
n = 10
a = np.zeros(n)
for i in range(n):
a[i] = 2.**i
b = a * 2.
print("a = ",a)
print("b = ",b)
which is equivalent to:
In [20]:
n = 10
a = np.zeros(n)
for i in range(n):
a[i] = 2.**i
b = np.copy(a)
b *= 2.
print("a = ",a)
print("b = ",b)
but this is bad:
In [21]:
n = 10
a = np.zeros(n)
for i in range(n):
a[i] = 2.**i
b = np.zeros(n)
b = a
b *= 2.
print("a = ",a)
print("b = ",b)
To perform operations an all elements, numpy has many functions. In the following, we
In [22]:
n = 4
a = np.zeros(n, dtype = np.float64)
for i in range(n):
a[i] = 2.**i
print("a=",a)
b = np.copy(a)
b += 1.
print("b=a+1=",b)
b = np.zeros(n, dtype = np.float64)
for i in range(n):
b[i] = np.float64(i)
print("a=",a)
print("b=",b)
print("a*b=",a*b)
print("a.b=",np.dot(a,b))
print("exp(-a)=",np.exp(-a))
Note that you need to use the exp of numpy and not from math, otherwise you get this:
In [23]:
print("exp(-a)=",math.exp(-a))
Getting errors is part of code development. Python will provide sometimes short, sometimes way too long error messages. Before you throw your hands in the air, give up and immediately email the TA or the instructor, browse the error message for things that could make sense. Typically, the last line contains useful information. Here it says that math.exp is expecting a scalar but we gave a length-1 array.
A very attractive feature of python is the nomenclature for indexing and slicing that enables to maximize the efficiency of vector operations. Here is a summary of the indexing and slicing nomenclature for a vector:
In [32]:
%matplotlib inline
# plots graphs within the notebook
%config InlineBackend.figure_format='svg' # not sure what this does, may be default images to svg format
from IPython.display import Image
from IPython.display import clear_output
from IPython.core.display import HTML
def header(text):
raw_html = '<h4>' + str(text) + '</h4>'
return raw_html
def box(text):
raw_html = '<div style="border:1px dotted black;padding:2em;">'+str(text)+'</div>'
return HTML(raw_html)
def nobox(text):
raw_html = '<p>'+str(text)+'</p>'
return HTML(raw_html)
def addContent(raw_html):
global htmlContent
htmlContent += raw_html
class PDF(object):
def __init__(self, pdf, size=(200,200)):
self.pdf = pdf
self.size = size
def _repr_html_(self):
return '<iframe src={0} width={1[0]} height={1[1]}></iframe>'.format(self.pdf, self.size)
def _repr_latex_(self):
return r'\includegraphics[width=1.0\textwidth]{{{0}}}'.format(self.pdf)
PDF('figures/indexing.pdf',size=(800,600))
Out[32]:
In [46]:
n = 6
a = np.zeros(6,dtype=np.float)
for i in range(n):
a[i] = 2**i
print("a[0:n] = ",a[0:n])
print("a[:] = ",a[:])
print("a[1:] = ",a[1:])
print("a[1:n] = ",a[1:n])
In [47]:
print("a[0:n] = ",a[0:n])
print("a[0:n-1] = ",a[0:n-1])
print("a[0:-1] = ",a[0:-1])
print("a[:-1] = ",a[:-1])
In [48]:
print("a[2:] = ",a[2:])
print("a[:-3]= ",a[:-3])
In [52]:
b = np.zeros(n,dtype=np.float)
b[:-1] = a[1:] - a[:-1]
print("a[1:] =",a[1:])
print("-")
print("a[:-1] =",a[:-1])
print(" =",b[:-1])
In [ ]:
n = 100000
mu = 0.
sigma = 1.
a = np.random.normal(loc = mu, scale = sigma, size = n)
print("a[:-(n-10)] = ", a[:-(n-10)])
print("a[0:10] = ", a[0:10])
In [ ]:
import matplotlib.pyplot as plt
count, bins, ignored = plt.hist(a, 50, normed=True)
plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) * \
np.exp( - (bins - mu)**2 / (2 * sigma**2) ),\
linewidth=2, color='r')
plt.show()
In [ ]:
n = 100
mu = 0.
sigma = 0.2
x = np.linspace(0,1.,n)
a = np.sin(2.*math.pi*x)
plt.plot(x,a, lw = 2)
plt.show()
a_noisy = np.copy(a)
n_noise = 4
k_noise = 50
noise_amplitude = np.random.normal(loc = mu, scale = sigma, size = n_noise)
noise_phase = 2*math.pi*np.random.normal(loc = mu, scale = 1.0, size = n_noise)
for i in range(n_noise):
a_noisy += noise_amplitude[i]*np.sin(2*(k_noise+i)*math.pi*x + noise_phase[i])
plt.plot(x,a_noisy, lw = 2)
plt.show()
print(noise_amplitude)
print(noise_phase)
In [ ]:
a_filter = np.zeros(n)
a_filter[1:-1] = (a_noisy[0:-2] + 2. * a_noisy[1:-1] + a_noisy[2:])/4.
a_filter[0] = (a_noisy[n-2] + 2. * a_noisy[0] + a_noisy[1])/4.
a_filter[n-1] = a_filter[0]
plt.plot(x,a_noisy, linestyle="solid", lw = 1, label = r"noisy signal")
plt.plot(x,a_filter, color = "red",linestyle="solid", lw = 2, label = r"filtered signal")
plt.plot(x,a, color = "green", linestyle="None", marker = "o", markeredgecolor = "green", markeredgewidth = 1,\
markerfacecolor = "None", label = r"original signal")
plt.legend(loc="lower left", bbox_to_anchor=[0, 1],
ncol=2, shadow=True, fancybox=True)
plt.xlabel(r"$x$", fontdict = fontlabel)
plt.ylabel(r"$a(x)$", fontdict = fontlabel)
plt.show()
In [ ]:
plt.semilogy(x,np.abs(a_noisy - a_filter), lw = 2, label=r"\vert a_{noisy}-a_{filter}\vert")
plt.semilogy(x,np.abs(a - a_filter), color = "red", lw = 2, label=r"\vert a-a_{filter}\vert")
plt.legend(loc="lower left", bbox_to_anchor=[0, 1],
ncol=2, shadow=True, fancybox=True)
plt.xlabel(r"$x$", fontdict = fontlabel)
plt.ylabel(r"difference", fontdict = fontlabel)
In [ ]:
def explicit_filter(a):
n = len(a)
a_filter = np.zeros(n)
a_filter[1:-1] = (a[0:-2] + 2.*a[1:-1] + a[2:])/4.
a_filter[0] = (a[n-2] + 2.*a[0] + a[1])/4.
a_filter[n-1] = a_filter[0]
return a_filter
In [ ]:
a_filter = explicit_filter(a_noisy)
plt.semilogy(x,np.abs(a_noisy - a_filter), lw = 2, label=r"$\vert a_{noisy}-a_{filter}\vert$")
plt.semilogy(x,np.abs(a - a_filter), color = "red", lw = 2, label=r"$\vert a-a_{filter}\vert$")
plt.legend(loc="lower left", bbox_to_anchor=[0, 1],
ncol=2, shadow=True, fancybox=True)
plt.xlabel(r"$x$", fontdict = fontlabel)
plt.ylabel(r"difference", fontdict = fontlabel)
In [ ]:
In [ ]:
%matplotlib inline
# plots graphs within the notebook
%config InlineBackend.figure_format='svg' # not sure what this does, may be default images to svg format
from IPython.display import display,Image, Latex
from __future__ import division
from sympy.interactive import printing
printing.init_printing(use_latex='mathjax')
import time
from IPython.display import display,Image, Latex
from IPython.display import clear_output
#import SchemDraw as schem
#import SchemDraw.elements as e
import matplotlib.pyplot as plt
import numpy as np
import math
import scipy.constants as sc
import sympy as sym
from IPython.core.display import HTML
def header(text):
raw_html = '<h4>' + str(text) + '</h4>'
return raw_html
def box(text):
raw_html = '<div style="border:1px dotted black;padding:2em;">'+str(text)+'</div>'
return HTML(raw_html)
def nobox(text):
raw_html = '<p>'+str(text)+'</p>'
return HTML(raw_html)
def addContent(raw_html):
global htmlContent
htmlContent += raw_html
class PDF(object):
def __init__(self, pdf, size=(200,200)):
self.pdf = pdf
self.size = size
def _repr_html_(self):
return '<iframe src={0} width={1[0]} height={1[1]}></iframe>'.format(self.pdf, self.size)
def _repr_latex_(self):
return r'\includegraphics[width=1.0\textwidth]{{{0}}}'.format(self.pdf)
class ListTable(list):
""" Overridden list class which takes a 2-dimensional list of
the form [[1,2,3],[4,5,6]], and renders an HTML Table in
IPython Notebook. """
def _repr_html_(self):
html = ["<table>"]
for row in self:
html.append("<tr>")
for col in row:
html.append("<td>{0}</td>".format(col))
html.append("</tr>")
html.append("</table>")
return ''.join(html)
font = {'family' : 'serif',
#'color' : 'black',
'weight' : 'normal',
'size' : 12,
}
fontlabel = {'family' : 'serif',
#'color' : 'black',
'weight' : 'normal',
'size' : 16,
}
from matplotlib.ticker import FormatStrFormatter
plt.rc('font', **font)