130
OpenFOAM 空間の離散化と係数行列の取り扱い Fumiya Nozaki 最終更新日: 2014年8月17日 日本語版 Keywords: OpenFOAM 有限体積法 係数行列

OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

Embed Size (px)

Citation preview

Page 1: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

OpenFOAM

空間の離散化と係数行列の取り扱い

Fumiya Nozaki

最終更新日: 2014年8月17日

日本語版

Keywords: • OpenFOAM • 有限体積法 • 係数行列

Page 2: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

2

はじめに

この資料では, 数値流体力学(CFD)の基本である

• 空間の離散化(discretization) や • その結果得られる代数方程式系の係数行列(coefficient matrix)の処理

などについて,オープンソースソフトウェアの1つである OpenFOAM® がどのように行っているのかをできるだけ平易に解説することを目指して作成しました.

Page 3: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

3

目次

Chapter 1:離散化の概要

Chapter 2:係数行列の表示(ソルバーのカスタマイズ)

Chapter 3:係数行列の表示(gdbOF の使用)

Chapter 4:空間の離散化

Chapter 5:境界条件の離散化

Chapter 6:simpleFoam の解説

Chapter 7:pUCoupledFoam の解説

参考文献

Page 4: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

4

Chapter 1

数値解法の一般的な事柄を理解しましょう.

Page 5: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

5

非圧縮性流体の運動方程式

非圧縮性流体の運動は,次の方程式で記述されます. • 質量保存則(連続の式)

𝛻 ∙ 𝒖 = 0

• 運動量保存則 𝜕𝒖

𝜕𝑡+ 𝒖 ∙ 𝛻 𝒖 = −

1

𝜌𝛻𝑝 + 𝛻 ∙ 𝜈𝛻𝒖

Navier–Stokes 方程式と呼ばれるこの方程式を解析的に解くことができれば,各時刻 𝑡,各場所 𝒙 での流速 𝒖 𝒙, 𝑡 ,圧力 𝑝 𝒙, 𝑡 の値を知ることができます

が, これを数学的に解く問題は,アメリカのクレイ数学研究所からその解決に100万ドルの懸賞金がかけられている数学上の未解決問題 [1] の一つであり,非常に難しい問題です.

Page 6: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

6

近似的なアプローチ

連続の世界で厳密に解く 離散化された世界で近似的に解く

厳密に解くことが難しいので,工学の世界では近似的に解くことが広く行われています.

𝒖 𝒙, 𝑡

𝑝 𝒙, 𝑡

𝒖 𝒙𝒊, 𝑡𝑗

𝒙1 𝒙2 𝒙3

𝒙4 𝒙5 𝒙6

𝑝 𝒙𝒊, 𝑡𝑗

時間の離散化:有限個の時刻 𝑡𝑗 での値を求める

空間の離散化:有限個 𝑁 の位置 𝒙𝑖 での流速,圧力の値を求める

上図は,𝑁 = 6 の場合

Page 7: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

隣接する点での変数値がどう関係しているか

上記の離散化の方法により, この関係式を導く考え方が異なります.

7

空間の離散化の方法

空間の離散化には様々な方法があります. 空間の離散化の方法 [2]

• 差分法(finite difference method : FDM) • 有限体積法(finite volume method : FVM) • 有限要素法(finite element method : FEM)

など

空間の離散化の目的

有限個の位置 𝒙𝑖 での流速や圧力などの変数の値を関係づける代数方程式を導きます.

𝑝1 𝑝2 𝑝3

𝑝4 𝑝5 𝑝6

𝑐1𝑝1 + 𝑐2𝑝2 + 𝑐4𝑝4 = 0 どのような関係?

Page 8: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

8

OpenFOAMでは?

OpenFOAM®では,空間の離散化に有限体積法を使用しています [3].

主要な商用 CFD ソフトウェアの多くも有限体積法を採用しています.

有限体積法の解説 春日さんの資料 [4] が分かりやすくてお勧めです.

面中心での変数の値の計算方法に注意して読んでみて下さい.

Page 9: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

9

空間の離散化の方法

有限体積法では,計算領域を多面体により分割します(下図).

この多面体はコントロールボリューム(以下 CV とも言う)やセルと呼ばれます.

OpenFOAM では • CV には何面体でも使用できます. • CV の各界面は面やフェイス(face)と呼ばれ,何角形でも使用できます. • 内部フェイスには必ずその両側にそれを共有する2つの CV が存在します. • 全ての変数値は CV の中心点で求められます(コロケート格子).

フェイス f の両側に2つの コントロールボリューム

7面体のCV

6面体のCV

Page 10: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

10

フェイス中心の値の計算

有限体積法ではガウス積分を使用して,各コントロールボリュームでの体積積分をその界面であるフェイスでの面積積分に変換して計算します. 例えば,勾配項 𝛻𝜙 は,

OpenFOAMのフェイス中心での値の計算 変数の値はセル中心において計算されるので,各フェイスについてその両側に

ある2つのセルの中心での値 𝜙𝑃,𝜙𝑁 を用いて,𝜙𝑓 の値を計算します.

𝛻𝜙𝑑𝑉𝑉

= 𝜙𝒏𝑑𝑆𝑆

~ 𝜙𝑓𝑺𝑓𝑓

ガウス積分 近似

フェイス中心での値 𝝓𝒇 が必要!

𝜙𝑃 𝜙𝑁 𝜙𝑓

Page 11: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

11

各CVで得られる代数方程式

7ページと8ページの から,OpenFOAMでは 離散化により,各CVでは次式のような代数方程式が得られます.

𝐴𝑝𝜙𝑝 + 𝐴𝑁𝜙𝑁𝑁

= 𝑠𝑃

𝜙𝑝 𝜙𝑁

注目するCV の各フェイスを共有する 全てのCV に関する和

OpenFOAMでは,あるCVにおける離散化式には, • そのCVのセル中心値と • そのCVとフェイスを共有するCVのセル中心値 のみが現れます.

Page 12: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

各CVで立てた式を連立して解くことで,全てのCV中心での変数値を求めることができます.

各CVに番号を付けて,係数行列 𝐴 の性質を見てみましょう.

12

係数行列の性質

𝜙1⋮𝜙9

=

𝑠1⋮𝑠9

𝐴

係数行列

1 2 3

6 5 4

7 8 9

対角成分 一色で色づけ

値が0ではない成分のみ色づけ

非対角成分 各フェイスについて,その 両側のCVに関係する成分を 同じ色で色づけ

右辺ベクトル

Page 13: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

13

係数行列の性質

1 2 3

6 5 4

7 8 9

2番目のCVと3番目のCVが共有するフェイスを見てみます.

注目するフェイスが離散化に使われるのはこの2ケースです.

2 3 2 3

(ⅰ)2番目のCVで離散化 (ⅱ)3番目のCVで離散化

Page 14: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

14

係数行列の性質

これまでの内容をまとめると, 係数行列の性質

• 非零要素は, -対角成分:CVの数だけ存在 -非対角成分:上三角行列と下三角行列の中に内部フェイスの数ずつ存在

• 上三角行列内の非零要素と下三角行列内の非零要素は,各内部フェイスに関してペアを構成しています.

OpenFOAMでは,上記の性質を利用して,係数行列の非零要素のみを効率的に保持しています.

Page 15: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

15

係数行列のデータの持ち方:lduMatrix クラス

OpenFOAMの係数行列のデータの持ち方

係数行列を対角行列と上三角行列と下三角行列とに分けて,それぞれの非零成分のみを配列に格納しています.

• 対角成分の配列: diag • 上三角行列の非零成分の配列: upper • 下三角行列の非零成分の配列: lower

□ ⋯ □⋮ ⋱ ⋮□ ⋯ □

『lduMatrix』クラス

upper

lower

diag

3つの配列 非零成分のみ保存

Page 16: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

16

係数行列のデータの持ち方:lduAddressing クラス

前ページの3つの配列には,係数行列の全ての非零要素が格納されていますが,これだけでは,それらが係数行列の何行何列目の成分なのかが分かりません. この情報を取り扱うのが,『lduAddressing』クラスです.

具体的には各内部フェイスについて,その番号とその両側にある2つのCVの番号との対応関係の情報を扱います.

• lowerAddr: 小さい方のセル番号 • upperAddr: 大きい方のセル番号

7番目の内部フェイス

3番目のCV 5番目のCV

例えば,左図の場合 𝑙𝑜𝑤𝑒𝑟𝐴𝑑𝑑𝑟 7 = 3 𝑢𝑝𝑝𝑒𝑟𝐴𝑑𝑑𝑟 7 = 5

です.

Page 17: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

17

簡単な例で見てみましょう!

-1- -2- -3-

-6- -5- -4-

-7- -8- -9-

(数字はセル番号)

2番目のセルでの離散化式における5番目のセルの係数

𝐴 𝑙𝑜𝑤𝑒𝑟𝐴𝑑𝑑𝑟 𝑘 𝑢𝑝𝑝𝑒𝑟𝐴𝑑𝑑𝑟 𝑘 = 𝑢𝑝𝑝𝑒𝑟 𝑘

5番目のセルでの離散化式における2番目のセルの係数

𝐴 𝑢𝑝𝑝𝑒𝑟𝐴𝑑𝑑𝑟 𝑘 𝑙𝑜𝑤𝑒𝑟𝐴𝑑𝑑𝑟 𝑘 = 𝑙𝑜𝑤𝑒𝑟 𝑘

3×3のメッシュ 係数行列 このフェイスの 番号が 𝑘 だと すると

Page 18: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

18

owner セルと neighbour セル

OpenFOAMでは,内部フェイスの両側にある2つのセル(CV)の内, • 番号が小さい方をそのフェイスの owner セル • 番号が大きい方をそのフェイスの neighbour セル

と定義しています.

内部フェイスに関して,lduAddressing クラスでは,

𝐮𝐩𝐩𝐞𝐫𝐀𝐝𝐝𝐫 k > 𝐥𝐨𝐰𝐞𝐫𝐀𝐝𝐝𝐫 k

と定義されているため, • 𝐥𝐨𝐰𝐞𝐫𝐀𝐝𝐝𝐫 k : 𝑘 番目のフェイスの owner セル番号 • 𝐮𝐩𝐩𝐞𝐫𝐀𝐝𝐝𝐫 k : 𝑘 番目のフェイスの neighbour セル番号 という関係が成り立ちます.

Page 19: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

19

連立方程式の取り扱い

離散化により得られる連立方程式の解法は『fvMatrix』クラスが担っています.

