Timothy Sauer版《数值分析》学习笔记+python实现——《常微分方程》(V)【完】

Ordinary Differential Equation

Import package

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
plt.rc("font", family="Times New Roman")
from tqdm import tqdm
import imageio
from mpl_toolkits.mplot3d import Axes3D

Finite difference method

Differential approximation:

y ′ ( t ) ≈ y ( t + h ) − y ( t − h ) 2 h y^{\prime}\left( t \right) \approx \frac{y\left( t+h \right) -y\left( t-h \right)}{2h} y(t)2hy(t+h)y(th)
y ′ ′ ( t ) ≈ y ( t + h ) − 2 y ( t ) + y ( t − h ) h 2 y^{''}\left( t \right) \approx \frac{y\left( t+h \right) -2y\left( t \right) +y\left( t-h \right)}{h^2} y′′(t)h2y(t+h)2y(t)+y(th)
For boundary value problems (BVP):
{ y ′ ′ = 4 y y ( 0 ) = 1 y ( 1 ) = 3 \begin{cases} y^{''}=4y\\ y\left( 0 \right) =1\\ y\left( 1 \right) =3\\ \end{cases} y′′=4yy(0)=1y(1)=3

Linear BVP

The differential form of this ODE system is:
ω i + 1 − 2 ω i + ω i − 1 h 2 − 4 ω i = 0 ⟹ ω i − 1 + ( − 4 h 2 − 2 ) ω i + ω i + 1 = 0 \frac{\omega _{i+1}-2\omega _i+\omega _{i-1}}{h^2}-4\omega _i=0\Longrightarrow \omega _{i-1}+\left( -4h^2-2 \right) \omega _i+\omega _{i+1}=0 h2ωi+12ωi+ωi14ωi=0ωi1+(4h22)ωi+ωi+1=0
For the n-step Iterative method, n linear equations can be formed as follows:
( − 4 h 2 − 2 1 0 ⋯ ⋯ ⋯ 0 1 − 4 h 2 − 2 1 0 ⋯ ⋯ 0 0 1 − 4 h 2 − 2 1 0 ⋯ 0 0 0 ⋱ ⋱ ⋱ 0 0 ⋮ ⋮ 0 1 − 4 h 2 − 2 1 0 ⋮ ⋮ ⋮ 0 1 − 4 h 2 − 2 1 0 0 0 0 0 1 − 4 h 2 − 2 ) ( ω 1 ω 2 ω 3 ⋮ ω n − 2 ω n − 1 ω n ) = ( − 1 0 0 ⋮ 0 0 − 3 ) \left( \begin{matrix}{} -4h^2-2& 1& 0& \cdots& \cdots& \cdots& 0\\ 1& -4h^2-2& 1& 0& \cdots& \cdots& 0\\ 0& 1& -4h^2-2& 1& 0& \cdots& 0\\ 0& 0& \ddots& \ddots& \ddots& 0& 0\\ \vdots& \vdots& 0& 1& -4h^2-2& 1& 0\\ \vdots& \vdots& \vdots& 0& 1& -4h^2-2& 1\\ 0& 0& 0& 0& 0& 1& -4h^2-2\\ \end{matrix} \right) \left( \begin{array}{l} \omega _1\\ \omega _2\\ \omega _3\\ \vdots\\ \omega _{n-2}\\ \omega _{n-1}\\ \omega _n\\ \end{array} \right) =\left( \begin{array}{l} -1\\ 0\\ 0\\ \vdots\\ 0\\ 0\\ -3\\ \end{array} \right) 4h22100014h22100014h22000110004h2210014h2210000014h22 ω1ω2ω3ωn2ωn1ωn = 100003
Please note the appearance of boundary values, and h = ( b − a ) / ( n + 1 ) h=(b-a)/(n+1) h=(ba)/(n+1), then solve this equation groups to get: ω 0 = 1 , ω 1 , … , ω n , ω n + 1 = 3 \omega_{0}=1, \omega_{1}, \dots, \omega_{n}, \omega_{n+1}=3 ω0=1,ω1,,ωn,ωn+1=3

# Conjugate Gradient method to solve linear equation group
def ConjugateGradient(matrix, base):
    n = len(matrix)
    x = np.array([0] * n, dtype=float)
    print("x0 = ", x.T.round(4))
    x = np.transpose([x])
    d = r = base - np.dot(matrix, x)
    rT = np.transpose(r)  # col -> row
    dT = np.transpose(d)
    for i in range(10000):
        if np.linalg.norm(r, 2) < 1e-4:
            print("Find solution: ", x.T.round(4))
            break
        rTr = np.dot(rT, r)[0, 0]  
        alpha = rTr/(np.dot(dT, np.dot(matrix, d))[0, 0])
        x = x + np.dot(alpha, d)
        print("x{} = ".format(i + 1), x.T.round(4))
        r = r - np.dot(alpha, np.dot(matrix, d))
        rT = np.transpose(r)
        beta = np.dot(rT, r)[0, 0]/rTr
        d = r + beta * d
        dT = np.transpose(d)
    return x

def func(t):  # analytical solution 
    return (3 - np.power(np.e, -2))/(np.power(np.e, 2) - np.power(np.e, -2)) * np.exp(2 * t) + (np.power(np.e, 2) - 3)/(np.power(np.e, 2) - np.power(np.e, -2)) * np.exp(-2 * t)
n_step = 10
step_h = (1.0 - 0.0)/(n_step + 1)
b_value1, b_value2 = 1.0, 3.0  # boundary value: y(0) = 1.0, y(1) = 3.0

coefficient_matrix = np.array([-4 * np.power(step_h, 2) - 2, 1] + [0] * (n_step - 2))
for i in range(1, n_step - 1):
    coefficient_matrix = np.vstack((coefficient_matrix, np.array([0] * (i - 1) + [1, -4 * np.power(step_h, 2) - 2, 1] + [0] * (n_step - 3 - (i - 1)))))
coefficient_matrix = np.vstack((coefficient_matrix, np.array([0] * (n_step - 2) + [1, -4 * np.power(step_h, 2) - 2])))
base = np.transpose([np.array([-1] + [0] * (n_step - 2) + [-3])])
omega = np.hstack((np.array([b_value1]), np.transpose(ConjugateGradient(coefficient_matrix, base)).squeeze(), np.array([b_value2])))

# plot:
plt.rcParams['xtick.direction'] = "in"  # ticks direction
plt.rcParams['ytick.direction'] = "in" 
axes=plt.gca()
axes.yaxis.set_major_locator(MaxNLocator(5))  # ticks num
axes.xaxis.set_major_locator(MaxNLocator(5))
plt.xticks(fontsize=20, fontweight="bold")  # ticks font
plt.yticks(fontsize=20, fontweight="bold")  
plt.xlabel("T", fontsize=22, fontweight="bold")
plt.ylabel("Y", fontsize=22, fontweight="bold")
plt.title("Finite difference method, n = 10", fontsize=24, fontweight="bold")
plt.scatter(np.linspace(0, 1, 12), func(np.linspace(0, 1, 12)), color="red", marker='o', s=100, label="Y")
plt.plot(np.linspace(0, 1, 100), func(np.linspace(0, 1, 100)), color="red", linewidth=3)
plt.scatter(np.linspace(0, 1, 12), omega, color="blue", marker='*', s=150, label="Omega")
# set legend:
legend_font = {
    "family": "Times New Roman", 
    "style" : "normal",
    "size" : 20, 
    'weight': "bold"
}
plt.legend(
    bbox_to_anchor=(0.95, 0), loc="lower right", 
    frameon=False, prop=legend_font
)
plt.show()

在这里插入图片描述

Non-linear BVP

{ y ′ ′ = y ′ + cos ⁡ y y ( 0 ) = 0 y ( π ) = 1 \begin{cases} y^{''}=y^{\prime}+\cos y\\ y\left( 0 \right) =0\\ y\left( \pi \right) =1\\ \end{cases} y′′=y+cosyy(0)=0y(π)=1
According to the finite difference method:
ω i + 1 − 2 ω i + ω i − 1 h 2 − ω i + 1 − ω i − 1 2 h − cos ⁡ ω i = 0 \frac{\omega _{i+1}-2\omega _i+\omega _{i-1}}{h^2}-\frac{\omega _{i+1}-\omega _{i-1}}{2h}-\cos \omega _i =0 h2ωi+12ωi+ωi12hωi+1ωi1cosωi=0
⇒ ( 1 + 1 2 h ) ω i − 1 − 2 ω i ( 1 − 1 2 h ) ω i + 1 − h 2 cos ⁡ ω i = 0 \Rightarrow \left( 1+\frac{1}{2}h \right) \omega _{i-1}-2\omega _i\left( 1-\frac{1}{2}h \right) \omega _{i+1}-h^2\cos \omega _i=0 (1+21h)ωi12ωi(121h)ωi+1h2cosωi=0
Thus, n-dimensional nonlinear functions can be obtained:
F ( ω ) = ( ( 1 + 1 2 h ) y ( a ) − 2 ω i ( 1 − 1 2 h ) ω 2 − h 2 cos ⁡ ω 1 ⋮ ( 1 + 1 2 h ) ω i − 1 − 2 ω i ( 1 − 1 2 h ) ω i + 1 − h 2 cos ⁡ ω i ⋮ ( 1 + 1 2 h ) ω n − 1 − 2 ω i ( 1 − 1 2 h ) y ( b ) − h 2 cos ⁡ ω n ) F\left( \omega \right) =\left( \begin{array}{c} \left( 1+\frac{1}{2}h \right) y\left( a \right) -2\omega _i\left( 1-\frac{1}{2}h \right) \omega _2-h^2\cos \omega _1\\ \vdots\\ \left( 1+\frac{1}{2}h \right) \omega _{i-1}-2\omega _i\left( 1-\frac{1}{2}h \right) \omega _{i+1}-h^2\cos \omega _i\\ \vdots\\ \left( 1+\frac{1}{2}h \right) \omega _{n-1}-2\omega _i\left( 1-\frac{1}{2}h \right) y\left( b \right) -h^2\cos \omega _n\\ \end{array} \right) F(ω)= (1+21h)y(a)2ωi(121h)ω2h2cosω1(1+21h)ωi12ωi(121h)ωi+1h2cosωi(1+21h)ωn12ωi(121h)y(b)h2cosωn
corresponding Jacobi matrix:
D F ( ω ) = ( − 2 + h 2 sin ⁡ ω 1 1 − h 2 0 ⋯ ⋯ ⋯ 0 1 + h 2 − 2 + h 2 sin ⁡ ω 2 1 − h 2 0 ⋯ ⋯ 0 0 1 + h 2 − 2 + h 2 sin ⁡ ω 3 1 − h 2 0 ⋯ 0 0 0 ⋱ ⋱ ⋱ 0 0 ⋮ ⋮ 0 1 + h 2 − 2 + h 2 sin ⁡ ω n − 2 1 − h 2 0 ⋮ ⋮ ⋮ 0 1 + h 2 − 2 + h 2 sin ⁡ ω n − 1 1 − h 2 0 0 0 0 0 1 + h 2 − 2 + h 2 sin ⁡ ω n ) DF\left( \omega \right) =\left( \begin{matrix} -2+h^2\sin \omega _1& 1-\frac{h}{2}& 0& \cdots& \cdots& \cdots& 0\\ 1+\frac{h}{2}& -2+h^2\sin \omega _2& 1-\frac{h}{2}& 0& \cdots& \cdots& 0\\ 0& 1+\frac{h}{2}& -2+h^2\sin \omega _3& 1-\frac{h}{2}& 0& \cdots& 0\\ 0& 0& \ddots& \ddots& \ddots& 0& 0\\ \vdots& \vdots& 0& 1+\frac{h}{2}& -2+h^2\sin \omega _{n-2}& 1-\frac{h}{2}& 0\\ \vdots& \vdots& \vdots& 0& 1+\frac{h}{2}& -2+h^2\sin \omega _{n-1}& 1-\frac{h}{2}\\ 0& 0& 0& 0& 0& 1+\frac{h}{2}& -2+h^2\sin \omega _n\\ \end{matrix} \right) DF(ω)= 2+h2sinω11+2h00012h2+h2sinω21+2h00012h2+h2sinω300012h1+2h0002+h2sinωn21+2h0012h2+h2sinωn11+2h0000012h2+h2sinωn

eps = 1e-4  
n_step = 40
step_h = (np.pi - 0.0)/(n_step + 1)  # h = (b - a)/(n + 1)
b_value1, b_value2 = 0.0, 1.0  # boundary value: y(0) = 1.0, y(1) = 3.0

def F(x, n_step, step_h):
    a = np.array([(1 + step_h/2) * b_value1 - 2 * x[0, 0] + (1 - step_h/2) * x[1, 0] - np.power(step_h, 2) * np.cos(x[0, 0])])
    b = np.array([
        [(1 + step_h/2) * x[i - 1, 0] - 2 * x[i, 0] + (1 - step_h/2) * x[i + 1, 0] - np.power(step_h, 2) * np.cos(x[i, 0])] for i in range(1, n_step -1)
    ])
    c = np.array([(1 + step_h/2) * x[n_step - 2, 0] - 2 * x[n_step - 1, 0] + (1 - step_h/2) * b_value2 - np.power(step_h, 2) * np.cos(x[n_step - 1, 0])])
    return np.vstack((a, b, c))

def DF(x, n_step, step_h): # x.size() = (n, 1)
    a = np.array([-2 + np.power(step_h, 2) * np.sin(x[0, 0]), 1 - step_h/2] + [0] * (n_step - 2), dtype=float)
    b = np.array([
        ([0] * (i - 1) + [1 + step_h/2, -2 + np.power(step_h, 2) * np.sin(x[i, 0]), 1 - step_h/2] + [0] * (n_step - 3 - (i - 1))) for i in range(1,  n_step - 1)
    ], dtype=float)
    c = np.array([0] * (n_step - 2) + [1 + step_h/2, -2 + np.power(step_h, 2) * np.sin(x[n_step - 1, 0])], dtype=float)
    return np.vstack((a, b, c))

def MultivariableNewton(n_step, step_h):  # define F(x) and DF(x) of your system first
    x = np.zeros((n_step, 1))
    last_x = np.ones((n_step, 1))
    print("x0 = ", x.T.round(4))
    i = 0
    while np.linalg.norm(x - last_x, np.inf) > eps:
        i += 1
        last_x = x
        x = x - np.dot(np.linalg.inv(DF(x, n_step=n_step,step_h=step_h)), F(x, n_step=n_step,step_h=step_h))
        print("x{} = ".format(i), x.T.round(4))
    return x
omega = np.hstack((np.array([b_value1]), np.transpose(MultivariableNewton(n_step=n_step, step_h=step_h)).squeeze(), np.array([b_value2])))

# plot:
plt.rcParams['xtick.direction'] = "in"  # ticks direction
plt.rcParams['ytick.direction'] = "in" 
axes=plt.gca()
axes.yaxis.set_major_locator(MaxNLocator(5))  # ticks num
axes.xaxis.set_major_locator(MaxNLocator(5))
plt.xticks(fontsize=20, fontweight="bold")  # ticks font
plt.yticks(fontsize=20, fontweight="bold")  
plt.xlabel("T", fontsize=22, fontweight="bold")
plt.ylabel("Y", fontsize=22, fontweight="bold")
plt.title("Finite difference method, n = 40", fontsize=24, fontweight="bold")
plt.plot(np.linspace(0, np.pi, n_step + 2), omega, color="red", linewidth=3)
# set legend:
legend_font = {
    "family": "Times New Roman", 
    "style" : "normal",
    "size" : 20, 
    'weight': "bold"
}
plt.legend(
    bbox_to_anchor=(0.95, 0), loc="lower right", 
    frameon=False, prop=legend_font
)
plt.show()

在这里插入图片描述

Collocation and Finite element method

The solution is given a functional form whose parameters are fit by the method.
Choose a set of basis functions ϕ 1 ( t ) , … , ϕ n ( t ) \phi_{1}(t), \dots, \phi_{n}(t) ϕ1(t),,ϕn(t), which may be polynomials, trigonometric functions, splines, or other simple functions. Then consider the possible solution:
y ( t ) = ∑ i = 1 n c i ϕ i ( t ) y\left( t \right) =\sum_{i=1}^n{c_i\phi _i\left( t \right)} y(t)=i=1nciϕi(t)

Collocation method

For BVP:
{ y ′ ′ = f ( t , y , y ′ ) y ( a ) = y a y ( b ) = y b \begin{cases} y^{''}=f\left( t, y, y^{\prime} \right)\\ y\left( a \right) =y_a\\ y\left( b \right) =y_b\\ \end{cases} y′′=f(t,y,y)y(a)=yay(b)=yb
Choose n points, beginning and ending with the boundary points a a a and b b b, say:
a = t 1 < ⋯ < t n = b a=t_1<\cdots <t_n=b a=t1<<tn=b
Here, we choose the basis functions ϕ j ( t ) = t j − 1 \phi_{j}(t)=t^{j-1} ϕj(t)=tj1 for 1 ⩽ j ⩽ n 1\leqslant j\leqslant n 1jn. The solution will be of form:
y ( t ) = ∑ j = 1 n c j ϕ j ( t ) = ∑ j = 1 n c i t j − 1 y\left( t \right) =\sum_{j=1}^n{c_j\phi _j\left( t \right)}=\sum_{j=1}^n{c_it^{j-1}} y(t)=j=1ncjϕj(t)=j=1ncitj1
We will write n equations in the n n n unknowns c 1 , . . . , c n c_{1},...,c_{n} c1,...,cn. The first and last are the boundary conditions:
i = 1 : ∑ j = 1 n c j a j − 1 = y ( a ) i = n : ∑ j = 1 n c j b j − 1 = y ( b ) i=1:\sum_{j=1}^n{c_ja^{j-1}}=y\left( a \right) \\ i=n:\sum_{j=1}^n{c_jb^{j-1}}=y\left( b \right) i=1:j=1ncjaj1=y(a)i=n:j=1ncjbj1=y(b)
The remaining n − 2 n−2 n2 equations come from the differential equation evaluated at t i t_{i} ti for 2 ⩽ i ⩽ n − 1 2\leqslant i\leqslant n−1 2in1:
∑ j = 1 n ( j − 1 ) ( j − 2 ) c j t j − 3 = f ( t , ∑ j = 1 n c j t j − 1 , ∑ j = 1 n ( j − 1 ) c j t j − 2 ) \sum_{j=1}^n{\left( j-1 \right) \left( j-2 \right) c_jt^{j-3}}=f\left( t,\sum_{j=1}^n{c_jt^{j-1}},\sum_{j=1}^n{\left( j-1 \right) c_jt^{j-2}} \right) j=1n(j1)(j2)cjtj3=f(t,j=1ncjtj1,j=1n(j1)cjtj2)

Application

For BVP:
{ y ′ ′ = 4 y y ( 0 ) = 1 y ( 1 ) = 3 \begin{cases} y^{''}=4y\\ y\left( 0 \right) =1\\ y\left( 1 \right) =3\\ \end{cases} y′′=4yy(0)=1y(1)=3
Through collocation method:
i = 1 : ∑ j = 1 n c j a j − 1 = c 1 = 1 i=1:\sum_{j=1}^n{c_ja^{j-1}}=c_1=1 i=1:j=1ncjaj1=c1=1
i = n : ∑ j = 1 n c j b j − 1 = ∑ j = 1 n c j = 3 i=n:\sum_{j=1}^n{c_jb^{j-1}}=\sum_{j=1}^n{c_j}=3 i=n:j=1ncjbj1=j=1ncj=3
∑ j = 1 n ( j − 1 ) ( j − 2 ) c j t i j − 3 = f ( t , ∑ j = 1 n c j t i j − 1 , ∑ j = 1 n ( j − 1 ) c j t i j − 2 ) ⇒ ∑ j = 1 n [ ( j − 1 ) ( j − 2 ) c j t i j − 3 − 4 t i j − 1 ] c j = 0 \sum_{j=1}^n{\left( j-1 \right) \left( j-2 \right) c_jt_{i}^{j-3}}=f\left( t,\sum_{j=1}^n{c_jt_{i}^{j-1}},\sum_{j=1}^n{\left( j-1 \right) c_jt_{i}^{j-2}} \right) \\ \Rightarrow \sum_{j=1}^n{\left[ \left( j-1 \right) \left( j-2 \right) c_jt_{i}^{j-3}-4t_{i}^{j-1} \right] c_j}=0 j=1n(j1)(j2)cjtij3=f(t,j=1ncjtij1,j=1n(j1)cjtij2)j=1n[(j1)(j2)cjtij34tij1]cj=0
which gives us a n-dimension linear equation:
( 1 0 ⋯ ⋯ 0 ⋯ ⋯ ( j − 1 ) ( j − 2 ) t i j − 3 − 4 t i j − 1 ⋯ ⋯ 1 1 ⋯ ⋯ 1 ) ( c 1 ⋮ c n ) = ( 1 ⋮ 3 ) ; 1 ⩽ j ⩽ n , 2 ⩽ i ⩽ n − 1 \left( \begin{matrix} 1& 0& \cdots& \cdots& 0\\ \cdots& \cdots& \left( j-1 \right) \left( j-2 \right) t_{i}^{j-3}-4t_{i}^{j-1}& \cdots& \cdots\\ 1& 1& \cdots& \cdots& 1\\ \end{matrix} \right) \left( \begin{array}{c} c_1\\ \vdots\\ c_n\\ \end{array} \right) =\left( \begin{array}{c} 1\\ \vdots\\ 3\\ \end{array} \right) ; 1\leqslant j\leqslant n, 2\leqslant i\leqslant n-1 1101(j1)(j2)tij34tij101 c1cn = 13 ;1jn,2in1
where: t i = a + i − 1 n − 1 ( b − a ) = i − 1 n − 1 t_i=a+\frac{i-1}{n-1}\left( b-a \right) =\frac{i-1}{n-1} ti=a+n1i1(ba)=n1i1

def Householder(matrix):
    A = np.transpose(matrix)
    n = A.shape[1]
    omega = np.array([np.linalg.norm(A[0], 2)] + [0] * (n - 1))
    v = omega - A[0]
    P = np.dot(np.transpose([v]), [v])/np.dot([v], np.transpose([v]))
    H_hat = np.eye(n) - 2 * P
    return H_hat

def AugmentH(h_hat, n):
    r = n - len(h_hat)
    return np.block([
            [np.eye(r, r), np.zeros((r, len(h_hat)))], 
            [np.zeros((len(h_hat), r)), h_hat]
    ])

def HouseholderQRDecomposition(matrix):
    A = np.transpose(matrix)
    hid_r = np.eye(len(matrix))
    state = matrix
    for i in range(matrix.shape[1]):
        h_hat = Householder(state)
        H = AugmentH(h_hat, len(matrix))
        hid_r = np.dot(H, hid_r)
        state = np.dot(hid_r, matrix)
        state = state[i + 1:, i + 1:]
        if state.shape[0] < 2:
            break
        cnt = 0
        for i in range(1, state.shape[0]):
            if state[i][0] == 0:
                cnt += 1  
        if cnt == state.shape[0] - 1:
            break
    R = np.dot(hid_r, matrix)
    Q = np.linalg.inv(hid_r)
    return Q, R

def GaussSeidel(matrix, base):
    x = np.array([0] * len(base))
    print("x0 = ", x.round(4))
    x = np.transpose([x])
    D = np.diag(np.diag(matrix))
    L = np.tril(matrix)
    U = np.triu(matrix) - D
    L_i = np.linalg.inv(L)
    i = 1
    while np.linalg.norm((base - np.dot(matrix, x)), np.inf) > eps:
        x = np.dot(L_i, (base - np.dot(U, x)))
        print("x{} = ".format(i), x.T.round(4))
        i += 1
    return x

def func(t):  # analytical solution 
    return (3 - np.power(np.e, -2))/(np.power(np.e, 2) - np.power(np.e, -2)) * np.exp(2 * t) + (np.power(np.e, 2) - 3)/(np.power(np.e, 2) - np.power(np.e, -2)) * np.exp(-2 * t)

def phi(t, cs):  # discrete function
    if isinstance(t, np.ndarray):
        ret = np.array([0] * len(t), dtype=float)
    else:
        ret = 0
    for i in range(len(cs)):
        ret += cs[i] * np.power(t, i)
    return ret
n_step = 4
t = [(i - 1)/(n_step - 1) for i in range(2, n_step)]
a = np.array([1] + [0] * (n_step - 1), dtype=float)
b = np.array([
    [(j - 1) * (j - 2) * np.power(((i - 1)/(n_step - 1)), j - 3) - 4 * np.power(((i - 1)/(n_step - 1)), j - 1) for j in range(1, n_step + 1)] for i in range(2, n_step)
], dtype=float) 
c = np.array([1] * n_step, dtype=float)
if n_step > 2:
    coefficient_matrix = np.vstack((a, b, c))
else:
    coefficient_matrix = np.vstack((a, c))
base = np.transpose([np.array([1] + (n_step - 2) * [0] + [3], dtype=float)])
Q, R = HouseholderQRDecomposition(coefficient_matrix)
R_hat = R[:n_step, :n_step]
d_hat = np.dot(np.transpose(Q), base)[:n_step, :]
cs = GaussSeidel(matrix=R_hat, base=d_hat)

# plot:
plt.rcParams['xtick.direction'] = "in"  # ticks direction
plt.rcParams['ytick.direction'] = "in" 
axes=plt.gca()
axes.yaxis.set_major_locator(MaxNLocator(5))  # ticks num
axes.xaxis.set_major_locator(MaxNLocator(5))
plt.xticks(fontsize=20, fontweight="bold")  # ticks font
plt.yticks(fontsize=20, fontweight="bold")  
plt.xlabel("T", fontsize=22, fontweight="bold")
plt.ylabel("Y", fontsize=22, fontweight="bold")
plt.title("Collocation method, n = 4", fontsize=24, fontweight="bold")
plt.plot(np.linspace(0, 1, 100), func(np.linspace(0, 1, 100)), color="red", linewidth=3, label="Analytical solution")
plt.plot(np.linspace(0, 1, 100), phi(np.linspace(0, 1, 100), cs), color="blue", linewidth=3, label="Approximate solution")
# set legend:
legend_font = {
    "family": "Times New Roman", 
    "style" : "normal",
    "size" : 20, 
    'weight': "bold"
}
plt.legend(
    bbox_to_anchor=(0.05, 0.95), loc="upper left", 
    frameon=False, prop=legend_font
)
plt.show()

在这里插入图片描述

Galerkin method (finite element analysis)

The choice of splines as basis functions leads to the Finite Element Method as:
y ( t ) = ∑ j = 0 n + 1 c j ϕ j ( t ) y\left( t \right) =\sum_{j=0}^{n+1}{c_j\phi _j(t)} y(t)=j=0n+1cjϕj(t)
ϕ i ( t ) = { t − t i − 1 t i − t i − 1 ; w h e n    t i − 1 < t ⩽ t i t i + 1 − t t i + 1 − t i ; w h e n    t i < t ⩽ t i + 1 0 ; o t h e r \phi _i\left( t \right) =\begin{cases} \frac{t-t_{i-1}}{t_i-t_{i-1}}; when\,\,t_{i-1}<t\leqslant t_i\\ \frac{t_{i+1}-t}{t_{i+1}-t_i}; when\,\,t_i<t\leqslant t_{i+1}\\ 0; other\\ \end{cases} ϕi(t)= titi1tti1;whenti1<ttiti+1titi+1t;whenti<tti+10;other
ϕ 0 ( t ) = { t 1 − t t 1 − t 0 ; w h e n    t 0 < t ⩽ t 1 0 ; o t h e r ; ϕ n + 1 ( t ) = { t − t n t n + 1 − t n ; w h e n    t n < t ⩽ t n + 1 0 ; o t h e r \phi _0\left( t \right) =\begin{cases} \frac{t_1-t}{t_1-t_0}; when\,\,t_0<t\leqslant t_1\\ 0; other\\ \end{cases}; \phi _{n+1}\left( t \right) =\begin{cases} \frac{t-t_n}{t_{n+1}-t_n}; when\,\,t_n<t\leqslant t_{n+1}\\ 0; other\\ \end{cases} ϕ0(t)={t1t0t1t;whent0<tt10;other;ϕn+1(t)={tn+1tnttn;whentn<ttn+10;other
The piecewise-linear “tent” functions ϕ i ( t ) \phi_{i}(t) ϕi(t) has the following properties:
ϕ i ( j ) = δ i j \phi _i\left( j \right) =\delta _{ij} ϕi(j)=δij
∑ i = 0 n + 1 c i ϕ i ( t ) = c j \sum_{i=0}^{n+1}{c_i\phi _i\left( t \right)}=c_j i=0n+1ciϕi(t)=cj
∫ a b ϕ i ( t ) ϕ i + 1 ( t ) d t = h 6 ; ∫ a b [ ϕ i ( t ) ] 2 d t = 2 h 3 \int_a^b{\phi _i\left( t \right) \phi _{i+1}\left( t \right) dt}=\frac{h}{6}; \int_a^b{\left[ \phi _i\left( t \right) \right] ^2dt}=\frac{2h}{3} abϕi(t)ϕi+1(t)dt=6h;ab[ϕi(t)]2dt=32h
∫ a b ϕ i ( t ) ϕ i + 1 ′ ( t ) d t = − 1 h ; ∫ a b [ ϕ i ′ ( t ) ] 2 d t = 2 h \int_a^b{\phi _i\left( t \right) \phi _{i+1}^{\prime}\left( t \right) dt}=-\frac{1}{h}; \int_a^b{\left[ \phi _{i}^{\prime}\left( t \right) \right] ^2dt}=\frac{2}{h} abϕi(t)ϕi+1(t)dt=h1;ab[ϕi(t)]2dt=h2
where h h h is the time step.

For BVP:
{ y ′ ′ = f ( t , y , y ′ ) y ( a ) = y a y ( b ) = y b \begin{cases} y^{''}=f\left( t, y, y^{\prime} \right)\\ y\left( a \right) =y_a\\ y\left( b \right) =y_b\\ \end{cases} y′′=f(t,y,y)y(a)=yay(b)=yb
The Galerkin Method consists of two main ideas. The first is to minimize r r r by
forcing it to be orthogonal to the basis functions:
∫ a b y ′ ′ ( t ) ϕ i ( t ) d t = ∫ a b f ′ ( t , y , y ′ ) ϕ i ( t ) d t \int_a^b{y^{''}\left( t \right) \phi _i\left( t \right) dt}=\int_a^b{f^{\prime}\left( t, y, y^{\prime} \right) \phi _i\left( t \right) dt} aby′′(t)ϕi(t)dt=abf(t,y,y)ϕi(t)dt
Now apply integration by parts to eliminate the second derivatives:
∫ a b y ′ ′ ( t ) ϕ i ( t ) d t = ϕ i ( b ) y ′ ( b ) − ϕ i ( a ) y ′ ( a ) − ∫ a b y ′ ( t ) ϕ i ′ ( t ) d t \int_a^b{y^{''}\left( t \right) \phi _i\left( t \right) dt}=\phi _i\left( b \right) y^{\prime}\left( b \right) -\phi _i\left( a \right) y^{\prime}\left( a \right) -\int_a^b{y^{\prime}\left( t \right) \phi _{i}^{\prime}\left( t \right) dt} aby′′(t)ϕi(t)dt=ϕi(b)y(b)ϕi(a)y(a)aby(t)ϕi(t)dt
According the properties of tent functions:
y ( a ) = ∑ i = 0 n + 1 c i ϕ i ( a ) = ∑ i = 0 n + 1 c i ϕ i ( t 0 ) = c 0 y\left( a \right) =\sum_{i=0}^{n+1}{c_i\phi _i\left( a \right)}=\sum_{i=0}^{n+1}{c_i\phi _i\left( t_0 \right)}=c_0 y(a)=i=0n+1ciϕi(a)=i=0n+1ciϕi(t0)=c0
y ( b ) = ∑ i = 0 n + 1 c i ϕ i ( b ) = ∑ i = 0 n + 1 c i ϕ i ( t n + 1 ) = c n + 1 y\left( b \right) =\sum_{i=0}^{n+1}{c_i\phi _i\left( b \right)}=\sum_{i=0}^{n+1}{c_i\phi _i\left( t_{n+1} \right)}=c_{n+1} y(b)=i=0n+1ciϕi(b)=i=0n+1ciϕi(tn+1)=cn+1
Therefore, the integration formula can be written as ( i = 1 , … , n i = 1, \dots, n i=1,,n):
∫ a b f ( t , y , y ′ ) ϕ i ( t ) d t + ∫ a b y ′ ( t ) ϕ i ′ ( t ) d t = 0 \int_a^b{f\left( t, y, y^{\prime} \right) \phi _i\left( t \right) dt}+\int_a^b{y^{\prime}\left( t \right) \phi _{i}^{\prime}\left( t \right) dt}=0 abf(t,y,y)ϕi(t)dt+aby(t)ϕi(t)dt=0

Application

For BVP:
{ y ′ ′ = 4 y y ( 0 ) = 1 y ( 1 ) = 3 \begin{cases} y^{''}=4y\\ y\left( 0 \right) =1\\ y\left( 1 \right) =3\\ \end{cases} y′′=4yy(0)=1y(1)=3
Through collocation method:
∑ j = 0 n + 1 c j [ 4 ∫ 0 1 ϕ i ( t ) ϕ j ( t ) d t + ∫ 0 1 ϕ j ′ ( t ) ϕ i ′ ( t ) d t ] \sum_{j=0}^{n+1}{c_j\left[ 4\int_0^1{\phi _i\left( t \right) \phi _j\left( t \right) dt}+\int_0^1{\phi _{j}^{\prime}\left( t \right) \phi _{i}^{\prime}\left( t \right) dt} \right]} j=0n+1cj[401ϕi(t)ϕj(t)dt+01ϕj(t)ϕi(t)dt]
System of linear equations can be obtained:
( α β 0 ⋯ ⋯ ⋯ 0 β α β 0 ⋯ ⋯ 0 0 β α β 0 ⋯ 0 0 0 ⋱ ⋱ ⋱ 0 0 ⋮ ⋮ 0 β α β 0 ⋮ ⋮ ⋮ 0 β α β 0 0 0 0 0 β α ) ( c 1 ⋮ ⋮ ⋮ ⋮ ⋮ c n ) = ( − y a β 0 ⋮ ⋮ ⋮ 0 − y b β ) \left( \begin{matrix} \alpha& \beta& 0& \cdots& \cdots& \cdots& 0\\ \beta& \alpha& \beta& 0& \cdots& \cdots& 0\\ 0& \beta& \alpha& \beta& 0& \cdots& 0\\ 0& 0& \ddots& \ddots& \ddots& 0& 0\\ \vdots& \vdots& 0& \beta& \alpha& \beta& 0\\ \vdots& \vdots& \vdots& 0& \beta& \alpha& \beta\\ 0& 0& 0& 0& 0& \beta& \alpha\\ \end{matrix} \right) \left( \begin{array}{c} c_1\\ \vdots\\ \vdots\\ \vdots\\ \vdots\\ \vdots\\ c_n\\ \end{array} \right) =\left( \begin{array}{c} -y_a\beta\\ 0\\ \vdots\\ \vdots\\ \vdots\\ 0\\ -y_b\beta\\ \end{array} \right) αβ000βαβ000βα000ββ000αβ00βαβ00000βα c1cn = yaβ00ybβ
where
α = 8 3 h + 2 h ; β = 2 3 h − 1 h ; y a = 1 ; y b = 3 \alpha =\frac{8}{3}h+\frac{2}{h}; \beta =\frac{2}{3}h-\frac{1}{h}; y_a=1; y_b=3 α=38h+h2;β=32hh1;ya=1;yb=3

def func(t):  # analytical solution 
    return (3 - np.power(np.e, -2))/(np.power(np.e, 2) - np.power(np.e, -2)) * np.exp(2 * t) + (np.power(np.e, 2) - 3)/(np.power(np.e, 2) - np.power(np.e, -2)) * np.exp(-2 * t)

n_step = 10
step_h = (1.0 - 0.0)/(n_step + 1)
b_value1, b_value2 = 1.0, 3.0  # boundary value: y(0) = 1.0, y(1) = 3.0
alpha = 8/3 * step_h + 2/step_h
beta = 2/3 * step_h - 1/step_h
a = np.array([alpha, beta] + [0] * (n_step - 2), dtype=float)
b = np.array([
    ([0] * (i - 1) + [beta, alpha, beta] + [0] * (n_step - 3 - (i - 1))) for i in range(1, n_step - 1)
])
c = np.array([0] * (n_step - 2) + [beta, alpha], dtype=float)
if n_step > 2:
    coefficient_matrix = np.vstack((a, b, c))
else:
    coefficient_matrix = np.vstack((a, c))
base = np.transpose([np.array([-b_value1 * beta] + [0] * (n_step - 2) + [-b_value2 * beta], dtype=float)])
omega = np.hstack((np.array([b_value1]), np.transpose(GaussSeidel(matrix=coefficient_matrix, base=base)).squeeze(), np.array([b_value2])))

# plot:
plt.rcParams['xtick.direction'] = "in"  # ticks direction
plt.rcParams['ytick.direction'] = "in" 
axes=plt.gca()
axes.yaxis.set_major_locator(MaxNLocator(5))  # ticks num
axes.xaxis.set_major_locator(MaxNLocator(5))
plt.xticks(fontsize=20, fontweight="bold")  # ticks font
plt.yticks(fontsize=20, fontweight="bold")  
plt.xlabel("T", fontsize=22, fontweight="bold")
plt.ylabel("Y", fontsize=22, fontweight="bold")
plt.title("Galerkin method, n = 10", fontsize=24, fontweight="bold")
plt.scatter(np.linspace(0, 1, 12), func(np.linspace(0, 1, 12)), color="red", marker='o', s=100, label="Y")
plt.plot(np.linspace(0, 1, 100), func(np.linspace(0, 1, 100)), color="red", linewidth=3)
plt.scatter(np.linspace(0, 1, 12), omega, color="blue", marker='*', s=150, label="Omega")
# set legend:
legend_font = {
    "family": "Times New Roman", 
    "style" : "normal",
    "size" : 20, 
    'weight': "bold"
}
plt.legend(
    bbox_to_anchor=(0.95, 0), loc="lower right", 
    frameon=False, prop=legend_font
)
plt.show()

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值