def go(v0): def f(R): return R * (vy + g / b) / vx + g * np.log(1 - b * R / vx) / (b**b) def df(R): return (vy + g / b) / vx - g / (b * (1 - b * R / vx) * vx) g, b = 9.8, 1.0 x, yb, yn, dtr = [], [], [], np.pi / 180 for theta in range(1, 90): vx, vy = v0 * np.cos(theta * dtr), v0 * np.sin(theta * dtr) Rb = rtf.bisect(f, 0.01, vx / b - 1e-5, 1e-6) Rn = rtf.newton(f, df, vx / b - 1e-5) if (Rb != None and Rn != None): x.append(theta) yb.append(Rb) yn.append(Rn) plt.figure() plt.plot(x, yb, label='Bisection method', zorder=-1) plt.plot(x, yn, 'r.', label='Newton Method') plt.xlabel('angle (deg)') plt.ylabel('R (m)') plt.legend(loc='best') plt.title('v0 = {0}'.format(v0)) plt.show()
# # Program 3.3: Range vs. angle (range.py) # J Wang, Computational modeling and visualization with Python # import rootfinder as rtf, math as ma # get root finders, math import matplotlib.pyplot as plt # get matplotlib plot functions def f(R): # range function, return R*(vy+g/b)/vx + g*ma.log(1.-b*R/vx)/(b*b) g, b, v0 = 9.8, 1.0, 100. # g, linear coeff., firing speed x, y, dtr = [], [], ma.pi/180. # temp arrays, deg-to-rad conv for theta in range(1,90): vx, vy = v0*ma.cos(theta*dtr), v0*ma.sin(theta*dtr) # init vel R = rtf.bisect(f, 0.01, vx/b-1.e-5, 1.e-6) # solve if (R != None): x.append(theta), y.append(R) plt.figure() # open fig, plot, label, show fig plt.plot(x, y), plt.xlabel('angle (deg)'), plt.ylabel('R (m)') plt.show()
E = En wfup, psiup = intsch([0., .1], N, xL, h) # march upward wfdn, psidn = intsch([0., .1], N, xR, -h) # march downward return psidn[0] * psiup[1] - psiup[0] * psidn[1] a, b, V0 = 4.0, 1.0, 6. # double well widths, depth xL, xR, N = -4 * a, 4 * a, 500 # limits, intervals xa = np.linspace(xL, xR, 2 * N + 1) # grid h, M = xa[1] - xa[0], 2 # step size, M=matching point E1, dE, j = -V0, 0.01, 1 plt.figure() while (E1 < 0): # find E, calc and plot wave function if (shoot(E1) * shoot(E1 + dE) < 0): # bracket E E = rtf.bisect(shoot, E1, E1 + dE, 1.e-8) print('Energy found: %.3f' % (E)) wfup, psiup = intsch([0., .1], N + M, xL, h) # compute WF wfdn, psidn = intsch([0., .1], N - M, xR, -h) psix = np.concatenate((wfup[:-1], wfdn[::-1])) # combine WF scale = psiup[0] / psidn[0] psix[N + M:] *= scale # match WF ax = plt.subplot(2, 2, j) ax.plot(xa, psix / max(psix)) # plot WF ax.plot(xa, np.vectorize(V)(xa) / (2 * V0)) # overlay V ax.set_xlim(-a, a) ax.text(2.2, 0.7, '%.3f' % (E)) if (j == 1 or j == 3): ax.set_ylabel(r'$\psi$') if (j == 3 or j == 4): ax.set_xlabel('$x$') if (j < 4): j += 1 # 4 plots max E1 += dE
global E # global E, needed in sch() E = En wfup, psiup = intsch([0., .1], N, xL, h) # march upward wfdn, psidn = intsch([0., .1], N, xR, -h) # march downward return psidn[0]*psiup[1] - psiup[0]*psidn[1] a, b, V0 = 4.0, 1.0, 6. # double well widths, depth xL, xR, N = -4*a, 4*a, 500 # limits, intervals xa = np.linspace(xL, xR, 2*N+1) # grid h, M = xa[1]-xa[0], 2 # step size, M=matching point E1, dE, j = -V0, 0.01, 1 plt.figure() while (E1 < 0): # find E, calc and plot wave function if (shoot(E1) * shoot(E1 + dE) < 0): # bracket E E = rtf.bisect(shoot, E1, E1 + dE, 1.e-8) print ('Energy found: %.3f' %(E)) wfup, psiup = intsch([0., .1], N+M, xL, h) # compute WF wfdn, psidn = intsch([0., .1], N-M, xR, -h) psix = np.concatenate((wfup[:-1], wfdn[::-1])) # combine WF scale = psiup[0]/psidn[0] psix[N+M:] *= scale # match WF ax = plt.subplot(2,2,j) ax.plot(xa, psix/max(psix)) # plot WF ax.plot(xa, np.vectorize(V)(xa)/(2*V0)) # overlay V ax.set_xlim(-a,a) ax.text(2.2,0.7, '%.3f' %(E)) if (j == 1 or j == 3): ax.set_ylabel(r'$\psi$') if (j == 3 or j == 4): ax.set_xlabel('$x$') if (j<4): j += 1 # 4 plots max E1 += dE
import rootfinder as rtf from scipy.optimize import fsolve def f(x): return 5*x - x**3 def df(x): return 5 - 3*x**2 a, b = -2, 2 bs = rtf.bisect(f, a, b) nt = rtf.newton(f, df, a) print(bs) print(nt) x = fsolve(f, -2) print(x)
# # Program 3.5: Shooting method (shoot.py) # J Wang, Computational modeling and visualization with Python # from __future__ import print_function # use print() as function import ode, rootfinder as rtf, numpy as np # ode, root solvers, numpy def proj(Y, t): # ideal projectile motion return np.array([Y[2],Y[3], 0.0,-g]) # [vx,vy,ax,ay] def fy(theta): # return f as a func of theta Y = [0., 0., v0*np.cos(theta), v0*np.sin(theta)] # [x,y,vx,vy] t = xb / Y[2] # Step 1: time to xb h = t / nsteps for i in range(nsteps): Y = ode.RK2(proj, Y, t, h) # no need to update t return Y[1] - yb # Step 2: $y(\theta) - y_b$ # number of steps, g, init speed, x and y boundary values nsteps, g, v0, xb, yb = 100, 9.8, 22., 40., 3. # para. theta = rtf.bisect(fy, 0.6, 1.2, 1.e-6) # Step 3: shoot for $\theta$ if (theta != None): print('theta(deg)=',theta*180/np.pi) # result
# # Program 3.5: Shooting method (shoot.py) # J Wang, Computational modeling and visualization with Python # from __future__ import print_function # use print() as function import ode, rootfinder as rtf, numpy as np # ode, root solvers, numpy def proj(Y, t): # ideal projectile motion return np.array([Y[2], Y[3], 0.0, -g]) # [vx,vy,ax,ay] def fy(theta): # return f as a func of theta Y = [0., 0., v0 * np.cos(theta), v0 * np.sin(theta)] # [x,y,vx,vy] t = xb / Y[2] # Step 1: time to xb h = t / nsteps for i in range(nsteps): Y = ode.RK2(proj, Y, t, h) # no need to update t return Y[1] - yb # Step 2: $y(\theta) - y_b$ # number of steps, g, init speed, x and y boundary values nsteps, g, v0, xb, yb = 100, 9.8, 22., 40., 3. # para. theta = rtf.bisect(fy, 0.6, 1.2, 1.e-6) # Step 3: shoot for $\theta$ if (theta != None): print('theta(deg)=', theta * 180 / np.pi) # result
def xection(theta, ba, da): # cross section cs = 0.0 # ba=impact para, da=deflection angle for i in range(len(ba) - 1): if ((theta - da[i]) * (theta - da[i + 1]) < 0.): # theta bracketed db = ba[i + 1] - ba[i] cs += (ba[i] + db / 2.) * abs(db / (da[i + 1] - da[i])) return cs / np.sin(theta) Z, R = 1.0, 1.0 # nuclear charge Z, radius of plum potential E, b, bmax = 1.2, 0.01, 20. # energy, initial b, bmax eps, tiny = 1.E-14, 1.E-5 # rel error, u-limit ba, theta = [], [] # impact para, deflection while (b <= bmax): umin = rtf.bisect(fu, tiny, 1. / b, eps) # find turning pt alpha = itg.gauss(fx, 0., np.sqrt(umin)) ba.append(b), theta.append(np.pi - 2 * alpha) b *= 1.02 plt.figure(), plt.plot(ba, theta) # plot deflection function plt.xlabel('$b$ (a.u.)'), plt.ylabel('$\Theta$', rotation=0) plt.yticks([0, np.pi / 2, np.pi], ['$0$', '$\pi/2$', '$\pi$']) plt.xlim(0, 3) cs, sa = [], np.linspace(0.01, np.pi - .01, 500) # scattering angle for x in sa: # calc, plot cross section cs.append(xection(x, ba, theta)) plt.figure(), plt.plot(sa, cs) plt.xlabel(r'$\theta$'), plt.ylabel(r'$\sigma(\theta)$') plt.xticks([0, np.pi / 2, np.pi], ['$0$', '$\pi/2$', '$\pi$'])
return 2*x*b/np.sqrt(fu(u)) def xection(theta, ba, da): # cross section cs = 0.0 # ba=impact para, da=deflection angle for i in range(len(ba)-1): if ((theta-da[i])*(theta-da[i+1]) < 0.): # theta bracketed db = ba[i+1] - ba[i] cs += (ba[i] + db/2.)*abs(db/(da[i+1]-da[i])) return cs/np.sin(theta) Z, R = 1.0, 1.0 # nuclear charge Z, radius of plum potential E, b, bmax = 1.2, 0.01, 20. # energy, initial b, bmax eps, tiny =1.E-14, 1.E-5 # rel error, u-limit ba, theta = [], [] # impact para, deflection while (b <= bmax): umin = rtf.bisect(fu, tiny, 1./b, eps) # find turning pt alpha = itg.gauss(fx, 0., np.sqrt(umin)) ba.append(b), theta.append(np.pi - 2*alpha) b *= 1.02 plt.figure(), plt.plot(ba, theta) # plot deflection function plt.xlabel('$b$ (a.u.)'), plt.ylabel('$\Theta$', rotation=0) plt.yticks([0, np.pi/2, np.pi], ['$0$','$\pi/2$', '$\pi$']) plt.xlim(0,3) cs, sa = [], np.linspace(0.01, np.pi-.01, 500) # scattering angle for x in sa: # calc, plot cross section cs.append(xection(x, ba, theta)) plt.figure(), plt.plot(sa, cs) plt.xlabel(r'$\theta$'), plt.ylabel(r'$\sigma(\theta)$') plt.xticks([0, np.pi/2, np.pi], ['$0$','$\pi/2$', '$\pi$'])