├── README.md ├── .gitattributes ├── 3D Histogram Example.py ├── PHYS510 A1 P2 Machine Precision.py ├── FourierExampleFFT.py ├── CSI690Prob1.13 SimpleEulerMethod.py ├── CSI690Prob14.8 2DSteepestDescent.py ├── CSI690Prob6.4 NewtonRaphsonRootFind.py ├── PHYS510 A6 Part1 Monte Carlo.py ├── CSI690 MonteCarloParticle2.py ├── CSI690 MonteCarloParticle1.py ├── PHYS510 A1 P3 Quadratic Equation.py ├── CSI690Prob9.9 MatrixSolve.py ├── CSI690Prob27.12 PowerMethod.py ├── CSI690Prob17.6 LeastSquares.py ├── CSI690Prob5.12 BisectionRootFind.py ├── PHYS510 A2 Root Find.py ├── PHYS510 A1 P4 Summing Series.py ├── .gitignore ├── CSI690Prob21.5 Integration.py ├── Linearization Exponential Fit.py ├── RKF45 Example.py ├── CSI690Prob25.5 RungeKutta.py ├── PHYS510 A7 ODEs.py ├── PHYS510 A4 Numerical Integration Parts123.py ├── PHYS510 A4 Numerical Integration Part4.py ├── PHYS510 A6 Part2 Monte Carlo.py ├── PHYS510 A5 Least Squares.py ├── rootFindFunctions.py └── PHYS510 A3 Interpolation.py /README.md: -------------------------------------------------------------------------------- 1 | # NumericalMethods 2 | A collection of numerical methods in Python. Includes root finding, interpolation, least squares, differentiation, integration, Monte Carlo, ODE solvers and a few extras. 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /3D Histogram Example.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example of how to use the matplotlib 3D module 3 | for making 3D histograms out of 3D bar plots. 4 | """ 5 | import matplotlib as mpl 6 | from mpl_toolkits.mplot3d import Axes3D 7 | import matplotlib.pyplot as plt 8 | import numpy as np 9 | 10 | fig = plt.figure() 11 | ax = fig.add_subplot(111, projection='3d') 12 | 13 | xpos=np.random.randint(1,10,10) 14 | ypos=np.random.randint(1,10,10) 15 | zpos=np.zeros(10) 16 | dx=np.ones(10) 17 | dy=np.ones(10) 18 | dz=np.random.randint(1,10,10) 19 | 20 | ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color='b', zsort='average') 21 | 22 | plt.show() 23 | 24 | -------------------------------------------------------------------------------- /PHYS510 A1 P2 Machine Precision.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Sat May 25 23:38:45 2013 3 | PHYS 510, Assignment 1, Problem 2 4 | """ 5 | 6 | # Determine your Machine Precision 7 | """ 8 | Write a program to determine the machine precision of your machine 9 | (within a factor of 2) for double precision floating-point operations. 10 | The output of your program should contain at least two columns showing 11 | the value of x and eps as eps gets increasing small. 12 | What is the value of eps for your machine? 13 | """ 14 | 15 | eps = 1 16 | x = 2 17 | i = 0 18 | 19 | # Iterate and make epsilon smaller by half each iteration 20 | # Then add to 1 until epsilon become small enough where 1+eps = 1 21 | while x > 1: 22 | eps = eps/2.0 23 | x = 1.0 + eps 24 | 25 | # use formatted print statement to get enough decimals of precision 26 | print '%2.0f' % i, '%0.16f' % eps, '%0.16f' % x 27 | 28 | i = i + 1 29 | 30 | print '\nIteration =', i-1 31 | print 'eps =', eps 32 | print 'x =', x 33 | 34 | -------------------------------------------------------------------------------- /FourierExampleFFT.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example of Fourier Spectrum Analysis using FFT. 3 | 4 | Generates a sin wave in the time domain and uses FFT to 5 | convert signal to frequency domain using numpy fft. 6 | """ 7 | 8 | 9 | import numpy as np 10 | from math import pi 11 | import matplotlib.pyplot as plt 12 | 13 | # generate sin wave as sample data in time domain (amplitude vs time) 14 | pts = 128 15 | sinFreq = 5.0 16 | t = np.linspace(0,1,pts) 17 | amp = np.sin(2*pi*sinFreq*t) 18 | 19 | # do FFT on time domain signal to get freq domain (freq spectrum vs freq) 20 | s = abs(np.fft.fftn(amp)) # full two-sided spectrum, take abs since FFT gives complex values 21 | spectrum = s[range(pts/2)] # take only one side of spectrum 22 | fmin = min(spectrum) 23 | fmax = max(spectrum) 24 | npts = len(spectrum) 25 | freq = np.linspace(fmin,fmax,npts) 26 | 27 | # plot time domain signal 28 | plt.subplot(211) 29 | plt.title('FFT of Time Signal to Freq Signal') 30 | plt.xlabel('Time (sec)') 31 | plt.ylabel('Amplitude') 32 | plt.plot(t,amp) 33 | 34 | # plot freq domain signal 35 | plt.subplot(212) 36 | plt.xlabel('Frequency (Hz)') 37 | plt.ylabel('Spectrum') 38 | plt.plot(freq,spectrum) -------------------------------------------------------------------------------- /CSI690Prob1.13 SimpleEulerMethod.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Tue Sep 01 21:44:01 2015 3 | CSI 690, Assignment 1 4 | Nick Crump 5 | """ 6 | 7 | # Problem 1.13: Euler method to solve simple 1st-order ODE 8 | 9 | """ 10 | From Numerical Methods for Engineers - Chapra 6th Ed 11 | """ 12 | 13 | from math import pi 14 | import matplotlib.pyplot as plt 15 | 16 | # set input parameters 17 | k = 0.1 # mm/min 18 | r0 = 3.0 # mm 19 | t0 = 0.0 # min 20 | tf = 20.0 # min 21 | dt = 0.25 # min 22 | 23 | # get initial values 24 | N = int((tf-t0)/dt) 25 | V0 = (4/3.0)*pi*r0**3 26 | ti = t0 27 | 28 | # print initial values 29 | print '%4.2f %10.6f %10.6f' % (t0,V0,r0) 30 | 31 | # loop to get numerical solution by simple Euler method 32 | V = [V0] 33 | t = [t0] 34 | for i in range(N): 35 | Vi = V[i] - 4*pi*k*dt*((3*V[i])/(4*pi))**(2/3.0) 36 | ri = ((3*Vi)/(4*pi))**(1/3.0) 37 | ti = ti + dt 38 | V.append(Vi) 39 | t.append(ti) 40 | print '%4.2f %10.6f %10.6f' % (ti,Vi,ri) 41 | 42 | 43 | # loop to get analytical solution done by hand 44 | Vact = [] 45 | for i in t: 46 | Vt = (V0**(1/3.0) - (4*pi/3.0)**(1/3.0)*k*i)**3 47 | Vact.append(Vt) 48 | 49 | 50 | # make plots 51 | plt.plot(t,Vact,'r.-',label='Analytical Solution') 52 | plt.plot(t,V,'b.-',label='Numerical Solution') 53 | plt.xlabel('time (min)',fontsize=16) 54 | plt.ylabel('volume (mm$^3$)',fontsize=16) 55 | plt.legend() -------------------------------------------------------------------------------- /CSI690Prob14.8 2DSteepestDescent.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Tue Oct 13 21:02:39 2015 3 | CSI 690, Assignment 5 4 | Nick Crump 5 | """ 6 | 7 | # Problem 14.8 Use steepest descent/ascent to minimize/maximize a 2D function 8 | 9 | """ 10 | From Numerical Methods for Engineers - Chapra 6th Ed 11 | """ 12 | 13 | # input parameters 14 | # ------------------------------------------------- 15 | # input function of 2-variables 16 | def f(x,y): 17 | f = -8*x + x**2 + 12*y + 4*y**2 - 2*x*y 18 | return f 19 | 20 | # input function gradient 21 | def gradf(x,y): 22 | dfx = -8 + 2*x - 2*y 23 | dfy = 12 + 8*y - 2*x 24 | return dfx,dfy 25 | 26 | # select whether finding max or min 27 | opt = 'min' # select 'max' or 'min' 28 | 29 | # input starting parameters 30 | x0,y0 = 0,0 # initial x,y point 31 | h = 0.2 # step size 32 | tol = 1e-8 # stop tolerance 33 | # ------------------------------------------------- 34 | 35 | # get sign for max/min selector 36 | if opt == 'max': sign = 1 37 | if opt == 'min': sign = -1 38 | 39 | # get initial values 40 | f0 = f(x0,y0) 41 | dfx0,dfy0 = gradf(x0,y0) 42 | err = 1 43 | itr = 0 44 | 45 | # print header 46 | print '\niteration x y f(x,y) relative error' 47 | print ' %i %8.3f %8.3f %8.3f %8.6f' % (itr,x0,y0,f0,err) 48 | 49 | # iterate to optimize function 50 | while err > tol: 51 | # get points on line along gradient direction 52 | xi,yi = x0+sign*dfx0*h, y0+sign*dfy0*h 53 | # get new function value and error 54 | fi = f(xi,yi) 55 | err = abs((fi-f0)/fi) 56 | # update values 57 | dfx0,dfy0 = gradf(xi,yi) 58 | x0,y0 = xi,yi 59 | f0 = fi 60 | itr += 1 61 | 62 | # print final results 63 | print ' %i %8.3f %8.3f %8.3f %8.6f' % (itr,x0,y0,f0,err) -------------------------------------------------------------------------------- /CSI690Prob6.4 NewtonRaphsonRootFind.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Sun Sep 27 17:46:41 2015 3 | CSI 690, Assignment 3 4 | Nick Crump 5 | """ 6 | 7 | # Problem 6.4: Newton-Raphson method to find roots of equation 8 | 9 | """ 10 | From Numerical Methods for Engineers - Chapra 6th Ed 11 | """ 12 | 13 | import numpy as np 14 | import matplotlib.pyplot as plt 15 | 16 | 17 | # input parameters 18 | # ------------------------------------------------- 19 | # input function 20 | def f(x): 21 | f = -1 + 5.5*x -4*x**2 + 0.5*x**3 22 | return f 23 | 24 | # input function derivative 25 | def df(x): 26 | df = 5.5 - 8*x + 1.5*x**2 27 | return df 28 | 29 | # input bracket parameters and stop criteria 30 | x0 = 6 # initial guess 31 | pTol = 0.01 # percent error tolerance to stop 32 | nMax = 20 # max iterations 33 | # ------------------------------------------------- 34 | 35 | 36 | # initialize variables 37 | err = 100 38 | ni = 0 39 | xi = 0 40 | 41 | # print header 42 | print '\n' 43 | print 'iteration xi f(xi) relative error %' 44 | 45 | # loop until error is less than input tolerance 46 | while err > pTol: 47 | 48 | # stop if max iterations reached 49 | if ni >= nMax: 50 | print '\nMAX ITERATIONS REACHED' 51 | print 'Root = ',xi 52 | print 'Iterations = ',ni 53 | print 'Relative Error =',round(err,3),'%' 54 | exit() 55 | 56 | # Newton-Raphson method 57 | xi = x0 - (f(x0)/df(x0)) # predict root from derivative 58 | err = abs(xi-x0)/xi*100 # calculate approx error 59 | ni += 1 # increment iteration 60 | x0 = xi # store the n-1 root 61 | 62 | 63 | # print results 64 | print ' %i %8.5f %8.5f %8.5f' % (ni,xi,f(xi),err) 65 | 66 | # plot functions 67 | x = np.arange(-2,8,0.1) 68 | n = len(x) 69 | plt.figure() 70 | plt.subplot(211) 71 | plt.plot(x,f(x),'b',label='function') 72 | plt.plot(x,np.zeros(len(x)),'k--') 73 | plt.legend(loc=2) 74 | plt.subplot(212) 75 | plt.plot(x,df(x),'r',label='derivative') 76 | plt.legend(loc=2) -------------------------------------------------------------------------------- /PHYS510 A6 Part1 Monte Carlo.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Thu Jun 27 20:48:37 2013 3 | PHYS 510, Assignment 6 Part 1 4 | """ 5 | 6 | # Monte Carlo Methods 7 | """ 8 | Part 1: Using the Monte Carlo approach, approximate the volume of a ball with radius 0.04 at 9 | x,y,z = (1/3 ,1/3, 1/2). Use 10e6 three dimensional points with seed x0 = 1. How close 10 | is your approximation to the correct answer? 11 | """ 12 | 13 | 14 | import math 15 | import numpy as np 16 | 17 | # Part 1 18 | # Approximate Volume of Sphere using Monte Carlo Method 19 | #******************************************************************* 20 | def Sphere(r,x0,y0,z0,n): 21 | # r = radius of sphere, x0,y0,z0 = center of sphere, n = number of points 22 | # calculates volume of a sphere using the method of generating random points 23 | # within a cube and counting how many fall within the sphere bounded by the cube 24 | # Volume of Sphere = (Volume of cube)*[(# points in sphere)/(# points in cube)] 25 | 26 | # get bounding box of cube 27 | xmin, xmax = x0 - r, x0 + r 28 | ymin, ymax = y0 - r, y0 + r 29 | zmin, zmax = z0 - r, z0 + r 30 | rSqr = r**2 31 | 32 | inSphere = 0 # start a counter for points landing in sphere 33 | 34 | # generate n random (x,y,z) points within cube 35 | # use sphere equation to determine if within sphere 36 | for i in range(int(n)): 37 | x = np.random.uniform(xmin,xmax) 38 | y = np.random.uniform(ymin,ymax) 39 | z = np.random.uniform(zmin,zmax) 40 | 41 | if (x-x0)**2 + (y-y0)**2 + (z-z0)**2 < rSqr: 42 | inSphere = inSphere + 1 43 | 44 | AreaCube = (2*r)**3 # area of cube 45 | AreaSphere = AreaCube*(inSphere/n) # approx area of sphere 46 | Actual = (4.0/3.0)*math.pi*(r**3) # actual area of sphere 47 | 48 | print 'Approximate Area = ', AreaSphere 49 | print 'Accurate to ', (abs(Actual-AreaSphere)/Actual)*100, '%' 50 | 51 | 52 | Sphere(0.04,1/3,1/3,1/2,10e6) 53 | #******************************************************************* -------------------------------------------------------------------------------- /CSI690 MonteCarloParticle2.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Fri Nov 27 22:50:06 2015 3 | CSI 690, Assignment 11 4 | Nick Crump 5 | """ 6 | 7 | # Monte Carlo simulation to compute average energy of single particle in 1D 8 | 9 | import numpy as np 10 | import matplotlib.pyplot as plt 11 | 12 | 13 | # input parameters 14 | # -------------------------------------- 15 | dmax = 10 # max step size 16 | tmp0 = 0.1 # start temp 17 | tmp1 = 1.0 # final temp 18 | ntmp = 10 # number of temps 19 | Etol = 0.1 # energy error tolerance 20 | # -------------------------------------- 21 | 22 | # set temperatures 23 | Tarr = np.linspace(tmp0,tmp1,ntmp) 24 | 25 | # initialize arrays 26 | Earr = [] 27 | Ethr = [] 28 | 29 | # loop over temps 30 | for i in range(ntmp): 31 | # initialize for this temp 32 | T = Tarr[i] 33 | x = 100 34 | E = 0.1*x*x 35 | aveE = E 36 | thrE = 0.5*T 37 | errE = 1 38 | acc = 0 39 | step = 0 40 | # loop over atom 41 | while errE > Etol: 42 | # store old values 43 | xi = x 44 | Ei = E 45 | # take a step 46 | x += np.random.uniform(-dmax,dmax,1)[0] 47 | # calculate new energy 48 | E = 0.1*x*x 49 | d = E-Ei 50 | # accept move if new energy is lower 51 | if d < 0: 52 | acc += 1 53 | # otherwise check boltzmann condition 54 | else: 55 | prob = np.exp(-d/T) 56 | # accept move with this probability 57 | if np.random.uniform(0,1,1)[0] < prob: 58 | acc += 1 59 | # reject move otherwise 60 | else: 61 | x = xi 62 | E = Ei 63 | # increment and collect running average 64 | step += 1 65 | aveEi = aveE 66 | aveE = aveEi + (E-aveEi)/float(step) 67 | errE = abs(thrE-aveE)/thrE 68 | 69 | # store values per temp 70 | accP = acc/float(step) 71 | Earr.append(aveE) 72 | Ethr.append(thrE) 73 | 74 | # print results 75 | if i == 0: print '\n T %Err %Acc Steps' 76 | print '%4.2f %6.2f %4.2f %4.2f %i' % (T,aveE,errE*100,accP*100,step) 77 | 78 | # make plots 79 | plt.figure() 80 | plt.plot(Tarr,Earr,'bo-',label='Simulated') 81 | plt.plot(Tarr,Ethr,'ro-',label='Theoretical') 82 | plt.title('Monte Carlo Particle Sim') 83 | plt.xlabel('T') 84 | plt.ylabel('') 85 | plt.legend(loc=2) -------------------------------------------------------------------------------- /CSI690 MonteCarloParticle1.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Fri Nov 27 22:50:06 2015 3 | CSI 690, Assignment 11 4 | Nick Crump 5 | """ 6 | 7 | # Monte Carlo simulation to compute average energy of single particle in 1D 8 | 9 | import numpy as np 10 | import matplotlib.pyplot as plt 11 | 12 | 13 | # input parameters 14 | # ---------------------------------- 15 | dmax = 10 # max step size 16 | tmp0 = 0.1 # start temp 17 | tmp1 = 1.0 # final temp 18 | ntmp = 10 # number of temps 19 | runs = 1000 # iterations per temp 20 | # ---------------------------------- 21 | 22 | # set temperatures 23 | Tarr = np.linspace(tmp0,tmp1,ntmp) 24 | 25 | # get uniform random numbers 26 | rand = np.random.uniform(-dmax,dmax,[ntmp,runs]) 27 | chek = np.random.uniform(0,1,[ntmp,runs]) 28 | 29 | # initialize arrays 30 | Earr = [] 31 | Ethr = [] 32 | x = 100 33 | # loop over temps 34 | for i in range(ntmp): 35 | # initialize for this temp 36 | T = Tarr[i] 37 | 38 | E = 0.1*x*x 39 | Esum = E 40 | acc = 0 41 | # loop over atom 42 | for j in range(runs): 43 | # store old values 44 | xi = x 45 | Ei = E 46 | # take a step 47 | x += rand[i,j] 48 | # calculate new energy 49 | E = 0.1*x*x 50 | d = E-Ei 51 | # accept move if new energy is lower 52 | if d < 0: 53 | Esum += E 54 | acc += 1 55 | # otherwise check boltzmann condition 56 | else: 57 | prob = np.exp(-d/T) 58 | # accept move with this probability 59 | if chek[i,j] < prob: 60 | Esum += E 61 | acc += 1 62 | # reject move otherwise 63 | else: 64 | x = xi 65 | E = Ei 66 | Esum += E 67 | 68 | # store average energy and acceptance probability per temp 69 | aveE = Esum/float(runs+1) 70 | accP = (acc/float(runs+1))*100 71 | Earr.append(aveE) 72 | 73 | # theoretical result and error 74 | thrE = 0.5*T 75 | errE = (abs(thrE-aveE)/thrE)*100 76 | Ethr.append(thrE) 77 | 78 | # print results 79 | if i == 0: print '\n T %Err %Acc Steps' 80 | print '%4.2f %6.2f %4.2f %4.2f %i' % (T,aveE,errE,accP,runs) 81 | 82 | # make plots 83 | plt.figure() 84 | plt.plot(Tarr,Earr,'bo-',label='Simulated') 85 | plt.plot(Tarr,Ethr,'ro-',label='Theoretical') 86 | plt.title('Monte Carlo Particle Sim') 87 | plt.xlabel('T') 88 | plt.ylabel('') 89 | plt.legend(loc=2) -------------------------------------------------------------------------------- /PHYS510 A1 P3 Quadratic Equation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Sun May 26 09:49:41 2013 3 | PHYS 510, Assignment 1, Problem 3 4 | """ 5 | 6 | # The Quadratic Formula and Subtractive Cancellation 7 | """ 8 | 1. Write a program that calculate the four solutions x1, x2, y1, and y2 9 | for the quadratic equation with a set of arbitrary values of a, b, and c. 10 | 2. Take a=b=1, and c=10^-n, n=1,2,3,... and compute the four solutions for 11 | increasing n. Make sure that your output have enough significant figures. 12 | 3. What is the largest n when machine precision causes Eq. (2) to fail? 13 | 4. Since b>0, subtractive cancellation will NOT occur in y1 and x2. Treat 14 | these two values as the accurate solutions to the quadratic equation and 15 | calcuate the errors in the other two solutions x1 and y2. Plot the fractional 16 | relative errors of x1 and y2 as a function of 4ac in a log-log graph. 17 | 5. Comment on your results in relation to the machine precision. 18 | """ 19 | 20 | import math 21 | from matplotlib import pyplot 22 | 23 | # Part 1 24 | #************************************************************** 25 | # Define functions for quadratic eq and alternate quadratic eq 26 | def quadraticEq(a,b,c): 27 | x1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a) 28 | x2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a) 29 | return x1, x2 30 | 31 | def AltquadraticEq(a,b,c): 32 | y1 = (-2*c) / (b + math.sqrt(b**2 - 4*a*c)) 33 | y2 = (-2*c) / (b - math.sqrt(b**2 - 4*a*c)) 34 | return y1, y2 35 | #************************************************************** 36 | 37 | 38 | # Parts 2 & 3 39 | a = 1 40 | b = 1 41 | n = 1 42 | 43 | x1Error = [] 44 | y2Error = [] 45 | array4ac = [] 46 | # By trail and error it was found that AltquadraticEq fails for n > 16 47 | # This is due to division by zero as c becomes too small to represent 48 | while n < 17: 49 | print 'n =', n 50 | c = 10**-n 51 | x1, x2 = quadraticEq(a,b,c) 52 | y1, y2 = AltquadraticEq(a,b,c) 53 | 54 | print 'x1 =', x1 55 | print 'x2 =', x2 56 | print 'y1 =', y1 57 | print 'y2 =', y2 58 | 59 | n = n + 1 60 | 61 | # Store the relative errors for x1 and y2 for plotting 62 | x1Error.append(abs((y1 - x1)/y1)) # relative error abs(x-x' / x) 63 | y2Error.append(abs((x2 - y2)/x2)) # relative error abs(x-x' / x) 64 | array4ac.append(4*a*c) 65 | 66 | 67 | # Part 4 68 | # Plot x1 and y2 relative errors against 4ac on a log-log plot 69 | pyplot.plot(array4ac, x1Error, 'bo', array4ac, y2Error, 'ro') 70 | pyplot.xscale('log') 71 | pyplot.yscale('log') 72 | pyplot.title('Relative Errors vs 4ac') 73 | pyplot.xlabel('4ac') 74 | pyplot.ylabel('Relative Error') 75 | pyplot.legend(('x1Error','y2Error')) 76 | -------------------------------------------------------------------------------- /CSI690Prob9.9 MatrixSolve.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Thu Oct 08 18:46:50 2015 3 | CSI 690, Assignment 4 4 | Nick Crump 5 | """ 6 | 7 | # Problem 9.9: Gaussian elimination to solve matrix equation 8 | 9 | """ 10 | From Numerical Methods for Engineers - Chapra 6th Ed 11 | """ 12 | 13 | import numpy as np 14 | 15 | 16 | # input parameters 17 | # --------------------------------------------------------------------- 18 | # input matrix as row elements 19 | # note: precision must be float or better to get good results! 20 | a = np.array([[4,1,-1],[5,1,2],[6,1,1]],float) 21 | b = np.array([[-2],[4],[6]],float) 22 | 23 | # input tolerance for detecting singularity (near-zero determinant) 24 | tol = 10e-6 25 | # --------------------------------------------------------------------- 26 | 27 | # get matrix dimensions 28 | arow = np.size(a,axis=0) 29 | acol = np.size(a,axis=1) 30 | brow = np.size(b,axis=0) 31 | bcol = np.size(b,axis=1) 32 | 33 | # check input is valid 34 | if arow != acol or arow != brow or bcol != 1: 35 | print '\nwarning: matrix is not square. check input.' 36 | exit() 37 | 38 | # initialize arrays 39 | acpy = np.copy(a) 40 | xsol = np.zeros([arow,1]) 41 | atmp = np.zeros(arow) 42 | btmp = np.zeros(1) 43 | sign = 0 44 | 45 | # forward elimination to reduce matrix 46 | for i in range(0,arow-1): 47 | # partial pivoting to avoid divide by zero 48 | indx = i 49 | pmax = abs(a[i,i]) 50 | for p in range(i+1,acol): 51 | ai = abs(a[p,i]) 52 | if ai > pmax: 53 | pmax = ai 54 | indx = p 55 | # exchange rows if pivot value not max 56 | if indx != i: 57 | atmp[:] = a[indx,:] 58 | btmp[:] = b[indx,:] 59 | a[indx,:] = a[i,:] 60 | b[indx,:] = b[i,:] 61 | a[i,:] = atmp[:] 62 | b[i,:] = btmp[:] 63 | sign += 1 64 | # main Gaussian elimination 65 | # final matrix is upper right triangular 66 | for j in range(i+1,arow): 67 | f = a[j,i]/float(a[i,i]) 68 | for k in range(i+1,arow): 69 | a[j,k] = a[j,k] - f*a[i,k] 70 | b[j] = b[j] - f*b[i] 71 | 72 | # check that matrix is not singular (zero determinant) 73 | # determinant for triangular matrix is product of diagonals 74 | det = np.prod(np.diag(a))*(-1)**sign 75 | if abs(det) < tol: 76 | print '\nwarning: singular matrix. check input.' 77 | exit() 78 | 79 | # back substitution to solve matrix 80 | mx = arow-1 81 | xsol[mx] = b[mx]/float(a[mx,mx]) 82 | for i in range(arow-1,-1,-1): 83 | s = b[i] 84 | for j in range(i+1,arow): 85 | s = s - a[i,j]*xsol[j] 86 | xsol[i] = s/float(a[i,i]) 87 | 88 | # check solution by substituting back into original equations 89 | xchk = np.sum(acpy*np.transpose(xsol),axis=1).reshape(arow,1) 90 | 91 | # print solution 92 | print '\nsolution:' 93 | print xsol 94 | print 'determinant:' 95 | print det 96 | print 'solution check:' 97 | print xchk -------------------------------------------------------------------------------- /CSI690Prob27.12 PowerMethod.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Sun Nov 15 14:49:36 2015 3 | CSI 690, Assignment 9 4 | Nick Crump 5 | """ 6 | 7 | # Problem 27.11/12 Power method to solve eigenvalue equation 8 | # Finds the highest and lowest eigenvalues and their eigenvectors 9 | """ 10 | From Numerical Methods for Engineers - Chapra 6th Ed 11 | """ 12 | 13 | import numpy as np 14 | 15 | 16 | # input parameters 17 | # ------------------------------------------------- 18 | # input matrix 19 | A = np.array([[2, 8, 10],\ 20 | [8, 4, 5], \ 21 | [10,5, 7]]) 22 | 23 | # input error tolerance 24 | tol = 1e-6 25 | # ------------------------------------------------- 26 | 27 | # solves eigenvalue equation Ax = Lx 28 | 29 | # get matrix dimension 30 | dim = len(A) 31 | # set initial guess for x 32 | xMax = np.ones((dim,1),float) 33 | xMin = np.ones((dim,1),float) 34 | # set initial error 35 | errMx = 1 36 | errMn = 1 37 | # set iteration variables 38 | itrMx = 0 39 | itrMn = 0 40 | tmpMx = 0 41 | tmpMn = 0 42 | 43 | # find max eigenvalue (L) & eigenvector (x) 44 | # iterate over matrix A 45 | while errMx > tol: 46 | # multiply Ax 47 | xMax = np.dot(A,xMax) 48 | # get eigenvalue 49 | mx = np.max(xMax) 50 | mn = np.min(xMax) 51 | if abs(mx) >= abs(mn): 52 | LMax = mx 53 | else: 54 | LMax = mn 55 | # normalize eigenvector 56 | xMax = xMax/LMax 57 | # get relative error 58 | errMx = abs((LMax-tmpMx)/LMax) 59 | tmpMx = LMax 60 | # count iterations 61 | itrMx += 1 62 | 63 | # find min eigenvalue (L) & eigenvector (x) 64 | # this time iterate over inverse of A 65 | Ainv = np.linalg.inv(A) 66 | while errMn > tol: 67 | # multiply inverse(A)x 68 | xMin = np.dot(Ainv,xMin) 69 | # get 1/eigenvalue 70 | mx = np.max(xMin) 71 | mn = np.min(xMin) 72 | if abs(mx) >= abs(mn): 73 | LMin = mx 74 | else: 75 | LMin = mn 76 | # normalize eigenvector 77 | xMin = xMin/LMin 78 | # get relative error 79 | errMn = abs((LMin-tmpMn)/LMin) 80 | tmpMn = LMin 81 | # count iterations 82 | itrMn += 1 83 | # get eigenvalue from reciprocal 84 | LMin = 1.0/LMin 85 | 86 | # check results Ax-Lx = 0 87 | diffMx = np.round(np.dot(A,xMax) - np.dot(LMax,xMax),3) 88 | diffMn = np.round(np.dot(A,xMin) - np.dot(LMin,xMin),3) 89 | 90 | # print max results 91 | print '\n' 92 | print 'max eigenvalue:' 93 | print '%11.6f' % LMax 94 | print 'eigenvector:' 95 | print xMax 96 | print 'iterations:' 97 | print '%4i' % itrMx 98 | # print min results 99 | print '\n' 100 | print 'min eigenvalue:' 101 | print '%11.6f' % LMin 102 | print 'eigenvector:' 103 | print xMin 104 | print 'iterations:' 105 | print '%4i' % itrMn 106 | # print check results 107 | print '\n' 108 | print 'check Ax-Lx=0:' 109 | print 'max:' 110 | print diffMx 111 | print 'min:' 112 | print diffMn -------------------------------------------------------------------------------- /CSI690Prob17.6 LeastSquares.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Thu Oct 22 21:35:13 2015 3 | CSI 690, Assignment 6 4 | Nick Crump 5 | """ 6 | 7 | # Problem 17.6 Use least squares polynomial regression to fit a data set 8 | 9 | """ 10 | From Numerical Methods for Engineers - Chapra 6th Ed 11 | """ 12 | 13 | import sys 14 | import numpy as np 15 | import matplotlib.pyplot as plt 16 | 17 | 18 | # input parameters 19 | # ------------------------------------------------- 20 | # input data set 21 | x = np.array([1,2,3,4,5,6,7,8,9],float) 22 | y = np.array([1,1.5,2,3,4,5,8,10,13],float) 23 | 24 | # input degree of polynomial fit 25 | n = 2 26 | # ------------------------------------------------- 27 | 28 | # fit model is polynomial: y = c0 + c1(x) + c2(x**2) +...+ cn(x**n) 29 | 30 | pts = len(x) # number of poins in data set 31 | polyval = [] # array to store poly fit values 32 | 33 | # if degree of polynomial is not less than number of points print error 34 | if n+1 > pts: 35 | print '\nWarning: Polynomial degree must be less than number of data points' 36 | print 'Check input' 37 | sys.exit() 38 | 39 | # compute fit function using polynomial least squares 40 | else: 41 | matrixA = np.zeros((pts,n+1)) # initialize matrix A 42 | matrixB = np.zeros((pts,1)) # initialize matrix b 43 | 44 | # loop to populate arrays 45 | for i in range(pts): 46 | matrixB[i][0] = y[i] # b gets y values 47 | for j in range(n+1): 48 | matrixA[i][j] = (x[i])**j # A gets x values^j 49 | 50 | # create normal equations (A^T)Ax=(A^T)b 51 | At = np.transpose(matrixA) # A transpose (A^T) 52 | AtA = np.dot(At,matrixA) # matrix multiply (A^T)A 53 | AtB = np.dot(At,matrixB) # matrix multiply (A^T)b 54 | coeff = np.linalg.solve(AtA,AtB) # solve normal equation (A^T)Ax=(A^T)b 55 | 56 | # get y-fit values 57 | for i in range(pts): 58 | yval = 0 59 | for j in range(n+1): 60 | yval = yval + coeff[j,0]*(x[i])**j # gets new y value using fit coeffs 61 | polyval.append(yval) # collect new y values 62 | 63 | # get standard deviation of fit as "goodness of fit" 64 | error = y-polyval 65 | sumval = np.sum(error**2) 66 | stddev = (sumval/(pts-(n+1)))**0.5 67 | 68 | # get correlation coefficient of fit as alternate "goodness of fit" 69 | ymean = np.sum(y)/pts 70 | sumfit = np.sum((y-ymean)**2) 71 | rvalue = ((sumfit-sumval)/sumfit)**0.5 72 | 73 | # plot data and fit 74 | plt.figure() 75 | plt.plot(x,y,'bo-',label='data set') 76 | plt.plot(x,polyval,'r-',label='polynomial fit') 77 | plt.xlabel('x') 78 | plt.ylabel('y') 79 | plt.legend(loc=2) 80 | 81 | # print results 82 | print '\npolynomial coefficients' 83 | for i in coeff.flatten(): 84 | print '%10.6f' % i 85 | print '\nstandard error' 86 | print '%10.6f' % stddev 87 | print '\ncorrelation coefficient' 88 | print '%10.6f' % rvalue -------------------------------------------------------------------------------- /CSI690Prob5.12 BisectionRootFind.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Sun Sep 27 17:46:41 2015 3 | CSI 690, Assignment 3 4 | Nick Crump 5 | """ 6 | 7 | # Problem 5.12: Bisection method to find max of equation 8 | 9 | """ 10 | From Numerical Methods for Engineers - Chapra 6th Ed 11 | """ 12 | 13 | from sys import exit 14 | from math import isnan,isinf 15 | import numpy as np 16 | import matplotlib.pyplot as plt 17 | 18 | 19 | # input parameters 20 | # ------------------------------------------------- 21 | # input function 22 | def f(x): 23 | f = -2*x**6 - 1.6*x**4 + 12*x + 1 24 | return f 25 | 26 | # input function derivative 27 | def df(x): 28 | df = -12*x**5 - 6.4*x**3 + 12 29 | return df 30 | 31 | # input bracket parameters and stop criteria 32 | xL = 0 # lower bracket value 33 | xH = 1 # upper bracker value 34 | pTol = 5 # percent error tolerance to stop 35 | nMax = 20 # max iterations 36 | # ------------------------------------------------- 37 | 38 | 39 | # error checking 40 | notnum1 = isnan(df(xL)*df(xH)) 41 | notnum2 = isinf(df(xL)*df(xH)) 42 | if df(xL)*df(xH) >= 0: 43 | print '\nEITHER NO ROOTS OR MULTIPLE ROOTS EXIST BETWEEN BRACKET POINTS.' 44 | print 'ADJUST BRACKET VALUES.\n' 45 | exit() 46 | if notnum1 == True or notnum2 == True: 47 | print '\nFUNCTION IS UNDEFINED AT BRACKET POINTS.' 48 | print 'ADJUST BRACKET VALUES.\n' 49 | exit() 50 | 51 | # initialize variables 52 | err = 100 53 | ni = 0 54 | xi = 0 55 | xM = 0 56 | 57 | # print header 58 | print '\n' 59 | print 'iteration x-value f-max relative error %' 60 | 61 | # loop until error is less than input tolerance 62 | while err > pTol: 63 | 64 | # stop if max iterations reached 65 | if ni >= nMax: 66 | print '\nMAX ITERATIONS REACHED' 67 | print 'Root = ',xM 68 | print 'Iterations = ',ni 69 | print 'Relative Error =',round(err,3),'%' 70 | exit() 71 | 72 | # bisection method 73 | xM = 0.5*(xL+xH) # define midpoint 74 | 75 | if df(xL)*df(xM) > 0: 76 | xL = xM 77 | err = abs(xM-xi)/xM*100 # calculate approx error 78 | ni += 1 # increment iteration 79 | xi = xM # store the n-1 midpoint 80 | 81 | elif df(xL)*df(xM) < 0: 82 | xH = xM 83 | err = abs(xM-xi)/xM*100 # calculate approx error 84 | ni += 1 # increment iteration 85 | xi = xM # store the n-1 midpoint 86 | 87 | # print results 88 | print ' %i %8.5f %8.5f %8.5f' % (ni,xM,f(xM),err) 89 | 90 | # plot functions 91 | x = np.arange(0,1.2,0.1) 92 | n = len(x) 93 | plt.figure() 94 | plt.subplot(211) 95 | plt.plot(x,f(x),'b',label='function') 96 | plt.plot([xM,xM],[0,10],'k--') 97 | plt.legend(loc=2) 98 | plt.subplot(212) 99 | plt.plot(x,df(x),'r',label='derivative') 100 | plt.plot(x,np.zeros(len(x)),'k--') 101 | plt.plot([xM,xM],[-20,15],'k--') 102 | plt.legend(loc=3) -------------------------------------------------------------------------------- /PHYS510 A2 Root Find.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Thu May 30 21:01:03 2013 3 | PHYS 510, Assignment 2 4 | (Calls 'rootFindFunctions.py' where algorithms are defined) 5 | """ 6 | 7 | # Root Finding 8 | """ 9 | Design a program that finds the roots of a given function so the user 10 | has the following options: 11 | 1. the user can enter root brackets between which a single root is sought 12 | 2. the user has the choice of the root-finding algorithm used 13 | * Bisection method 14 | * Hybrid Bisection / Newton-Raphson method 15 | * Hybrid Bisection / Secant method 16 | * Hybrid Bisection / Muller-Brent method 17 | 3. the user should be able to enter the function whose roots are to be found 18 | 4. the program should report the number of iterations 19 | """ 20 | 21 | import math 22 | import rootFindFunctions 23 | 24 | # define root finding function with choices for algorithm used 25 | #-------------------------------------------------------------------------------------- 26 | # called as rootFind('function(x)', xInitial, xFinal, Tolerance, MaxIterations, Method) 27 | # 'function(x)' = input function of x inside quotes (Ex: 'cos(x)-x') 28 | # xInitial = initial x bracket value on one side of the root (entered as decimal) 29 | # xFinal = initial x bracket value on the other side of the root (entered as decimal) 30 | # Tolerance = the degree of accuracy in which to compute the root (Ex: 10e-5) 31 | # MaxIterations = max number of iterations to compute if Tolerance has not been met 32 | # Method = choice of root finding method to use, entered inside quotes 33 | # (options are: 'bisection', 'newton', 'secant', 'muller') 34 | #-------------------------------------------------------------------------------------- 35 | 36 | def rootFind(g, xI, xF, Tol, nMax, Mthd): 37 | f = lambda x: eval(g) # create function from input 38 | 39 | # check input bracket condition to ensure root is betwwen braket points 40 | # check to make sure function is defined at bracket points too 41 | # this checks for examples like ln(0) = -inf or ln(0)*ln(4) = nan 42 | notnum1 = math.isnan(f(xI)*f(xF)) 43 | notnum2 = math.isinf(f(xI)*f(xF)) 44 | if f(xI)*f(xF) >= 0 or notnum1 == True or notnum2 == True: 45 | print '\nNO ROOTS BETWEEN THESE POINTS OR FUNCTION IS UNDEFINED.' 46 | print 'PLEASE ADJUST BRACKET VALUES.\n' 47 | return 48 | 49 | if Mthd == 'bisection': 50 | # enter root finding algorithm by Bisection method 51 | rootFindFunctions.rootBisection(g, f, xI, xF, Tol, nMax, Mthd) 52 | 53 | elif Mthd == 'newton': 54 | # enter root finding algorithm by hybrid Bisection/Newton-Raphson method 55 | rootFindFunctions.rootNewtonRaphson(g, f, xI, xF, Tol, nMax, Mthd) 56 | 57 | elif Mthd == 'secant': 58 | # enter root finding algorithm by hybrid Bisection/Secant method 59 | rootFindFunctions.rootSecant(g, f, xI, xF, Tol, nMax, Mthd) 60 | 61 | elif Mthd == 'muller': 62 | # enter root finding algorithm by hybrid Bisection/Muller-Brent method 63 | rootFindFunctions.rootMullerBrent(g, f, xI, xF, Tol, nMax, Mthd) 64 | 65 | 66 | else: 67 | print '\nINVALID ENTRY. PLEASE ADJUST INPUT AND TRY AGAIN.\n' -------------------------------------------------------------------------------- /PHYS510 A1 P4 Summing Series.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Mon May 27 13:54:27 2013 3 | PHYS 510, Assignment 1, Problem 4 4 | """ 5 | 6 | # Summing Series 7 | """ 8 | 1. Write a program that plots the partial sum S(x,N) of the Taylor expansion 9 | for exp(x) and its relative fractional error vs N up to N=30 for a given x. 10 | Test your program for x=10,2,-2, and -10. From the plots, explain why 11 | this is not a good way to evaluate exp(x) when x<0. [Note: when x<0, 12 | the Taylor expansion of the exponential is an alternating series.] 13 | 2. Modify your program so that it uses the identity exp(x)=1/exp(-x)~1/S(-x,N) 14 | to evaluate the exponential when x is negative. Explain why this 15 | approach works better. 16 | """ 17 | 18 | import math 19 | from matplotlib import pyplot 20 | 21 | # Part 1 22 | #***************************************************************** 23 | # Define function to approximate exp(x) using a Taylor expansion 24 | # Calculates partial sums and absolute fractional error 25 | # Then plots partial sums and errors vs n 26 | def TaylorExp(x,n): 27 | actual = math.exp(x) 28 | psum = 0 29 | psumArray = [] 30 | relError = [] 31 | iteration = range(n) 32 | 33 | for i in iteration: 34 | term = (float(x)**i) / math.factorial(i) # compute each term 35 | psum = psum + term # keep a rolling partial sum 36 | 37 | err = abs((actual - psum)/actual) # compute error abs(x-x' / x) 38 | 39 | psumArray.append(psum) # write values to arrays 40 | relError.append(err) 41 | 42 | # generate plot for partial sum 43 | pyplot.subplot(2,1,1) 44 | pyplot.plot(iteration, psumArray, 'bo') 45 | pyplot.title('Taylor Approximation of Exp(' + str(x) + ')') 46 | pyplot.ylabel('Partial Sum') 47 | 48 | # plot actual exp(x) value as a line on partial sum plot 49 | pyplot.subplot(2,1,1) 50 | pyplot.plot([0, n-1], [actual, actual], 'r') 51 | 52 | # generate plot for errors 53 | pyplot.subplot(2,1,2) 54 | pyplot.plot(iteration, relError, 'ro') 55 | pyplot.xlabel('Iteration n') 56 | pyplot.ylabel('Relative Error') 57 | #***************************************************************** 58 | 59 | 60 | # Part 2 61 | #***************************************************************** 62 | # Define a function that modifies the Taylor approximation function above 63 | # This function uses the identity described in the intro to evaluate the 64 | # exponential when x is negative 65 | def ModTaylorExp(x,n): 66 | actual = math.exp(x) 67 | psum = 0 68 | psumArray = [] 69 | relError = [] 70 | iteration = range(n) 71 | 72 | for i in iteration: 73 | term = (float(-x)**i) / math.factorial(i) # modified so x = -x 74 | psum = psum + term # keep a rolling partial sum 75 | 76 | err = abs((actual - (1/psum))/actual) # modified so psum = 1/psum 77 | 78 | psumArray.append(1/psum) # modified so psum = 1/psum 79 | relError.append(err) 80 | 81 | # generate plot for partial sum 82 | pyplot.subplot(2,1,1) 83 | pyplot.plot(iteration, psumArray, 'bo') 84 | pyplot.title('Modified Taylor Approximation of Exp(' + str(x) + ')') 85 | pyplot.ylabel('Modified Partial Sum') 86 | #pyplot.axis([0,30,-0.1,1]) 87 | 88 | # plot actual exp(x) value as a line on partial sum plot 89 | pyplot.subplot(2,1,1) 90 | pyplot.plot([0, n-1], [actual, actual], 'r') 91 | 92 | # generate plot for errors 93 | pyplot.subplot(2,1,2) 94 | pyplot.plot(iteration, relError, 'ro') 95 | pyplot.xlabel('Iteration n') 96 | pyplot.ylabel('Relative Error') 97 | #***************************************************************** 98 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | *.publishproj 131 | 132 | # NuGet Packages Directory 133 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 134 | #packages/ 135 | 136 | # Windows Azure Build Output 137 | csx 138 | *.build.csdef 139 | 140 | # Windows Store app package directory 141 | AppPackages/ 142 | 143 | # Others 144 | sql/ 145 | *.Cache 146 | ClientBin/ 147 | [Ss]tyle[Cc]op.* 148 | ~$* 149 | *~ 150 | *.dbmdl 151 | *.[Pp]ublish.xml 152 | *.pfx 153 | *.publishsettings 154 | 155 | # RIA/Silverlight projects 156 | Generated_Code/ 157 | 158 | # Backup & report files from converting an old project file to a newer 159 | # Visual Studio version. Backup files are not needed, because we have git ;-) 160 | _UpgradeReport_Files/ 161 | Backup*/ 162 | UpgradeLog*.XML 163 | UpgradeLog*.htm 164 | 165 | # SQL Server files 166 | App_Data/*.mdf 167 | App_Data/*.ldf 168 | 169 | ############# 170 | ## Windows detritus 171 | ############# 172 | 173 | # Windows image file caches 174 | Thumbs.db 175 | ehthumbs.db 176 | 177 | # Folder config file 178 | Desktop.ini 179 | 180 | # Recycle Bin used on file shares 181 | $RECYCLE.BIN/ 182 | 183 | # Mac crap 184 | .DS_Store 185 | 186 | 187 | ############# 188 | ## Python 189 | ############# 190 | 191 | *.py[cod] 192 | 193 | # Packages 194 | *.egg 195 | *.egg-info 196 | dist/ 197 | build/ 198 | eggs/ 199 | parts/ 200 | var/ 201 | sdist/ 202 | develop-eggs/ 203 | .installed.cfg 204 | 205 | # Installer logs 206 | pip-log.txt 207 | 208 | # Unit test / coverage reports 209 | .coverage 210 | .tox 211 | 212 | #Translations 213 | *.mo 214 | 215 | #Mr Developer 216 | .mr.developer.cfg 217 | -------------------------------------------------------------------------------- /CSI690Prob21.5 Integration.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Sat Oct 31 22:37:14 2015 3 | CSI 690, Assignment 7 4 | Nick Crump 5 | """ 6 | 7 | # Problem 21.5 Numerically integrate a function 8 | # Uses Trapezoid, Simpson 1/3, Romberg, Gauss-Legendre methods 9 | 10 | """ 11 | From Numerical Methods for Engineers - Chapra 6th Ed 12 | """ 13 | 14 | import numpy as np 15 | from scipy.special import p_roots 16 | 17 | 18 | # input parameters 19 | # ------------------------------------------------- 20 | # input function 21 | def f(x): 22 | f = (4*x - 3)**3 23 | return f 24 | 25 | # input limits of integration 26 | a = -3 27 | b = 5 28 | 29 | # input number of intervals 30 | n = 10 31 | # ------------------------------------------------- 32 | 33 | # analytical solution 34 | def intf(a,b): 35 | intf = ((4*b-3)**4 - (4*a-3)**4)/16 36 | return intf 37 | asol = intf(a,b) 38 | 39 | 40 | # trapezoid method 41 | # ------------------------------------- 42 | def trapezoid(f,a,b,n): 43 | # get intervals 44 | h = (b-a)/float(n) 45 | x = np.arange(a,b+h,h) 46 | # sum intervals 47 | trap = f(x[0])+f(x[n]) 48 | for i in range(1,n): 49 | trap += 2*f(x[i]) 50 | trap = (h/2.0)*trap 51 | return trap 52 | # ------------------------------------- 53 | 54 | # simpson 1/3 method 55 | # ------------------------------------- 56 | def simpson(f,a,b,n): 57 | # intervals must be even for simpson 1/3 58 | if n%2 != 0: 59 | n += 1 60 | h = (b-a)/float(n) 61 | x = np.arange(a,b+h,h) 62 | # sum intervals 63 | simp = f(x[0])+f(x[n]) 64 | for i in range(1,n): 65 | if i%2 == 0: w = 2 66 | else: w = 4 67 | simp += w*f(x[i]) 68 | simp = (h/3.0)*simp 69 | return simp 70 | # ------------------------------------- 71 | 72 | # romberg method 73 | # ------------------------------------- 74 | def romberg(f,a,b,n): 75 | # initialize romberg matrix 76 | steps = [] 77 | R = np.zeros((n,n)) 78 | R[0,0] = 0.5*(b-a)*(f(a)+f(b)) 79 | # fill first column of romberg matrix 80 | for i in range(1,n): 81 | pts = 2**i 82 | h = (b-a)/float(pts) 83 | steps.append(h) 84 | psum = 0 85 | for j in range(1, pts): 86 | if j % 2 != 0: 87 | psum += f(a + j*h) 88 | # populate matrix 89 | R[i,0] = 0.5*R[i-1,0] + h*psum 90 | # get integral from romberg matrix 91 | for i in range(1,n): 92 | for j in range(i,n): 93 | r1 = R[j,i-1] 94 | r0 = R[j-1,i-1] 95 | k = 1.0/(4.0**i-1) 96 | R[j,i] = r1 + k*(r1 - r0) 97 | romb = R[n-1,n-1] 98 | return romb 99 | # ------------------------------------- 100 | 101 | # gauss-legendre method 102 | # ------------------------------------- 103 | def gausslegendre(f,a,b,n): 104 | # uses roots of legendre polynomials 105 | x,w = p_roots(n) 106 | psum = 0 107 | # valid only over interval [-1,1] 108 | # map input [a,b] to interval [-1,1] 109 | for i in range(n): 110 | # transform interval 111 | psum += w[i]*f(0.5*(b-a)*x[i] + 0.5*(b+a)) 112 | gaus = 0.5*(b-a)*psum 113 | return gaus 114 | # ------------------------------------- 115 | 116 | 117 | # call integration routines 118 | trap = trapezoid(f,a,b,n) 119 | simp = simpson(f,a,b,n) 120 | romb = romberg(f,a,b,n) 121 | gaus = gausslegendre(f,a,b,n) 122 | # get integration error 123 | terr = (abs(asol-trap)/asol)*100 124 | serr = (abs(asol-simp)/asol)*100 125 | rerr = (abs(asol-romb)/asol)*100 126 | gerr = (abs(asol-gaus)/asol)*100 127 | 128 | 129 | # print results 130 | print '\nMethod Solution Error' 131 | print '--------------------------------------' 132 | print 'analytical %12.6f %6.3f' % (asol,0),'%' 133 | print 'trapezoid %12.6f %6.3f' % (trap,terr),'%' 134 | print 'simpson %12.6f %6.3f' % (simp,serr),'%' 135 | print 'romberg %12.6f %6.3f' % (romb,rerr),'%' 136 | print 'gauss-legendre %12.6f %6.3f' % (gaus,gerr),'%' -------------------------------------------------------------------------------- /Linearization Exponential Fit.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Thu Jun 20 06:14:19 2013 3 | PHYS 510, Assignment 5 (This part just for fun) 4 | """ 5 | 6 | # Exponential Fitting by Linearization 7 | """ 8 | The program below uses the Least Squares method to fit an exponential to a data set using the method 9 | of linearization. The exponential model is first transormed into a log model in order to linearize 10 | the data and compute the best coefficients which can then be placed back into the exponential model. 11 | This is a common technique of linearizing a nonlinear problem so it can be solved easier. 12 | NOTE: THIS ONLY WORKS FOR DATA SETS WITH POSITIVE Y VALUES SINCE IT INVOLVES TAKING A LOG(Y)! 13 | """ 14 | 15 | 16 | import numpy as np 17 | import matplotlib.pyplot as plt 18 | import math 19 | 20 | # this part just for fun 21 | # Exponential fitting method for nonlinear data 22 | #******************************************************************* 23 | def ExponentialFit(x,y): 24 | # ** NOTE: this model only works on data sets for POSITIVE y values since uses log(y) ** 25 | # fit model is exponential: y = c0exp(c1*x), but we have to linearize it to use least squares 26 | # instead we change the fit model to: ln(y) = ln(c0) + c1(x) = k0 + c1(x) 27 | # where k0 = ln(c0) to make linear 28 | # solve for these coeffients k0 and c1 then plug back into exponential model 29 | 30 | pts = len(x) # number of points in data set 31 | expval = [] # array to store exponential fit values 32 | 33 | matrixA = np.zeros((pts,2)) # initialize matrix A 34 | matrixB = np.zeros((pts,1)) # initialize matrix b 35 | 36 | # loop to populate arrays 37 | for i in range(pts): 38 | matrixB[i][0] = math.log(y[i]) # b gets ln(y) values to linearize fit model 39 | matrixA[i][0] = 1 # 1st column of A for k0 coeffs are 1's 40 | matrixA[i][1] = x[i] # 2nd column of A for c1 coeffs are x values 41 | 42 | # create normal equation (A^T)Ax=(A^T)b 43 | At = np.transpose(matrixA) # A transpose (A^T) 44 | AtA = np.dot(At,matrixA) # matrix multiply (A^T)A 45 | AtB = np.dot(At,matrixB) # matrix multiply (A^T)b 46 | 47 | coeff = np.linalg.solve(AtA,AtB) # solve normal equation (A^T)Ax=(A^T)b for x 48 | k0 = coeff[0] # name nonlinear coefficient k0 for use below 49 | c0 = math.exp(k0) # name linear coefficient c0 for use below 50 | c1 = coeff[1] # name nonlinear coefficient c1 for use below 51 | 52 | 53 | # we now have the coefficients for the exponential fit 54 | # next plug x values back into fit model and compute new y fit values 55 | varsum = 0 56 | # loop to get y fit values and compute variance on fit 57 | for i in range(pts): 58 | yval = c0*math.exp(c1*x[i]) 59 | expval.append(yval) 60 | 61 | # compute variance from erorr (error=actualY-fitY) 62 | # NOTE: variance here is calculated on the LINEARIZED equation 63 | error = math.log(y[i]) - k0 - c1*x[i] 64 | varsum = varsum + error**2 65 | 66 | # using variance as measure for 'goodness of fit' 67 | # computed as variance = (sum of squares of errors) / (nDataPts-nFitCoefficients-1) 68 | variance = round(varsum/(pts-2-1), 4) 69 | 70 | 71 | # plot data set with exponential fit and annotate variance 72 | plt.title('Exponential Fit by Linearization') 73 | plt.xlabel('x') 74 | plt.ylabel('y') 75 | plt.plot(x,y,'bo', label='Data') 76 | plt.plot(x,expval, 'r', linewidth=2, label='Exponential') 77 | plt.annotate('Variance='+str(variance),fontsize=14,xy=(0.15,0.83),xycoords='figure fraction') 78 | plt.legend() 79 | 80 | 81 | #ExponentialFit(x,y) 82 | #------------------------------------------------------------------- 83 | # x = x data set 84 | # y = y data set (y DATA MUST BE POSITIVE) 85 | #------------------------------------------------------------------- 86 | #******************************************************************* -------------------------------------------------------------------------------- /RKF45 Example.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example of fifth-order Runge-Kutta-Fehlberg method (RKF45) with 3 | adaptive step size to solve a first-order linear homogeneous ODE. 4 | 5 | ODE: y'(x) - y = x 6 | Initial Condition: y(1) = 3 7 | Boundary: x = [-2, 2] 8 | """ 9 | 10 | 11 | import math as m 12 | import numpy as np 13 | import matplotlib.pyplot as plt 14 | 15 | 16 | # ODE function f = y'(x) = x + y 17 | #********************************* 18 | def ODEfunc(xi, yi): 19 | fi = xi + yi 20 | 21 | return fi 22 | #********************************* 23 | 24 | 25 | # Fifth-Order Runge-Kutta-Fehlberg Method (RKF45) with adaptive step size 26 | #************************************************************************************* 27 | def RKF45(x0,xf,y0,h,eps): 28 | 29 | # create x and y arrays for storing solution values 30 | x = [x0] 31 | y = [y0] 32 | 33 | # set initial values 34 | xi = x0 35 | yi = y0 36 | 37 | # RKF45 coefficients 38 | # for intermediate function f1 39 | a1, b1, = 0.25, 0.25 40 | # for intermediate function f2 41 | a2, b2, c2 = 3.0/8.0, 3.0/32.0, 9.0/32.0 42 | # for intermediate function f3 43 | a3, b3, c3, d3 = 12.0/13.0, 1932.0/2197.0, 7200.0/2197.0, 7296.0/2197.0 44 | # for intermediate function f4 45 | a4, b4, c4, d4, e4 = 1, 439.0/216.0, 8, 3680.0/513.0, 845.0/4104.0 46 | # for intermediate function f5 47 | a5, b5, c5, d5, e5, f5 = 0.5, 8.0/27.0, 2, 3544.0/2565.0, 1859.0/4104.0, 11.0/40.0 48 | 49 | # for fifth-order solution 50 | Y1, Y2, Y3, Y4, Y5 = 16.0/135.0, 6656.0/12825.0, 28561.0/56430.0, 9.0/50.0, 2.0/55.0 51 | # for error estimate 52 | E1, E2, E3, E4, E5 = 1.0/360.0, 128.0/4275.0, 2197.0/75240.0, 1.0/50.0, 2.0/55.0 53 | 54 | # RKF45 method to solve ODE over each adaptive step h 55 | while xi <= xf: 56 | 57 | f0 = ODEfunc(xi,yi) 58 | 59 | xI = xi + a1*h 60 | yI = yi + b1*h*f0 61 | f1 = ODEfunc(xI,yI) 62 | 63 | xI = xi + a2*h 64 | yI = yi + b2*h*f0 + c2*h*f1 65 | f2 = ODEfunc(xI,yI) 66 | 67 | xI = xi + a3*h 68 | yI = yi + b3*h*f0 - c3*h*f1 + d3*h*f2 69 | f3 = ODEfunc(xI,yI) 70 | 71 | xI = xi + a4*h 72 | yI = yi + b4*h*f0 - c4*h*f1 + d4*h*f2 - e4*h*f3 73 | f4 = ODEfunc(xI,yI) 74 | 75 | xI = xi + a5*h 76 | yI = yi - b5*h*f0 + c5*h*f1 - d5*h*f2 + e5*h*f3 - f5*h*f4 77 | f5 = ODEfunc(xI,yI) 78 | 79 | 80 | yy = yi + h*(Y1*f0 + Y2*f2 + Y3*f3 - Y4*f4 + Y5*f5) 81 | error = h*(E1*f0 - E2*f2 - E3*f3 + E4*f4 + E5*f5) 82 | RelError = abs(error/yy) 83 | 84 | hNew = h*(eps/RelError)**0.2 85 | if hNew >= h: 86 | xi = xi + h 87 | yi = yy 88 | x.append(xi) 89 | y.append(yy) 90 | 91 | h = 0.9*hNew 92 | 93 | return x,y 94 | #************************************************************************************* 95 | 96 | 97 | # Main program that calls methods and plots solutions 98 | #************************************************************************************* 99 | # set up analytic solution of ODE y'(x)= y(x) + x for plotting 100 | # analytic solution is y(x) = C*exp(x) - x - 1, for C = 5/exp(1) from y(1) = 3 101 | # plotting over interval x = [-2,2] so y(-2) used as initial y0 in methods 102 | x = np.linspace(-2,2,81) 103 | y = [] 104 | c = 5.0/m.exp(1) 105 | y0 = c*m.exp(-2) + 2 - 1 106 | 107 | # get exact solution for y 108 | for i in x: 109 | yActual = c*m.exp(i) - i - 1 110 | y.append(yActual) 111 | 112 | # plot exact solution for comparison with method solutions 113 | plt.title("Runge-Kutta-Fehlberg (RKF45) Solution to ODE $y$"+"'"+"$(x) - y = x$") 114 | plt.xlabel('x') 115 | plt.ylabel('y') 116 | plt.plot(x,y, linewidth=4, label='Exact Solution') 117 | 118 | # call and plot method solution 119 | xx,yy = RKF45(-2,2,y0,0.1,1.0e-5) 120 | 121 | # plot method solutions 122 | plt.plot(xx,yy, 'r', linewidth=1.5, label='RKF45') 123 | plt.legend(loc=2) 124 | #************************************************************************************* -------------------------------------------------------------------------------- /CSI690Prob25.5 RungeKutta.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Tue Nov 03 16:34:18 2015 3 | CSI 690, Assignment 8 4 | Nick Crump 5 | """ 6 | 7 | # Problem 25.5 Numerically solve ODE 8 | # Uses Euler, Heun, Midpoint, RK2 and RK4 methods 9 | 10 | """ 11 | From Numerical Methods for Engineers - Chapra 6th Ed 12 | """ 13 | 14 | import numpy as np 15 | import matplotlib.pyplot as plt 16 | 17 | 18 | # input parameters 19 | # ------------------------------------------------- 20 | # input ode as function 21 | def func(x,y): 22 | f = y*np.sin(x)**3 23 | return f 24 | 25 | # input initial conditions 26 | y0 = 1 # initial condition on y 27 | x0 = 0 # initial condition on x 28 | xf = 3 # upper limit on x 29 | h = 0.1 # step size 30 | # ------------------------------------------------- 31 | 32 | # analytical solution 33 | def y(x): 34 | y = 1.947734*np.exp((np.cos(3*x)-9*np.cos(x))/12.0) 35 | return y 36 | 37 | # simple euler method 38 | # ------------------------------------- 39 | def simpleEuler(func,x0,y0,xf,h): 40 | # uses derivative at start of interval 41 | pts = np.int(abs(xf-x0)/float(h))+1 42 | x = np.linspace(x0,xf,pts) 43 | y = np.zeros(pts) 44 | y[0] = y0 45 | # integrate ode 46 | for i in range(pts-1): 47 | # get startpoint derivative 48 | dy = func(x[i],y[i]) 49 | y[i+1] = y[i] + h*dy 50 | return x,y 51 | # ------------------------------------- 52 | 53 | # improved euler method (Heun) 54 | # ------------------------------------- 55 | def improvedEuler(func,x0,y0,xf,h): 56 | # uses average derivative at endpoints of interval 57 | pts = np.int(abs(xf-x0)/float(h))+1 58 | x = np.linspace(x0,xf,pts) 59 | y = np.zeros(pts) 60 | y[0] = y0 61 | # integrate ode 62 | for i in range(pts-1): 63 | # get average derivative 64 | dy1 = func(x[i],y[i]) 65 | dy2 = func(x[i]+h,y[i]+h*dy1) 66 | dyAvg = 0.5*(dy1+dy2) 67 | y[i+1] = y[i] + h*dyAvg 68 | return x,y 69 | # ------------------------------------- 70 | 71 | # modified euler method (Midpoint) 72 | # ------------------------------------- 73 | def modifiedEuler(func,x0,y0,xf,h): 74 | # uses derivative at midpoint of interval 75 | pts = np.int(abs(xf-x0)/float(h))+1 76 | x = np.linspace(x0,xf,pts) 77 | y = np.zeros(pts) 78 | y[0] = y0 79 | # integrate ode 80 | for i in range(pts-1): 81 | # get midpoint derivative 82 | xmid = x[i]+0.5*h 83 | ymid = y[i]+0.5*h*func(x[i],y[i]) 84 | dyMid = func(xmid,ymid) 85 | y[i+1] = y[i] + h*dyMid 86 | return x,y 87 | # ------------------------------------- 88 | 89 | # 2nd-order runge-kutta (Ralston RK2) 90 | # ------------------------------------- 91 | def rungekutta2(func,x0,y0,xf,h): 92 | # 2nd order accurate 93 | pts = np.int(abs(xf-x0)/float(h))+1 94 | x = np.linspace(x0,xf,pts) 95 | y = np.zeros(pts) 96 | y[0] = y0 97 | # integrate ode 98 | for i in range(pts-1): 99 | y1 = func(x[i],y[i]) 100 | y2 = func(x[i]+0.75*h,y[i]+0.75*h*y1) 101 | y[i+1] = y[i] + (h/3.0)*(y1 + 2*y2) 102 | return x,y 103 | # ------------------------------------- 104 | 105 | # 4th-order runge-kutta (Standard RK4) 106 | # ------------------------------------- 107 | def rungekutta4(func,x0,y0,xf,h): 108 | # 4th order accurate 109 | pts = np.int(abs(xf-x0)/float(h))+1 110 | x = np.linspace(x0,xf,pts) 111 | y = np.zeros(pts) 112 | y[0] = y0 113 | # integrate ode 114 | for i in range(pts-1): 115 | y1 = func(x[i],y[i]) 116 | y2 = func(x[i]+0.5*h,y[i]+0.5*h*y1) 117 | y3 = func(x[i]+0.5*h,y[i]+0.5*h*y2) 118 | y4 = func(x[i]+h,y[i]+h*y3) 119 | y[i+1] = y[i] + (h/6.0)*(y1 + 2*y2 + 2*y3 + y4) 120 | return x,y 121 | # ------------------------------------- 122 | 123 | 124 | # call functions 125 | x1,y1 = simpleEuler(func,x0,y0,xf,h) 126 | x2,y2 = improvedEuler(func,x0,y0,xf,h) 127 | x3,y3 = modifiedEuler(func,x0,y0,xf,h) 128 | x4,y4 = rungekutta2(func,x0,y0,xf,h) 129 | x5,y5 = rungekutta4(func,x0,y0,xf,h) 130 | ya = y(x1) 131 | 132 | # plot results 133 | plt.figure() 134 | plt.plot(x1,ya,'o-',label='Analytical') 135 | plt.plot(x1,y1,label='Euler') 136 | plt.plot(x2,y2,label='Heun') 137 | plt.plot(x3,y3,label='Midpoint') 138 | plt.plot(x4,y4,label='RK2') 139 | plt.plot(x5,y5,label='RK4') 140 | plt.xlabel('x') 141 | plt.ylabel('y') 142 | plt.legend(loc=2) 143 | plt.annotate('h='+str(h),fontsize=16,xy=(0.20,0.54),xycoords='figure fraction') -------------------------------------------------------------------------------- /PHYS510 A7 ODEs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Wed Jul 10 20:41:20 2013 3 | PHYS 510, Assignment 7 4 | 5 | """ 6 | 7 | # Ordinary Differential Equations (ODEs) 8 | """ 9 | Write a program to solve the differential equation y'(x) = y + x using the following methods: 10 | 11 | 1. Simple Euler Method 12 | 2. Modified Euler Method 13 | 3. Improved Euler Method 14 | 4. Fourth-Order Runge-Kutta Method (RK4) 15 | 16 | Use x in the range [-2,2] with the initial condition y(1) = 3. 17 | Plot the results for step size h = 0.05, 0.10, 0.15, and 0.20, along with the exact result. 18 | Compare and discuss the four methods. 19 | """ 20 | 21 | 22 | import math as m 23 | import numpy as np 24 | import matplotlib.pyplot as plt 25 | 26 | # Part 1 27 | # Simple Euler Method 28 | #************************************************************************************* 29 | def simpleEuler(x0,xf,y0,h): 30 | # this solves the ODE y'(x)= y(x) + x with initial condition y(1) = 3 31 | # [x0,xf] = boundary of function domain, y0 = initial condition, h = step size 32 | # this method uses the derivative at the start of the interval across each step 33 | 34 | # get number of points over interval for step size h 35 | pts = m.floor(abs(xf-x0)/h) + 1 36 | 37 | # create x array of points and y array for storing solution values 38 | x = np.linspace(x0,xf,pts) 39 | y = np.zeros(pts) 40 | y[0] = y0 41 | 42 | # do Simple Euler Method to solve ODE over each step h 43 | for i in np.arange(0,pts-1): 44 | y[i+1] = y[i] + h*(y[i] + x[i]) # Euler approx to function 45 | 46 | return x,y 47 | #************************************************************************************* 48 | 49 | 50 | # Part 2 51 | # Modified Euler Method 52 | #************************************************************************************* 53 | def modifiedEuler(x0,xf,y0,h): 54 | # this solves the ODE y'(x)= y(x) + x with initial condition y(1) = 3 55 | # this method uses the derivative at the midpoint of the interval across each step 56 | 57 | # get number of points over interval for step size h 58 | pts = m.floor(abs(xf-x0)/h) + 1 59 | 60 | # create x array of points and y array for storing solution values 61 | x = np.linspace(x0,xf,pts) 62 | y = np.zeros(pts) 63 | y[0] = y0 64 | 65 | # do Modified Euler Method to solve ODE over each step h 66 | for i in np.arange(0,pts-1): 67 | xmid = x[i] + 0.5*h # get x midpoint across interval 68 | ymid = y[i] + 0.5*h*(y[i] + x[i]) # get y at x midpoint 69 | 70 | y[i+1] = y[i] + h*(ymid + xmid) # Euler approx to function at midpoint 71 | 72 | return x,y 73 | #************************************************************************************* 74 | 75 | 76 | # Part 3 77 | # Improved Euler Method 78 | #************************************************************************************* 79 | def improvedEuler(x0,xf,y0,h): 80 | # this solves the ODE y'(x)= y(x) + x with initial condition y(1) = 3 81 | # this method uses the average derivative value over the interval across each step 82 | 83 | # get number of points over interval for step size h 84 | pts = m.floor(abs(xf-x0)/h) + 1 85 | 86 | # create x array of points and y array for storing solution values 87 | x = np.linspace(x0,xf,pts) 88 | y = np.zeros(pts) 89 | y[0] = y0 90 | 91 | # do Improved Euler Method to solve ODE over each step h 92 | for i in np.arange(0,pts-1): 93 | dy1 = y[i] + x[i] # get derivative at interval start 94 | dy2 = (y[i] + h*dy1) + (x[i] + h) # get derivative at interval end 95 | dyAvg = 0.5*(dy1 + dy2) # take average of derivatives 96 | 97 | y[i+1] = y[i] + h*(dyAvg) # Euler approx to function using dyAvg 98 | 99 | return x,y 100 | #************************************************************************************* 101 | 102 | 103 | # Part 4 104 | # Fourth-Order Runge-Kutta Method (RK4) 105 | #************************************************************************************* 106 | def RungeKutta(x0,xf,y0,h): 107 | # this solves the ODE y'(x)= y(x) + x with initial condition y(1) = 3 108 | # this method uses the fourth-order Runge-Kutta Method (RK4) 109 | 110 | # get number of points over interval for step size h 111 | pts = m.floor(abs(xf-x0)/h) + 1 112 | 113 | # create x array of points and y array for storing solution values 114 | x = np.linspace(x0,xf,pts) 115 | y = np.zeros(pts) 116 | y[0] = y0 117 | 118 | # do Runge-Kutta Method to solve ODE over each step h 119 | for i in np.arange(0,pts-1): 120 | y1 = y[i] + x[i] 121 | y2 = (y[i] + 0.5*h*y1) + (x[i] + 0.5*h) 122 | y3 = (y[i] + 0.5*h*y2) + (x[i] + 0.5*h) 123 | y4 = (y[i] + h*y3) + (x[i] + h) 124 | 125 | y[i+1] = y[i] + (h/6.0)*(y1 + 2*y2 + 2*y3 + y4) 126 | 127 | return x,y 128 | #************************************************************************************* 129 | 130 | 131 | # Main program that calls methods and plots solutions 132 | #************************************************************************************* 133 | # set up analytic solution of ODE y'(x)= y(x) + x for plotting 134 | # analytic solution is y(x) = C*exp(x) - x - 1, for C = 5/exp(1) from y(1) = 3 135 | # plotting over interval x = [-2,2] so y(-2) used as initial y0 in methods 136 | x = np.linspace(-2,2,81) 137 | y = [] 138 | c = 5.0/m.exp(1) 139 | y0 = c*m.exp(-2) + 2 - 1 140 | 141 | # get exact solution for y 142 | for i in x: 143 | yActual = c*m.exp(i) - i - 1 144 | y.append(yActual) 145 | 146 | # plot exact solution for comparison with method solutions 147 | plt.title("Runge-Kutta (RK4) Solution to ODE $y$"+"'"+"$(x) - y = x$") 148 | plt.xlabel('x') 149 | plt.ylabel('y') 150 | plt.plot(x,y, linewidth=2.5, label='Exact Solution') 151 | 152 | # call and plot method solutions for different step sizes below 153 | h = [0.05, 0.10, 0.15, 0.20] 154 | for i in h: 155 | #xi,yi = simpleEuler(-2,2,y0,i) 156 | #xi,yi = modifiedEuler(-2,2,y0,i) 157 | #xi,yi = improvedEuler(-2,2,y0,i) 158 | xi,yi = RungeKutta(-2,2,y0,i) 159 | 160 | # plot method solutions 161 | plt.plot(xi,yi, '.-', linewidth=1.5, label='h =' + str(i)) 162 | plt.legend(loc=2) 163 | #************************************************************************************* -------------------------------------------------------------------------------- /PHYS510 A4 Numerical Integration Parts123.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Thu Jun 13 20:47:04 2013 3 | PHYS 510, Assignment 4 Parts 1,2,3 4 | """ 5 | 6 | # Numerical Integration 7 | """ 8 | This assignment is to develop algorithms for numerical integration using the following methods: 9 | 1. Trapezoid 10 | 2. Composite Simpson 1/3 11 | 3. Romberg 12 | Use the algorithms to evaluate the following integrals: 13 | 1. Int[sin(x)*exp(x)], x = -pi to pi 14 | 2. Int[x*exp(x**2)], x = -1 to 1 15 | 3. Int[1/(1+x**2)], x= -4 to 4 16 | Make a result table and compare your numerical result to the analytical solution by finding the relative 17 | percent error for each method. 18 | """ 19 | 20 | import numpy as np 21 | 22 | # Part 1 23 | # Trapezoid method 24 | #******************************************************************* 25 | def Trapezoid(g, a, b, n): 26 | f = lambda x: eval(g) # define function to evaluate 27 | 28 | h = (b-a)/n # interval size (using n rather than n-1 for Python) 29 | x = np.arange(a,b,h) # x array defined by interval size 30 | fx = [f(z) for z in x] # y array of function values evaluated at x 31 | 32 | m = len(x) # number of points to integrate over 33 | intSum = 0 # collects sum as integration iterates 34 | 35 | # loop over points to sum trapezoids in each interval to get integral 36 | for i in range(m): 37 | # check for using correct weight value in summation 38 | if i == 0 or i == n-1: 39 | w = 0.5 40 | else: 41 | w = 1 42 | 43 | # Trapezoid routine 44 | intSum = intSum + fx[i]*h*w 45 | 46 | print 'Trapezoid Integral = ', intSum 47 | 48 | 49 | #Trapezoid('sin(x)*exp(x)',-pi, pi, 50) 50 | #Trapezoid('x*exp(x**2)',-1.0, 1.0, 50) 51 | #Trapezoid('1/(1+x**2)', -4.0, 4.0, 50) 52 | #------------------------------------------------------------------- 53 | # g = 'function of x' entered in quotes (Ex. 'sin(x)') 54 | # a = integration region x start point (entered as decimal) 55 | # b = integration region x end point (entered as decimal) 56 | # n = number of points to evaluate 57 | #------------------------------------------------------------------- 58 | #******************************************************************* 59 | 60 | 61 | # Part 2 62 | # Simpson method 63 | #******************************************************************* 64 | def Simpson(g, a, b, n): 65 | f = lambda x: eval(g) # define function to evaluate 66 | 67 | # Simpson requires that n be odd 68 | # check if n is odd and if not then add 1 69 | if n % 2 == 0: 70 | n = n + 1 71 | 72 | h = (b-a)/n # interval size (using n rather than n-1 for Python) 73 | x = np.arange(a,b,h) # x array defined by interval size 74 | fx = [f(z) for z in x] # y array of function values evaluated at x 75 | 76 | m = len(x) # number of points to integrate over 77 | intSum = 0 # collects sum as integration iterates 78 | 79 | # loop over points to sum parabolas in each interval to get integral 80 | for i in range(m): 81 | # check for using correct weight value in summation 82 | if i == 0 or i == n-1: # for endpoints use w = 1/3 83 | w = 1.0/3.0 84 | elif i % 2 != 0: # for odd index use w = 4/3 85 | w = 4.0/3.0 86 | elif i % 2 == 0: # for even index use w = 2/3 87 | w = 2.0/3.0 88 | 89 | # Simpson routine 90 | intSum = intSum + fx[i]*h*w 91 | 92 | print 'Simpson Integral = ', intSum 93 | 94 | 95 | #Simpson('sin(x)*exp(x)',-pi, pi, 50) 96 | #Simpson('x*exp(x**2)',-1.0, 1.0, 50) 97 | #Simpson('1/(1+x**2)', -4.0, 4.0, 50) 98 | #------------------------------------------------------------------- 99 | # g = 'function of x' entered in quotes (Ex. 'sin(x)') 100 | # a = integration region x start point (entered as decimal) 101 | # b = integration region x end point (entered as decimal) 102 | # n = number of points to evaluate 103 | #------------------------------------------------------------------- 104 | #******************************************************************* 105 | 106 | 107 | # Part 3 108 | # Romberg method 109 | #******************************************************************* 110 | def Romberg(g, a, b, n): 111 | f = lambda x: eval(g) # define function to evaluate 112 | 113 | Rnm = np.zeros((n,n)) # create Romberg matrix 114 | 115 | # this part populates the initial column of the Romberg matrix 116 | # using modified Trapezoid rule 117 | # --------------------------------------------------- 118 | # iterate over interval step size up to n 119 | for s in range(n): 120 | 121 | h = (b-a)/(2**s) # interval size 122 | pSum = 0 # partial sum in integral routine 123 | 124 | if s == 0: 125 | R = 0.5*(b-a)*(f(a)+f(b)) # R(0,0) of Romberg method 126 | Rnm[s][0] = R # populate first value of matrix 127 | 128 | else: 129 | # iterate over interval size up to 2**(n-1) 130 | for k in range(1, 2**s): 131 | if k % 2 != 0: # only odds (k=1,3,5,..2**(n-1)) 132 | pSum = pSum + f(a + k*h) # partial sum in integral routine 133 | 134 | R = 0.5*Rnm[s-1][0] + h*pSum # R(n,0) of Romberg method 135 | Rnm[s][0] = R # populate first column of matrix 136 | # --------------------------------------------------- 137 | 138 | # this part uses previous values in Romberg matrix to get new values 139 | # each new value is closer to the actual answer 140 | # --------------------------------------------------- 141 | # iterate over rows and columns of Romberg matrix to get new values 142 | for col in range(1,n): 143 | for row in range(col,n): 144 | romb1 = Rnm[row][col-1] 145 | romb0 = Rnm[row-1][col-1] 146 | coeff = 1/((4.0**col)-1) 147 | 148 | # R(n,m) of Romberg method 149 | Rnm[row][col] = romb1 + coeff*(romb1 - romb0) 150 | # --------------------------------------------------- 151 | 152 | print 'Romberg Integral = ', Rnm[n-1][n-1] 153 | 154 | 155 | #Romberg('sin(x)*exp(x)',-pi, pi, 10) 156 | #Romberg('x*exp(x**2)',-1.0, 1.0, 10) 157 | #Romberg('1/(1+x**2)', -4.0, 4.0, 10) 158 | #------------------------------------------------------------------- 159 | # g = 'function of x' entered in quotes (Ex. 'sin(x)') 160 | # a = integration region x start point (entered as decimal) 161 | # b = integration region x end point (entered as decimal) 162 | # n = number of interval steps up to 2**(n-1) 163 | #------------------------------------------------------------------- 164 | #******************************************************************* -------------------------------------------------------------------------------- /PHYS510 A4 Numerical Integration Part4.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Thu Jun 13 20:47:04 2013 3 | PHYS 510, Assignment 4 Part 4 4 | """ 5 | 6 | # Numerical Integration 7 | """ 8 | This assignment is to develop algorithms for numerical integration using the following methods: 9 | 4. Gauss-Legendre Quadrature 10 | Use the algorithms to evaluate the following integrals: 11 | 1. Int[sin(x)*exp(x)], x = -pi to pi 12 | 2. Int[x*exp(x**2)], x = -1 to 1 13 | 3. Int[1/(1+x**2)], x= -4 to 4 14 | Make a result table and compare your numerical result to the analytical solution by finding the relative 15 | percent error for each method. 16 | """ 17 | 18 | from sympy import * 19 | 20 | # Part 4 21 | # Gauss-Legendre method 22 | #******************************************************************* 23 | def Gauss(g, a, b, n): 24 | f = lambda x: eval(g) # define function to evaluate 25 | 26 | # Gauss-Legendre lists in function below only goes to n = 12 27 | if n > 12: print 'NUMBER OF POINTS TO EVALUATE MUST BE LESS THAN 12' 28 | 29 | # get abscissas (xi), and weights (wi) from function below 30 | # GaussLegendre function below has values of xi and wi up to n = 12 31 | abscissa, weight = GaussLegendre(n) 32 | intSum = 0 33 | 34 | # Gauss-Legendre method is valid only over interval [-1,1] 35 | # check if integral is over [-1,1], if so do as normal 36 | # if not, need to map interval [a,b] to [-1,1] 37 | if a == -1 and b == 1: 38 | for i in range(n): 39 | intSum = intSum + weight[i]*f(abscissa[i]) # evaluate integral 40 | 41 | print 'Gauss Integral = ', intSum 42 | 43 | # if interval not [-1,1], map input [a,b] to [-1,1] 44 | else: 45 | sx = Symbol('sx') # define symbolic variable x 46 | x = 0.5*(b-a)*sx + 0.5*(b+a) # change of variables to map [a,b] to [-1,1] 47 | 48 | sf = eval(g) # create new symbolic function over [-1,1] 49 | f = lambdify(sx, sf) # turn symbolic function into real function 50 | 51 | for i in range(n): 52 | intSum = intSum + weight[i]*f(abscissa[i]) # evaluate integral 53 | 54 | print 'Gauss Integral = ', 0.5*(b-a)*intSum 55 | 56 | 57 | #Gauss('sin(x)*exp(x)',-pi, pi, 10) 58 | #Gauss('x*exp(x**2)',-1.0, 1.0, 10) 59 | #Gauss('1/(1+x**2)', -4.0, 4.0, 10) 60 | #------------------------------------------------------------------- 61 | # g = 'function of x' entered in quotes (Ex. 'sin(x)') 62 | # a = integration region x start point (entered as decimal) 63 | # b = integration region x end point (entered as decimal) 64 | # n = number of points to generate and evaluate (up to n = 12) 65 | #------------------------------------------------------------------- 66 | #******************************************************************* 67 | 68 | 69 | # the function below stores the abscissas (xi) and weights (wi) 70 | # for the Gauss-Legendre integration method for integration over [-1,1] 71 | #******************************************************************* 72 | def GaussLegendre(n): 73 | if n == 2: 74 | xi = [-0.5773502691896257, 0.5773502691896257] 75 | wi = [1.0000000000000000, 1.0000000000000000] 76 | 77 | if n == 3: 78 | xi = [0.0000000000000000, -0.7745966692414834, 0.7745966692414834] 79 | wi = [0.8888888888888888, 0.5555555555555556, 0.5555555555555556] 80 | 81 | if n == 4: 82 | xi = [-0.3399810435848563, 0.3399810435848563, -0.8611363115940526, 83 | 0.8611363115940526] 84 | wi = [0.6521451548625461, 0.6521451548625461, 0.3478548451374538, 85 | 0.3478548451374538] 86 | 87 | if n == 5: 88 | xi = [0.0000000000000000, -0.5384693101056831, 0.5384693101056831, 89 | -0.9061798459386640, 0.9061798459386640] 90 | wi = [0.5688888888888889, 0.4786286704993665, 0.4786286704993665, 91 | 0.2369268850561891, 0.2369268850561891] 92 | 93 | if n == 6: 94 | xi = [0.6612093864662645, -0.6612093864662645, -0.2386191860831969, 95 | 0.2386191860831969, -0.9324695142031521, 0.9324695142031521] 96 | wi = [0.3607615730481386, 0.3607615730481386, 0.4679139345726910, 97 | 0.4679139345726910, 0.1713244923791704, 0.1713244923791704] 98 | 99 | if n == 7: 100 | xi = [0.0000000000000000, 0.4058451513773972, -0.4058451513773972, 101 | -0.7415311855993945, 0.7415311855993945, -0.9491079123427585, 102 | 0.9491079123427585] 103 | wi = [0.4179591836734694, 0.3818300505051189, 0.3818300505051189, 104 | 0.2797053914892766, 0.2797053914892766, 0.1294849661688697, 105 | 0.1294849661688697] 106 | 107 | if n == 8: 108 | xi = [-0.1834346424956498, 0.1834346424956498, -0.5255324099163290, 109 | 0.5255324099163290, -0.7966664774136267, 0.7966664774136267, 110 | -0.9602898564975363, 0.9602898564975363] 111 | wi = [0.3626837833783620, 0.3626837833783620, 0.3137066458778873, 112 | 0.3137066458778873, 0.2223810344533745, 0.2223810344533745, 113 | 0.1012285362903763, 0.1012285362903763] 114 | 115 | if n == 9: 116 | xi = [0.0000000000000000, -0.8360311073266358, 0.8360311073266358, 117 | -0.9681602395076261, 0.9681602395076261, -0.3242534234038089, 118 | 0.3242534234038089, -0.6133714327005904, 0.6133714327005904] 119 | wi = [0.3302393550012598, 0.1806481606948574, 0.1806481606948574, 120 | 0.0812743883615744, 0.0812743883615744, 0.3123470770400029, 121 | 0.3123470770400029, 0.2606106964029354, 0.2606106964029354] 122 | 123 | if n == 10: 124 | xi = [-0.1488743389816312, 0.1488743389816312, -0.4333953941292472, 125 | 0.4333953941292472, -0.6794095682990244, 0.6794095682990244, 126 | -0.8650633666889845, 0.8650633666889845, -0.9739065285171717, 127 | 0.9739065285171717] 128 | wi = [0.2955242247147529, 0.2955242247147529, 0.2692667193099963, 129 | 0.2692667193099963, 0.2190863625159820, 0.2190863625159820, 130 | 0.1494513491505806, 0.1494513491505806, 0.0666713443086881, 131 | 0.0666713443086881] 132 | 133 | if n == 11: 134 | xi = [0.0000000000000000, -0.2695431559523450, 0.2695431559523450, 135 | -0.5190961292068118, 0.5190961292068118, -0.7301520055740494, 136 | 0.7301520055740494, -0.8870625997680953, 0.8870625997680953, 137 | -0.9782286581460570, 0.9782286581460570] 138 | wi = [0.2729250867779006, 0.2628045445102467, 0.2628045445102467, 139 | 0.2331937645919905, 0.2331937645919905, 0.1862902109277343, 140 | 0.1862902109277343, 0.1255803694649046, 0.1255803694649046, 141 | 0.0556685671161737, 0.0556685671161737] 142 | 143 | if n == 12: 144 | xi = [-0.1252334085114689, 0.1252334085114689, -0.3678314989981802, 145 | 0.3678314989981802, -0.5873179542866175, 0.5873179542866175, 146 | -0.7699026741943047, 0.7699026741943047, -0.9041172563704749, 147 | 0.9041172563704749, -0.9815606342467192, 0.9815606342467192] 148 | wi = [0.2491470458134028, 0.2491470458134028, 0.2334925365383548, 149 | 0.2334925365383548, 0.2031674267230659, 0.2031674267230659, 150 | 0.1600783285433462, 0.1600783285433462, 0.1069393259953184, 151 | 0.1069393259953184, 0.0471753363865118, 0.0471753363865118] 152 | 153 | return xi, wi 154 | #******************************************************************* -------------------------------------------------------------------------------- /PHYS510 A6 Part2 Monte Carlo.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Thu Jun 27 20:48:37 2013 3 | PHYS 510, Assignment 6 Part 2 4 | """ 5 | 6 | # Monte Carlo Methods 7 | """ 8 | Part 2: Simulate a beam of particles scattering off of an arbitrary target. We will assume the 9 | beam initially moves along the x-axis. At some negative value x = -L, far from the target 10 | (at x = 0), the beam has a circular cross section with radius R. Assume the particles are 11 | uniformly distributed throughout the circle. We'll assume the momentum of the particles 12 | form a Gaussian distribution with a mean and standard deviation. As they propagate, the 13 | target exerts a force F(r) on each particle at distance r. The goal is to find the trajectory 14 | of the particles and get the position distribution of the particles when they hit a large 15 | flat detector at x = L. 16 | """ 17 | 18 | 19 | import numpy as np 20 | import matplotlib.pyplot as plt 21 | from mpl_toolkits.mplot3d import Axes3D # used for 3D plotting 22 | 23 | # Part 2 24 | # Simulate a beam of particles using the Monte Carlo Method 25 | #******************************************************************* 26 | def ParticleSim(N,m,C,L,R,Pmu,Psig,dt): 27 | 28 | # initialize trajectory plot to create 3D scatter plot of particle positions 29 | fig = plt.figure() 30 | ax = fig.add_subplot(111, projection='3d') 31 | 32 | # create random uniform distribution of values for initial y and z locations 33 | # this creates random points within the box from -R to R of N points 34 | # initial x starts at -L 35 | y00 = np.random.uniform(-R,R,N) 36 | z00 = np.random.uniform(-R,R,N) 37 | 38 | # create arrays to store initial y,z points that fall within the cross section 39 | x0 = -L 40 | y0 = [] 41 | z0 = [] 42 | 43 | # loop over initial y,z points, check if they fall within the circle of radius R 44 | # the yz-axis is in the plane of the beam cross section 45 | # only keep y,z points within the beam circular cross section 46 | Rsqr = R**2 47 | for i in range(N): 48 | if y00[i]**2 + z00[i]**2 < Rsqr: 49 | y0.append(y00[i]) 50 | z0.append(z00[i]) 51 | 52 | # define new total number of particles after keeping only those within the beam 53 | N = len(y0) 54 | 55 | # create random normal distribution of values for inital particle momentums 56 | # this uses a mean of Pmu and standard dev of Psig 57 | P0 = np.random.normal(Pmu,Psig,N) 58 | 59 | # create arrays to store final y,z values that reach the detector plate at x=L 60 | yFinal = [] 61 | zFinal = [] 62 | 63 | # loop over each of the N particles to generate new x,y,z positions of trajectory 64 | for i in range(N): 65 | # get initial x,y,z position of ith particle 66 | xp = x0 67 | yp = y0[i] 68 | zp = z0[i] 69 | 70 | # get x,y,z momentum of ith particle 71 | # initial y and z components of momentum are zero 72 | vpx = P0[i]/m 73 | vpy = 0 74 | vpz = 0 75 | 76 | # set inital time to zero 77 | t = 0 78 | 79 | # create arrays for storing x,y,z positions of particles for trajectory plot 80 | xarr = [xp] 81 | yarr = [yp] 82 | zarr = [zp] 83 | 84 | # for a single ith particle this is where the time and position stepping is 85 | # x,y,z Force is calculated at time t to update position at time t+dt 86 | # x,y,z Position in then updated for time t+dt 87 | # x,y,z Velocity is then updated for time t+dt 88 | # then time is stepped to the next t+dt 89 | # the loop continues as long as xPosition < L and xVelocity is positive 90 | # this ensures that particles deflected back are not tracked 91 | while xp < L and vpx > 0: 92 | # calcuate x,y,z force using the Coulomb force: F=kqQ/r**2 93 | Fx = (C*xp)/(xp**2 + yp**2 + zp**2)**(3.0/2.0) 94 | Fy = (C*yp)/(xp**2 + yp**2 + zp**2)**(3.0/2.0) 95 | Fz = (C*zp)/(xp**2 + yp**2 + zp**2)**(3.0/2.0) 96 | 97 | # take a time step 98 | t = t + dt 99 | 100 | # calculate x,y,z position using standard kinematic equations 101 | # x = x0 + v0t + 0.5at**2 (where a = Fx/m) 102 | # this assumes constant acceleration between t and t+dt (approximate) 103 | x = xp + vpx*t + (0.5/m)*Fx*(t**2) 104 | y = yp + vpy*t + (0.5/m)*Fy*(t**2) 105 | z = zp + vpz*t + (0.5/m)*Fz*(t**2) 106 | 107 | # calculate x,y,z velocity using v = v0 + at (where a = F/m) 108 | vx = vpx + (1.0/m)*Fx*t 109 | vy = vpy + (1.0/m)*Fy*t 110 | vz = vpz + (1.0/m)*Fz*t 111 | 112 | # store positions to arrays for trajectory plotting 113 | xarr.append(x) 114 | yarr.append(y) 115 | zarr.append(z) 116 | 117 | # update values for next iteration (prev values = new values) 118 | xp = x 119 | yp = y 120 | zp = z 121 | vpx = vx 122 | vpy = vy 123 | vpz = vz 124 | 125 | # check if particle hits detector plate and store y,z position to array if so 126 | # I had to give the plate a thickness since no particle lands exactly at x=L 127 | # this is due to a fixed time step and particles arriving at different times 128 | if L <= x <= L+5 and -L <= y <= L and -L <= z <= L: 129 | yFinal.append(y) 130 | zFinal.append(z) 131 | 132 | # plot 3D scatter of ith particle trajectory 133 | ax.scatter(xarr,yarr,zarr) 134 | 135 | # finish and show trajectory plot after all particles have been plotted 136 | # this is inside particle for loop but outside position stepping while loop 137 | plt.title('Particle Trajectories') 138 | ax.set_xlabel('x') 139 | ax.set_ylabel('y') 140 | ax.set_zlabel('z') 141 | plt.show() 142 | 143 | # plot 3D histogram after all particle trajectories have been calculated 144 | fig = plt.figure() 145 | ax = fig.add_subplot(111, projection='3d') 146 | 147 | # create 2D histogram of final y,z positions (returns arrays for plotting) 148 | hist,xedges,yedges = np.histogram2d(yFinal,zFinal,bins=10) 149 | 150 | # set plot increments 151 | elements = (len(xedges) - 1) * (len(yedges) - 1) 152 | xpos, ypos = np.meshgrid(xedges[:-1], yedges[:-1]) 153 | 154 | # using 3D bar plot for making 3D histogram of x,y,z positions 155 | # each bar needs a x,y,z position and x,y,z width 156 | # had to flatten 2D hist array to make into 1D array for plotting 157 | xpos = xpos.flatten() 158 | ypos = ypos.flatten() 159 | zpos = np.zeros(elements) 160 | dx = 15*np.ones_like(zpos) 161 | dy = 15*np.ones_like(zpos) 162 | dz = hist.flatten() 163 | 164 | # make and show 3D bar plot 165 | ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color='b', zsort='average') 166 | ax.set_title('Particle Distribution at Detector Plate') 167 | ax.set_xlabel('y') 168 | ax.set_ylabel('z') 169 | plt.show() 170 | 171 | 172 | ParticleSim(1000,1.0,1.0,100,0.1,5.0,0.5,0.01) 173 | #------------------------------------------------------------------- 174 | # N = number of particles 175 | # m = mass of particle 176 | # C = kqQ constant in Coulomb force 177 | # L = length between origin and detector plate 178 | # R = radius of particle beam cross section 179 | # Pmu = mean of Gaussian distribution describing initial particle momentum 180 | # Psig = standard dev of Gaussian distribution describing initial momentum 181 | # dt = time step 182 | #------------------------------------------------------------------- 183 | #******************************************************************* -------------------------------------------------------------------------------- /PHYS510 A5 Least Squares.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Thu Jun 20 06:14:19 2013 3 | PHYS 510, Assignment 5 4 | """ 5 | 6 | # Least Squares Fitting 7 | """ 8 | 1. Using the file 'data.txt', find the least squares approximation for polynomials 9 | of degree 1-7 and compare these techniques by plotting the variance vs. the degree 10 | of the polynomial. Determine which technique gives the best result. 11 | 2. Repeat the first problem for an exponential fit. How does the approximation 12 | in problem 1 compare to the result just found? 13 | """ 14 | 15 | 16 | import numpy as np 17 | import matplotlib.pyplot as plt 18 | import math 19 | 20 | # import sample data set "data.txt" 21 | #x, y = np.loadtxt('data.txt', skiprows=1, unpack=True) 22 | 23 | 24 | # Part 1 25 | # Least Squares fitting method for linear data 26 | #******************************************************************* 27 | def LeastSquaresFit(x,y,n): 28 | # fit model is polynomial: y = c0 + c1(x) + c2(x**2) +...+ cn(x**n) 29 | 30 | pts = len(x) # number of poins in data set 31 | polyval = [] # array to store poly fit values 32 | 33 | # if degree of polynomial is greater than number of points print error 34 | if n+1 >= pts: 35 | print 'INVALID ENTRY' 36 | print 'POLYNOMIAL DEGREE CANNOT BE GREATER THAN NUMBER OF DATA POINTS' 37 | 38 | # otherwise compute coefficients for polynomial fit 39 | # solves for coefficients using matrix solve of 'normal equations' 40 | # turns matrix equation Ax=b into 'normal equation' (A^T)Ax=(A^T)b 41 | # where b = y values, A = x values^power 42 | # this needed because system of equations is overdetermined (#equations > #unknowns) 43 | else: 44 | matrixA = np.zeros((pts,n+1)) # initialize matrix A 45 | matrixB = np.zeros((pts,1)) # initialize matrix b 46 | 47 | # loop to populate arrays 48 | for i in range(pts): 49 | matrixB[i][0] = y[i] # b gets y values 50 | 51 | for j in range(n+1): 52 | matrixA[i][j] = (x[i])**j # A gets x values^j 53 | 54 | # create normal equation (A^T)Ax=(A^T)b 55 | At = np.transpose(matrixA) # A transpose (A^T) 56 | AtA = np.dot(At,matrixA) # matrix multiply (A^T)A 57 | AtB = np.dot(At,matrixB) # matrix multiply (A^T)b 58 | 59 | coeff = np.linalg.solve(AtA,AtB) # solve normal equation (A^T)Ax=(A^T)b for x 60 | 61 | 62 | # we now have the coefficients for the polynomial fit 63 | # next plug x values back into fit model and compute new y fit values 64 | varsum = 0 65 | # loop to get y fit values and compute variance on fit 66 | for i in range(pts): 67 | yval = 0 68 | for j in range(n+1): 69 | yval = yval + coeff[j]*(x[i])**j # gets new y value for each x using fit coeffs 70 | 71 | polyval.append(yval) # collect new y values 72 | 73 | # compute variance from erorr (error=actualY-fitY) 74 | error = y[i]-yval 75 | varsum = varsum + error**2 76 | 77 | # using variance as measure for 'goodness of fit' 78 | # computed as variance = (sum of squares of errors) / (nDataPts-PolyDegree-1) 79 | variance = round(varsum/(pts-n-1), 4) 80 | 81 | 82 | # plot data set with poly fit and annotate variance 83 | plt.title('Least Squares Polynomial Fit') 84 | plt.xlabel('x') 85 | plt.ylabel('y') 86 | plt.plot(x,y,'bo', label='Data') 87 | plt.plot(x,polyval, 'r', linewidth=2, label='Order=' + str(n)) 88 | plt.annotate('Variance='+str(variance),fontsize=14,xy=(0.15,0.83),xycoords='figure fraction') 89 | plt.legend() 90 | 91 | #LeastSquaresFit(x,y,4) 92 | #------------------------------------------------------------------- 93 | # x = x data set 94 | # y = y data set 95 | # n = degree of polynomial fit 96 | #------------------------------------------------------------------- 97 | #******************************************************************* 98 | 99 | 100 | # Part 2 101 | # Gauss-Newton Exponential fitting method for nonlinear data 102 | #******************************************************************* 103 | def GaussNewtonFit(x,y,c0,c1,n): 104 | # fit model is exponential: y = c0exp(c1*x) 105 | # solves for coefficients using a matrix solve of modified 'normal equations' 106 | # turns matrix equation Ax=b into 'normal equation' (A^T)Ax=(A^T)b 107 | # where b = errors to minimize (actualY-fitY), A = numeric derivative of b 108 | # the initial guess of c0 and c1 is used to construct both b and A 109 | 110 | pts = len(x) # number of points in data set 111 | expval = [] # array to store exponential fit values 112 | 113 | # loop over specified number of iterations to update coefficients c0 and c1 114 | for k in range(n): 115 | matrixA = np.zeros((pts,2)) # initialize matrix A 116 | matrixB = np.zeros((pts,1)) # initialize matrix b 117 | 118 | # loop to populate arrays 119 | for i in range(pts): 120 | matrixB[i][0] = y[i]-c0*math.exp(c1*x[i]) # b gets residual errors y[i]-c0exp(c1*x[i]) 121 | matrixA[i][0] = math.exp(c1*x[i]) # 1st column of A gets derivative of b wrt c0 122 | matrixA[i][1] = c0*x[i]*math.exp(c1*x[i]) # 2nd column of A gets derivative of b wrt c1 123 | 124 | # create normal equation (A^T)Ax=(A^T)b 125 | At = np.transpose(matrixA) # A transpose (A^T) 126 | AtA = np.dot(At,matrixA) # matrix multiply (A^T)A 127 | AtB = np.dot(At,matrixB) # matrix multiply (A^T)b 128 | 129 | coeff = np.linalg.solve(AtA,AtB) # solve normal equation (A^T)Ax=(A^T)b for x 130 | c0 = c0 + coeff[0] # update c0 for next iteration 131 | c1 = c1 + coeff[1] # update c1 for next iteration 132 | 133 | 134 | # we now have the coefficients for the exponential fit 135 | # next plug x values back into fit model and compute new y fit values 136 | varsum = 0 137 | # loop to get y fit values and compute variance on fit 138 | for i in range(pts): 139 | yval = c0*math.exp(c1*x[i]) 140 | expval.append(yval) 141 | 142 | # compute variance from erorr (error=actualY-fitY) 143 | error = y[i] - c0*math.exp(c1*x[i]) 144 | varsum = varsum + error**2 145 | 146 | # using variance as measure for 'goodness of fit' 147 | # computed as variance = (sum of squares of errors) / (nDataPts-nFitCoefficients-1) 148 | variance = round(varsum/(pts-2-1), 4) 149 | 150 | print c0,c1 151 | 152 | # plot data set with exponential fit and annotate variance 153 | plt.title('Exponential Fit by Gauss-Newton Method') 154 | plt.xlabel('x') 155 | plt.ylabel('y') 156 | plt.plot(x,y,'bo', label='Data') 157 | plt.plot(x,expval, 'r', linewidth=2, label='Exponential') 158 | plt.annotate('Variance='+str(variance),fontsize=14,xy=(0.15,0.83),xycoords='figure fraction') 159 | plt.legend() 160 | 161 | 162 | #GaussNewtonFit(x,y,3.5,-1.5,5) 163 | #------------------------------------------------------------------- 164 | # x = x data set 165 | # y = y data set 166 | # c0 = initial first guess at coefficient c0 in y = c0exp(c1*x) 167 | # c1 = initial first guess at coefficient c1 in y = c0exp(c1*x) 168 | # n = number of iterations to converge on c0 and c1 169 | #------------------------------------------------------------------- 170 | #******************************************************************* -------------------------------------------------------------------------------- /rootFindFunctions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Thu May 30 21:01:03 2013 3 | PHYS 510, Assignment 2 Functions 4 | (Called by 'PHYS510 A2 Root Find.py' main program) 5 | """ 6 | 7 | # Root Finding 8 | """ 9 | The following functions are called for Assignment 2 in the root finding program. 10 | 1. Bisection method 11 | 2. Hybrid Bisection/Newton-Raphson method 12 | 3. Hybrid Bisection/Secant method 13 | 4. Hybrid Bisection/Muller-Brent method 14 | """ 15 | 16 | import math 17 | import sympy 18 | 19 | # 1 20 | def rootBisection(g, f, xI, xF, Tol, nMax, Mthd): 21 | # enter root finding algorithm by Bisection method 22 | #*********************************************************************** 23 | # initialize variables 24 | error = 1 25 | n = 1 26 | found = 'no' 27 | xiMid = 0 # initial midpoint value to store the n-1 value 28 | 29 | # loop until error is less than input tolerance 30 | while error > Tol: 31 | xMid = 0.5*(xI+xF) 32 | 33 | # set up main Bisection method: 34 | # make bracket interval smaller each iteration until root is found 35 | # check conditions and update bracket points 36 | if f(xI)*f(xMid) > 0: 37 | xI = xMid 38 | error = abs(xMid - xiMid) # calculate approx error 39 | n = n + 1 40 | xiMid = xMid # store the n-1 midpoint 41 | 42 | elif f(xI)*f(xMid) < 0: 43 | xF = xMid 44 | error = abs(xMid - xiMid) # calculate approx error 45 | n = n + 1 46 | xiMid = xMid # store the n-1 midpoint 47 | 48 | # break out of loop if root round 49 | else: 50 | found = 'yes' 51 | break 52 | 53 | # output results to user 54 | if found == 'yes': 55 | print 'Exact Root Found =', xMid 56 | print 'Iterations = ', n 57 | print '\n' 58 | else: 59 | print 'Approximate Root =', xMid 60 | print 'Approximate Error =', error 61 | print 'Iterations = ', n-1 62 | print '\n' 63 | 64 | # end rootBisection function 65 | #*********************************************************************** 66 | 67 | 68 | # 2 69 | def rootNewtonRaphson(g, f, xI, xF, Tol, nMax, Mthd): 70 | # enter root finding algorithm by hybrid Bisection/Newton-Raphson method 71 | #*********************************************************************** 72 | # initialize variables 73 | error = 1 74 | n = 1 75 | found = 'no' 76 | 77 | # get symbolic derivative of input function 78 | x = sympy.Symbol('x') # define x as symbolic variable 79 | sdf = sympy.diff(g, x) # get symbolic derivative of input function g 80 | df = sympy.lambdify(x, sdf) # turn symbolic derivative into numeric function 81 | 82 | # check condition for starting x value 83 | if f(xI) < f(xF): xn0 = xI 84 | else: xn0 = xF 85 | 86 | # loop until error is less than input tolerance 87 | while error > Tol: 88 | 89 | # set up main Newton-Raphson method: 90 | # use derivative of function as tangent line to get new x point 91 | # calcuate new x value from f(x) and df(x) 92 | xn1 = xn0 - (f(xn0)/df(xn0)) 93 | 94 | # if new x point is outside bracket interval then use midpoint instead 95 | if xn1 < xI or xn1 > xF: 96 | xn1 = 0.5*(xI+xF) 97 | 98 | # check conditions and update bracket points 99 | if f(xI)*f(xn1) > 0: 100 | xI = xn1 101 | 102 | elif f(xI)*f(xn1) < 0: 103 | xF = xn1 104 | 105 | error = abs(xn1 - xn0) # calculate approx error 106 | n = n + 1 107 | xn0 = xn1 # store the n-1 value for x 108 | 109 | # break out of loop if input max iterations met 110 | if n-1 >= nMax: 111 | found = 'yes' 112 | break 113 | 114 | # output results to user 115 | if found == 'yes': 116 | print 'MAXIMUM ITERATIONS EXCEEDED' 117 | print 'Approximate Root =', xn1 118 | print 'Approximate Error =', error 119 | print 'Iterations =', n-1 120 | print '\n' 121 | else: 122 | print 'Approximate Root =', xn1 123 | print 'Approximate Error =', error 124 | print 'Iterations =', n-1 125 | print '\n' 126 | 127 | # end rootNewtonRaphson function 128 | #*********************************************************************** 129 | 130 | 131 | # 3 132 | def rootSecant(g, f, xI, xF, Tol, nMax, Mthd): 133 | # enter root finding algorithm by hybrid Bisection/Secant method 134 | #*********************************************************************** 135 | # initialize variables 136 | error = 1 137 | n = 1 138 | found = 'no' 139 | 140 | # initialize starting values 141 | xn0 = xI 142 | xn1 = xF 143 | 144 | # loop until error is less than input tolerance 145 | while error > Tol: 146 | 147 | # set up main Secant method: 148 | # use secant line as linear approx to function to get new x point 149 | # calcuate new x value from secant line 150 | xn2 = xn1 - ((f(xn1)*(xn1 - xn0)) / (f(xn1) - f(xn0))) 151 | 152 | # if new x point is outside bracket then use midpoint instead 153 | if xn2 < xI or xn2 > xF: 154 | xn2 = 0.5*(xI+xF) 155 | 156 | # check conditions and update bracket points 157 | if f(xI)*f(xn2) > 0: 158 | xI = xn2 159 | 160 | elif f(xI)*f(xn2) < 0: 161 | xF = xn2 162 | 163 | error = abs(xn2 - xn1) # calculate approx error 164 | n = n + 1 165 | xn0 = xn1 # store the n-1 value for x 166 | xn1 = xn2 # store the nth value for x 167 | 168 | # break out of loop if input max iterations met 169 | if n-1 >= nMax: 170 | found = 'yes' 171 | break 172 | 173 | # output results to user 174 | if found == 'yes': 175 | print 'MAXIMUM ITERATIONS EXCEEDED' 176 | print 'Approximate Root =', xn2 177 | print 'Approximate Error =', error 178 | print 'Iterations =', n-1 179 | print '\n' 180 | else: 181 | print 'Approximate Root =', xn2 182 | print 'Approximate Error =', error 183 | print 'Iterations =', n-1 184 | print '\n' 185 | 186 | # end rootSecant function 187 | #*********************************************************************** 188 | 189 | 190 | # 4 191 | def rootMullerBrent(g, f, xI, xF, Tol, nMax, Mthd): 192 | # enter root finding algorithm by hybrid Bisection/Muller-Brent method 193 | #*********************************************************************** 194 | # initialize variables 195 | error = 1 196 | n = 1 197 | found = 'no' 198 | 199 | # initialize starting values 200 | xn0 = xI 201 | xn1 = xF 202 | # use midpoint for 3rd point for use in quadratic approx to function 203 | xn2 = 0.5*(xn0+xn1) 204 | 205 | # loop until error is less than input tolerance 206 | while error > Tol: 207 | 208 | # set up main Muller-Brent method: 209 | # use 3 points as quadratic approx to function to get new x point 210 | # first calculate a, b, c from function values at 3 known points 211 | c = f(xn2) 212 | bNumer = (((xn0-xn2)**2)*(f(xn1)-f(xn2))) - (((xn1-xn2)**2)*(f(xn0)-f(xn2))) 213 | aNumer = ((xn1-xn2)*(f(xn0)-f(xn2))) - ((xn0-xn2)*(f(xn1)-f(xn2))) 214 | Denom = (xn0-xn1)*(xn0-xn2)*(xn1-xn2) 215 | b = bNumer / Denom 216 | a = aNumer / Denom 217 | 218 | # then calculate new x value from quadratic eq 219 | # check b and use alternate quadratic eq to avoid subtractive cancellations 220 | if b >= 0: 221 | xn3 = xn2 - (2*c) / (b + math.sqrt(b**2 - 4*a*c)) 222 | else: 223 | xn3 = xn2 + (2*c) / (-b + math.sqrt(b**2 - 4*a*c)) 224 | 225 | # if new x point is outside bracket interval then use midpoint instead 226 | if xn3 < xI or xn3 > xF: 227 | xn3 = 0.5*(xI+xF) 228 | 229 | # check conditions and update bracket points 230 | if f(xI)*f(xn3) > 0: 231 | xI = xn3 232 | 233 | elif f(xI)*f(xn3) < 0: 234 | xF = xn3 235 | 236 | error = abs(xn3 - xn2) # calculate approx error 237 | n = n + 1 238 | xn0 = xn1 # store the n-1 value for x 239 | xn1 = xn2 # store the nth value for x 240 | xn2 = xn3 # store the n+1 value for x 241 | 242 | # break out of loop if input max iterations met 243 | if n-1 >= nMax: 244 | found = 'yes' 245 | break 246 | 247 | # output results to user 248 | if found == 'yes': 249 | print 'MAXIMUM ITERATIONS EXCEEDED' 250 | print 'Approximate Root =', xn3 251 | print 'Approximate Error =', error 252 | print 'Iterations =', n-1 253 | print '\n' 254 | else: 255 | print 'Approximate Root =', xn3 256 | print 'Approximate Error =', error 257 | print 'Iterations =', n-1 258 | print '\n' 259 | 260 | # end rootMullerBrent function 261 | #*********************************************************************** -------------------------------------------------------------------------------- /PHYS510 A3 Interpolation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on Tue Jun 04 17:40:50 2013 3 | PHYS 510, Assignment 3 4 | """ 5 | 6 | # Interpolation 7 | """ 8 | Below is the cross section for a resonant scattering experiment of a neutron from a nucleus 9 | ----------------------------------------------------------------------- 10 | E(MeV) | 0 | 25 | 50 | 75 | 100 | 125 | 150 | 175 | 200 | 11 | Sig(mb) | 10.6 | 16.0 | 45.0 | 83.5 | 52.8 | 19.9 | 10.8 | 8.25 | 4.7 | 12 | ----------------------------------------------------------------------- 13 | You are asked to determine values for the cross section at energies between 14 | the measured values. we assume that we don't have a theoretical model for 15 | this process and we simply want to interpolate the measured data. 16 | 17 | Complete the following tasks: 18 | 1. Use the improved Neville's algorithm to fit the entire experimental spectrum with 19 | one polynomial. This means using an eight degree polynomial to interpolated the nine 20 | data points. Use the interpolated values to plot the cross section in steps of 5 Mev. 21 | 2. A more reasonable use of interpolation algorithms is to model LOCAL behavior with a 22 | small number of data points. Redo the interpolation of the cross section data with 23 | only 3 data points at a time. Plot the resulting piece-wise smooth interpolating 24 | polynomials in 5 Mev steps. 25 | 3. Use the Cubic Spline Interpolation and repeat step 3 (use natural spline condition 26 | for the end points). 27 | 4. The actual theoretical model for this scattering process is given by the Breit-Wigner 28 | function. Compare these values with the following theoretical values: 29 | Sig0 = 6.389x10**4, Er = 78, and Gamma = 55 30 | Plot the theoretical prediction on top of the two interpolated curves 31 | """ 32 | 33 | import matplotlib.pyplot as plt 34 | import numpy as np 35 | import sympy as sym 36 | 37 | # data set to interpolate 38 | E = [0, 25, 50, 75, 100, 125, 150, 175, 200] 39 | Sig = [10.6, 16.0, 45.0, 83.5, 52.8, 19.9, 10.8, 8.25, 4.7] 40 | 41 | 42 | # Warmup 43 | # Lagrange Interpolation method 44 | #******************************************************************* 45 | def LagrangeInterp(x, y, nPoints, nxIncrement): 46 | t = sym.Symbol('t') # define symbolic variable 47 | n = range(nPoints) # index for interpolation 48 | p = 0 49 | 50 | for i in n: 51 | term = 1 52 | 53 | # Lagrange Method 54 | for j in [k for k in n if k != i]: 55 | term = term * ((t - x[j]) / (x[i] - x[j])) 56 | 57 | p = p + y[i]*term # build symbolic interpolating polynomial 58 | 59 | fInterp = sym.lambdify(t,p) # turn symbolic poly into real poly 60 | xx = np.arange(x[0], x[nPoints-1]+nxIncrement, nxIncrement) # create x interped values 61 | yy = [fInterp(z) for z in xx] # get y interped values 62 | 63 | # plot 64 | plt.figure(1) 65 | plt.title('Data Interpolation' + '\nInterpolated in 5 Mev Steps') 66 | plt.xlabel('Energy (MeV)') 67 | plt.ylabel('Cross Section (mb)') 68 | plt.plot(x,y,'bo', label='Data') 69 | plt.plot(xx,yy, label=str(nPoints)+' Pts') 70 | plt.legend() 71 | 72 | 73 | #LagrangeInterp(E,Sig,9,5) 74 | #------------------------------------------------------------------- 75 | # x = x data array 76 | # y = y data array 77 | # nPoints = number of data points to use (degree of polynomial) 78 | # nxIncrement = x axis interpolation step size 79 | #------------------------------------------------------------------- 80 | #******************************************************************* 81 | 82 | 83 | # Part 1 84 | # Neville Interpolation method 85 | #******************************************************************* 86 | def NevilleInterp(x, y, nPoints, nxIncrement): 87 | xx = np.arange(x[0], x[nPoints-1]+nxIncrement, nxIncrement) # create x interped values 88 | yy = [] # for storing y interped values 89 | 90 | for xval in xx: 91 | 92 | arry = y[0:nPoints] # get intial y values 93 | arr = np.zeros((nPoints,nPoints)) # create Neville matrix 94 | arr[0] = arry # write y values to matrix 95 | 96 | xpos = 0 97 | 98 | for i in range(nPoints - 1): 99 | xpos = xpos + 1 100 | 101 | # Neville Method & build matrix 102 | for j in range(nPoints - 1 - i): 103 | term = ((xval-x[j+xpos])*arr[i][j] - (xval-x[j])*arr[i][j+1]) / (x[j]-x[j+xpos]) 104 | arr[i+1][j] = term # build Neville matrix 105 | 106 | yy.append(term) 107 | 108 | print arr 109 | 110 | # plot 111 | plt.figure(2) 112 | plt.title('Neville Polynomial Interpolation'+'\n'+str(nPoints)+' Points Interpolated in 5 Mev Steps') 113 | plt.xlabel('Energy (MeV)') 114 | plt.ylabel('Cross Section (mb)') 115 | plt.plot(x,y,'bo', label='Data') 116 | plt.plot(xx,yy, label=str(nPoints)+' Pts') 117 | plt.legend() 118 | 119 | 120 | NevilleInterp(E,Sig,4,5) 121 | #------------------------------------------------------------------- 122 | # x = x data array 123 | # y = y data array 124 | # nPoints = number of data points to use (degree of polynomial) 125 | # nxIncrement = x axis interpolation step size 126 | #------------------------------------------------------------------- 127 | #******************************************************************* 128 | 129 | 130 | # Part 2 131 | # Lagrange Piecewise Interpolation method 132 | #******************************************************************* 133 | def LagrangeInterpPWise(x, y, nPoints, nLocal, nxIncrement): 134 | t = sym.Symbol('t') # define symbolic variable 135 | n = range(0, nPoints-nLocal+1, nLocal-1) # create x interped values 136 | 137 | xx = [] # for storing x interped values 138 | yy = [] # for storing y interped values 139 | 140 | # iterate over data points 141 | for loc in n: 142 | p = 0 143 | pts = range(loc, loc+nLocal) # define local points to iterate over 144 | 145 | # iterate over local points 146 | for i in pts: 147 | term = 1 148 | 149 | # Lagrange Method 150 | for j in [k for k in pts if k != i]: 151 | term = term * ((t - x[j]) / (x[i] - x[j])) 152 | 153 | p = p + y[i]*term # build symbolic interpolating polynomial 154 | 155 | fInterp = sym.lambdify(t,p) # turn symbolic poly into real poly 156 | xx0 = np.arange(x[loc], x[loc+nLocal-1]+nxIncrement, nxIncrement) # get local interped x values 157 | yy0 = [fInterp(z) for z in xx0] # get local interped y values 158 | # write local interped x and y values to array 159 | # NOTE: duplicate data points exist at locations where piecewise function comes together 160 | # NOTE: but since they're equal it doesn't matter 161 | xx = np.concatenate((xx,xx0)) 162 | yy = np.concatenate((yy,yy0)) 163 | 164 | 165 | # plot 166 | plt.figure(3) 167 | plt.title('Lagrange PieceWise Interpolation'+'\n'+str(nLocal)+' Point Local Interpolation in 5 Mev Steps') 168 | plt.xlabel('Energy (MeV)') 169 | plt.ylabel('Cross Section (mb)') 170 | plt.plot(x,y,'bo', label='Data') 171 | plt.plot(xx,yy, label=str(nLocal)+' Pts') 172 | plt.legend() 173 | 174 | 175 | #LagrangeInterpPWise(E,Sig,9,3,5) 176 | #------------------------------------------------------------------- 177 | # x = x data array 178 | # y = y data array 179 | # nPoints = number of data points to use (degree of polynomial) 180 | # nLocal = number of local points to use for piecewise 181 | # nxIncrement = x axis interpolation step size 182 | #------------------------------------------------------------------- 183 | #******************************************************************* 184 | 185 | 186 | # Part 3 187 | # Cubic Spline Interpolation method 188 | # NOTE: uses 'natrual spline' condition (set 2nd derivative to zero at endpoints) 189 | #******************************************************************* 190 | def CubicSpline(x, y, nPoints, nxIncrement): 191 | # start by solving for double primes to use in cubic spline equation 192 | # create matrices for Ax=b matrix solver to get values of double primes 193 | dprimesA = np.zeros((nPoints,nPoints)) # create NxN matrix A for double primes 194 | dprimesB = np.zeros((nPoints)) # create Nx1 matrix b for double primes 195 | 196 | # build matrix A and b to solve for double primes 197 | for i in range(1, nPoints-1): 198 | # build matrix A of coefficients 199 | dprimesA[i][i-1] = x[i]-x[i-1] 200 | dprimesA[i][ i ] = 2*(x[i]-x[i-1]) + 2*(x[i+1]-x[i]) 201 | dprimesA[i][i+1] = x[i+1]-x[i] 202 | # build matrix b 203 | dprimesB[i] = 6*((y[i+1]-y[i])/(x[i+1]-x[i])) - 6*((y[i]-y[i-1])/(x[i]-x[i-1])) 204 | 205 | # set endpoint values for spline 'natural condition' 206 | dprimesA[0][0] = 1 207 | dprimesA[nPoints-1][nPoints-1] = 1 208 | dprimesA[1][0] = 0 209 | 210 | # solve for double primes using matrix Ax=b solver to get x 211 | dprimesX = np.linalg.solve(dprimesA,dprimesB) 212 | 213 | #-------------------------------------------------------------- 214 | 215 | xx = [] # for storing x interped values 216 | yy = [] # for storing y interped values 217 | 218 | t = sym.Symbol('t') # define symbolic variable 219 | n = range(nPoints-1) # index for interpolation 220 | p = 0 221 | 222 | for i in n: 223 | # Cubic Spline Method 224 | p0 = y[i] 225 | p1 = (y[i+1]-y[i])/(x[i+1]-x[i]) - (x[i+1]-x[i])*dprimesX[i+1]/6 - (x[i+1]-x[i])*dprimesX[i]/3 226 | p2 = dprimesX[i]/2 227 | p3 = (dprimesX[i+1]-dprimesX[i])/(6*(x[i+1]-x[i])) 228 | 229 | # build symbolic cubic function at each point 230 | p = p0 + p1*(t-x[i]) + p2*(t-x[i])**2 + p3*(t-x[i])**3 231 | 232 | fInterp = sym.lambdify(t,p) # turn symbolic p into real p 233 | xx0 = np.arange(x[i], x[i+1]+nxIncrement, nxIncrement) # get interped values from x(i) to x(i+1) 234 | yy0 = [fInterp(z) for z in xx0] # get interped y values 235 | # write local interped x and y values to array 236 | # NOTE: duplicate data points exist at locations where piecewise function comes together 237 | # NOTE: but since they're equal it doesn't matter 238 | xx = np.concatenate((xx,xx0)) 239 | yy = np.concatenate((yy,yy0)) 240 | 241 | # plot 242 | plt.figure(4) 243 | plt.title('Cubic Spline Interpolation'+'\n'+ 'Interpolated in 5 Mev Steps') 244 | plt.xlabel('Energy (MeV)') 245 | plt.ylabel('Cross Section (mb)') 246 | plt.plot(x,y,'bo', label='Data') 247 | plt.plot(xx,yy, label='Cubic Spline') 248 | plt.legend() 249 | 250 | 251 | #CubicSpline(E,Sig,9,5) 252 | #------------------------------------------------------------------- 253 | # x = x data array 254 | # y = y data array 255 | # nPoints = number of data points to use 256 | # nxIncrement = x axis interpolation step size 257 | #------------------------------------------------------------------- 258 | #******************************************************************* --------------------------------------------------------------------------------