大概思路是對的,但是查老師可能會出現幻覺,小心食用 😃
這段代碼是在初始化迭代法求解器,構建迭代矩陣和分裂矩陣。以下是詳細解釋:
if init_from_func or init_from_input:# 1. 存儲剛度矩陣self.stiff_p = stiff_p# 2. 矩陣分裂:將剛度矩陣分解為下三角、對角、上三角部分l_p = np.tril(self.stiff_p, -1) # 嚴格下三角部分d_p = np.diag(np.diag(self.stiff_p)) # 對角部分u_p = np.triu(self.stiff_p, 1) # 嚴格上三角部分# 3. 組合常用矩陣塊lu_p = l_p + u_p # 非對角部分(L+U)ld_p = l_p + d_p # 下三角+對角(L+D)# 4. 根據求解方法選擇分裂方式if self.solver_method in ['Jacobi', 'CG', 'MG-J']:self.m_p = d_p # Jacobi方法:M = Dself.n_p = lu_p # N = L + Uelif self.solver_method in ['GS', 'MG-GS']:self.m_p = ld_p # Gauss-Seidel方法:M = L + Dself.n_p = u_p # N = Uelse:raise ValueError('Incorrect solver method')# 5. 計算 M?1N(迭代矩陣的關鍵組成部分)self.m_inv_n_p = np.linalg.solve(self.m_p, self.n_p)# 6. 構造完整的迭代矩陣 Gself.g_mat = (np.eye(stiff_p.shape[0]) - configs.OMEGA *np.linalg.solve(self.m_p, self.stiff_p))
🔍 關鍵概念說明:
1. 矩陣分裂(Matrix Splitting)
迭代法的核心思想:A = M - N
,其中:
M
是容易求逆的矩陣N
是剩余部分
2. 不同方法的分裂方式
Jacobi方法:
A = D - (L + U)
M = D, N = L + U
迭代矩陣:G = I - ω·D?1·A
Gauss-Seidel方法:
A = (L + D) - U
M = L + D, N = U
迭代矩陣:G = I - (L + D)?1·A
3. 變量含義:
self.m_p
: 預處理矩陣 Mself.n_p
: 剩余矩陣 Nself.m_inv_n_p
: M?1N,用于迭代更新self.g_mat
: 完整的迭代矩陣 G
🎯 迭代矩陣的作用:
迭代公式:
u^{(k+1)} = G·u^{(k)} + M?1·f
其中 G = I - ω·M?1·A
是迭代矩陣
收斂性分析:
- 當
G
的譜半徑 ρ(G) < 1 時,迭代收斂 - 特征值分析可以預測收斂速率
📊 應用場景:
- ‘Jacobi’: 標準Jacobi迭代
- ‘CG’: 可能用于預處理共軛梯度法
- ‘MG-J’: 多重網格中的Jacobi光滑器
- ‘GS’: Gauss-Seidel迭代
- ‘MG-GS’: 多重網格中的Gauss-Seidel光滑器
這段代碼為后續的迭代求解和收斂性分析準備了必要的矩陣組件。
這段代碼實現了在迭代過程中更新各種誤差指標的功能。以下是詳細解釋:
def update_metrics(self, u_approx, index):# 1. 計算殘差residual = utils.compute_residual(self.stiff_p, self.f_p, u_approx,non_bc=self.solvers[0].non_bc)self.residuals[index, :] = residual# 2. 計算誤差error = u_approx - self.u_trueself.errors[index, :] = error# 3. 計算殘差范數和誤差范數self.residual_norms[index] = np.sqrt(np.mean(residual ** 2))self.error_norms[index] = np.sqrt(np.mean(error ** 2))# 4. 計算模態誤差(將誤差投影到特征模態上)if configs.DIMENSIONS == 1:scores = np.linalg.solve(self.eigenvectors, self.errors[index, 1:-1])else:scores = np.linalg.solve(self.eigenvectors,self.errors[index, self.solvers[0].non_bc])self.modes_errors[index, :] = \scores[np.array(self.modes_of_interest)-1]
🔍 詳細步驟說明:
1. 計算殘差
residual = utils.compute_residual(self.stiff_p, self.f_p, u_approx, non_bc=self.solvers[0].non_bc)
- 計算當前解的殘差:
r = f - A·u
non_bc
參數排除邊界點(只考慮內部點)
2. 計算誤差
error = u_approx - self.u_true
- 計算與真實解的誤差:
e = u_approx - u_exact
3. 計算范數
self.residual_norms[index] = np.sqrt(np.mean(residual ** 2)) # L2范數
self.error_norms[index] = np.sqrt(np.mean(error ** 2)) # L2范數
- 計算殘差和誤差的L2范數(均方根)
4. 計算模態誤差(核心部分)
# 1D情況:排除邊界點
if configs.DIMENSIONS == 1:scores = np.linalg.solve(self.eigenvectors, self.errors[index, 1:-1])
# 多維情況:使用non_bc掩碼
else:scores = np.linalg.solve(self.eigenvectors,self.errors[index, self.solvers[0].non_bc])# 提取感興趣模態的誤差
self.modes_errors[index, :] = scores[np.array(self.modes_of_interest)-1]
🎯 模態誤差計算原理:
數學基礎:
誤差向量可以表示為特征模態的線性組合:
e = Σ c_i · φ_i
其中 c_i
是模態系數(即模態誤差)
計算方法:
通過求解線性系統:
Φ · c = e
其中:
Φ
: 特征向量矩陣(列是特征模態)c
: 模態系數向量e
: 誤差向量
結果:
scores[i]
就是第 i+1
個模態的誤差幅度
📊 在文獻中的應用:
這正好對應了Zhang等(2024)論文圖2C第四列,用于顯示:
- 模態1(低頻):收斂最慢,DeepONet重點處理
- 模態5(中頻):中等收斂速度
- 模態10(高頻):收斂最快,Jacobi處理效果好
💡 索引調整:
scores[np.array(self.modes_of_interest)-1]
-1
是因為Python索引從0開始,而模態編號從1開始- 例如:模態1對應
scores[0]
,模態5對應scores[4]
這個函數是分析迭代法頻譜特性的核心工具,幫助理解不同頻率分量的收斂行為。