1 # Burgers' equation之求解 - 有限体积法
2 # 1. monotonicity
3 # 2. high accuracy
4
5 import numpy
6 from matplotlib import pyplot as plt
7 from matplotlib import animation
8
9
10 # Runge-Kutta方法
11 def RK4(func, t, u, h):
12 '''
13 func: 导函数func(t, u)
14 t: 当前时刻
15 u: t时刻之u值
16 h: 下一时刻与当前时刻之时间差
17 '''
18 half_h = h / 2
19
20 k1 = func(t, u)
21 k2 = func(t + half_h / 2, u + half_h * k1)
22 k3 = func(t + half_h / 2, u + half_h * k2)
23 k4 = func(t + h, u + h * k3)
24
25 uNew = u + h / 6 * (k1 + 2 * k2 + 2 * k3 + k4)
26 return uNew
27
28
29 # Burgers' equation求解
30 class BurgersEq(object):
31
32 def __init__(self, nx=100, nt=100):
33 self.__nx = nx # x轴网格数
34 self.__nt = nt # t轴网格数
35
36 self.__init_grid() # 网格初始化
37
38
39 def get_solu(self):
40 UList = list()
41
42 U0 = self.__calc_U0()
43 UList.append(U0)
44 for t in self.__T[:-1]:
45 Uk = self.__calc_Uk(t, U0)
46 UList.append(Uk)
47 U0 = Uk
48
49 return self.__T, self.__X, UList
50
51
52 def __calc_Uk(self, t, UOld):
53 UNew = RK4(self.__calc_dUdT, t, UOld, self.__ht)
54 return UNew
55
56
57 def __calc_dUdT(self, t, UOld):
58 U = self.__fill_U_boundary(UOld) # u边界填充
59 UHL = self.__calc_UHalfLeft(U) # 不含首尾边界
60 UHR = self.__calc_UHalfRight(U) # 不含首尾边界
61 FH = self.__get_GodunovFlux(UHL, UHR) # 不含首尾边界
62 F = self.__fill_F_boundary(FH) # flux边界填充
63 dUdT = (F[:-1] - F[1:]) / self.__hx
64 return dUdT
65
66
67 def __fill_F_boundary(self, FH):
68 tmpFH = numpy.hstack(([0], FH, [0]))
69 return tmpFH
70
71
72 def __get_GodunovFlux(self, UHL, UHR):
73 FH = numpy.zeros(UHL.shape)
74 FHL = UHL ** 2 / 2
75 FHR = UHR ** 2 / 2
76 FH[UHL >= UHR] = numpy.max((FHL, FHR), axis=0)[UHL >= UHR]
77 FH[UHL < UHR] = numpy.min((FHL, FHR), axis=0)[UHL < UHR]
78 FH[(UHL < UHR) & (UHL * UHR < 0)] = 0
79 return FH
80
81
82 def __calc_UHalfRight(self, U):
83 Ui = U[1:-2]
84 UiPlusOne = U[2:-1]
85 UiPlusTwo = U[3:]
86
87 tmpItem = UiPlusOne - UiPlusTwo
88 UHR = list()
89 for idx, ele in enumerate(tmpItem):
90 if ele == 0:
91 UHR.append(UiPlusOne[idx])
92 else:
93 r = (Ui[idx] - UiPlusOne[idx]) / ele
94 phi = self.__get_limitor(r)
95 UHR.append(UiPlusOne[idx] + ele / 2 * phi)
96 UHR = numpy.array(UHR)
97 return UHR
98
99
100 def __calc_UHalfLeft(self, U):
101 Ui = U[1:-2]
102 UiMinusOne = U[0:-3]
103 UiPlusOne = U[2:-1]
104
105 tmpItem = Ui - UiMinusOne
106 UHL = list()
107 for idx, ele in enumerate(tmpItem):
108 if ele == 0:
109 UHL.append(Ui[idx])
110 else:
111 r = (UiPlusOne[idx] - Ui[idx]) / ele
112 phi = self.__get_limitor(r)
113 UHL.append(Ui[idx] + ele / 2 * phi)
114 UHL = numpy.array(UHL)
115 return UHL
116
117
118 def __get_limitor(self, r):
119 phi = 0
120 if r >= 0:
121 phi = 2 * r / (1 + r)
122 return phi
123
124
125 def __fill_U_boundary(self, UOld):
126 tmpUOld = numpy.hstack(([0], UOld, [0]))
127 return tmpUOld
128
129
130 def __calc_U0(self):
131 '''
132 计算第0层时间步数值
133 '''
134 U0 = self.__calc_u0(self.__X)
135 return U0
136
137
138 def __calc_u0(self, x):
139 u0 = numpy.sin(2 * numpy.pi * x)
140 return u0
141
142
143 def __init_grid(self):
144 xMin, xMax = 0, 1
145 tMin, tMax = 0, 0.5
146 self.__hx = (xMax - xMin) / self.__nx
147 self.__ht = (tMax - tMin) / self.__nt
148 self.__X_interface = numpy.linspace(xMin, xMax, self.__nx + 1)
149 self.__X = (self.__X_interface[:-1] + self.__X_interface[1:]) / 2
150 self.__T = numpy.linspace(tMin, tMax, self.__nt + 1)
151
152
153 class BurgersPlot(object):
154
155 fig = None
156 ax1 = None
157 line = None
158 txt = None
159 T, X, UList = None, None, None
160
161 @classmethod
162 def plot_ani(cls, burgersObj):
163 cls.fig = plt.figure(figsize=(6, 4))
164 cls.ax1 = plt.subplot()
165 cls.line = cls.ax1.plot([], [], lw=3)[0]
166 cls.txt = cls.ax1.text(x=0.8, y=0.8, s="t = {:.3f}".format(0))
167 cls.T, cls.X, cls.UList = burgersObj.get_solu()
168
169 ani = animation.FuncAnimation(cls.fig, cls.update, frames=numpy.arange(len(cls.UList)), init_func=cls.init, blit=True, interval=50, repeat=True)
170 ani.save("plot_ani.gif", writer="PillowWriter", fps=20)
171
172 plt.close()
173
174
175 @classmethod
176 def update(cls, frame):
177 cls.line.set_data(cls.X, cls.UList[frame])
178 cls.txt.set_text("t = {:.3f}".format(cls.T[frame]))
179 return cls.line, cls.txt
180
181
182 @classmethod
183 def init(cls):
184 cls.ax1.set(xlim=(0, 1), ylim=(-1, 1), xlabel="x", ylabel="u")
185 return cls.line, cls.txt
186
187
188 @staticmethod
189 def plot_fig(burgersObj):
190 T, X, UList = burgersObj.get_solu()
191
192 fig = plt.figure(figsize=(6, 4))
193 ax1 = plt.subplot()
194 for U in UList:
195 ax1.plot(X, U)
196 ax1.set(xlabel="x", ylabel="u")
197
198 fig.savefig("plot_fig.png", dpi=100)
199 # plt.show()
200 plt.close()
201
202
203
204 if __name__ == "__main__":
205 burgersObj = BurgersEq(200, 100)
206 BurgersPlot.plot_ani(burgersObj)
207 # BurgersPlot.plot_fig(burgersObj)