一種不同的美德:把帳記得分毫不差
這一級的前四篇造出了一台機器:把偏微分方程重述成它的弱形式,用網格形狀函數張出解,施以伽遼金投影,再解所得的剛度矩陣系統。這台機器擅長橢圓型問題,如彈性力學與穩態傳熱——在那些地方,對一個近似最該要求的,是它在平均的、能量的意義下接近真解。但還有一整個物理世界,那裡「接近」並不是你最需要守護的性質。當你模擬空氣掠過機翼,或洪水沿河而下時,你絕不能悄悄違反的那個量,叫做守恆:系統裡的質量、動量與能量,只能因為穿越它的邊界而流動才改變,絕不能因為你格式裡一次捨入的差錯,憑空漏進稀薄空氣裡。
守恆憑什麼配當那條主宰原則?因為流體的支配方程本身就是喬裝過的守恆律——它們陳述的是:任何區域內部的東西,其變化率等於穿越該區域邊界的東西之淨流量。一個精確尊重這一點的格式,即使粗疏,也會把震波位置、總質量與長時間行為算對;而一個違反它的格式,可以看起來平滑又像樣,卻仍然漂向一個物理上不可能的答案,一次一絲地製造或摧毀質量,直到走了一百萬步之後,河裡裝著錯誤份量的水。有限體積法(FVM) 從根基上就被造來讓那種漏失在結構上不可能發生。正因如此,它是計算流體力學的主力馬。
從守恆律到控制體積
從一維裡最簡單的守恆律開始:u_t + f(u)_x = 0。從物理上讀它。量 u 是一個密度——比方說單位長度的質量——而 f(u) 是它的通量,即那個量流經一點的速率。這個方程說:密度隨時間改變,只因為從一側進來的通量多過從另一側離開的。對速度為 a 的純輸運,通量是 f(u) = a*u;對交通流或淺水波它是非線性的,但形式相同。有限元素法此刻會去乘一個測試函數。有限體積法做的事更字面、也更物理:它把方程拿起來,在一小塊空間——一個控制體積——上做積分,問的不是「這在逐點意義下成立嗎?」,而是「這個胞的收支平衡嗎?」
把直線剁成胞;把第 i 個胞叫做從 x_{i-1/2} 到 x_{i+1/2} 的區間,寬度為 h。在那個胞上對 u_t + f(u)_x = 0 積分。第一項變成胞內總量的變化率;第二項,藉由微積分基本定理,塌縮成兩個胞面上通量之差:從左面進入的通量,減去從右面離開的通量。把 U_i(t) 定義為胞平均,即 u 在胞 i 上的積分除以 h——不是某一點的值,而是整個胞裡的平均密度。胞 i 那個精確、尚未任何近似的收支是 h * dU_i/dt = f(u 在 x_{i-1/2}) - f(u 在 x_{i+1/2})。這無非是把記帳精確化:一個箱子裡的存量,正好以「流進的速率減流出的速率」改變。
conservation law: u_t + f(u)_x = 0 u = density, f(u) = flux
integrate over cell i = [x_{i-1/2}, x_{i+1/2}], width h, U_i = cell average
d/dt ( integral of u over cell i ) + [ f at right face - f at left face ] = 0
h * dU_i/dt = f(x_{i-1/2}) - f(x_{i+1/2}) <- EXACT so far
replace true face fluxes by NUMERICAL fluxes F:
dU_i/dt = -( F_{i+1/2} - F_{i-1/2} ) / h
note: F_{i+1/2} leaves cell i and ENTERS cell i+1 with the SAME value
-> whatever cell i loses, cell i+1 gains -> nothing is created數值通量正是守恆變得自動之處
上面那個收支是精確的,但它要的是每個胞面上的真通量,而我們在那裡並沒有真解——我們只知道胞平均,每個胞一個數。所以我們必須從一個面兩側的胞平均,去猜每個面的通量。那個猜測就是數值通量,記作 F_{i+1/2},是左右兩個鄰居的函數:F_{i+1/2} = F(U_i, U_{i+1})。把精確的面通量換成 F,就把精確的收支變成一個可計算的更新 dU_i/dt = -(F_{i+1/2} - F_{i-1/2}) / h。一切如今都繫於把 F 選好——而整個方法最重要的那個結構性事實,就在這裡。
注意胞 i 與胞 i+1 之間的那個面是共用的:它既是 i 的右面、又是 i+1 的左面。若兩個胞都用同一個公式 F(U_i, U_{i+1}) 在那裡算通量,它們用的是字面上完全相同的那個數。所以更新從胞 i 跨越那個面扣掉多少,就恰好是它加給胞 i+1 的多少。把更新對所有胞求和,內部的通量便兩兩相消——一個伸縮級數——只剩下區域兩個遠端的通量。於是整個格點裡 u 的總量,只透過外邊界改變,這正是守恆,而且不論網格多粗、F 多粗糙,它都成立到機器精度。這就是 FVM 受信賴的深層理由:守恆不是一個你往它調校的準確度性質,它是記帳本身的一個代數恆等式。
迎風法:尊重風往哪邊吹
F(U_i, U_{i+1}) 該是什麼?天真的選擇是取平均,對線性通量 f(u) = a*u 取 F = a * (U_i + U_{i+1}) / 2。代進去,你會懊惱地發現你重建了一個中心格式——而如同你兩篇之前所見,純對流的中心空間離散有純虛的半離散特徵值,在前向尤拉法下不穩定,不論步長多小都會炸開。修正的辦法,是所有數值偏微分方程裡最具物理意味的想法之一:迎風法。在 u_t + a*u_x = 0 裡,資訊朝單一個方向、以速度 a 傳播。若 a > 0,風由左吹向右,於是抵達一個面的值,來自它左側那個胞——上風側。就從那裡取通量:a > 0 時 F_{i+1/2} = a*U_i,a < 0 時 F_{i+1/2} = a*U_{i+1}。別跨著風取平均;要迎著風去看。
這正是你在有限差分法下見過的迎風格式,如今從通量的圖像裡有機地長了出來,而它是穩定的——但只是條件穩定。用前向尤拉法在時間上推進它,只在CFL 條件成立時穩定:那個無因次數 |a|*h_t/h,稱為庫朗數,必須至多為 1。從物理上看,CFL 數是風在一個時間步內跨過一個胞的比例,而這個條件說:你不可讓資訊在單一步內跳過一整個胞——數值的依賴域必須包住真正的那個。迎風法使格式穩定;CFL 數告訴你那份穩定容許多大的步長。隱式時間步進解除了 CFL 上限,代價是每一步解一個線性系統,正是你在有限差分那一級權衡過的那個取捨。
迎風法買到了穩定,但它只有一階準確度 O(h),而那個低階表現為沉重的數值耗散——u 裡一道銳利的階躍被抹成一道和緩的斜坡,彷彿格式悄悄加了一劑人工黏性。把它磨利的辦法,是在每個胞內重建一條帶斜率的直線、而非一個扁平的平均(一個更高階的重建),於是在光滑的部分準確度跳到 O(h^2)。但生硬的高階重建會在震波附近過衝,捏造出虛假的波紋——正是糾纏高階格式的那個色散振鈴。解藥是一個斜率限制器:它盯著資料,在解正陡峭成震波之處,把重建的斜率壓平、退回一階,於是在光滑流動上保有高階方法那份俐落的解析度,同時拒絕在不連續處製造新的極大或極小。
有限體積法的位置,以及誠實的細則
退一步看這個家族。有限差分法要求偏微分方程在點上成立;有限元素法要求它弱地、對著測試函數成立,在平均的能量意義下最小化一個誤差;有限體積法要求每個胞的收支平衡,把守恆當作一個恆等式執行。這是對同一個問題的三個答案——我該如何把一個連續的偏微分方程,變成有限多條方程?——而每一個都有它發光的領域:有限元素法用於結構與複雜幾何上的橢圓型問題,有限體積法用於守恆律與流體,有限差分法用於簡單的規則區域。它們甚至會交融:間斷伽遼金法把有限元素那種在每個胞內的高階形狀函數,與有限體積那種跨越胞面的通量交換融在一起,一次同時得到高準確度與精確守恆。
誠實的但書,就是這整座階梯一貫的紀律,只是被流體的場景磨得更利。每一個數值答案都是近似的:面通量是從鄰居猜出來的,胞積分本身是用胞平均估出來的,而這一切都在浮點數裡運行。準確度依舊是條件數乘以穩定性,所以一個在嚴重扭曲的網格上、或在近乎奇異的震波旁的、漂漂亮亮守恆的格式,仍可能損失位數;守恆守護的是全域收支,不是局部的條件數。淺水方程或尤拉方程這類非線性通量,使得連「正確的通量」都成了一個研究課題——精確與近似的黎曼解算器之所以存在,正是因為跨越一道震波去正確選擇 F(U_i, U_{i+1}) 真的很難,而一個草率的通量,可能麻利地收斂到一個自信滿滿卻錯誤的、非物理的解。