DEXCSランチャー v2.5 製作メモ / 3.2

3.2 残差プロット 2



ここでは、 DEXCS ランチャーで作成したケースファイルに対して、 [ Analysis control] タスク画面(図 11 )
を改変使用して、計算実行、残差プロット表示できないものか、試みた結果について記しておく。

図 11 [Analysis control] タスク画面

[Analysis control] タスク画面は、 CfdOF ツールバーの [Edit Properties and run solver] ボタンをクリック、または CfdSolver コンテナをダブルクリックした時に現れる。
CfdOF 本来の使用方法としては、 Case[Write] ボタンを押すと解析用のケースフォルダ( case )が作成され、
Solver[Run] ボタンがアクティブになって、これをクリックすると計算実行が始まり、同時に残差プロット画
面が現れ、残差プロット図が 2 秒毎に更新される。 Results[Paraview] ボタンをクリックすれば、 Paraview が
立ち上がって可視化できるという仕組みである。
Solver[Run] ボタンをクリックすると、 _TaskPanelCfdSolverControl.py の 74 行目

74: self.form.pb_run_solver.clicked.connect(self.runSolverProcess)


に従って、 runSolverProcess

152: def runSolverProcess(self):
153:     self.Start = time.time()
154:
155:     solverDirectory = os.path.join(self.working_dir, self.solver_object.InputCaseName)
156:     solverDirectory = os.path.abspath(solverDirectory)
157:     cmd = self.solver_runner.get_solver_cmd(solverDirectory)
158:     FreeCAD.Console.PrintMessage(’ ’.join(cmd) + ’\n’)
159:     envVars = self.solver_runner.getRunEnvironment()
160:     QApplication.setOverrideCursor(Qt.WaitCursor)
161:     self.solver_run_process.start(cmd, env_vars=envVars)
162:     if self.solver_run_process.waitForStarted():
163:         # Setting solve button to inactive to ensure that two instances of the same
164:         # simultaneously
165:         self.form.pb_write_inp.setEnabled(False)
166:         self.form.pb_run_solver.setEnabled(False)
167:         self.form.terminateSolver.setEnabled(True)
168:         self.form.pb_paraview.setEnabled(True)
169:         self.consoleMessage("Solver started")
170:     else:
171:          self.consoleMessage("Error starting solver")
172:     QApplication.restoreOverrideCursor()

が起動、 157 行目にて、 self.solver runner.get solver cmd(solverDirectory) を経て、 CfdRunnableFoam.py
の、 get_solver_cmd

89: def get_solver_cmd(self, case_dir):
90:     self.initResiduals()
91:
92:     self.residualPlot = ResidualPlot()
93:
94:     # Environment is sourced in run script, so no need to include in run command
95:     cmd = CfdTools.makeRunCommand(’./Allrun’, case_dir, source_env=False)
96:     FreeCAD.Console.PrintMessage("Solver run command: " + ’ ’.join(cmd) + "\n")
97:     return cmd

となっており、 92 行目で残差プロットを起動、 95 行目で ./Allrun コマンドを実行するというものである。で
は、この Allrun はどうなっているかというと、図 11[Analysis control] タスク画面の Case[Write] ボタンを
クリックした際に自動生成されるもので、以下の内容になっていた。

1: #!/bin/bash
2:
3: runCommand()
4: {
5: if [ "$1" == "mpiexec" ]; then sol="$4"; else sol="$1"; fi
6: sol=$(basename -- "$sol")
7: sol="${sol%.*}"
8: if [ -f log."$sol" ]; then rm log."$sol"; fi
9: "$@" 1> >(tee -a log."$sol") 2> >(tee -a log."$sol" >&2)
10: err1=$?
11: if [ ! $err -eq 0 ]; then exit $err; fi
12: }
13:
14: # Unset and source bashrc
15: FOAMDIR="/home/et/OpenFOAM/OpenFOAM-v2006"
16: source "$FOAMDIR/etc/config.sh/unset" 2> /dev/null
17: source "$FOAMDIR/etc/bashrc"
18:
19: # Copy mesh from mesh case dir if available
20: MESHDIR="../meshCase"
21: if [ -f "$MESHDIR"/constant/polyMesh/faces ]
22: then
23: rm -r constant/polyMesh 2> /dev/null
23: cp -r "$MESHDIR"/constant/polyMesh constant/polyMesh
24: elif [ ! -f constant/polyMesh/faces ]
25: then
26: echo "Fatal error: Unable to find mesh in directory $MESHDIR" 1>\&2
27: exit 1
28: fi
29:
30: # Update patch name and type
31: runCommand createPatch -overwrite
32:
33: # Run application in parallel
34: runCommand decomposePar -force
35: runCommand mpiexec -np 4 simpleFoam -parallel

