OpenFOAMカスタマイズの始め方
OpenFOAMカスタマイズの始め方
2019年11月16日オープンCAE勉強会@富山(富山県立大学 中川慎二)
Disclaimer
OPENFOAM® is a registered trade mark of OpenCFD Limited, the producer of the OpenFOAM software and owner of the OPENFOAM® and OpenCFD® trade marks. This offering is not approved or endorsed by OpenCFD Limited.
注意
本資料の内容は,OpenFOAMユーザーガイド,プログラマーズガイド,OpenFOAM Wiki,CFD Online,その他多くの情報を参考にしています。開発者,情報発信者の皆様に深い謝意を表します。
内容は,講師の個人的な経験(主に,卒研生等とのコードリーディング)から得た知識を共有するものです。この内容の正確性を保証することはできません。この情報を使用したことによって問題が生じた場合,その責任は負いかねますので,予めご了承ください。
はじめに
OpenFOAMをはじめてカスタマイズする初心者を想定し,基礎の基礎をハンズオン形式で学びます。OpenFOAMの改造をどこからはじめて良いか分からないといった人が,元のコードをコピーして,新たな名前のモデルやライブラリを作る手順を確認していきます。
参考サイト1:オープンCAE勉強会@富山(第34回2015年7月25日)「OpenFOAM 非ニュートンモデル カスタマイズ(秋山氏)」
上記参考サイトの情報と,本演習との違いを考えることで,同じ結果を得るための複数のカスタマイズ方法を知ることができます。
下記の内容の一部や,ライブラリによる違いについても説明する予定です。
参考サイト3
基本方針
改造は少しずつ。改造・コンパイル・テストを細かくくり返す。
エラーが発生した場合には,エラーメッセージをしっかりと読む。1番はじめのエラーへ対応する。
使用環境の確認
使用するマシンのOpenFOAMの環境を確認する。
user@user-VirtualBox:~$ echo $WM_PROJECT_DIR
/home/user/OpenFOAM/OpenFOAM-v1812
user@user-VirtualBox:~$ echo $FOAM_SRC
/home/user/OpenFOAM/OpenFOAM-v1812/src
user@user-VirtualBox:~$ echo $FOAM_SOLVERS
/home/user/OpenFOAM/OpenFOAM-v1812/applications/solvers
user@user-VirtualBox:~$ echo $FOAM_TUTORIALS
/home/user/OpenFOAM/OpenFOAM-v1812/tutorials
user@user-VirtualBox:~$ echo $WM_PROJECT_USER_DIR
/home/user/OpenFOAM/user-v1812
user@user-VirtualBox:~$ echo $FOAM_RUN
/home/user/OpenFOAM/user-v1812/run
user@user-VirtualBox:~$ echo $FOAM_USER_APPBIN
/home/user/OpenFOAM/user-v1812/platforms/linux64GccDPInt32Opt/bin
user@user-VirtualBox:~$ echo $FOAM_USER_LIBBIN
/home/user/OpenFOAM/user-v1812/platforms/linux64GccDPInt32Opt/lib
ソルバのカスタマイズ手順の確認
既存のソルバをコピー,名前の変更,コンパイル
copy original files (solver)
コピー元: $FOAM_SOLVERS/incompressible/simpleFoam/
コピー先: $WM_PROJECT_USER_DIR/solvers/
cp -r $FOAM_SOLVERS/incompressible/simpleFoam/ $WM_PROJECT_USER_DIR/solvers/
今回は不要な3つのディレクトリ(overSimpleFoam porousSimpleFoam SRFSimpleFoam)を削除する。
cd $WM_PROJECT_USER_DIR/solvers/simpleFoam
rm -r *Foam
名前の変更
ディレクトリ名,ファイル名,ファイル中のクラス名や関数名を変更する。
変更前: simpleFoam
変更後: mySimpleFoam
ディレクトリ名を simpleFoam
から mySimpleFoam
に変更する。
cd $WM_PROJECT_USER_DIR/solvers/
mv simpleFoam mySimpleFoam
ファイル名を simpleFoam.C
から mySimpleFoam.C
に変更する。
cd mySimpleFoam
mv simpleFoam.C mySimpleFoam.C
mySimpleFoam.C
と Make/files
の中に現れる simpleFoam
を mySimpleFoam
に変更する。さらに,Make/files
の中で,コンパイル後のファイル保存先を FOAM_APPBIN
から FOAM_USER_APPBIN
に変更する。
sed -i s/simpleFoam/mySimpleFoam/g mySimpleFoam.C
sed -i s/simpleFoam/mySimpleFoam/g Make/files
sed -i s/FOAM_APPBIN/FOAM_USER_APPBIN/g Make/files
コンパイル
正しく変更できたかを確認するため,コンパイルする。端末上で $WM_PROJECT_USER_DIR/solvers/mySimpleFoam
に移動し,wmake
コマンドを実行する。wmake
は,OpenFOAMに付属するスクリプトであり,一般的にコンパイルに使われる make
コマンドにOpenFOAMに必要な設定などが追加されている。
cd $WM_PROJECT_USER_DIR/solvers/mySimpleFoam
wclean
wmake
エラーがないことを確認する。さらに,ディレクトリ $FOAM_USER_APPBIN
(これは $WM_PROJECT_USER_DIR/platforms/linux64GccDPInt32Opt/bin/
と同じ。コンパイルオプションによって異なる場合がある。) に ファイル mySimpleFoam が作成されていることを確認する。
cd $FOAM_USER_APPBIN
ls -al
テスト用例題(ケース)の作成
copy original files (tutorial)
標準例題を複製し,作成したソルバが動作することを確認するための例題を作成する。
コピー元: $FOAM_TUTORIALS/incompressible/simpleFoam/bump2D/
コピー先: $FOAM_RUN
cp -r $FOAM_TUTORIALS/incompressible/simpleFoam/bump2D/ $FOAM_RUN
system/controlDictの編集(application名の変更)
作業先の bump2D
ディレクトリに移動する。system/controlDict
ファイル内のsimpleFoam
を mySimpleFoam
に変更する。
cd $FOAM_RUN/bump2D
sed -i s/simpleFoam/mySimpleFoam/g system/controlDict
計算実行と結果の確認
過去の実行結果を削除し,改めて,Allrunスクリプトにより計算を実行する。
foamCleanTutorials
./Allrun
ケースディレクトリに log.mySimpleFoam
が作成されていることを確認する。そのファイルを開き,mySimpleFoam
が実行されていることを確認する。(ファイル冒頭部分の Exec: 欄にソルバ名が記録されている。)
計算が完了するまでは時間がかかる。途中で停止したい場合には,計算を実行した端末上で Ctrl + C
キーを入力する。
ライブラリのカスタマイズ手順の確認(ライブラリ全体の複製)
ここでは,OpenFOAMの全ライブラリを格納する src
ディレクトリ全体をコピーし,その中で改造が必要な部分だけを変更する方法について説明する。
大まかな作業手順は,既存の全ライブラリをコピー,改造部分の名前の変更,コンパイルとなる。
copy original files (library)
コピー元: $FOAM_SRC
コピー先: $WM_PROJECT_USER_DIR/src/
OpenFOAMのsrcディレクトリ全体を,ユーザのディレクトリにコピーする。ファイル数が多いので,少し時間がかかる。
cp -r $FOAM_SRC $WM_PROJECT_USER_DIR/src/
モデルの複製と名前の変更
OpenFOAMに標準で作成されているCrossPowerLaw(非ニュートン粘性モデル)から,myCrossPowerLawモデルを作成する。ファイル名,ファイル中のクラス名や関数名を変更する。
コピー元 $WM_PROJECT_USER_DIR/src/transportModels/incompressible/viscosityModels/CrossPowerLaw
コピー先 $WM_PROJECT_USER_DIR/src/transportModels/incompressible/viscosityModels/myCrossPowerLaw
cp -r $WM_PROJECT_USER_DIR/src/transportModels/incompressible/viscosityModels/CrossPowerLaw $WM_PROJECT_USER_DIR/src/transportModels/incompressible/viscosityModels/myCrossPowerLaw
新しく作成されたmyCrossPowerLawディレクトリへ移動する。そこに格納されている2つのファイル名を,CrossPowerLawからmyCrossPowerLawへ変更する。
cd $WM_PROJECT_USER_DIR/src/transportModels/incompressible/viscosityModels/myCrossPowerLaw
mv CrossPowerLaw.C myCrossPowerLaw.C
mv CrossPowerLaw.H myCrossPowerLaw.H
上記の作業で作成された myCrossPowerLaw.H および myCrossPowerLaw.C ファイルの中で,CrossPowerLaw とかかれた部分を,myCrossPowerLaw に書き換える。(ファイルを開いて,エディタの検索と置換機能を使う。あるいは,下記コマンドを実行する。)
sed -i s/CrossPowerLaw/myCrossPowerLaw/g myCrossPowerLaw.H
sed -i s/CrossPowerLaw/myCrossPowerLaw/g myCrossPowerLaw.C
myCrossPowerLaw関連ファイルがコンパイルされるように,$WM_PROJECT_USER_DIR/src/transportModels/incompressible/Make
の中にあるfiles ファイルを修正する。
5行目をコピーし,6行目に貼り付けて次のように修正する。
viscosityModels/myCrossPowerLaw/myCrossPowerLaw.C
さらに,コンパイル後の保存先を FOAM_LIBBIN
から FOAM_USER_LIBBIN
に変更する。
cd $WM_PROJECT_USER_DIR/src/transportModels/incompressible/Make
sed -i -e '/CrossPowerLaw.C$/a viscosityModels\/myCrossPowerLaw\/myCrossPowerLaw.C' files
sed -i s/FOAM_LIBBIN/FOAM_USER_LIBBIN/g files
コンパイル
ディレクトリ $WM_PROJECT_USER_DIR/src/transportModels/incompressible
から,wmake コマンドを実行して,ソースコードをコンパイルする。
cd $WM_PROJECT_USER_DIR/src/transportModels/incompressible
wclean
wmake
コンパイルに成功すると,$FOAM_USER_LIBBIN
に libincompressibleTransportModels.so
というファイルが生成される。[ 講習会用マシンでは, home/user/OpenFOAM/user-v1812/platforms/linux64GccDPInt32Opt/lib/libincompressibleTransportModels.so
となる。]
動作確認
例題
先ほど作成した例題 $FOAM_RUN/bump2D
を使って,作成したモデルの実行を確認する。
例題で使用する粘性モデルをmyCrossPowerLawに変更する。constant/transportProperties
ファイルを開き,transportModel に myCrossPowerLaw を指定する。myCrossPowerLawCoeffsを次のように指定する。($FOAM_TUTORIALS/incompressible/nonNewtonianIcoFoam/offsetCylinder/constant/transportProperties
を参考にしてもよい。)
transportModel myCrossPowerLaw; myCrossPowerLawCoeffs { nu0 0.01; nuInf 10; m 0.4; n 3; }
例題を実行し,ログを確認して,問題ないことを確認する。ログの冒頭付近に,下記の記述があり,作成したモデルが使用されていることを確認する。
Selecting incompressible transport model myCrossPowerLaw
ライブラリのカスタマイズ(新しい粘性モデルだけを含むライブラリの作成)
copy original files
OpenFOAM標準のCrossPowerLawモデルのコードだけを,$WM_PROJECT_USER_DIR/src
ディレクトリにコピーする。
cp -r $FOAM_SRC/transportModels/incompressible/viscosityModels/CrossPowerLaw/ $WM_PROJECT_USER_DIR/src/newCrossPowerLaw/
コピーしたファイルの名前を,CrossPowerLawからnewCrossPowerLawに変更する。CrossPowerLaw.depファイルが存在する場合には削除する。
cd $WM_PROJECT_USER_DIR/src/newCrossPowerLaw/
mv CrossPowerLaw.H newCrossPowerLaw.H
mv CrossPowerLaw.C newCrossPowerLaw.C
同じディレクトリ内に,コンパイルに必要な情報をコピーする。非ニュートン粘性モデルライブラリのためのMakeディレクトリ($FOAM_SRC/transportModels/incompressible/Make/
)を,$WM_PROJECT_USER_DIR/src/newCrossPowerLaw/
にコピーする。
cp -R $FOAM_SRC/transportModels/incompressible/Make/ $WM_PROJECT_USER_DIR/src/newCrossPowerLaw/
modify source files
ファイル内のモデル名をnewCrossPowerLawに変更する。
sed -i s/CrossPowerLaw/newCrossPowerLaw/g newCrossPowerLaw.H
sed -i s/CrossPowerLaw/newCrossPowerLaw/g newCrossPowerLaw.C
Make ディレクトリの files と options ファイルを修正
新たなモデルを独立したライブラリとしてコンパイルするために,コンパイルに必要な情報を修正する。この情報は,$WM_PROJECT_USER_DIR/src/newCrossPowerLaw/Make
ディレクトリ内に格納されている。
cd $WM_PROJECT_USER_DIR/src/newCrossPowerLaw/Make
Make/files
新しく作成したソースコード newCrossPowerLaw.C だけをコンパイルし,libnewCrossPowerLawという名前のライブラリを作成する。filesファイルの内容を下記に書き換える。
newCrossPowerLaw.C
LIB = $(FOAM_USER_LIBBIN)/libnewCrossPowerLaw
Make/options
新しく作成したソースコード newCrossPowerLaw.C のコンパイルに必要なインクルードファイルの場所を指定する。また,newCrossPowerLawモデルを通常の非ニュートンモデルと入れ替えて使えるように,incompressibleTransportModelsライブラリを指定する。
EXE_INC = \ -I$(LIB_SRC)/transportModels/incompressible/lnInclude \ -I$(LIB_SRC)/finiteVolume/lnInclude LIB_LIBS = \ -lincompressibleTransportModels \ -lfiniteVolume
compile
cd $WM_PROJECT_USER_DIR/src/newCrossPowerLaw
wmake
ライブラリなので,wmake libso としてもよい。wmake を実行するだけでも,自動的にそうなっている。
コンパイルに成功すると,$FOAM_USER_LIBBIN
に libnewCrossPowerLaw.so
というファイルが生成される。
create a tutarial case
先ほど作成した例題 $FOAM_RUN/bump2D
を使って,作成したライブラリとモデルの実行を確認する。
testCrossLaw 例題ディレクトリに移動する。不要な情報を削除して,まっさらな状態に戻すため,foamCleanTutorials を実行する。
cd $FOAM_RUN/bump2D/
foamCleanTutorials
作成したライブラリを使用するために,controlDictにライブラリを登録する。下記の内容を,controlDict最後に追加する。
libs
(
"libnewCrossPowerLaw.so"
);
newCrossPowerLawモデルを使うように,constant/transportPropertiesを変更する。元のファイルにおいて,myCrossPowerLawをnewCrossPowerLawに書き換える。
sed -i s/myCrossPowerLaw/newCrossPowerLaw/g ./constant/transportProperties
blockMesh でメッシュを生成,Allrunスクリプト を実行する。
./Allrun
ログを確認して,問題ないことを確認する。ログの冒頭付近に,下記の記述があり,作成したモデルが使用されていることを確認する。
Selecting incompressible transport model newCrossPowerLaw
考察
src 丸ごとコピーと,クラス単位の改造,どちらが良いの?
手っ取り早いのは、丸ごとコピー。
ただし,標準ディレクトリとユーザーディレクトリに,重複した同一コードが多数存在する状態となる。これは,危険をはらむ。
クラス単位の場合,直接改造した部分以外は,標準のコードが使われる。思わぬコード違いが防げる。
個人の意見:クラス単位の改造を推奨する。バージョン変更への追随も容易になるか?
乱流モデルとtransportModelとの違い
Make/files を見て確認する。
乱流モデルは,マクロを活用して,1組のコードから複数の種類(圧縮性/非圧縮性)のクラスを生成する。そのため,複雑に見える。
乱流モデルの生成に使われるマクロや,単独の乱流モデルをライブラリにする方法などは,下記に説明がある。
参考サイト3
モデルのさらなる改造
非ニュートン粘性モデルの検証に使えるように,ひずみ速度を出力するための変更を加える。
newCrossPowerLaw.H の修正
newCrossPowerLaw.H
の70行目付近に,volScalarFieldクラスの変数として,変数 strainRate_
を宣言する。OpenFOAMの流儀に従って,クラス内の変数名最後にはアンダーバー_を付している。
なお,strainRate_
の宣言は,変数 nu_
の前に書くことが必要である。これは,後ほど確認する初期化方法に関連している。
さらに,同じファイル内で,関数 calcNu()
のconst指定をコメントアウトする。これは,この関数内で歪み速度を計算して,変数 strainRate_
の値を変更するためである。コードの該当部分を下にしめす。
protected:
// Protected data
volScalarField strainRate_; // newly added
volScalarField nu_;
// Protected Member Functions
//- Calculate and return the laminar viscosity
tmp<volScalarField> calcNu(); //"const" is commented out.
newCrossPowerLaw.C の修正
newCrossPowerLaw.C
の51行目付近で,calcNu()
関数のconst指定をコメントアウトする。
この関数の中で,変数 strainRate_
に,関数 strainRate()
で求めた値を代入する。returnする値の計算式ないで,関数 strainRate()
を呼び出していた部分を,先に値を定めた変数 strainRate_
に置き換える。改訂する部分を下記に示す。
なお,ここで使用する strainRate()
関数は,newCrossPowerLawクラスが継承している元のクラス viscosityModel で定義されている。
Foam::tmp<Foam::volScalarField>
Foam::viscosityModels::newCrossPowerLaw::calcNu() //const//const is commented out.
{
strainRate_ = strainRate();
return (nu0_ - nuInf_)/(scalar(1) + pow(m_*strainRate_, n_)) + nuInf_;
//return (nu0_ - nuInf_)/(scalar(1) + pow(m_*strainRate(), n_)) + nuInf_;
}
さらに,newCrossPowerLaw.C
の78行目付近で,Constructor の初期化部分に,変数 strainRate_
を加える。初期化リストは,変数を宣言した順に並べる必要がある。そのため,,strainRate_
の初期化を,変数 nu_
の前に記述する。
ここで,変数 nu_
の初期化方法を見ると,calcNu()
関数が使われている。今回のプログラム改造では,この関数内でstrainRate_
変数を扱うため,strainRate_
を先に初期化した。
strainRate_
(
IOobject
(
"strainRate",
U_.time().timeName(),
U_.db(),
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
U_.mesh(),
dimensionedScalar("strainRate", dimVelocity/dimLength, Zero) //or strainRate()
),
nu_
(
IOobject
(
name,
U_.time().timeName(),
U_.db(),
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
calcNu()
)
参考のために,作成したコード類を圧縮して添付する。
コンパイル
cd $WM_PROJECT_USER_DIR/src/newCrossPowerLaw
wmake
動作確認
例題を実行する。結果の時刻ディレクトリに,strainRateというファイルが書き出されていることを確認する。そのファイル内の情報が正しいことを確認する。
参考情報:クリックで折りたたみ表示の設定/解除が切り替えられます。
参考情報
ソルバからの書き出しにfunctionObjectが使えるのか?
OpenFOAMのバージョン2.0.0から追加された runtimeCodeCompilation 機能によって,ソルバを改造せずに,歪み速度を書き出すことを検討する。下記サイトの紹介では,簡単な使用例が記載されている。
http://www.openfoam.org/version2.0.0/runtime-control.php#runtimeCodeCompilation
functions
(
pAverage
{
functionObjectLibs ("libutilityFunctionObjects.so");
type coded;
redirectType average;
outputControl outputTime;
code
#{
const volScalarField& p =
mesh().lookupObject<volScalarField>("p");
Info<<"p avg:" << average(p) << endl;
#};
}
);
OpenFOAMユーザーガイドにも,説明がある。
OpenFOAM User Guide: 6.2 Function Objects
http://cfd.direct/openfoam/user-guide/function-objects/
ソルバ内に作成されている変数を書き出すためには,writeRegisteredObject タイプを使用する。変数を新たに定義して書き出すためには,これは使えない。少し込み入ったコードを作成する必要がある。
CFD-Online に,関連するディスカッションが存在する。下記のポスト#9を参考にして,サンプルを作成した。
http://www.cfd-online.com/Forums/openfoam-programming-development/99207-create-registered-object-runtime-using-functionobject.html#post384295
functions
(
str
{
functionObjectLibs ("libutilityFunctionObjects.so");
type coded;
redirectType strRate; // arbitrary name
//outputControl outputTime; // for Info
outputControl timeStep; // for Info
outputInterval 1; // strRate avg will be written every time step
code
#{
const volVectorField& U = mesh().lookupObject<volVectorField>("U");
static autoPtr<volScalarField> pField;
if(!pField.valid())
{
Info << "Creating strRatio" << nl;
pField.set
(
new volScalarField
(
IOobject
(
"strRatio",
mesh().time().timeName(),
U.mesh(),
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
Foam::sqrt(2.0)*mag(symm(fvc::grad(U)))
)
);
}
volScalarField &strRatio = pField();
strRatio.checkIn();
strRatio = Foam::sqrt(2.0)*mag(symm(fvc::grad(U)));
Info<<"strRate avg:" << average(strRatio) << endl;
#};
}
);
function objects に関する参考サイト
function objects
http://www.geocities.co.jp/penguinitis2002/study/OpenFOAM/function_objects.html
Tip Function Object writeRegisteredObject
https://openfoamwiki.net/index.php/Tip_Function_Object_writeRegisteredObject