## module euler ''' X,Y = integrate(F,x,y,xStop,h). Euler's method for solving the initial value problem {y}' = {F(x,{y})}, where {y} = {y[0],y[1],...y[n-1]}. x,y = initial conditions xStop = terminal value of x h = increment of x used in integration F = user-supplied function that returns the array F(x,y) = {y'[0],y'[1],...,y'[n-1]}. ''' import numpy as np def integrate(F,x,y,xStop,h): X = [] Y = [] X.append(x) Y.append(y) while x < xStop: h = min(h,xStop - x) y = y + h*F(x,y) x = x + h X.append(x) Y.append(y) return np.array(X),np.array(Y)
## module printSoln ''' printSoln(X,Y,freq). Prints X and Y returned from the differential equation solvers using printput frequency 'freq'. freq = n prints every nth step. freq = 0 prints initial and final values only. ''' def printSoln(X,Y,freq): def printHead(n): print("\n x ",end=" ") for i in range (n): print(" y[",i,"] ",end=" ") print() def printLine(x,y,n): print("{:13.4e}".format(x),end=" ") for i in range (n): print("{:13.4e}".format(y[i]),end=" ") print() m = len(Y) try: n = len(Y[0]) except TypeError: n = 1 if freq == 0: freq = m printHead(n) for i in range(0,m,freq): printLine(X[i],Y[i],n) if i != m - 1: printLine(X[m - 1],Y[m - 1],n)
Integrate the initial value problem $$ {y}''=-0.1{y}'-x \:\:\:\:\:\:\: y(0)=0 \:\:\:\:\:\:\:{y}'(0)=1 $$ from x = 0 to 2 with Euler’s method using h = 0.05. Plot the computed y together with the analytical solution, \( y=100x-5x^{2}+990(e^{-0.1x}-1) \)
import numpy as np from euler import * import matplotlib.pyplot as plt def F(x,y): F = np.zeros(2) F[0] = y[1] F[1] = -0.1*y[1] - x return F x = 0.0 # Start of integration xStop = 2.0 # End of integration y = np.array([0.0, 1.0]) # Initial values of {y} h = 0.05 # Step size X,Y = integrate(F,x,y,xStop,h) yExact = 100.0*X - 5.0*X**2 + 990.0*(np.exp(-0.1*X) - 1.0) plt.plot(X,Y[:,0],'o',X,yExact,'-') plt.grid(True) plt.xlabel('x'); plt.ylabel('y') plt.legend(('Numerical','Exact'),loc=0) plt.show() input("Press return to exit")
## module run_kut4 ''' X,Y = integrate(F,x,y,xStop,h). 4th-order Runge-Kutta method for solving the initial value problem {y}' = {F(x,{y})}, where {y} = {y[0],y[1],...y[n-1]}. x,y = initial conditions xStop = terminal value of x h = increment of x used in integration F = user-supplied function that returns the array F(x,y) = {y'[0],y'[1],...,y'[n-1]}. ''' import numpy as np def integrate(F,x,y,xStop,h): def run_kut4(F,x,y,h): K0 = h*F(x,y) K1 = h*F(x + h/2.0, y + K0/2.0) K2 = h*F(x + h/2.0, y + K1/2.0) K3 = h*F(x + h, y + K2) return (K0 + 2.0*K1 + 2.0*K2 + K3)/6.0 X = [] Y = [] X.append(x) Y.append(y) while x < xStop: h = min(h,xStop - x) y = y + run_kut4(F,x,y,h) x = x + h X.append(x) Y.append(y) return np.array(X),np.array(Y)
Integrate the initial value problem $$ {y}''=-0.1{y}'-x \:\:\:\:\:\:\: y(0)=0 \:\:\:\:\:\:\:{y}'(0)=1 $$ with the fourth-order Runge-Kutta method from x = 0 to 2 in increments of h = 0.2. Plot the computed y together with the analytical solution, \( y=100x-5x^{2}+990(e^{-0.1x}-1) \)
Solution: Letting y0 = y and y1 = y', the equivalent first-order equations are $$F(x,y)=\begin{bmatrix} {y}_{0}'\\ {y}_{1}' \end{bmatrix} = \begin{bmatrix} y_{1}\\ -0.1y_{1}-x \end{bmatrix}$$
import numpy as np from printSoln import * from run_kut4 import * import matplotlib.pyplot as plt def F(x,y): F = np.zeros(2) F[0] = y[1] F[1] = -0.1*y[1] - x return F x = 0.0 # Start of integration xStop = 2.0 # End of integration y = np.array([0.0, 1.0]) # Initial values of {y} h = 0.2 # Step size X,Y = integrate(F,x,y,xStop,h) yExact = 100.0*X - 5.0*X**2 + 990.0*(np.exp(-0.1*X) - 1.0) plt.plot(X,Y[:,0],'o',X,yExact,'-') plt.grid(True) plt.xlabel('x'); plt.ylabel('y') plt.legend(('Numerical','Exact'),loc=0) plt.show() input("Press return to exit"))
Use the fourth-order Runge-Kutta method to integrate $$ {y}'=3y-4e^{-x} \;\;\;\;\; y(0)=1 $$ from x = 0 to 10 in steps of h = 0.1. Compare the result with the analytical solution \( y=e^{-x} \)
## example7_5 import numpy as np from run_kut4 import * from printSoln import * from math import exp def F(x,y): F = np.zeros(1) F[0] = 3.0*y[0] - 4.0*exp(-x) return F x = 0.0 # Start of integration xStop = 10.0 # End of integration y = np.array([1.0]) # Initial values of {y} h = 0.1 # Step size freq = 20 # Printout frequency X,Y = integrate(F,x,y,xStop,h) printSoln(X,Y,freq) input("\nPress return to exit")
Example7_6: A spacecraft is launched at the altitude H = 772 km above sea level with the speed v0 = 6700 m/s in the direction shown.
The differential equations describing the motion
of the spacecraft are
$$ \ddot{r}=r\dot{\theta }^{2}-\frac{GM_{e}}{r^{2}} \;\;\;\;\; \ddot{\theta }=-\frac{2\dot{r\dot{\theta }}}{r}$$
where r and θ are the polar coordinates of the spacecraft. The constants involved in
the motion are
G = 6.672 × 10−11 m3 kg−1s−2 = universal gravitational constant
Me = 5.9742 × 1024 kg = mass of the earth
Re = 6378.14 km = radius of the earth at sea level
(1) Derive the first-order differential equations and the initial conditions of the form
y' = F(t, y), y(0) = b.
(2) Use the fourth-order Runge-Kutta method to integrate the
equations from the time of launch until the spacecraft hits the earth. Determine θ at
the impact site
Solution:
## example7_6 import numpy as np from run_kut4 import * from printSoln import * def F(x,y): F = np.zeros(4) F[0] = y[1] F[1] = y[0]*(y[3]**2) - 3.9860e14/(y[0]**2) F[2] = y[3] F[3] = -2.0*y[1]*y[3]/y[0] return F x = 0.0 xStop = 1200.0 y = np.array([7.15014e6, 0.0, 0.0, 0.937045e-3]) h = 50.0 freq = 2 X,Y = integrate(F,x,y,xStop,h) printSoln(X,Y,freq) input("\nPress return to exit")
## module run_kut5 ''' X,Y = integrate(F,x,y,xStop,h,tol=1.0e-6). Adaptive Runge-Kutta method with Dormand-Price coefficients for solving the initial value problem {y}' = {F(x,{y})}, where {y} = {y[0],y[1],...y[n-1]}. x,y = initial conditions xStop = terminal value of x h = initial increment of x used in integration tol = per-step error tolerance F = user-supplied function that returns the array F(x,y) = {y'[0],y'[1],...,y'[n-1]}. ''' import math import numpy as np def integrate(F,x,y,xStop,h,tol=1.0e-6): a1 = 0.2; a2 = 0.3; a3 = 0.8; a4 = 8/9; a5 = 1.0 a6 = 1.0 c0 = 35/384; c2 = 500/1113; c3 = 125/192 c4 = -2187/6784; c5 = 11/84 d0 = 5179/57600; d2 = 7571/16695; d3 = 393/640 d4 = -92097/339200; d5 = 187/2100; d6 = 1/40 b10 = 0.2 b20 = 0.075; b21 = 0.225 b30 = 44/45; b31 = -56/15; b32 = 32/9 b40 = 19372/6561; b41 = -25360/2187; b42 = 64448/6561 b43 = -212/729 b50 = 9017/3168; b51 =-355/33; b52 = 46732/5247 b53 = 49/176; b54 = -5103/18656 b60 = 35/384; b62 = 500/1113; b63 = 125/192; b64 = -2187/6784; b65 = 11/84 X = [] Y = [] X.append(x) Y.append(y) stopper = 0 # Integration stopper(0 = off, 1 = on) k0 = h*F(x,y) for i in range(10000): k1 = h*F(x + a1*h, y + b10*k0) k2 = h*F(x + a2*h, y + b20*k0 + b21*k1) k3 = h*F(x + a3*h, y + b30*k0 + b31*k1 + b32*k2) k4 = h*F(x + a4*h, y + b40*k0 + b41*k1 + b42*k2 + b43*k3) k5 = h*F(x + a5*h, y + b50*k0 + b51*k1 + b52*k2 + b53*k3 \ + b54*k4) k6 = h*F(x + a6*h, y + b60*k0 + b62*k2 + b63*k3 + b64*k4 \ + b65*k5) dy = c0*k0 + c2*k2 + c3*k3 + c4*k4 + c5*k5 E = (c0 - d0)*k0 + (c2 - d2)*k2 + (c3 - d3)*k3 \ + (c4 - d4)*k4 + (c5 - d5)*k5 - d6*k6 e = math.sqrt(np.sum(E**2)/len(y)) hNext = 0.9*h*(tol/e)**0.2 # Accept integration step if error e is within tolerance if e <= tol: y = y + dy x = x + h X.append(x) Y.append(y) if stopper == 1: break # Reached end of x-range if abs(hNext) > 10.0*abs(h): hNext = 10.0*h # Check if next step is the last one; if so, adjust h if (h > 0.0) == ((x + hNext) >= xStop): hNext = xStop - x stopper = 1 k0 = k6*hNext/h else: if abs(hNext) < 0.1*abs(h): hNext = 0.1*h k0 = k0*hNext/h h = hNext return np.array(X),np.array(Y)
The aerodynamic drag force acting on a certain object in free fall can be approximated
by
\( F_{D}=av^{2}e^{-by} \)
where
v = velocity of the object in m/s
y = elevation of the object in meters
a = 7.45 kg/m
b = 10.53 × 10−5 m−1
The exponential term accounts for the change of air density with elevation. The differential
equation describing the fall is
where g = 9.806 65 m/s2 and m = 114 kg is the mass of the object. If the object is
released at an elevation of 9 km, determine its elevation and speed after a 10-s fall
with the adaptive Runge-Kutta method.
Solution:
## example7_8 import numpy as np import math from run_kut5 import * from printSoln import * def F(x,y): F = np.zeros(2) F[0] = y[1] F[1] = -9.80665 + 65.351e-3 * y[1]**2 * math.exp(-10.53e-5*y[0]) return F x = 0.0 xStop = 10.0 y = np.array([9000, 0.0]) h = 0.5 freq = 1 X,Y = integrate(F,x,y,xStop,h,1.0e-2) printSoln(X,Y,freq) input("\nPress return to exit")
Integrate the moderately stiff problem
y'' = −19/4y − 10y' y(0) = −9 y'(0) = 0
from x = 0 to 10 with the adaptive Runge-Kutta method and plot the results
Solution:
## example7_9 import numpy as np import matplotlib.pyplot as plt from run_kut5 import * from printSoln import * def F(x,y): F = np.zeros(2) F[0] = y[1] F[1] = -4.75*y[0] - 10.0*y[1] return F x = 0.0 xStop = 10.0 y = np.array([-9.0, 0.0]) h = 0.1 freq = 4 X,Y = integrate(F,x,y,xStop,h) printSoln(X,Y,freq) plt.plot(X,Y[:,0],'o-',X,Y[:,1],'ˆ-') plt.xlabel('x') plt.legend(('y','dy/dx'),loc=0) plt.grid(True) plt.show() input("\nPress return to exit")
## module midpoint ''' yStop = integrate (F,x,y,xStop,tol=1.0e-6) Modified midpoint method for solving the initial value problem y' = F(x,y}. x,y = initial conditions xStop = terminal value of x yStop = y(xStop) F = user-supplied function that returns the array F(x,y) = {y'[0],y'[1],...,y'[n-1]}. ''' import numpy as np import math def integrate(F,x,y,xStop,tol): def midpoint(F,x,y,xStop,nSteps): # Midpoint formulas h = (xStop - x)/nSteps y0 = y y1 = y0 + h*F(x,y0) for i in range(nSteps-1): x = x + h y2 = y0 + 2.0*h*F(x,y1) y0 = y1 y1 = y2 return 0.5*(y1 + y0 + h*F(x,y2)) def richardson(r,k): # Richardson's extrapolation for j in range(k-1,0,-1): const = (k/(k - 1.0))**(2.0*(k-j)) r[j] = (const*r[j+1] - r[j])/(const - 1.0) return kMax = 51 n = len(y) r = np.zeros((kMax,n)) # Start with two integration steps nSteps = 2 r[1] = midpoint(F,x,y,xStop,nSteps) r_old = r[1].copy() # Increase the number of integration points by 2 # and refine result by Richardson extrapolation for k in range(2,kMax): nSteps = 2*k r[k] = midpoint(F,x,y,xStop,nSteps) richardson(r,k) # Compute RMS change in solution e = math.sqrt(np.sum((r[1] - r_old)**2)/n) # Check for convergence if e < tol: return r[1] r_old = r[1].copy() print("Midpoint method did not converge")
## module bulStoer ''' X,Y = bulStoer(F,x,y,xStop,H,tol=1.0e-6). Simplified Bulirsch-Stoer method for solving the initial value problem {y}' = {F(x,{y})}, where {y} = {y[0],y[1],...y[n-1]}. x,y = initial conditions xStop = terminal value of x H = increment of x at which results are stored F = user-supplied function that returns the array F(x,y) = {y'[0],y'[1],...,y'[n-1]}. ''' import numpy as np from midpoint import * def bulStoer(F,x,y,xStop,H,tol=1.0e-6): X = [] Y = [] X.append(x) Y.append(y) while x < xStop: H = min(H,xStop - x) y = integrate(F,x,y,x + H,tol) # Midpoint method x = x + H X.append(x) Y.append(y) return np.array(X),np.array(Y)
The differential equations governing the loop current i and the charge q on the capacitor
of the electric circuit shown below are:
Ldi/dt+ Ri + q/C = E(t ) dq/dt= i
If the applied voltage E is suddenly increased from zero to 9 V, plot the resulting loop
current during the first 10 s.
Use R = 1.0 Ω, L = 2 H, and C = 0.45 F.
We solved the problem with the function bulStoer with the increment H = 0.25 s
Solution:
from bulStoer import * import numpy as np import matplotlib.pyplot as plt def F(x,y): F = np.zeros(2) F[0] = y[1] F[1] =(-y[1] - y[0]/0.45 + 9.0)/2.0 return F H = 0.25 xStop = 10.0 x = 0.0 y = np.array([0.0, 0.0]) X,Y = bulStoer(F,x,y,xStop,H) plt.plot(X,Y[:,1],'o-') plt.xlabel('Time (s)') plt.ylabel('Current (A)') plt.grid(True) plt.show() input("\nPress return to exit")