ポイントは、 19 〜 28 行目にて、メッシュをコピーしている点や、 30 〜 31 行目は createParch にて、境界条
件を設定している点であり、これらは本節での用途では不要となるもので、最終の 2 行で、独自の組み込

み runCommand ( 3 〜 12 行目)で領域分割と並列計算を実行しているということである。そこで、試しに、
DEXCS ランチャーの計算実行時に作成されるスクリプト run を Allrun に変更して使用してみたところ、問
題なく動作する事は確認できた。但し、これだけでは、ケースファイルがデフォルト( /tmp )の case フォル
ダ化にあることが前提なので、「編集」⇒「設定」メニューにて、このデフォルトを、解析モデルが存在する
ディレクトリに設定しておくのと、 CfdSolverFoam.py の 85 行目を以下変更した。

85: #addObjectProperty(obj, "InputCaseName", "case", "App::PropertyFile", "Solver",
86: addObjectProperty(obj, "InputCaseName", "", "App::PropertyFile", "Solver",

そこで、次にこの Allrun を自動作成する方法であるが、これには現行の [Analysis control] タスク画面の
Case[Write] ボタンをクリックした時の動作を変更するというのが順当であろう。つまり、

72:#self.form.pb_write_inp.clicked.connect(self.write_input_file_handler)
73:self.form.pb_write_inp.clicked.connect(self.write_input_file_handler_dexcs)

として 、 write_input_file_handlerの代わりに相 応 の write_input_file_handler_dexcs を作成した 。
write_input_file_handler は、

def write_input_file_handler(self):
    self.Start = time.time()
    import CfdCaseWriterFoam
    import importlib
    importlib.reload(CfdCaseWriterFoam)
    if self.check_prerequisites_helper():
        self.consoleMessage("Case writer called")
        self.form.pb_paraview.setEnabled(False)
        self.form.pb_edit_inp.setEnabled(False)
        self.form.pb_run_solver.setEnabled(False)
        QApplication.setOverrideCursor(Qt.WaitCursor)
        try:
            FreeCADGui.addModule("CfdCaseWriterFoam")
            FreeCADGui.doCommand("writer = CfdCaseWriterFoam.CfdCaseWriterFoam(FreeCAD.
self.solver_runner.analysis.Name + ")")
            FreeCADGui.doCommand("writer.writeCase()")
        except Exception as e:
            self.consoleMessage("Error writing case:", "#FF0000")
            self.consoleMessage(type(e).__name__ + ": " + str(e), "#FF0000")
            self.consoleMessage("Write case setup file failed", "#FF0000")
            raise
        finally:
            QApplication.restoreOverrideCursor()
            self.consoleMessage("Write case is completed")
            self.updateUI()
            self.form.pb_run_solver.setEnabled(True)
        else:
            self.consoleMessage("Case check failed", "#FF0000")

となっていたのを、以下朱字部分に変更しただけである。

def write_input_file_handler[_dexcs](self):
    self.Start = time.time()
    import [dexcsCfdCaseWriterFoam]
    import importlib
    importlib.reload([dexcsCfdCaseWriterFoam])
    if self.check_prerequisites_helper():
        self.consoleMessage("[Writing dexcs Allrun ...]")
        self.form.pb_paraview.setEnabled(False)
        self.form.pb_edit_inp.setEnabled(False)
        self.form.pb_run_solver.setEnabled(False)
        QApplication.setOverrideCursor(Qt.WaitCursor)
        try:
            FreeCADGui.addModule("[dexcsCfdCaseWriterFoam]")
            FreeCADGui.doCommand("writer =      [dexcsCfdCaseWriterFoam.dexcsCfdCaseWriteself.solver_runner.analysis.Name + ")")
            FreeCADGui.doCommand("writer.[writeAllrun()]")
        except Exception as e:
            self.consoleMessage("Error writing case:", "#FF0000")
            self.consoleMessage(type(e).__name__ + ": " + str(e), "#FF0000")
            self.consoleMessage("Write case setup file failed", "#FF0000")
            raise
        finally:
            QApplication.restoreOverrideCursor()
            self.consoleMessage("[Write dexcs Allrun is completed]")
            self.updateUI()
            self.form.pb_run_solver.setEnabled(True)
        else:
            self.consoleMessage("Case check failed", "#FF0000")

朱字部分の変更も、オリジナルが CfdCaseWriter を import していたのに対し、これを dexcsCfdCaseWriterに変更しているので、関連部を機械的に変更したのと、メッセージの変更、実際の書き込みを行う関数( writer )
の内容が変更するので相応部分を変更しているだけである。
dexcsCfdCaseWriter.py も、オリジナルの CfdCaseWriter.py をベースに変更した。とはいうもの、オリジ
ナルの CfdCaseWriter.py 中で定義している様々な関数は使わない。念の為、

def __init__(self, analysis_obj):

の初期化部分だけはそのまま流用している。これはこの関数がコールされた時の引数( analysis_obj )を
使って、 self.working_dir など、書き込みに必要となるパラメタをここで定義しており、これらはそのまま使
いたいためである *5 。これ以外の関数はすべて削除、新たに Allrun ファイルを作成する関数( writeAllrun )
を、 DEXCS ランチャーの作法に則り作り直している。

55: def writeAllrun(self, progressCallback=None):
56:     """ writeCase() will collect case settings, and finally build a runnable case. """
57:     cfdMessage("Writing AllrunDexcs to folder {}\n".format(self.working_dir))
58:     if not os.path.exists(self.working_dir):
59:         raise IOError("Path " + self.working_dir + " does not exist.")
60:
61:     # Perform initialisation here rather than __init__ in case of path changes
62:     self.case_folder = os.path.join(self.working_dir, self.solver_obj.InputCaseName)
63:     self.case_folder = os.path.expanduser(os.path.abspath(self.case_folder))
64:
65:     os.chdir(self.case_folder)
66:     solver = self.getSolver().replace(’;’,’’)
67:
68:     import pathlib
69:     fname = os.path.join(self.case_folder, "Allrun")
70:     p_new = pathlib.Path(fname)
71:
72:     title = "#!/bin/bash\n"
73:     configDict = pyDexcsSwakSubset.readConfigTreeFoam()
74:     envOpenFOAMFix = configDict["bashrcFOAM"]
75:     configDict = pyDexcsSwakSubset.readConfigDexcs()
76:     envTreeFoam = configDict["TreeFoam"]
77:     envOpenFOAMFix = envOpenFOAMFix.replace(’ $ TreeFoamUserPath’,envTreeFoam)
78:     envOpenFOAMFix = os.path.expanduser(envOpenFOAMFix)
79:     envSet = "source " + envOpenFOAMFix + ’\n’
80:     #envSet = ". /opt/OpenFOAM/OpenFOAM-v2006/etc/bashrc\n"
81:     solverSet = solver + " | tee solve.log"
82:     cont = title + envSet + solverSet
83:
84:     with p_new.open(mode=’w’) as f:
85:     f.write(cont)
86:
87:     # Update Allrun permission - will fail silently on Windows
88:     fname = os.path.join(self.case_folder, "Allrun")
89:     import stat
90:     s = os.stat(fname)
91:     os.chmod(fname, s.st_mode | stat.S_IEXEC)
92:
93:     cfdMessage("Successfully wrote case to folder {}\n".format(self.working_dir))
94:
95:     self.template_path = os.path.join(CfdTools.get_module_path(), "data", "dexcs")
96:     settings={}
97:     settings[’system’]={}
98:     settings[’system’][’CasePath’] = self.case_folder
99:     TemplateBuilder.TemplateBuilder(self.case_folder, self.template_path, settings)
100:
101:    return True

55 〜 63 、 87 〜 93 行は、オリジナルの writeCase 関数部分から流用しており、 72 〜 85 が、 DEXCS ランチャーと同じやり方で実行スクリプトを作成している部分である。ここで 66 行目でソルバー名( solver )を、 getSolver 関数で取得している。留意点として、ソルバー名を取得する関数として、オリジナルの CfdCaseWriterFoam.pyでは getSolverName という関数を定義しているが、これは CfdOF のコンテナ情報から取得するもので、DEXCS ランチャーではケースファイルが存在するという前提なので、 system/controlDict を読み取って取得( getSolver )という違いがある。
また、 95 〜 99 行目は、 Paraview の起動用に、スクリプト( pvScript.py )と、ダミーファイル pv.foam を作成するもので、本来この関数( writeAllrun )に含めるべき内容ではないが、便宜的にここで作成してみたものであり、いずれは別関数なりで処理することにしたい。本ブロックは、先の 2.4 にて、テンプレートファイルを書き換える仕組みとして TemplateBuilder について汎用的に使えると記したが、ここで実際にそういう使い方を実践してみたということであり、本例を参考にすれば、応用範囲も拡げられそうである。
以下簡単に、本例での書き換え内容を説明しておく。 99 行目が、

TemplateBuilder.TemplateBuilder(self.case_folder, self.template_path, settings)

と な っ て お り 、こ れ で 、「 self.template path 中 の フ ァ イ ル を settings に 応 じ て 書 き 換 え た も の
を self.case folder に 収 納 す る 」と い う こ と を や っ て く れ る 。こ こ で 、 self.template path は こ の 場
合、 .FreeCAD/Mod/CfdOF/data/dexcs であり、その中には、 pv.Foam と、 pvScriopt.py という 2 つの
ファイルを収納してある。 pv.foam はダミーファイルで単にそのまま self.case folder (解析用のケースフォルダ)にコピーされるだけであるが、 pvScriopt.py は、以下のようになっており、

1: #### import the simple module from the paraview
2: from paraview.simple import *
3: #### disable automatic camera reset on ’Show’
4: paraview.simple._DisableFirstRenderCameraReset()
5:
6: # create a new OpenFOAMReader
7: pfoam = OpenFOAMReader(FileName=r’%(system/CasePath%)/pv.foam’)
8: %{%(solver/Parallel%)
9: %:True
10: pfoam.CaseType = ’Decomposed Case’
11: %:False
12: pfoam.CaseType = ’Reconstructed Case’
13: %}
14: pfoam.Decomposepolyhedra = 0
15:
16: # get active view
17: renderView1 = GetActive
18:	   ...... 以下省略

これを setting パラメタ(辞書)を使って書き換えるということである。本例で定義した setting は 1 項目

settings[’system’][’CasePath’] = self.case_folder

だけなので、

  • 7 行目の、 %(system/CasePath%) の部分を、 self.case folder に置き換える。
  • 8 行目の %(solver/Parallel%) に対しては、この辞書が存在しないので、 12 行目が採用される。

ということになる。

前へ 目次 次へ

DEXCSランチャー v2.5 製作メモ/ 3

3 DEXCS ワークベンチ / ランチャー化へ向けての取り組み



まずは、残差プロットの仕組みを、 CfdOF ワークベンチを切り離して使えないものかを調べてみた。メッ
シュ作成からケースセットアップまでは、現行の DEXCS ランチャーで実施できているという前提である。

3.1 残差プロット 1

DEXCS ランチャーにおける[plotWatcher の起動 ] (残差プロット表示)は、 runPlotWatcher.py で、
PyFoam の pyFoamPlotWatcher.py を起動できるようにしたものであった (94 〜 109 行目 ) 。

94: cont = "#!/bin/bash\n"
95: cont = cont + ". " + envOpenFOAMFix + "\n"
96: cont = cont + ’echo -n "running plotWatcher"\n’
97: cont = cont + "pyFoamPlotWatcher.py " + logFile + " 1> /dev/null 2> /dev/null\n"
98: f = open("plotWatcher", "w")
99: f.write(cont)
100: f.close()
101: os.system("chmod a+x plotWatcher")
102: title = solveCaseFix
103: if len(title) > 30:
104: title = "_..." + title[-30:]
105: title = "plotWatcher:" + title
106: #comm = "gnome-terminal --name=" + title + " --geometry=80x2 --hide-menubar -x bash --rcfil
107: comm = "gnome-terminal --name=" + title + " --geometry=80x2 --hide-menubar -- bash --rcfile
108: os.system(comm)
109: 9os.chdir(saveDir)

この部分を以下のように書き換えた。

156:
#print(logFile)
157:
158: UxResiduals = []
159: UyResiduals = []
160: UzResiduals = []
161: pResiduals = []
162: rhoResiduals = []
163: EResiduals = []
164: kResiduals = []
165: omegaResiduals = []
166: niter = 0
167: itimer=1
168:
169: residualPlot = ResidualPlot()
170:
171: #Timer.setInterval(2000)
172: #Timer.timeout.connect(_plotResidual(logFile, niter))
173: #Timer.start()
174: #while itimer:
175: _plotResidual(logFile, niter)
176: #sleep(2)
177: #_plotResidual(logFile, niter)
178: #sleep(2)
179: #_plotResidual(logFile, niter)
180: #sleep(2)

169 行目で、 ResidualPlot() を呼び出しているが、この段階では CfdOF モジュールとのは考えていないので、
便宜的に CfdOF モジュール中の、 CfdResidualPlot.py と同じ内容で、 dexcsCfdResidualPlot.py を用意し
て、 12 行目

from dexcsCfdResidualPlot import ResidualPlot

で使えるようにした。また、 175 行目 plotResidual(logFile, niter) の実体は、

113: def _plotResidual(logFile, niter):
114: print("log=",logFile)
115: f=open(modelDir+"/"+logFile)
116: loglines = f.readlines()
117: #f.close()
118: process_output(loglines, niter)
119: residualPlot.updateResiduals

logFile を読み込んで、その内容を process output(loglines, niter) に渡して、 residualPlot.updateResiduals
(プロット図をアップデート)しようとするもので、 CfdRunnableFoam.py 中のそれを真似して作成したもの
である。 process output(loglines, niter) も、 CfdOF モジュールとの連携を考えていないので、

66: def process_output(text, niter):
67: itimer = 0
68: for line in text:
69: #print(line),
70: split = line.split()
71:
72: # Only store the first residual per timestep
73: if line.startswith(u"Time = "):
74: niter += 1
75:
76: # print split
77: if "Ux," in split and niter-1 > len(UxResiduals):
78: UxResiduals.append(float(split[7].split(’,’)[0]))
79: if "Uy," in split and niter-1 > len(UyResiduals):
80: ... 以下省略 ...

と、 CfdOF モジュールの CfdRunnableFoam.py 中の 102 行目 def process output(self,text) の内容をほと
んどそのまま流用した。 CfdOF オリジナルからの変更点として、引数として niter を加えてあるが、これは
イタレーション回数を見ながら自動更新処理を出来ないかと工夫の名残りである。また、 171 行目〜 180 行目
でコメントアウトした行も、同じ目的で試行錯誤したもので、現時点で自動更新処理は出来ていないので、こ
れらの部分は不要である。
以上の改変にて、残差プロットは CfdOF と同じものを表示できるようになった(見栄えは良くなった!)。
但し、上記説明の中で記したように、計算の開始直後にこれを起動して、計算の進行とともに自動更新処理を
させようと試みたが、実現できていない。
ここで一旦、自動更新の試みを断念して、次節では別のアプローチで残差グラフ表示に取り組むこととする
が、その前に本節の取り組みで判ったことを記しておく。

判明項目17

CfdOF の残差プロットは、計算実行時の標準出力をモニターしているのに対して、今回試みたのは、
実行ログファイルの内容を読み直す方法であり、これでは無理っぽい。

判明項目18


PyFoam の plotWatcher.py はログファイルを監視しつつ更新している(多分、読み直したりはしてい
ない)ので、その方法に習えば、実現できる可能性もあるので、改めて調査予定。

判明項目19

DEXCS ランチャーで、 postProcessing フォルダ中に出力されるデータをプロットするのに、 JGNPlot
を使っているが、 CfdResidualPlot.py を参考に Plot ワークベンチで代用することはできるかもしれな
いので、これも改めて調査予定。

前へ 目次 次へ

DEXCSランチャー v2.5 製作メモ / 2. 4



2.4 CdfOFのソースコードと主要プログラムの動作メカニズム

FreeCAD に対して拡張したワークベンチは、 .FreeCAD/Mod フォルダ中に収納される。 Mod フォルダ下
には、 CfdOF フォルダと Plot フォルダがあり、それぞれのコードが収納される。
Mod フォルダ下には、以下のファイルとサブフォルダ( Gui, pycashe , data, testFiles )が存在する。

├── CfdAnalysis.py
├── CfdCaseWriterFoam.py
├── CfdConsoleProcess.py
├── CfdFaceSelectWidget.py
├── CfdFluidBoundary.py
├── CfdFluidMaterial.py
├── CfdInitialiseFlowField.py
├── CfdMesh.py
├── CfdMeshRefinement.py
├── CfdMeshTools.py
├── CfdPhysicsSelection.py
├── CfdPreferencePage.py
├── CfdPreferencePage.ui
├── CfdResidualPlot.py
├── CfdRunnableFoam.py
├── CfdSolverFoam.py
├── CfdTools.py
├── CfdZone.py
├── Init.py
├── InitGui.py
├── README.md
├── TaskPanelCfdFluidBoundary.ui
├── TaskPanelCfdFluidProperties.ui
├── TaskPanelCfdInitialiseInternalField.ui
├── TaskPanelCfdListOfFaces.ui
├── TaskPanelCfdMesh.ui
├── TaskPanelCfdMeshRefinement.ui
├── TaskPanelCfdSolverControl.ui
├── TaskPanelCfdZone.ui
├── TaskPanelPhysics.ui
├── TemplateBuilder.py
├── TestCfd.py
├── WindowsRunWrapper.py
├── _TaskPanelCfdFluidBoundary.py
├── _TaskPanelCfdFluidProperties.py
├── _TaskPanelCfdInitialiseInternalFlowField.py
├── _TaskPanelCfdMesh.py
├── _TaskPanelCfdMeshRefinement.py
├── _TaskPanelCfdPhysicsSelection.py
├── _TaskPanelCfdSolverControl.py
├── _TaskPanelCfdZone.py
├── metadata.txt

Plot ワークベンチに関しては、 Mod/Plot フォルダ下、 freecad/plot フォルダ中に以下の python コード
と、他にもいくつかのサブフォルダに分けてコードが収納されており、コードの収納方法に決まりは無いよう
である。

├── CMakeLists.txt
├── Plot.py
├── PlotGui.py
├── Plot_rc.py
├── __init__.py
├── compile_resources.py
├── freecad_backend.py
├── init_gui.py
├── plot.dox
└── version.py

どういうイベントでどのプログラムが起動されるのかという、コードの動作原理についてはまだ十分解明できていないが、現時点で判っていることを以下に記しておく。

判明項目1

メッシュ作成および解析実行ケースは、 Default output directory 下の meshcase, case フォルダにそれぞれ収納される仕組みとなっており、 Default output directory は、デフォルトでは /tmp となるが、「編集」⇒「設定」メニューにより、任意に指定は可能。

判明項目2

CfdOF ワークベンチが選択されると、 InitGui.py 中の cmdlist に定義した内容にしたがって、ツールバーのボタンと、ボタンが押された時の実行メニューが割り当てられ、ツールバーが表示される(どういう仕組みで InitGui.py が起動されるのかはわかっていない)。

判明項目3

ツールバー中の CfdAnalysis ボタンを押すと、 CfdAnalysis.py の CommandCfdAnalysis() が実行され、コンボビューに 4 つのコンテナ( PhysicsModel, FluidProperties, InitialFields, CfdSolver )が追加表示される。

判明項目4

コンボビュー上の Part オブジェクトをどれか一つを選択すると、ツールボタンの [Create a mesh usinf…] ボタンがアクティブになるので、これをクリックすると選択した Part オブジェクトを対象にfluidRegion_ Mesh コンテナが作成され、 [CFD Mesh] タスク画面が現れて、メッシュの制御(ケー ス作成、実行、表示)ボタンが使えるようになる(⇒ TaskPanelCfdMesh.py )。

判明項目5

Mesh Parameters として、 3D/2D の選択、 cfMesh/snappyHexMesh/gmsh の選択が可能で、選択に 応じてタスク画面の下部表示内容が変化する。

判明項目6

タスク画面を閉じて、モデルツリー上の fluidRegion_Mesh コンテナを選択すると、ツールボタンの [Creates a mesh refinement] ボタンがアクティブになるので、これをクリックすると [Meshrefinement] タスク画面が現れて、メッシュの細分化設定が可能になる。ここで着目したいのが、細分化対象の設定方法である(図 8 )。本来は、先にパーツを選択して、右クリックメニューなどでこの画面を出したいところであるが、かような方法であれば許容範囲でないかと思われる。

図 8 細分化対象パーツの設定
判明項目7

細分化指定のもう一つの方法、図 9 InternalVolume についても、同様に パーツ選択するだけで、プロパティに登録されるようになっているが、この設定は snappyHexMesh の場合に有効であるが、このコンテナが存在する状態で cfMesh を作成しようとするとエラーになってしまう。

図9 領域細分化の設定
判明項目8

openSimで公開されているチュートリアル資料「 CFD Tutorial 4 – External Aerodynamics of a UAV.pdf」によれば、 [Mesh region] というタスク画面で、 cfMesh 用のプリミティブ定義メニュー(図 10 )を使えているのだが、現行モジュールではこのタスク画面が出てこない。というか、タスク画面の名前そのものが異なっている。

図 10 領域細分化の設定 [Mesh region] タスク画面
判明項目9

図 9 で設定が完了し [ 閉じる ] をクリックすると、コンボビュー上でコンテナに対するプロパティとして登録されるようになる(図 9 の右下赤破線の四角枠内)。上述の cfMesh の region 設定に係る不具合もあって現行の設定メニューをそのまま使うことはできないが、このようにパーツ毎の設定情報をFreeCAD モデル本体に具現することができれば、現行 DEXCS でやっているような meshDict を読み込み直して設定を再現するという回りくどいやり方をしないで済むようになるということである。

判明項目10

CfdSolver コンテナをダブルクリックすると、 [Analysis control] タスク画面が現れる( TaskPanelCfdControl.py )。Case[Write] ボタンをクリックすればケースファイルが作られて、 Solver[Run] ボタンがアクティブになるので、それをクリックすれば計算が開始すると同時に、残差グラフが現れて、その表示内容が計算の進行とともに更新されていく。

判明項目11

Case[Write] ボタンをクリックした時に起動されるプログラムが CfdWriterFoam.py で、この中で 118行目、

TemplateBuilder.TemplateBuilder(self.case folder, self.template path, self.settings)

によって解析実行用のケースファイルが作成されている。ここに、 self.case folder が出力先フォルダ、self.template path がテンプレートケース(デフォルトでは、 FreeCAD/Mod/CfdOF/data/defaults )であり、 self.settings に様々な設定条件パラメタが収納されるという仕組みである。本 CfdWriter-Foam.py では、計算実行に必要な全パラメタセットを対象に一括してテンプレートケースを書き換えることになるが、この TemplateBuilder は汎用的に使えるようになっているので、特定ファイル中の特定のパラメタだけを対象にして、この構文を使って書き換えることもできるという点を強調しておきたい。

判明項目12

テンプレートファイルを書き換える仕組みの基本は、テンプレートファイル中 %( と %) で括られたパラメタを setting の Dict ファイルを使って書き換えるというものである。単なる置き換えだけでなく、 %{ や、 %: を使って、簡単な if 構文的な書き換えもできるようになっている。

判明項目12

残差グラフ表示は、 [Analysis control] タスク画面で、 Solver[Run] ボタンをクリックした時に起動される CfdRunnableFoam.py の(89 行目 )get solver cmd が起動され、この中で (92 行目 )

self.residualPlot = ResidualPlot()

として、 CfdRedisualPlot.py の ResidualPlot() が起動される。

判明項目13

ResidualPlot() は、 QtCore.QTimer() オブジェクトで、 self.Timer.start(2000) として、 2 秒毎に更新( self.refresh )されるようになっている。その他、グラフ軸の表示方法( Plot モジュールの設定)などはここで実施している。

判明項目14

残差データそのものは、 TaskPanelCfdControl.py 中( 55 行目)

self.solver run process = CfdConsoleProcess(finishedHook=self.solverFinished,
std-outHook=self.gotOutputLines, stderrHook=self.gotErrorLines)

として、 self.gotOutputLines にストアされた計算ログ出力が CfdRunnableFoam.py の( 102 行目)
process output(self, text): に渡されて、ログの解析を実施した後、( 138 行目) updateResidual されるようになっているので、これを CfdRedisualPlot.py の (43 行目 )def updateResiduals(self, residuals):
で受けて、 self.update フラグが True に更新されるので、残差グラフの更新も実施されという仕組みで
ある。

判明項目15

CFD Mesh タスク画面において [Write mesh case] ボタンを押すと、 184 行目の writeMesh() 関数が実行され、

208 FreeCADGui.doCommand("cart_mesh.setupMeshCaseDir()")
209 self.consoleMessage("Exporting mesh refinement data ...")
210 FreeCADGui.doCommand("cart_mesh.processRefinements()") # Writes stls so need file structure
211 FreeCADGui.doCommand("cart_mesh.processDimension()")
212 FreeCADGui.doCommand("cart_mesh.writeMeshCase()")

208 行目でメッシュ作成用ケースフォルダを作成、 212 行目にて CfdMeshTools.py の writeMesh-
Case() 関数により、ファイルの実体が書き換えられる事になるが、ここでも最終的に、 718 行目の
TemplateBuilder が使用されている。

TemplateBuilder.TemplateBuilder(self.meshCaseDir, self.template path, self.settings)
判明項目16

CFD Mesh タスク画面において [Run mesher] ボタンを押すと、 228 行目の runMesh() 関数が実行され、上記 writeMeshCase() 関数により作成された Allmesh コマンドを使って、以下のようにして、コマンドを実行し、コンソール出力している。

235 cmd = CfdTools.makeRunCommand(’./Allmesh’, cart_mesh.meshCaseDir, source_env=False)
236 FreeCAD.Console.PrintMessage("Executing: " + ’ ’.join(cmd) + "\n")

前へ 目次 次へ

DEXCSランチャー v2.5 製作メモ / 2. CdfOFとは



CfdOF は OpenFOAM のフロントエンドとして機能させるべく、 FreeCAD のワークベンチモジュールと
して開発中のもので、 https://github.com/jaheyns/CfdOF に公開されているものである(図 3 )。

図 3 CfdOF (イメージは開発元の HP より転用)

また最近になって、使用方法を解説した日本語記事も見られるようになったので、以下に記しておく。

2.1 CfdOF の使用方法概要

図 4 において、CfdOF ワークベンチを選択すると、 CfdOF ツールバーが現れるので、これを使って、
に示すような様々なコンテナを作成していくものである。図 5 には、図 4 におけるそれぞれのコンテナと
ツールボタンの対応を取り纏めておくが、解析に必要な機能が凡そ網羅されていることが確認できよう。それ
ぞれのツールボタンを押すとコンテナが作成され、そのコンテナ上で様々な選択メニューを使って FreeCAD
のコンポーネントに対応付けて解析パラメタを設定できるようになっている。当然であるが、作成されたコン
テナをダブルクリックして設定変更も可能である。

図 4 CfdOF の使用方法イメージ
図 5 CfdOF の主要コンテナ

2.2 CfdOF の特徴と使用感

(注)評価は2021年5月時点のもので、本記事の公開時点(2021年7月)では更新されたものになっており、その内容については未評価である。

ざっと使ってみただけの使用感であるが、ソルバー選択(図 6 )や流体の選択メニュー(図 7 )に見られる
ように、商用ソフト的な使い方を目指したソフトと思われた。残念ながら現時点ではソルバー対応が不十分、
メッシュの詳細適合が困難などあって、限定的な用途でしか使えないと考えられた。特に後者で cfMesh の領
域細分化機能を使えないのが致命的であった。

図 6 ソルバー選択タスク画面
図 7 流体特性選択タスク画面

一方、フレーム全体としては、 FEM ワークベンチと類似であり、次節に示すようにコード内容も比較的容
易に理解できるものであったので、 DEXCS ランチャーの新プラットフォームとして、本ワークベンチを使え
そうな感触は得られた。

2.3 DEXCS ワークベンチ / ランチャー化へ向けての着眼点・方針

DEXCS-OF の GUI 化コンセプトは、商用ソフトのそれとは異なり、 OpenFOAM 本来の設定ファイルを
ブラックボックス化するものではなく、あくまで設定ファイルの変更や編集の手助けをするツールとして位置
づけるものである。
したがって、 CfdOF のコンテナの中で、

  • ソルバー選択
  • 流体特性
  • 初期条件
  • 境界条件

等のコンテナについてまで流用しようとするものでなく、これらは現行 DEXCS ランチャーの機能で十分と
考えている。
一方、現行 DEXCS のメッシュ作成マクロについては、改良したい課題もあるので、 CfdOF のコンテナの

  • メッシュ作成ケース
  • メッシュ細分化設定

を使って、現行 Wiget で実施出来ている機能(+改良予定項目)が実現出来るべく、現行 CfdOF/ メッシュ
細分化設定コンテナのプロパティを拡張できないか?という考え方である。
また、

  • ソルバー実行ケース

コンテナについては、現行 DEXCS ランチャーの機能でも十分ではあるが、残差プロット表示は見た目にも
DEXCS のそれよりも美しい。これは Plot ワークベンチを使っているという説明であったが、あわよくばこ
れを使って現行 DEXCS の jgp を代用できる可能性もありそうな感触を得た。
そこで現行 CfdOF のコードについて、メッシュ作成とソルバー実行⇒残差グラフ表示の仕組みあたりを中
心に、まずはどういう仕組みでプログラムが成り立ち、動いているのか調べてみた。

前へ 目次 次へ

DEXCSランチャー v2.5 製作メモ/ 1. はじめに



DEXCS ランチャーは、図 1 に示すような開発経緯を経て、 v2 ( DEXCS2019 )以降の現在は FreeCAD を
プラットフォームとして起動することで、解析対象を見ながら設定が可能となり、それなりの使い勝手が向上
したと考えている。

図 1 DEXCS ランチャー開発経緯

一方、解析に際して肝となるのがメッシュ作成であり、 v1.5 ( DEXCS2014 )ではこれを従来の snappy-
HexMesh から cfMesh に変更することで、設定も作成も容易になった。とは云うもの、 cfMesh のフルオプ
ションを手軽に設定できるまでには至っていないので、これを少しずつ改良して現在に至っているが、依然と
していくつかの問題が残されている。たとえば、

  • スケール変換機能の組み込み
  • meshDict インポート不具合対応
  • オプションパラメタの GUI 化
  • テンプレートケースの変更設定
  • maxCellSize のロジック変更
  • OF 端末起動

といったあたりである。
それぞれの具体的な課題は認識されており、個々の対応もさほど難しいものではないが、これを現在の
Widget 上で実現するのは困難になってきた(図 2 )。


図 2 メッシュ作成マクロ( Widget )の変遷

そこで、これまでの設定方法をこの Widget の手直しでなく、 DEXCS ワークベンチともいえるような新た
なフレーム上で再構築できないと考えた。とはいえこれをスクラッチで作成出来る能力はないので、既存のフ
レームを改変して実現できないかと考えた。既存のフレーム(ワークベンチ)を調査したところ、 CfdOF と
いうワークベンチが候補として浮上した。

目次 次へ