1 # Poisson's equation之实现 - 有限元法
2 # 注意, 采用Gauss-Legendre Quadrature进行数值积分
3
4 import numpy
5 from matplotlib import pyplot as plt
6
7
8 numpy.random.seed(0)
9
10
11 # Gauss-Legendre Quadrature之实现
12 def getGaussParams(num=6):
13 if num == 1:
14 X = numpy.array([0])
15 A = numpy.array([2])
16 elif num == 2:
17 X = numpy.array([numpy.math.sqrt(1/3), -numpy.math.sqrt(1/3)])
18 A = numpy.array([1, 1])
19 elif num == 3:
20 X = numpy.array([numpy.math.sqrt(3/5), -numpy.math.sqrt(3/5), 0])
21 A = numpy.array([5/9, 5/9, 8/9])
22 elif num == 6:
23 X = numpy.array([0.238619186081526, -0.238619186081526, 0.661209386472165, -0.661209386472165, 0.932469514199394, -0.932469514199394])
24 A = numpy.array([0.467913934574257, 0.467913934574257, 0.360761573028128, 0.360761573028128, 0.171324492415988, 0.171324492415988])
25 elif num == 10:
26 X = numpy.array([0.973906528517240, -0.973906528517240, 0.433395394129334, -0.433395394129334, 0.865063366688893, -0.865063366688893,
27 0.148874338981367, -0.148874338981367, 0.679409568299053, -0.679409568299053])
28 A = numpy.array([0.066671344307672, 0.066671344307672, 0.269266719309847, 0.269266719309847, 0.149451349151147, 0.149451349151147,
29 0.295524224714896, 0.295524224714896, 0.219086362515885, 0.219086362515885])
30 else:
31 raise Exception(">>> Unsupported num = {} <<<".format(num))
32 return X, A
33
34
35 def getGaussQuadrature(func, a, b, X, A):
36 '''
37 func: 原始被积函数
38 a: 积分区间下边界
39 b: 积分区间上边界
40 X: 求积节点数组
41 A: 求积系数数组
42 '''
43 term1 = (b - a) / 2
44 term2 = (a + b) / 2
45 term3 = func(term1 * X + term2)
46 term4 = numpy.sum(A * term3)
47 val = term1 * term4
48 return val
49
50
51 class PoissonEq(object):
52
53 def __init__(self, n, order=6):
54 self.__n = n # 子区间划分数
55 self.__order = order # Legendre多项式之阶数
56
57 self.__X = self.__build_gridPoints(n) # 构造网格节点
58 self.__XQuad, self.__AQuad = getGaussParams(order) # 获取数值积分之求积节点、求积系数
59
60
61 def get_solu(self):
62 A = self.__build_A()
63 b = self.__build_b()
64 alpha = numpy.matmul(numpy.linalg.inv(A), b)
65
66 U = numpy.zeros(self.__X.shape)
67 U[1:-1] = alpha.flatten()
68
69 return self.__X, U
70
71
72 def __build_b(self):
73 '''
74 构造列向量b
75 '''
76 self.__xiMinusOne, self.__xi, self.__xiPlusOne = None, None, None
77
78 b = numpy.zeros((self.__n-1, 1))
79 for i in range(b.shape[0]):
80 self.__xiMinusOne = self.__X[i]
81 self.__xi = self.__X[i+1]
82 self.__xiPlusOne = self.__X[i+2]
83 quadValLeft = getGaussQuadrature(self.__funcLeft, self.__xiMinusOne, self.__xi, self.__XQuad, self.__AQuad)
84 quadValRight = getGaussQuadrature(self.__funcRight, self.__xi, self.__xiPlusOne, self.__XQuad, self.__AQuad)
85 b[i, 0] = quadValLeft + quadValRight
86 return b
87
88
89 def __funcLeft(self, x):
90 val = (x - self.__xiMinusOne) / (self.__xi - self.__xiMinusOne) * numpy.sin(numpy.pi * x)
91 return val
92
93
94 def __funcRight(self, x):
95 val = (self.__xiPlusOne - x) / (self.__xiPlusOne - self.__xi) * numpy.sin(numpy.pi * x)
96 return val
97
98
99 def __build_A(self):
100 '''
101 构造矩阵A
102 '''
103 dPhiLeft = 1 / (self.__X[1:-1] - self.__X[:-2])
104 dPhiRight = -1 / (self.__X[2:] - self.__X[1:-1])
105 interval = self.__X[1:] - self.__X[:-1]
106
107 A = numpy.zeros((self.__n-1, self.__n-1))
108 for i in range(A.shape[0]):
109 for j in range(A.shape[1]):
110 if j == i-1:
111 A[i, j] = dPhiLeft[i] * dPhiRight[j] * interval[i]
112 elif j == i:
113 A[i, j] = dPhiLeft[i] * dPhiLeft[j] * interval[i] + dPhiRight[i] * dPhiRight[j] * interval[i+1]
114 elif j == i+1:
115 A[i, j] = dPhiRight[i] * dPhiLeft[j] * interval[i+1]
116 return A
117
118
119 def __build_gridPoints(self, n):
120 '''
121 随机初始化网格节点
122 '''
123 xMin, xMax = 0, 1
124 X = numpy.sort(numpy.random.uniform(xMin, xMax, n+1))
125 X[0] = xMin
126 X[-1] = xMax
127 return X
128
129
130 class PoissonPlot(object):
131
132 @staticmethod
133 def plot_fig(poissonObj):
134 X, U = poissonObj.get_solu()
135
136 xMin, xMax = numpy.min(X), numpy.max(X)
137 X_ = numpy.linspace(xMin, xMax, 1000)
138 U_ = numpy.sin(numpy.pi * X_) / numpy.pi ** 2
139
140 fig = plt.figure(figsize=(6, 4))
141 ax1 = plt.subplot()
142
143 ax1.plot(X, U, marker='.', ls="--", label="numerical solution")
144 ax1.plot(X_, U_, label="analytical solution")
145 ax1.set(xlabel="$x$", ylabel="$u$")
146 ax1.legend()
147 fig.savefig("plot_fig.png", dpi=100)
148
149
150
151 if __name__ == "__main__":
152 n = 20
153 order = 6
154 poissonObj = PoissonEq(n, order)
155
156 PoissonPlot.plot_fig(poissonObj)