• 連立方程式の解法に必要な種々の関数が実装されています:

‐source: ソース項(右辺ベクトル) ‐relax: 係数行列の不足緩和 ‐residual: 残差の計算 ‐faceFluxCorrectionPtr: 非直交補正 ‐flux: 連続式を満たすための流束の修正量

• 境界条件の処理(係数行列の対角成分及びソース項への境界条件からの寄与の計算)を行います: ‐internalCoeffs: 係数行列の対角成分への寄与 ‐boundaryCoeffs: ソース項への寄与

Page 20: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

20

境界条件の取り扱い

境界条件を離散化したときの,係数行列の対角成分への寄与やソース項への寄与は,使用する境界条件のタイプ(fixedValue:ディリクレ条件,zeroGradient:ノイマン条件など)により異なります.

OpenFOAMではこれを取り扱うために,境界条件のタイプごとに以下の4つの関数が定義されており, internalCoeffs 及び boundaryCoeffs はこれらの関数から計算されます.

• 対流項の離散化

- valueInternalCoeffs: 対角成分への寄与 - valueBoundaryCoeffs: ソース項への寄与

• ラプラシアン項の離散化

‐ gradientInternalCoeffs: 対角成分へ寄与 ‐ gradientBoundaryCoeffs: ソース項への寄与

対流項の流束の計算にはCV界面の値が必要なのに対し,ラプラシアン項の流束の計算にはCV界面の勾配が必要であり,境界条件の取り扱いが異なるため,上記のようにそれぞれの項に対し,関数が用意されています.

Page 21: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

Chapter 2

実際に1次元のラプラス方程式を解くことで,OpenFOAMへの理解を深めましょう.

21

Page 22: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

22

参考にしたテキスト

H.Versteeg, W.Malalasekera 著 『An Introduction to Computational Fluid Dynamics: The Finite Volume Method』

有限体積法について,理論から計算例の紹介までとても内容が豊富です.

記述も丁寧なので,学生さんにもおすすめです.

著者のホームページ • Henk Versteeg先生

http://www.lboro.ac.uk/departments/mechman/staff/henk-versteeg.html

• W.Malalasekera先生 http://lupo.lboro.ac.uk/staff/malalasekera.html

お二人とも英国のラフバラー大学の先生です.

Page 23: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

早速,次の定常拡散方程式を数値的に解いてみましょう. 支配方程式:ラプラス方程式

境界条件

23

問題設定:一次元の定常熱伝導問題

𝑑

𝑑𝑥𝑘𝑑𝑇

𝑑𝑥= 0

0.5m A

𝑇𝐴 = 100℃ 𝑇𝐵 = 500℃

B

𝑇 0 = 100 𝑇 0.5 = 500

断面積 10 × 10−3 𝑚2

𝑘 = 1000 𝑊𝑚−1𝐾−1 熱伝導率

Page 24: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

24

この問題の解析解

この問題の解析解は簡単に求められます.

𝑇 = 800𝑥 + 100 ℃

線形的な温度変化

Page 25: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

25

何をするの?

この問題は,OpenFOAMに付属のソルバーである

laplacianFoam を使用することで簡単に解けてしまいますが,ここではこれを改造して,

離散化して得られる係数行列を表示できるようにする

ことを目指します.

Page 26: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

laplacianFoam ソルバーのフォルダをコピーして,mylaplacianFoam フォルダを作成します.

mylaplacianFoam フォルダに移動し,laplacianFoam.C ファイルの名前を

変更します.

Make フォルダ内の files ファイルの内容を変更します.

26

作業1:準備

$ sol $ cd basic $ cp –r laplacianFoam mylaplacianFoam

$ cd mylaplacianFoam $ mv laplacianFoam.C mylaplacianFoam.C

laplacianFoam.C EXE = $(FOAM_APPBIN)/laplacianFoam

mylaplacianFoam.C EXE = $(FOAM_USER_APPBIN)/mylaplacianFoam

変更前

変更後

Page 27: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

27

作業2:mylaplacianFoam.C の変更

#include "fvCFD.H" #include "simpleControl.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // int main(int argc, char *argv[]) { #include "setRootCase.H" #include "createTime.H" #include "createMesh.H" #include "createFields.H" simpleControl simple(mesh); // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Info<< "¥nCalculating temperature distribution¥n" << endl; while (simple.loop()) { Info<< "Time = " << runTime.timeName() << nl << endl; while (simple.correctNonOrthogonal()) { solve ( fvm::ddt(T) - fvm::laplacian(DT, T) ); } #include "write.H" Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s" << " ClockTime = " << runTime.elapsedClockTime() << " s" << nl << endl; } Info<< "End¥n" << endl; return 0; } // ************************************************************************* //

mylaplacianFoam.C の内容(下記)を次ページのように変更します.

変更前

Page 28: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

28

作業2:mylaplacianFoam.C の変更

#include "fvCFD.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // int main(int argc, char *argv[]) { #include "setRootCase.H" #include "createTime.H" #include "createMesh.H" #include "createFields.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Info<< "¥nCalculating temperature distribution¥n" << endl; while (runTime.loop()) { fvScalarMatrix TEqn(fvm::laplacian(k, T)); TEqn.solve(); forAll(T, cellI) { Info<< "X = " << mesh.C()[cellI].component(vector::X) << ", T = " << T[cellI] << endl; } runTime.writeAndEnd(); } Info<< "End¥n" << endl; return 0; } // ************************************************************************* //

変更後の mylaplacianFoam.C ファイルです.

𝑑

𝑑𝑥𝑘𝑑𝑇

𝑑𝑥= 0 を離散化して解く部分です.

各セル中心の X 座標とそこでの温度 T を 書き出します.

変更後

Page 29: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

29

作業3:createFields.H の変更

Info<< "Reading field T¥n" << endl; volScalarField T ( IOobject ( "T", runTime.timeName(), mesh, IOobject::MUST_READ, IOobject::AUTO_WRITE ), mesh ); Info<< "Reading transportProperties¥n" << endl; IOdictionary transportProperties ( IOobject ( "transportProperties", runTime.constant(), mesh, IOobject::MUST_READ_IF_MODIFIED, IOobject::NO_WRITE ) ); Info<< "Reading diffusivity DT¥n" << endl; dimensionedScalar DT ( transportProperties.lookup("DT") );

createFields.H の内容(下記)を次ページのように変更します.

変更前

Page 30: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

30

作業3:createFields.H の変更

