1 # 椭圆型方程网格生成法
2
3 import numpy
4 from matplotlib import pyplot as plt
5
6
7 # 对称翼型的上半部
8 def half_wing(x):
9 funcVal = 0.1781 * numpy.sqrt(x) - 0.0756 * x - 0.2122 * x ** 2 + 0.1705 * x ** 3 - 0.0609 * x ** 4
10 return funcVal
11
12
13 # 构造物理空间与计算空间边界映射关系
14 def build_bdy_maps():
15 p2c_xi = [
16 ((1.0, 0.0), (0, 15)),
17 ((0.9, half_wing(0.9)), (1, 15)),
18 ((0.8, half_wing(0.8)), (2, 15)),
19 ((0.7, half_wing(0.7)), (3, 15)),
20 ((0.6, half_wing(0.6)), (4, 15)),
21 ((0.5, half_wing(0.5)), (5, 15)),
22 ((0.4, half_wing(0.4)), (6, 15)),
23 ((0.3, half_wing(0.3)), (7, 15)),
24 ((0.2, half_wing(0.2)), (8, 15)),
25 ((0.1, half_wing(0.1)), (9, 15)),
26 ((0.0, half_wing(0.0)), (10, 15)),
27 ((0.1, -half_wing(0.1)), (11, 15)),
28 ((0.2, -half_wing(0.2)), (12, 15)),
29 ((0.3, -half_wing(0.3)), (13, 15)),
30 ((0.4, -half_wing(0.4)), (14, 15)),
31 ((0.5, -half_wing(0.5)), (15, 15)),
32 ((0.6, -half_wing(0.6)), (16, 15)),
33 ((0.7, -half_wing(0.7)), (17, 15)),
34 ((0.8, -half_wing(0.8)), (18, 15)),
35 ((0.9, -half_wing(0.9)), (19, 15)),
36 ((1.0, 0.0), (20, 15)),
37 ((4.0, 0.0), (0, 0)),
38 ((4.0, 1.0), (1, 0)),
39 ((4.0, 2.0), (2, 0)),
40 ((3.0, 2.0), (3, 0)),
41 ((2.0, 2.0), (4, 0)),
42 ((1.0, 2.0), (5, 0)),
43 ((0.0, 2.0), (6, 0)),
44 ((-1.0, 2.0), (7, 0)),
45 ((-2.0, 2.0), (8, 0)),
46 ((-2.0, 1.0), (9, 0)),
47 ((-2.0, 0.0), (10, 0)),
48 ((-2.0, -1.0), (11, 0)),
49 ((-2.0, -2.0), (12, 0)),
50 ((-1.0, -2.0), (13, 0)),
51 ((0.0, -2.0), (14, 0)),
52 ((1.0, -2.0), (15, 0)),
53 ((2.0, -2.0), (16, 0)),
54 ((3.0, -2.0), (17, 0)),
55 ((4.0, -2.0), (18, 0)),
56 ((4.0, -1.0), (19, 0)),
57 ((4.0, 0.0), (20, 0))
58 ]
59
60 p2c_eta = [
61 ((4.0, 0.0), (0, 0)),
62 ((3.8, 0.0), (0, 1)),
63 ((3.6, 0.0), (0, 2)),
64 ((3.4, 0.0), (0, 3)),
65 ((3.2, 0.0), (0, 4)),
66 ((3.0, 0.0), (0, 5)),
67 ((2.8, 0.0), (0, 6)),
68 ((2.6, 0.0), (0, 7)),
69 ((2.4, 0.0), (0, 8)),
70 ((2.2, 0.0), (0, 9)),
71 ((2.0, 0.0), (0, 10)),
72 ((1.8, 0.0), (0, 11)),
73 ((1.6, 0.0), (0, 12)),
74 ((1.4, 0.0), (0, 13)),
75 ((1.2, 0.0), (0, 14)),
76 ((1.0, 0.0), (0, 15)),
77 ((4.0, 0.0), (20, 0)),
78 ((3.8, 0.0), (20, 1)),
79 ((3.6, 0.0), (20, 2)),
80 ((3.4, 0.0), (20, 3)),
81 ((3.2, 0.0), (20, 4)),
82 ((3.0, 0.0), (20, 5)),
83 ((2.8, 0.0), (20, 6)),
84 ((2.6, 0.0), (20, 7)),
85 ((2.4, 0.0), (20, 8)),
86 ((2.2, 0.0), (20, 9)),
87 ((2.0, 0.0), (20, 10)),
88 ((1.8, 0.0), (20, 11)),
89 ((1.6, 0.0), (20, 12)),
90 ((1.4, 0.0), (20, 13)),
91 ((1.2, 0.0), (20, 14)),
92 ((1.0, 0.0), (20, 15))
93 ]
94
95 return p2c_xi, p2c_eta
96
97
98 class EllipticGrid(object):
99
100 def __init__(self, p2c_xi, p2c_eta):
101 self.__p2c_xi = p2c_xi # 物理空间与计算空间xi轴边界映射关系
102 self.__p2c_eta = p2c_eta # 物理空间与计算空间eta轴边界映射关系
103
104 self.__n_xi, self.__n_eta = self.__get_n() # 计算空间子区间划分数
105 self.__ht = 0.1
106
107 self.__bdyX, self.__bdyY = self.__get_bdy()
108
109
110 def get_solu(self, maxIter=1000000, epsilon=1.e-9):
111 '''
112 数值求解
113 maxIter: 最大迭代次数
114 epsilon: 收敛判据
115 '''
116 X0 = self.__get_initX()
117 Y0 = self.__get_initY()
118
119 for i in range(maxIter):
120 Xx = self.__calc_Ux(X0)
121 Xe = self.__calc_Ue(X0)
122 Xxx = self.__calc_Uxx(X0)
123 Xee = self.__calc_Uee(X0)
124 Xxe = self.__calc_Uxe(X0)
125 Yx = self.__calc_Ux(Y0)
126 Ye = self.__calc_Ue(Y0)
127 Yxx = self.__calc_Uxx(Y0)
128 Yee = self.__calc_Uee(Y0)
129 Yxe = self.__calc_Uxe(Y0)
130
131 alpha = self.__calc_alpha(Xe, Ye)
132 beta = self.__calc_beta(Xx, Xe, Yx, Ye)
133 gamma = self.__calc_gamma(Xx, Yx)
134
135 Kx = alpha * Xxx - 2 * beta * Xxe + gamma * Xee
136 Ky = alpha * Yxx - 2 * beta * Yxe + gamma * Yee
137
138 Xk = self.__calc_Uk(X0, Kx, self.__ht)
139 Yk = self.__calc_Uk(Y0, Ky, self.__ht)
140 self.__fill_bdyX(Xk)
141 self.__fill_bdyY(Yk)
142
143 # print(i, numpy.linalg.norm(Xk - X0, numpy.inf), numpy.linalg.norm(Yk - Y0, numpy.inf))
144 if self.__converged(Xk - X0, Yk - Y0, epsilon):
145 break
146
147 X0 = Xk
148 Y0 = Yk
149 else:
150 raise Exception(">>> Not converged after {} iterations! <<<".format(maxIter))
151
152 return Xk, Yk
153
154
155 def __converged(self, deltaX, deltaY, epsilon):
156 normVal1 = numpy.linalg.norm(deltaX, numpy.inf)
157 normVal2 = numpy.linalg.norm(deltaY, numpy.inf)
158 if normVal1 < epsilon and normVal2 < epsilon:
159 return True
160 return False
161
162
163 def __calc_Ux(self, U):
164 Ux = numpy.zeros(U.shape)
165 Ux[:, 1:-1] = (U[:, 2:] - U[:, :-2]) / 2
166 return Ux
167
168
169 def __calc_Ue(self, U):
170 Ue = numpy.zeros(U.shape)
171 Ue[1:-1, :] = (U[2:, :] - U[:-2, :]) / 2
172 return Ue
173
174
175 def __calc_Uxx(self, U):
176 Uxx = numpy.zeros(U.shape)
177 Uxx[:, 1:-1] = U[:, 2:] + U[:, :-2] - 2 * U[:, 1:-1]
178 return Uxx
179
180
181 def __calc_Uee(self, U):
182 Uee = numpy.zeros(U.shape)
183 Uee[1:-1, :] = U[2:, :] + U[:-2, :] - 2 * U[1:-1, :]
184 return Uee
185
186
187 def __calc_Uxe(self, U):
188 Uxe = numpy.zeros(U.shape)
189 Uxe[1:-1, 1:-1] = (U[2:, 2:] + U[:-2, :-2] - U[:-2, 2:] - U[2:, :-2]) / 4
190 return Uxe
191
192
193 def __calc_alpha(self, Xe, Ye):
194 alpha = Xe ** 2 + Ye ** 2
195 return alpha
196
197
198 def __calc_beta(self, Xx, Xe, Yx, Ye):
199 beta = Xx * Xe + Yx * Ye
200 return beta
201
202
203 def __calc_gamma(self, Xx, Yx):
204 gamma = Xx ** 2 + Yx ** 2
205 return gamma
206
207
208 def __calc_Uk(self, U, K, ht):
209 Uk = U + K * ht
210 return Uk
211
212
213 def __get_bdy(self):
214 '''
215 获取边界条件
216 '''
217 bdyX = numpy.zeros((self.__n_eta + 1, self.__n_xi + 1))
218 bdyY = numpy.zeros((self.__n_eta + 1, self.__n_xi + 1))
219
220 for XY, XE in self.__p2c_xi:
221 bdyX[XE[1], XE[0]] = XY[0]
222 bdyY[XE[1], XE[0]] = XY[1]
223
224 for XY, XE in self.__p2c_eta:
225 bdyX[XE[1], XE[0]] = XY[0]
226 bdyY[XE[1], XE[0]] = XY[1]
227
228 return bdyX, bdyY
229
230
231 def __get_initX(self):
232 '''
233 获取X之初始条件
234 '''
235 X0 = numpy.zeros(self.__bdyX.shape)
236 self.__fill_bdyX(X0)
237 return X0
238
239
240 def __get_initY(self):
241 '''
242 获取Y之初始条件
243 '''
244 Y0 = numpy.zeros(self.__bdyY.shape)
245 self.__fill_bdyY(Y0)
246 return Y0
247
248
249 def __fill_bdyX(self, U):
250 '''
251 填充X之边界条件
252 '''
253 U[:, 0] = self.__bdyX[:, 0]
254 U[:, -1] = self.__bdyX[:, -1]
255 U[0, :] = self.__bdyX[0, :]
256 U[-1, :] = self.__bdyX[-1, :]
257
258
259 def __fill_bdyY(self, U):
260 '''
261 填充Y之边界条件
262 '''
263 U[:, 0] = self.__bdyY[:, 0]
264 U[:, -1] = self.__bdyY[:, -1]
265 U[0, :] = self.__bdyY[0, :]
266 U[-1, :] = self.__bdyY[-1, :]
267
268
269 def __get_n(self):
270 arr_xi = numpy.array(list(item[1] for item in self.__p2c_xi))
271 n_xi = numpy.max(arr_xi[:, 0])
272 n_eta = numpy.max(arr_xi[:, 1])
273 return n_xi, n_eta
274
275
276 class EGPlot(object):
277
278 @staticmethod
279 def plot_fig(egObj):
280 maxIter = 1000000
281 epsilon = 1.e-9
282
283 X, Y = egObj.get_solu(maxIter, epsilon)
284
285 fig = plt.figure(figsize=(6, 4))
286 ax1 = plt.subplot()
287
288 ax1.plot(X[:, 0], Y[:, 0], c="red", lw=1, label="mapping to $\eta$")
289 ax1.plot(X[:, -1], Y[:, -1], c="red", lw=1)
290 n_eta, n_xi = X.shape
291 for colIdx in range(1, n_xi-1):
292 tmpX = X[:, colIdx]
293 tmpY = Y[:, colIdx]
294 ax1.plot(tmpX, tmpY, "k-", lw=1)
295
296 ax1.plot(X[0, :], Y[0, :], c="green", lw=1, label="mapping to $\xi$")
297 ax1.plot(X[-1, :], Y[-1, :], c="green", lw=1)
298 for rowIdx in range(1, n_eta-1):
299 tmpX = X[rowIdx, :]
300 tmpY = Y[rowIdx, :]
301 ax1.plot(tmpX, tmpY, "k-", lw=1)
302 ax1.legend()
303
304 fig.tight_layout()
305 fig.savefig("plot_fig.png", dpi=100)
306
307
308
309 if __name__ == "__main__":
310 p2c_xi, p2c_eta = build_bdy_maps()
311 egObj = EllipticGrid(p2c_xi, p2c_eta)
312
313 EGPlot.plot_fig(egObj)