Info<< "Reading field T¥n" << endl; volScalarField T ( IOobject ( "T", runTime.timeName(), mesh, IOobject::MUST_READ, IOobject::AUTO_WRITE ), mesh ); Info<< "Reading transportProperties¥n" << endl; IOdictionary transportProperties ( IOobject ( "transportProperties", runTime.constant(), mesh, IOobject::MUST_READ_IF_MODIFIED, IOobject::NO_WRITE ) ); Info<< "Reading diffusivity k¥n" << endl; dimensionedScalar k ( transportProperties.lookup(“k") );

初期・境界条件をファイルから読み込み,変数Tを定義しています.

熱伝導率 k を transportProperties ファイルから読み込みます. 問題設定に合わせて, 記号を DT から k に 変更しています.

変更後の createFields.H ファイルです.

変更後

Page 31: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

31

作業4:確認計算

作業が半分終了したので,ここで確認計算をしてみましょう! 計算実行に必要なファイルを下記 URL にアップロードしてあります. https://www.dropbox.com/s/lbjd9r6zkmz5j9e/OpenFOAM_Practice1_20140316.zip

ダウンロードしたファイルを解凍すると,2つのフォルダがあります.

• mylaplacianFoam:

これまでの作業で作成したソルバーです.

• testCase1: 22ページの問題の計算条件を設定したケースです.

Page 32: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

32

作業4:確認計算

まず,mylaplacianFoam をコンパイルします.

計算を実行してみましょう!

$ sol $ cd basic/mylaplacianFoam $ wmake

ケースフォルダに移動します. $ cd testCase1 計算格子を作成します. $ blockMesh 作成したソルバーを実行します. $ mylaplacianFoam

Page 33: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

33

作業4:確認計算

Create time Create mesh for time = 0 Reading field T Reading transportProperties Reading diffusivity k Calculating temperature distribution DICPCG: Solving for T, Initial residual = 1, Final residual = 1.21266e-16, No Iterations 1 X = 0.05, T = 140 X = 0.15, T = 220 X = 0.25, T = 300 X = 0.35, T = 380 X = 0.45, T = 460 End

計算はすぐに終了し,ターミナル画面に次のような出力があります.

セル中心の X 座標とそこでの温度 T の計算結果です.

ターミナル画面への出力

Page 34: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

計算結果が解析解と一致しているのが確認できます.

それでは次のページからソルバーを更に変更して,

係数行列を出力して確認してみましょう.

34

作業4:確認計算

Page 35: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

35

作業5:mylaplacianFoam.C の変更

mylaplacianFoam.C を下記のように変更します. #include "fvCFD.H“ #include "simpleMatrix.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // int main(int argc, char *argv[]) { #include "setRootCase.H" #include "createTime.H" #include "createMesh.H" #include "createFields.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Info<< "¥nCalculating temperature distribution¥n" << endl; while (runTime.loop()) { fvScalarMatrix TEqn(fvm::laplacian(k, T)); TEqn.solve(); forAll(T, cellI) { Info<< "X = " << mesh.C()[cellI].component(vector::X) << ", T = " << T[cellI] << endl; } #include "matrixWrite.H" runTime.writeAndEnd(); } Info<< "End¥n" << endl; return 0; } // ************************************************************************* //

赤字の2行を追加します.

Page 36: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

36

作業6:matrixWrite.H ファイルの作成

matrixWrite.H の内容は下記の通りです(あと2ページ続きます).

// Investigate the Coefficient Matrix label Nc = mesh.nCells(); //Total number of cells simpleMatrix<scalar> A(Nc); //Coefficient matrix // Initialization of matrix for(label i=0; i<Nc; i++) { A.source()[i] = 0.0; for(label j=0; j<Nc; j++) { A[i][j] = 0.0; } }

行列Aを作成して,初期化しています.

matrixWrite.H Part1

Page 37: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

37

作業6:matrixWrite.H ファイルの作成

// Assigning diagonal coefficients for(label i=0; i<Nc; i++) { A[i][i] = TEqn.diag()[i]; } // Assigning off-diagonal coefficients for(label faceI=0; faceI<TEqn.lduAddr().lowerAddr().size(); faceI++) { label l = TEqn.lduAddr().lowerAddr()[faceI]; label u = TEqn.lduAddr().upperAddr()[faceI]; A[l][u] = TEqn.upper()[faceI]; A[u][l] = TEqn.upper()[faceI]; } // Assigning contribution from BC forAll(T.boundaryField(), patchI) { const fvPatch &pp = T.boundaryField()[patchI].patch(); forAll(pp, faceI) { label cellI = pp.faceCells()[faceI]; A[cellI][cellI] += TEqn.internalCoeffs()[patchI][faceI]; A.source()[cellI] += TEqn.boundaryCoeffs()[patchI][faceI]; } }

matrixWrite.H Part2 行列Aに対角成分を代入しています.

行列Aに非対角成分を代入しています.

境界条件から対角成分への寄与とソース項への寄与分を行列Aに代入しています.

Page 38: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

38

作業6:matrixWrite.H ファイルの作成

Info<< "¥n==Coefficient Matrix==" << endl; for(label i=0; i<Nc; i++) { for(label j=0; j<Nc; j++) { Info<< A[i][j] << " "; } Info<< A.source()[i] << endl; } //Info<< A << endl; Info<< "Solution: " << A.solve() << endl;

行列Aの各成分とソース項(右辺ベクトル)の各成分を書き出します.

『AT=右辺ベクトル』 を解いています.

matrixWrite.H Part3

この解が,作業4の確認計算の解と一致すれば, fvScalarMatrix TEqn(fvm::laplacian(k, T))

の離散化で作成される係数行列を正しく行列Aで再現できたと言えます.

Page 39: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

39

作業7:最終計算

まず,mylaplacianFoam をコンパイルしなおします.

計算を実行してみましょう!

$ sol $ cd basic/mylaplacianFoam $ wclean $ wmake

$ cd testCase1 $ mylaplacianFoam

Page 40: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

40

作業7:最終計算

計算を実行すると,ターミナル画面には次の出力があります.

DICPCG: Solving for T, Initial residual = 1, Final residual = 1.21266e-16, No Iterations 1 X = 0.05, T = 140 X = 0.15, T = 220 X = 0.25, T = 300 X = 0.35, T = 380 X = 0.45, T = 460 ==Coefficient Matrix== -300 100 0 0 0 -20000 100 -200 100 0 0 0 0 100 -200 100 0 0 0 0 100 -200 100 0 0 0 0 100 -300 -100000 Solution: 5(140 220 300 380 460) End

無事解が一致しています!

−300 100000

100−200 10000

0100−200 1000

00100−200 100

000100−300

𝑇1𝑇2𝑇3𝑇4𝑇5

=

−20000000

−100000

以上から,fvScalarMatrix TEqn(fvm::laplacian(k, T)) により作成される 係数行列と右辺ベクトルは以下のようになることがわかりました.

係数行列

右辺ベクトル

Page 41: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

41

Chapter 3

gdbOF ツールを使用して係数行列

を表示してみましょう.

Page 42: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

42

gdbOF について

gdbOF とは GDB(GNU Project Debugger)と共に用いて,OpenFOAM のアプリケーションのデバッグ作業を手助けしてくれるツールです.

何ができるの? • 離散化により得られた係数行列の表示 や • セル中心値や境界値の表示 など他にもいろいろできるようです.詳細は,こちらの資料 [8] をご覧ください.

ダウンロードサイト http://openfoamwiki.net/index.php/Contrib_gdbOF

Page 43: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

43

インストール

自分の環境(Ubuntu 12.04,OpenFOAM v2.3.0)では,以下の手順でインストールができました. 1. (事前準備) OpenFOAM v2.3.0 をデバッグオプションでコンパイル

2. (事前準備) 必要なライブラリのインストール

3. ダウンロードしたファイル GdbOF_v1.01a.tar.gz を解凍

4. 解凍したフォルダ内のインストール用のスクリプトを実行

#- Optimised, debug, profiling:

# WM_COMPILE_OPTION = Opt | Debug | Prof

export WM_COMPILE_OPTION=Debug

etc/bashrc ファイル

(必要があれば)実行権限の付与 $ chmod +x installgdbOF.sh スクリプトを実行 $ ./installgdbOF.sh

$ sudo apt-get install gawk python gdb

Page 44: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

44

何をするの?

再び Part2 で解いた定常熱伝導問題を題材にして

mylaplacianFoam を gdb を使用してデバッグして,

gdbOF により係数行列と右辺ベクトルを表示してみましょう!

Page 45: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

45

作業1,2

作業1:mylaplacianFoam をデバッグオプションでコンパイルし直します.

作業2:ケースフォルダに移動し,GDB を起動します.

$ cd testCase1 $ gdb mylaplacianFoam

GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04 Copyright (C) 2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". For bug reporting instructions, please see: <http://bugs.launchpad.net/gdb-linaro/>... Reading symbols from ~/platforms/linux64GccDPDebug/bin/mylaplacianFoam...done. (gdb)

GDB が起動します.

Page 46: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

作業3:ブレークポイント(プログラムを強制的に一時停止させるポイント)を設定します.

fvSclarMatrix.C ファイルの 170行目で一時停止させるという設定です.

46

作業3

(gdb) break fvScalarMatrix.C:170 No source file named fvScalarMatrix.C. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (fvScalarMatrix.C:170) pending. (gdb)

160 // Solver call 161 solverPerformance solverPerf = lduMatrix::solver::New 162 ( 163 psi.name(), 164 *this, 165 boundaryCoeffs_, 166 internalCoeffs_, 167 psi.boundaryField().scalarInterfaces(), 168 solverControls 169 )->solve(psi.internalField(), totalSource); 170 171 if (solverPerformance::debug) 172 { 173 solverPerf.print(Info.masterStream(mesh().comm())); 174 }

STOP!

Page 47: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

47

作業4

作業4:ソルバーを実行します.

Breakpoint 1 (fvScalarMatrix.C:170) pending. (gdb) run

・・・ Reading diffusivity k Calculating temperature distribution Breakpoint 1, Foam::fvMatrix<double>::solveSegregated (this=0x7fffffffcaf0, solverControls=...) at fvMatrices/fvScalarMatrix/fvScalarMatrix.C:171 171 if (solverPerformance::debug) (gdb)

作業3で指定したブレークポイントでソルバーが停止します.

Page 48: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

48

作業5

作業5:係数行列をファイルに出力します. matrix.txt は出力先のファイル名なので,任意の名前で構いません. 成功すれば,このような出力があるはずです.

Breakpoint 1, Foam::fvMatrix<double>::solveSegregated (this=0x7fffffffcaf0, solverControls=...) at fvMatrices/fvScalarMatrix/fvScalarMatrix.C:171 171 if (solverPerformance::debug) (gdb) pfvmatrixfull this matrix.txt

Saved correctly!

(gdb)

Page 49: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

49

作業6

作業6:ファイルの中身を見てみましょう.

𝐴00 𝐴01 𝐴02 𝐴03 𝐴04 𝐴10 𝐴11 𝐴12 𝐴13 𝐴14 𝐴20 𝐴21 𝐴22 𝐴23 𝐴24 𝐴30 𝐴31 𝐴32 𝐴33 𝐴34 𝐴40 𝐴41 𝐴42 𝐴43 𝐴44

(gdb) pfvmatrixfull this matrix.txt 1 1 3 3 とすると赤枠内のみファイルに出力されます.

小さな誤差はありますが,40ページと同じ係数行列が得られています.

-300.0 100.0 0 0 0 100.0 -200.00000000000006 100.00000000000006 0 0 0 100.00000000000006 -200.0000000000001 100.00000000000006 0 0 0 100.00000000000006 -199.99999999999991 99.99999999999986 0 0 0 99.99999999999986 -300.00000000000057

係数行列の出力フォーマット

Page 50: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

50

作業7

作業7:右辺ベクトルを出力します. 小さな誤差はありますが,40ページと同じ右辺ベクトルが得られています.

(gdb) p *totalSource.v_@5

$6 = {-19999.999999999996, 0, 0, 0, -100000.00000000036}

コマンド中の5は要素数です.

係数行列

右辺ベクトル

Page 51: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

51

Chapter 4

各項の離散化について理解を深めましょう.

これにより,fvSchemes ファイルの設定

の意味が理解できます.

Page 52: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

52

参考となる資料

OpenFOAM の Programmer’s Guide [9] の 2章

Jasak 博士の博士論文 [10] の 3章

を読めば,必要な情報はほとんど得られると思います.

Page 53: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

早速,非圧縮性流体の支配方程式を見てみましょう. それぞれの項には名前がついています.

それぞれの項の離散化の方法を見ていきましょう.

53

方程式の項の分類

𝜕𝒖

𝜕𝑡+ 𝒖 ∙ 𝛻 𝒖 = −

1

𝜌𝛻𝑝 + 𝛻 ∙ 𝜈 𝛻𝒖 + 𝛻𝒖 𝑇

時間微分項

対流項

勾配項

ラプラシアン項

𝛻 ∙ 𝜈𝛻𝒖 + 𝛻 ∙ 𝜈 𝛻𝒖 𝑇

分解

発散項

Page 54: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

54

勾配項の離散化

ガウスの発散定理を使用します.

𝛻𝑝 𝑑𝑉𝑉

= 𝑑𝑺 ∙ 𝑝𝑆

= 𝑺𝑓 ∙ 𝑝𝑓𝑓

𝑺𝑓

P N f

𝑝𝑓

gradSchemes { grad(p) Gauss linear; }

セル中心から補間した

フェイスでの値 𝑝𝑓

ガウスの発散定理 𝑝𝑓 の補間スキーム linear は線形補間.

Page 55: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

55

勾配項の離散化|ソースコード

075 const labelUList& owner = mesh.owner();

076 const labelUList& neighbour = mesh.neighbour();

077 const vectorField& Sf = mesh.Sf();

078

079 Field<GradType>& igGrad = gGrad;

080 const Field<Type>& issf = ssf;

081

082 forAll(owner, facei)

083 {

084 GradType Sfssf = Sf[facei]*issf[facei];

085

086 igGrad[owner[facei]] += Sfssf;

087 igGrad[neighbour[facei]] -= Sfssf;

088 }

089

①内部フェイスでループ

• ①の部分で,内部フェイスをループし,各フェイスにおいて 𝑺𝑓𝜙𝑓 を計算し,その値をそのフェイスを界面とするセルに加えています.

• 087 行で負符号が付いているのは,neighbour セルに関しては,その外向きベクトル

が面積ベクトル 𝑺𝑓 の逆向きのためです(𝑺𝑓 の向きは owner ⇒ neighbour セルと定義されています).

gaussGrad.C

Page 56: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

56

勾配項の離散化|ソースコード

090 forAll(mesh.boundary(), patchi)

091 {

092 const labelUList& pFaceCells =

093 mesh.boundary()[patchi].faceCells();

094

095 const vectorField& pSf = mesh.Sf().boundaryField()[patchi];

096

097 const fvsPatchField<Type>& pssf = ssf.boundaryField()[patchi];

098

099 forAll(mesh.boundary()[patchi], facei)

100 {

101 igGrad[pFaceCells[facei]] += pSf[facei]*pssf[facei];

102 }

103 }

104

105 igGrad /= mesh.V();

106

107 gGrad.correctBoundaryConditions();

②境界フェイスでループ

境界上のフェイスを界面にもつセルの番号のリスト

• ②の部分で,境界フェイスに対して①と同様の計算をしています.

• 境界上のフェイスの法線ベクトルはセル外向きなので,101 行では正の符号.

• 105 行で各セルでの体積積分値をセル体積で除し,勾配を計算しています.

Page 57: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

divSchemes { div(phi,k) Gauss upwind; }

57

対流項の離散化

ガウスの発散定理を使用します.

𝛻 ∙ 𝑼𝑘 𝑑𝑉𝑉

= 𝑑𝑺 ∙ 𝑼𝑘𝑆

= 𝑺𝑓 ∙ 𝑼𝑓 𝑘𝑓𝑓

= 𝐹𝑘𝑓𝑓

ガウスの発散定理

𝑺𝑓

P N f

𝑘𝑓

セル中心から補間した

フェイスでの値 𝑘𝑓

𝑘𝑓 の補間スキーム upwind:風上補間

流束 (flux) 場

Page 58: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

58

対流項の係数行列

補間スキームに “upwind” を使用した場合の係数行列を 見てみましょう.

i

j i

j

F>0

i:owner j:neighbour

𝑘𝑖

𝑘𝑗

<

0

−𝐹

𝐹

0

upwind

Page 59: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

59

対流項の係数行列

i

j i

j

F≦0

i:owner j:neighbour

𝑘𝑖

𝑘𝑗

<

𝐹

0

0

−𝐹

upwind

補間スキームに “upwind” を使用した場合の係数行列を 見てみましょう.

Page 60: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

60

対流項の係数行列

補間の重み w = 1 (F > 0の場合),w = 0 (F ≦0の場合) と定義することで, F の符号に関係なく,係数行列の成分は次のように表現できます.

i

j i

j

𝑘𝑖

𝑘𝑗

<

1 − 𝑤 ∙ 𝐹

−𝑤 ∙ 𝐹

𝑤 ∙ 𝐹

upwind

− 1 − 𝑤 ∙ 𝐹

Page 61: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

61

対流項の離散化|ソースコード

093 fvMatrix<Type>& fvm = tfvm();

094

095 fvm.lower() = -weights.internalField()*faceFlux.internalField();

096 fvm.upper() = fvm.lower() + faceFlux.internalField();

097 fvm.negSumDiag();

098

099 forAll(vf.boundaryField(), patchI)

100 {

101 const fvPatchField<Type>& psf = vf.boundaryField()[patchI];

102 const fvsPatchScalarField& patchFlux = faceFlux.boundaryField()[patchI];

103 const fvsPatchScalarField& pw = weights.boundaryField()[patchI];

104

105 fvm.internalCoeffs()[patchI] = patchFlux*psf.valueInternalCoeffs(pw);

106 fvm.boundaryCoeffs()[patchI] = -patchFlux*psf.valueBoundaryCoeffs(pw);

107 }

108

109 if (tinterpScheme_().corrected())

110 {

111 fvm += fvc::surfaceIntegrate(faceFlux*tinterpScheme_().correction(vf));

112 }

113

114 return tfvm;

gaussConvectionScheme.C

①内部フェイスでの離散化

②境界上のフェイスでの離散化

③補間の補正項の陽的な処理

upwind 以外の場合も同様にして,対流項の係数行列の各成分は,フェイスにおける流束 faceFlux と補間スキームの重み weights から以下のように計算されます.

Page 62: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

例えば,fvSchemes ファイルにおいて “div(phi,k) Gauss upwind;” と設定した場合には, • ”faceFlux” が “phi” を, • ”weights” が “upwind” 補間スキームで定義されている重みを, • ”tinterpScheme_()” が 補間スキーム “upwind” を それぞれ表します.

補正 (correction) を伴う補間スキームについては,111 行でその補正項を陽的に評価

しています.

例えば,“linearUpwind” スキームの場合は,

𝛻 ∙ 𝑼𝑘 𝑑𝑉𝑉

= 𝐹𝑓 ∙ 𝑘 upstream cell + correction𝑓𝑓

= 𝐹𝑓 ∙ 𝑘 upstream cell + 𝐹𝑓 ∙ correction𝑓𝑓𝑓

62

対流項の離散化|ソースコード

109 if (tinterpScheme_().corrected())

110 {

111 fvm += fvc::surfaceIntegrate(faceFlux*tinterpScheme_().correction(vf));

112 }

陰的に処理 ⇒ 係数行列へ 陽的に処理 ⇒ ソース項 (右辺ベクトル)へ

111 行で 加えている項

Page 63: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

63

対流項の離散化|bounded オプション

詳細は次ページから見ていきます.

OpenFOAM v2.2.0 Release Note

Page 64: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

64

対流項の離散化|bounded オプション

0067 template<class Type>

0068 tmp<fvMatrix<Type> >

0069 boundedConvectionScheme<Type>::fvmDiv

0070 (

0071 const surfaceScalarField& faceFlux,

0072 const GeometricField<Type, fvPatchField, volMesh>& vf

0073 ) const

0074 {

0075 return

0076 scheme_().fvmDiv(faceFlux, vf)

0077 - fvm::Sp(fvc::surfaceIntegrate(faceFlux), vf);

0078 }

boundedConvectionScheme.C

divSchemes { div(phi,k) bounded Gauss upwind; }

𝛻 ∙ 𝑼𝑘 を 𝛻 ∙ 𝑼𝑘 − 𝛻 ∙ 𝑼 𝑘 と計算します.

の場合

Page 65: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

65

対流項の離散化|bounded オプション

bounded オプションを使用した場合には,対流項は次のように離散化されます.

𝛻 ∙ 𝑼𝑘 − 𝛻 ∙ 𝑼 𝑘 𝑑𝑉𝑉

= 𝑑𝑺 ∙ 𝑼𝑘𝑆

− 𝛻 ∙ 𝑼 𝑘 𝑑𝑉𝑉

= 𝑺𝑓 ∙ 𝑼𝑓 𝑘𝑓𝑓

− 𝑉𝑝 ∙ 𝑺𝑓 ∙ 𝑼𝑓 𝑓

𝑉𝑝∙ 𝑘𝑝

= 𝐹𝑓𝑘𝑓 − 𝑘𝑝 𝐹𝑓𝑓𝑓

連続の式から,非圧縮流れでは 解の収束に伴って 0 に収束します.

Sp (61ページ) surfaceIntegrate (62ページ)

Page 66: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

66

対流項の離散化|bounded オプション

0098 template<class Type>

0099 Foam::tmp<Foam::fvMatrix<Type> >

0100 Foam::fvm::Sp

0101 (

0102 const DimensionedField<scalar, volMesh>& sp,

0103 const GeometricField<Type, fvPatchField, volMesh>& vf

0104 )

0105 {

0106 const fvMesh& mesh = vf.mesh();

0107

0108 tmp<fvMatrix<Type> > tfvm

0109 (

0110 new fvMatrix<Type>

0111 (

0112 vf,

0113 dimVol*sp.dimensions()*vf.dimensions()

0114 )

0115 );

0116 fvMatrix<Type>& fvm = tfvm();

0117

0118 fvm.diag() += mesh.V()*sp.field();

0119

0120 return tfvm;

0121 }

fvmSup.C

係数行列の 対角成分に加えています.

fvm::Sp(fvc::surfaceIntegrate(faceFlux), vf) の計算

Page 67: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

67

対流項の離散化|bounded オプション

0042 template<class Type>

0043 void surfaceIntegrate

0044 (

0045 Field<Type>& ivf,

0046 const GeometricField<Type, fvsPatchField, surfaceMesh>& ssf

0047 )

0048 {

0049 const fvMesh& mesh = ssf.mesh();

0050

0051 const labelUList& owner = mesh.owner();

0052 const labelUList& neighbour = mesh.neighbour();

0053

0054 const Field<Type>& issf = ssf;

0055

0056 forAll(owner, facei)

0057 {

0058 ivf[owner[facei]] += issf[facei];

0059 ivf[neighbour[facei]] -= issf[facei];

0060 }

0061

0062 forAll(mesh.boundary(), patchi)

0063 {

0064 const labelUList& pFaceCells =

0065 mesh.boundary()[patchi].faceCells();

0066

0067 const fvsPatchField<Type>& pssf = ssf.boundaryField()[patchi];

0068

0069 forAll(mesh.boundary()[patchi], facei)

0070 {

0071 ivf[pFaceCells[facei]] += pssf[facei];

0072 }

0073 }

0074

0075 ivf /= mesh.V();

0076 }

内部フェイスでループ

境界フェイスでループ

fvcSurfaceIntegrate.C

fvm::Sp(fvc::surfaceIntegrate(faceFlux), vf) の計算

Page 68: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

68

対流項の離散化|bounded オプションまとめ

divSchemes { div(phi,k) Gauss upwind; }

divSchemes { div(phi,k) bounded Gauss upwind; }

𝛻 ∙ 𝑼𝑘

𝛻 ∙ 𝑼𝑘 − 𝛻 ∙ 𝑼 𝑘

Page 69: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

69

ラプラシアン項の離散化

ガウスの発散定理を使用します.

𝛻 ∙ Γ𝛻𝜙 𝑑𝑉𝑉

= 𝑑𝑺 ∙ Γ𝛻𝜙𝑆

= Γ𝑓 𝑺𝑓 ∙ 𝛻𝜙 𝑓𝑓

フェイスの法線方向 𝑺𝒇 の 𝜙 の勾配値

Γ𝑓 の補間スキーム laplacianSchemes { default Gauss linear corrected; }

ガウスの発散定理

Page 70: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

70

ラプラシアン項の離散化

𝛻 ∙ Γ𝛻𝜙 𝑑𝑉𝑉

= 𝑑𝑺 ∙ Γ𝛻𝜙𝑆

= Γ𝑓 𝑺𝑓 ∙ 𝛻𝜙 𝑓𝑓

𝑺𝑓

P N

セル中心間を結ぶ線分が その間のフェイスと直交する場合

𝑺𝑓 𝜙𝑁 − 𝜙𝑃𝒅

簡単に離散化できます. が・・・

Page 71: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

71

ラプラシアン項の離散化

実際の計算では,前ページのような 理想的なメッシュは生成できず, ほとんどこちらのケースになります. この場合,

𝑺𝑓 ∙ 𝛻𝜙 𝑓 の評価には工夫が必要です.

𝑺𝑓

P N

• セル中心間を結んだ線分 PN と • フェイスの法線ベクトル とが平行にならない場合

Page 72: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

72

ラプラシアン項の離散化

フェイスの面積ベクトル 𝑺𝑓 を分解 ⇒ 𝑺𝑓 = ∆ + 𝒌

Γ𝑓𝑺𝑓 ∙ 𝛻𝜙 𝑓 = Γ𝑓∆ ∙ 𝛻𝜙 𝑓 + Γ𝑓𝒌 ∙ 𝛻𝜙 𝑓

• 右辺第一項: 陰的に処理 ⇒ 係数行列 • 右辺第二項: 陽的に処理 ⇒ ソース項

= Γ𝑓 ∆𝜙𝑁 − 𝜙𝑃𝒅+ Γ𝑓𝒌 ∙ 𝛻𝜙 𝑓

非直交補正

Page 73: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

73

ラプラシアン項の離散化

∆=𝑺 2

𝒅 ∙ 𝑺𝒅 𝑺 = ∆ + 𝒌

𝑺 ∙ 𝒌 = 0

OpenFOAMでは,Jasak [10] に紹介されている3つの手法の内の 『over-relaxed approach』により非直交補正を行っています.

𝜃

Page 74: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

74

ラプラシアン項の離散化|非直交補正の大きさのコントロール

laplacianSchemes { default Gauss linear uncorrected; }

Γ𝑓𝑺𝑓 ∙ 𝛻𝜙 𝑓 = Γ𝑓 ∆𝜙𝑁 − 𝜙𝑃𝒅+ Γ𝑓𝒌 ∙ 𝛻𝜙 𝑓

laplacianSchemes { default Gauss linear corrected; }

Γ𝑓𝑺𝑓 ∙ 𝛻𝜙 𝑓 = Γ𝑓 ∆𝜙𝑁 − 𝜙𝑃𝒅+ Γ𝑓𝒌 ∙ 𝛻𝜙 𝑓

Page 75: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

75

ラプラシアン項の離散化|非直交補正の大きさのコントロール

laplacianSchemes { default Gauss linear limited 𝝍; }

0 ≤ 𝜓 ≤ 1

Γ𝑓𝑺𝑓 ∙ 𝛻𝜙 𝑓 = Γ𝑓 ∆𝜙𝑁 − 𝜙𝑃𝒅+ Γ𝑓𝒌 ∙ 𝛻𝜙 𝑓 ∙ 𝑙𝑖𝑚𝑖𝑡𝑒𝑟 𝜓

𝜓 =

0

0.333

0.5

1

uncorrected の場合と同じです.

corrected の場合と同じです.

Γ𝑓𝒌 ∙ 𝛻𝜙 𝑓 ≤ 0.5 × ∆𝜙𝑁 − 𝜙𝑃𝒅

Γ𝑓𝒌 ∙ 𝛻𝜙 𝑓 ≤ ∆𝜙𝑁 − 𝜙𝑃𝒅

corrected と uncorrected の 中間的な処理に なっています.

Page 76: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

76

ラプラシアン項の離散化|非直交補正の大きさのコントロール

0051 template<class Type>

0052 tmp<GeometricField<Type, fvsPatchField, surfaceMesh> >

0053 limitedSnGrad<Type>::correction

0054 (

0055 const GeometricField<Type, fvPatchField, volMesh>& vf

0056 ) const

0057 {

0058 const GeometricField<Type, fvsPatchField, surfaceMesh> corr

0059 (

0060 correctedScheme_().correction(vf)

0061 );

0062

0063 const surfaceScalarField limiter

0064 (

0065 min

0066 (

0067 limitCoeff_

0068 *mag(snGradScheme<Type>::snGrad(vf, deltaCoeffs(vf), "SndGrad"))

0069 /(

0070 (1 - limitCoeff_)*mag(corr)

0071 + dimensionedScalar("small", corr.dimensions(), SMALL)

0072 ),

0073 dimensionedScalar("one", dimless, 1.0)

0074 )

0075 );

0076

0077 if (fv::debug)

0078 {

0079 Info<< "limitedSnGrad :: limiter min: " << min(limiter.internalField())

0080 << " max: "<< max(limiter.internalField())

0081 << " avg: " << average(limiter.internalField()) << endl;

0082 }

0083

0084 return limiter*corr;

0085 }

correctedSnGrads.C の Foam::fv::correctedSnGrad <Foam::vector>::correction が呼ばれます.

limiter(𝜓) は以下の limiter に対応しています.

𝜓 の値

Page 77: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

77

ラプラシアン項の離散化

0042 template<class Type>

0043 Foam::tmp<Foam::GeometricField<Type, Foam::fvsPatchField, Foam::surfaceMesh> >

0044 Foam::fv::correctedSnGrad<Type>::fullGradCorrection

0045 (

0046 const GeometricField<Type, fvPatchField, volMesh>& vf

0047 ) const

0048 {

0049 const fvMesh& mesh = this->mesh();

0050

0051 // construct GeometricField<Type, fvsPatchField, surfaceMesh>

0052 tmp<GeometricField<Type, fvsPatchField, surfaceMesh> > tssf =

0053 mesh.nonOrthCorrectionVectors()

0054 & linear<typename outerProduct<vector, Type>::type>(mesh).interpolate

0055 (

0056 gradScheme<Type>::New

0057 (

0058 mesh,

0059 mesh.gradScheme("grad(" + vf.name() + ')')

0060 )().grad(vf, "grad(" + vf.name() + ')')

0061 );

0062 tssf().rename("snGradCorr(" + vf.name() + ')');

0063

0064 return tssf;

0065 }

𝛻𝜙 𝑓

非直交補正中の 𝛻𝜙 𝑓 の補間には,線形補間が使用されます.

correctedSnGrad.C

Page 78: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

78

発散項の離散化

ガウスの発散定理を使用します.

𝛻 ∙ 𝜈 𝛻𝒖 𝑇 𝑑𝑉𝑉

= 𝑑𝑺 ∙ 𝜈 𝛻𝒖 𝑇

𝑆

= 𝑺𝑓 ∙ 𝜈 𝛻𝒖𝑇𝑓

𝑓

divSchemes { div(nu*T(grad(U))) Gauss linear; }

セル中心からフェイスへの 補間スキーム

ガウスの発散定理

Page 79: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

79

ソース項の離散化

ソース項の離散化には,次の3つの方法を使用できます.

1

2

3

Programmer’s Guide P-34

vol*Field として陽的にソース項を 定義します.セル体積をかける必要は ありません.

詳細は,次ページをご覧ください.

詳細は,81ページをご覧ください.

Page 80: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

80

ソース項の離散化

0098 template<class Type>

0099 Foam::tmp<Foam::fvMatrix<Type> >

0100 Foam::fvm::Sp

0101 (

0102 const DimensionedField<scalar, volMesh>& sp,

0103 const GeometricField<Type, fvPatchField, volMesh>& vf

0104 )

0105 {

0106 const fvMesh& mesh = vf.mesh();

0107

0108 tmp<fvMatrix<Type> > tfvm

0109 (

0110 new fvMatrix<Type>

0111 (

0112 vf,

0113 dimVol*sp.dimensions()*vf.dimensions()

0114 )

0115 );

0116 fvMatrix<Type>& fvm = tfvm();

0117

0118 fvm.diag() += mesh.V()*sp.field();

0119

0120 return tfvm;

0121 }

fvmSup.C

2

𝜌𝜙 𝑑𝑉𝑉

= 𝑉𝑃𝜌𝑃𝜙𝑃

ソース項を陰的に扱います.

係数行列の対角成分に加えています.

Page 81: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

81

ソース項の離散化

0190 template<class Type>

0191 Foam::tmp<Foam::fvMatrix<Type> >

0192 Foam::fvm::SuSp

0193 (

0194 const DimensionedField<scalar, volMesh>& susp,

0195 const GeometricField<Type, fvPatchField, volMesh>& vf

0196 )

0197 {

0198 const fvMesh& mesh = vf.mesh();

0199

0200 tmp<fvMatrix<Type> > tfvm

0201 (

0202 new fvMatrix<Type>

0203 (

0204 vf,

0205 dimVol*susp.dimensions()*vf.dimensions()

0206 )

0207 );

0208 fvMatrix<Type>& fvm = tfvm();

0209

0210 fvm.diag() += mesh.V()*max(susp.field(), scalar(0));

0211

0212 fvm.source() -= mesh.V()*min(susp.field(), scalar(0))

0213 *vf.internalField();

0214

0215 return tfvm;

0216 }

3

fvmSup.C

ソース項の処理を符号で 場合分けします.

𝜌𝜙 𝑑𝑉𝑉

= 𝑉𝑃𝜌𝑃𝜙𝑃

𝝆𝑷 > 𝟎 の場合: の場合と同様に陰的に処理 2

𝝆𝑷 < 𝟎 の場合: の場合と同様に陽的に処理 1

Page 82: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

82

Chapter 5

内部フェイスと異なり,境界フェイスにおける離散化では境界条件ごとに異なる取り扱いが必要です.

OpenFOAMでの実装を理解しましょう.

𝒅 𝜙𝑏

𝜙𝑃

Page 83: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

まず境界フェイスにおけるラプラシアンの離散化を考えます.

境界フェイスでは4章で学んだ非直交補正の処理は行われません.

Γ𝑓𝑺𝑓 ∙ 𝛻𝜙 𝑓 = Γ𝑏 𝑺𝑏𝜙𝑏 − 𝜙𝑃𝒅

83

境界フェイスでのラプラシアンの離散化

境界フェイスにおけるラプラシアン流束

𝒅 𝜙𝑏

𝜙𝑃

フェイス面積 𝑺𝑏

(添え字の b は境界上の値の意味です.)

境界隣接セル

Page 84: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

84

境界フェイスでのラプラシアンの離散化|zeroGradient 境界条件

勾配0 (zeroGradient) の条件を課した境界を考えます.

Γ𝑓𝑺𝑓 ∙ 𝛻𝜙 𝑓 = Γ𝑏 𝑺𝑏𝜙𝑏 − 𝜙𝑃𝒅= 𝟎

𝑎11 𝑎1𝑁

𝑎𝑁1 𝑎𝑁𝑁

𝜙1𝜙2⋮𝜙𝑁

=

𝑠1𝑠2⋮𝑠𝑁

=0 (勾配が 0 より)

係数行列の”対角成分”と 右辺ベクトルの両方に 対して寄与がありません.

Page 85: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

85

境界フェイスでのラプラシアンの離散化|fixedValue 境界条件

次に,境界上で値 𝜙𝑏 を規定した場合 (fixedValue) は,

Γ𝑓𝑺𝑓 ∙ 𝛻𝜙 𝑓 = Γ𝑏 𝑺𝑏𝜙𝑏 − 𝜙𝑃𝒅

𝑎11 𝑎1𝑁

𝑎𝑁1 𝑎𝑁𝑁

𝜙1𝜙2⋮𝜙𝑁

=

𝑠1𝑠2⋮𝑠𝑁

= Γ𝑏 𝑺𝑏−1

𝒅𝜙𝑃 + Γ𝑏 𝑺𝑏

1

𝒅𝜙𝑏

係数行列の”対角成分”と 右辺ベクトルの両方に

対して寄与があります.

Page 86: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

86

gradientInternalCoeffs と gradientBoundaryCoeffs

具体的に見てきたように,ラプラシアンを境界フェイスで離散化する際の • 係数行列の対角成分 • 右辺ベクトル への寄与は境界条件によって異なります.

OpenFOAMではこれを取り扱うために,境界条件ごとに次の2つの関数が用意されています. • gradientInternalCoeffs()

係数行列の対角成分への寄与 • gradientBoundaryCoeffs()

右辺ベクトルへの寄与

次のスライドから基本的な境界条件についてこれらの関数を見ていきましょう.

Page 87: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

87

境界フェイスでのラプラシアンの離散化|zeroGradient 境界条件

template<class Type>

tmp<Field<Type> > zeroGradientFvPatchField<Type>::gradientInternalCoeffs() const { return tmp<Field<Type> > (

new Field<Type>(this->size(), pTraits<Type>::zero) ); } template<class Type>

tmp<Field<Type> > zeroGradientFvPatchField<Type>::gradientBoundaryCoeffs() const { return tmp<Field<Type> > (

new Field<Type>(this->size(), pTraits<Type>::zero) ); }

“zeroGradient” (勾配0) 境界条件の場合

係数行列の”対角成分”と 右辺ベクトルの両方に

対して寄与がありません.

zeroGradientFvPatchField.C

Page 88: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

88

境界フェイスでのラプラシアンの離散化|fixedValue 境界条件

“fixedValue” (ディリクレ) 境界条件の場合

template<class Type> tmp<Field<Type> > fixedValueFvPatchField<Type>::gradientInternalCoeffs() const { return -pTraits<Type>::one*this->patch().deltaCoeffs(); }

Γ𝑓𝑺𝑓 ∙ 𝛻𝜙 𝑓 = Γ𝑏 𝑺𝑏−1

𝒅𝜙𝑃 + Γ𝑏 𝑺𝑏

1

𝒅𝜙𝑏

template<class Type> tmp<Field<Type> > fixedValueFvPatchField<Type>::gradientBoundaryCoeffs() const { return this->patch().deltaCoeffs()*(*this); }

係数行列の”対角成分”と 右辺ベクトルの両方に

対して寄与があります.

境界フェイスにおいて, deltaCoeffs() は,フェイス中心点と隣接セル中心点間の距離の逆数を返します.

fixedValueFvPatchField.C

Page 89: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

89

境界フェイスでのラプラシアンの離散化

forAll(vf.boundaryField(), patchi) {

const fvPatchField<Type>& pvf = vf.boundaryField()[patchi];

const fvsPatchScalarField& pGamma = gammaMagSf.boundaryField()[patchi]; const fvsPatchScalarField& pDeltaCoeffs =

deltaCoeffs.boundaryField()[patchi];

if (pvf.coupled()) { //省略 cyclic境界条件などの場合の処理 } else {

fvm.internalCoeffs()[patchi] = pGamma*pvf.gradientInternalCoeffs();

fvm.boundaryCoeffs()[patchi] = -pGamma*pvf.gradientBoundaryCoeffs(); } }

ラプラシアンの離散化のコードを確認してみましょう.

Γ𝑓𝑺𝑓 ∙ 𝛻𝜙 𝑓 = Γ𝑏 𝑺𝑏−1

𝒅𝜙𝑃 + Γ𝑏 𝑺𝑏

1

𝒅𝜙𝑏

cyclic境界以外の境界での離散化

gaussLaplacianScheme.C

Page 90: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

90

境界フェイスでの対流項の離散化

続いて対流項の場合を見ていきます.

対流項は各セルで次のように離散化されることを第4章で学びました.

𝛻 ∙ 𝑼𝜙 𝑑𝑉𝑉

= 𝐹𝜙𝑓𝑓

この式から,境界フェイスでは,

𝐹𝜙𝑏

の評価が必要であることが分かります.

𝜙𝑏

𝜙𝑃

Page 91: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

91

境界フェイスでの対流項の離散化|zeroGradient 境界条件

勾配0 (zeroGradient) の条件を課した境界を考えると,

𝜙𝑏 − 𝜙𝑃𝒅= 0 → 𝜙𝑏 = 𝜙𝑃 → 𝐹𝜙𝑏 = 𝐹𝜙𝑃

𝑎11 𝑎1𝑁

𝑎𝑁1 𝑎𝑁𝑁

𝜙1𝜙2⋮𝜙𝑁

=

𝑠1𝑠2⋮𝑠𝑁

𝜙𝑏

𝜙𝑃

係数行列の”対角成分” に加わります.

セル中心値は未知数なので

Page 92: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

92

境界フェイスでの対流項の離散化|fixedValue 境界条件

これに対し,境界上で値 𝜙𝑏 を規定した場合 (fixedValue) には,この値を使って単純に次式により評価できます.

𝐹𝜙𝑏

𝑎11 𝑎1𝑁

𝑎𝑁1 𝑎𝑁𝑁

𝜙1𝜙2⋮𝜙𝑁

=

𝑠1𝑠2⋮𝑠𝑁

右辺ベクトル に加わります.

全て値が既知なので

Page 93: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

93

valueInternalCoeffs と valueBoundaryCoeffs

具体的に見てきたように,境界フェイスにおける対流項の流束からの • 係数行列の対角成分 • 右辺ベクトル への寄与は境界条件によって異なります.

OpenFOAMではこれを取り扱うために,境界条件ごとに次の2つの関数が用意されています. • valueInternalCoeffs()

係数行列の対角成分への寄与 • valueBoundaryCoeffs()

右辺ベクトルへの寄与

次のスライドから基本的な境界条件についてこれらの関数を見ていきましょう.

Page 94: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

94

境界フェイスでの対流項の離散化|zeroGradient 境界条件

template<class Type> tmp<Field<Type> > zeroGradientFvPatchField<Type>::valueInternalCoeffs ( const tmp<scalarField>& ) const { return tmp<Field<Type> > ( new Field<Type>(this->size(), pTraits<Type>::one) ); } template<class Type> tmp<Field<Type> > zeroGradientFvPatchField<Type>::valueBoundaryCoeffs ( const tmp<scalarField>& ) const { return tmp<Field<Type> > ( new Field<Type>(this->size(), pTraits<Type>::zero) ); }

“zeroGradient” (勾配0) 境界条件の場合 zeroGradientFvPatchField.C

係数行列の”対角成分” に加わります.

右辺ベクトルへの 寄与はありません.

Page 95: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

95

境界フェイスでの対流項の離散化|fixedValue 境界条件

template<class Type> tmp<Field<Type> > fixedValueFvPatchField<Type>::valueInternalCoeffs ( const tmp<scalarField>& ) const { return tmp<Field<Type> > ( new Field<Type>(this->size(), pTraits<Type>::zero) ); } template<class Type> tmp<Field<Type> > fixedValueFvPatchField<Type>::valueBoundaryCoeffs ( const tmp<scalarField>& ) const { return *this; }

fixedValueFvPatchField.C “fixedValue” (ディリクレ) 境界条件の場合

係数行列の”対角成分” への寄与はありません.

境界値を返しています.

Page 96: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

96

境界フェイスでの対流項の離散化

対流項の離散化のコードを確認してみます.

𝐹 𝜙𝑏

forAll(vf.boundaryField(), patchI) {

const fvPatchField<Type>& psf = vf.boundaryField()[patchI];

const fvsPatchScalarField& patchFlux = faceFlux.boundaryField()[patchI];

const fvsPatchScalarField& pw = weights.boundaryField()[patchI];

fvm.internalCoeffs()[patchI] = patchFlux*psf.valueInternalCoeffs(pw);

fvm.boundaryCoeffs()[patchI] = -patchFlux*psf.valueBoundaryCoeffs(pw); }

gaussConvectionScheme.C

Page 97: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

97

まとめ

Gaussの発散定理を使用した場合には,境界隣接セルの離散化に際して,境界フェイスにおける流束の評価が必要ですが,この評価が境界条件により異なります.

境界条件ごとに実装されている4つの関数がこの評価を行っています.

• valueInternalCoeffs • valueBoundaryCoeffs • gradientInternalCoeffs • gradientBoundaryCoeffs

対角成分への寄与 右辺ベクトルへの寄与

対流項 valueInternalCoeffs valueBoundaryCoeffs

ラプラシアン項 gradientInternalCoeffs gradientBoundaryCoeffs

Page 98: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

98

Chapter 6

simpleFoam を教材にして,流体計算のながれを

より詳細に見ていきましょう.

Page 99: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

99

simpleFoam について

simpleFoam とは • 定常非圧縮性流れ計算のためのソルバーです. • RANS乱流モデルを使用できます.

支配方程式

𝛻 ∙ 𝒖 𝒖 = −𝛻𝑝 + 𝛻 ∙ 𝜈𝑒𝑓𝑓 𝛻𝒖 + 𝛻𝒖

𝑇

𝛻 ∙ 𝒖 = 0

+ 乱流変数の輸送方程式(乱流モデルにより異なります)

流速 𝑚/𝑠

密度で割った圧力 𝑚2/𝑠2

渦動粘性係数と分子動粘性係数の和 𝑚2/𝑠

運動方程式

連続の式

Page 100: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

100

対流項の表現

対流項をベクトルの成分で書き下すと

𝛻 ∙ 𝒖 𝒖 = 𝛻 ∙

𝑢1𝑢1 𝑢1𝑢2 𝑢1𝑢3𝑢2𝑢1 𝑢2𝑢2 𝑢2𝑢3𝑢3𝑢1 𝑢3𝑢2 𝑢3𝑢3

=

𝜕 𝑢1𝑢1𝜕𝑥1

+𝜕 𝑢2𝑢1𝜕𝑥2

+𝜕 𝑢3𝑢1𝜕𝑥3

𝜕 𝑢1𝑢2𝜕𝑥1

+𝜕 𝑢2𝑢2𝜕𝑥2

+𝜕 𝑢3𝑢2𝜕𝑥3

𝜕 𝑢1𝑢3𝜕𝑥1

+𝜕 𝑢2𝑢3𝜕𝑥2

+𝜕 𝑢3𝑢3𝜕𝑥3

Page 101: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

101

対流項の表現

対流項は次式のように式変形できます.

𝛻 ∙ 𝒖 𝒖 = 𝛻 ∙ 𝒖 𝒖 + 𝒖 ∙ 𝛻 𝒖 第4章で見た対流項の離散化の ”bounded” オプションを使用した場合には,

収束までの過程で,非保存形 (non-conservative form) の表現を使用することを意味します.

𝛻 ∙ 𝒖 𝒖 − 𝛻 ∙ 𝒖 𝒖 = 𝒖 ∙ 𝛻 𝒖

計算が収束して,連続の式が満たされれば,次式が成り立ちます.

𝛻 ∙ 𝒖 𝒖 = 𝒖 ∙ 𝛻 𝒖

“bounded” オプションを 使用した場合の対流項の表現

非保存形

Page 102: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

102

simpleFoam のソースコード

simpleFoam のソースコードの場所 $WM_PROJECT_DIR/applications/solvers/incompressible/simpleFoam

simpleFoam のソースファイル

• simpleFoam.C:メイン処理をまとめたファイル • createFields.H:流速 U や圧力 p 等の変数を定義します. • UEqn.H:運動方程式を解きます. • pEqn.H:圧力ポアソン方程式を解きます.

“simpleFoam” の名前の由来にもなっている SIMPLE アルゴリズムの実装の中核を担っている “UEqn.H” と “pEqn.H” のコードの詳細を見ていきましょう.

Page 103: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

計算の流れに沿って,UEqn.H ファイルから見ていきます.

UEqn.H ファイルでは運動方程式を離散化して解きます.

次のページからより詳しく見ていきましょう.

103

UEqn.H|概要

1 // Momentum predictor 2

3 tmp<fvVectorMatrix> UEqn 4 (

5 fvm::div(phi, U)

6 + turbulence->divDevReff(U) 7 ==

8 fvOptions(U) 9 ); 10

11 UEqn().relax(); 12

13 fvOptions.constrain(UEqn()); 14

15 solve(UEqn() == -fvc::grad(p)); 16

17 fvOptions.correct(U);

運動方程式を離散化しています. 係数行列の不足緩和を行っています. 圧力勾配項を前の時間ステップの圧力から計算して,流速場を計算します.

Page 104: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

104

UEqn.H|運動方程式の離散化

陰的に処理される項は係数行列を,陽的に処理される項は右辺ベクトルをそれぞれ構成します.

𝛻 ∙ 𝒖 𝒖 − 𝛻 ∙ 𝒖 𝒖 = −𝛻𝑝 + 𝛻 ∙ 𝜈𝑒𝑓𝑓 𝛻𝒖 + 𝛻𝒖𝑇

𝐴11 𝐴1𝑁

𝐴𝑁1 𝐴𝑁𝑁

𝑢1𝑘𝑢2𝑘⋮𝑢𝑁𝑘

=

𝑠1𝑘𝑠2𝑘⋮𝑠𝑁𝑘

ここで,𝑢𝑖𝑘 および 𝑠𝑖𝑘 の1つ目の添え字 𝑖 はセル番号を,2つ目の添え字 𝑘

はベクトルの成分 𝑘 = 1, 2, 3 を表しています.

陰的処理 陽的処理

非直交 補正

Page 105: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

105

UEqn.H|不足緩和(under relaxation)

離散化 (3~9行) により得られる方程式は,次式のように書き表せます.

𝐴𝑃𝒖𝑃 + 𝐴𝑁𝒖𝑁𝑁

= 𝒔

11行目で行っている不足緩和は,係数行列の対角成分を大きくするための操

作です.これにより連立方程式が解きやすくなります.

𝐴𝑃𝛼𝒖𝑝 + 𝐴𝑁𝒖𝑁

𝑁

= 𝒔 +𝐴𝑃𝛼− 𝐴𝑃 𝒖𝑃

0

これを少し整理すると,

𝐴𝑃𝛼𝒖𝑃 + 𝐴𝑁𝒖𝑁

𝑁

= 𝒔 +1 − 𝛼

𝛼𝐴𝑃𝒖𝑃0

641 // ... then relax

642 D /= alpha;

671 // Finally add the relaxation contribution to the source.

672 S += (D - D0)*psi_.internalField();

fvMatrix.C

0 < 𝛼 < 1 なので,もともとの係数 𝐴𝑝 よりも大きな値をとります.

1

2

𝛼:緩和係数 𝒖𝑃0:前の時間ステップの解

Page 106: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

106

UEqn.H|不足緩和(under relaxation)

前ページの 式と 式の関係を見てみます.

𝐴𝑃𝒖𝑃 +1 − 𝛼

𝛼𝐴𝑃𝒖𝑃 + 𝐴𝑁𝒖𝑁

𝑁

= 𝒔 +1 − 𝛼

𝛼𝐴𝑃𝒖𝑃0

式の両辺に,青枠の項が足された形になっているのが分かります.

この連立方程式を,反復解法により解いて収束解が得られる場合には,青枠の項は同じ値に収束するので, 式と 式とで同じ解が得られることが分かります.

以上説明してきた緩和係数 𝛼 の値は,fvSolution ファイルで設定します.

1 2

式を変形すると, 2

1

1 2

relaxationFactors

{

equations

{

U 0.7;

k 0.7;

epsilon 0.7;

}

}

連立方程式を解くそれぞれの変数ごとに 緩和係数の値を設定します.

Page 107: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

107

UEqn.H|流速場の予測値

15行目で得られた解 𝒖𝑃∗ について次の関係が成り立っています.

𝐴𝑃𝒖𝑃∗ + 𝐴𝑁𝒖𝑁

𝑁

= 𝒔 − 𝑉𝑃 ∙ 𝛻 𝑝𝑛−1

これを変形すると,

𝒖𝑃∗ =1

𝐴𝑃𝒔 − 𝐴𝑁𝒖𝑁

𝑁

−𝑉𝑃𝐴𝑃𝛻𝑝 𝑛−1

ここで,𝐴𝑃,𝐴𝑁,𝒔 をセル体積で除したものを再び同じ記号で表すと,次式のように書き表せます.

𝒖𝑃∗ =1

𝐴𝑃𝒔 − 𝐴𝑁𝒖𝑁

𝑁

−1

𝐴𝑃𝛻𝑝 𝑛−1 3

前のステップの圧力

流速場の予測値

セル体積

Page 108: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

108

この後の計算の流れ

SIMPLE 法では,流速場の修正量を次式から見積もります.

𝒖𝑃′ = −

1

𝐴𝑃𝛻𝑝′

修正後の流速場 𝒖𝑃𝑛

が,連続の式を満たすように修正量を決定します.

𝛻 ∙ 𝒖𝑃𝑛= 𝛻 ∙ 𝒖𝑃

∗ + 𝒖𝑃′ = 0

𝛻 ∙1

𝐴𝑃𝒔 − 𝐴𝑁𝒖𝑁

𝑁

−1

𝐴𝑃𝛻𝑝 𝑛−1 −

1

𝐴𝑃𝛻𝑝′ = 0

𝛻 ∙1

𝐴𝑃𝛻𝑝 𝑛 = 𝛻 ∙

1

𝐴𝑃𝒔 − 𝐴𝑁𝒖𝑁

𝑁

4

5

3 と を使って変形 4

6

Page 109: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

109

pEqn.H (Part1)

1 {

2 volScalarField rAU(1.0/UEqn().A());

3 volVectorField HbyA("HbyA", U);

4 HbyA = rAU*UEqn().H();

5 UEqn.clear(); 6

7 surfaceScalarField phiHbyA("phiHbyA", fvc::interpolate(HbyA) & mesh.Sf()); 8

9 fvOptions.makeRelative(phiHbyA); 10

11 adjustPhi(phiHbyA, U, p);

前のスライドの内容をどのように実装しているのか見ていきましょう.

pEqn.H

2~4行目

𝒖𝑃∗ =1

𝐴𝑃𝒔 − 𝐴𝑁𝒖𝑁

𝑁

−1

𝐴𝑃𝛻𝑝 𝑛−1 (再掲)

4行目で,HbyA という変数に代入しています.

rAU

UEqn().H()

3

Page 110: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

110

pEqn.H (Part1) |UEqn().A()

このスライドの赤字の部分の処理に対応して,UEqn().A() は係数行列の対角成分をセル体積で割った値を返します.

template<class Type>

Foam::tmp<Foam::volScalarField> Foam::fvMatrix<Type>::A() const {

tmp<volScalarField> tAphi (

new volScalarField (

IOobject ( "A("+psi_.name()+')',

psi_.instance(),

psi_.mesh(),

IOobject::NO_READ,

IOobject::NO_WRITE ),

psi_.mesh(),

dimensions_/psi_.dimensions()/dimVol,

zeroGradientFvPatchScalarField::typeName ) );

tAphi().internalField() = D()/psi_.mesh().V();

tAphi().correctBoundaryConditions();

return tAphi; }

fvMatrix.C

Page 111: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

111

pEqn.H (Part1) |UEqn().H()

このスライドの赤字の部分の処理に対応して,UEqn().H() は係数行列の非対角成分と右辺ベクトルをセル体積で割った値で計算されます.

template<class Type> Foam::tmp<Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh> > Foam::fvMatrix<Type>::H() const { tmp<GeometricField<Type, fvPatchField, volMesh> > tHphi ( new GeometricField<Type, fvPatchField, volMesh> ( IOobject ( "H("+psi_.name()+')', psi_.instance(), psi_.mesh(), IOobject::NO_READ, IOobject::NO_WRITE ), psi_.mesh(), dimensions_/dimVol, zeroGradientFvPatchScalarField::typeName ) ); GeometricField<Type, fvPatchField, volMesh>& Hphi = tHphi(); (中略) Hphi.internalField() += lduMatrix::H(psi_.internalField()) + source_; addBoundarySource(Hphi.internalField()); Hphi.internalField() /= psi_.mesh().V(); Hphi.correctBoundaryConditions();

fvMatrix.C

Page 112: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

112

pEqn.H (Part1) |補足

1 // Momentum predictor 2

3 tmp<fvVectorMatrix> UEqn 4 (

5 fvm::div(phi, U)

6 + turbulence->divDevReff(U) 7 ==

8 fvOptions(U) 9 ); 10

11 UEqn().relax(); 12

13 fvOptions.constrain(UEqn()); 14

15 solve(UEqn() == -fvc::grad(p)); 16

17 fvOptions.correct(U);

方程式の離散化に際して,UEqn() (3~9行)の定義の方に圧力勾配項 -fvc::grad(p) を含めないことで,UEqn().H() はこの項を含まずに計算しています.

-fvc::grad(p) を UEqn() の定義に含めていない

Page 113: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

113

pEqn.H (Part1)|体積流束 (volumetric flux) の計算

7行目:HbyA から体積流束を計算しています.

fvc::interpolate(HbyA) & mesh.Sf() 11行目:

どの境界でも圧力を規定していない場合に,計算領域に流入出する流量の収支が満たされるように流束を修正します. 流量の収支 = massIn - fixedMassOut - massCorr * adjustableMassOut と書き表した時に,流量の収支が満たされるように adjustableMassOut を調整します. ここで, • massIn:計算領域に流入する全流量 • fixedMassOut:流速が規定されている境界から流出する流量 • adjustableMassOut:流速が規定されていない境界から流出する流量 • massCorr = (massIn - fixedMassOut)/adjustableMassOut

HbyA をセル中心からフェイスへ補間 フェイスの法線ベクトル (大きさ;フェイスの面積)

Page 114: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

114

pEqn.H (Part2)|概要

13 // Non-orthogonal pressure corrector loop

14 while (simple.correctNonOrthogonal()) 15 {

16 fvScalarMatrix pEqn 17 (

18 fvm::laplacian(rAU, p) == fvc::div(phiHbyA) 19 ); 20

21 pEqn.setReference(pRefCell, pRefValue); 22

23 pEqn.solve(); 24

25 if (simple.finalNonOrthogonalIter()) 26 {

27 phi = phiHbyA - pEqn.flux(); 28 } 29 }

pEqn.H

圧力に関するポアソン方程式 を解いて,連続の式を満たすように圧力を求め,流束の修正を行っています.次のページで詳細を見ていきます.

6

Page 115: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

115

pEqn.H (Part2)|圧力ポアソン方程式の解法

16~19行目:圧力ポアソン方程式の離散化 離散化により得られる関係式

1

𝐴𝑃 𝑓∆𝑝𝑁 − 𝑝𝑃𝒅+1

𝐴𝑃 𝑓𝒌 ∙ 𝛻𝑝 𝑓

𝑓

= 𝑯

𝐴𝑃 𝑓∙ 𝑺𝑓

𝑓

両辺まとめると,

𝑯

𝐴𝑃 𝑓∙ 𝑺𝑓 −

1

𝐴𝑃 𝑓∆𝑝𝑁 − 𝑝𝑃𝒅+1

𝐴𝑃 𝑓𝒌 ∙ 𝛻𝑝 𝑓 = 0

𝑓

25~28行目:流束場の修正

フェイスにおける流束を

phi = phiHbyA - pEqn.flux()

と計算することで,上式より 𝑝ℎ𝑖𝑓 = 0 となり,連続の式を満たすことが分かります.

phiHbyA pEqn.flux()

Page 116: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

メッシュの non-orthogonality が大きい場合には,非直交補正の処理をループで行います.

非直交補正のループの回数は,”fvSolution” ファイルに設定します.

ループで圧力値が更新されるのに伴い非直交補正の量が更新されます.

1

𝐴𝑃 𝑓∆𝑝𝑁 − 𝑝𝑃𝒅+1

𝐴𝑃 𝑓𝒌 ∙ 𝛻𝑝 𝑓

𝑓

= 𝑯

𝐴𝑃 𝑓∙ 𝑺𝑓

𝑓

116

pEqn.H (Part2)|非直交補正ループ

13 // Non-orthogonal pressure corrector loop

14 while (simple.correctNonOrthogonal())

(省略) 29 }

SIMPLE { nNonOrthogonalCorrectors 5; }

Page 117: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

117

pEqn.H (Part3)

31 #include "continuityErrs.H" 32 33 // Explicitly relax pressure for momentum corrector

34 p.relax(); 35 36 // Momentum corrector

37 U = HbyA - rAU*fvc::grad(p);

38 U.correctBoundaryConditions();

39 fvOptions.correct(U); 40 }

pEqn.H

34行目:圧力場の不足緩和

SIMPLE法では,圧力の修正量 𝑝 𝑛 − 𝑝 𝑛−1 (𝑝 𝑛 : ポアソン方程式の解,

𝑝 𝑛−1 : 前のステップの解) が過大に評価され,計算の収束性に悪影響を与える傾向があるため,それを防ぐために不足緩和が行われます.

𝑝 𝑛−1 + 𝛼𝑝 𝑝𝑛 − 𝑝 𝑛−1

緩和係数 𝛼𝑝 の値は,fvSolution ファイルに設定します.

relaxationFactors { fields { p 0.3; } }

Page 118: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

圧力場に対する不足緩和は次のコードで行われます.

118

pEqn.H (Part3)|圧力場の不足緩和

873 template<class Type, template<class> class PatchField, class GeoMesh>

874 void Foam::GeometricField<Type, PatchField, GeoMesh>::relax(const scalar alpha) 875 {

876 if (debug) 877 {

878 InfoIn 879 ( 880 "GeometricField<Type, PatchField, GeoMesh>::relax" 881 "(const scalar alpha)"

882 ) << "Relaxing" << endl << this->info() << " by " << alpha << endl; 883 } 884

885 operator==(prevIter() + alpha*(*this - prevIter())); 886 }

GeometricField.C

Page 119: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

119

pEqn.H (Part3)|流速場の修正

37行目:流速場の修正 不足緩和を行った圧力場から勾配を計算して,流速場を修正します.

𝒖𝑃𝑛=1

𝐴𝑃𝒔 − 𝐴𝑁𝒖𝑁

𝑁

−1

𝐴𝑃𝛻𝑝

𝑝 𝑛−1 + 𝛼𝑝 𝑝𝑛 − 𝑝 𝑛−1

Page 120: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

120

Chapter 7

運動方程式と連続の式を連立して1つの行列で解く

pUCoupledFoam を探検していきます.

Page 121: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

pUCoupledFoam は,foam のバージョン3.1に実装されています.

foam のインストール方法はこちら

ソースコードのヘッダー部の説明を見てみましょう. 支配方程式は,simpleFoam の場合と同じですが,この解法が異なります.

121

pUCoupledFoam の概要

Application pUCoupledFoam Description Steady-state solver for incompressible, turbulent flow, with implicit coupling between pressure and velocity achieved by BlockLduMatrix Turbulence is in this version solved using the existing turbulence structure. Authors Klas Jareteg, Chalmers University of Technology, Vuko Vukcevic, FMENA Zagreb.

Page 122: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

122

pUCoupledFoam の参考資料

開発者 Klas Jareteg さんの資料 (pdf) • pUCoupledFoam の開発者自身による説明資料です.

• OpenFOAMへの実装方法が詳しく説明されておりとても参考になります. 私のスライドも上記の資料を参考にしていますが,この資料に記載のない内容までカバーできるように理解を深めていきたいと思います.

Page 123: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

123

pUCoupledFoam の森へ1歩1歩足を踏み入れていきましょう!

Page 124: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

124

解ベクトル Up

Info << "Creating field Up¥n" << endl; volVector4Field Up ( IOobject ( "Up", runTime.timeName(), mesh, IOobject::NO_READ, IOobject::AUTO_WRITE ), mesh, dimensionedVector4("zero", dimless, vector4::zero) );

流速 𝑈 の3つの方向成分と圧力 𝑝 の計4成分をもつベクトルを vector4 タイプの変数で表します.

𝑈𝑥 , 𝑈𝑌, 𝑈𝑍, 𝑝𝑇

4成分

Page 125: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

125

今年中にかたちになるように, 逐次更新していきます.

Page 126: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

126

参考文献

[1] http://www.claymath.org/millennium-problems (accessed 03/16/2014) [2] ファーツィガー,ペリッチ,『コンピュータによる流体力学』 [3] http://www.openfoam.org/features/numerical-method.php (accessed 03/16/2014) [4] http://www.geocities.jp/penguinitis2002/index.html (accessed 03/16/2014) [5] https://www.simonsfoundation.org/quanta/20140224-a-fluid-new-path-in-grand-math-challenge/ (accessed 03/16/2014) [6] http://www.math.kz/images/journal/2013-4/Otelbaev_N-S_21_12_2013.pdf (accessed 03/16/2014) [7] http://arxiv.org/pdf/1402.0290v2.pdf (accessed 03/16/2014)

Page 128: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

128

付録

Page 129: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

129

解析的なアプローチ:最近の動向

Navier-Stokes 方程式の解の存在の証明に関しては,2014年に入ってから多くのニュースがあります [5]. • カザフスタンの Mukhtarbay Otelbaev 教授が,1月に解の存在証明に成

功したと宣言した論文 [6] については現在世界中の数学者による検証中ですが,既に証明に問題があることが判明し,教授がその解決に取り組んでいるそうです.

The most recent attempt to garner serious attention, by Mukhtarbay Otelbaev of the Eurasian National University in Astana, Kazakhstan, is still under review, but mathematicians have already uncovered significant problems with the proof, which Otelbaev is trying to solve [5].

• カリフォルニア大学の Terence Tao 教授が2月に論文 [7] を発表しました.

Page 130: OpenFOAM -空間の離散化と係数行列の取り扱い(Spatial Discretization and Coefficient Matrix)-

130

Thank You!