4.5 まとめ
以上で、CfdOFを改変して、DEXCSランチャーの機能の肩代わりと、予定していた機能追加を凡そ実現できたと考えている(次章のpost処理機能は、CfdOFの改変とは直接関係ない)。
ここで改めて、DEXCS標準チュートリアルを題材に改変したdexcsCfdOFの動作を確認し、表示や操作方法の面で問題になるかもしれない項目を(これまでの取り組みで今後の課題とした項目も含めて)取り纏めておくことにした。
4.5.1 動作確認
先に、3.7. 中間まとめで実施したものと比較しながら説明する。ワークベンチを切り替え、[CfdAnalysisis]ボタンをクリックするまでは同じであるが、ここでは、この段階で、

CFDMeshコンテナも併せて追加されるようになっている。これをダブルクリックすれば、改変したメッシュ作成タスク画面(dexcsCFD Mesh)が表示される。

これを一旦閉じて、CFDMeshコンテナを選択した状態にあれば、[メッシュ細分化]ボタンが有効になるので、これをクリックすると、同様に改変したメッシュ細分化のタスク画面(Mesh refinement)が現れる。

オリジナルのCdfOF設定画面に比べると、設定項目が増えたという煩わしさはあるかもしれないが、細分化レベルとセルサイズが連動して動く辺りは解りやすくなったのではないかと思う。追加した項目についても、cfMeshに関する知識の無い人には難しいかもしれないが、何もチェックせずそのままでも使えるので大きな問題はないが、後でもう少し考えることとしたい。

DEXCS標準チュートリアルの場合の推奨設定は、Dexcsを対象とした表面細分化と、regionBoxを対象とした内部領域細分化を指定することになる(図)が、対象オブジェクト毎の区別でなく、細分化方法毎の区別である点には留意したい。すなわち細分化方法というのは、
- 表面細分化か内部細分化
- 細分化レベルの違い
- レイヤ-の有無、またそのパラメタの違い
- keepCellIntersectingPatchesオプションの有無
- removeCellsIntersectingPatchオプションの有無
の違いに応じて必要な数だけ追加することになるのであって、オブジェクトを対象に個々に設定する必要はなく、Referencesのリストの中で複数のオブジェクトを指定することが出来る。但し一つのオブジェクトに対して、複数の異なる設定があった場合の結果がどうなるかは、やってみないとわからない(どちらが設定されるかはケースバイケースになると思われる)。
細分化設定が終了したら、メッシュ作成タスク画面に戻る。グローバルオプションや、Scale to Meter といった改変項目はあるが、DEXCS標準チュートリアルの場合はこのまま[Write mesh case]⇒[Run mesher]⇒{Paraview]と押していって、ソルバー実行までの操作は3.7. 中間まとめで実施したのと全く同一の手順で同一の結果になる。
4.5.2 問題点など
メッシュ作成タスク画面
- コンボビューのタスク画面は縦スクロール可能だが横スクロールができない。改変によって横幅が大きくなった事により、画面サイズの変更等の手間が増える。⇒横幅が大きくならないレイアウトにできれば良い。
- Visualisation ブロックの、[Load surface mesh][Clear]ボタンの意味不明⇒当面削除
- 代わりに[checkMesh]でどうか
- Mesh Parameter ブロックの[Element dimension:],[Mesh utility]⇒当面削除
- optimiseLayer オプションのmaximum allowed thickness のデフォルト値 0.01 ⇒ 0.05 ⇒(5)
メッシュ作成コンテナ
- [Characteristic Length Max] ⇒ [Base Mesh Size] ⇒(2)
- 上記のロジック変更⇒(3)
- 使用しないまたは不要なパラメタ
- Case Name
- Number Of Processes
- Number Of Treads
- STLLinear Deflection
- Cells Between Levels
- Edge Refinement
- (Element Dimension)
- (Mesh Utility)
- Part
メッシュ細分化タスク画面
- Boundary Layersにチェックを入れた場合の[Number of layers:]デフォルト値 1⇒ 3 ⇒(6)
- [keepCells…][removeCells…]を[MoreOption]で一括 ⇒(8)
- References ⇒ Object ⇒(7)
- Refinement Parameter (cfMesh) のラベル不要、パラメタも[MoreOption]へ
メッシュ細分化コンテナ
- snappy Hex… 以下は不要 ⇒(9)
ソルバー
- Input Case Name ?
- 並列オプション
- タスク画面で設定項目なし
- プロパティで設定はあるが、機能していない
- Iteration Control / Time Step Control は使用していない
その他全般
- ワークベンチのアイコン
- プロパティのい表示される数値の小数点以下桁数の問題
- CfdOFのオリジナルソース(ファイル名)の改変⇒別名(dexcs….py)⇒(1)
- testDict_…. ⇒ dexcsCfdDict_… ⇒(4)
- 日本語辞書
4.5.3 追加のソース改変
前節の問題点に対し、現時点で対応可能であった箇所について、以下に取り纏めておくが、対応の順番は行辺りばったりである点はお断りしておく。
(1) CfdOFのオリジナルソース(ファイル名)の改変⇒別名(dexcs….py)
最終的に、CfdOFのオリジナルソースからの変更点をdiffツールを使って明確にしたくなるであろうから、現時点でCfdOFオリジナルのファイル名と、それに対応するdecxsCfdOFのファイル名との対応表を以下に示しておく。
基本は、オリジナルのコードを少しでも変更したら改名しているが、改名したファイルをインポートするファイルの名前も変更する必要が出てくるので、最終的にはほとんどすべてのファイル名を変更する必要が生じてしまう。さすがにinitGUI.py の名前まで変更してしまうと、(多分)ワークベンチが起動しなくなってしまうので、そこまでは改名しなかったが、そのまま使えているファイルもいくつか存在する。
CfdOFオリジナル | dexcsCfdOF |
---|---|
CfdAnalysis.py | dexcsCfdAnalysis.py |
CfdCaseWriterFoam.py | dexcsCfdCaseWriterFoam.py |
CfdConsoleProcess.py | dexcsCfdConsoleProcess.py |
CfdFaceSelectWidget.py | CfdFaceSelectWidget.py |
CfdFluidBoundary.py | |
CfdFluidMaterial.py | |
CfdInitialiseFlowField.py | |
CfdMesh.py | dexcsCfdMesh.py |
CfdMeshRefinement.py | dexcsCfdMeshRefinement.py |
CfdMeshTools.py | |
CfdPhysicsSelection.py | dexcsCfdMeshTools.py |
CfdPreferencePage.py | dexcsCfdPreferencePage.py |
CfdPreferencePage.ui | CfdPreferencePage.ui |
CfdResidualPlot.py | CfdResidualPlot.py |
CfdRunnableFoam.py | dexcsCfdRunnableFoam.py |
CfdSolverFoam.py | dexcsCfdSolverFoam.py |
CfdTools.py | dexcsCfdTools.py |
CfdZone.py | |
Init.py | Init.py |
InitGui.py | InitGui.py |
README.md | README.md |
TaskPanelCfdFluidBoundary.ui | |
TaskPanelCfdFluidProperties.ui | |
TaskPanelCfdInitialiseInternalField.ui | |
TaskPanelCfdListOfFaces.ui | TaskPanelCfdListOfFaces.ui |
TaskPanelCfdMesh.ui | dexcsTaskPanelCfdMesh.ui |
TaskPanelCfdMeshRefinement.ui | dexcsTaskPanelCfdMeshRefinement.ui |
TaskPanelCfdSolverControl.ui | TaskPanelCfdSolverControl.ui |
TaskPanelCfdZone.ui | |
TaskPanelPhysics.ui | |
TemplateBuilder.py | TemplateBuilder.py |
TestCfd.py | |
WindowsRunWrapper.py | WindowsRunWrapper.py |
_TaskPanelCfdFluidBoundary.py | |
_TaskPanelCfdFluidProperties.py | |
_TaskPanelCfdInitialiseInternalFlowField.py | |
_TaskPanelCfdMesh.py | _dexcsTaskPanelCfdMesh.py |
_TaskPanelCfdMeshRefinement.py | _dexcsTaskPanelCfdMeshRefinement.py |
_TaskPanelCfdPhysicsSelection.py | |
_TaskPanelCfdSolverControl.py | _dexcsTaskPanelCfdSolverControl.py |
_TaskPanelCfdZone.py | |
metadata.txt | metadata.txt |
Gui | Gui |
data/CfdFluidMaterialProperties | |
data/defaults | |
data/defaultsMesh | |
data/dexcs | |
data/dexcsMesh | |
testFiles | |
dexcsCfMeshTools.py |
右欄黒字以外のファイルは、左欄のオリジナルファイルをベースに改変が施されている。また最下行の、dexcsCfMeshTools.py は、DEXCSマクロのオリジナルコードを改変したものであり、その上の緑字フォルダ内に収録されたファイルは、オリジナルのdata/defaults, data/defaultsMeshに存在したparaViewの立ち上げ用スクリプトだけをフォルダ名を変更して追加したものである。
(2) CharacteristicLengthMax ⇒ BaseCellSize
基本的にテキスト検索して、置き換えるだけである。
- _dexcsTaskPanelCfdMesh.py
def load(self):
""" Fills the widgets """
setQuantity(self.form.if_max, self.mesh_obj.CharacteristicLengthMax)
def store(self):
FreeCADGui.doCommand("FreeCAD.ActiveDocument.{}.MeshUtility "
"= '{}'".format(self.mesh_obj.Name, self.form.cb_utility.currentText()))
FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.CharacteristicLengthMax "
"= '{}'".format(self.mesh_obj.Name, getQuantity(self.form.if_max)))
- _dexcsTaskPanelCfdMeshRefinement.py
(L73) self.baseMeshSize = Units.Quantity(self.mesh_obj.CharacteristicLengthMax).Value
(L109) self.mesh_obj.CharacteristicLengthMax = float(cellLength) * 2**(self.form.if_reflevel.value())
- dexcsCfdMesh.py
(L138) addObjectProperty(obj, "CharacteristicLengthMax", "0 m", "App::PropertyLength", "Mesh Parameters",
"Max mesh element size (0.0 = infinity)")
- dexcsCfdMeshTools.py
(L54) self.clmax = Units.Quantity(self.mesh_obj.CharacteristicLengthMax).Value
(L86) self.mesh_obj.CharacteristicLengthMax = sumOf3Edges / 60.0
- dexcsCfMeshTools.py
(L1694) testDict_maxCellSize = self.mesh_obj.CharacteristicLengthMax * self.mesh_obj.ScaleToMeter
(3) BaseMeshSize のロジック変更
前項において、dexcsCfdMeshTools.pyにてBaseCellSizeを計算していることが改めてわかったので、ついでにこのロジックも変更した。
#self.mesh_obj.BaseCellSize = sumOf3Edges / 60.0
self.mesh_obj.BaseCellSize = ((xmax-xmin)*(ymax-ymin)*(zmax-zmin)/6000) ** (1/3)
旧ロジックもコメント行として残しておくことにした。6000という数字は、Dexcsの標準チュートリアル問題にて、旧ロジックと大体同じ値になるように設定したものである。
(4) testDict_…. ⇒ dexcsCfdDict_…
前々項において、testDict_…という変数名を使用している箇所に辿り着いているので、前項と同様、ついでにこれも修正しておく。
(L1693)
#testDict = True
testDict_maxCellSize = self.mesh_obj.BaseCellSize * self.mesh_obj.ScaleToMeter
testDict_minCellSize = Model.EMPTY_STR
testDict_untangleLayerCHKOption = 0
testDict_optimiseLayerCHKOption = self.mesh_obj.optimiseLayer
testDict_opt_nSmoothNormals= str(self.mesh_obj.opt_nSmoothNormals)
testDict_opt_maxNumIterations= str(self.mesh_obj.opt_maxNumIterations)
testDict_opt_featureSizeFactor= str(self.mesh_obj.opt_featureSizeFactor)
if self.mesh_obj.opt_reCalculateNormals==1:
testDict_opt_reCalculateNormalsCHKOption = "1"
else:
testDict_opt_reCalculateNormalsCHKOption = "0"
testDict_opt_relThicknessTol= str(self.mesh_obj.opt_relThicknessTol)
testDict_keepCellsIntersectingBoundaryCHKOption = self.mesh_obj.keepCellsIntersectingBoundary
なお、L1693をコメント行に変更したのは、オリジナルのDEXCSマクロにおいて、細分化指定パラメタの数字をCellSize / RefLevelのどちらで解釈させるかに応じて、隠しパラメタ的にmeshDict中に出力していた箇所(下記)
(L1714)
#if self.viewControl.get_refinementOption() == 1 :
#if (testDict) :
# strings = ['//CellSize\n']
#else:
# strings = ['//RefLevel\n']
#meshDict.writelines(strings)
があった為、これまでは、self.viewControl.を使わずにこの部分を整合させようとして暫定的に使用していたものであるが、今後は必要無しと判断し、上記ブロックも併せてコメントアウトした(最終的には削除の予定)。
(L1733) 'maxCellSize\t' + str(testDict_maxCellSize) + ';\n'
(L1741)
minCellSizeValue = testDict_minCellSize
if str(minCellSizeValue) != Model.EMPTY_STR:
meshDict.write('minCellSize\t' + str(minCellSizeValue) + ';\n')
else:
meshDict.write('//minCellSize\t' + ';\n')
FmsFileName = os.path.basename(self.fmsFileName)
#if self.viewControl.get_untangleLayerCHKOption() == 1 :
if testDict_untangleLayerCHKOption == 1 :
untangleLayerString = '\tuntangleLayers 0; // \n'
else :
untangleLayerString = '\t// untangleLayers 0; // \n'
#if self.viewControl.get_optimiseLayerCHKOption() == 1 :
if testDict_optimiseLayerCHKOption == 1 :
(L1800)
' \t\tnSmoothNormals\t' + testDict_opt_nSmoothNormals + ';\n'
'\t\n'
' \t\t// maximum number of iterations\n'
' \t\t// of the whole procedure (optional)\n'
#' \t\tmaxNumIterations\t5;\n'
' \t\tmaxNumIterations\t' + testDict_opt_maxNumIterations + ';\n'
'\t\n'
' \t\t// ratio between the maximum layer thickness\n'
' \t\t// and the estimated feature size (optional)\n'
#' \t\tfeatureSizeFactor\t0.4;\n'
' \t\tfeatureSizeFactor\t' + testDict_opt_featureSizeFactor + ';\n'
'\t\n'
' \t\t// activale 1 or deactivate 0 calculation of normal\n'
' \t\t// (optional)\n'
#' \t\treCalculateNormals\t1;\n'
' \t\treCalculateNormals\t' + testDict_opt_reCalculateNormalsCHKOption + ';\n'
'\t\n'
' \t\t// maximum allowed thickness variation of thickness\n'
' \t\t// between two neighbouring points, devided by\n'
' \t\t// the distance between the points (optional)\n'
#' \t\trelThicknessTol\t0.01;\n'
' \t\trelThicknessTol\t' + testDict_opt_relThicknessTol + ';\n'
(L1931)
if testDict_keepCellsIntersectingBoundaryCHKOption == 1 :
(5) optimiseLayer オプションのmaximum allowed thickness のデフォルト値
dexcsCfdMesh.py
(L131)
addObjectProperty(obj, "opt_relThicknessTol", 0.05, "App::PropertyFloat", "Mesh Parameters",
"maximum allowed thickness variation of thickness between two neighbouring points, devided by the distance between the points")
(6) Boundary Layersにチェックを入れた場合の[Number of layers:]デフォルト値
_dexcsTaskPanelCfdMeshRefinement.py の、def updateUI(self)において、以下追加
if self.form.check_boundlayer.isChecked():
if self.form.if_numlayer.value()==1:
self.form.if_numlayer.setValue(3)
また、def load(self) において、
if (self.obj.KeepCell == True) or (self.obj.RemoveCell == True):
self.form.check_moreoption.setChecked(self.obj.KeepCell)
(7) References ⇒ Object
dexcsTaskPanelCfdMeshRefinement.ui 中の下記2行の表示ラベルだけを変更。
(L527)
(L577)
<string>Objects</string>
なお、このラベルは、
<widget class="QFrame" name="ReferencesFrame">
の中で記述されているので、ラベル名を変更したら、このwidget名も変更した方が、プログラムを理解するには解り易いだろうと考えられる。しかしここまで変更すると、これに関連した箇所も数10箇所変更する必要がありそうだった。これをやったとしても、ユーザー目線からは見えない部分の変更でしかない。したがって、関連箇所は変更していない。
(8) [keepCells…][removeCells…]を[MoreOption]で一括
More Option のチェックボックスを追加したので、この状態変化
self.form.check_boundlayer.stateChanged.connect(self.updateUI)
self.form.check_moreoption.stateChanged.connect(self.updateUI)
def updateUI(self) では、
if self.form.check_moreoption.isChecked():
self.form.moreoption_frame.setVisible(True)
else:
self.form.moreoption_frame.setVisible(False)
self.form.check_keepCells.setChecked(False)
self.form.check_removeCells.setChecked(False)
また
(9) メッシュ細分化コンテナのsnappy Hex…は不要(邪魔)
将来的には、snappyHexにも対応できるようになるかもしれないので、当面は削除するでなく、コメントアウト等して単に表示させないようにしたい。
本プロパティは、その定義部をコメントアウトしたところ、
# snappy:
#addObjectProperty(obj, "RegionEdgeRefinement", 1, "App::PropertyFloat", "snappyHexMesh",
# "Relative edge (feature) refinement")
だけでなく、def load(self) において、これを参照している箇所があり、エラーとなるので、これもコメントアウトする必要があった。
#self.form.if_edgerefinement.setValue(self.obj.RegionEdgeRefinement)
def accept(self)
#FreeCADGui.doCommand("FreeCAD.ActiveDocument.{}.RegionEdgeRefinement "
# "= {}".format(self.obj.Name, self.form.if_edgerefinement.value()))
他にも、参照している箇所は存在するが、現状想定される使用範囲の中で参照されることの無さそうな部分は、将来的な拡張の可能性を考えて、そのまま残すこととしている。
4.5.4 タスク画面とプロパティコンテナの再構築整理
ここまでタスク画面を変更するのに、インクルードされる拡張子が.uiのファイルを、エディタで直接変更してきたが、ファイルマネージャ上で、このファイルをダブルクリックすれば、Qt Desiner というGUIツールが立ち上がることがわかった(図)。

これを使って、
- ボタンやテキストなどのウィジェットの位置や表示名を変更して保存すれば、FreeCAD上で何の問題もなく反映される。
- 新たにウィジェットを追加しても、FreeCAD上のタスク画面には問題なく反映される。
- ウィジェットを削除する場合は、objectNameの名前を覚えておく。削除したことで問題があるようなら、FreeCAD上のタスク画面操作をした際にそのオブジェクトに関するエラーが表示される。単に未定義エラーであればプログラムの該当箇所をコメントアウトするなりの対処ができる。
- これら一連の操作をするに際して、.uiファイルの実体については、何ら参照や編集の必要は生じなかった。
ということがわかったので、以降は、これを使ってタスク画面を再構築した。
(1) タスク画面の再構築
以下に、再構築前後のタスク画面を比較表示しておくが、改変後の図中で、赤枠で括った部分は、ウィジェットを追加したというだけで、この時点で機能は実装していない。



(2) プロパティリストの再構築
コンテナを選択した時にプロパティリストに表示される項目については、それが定義されるコード箇所、すなわち
- メッシュコンテナ dexcsCfdMesh.py の、class _CfMesh / def initProperties() セクション
- メッシュ細分化コンテナ dexcsCfdMeshRefinement.py の、class _CfMeshRefinement / def initProperties() セクション
- ソルバー実行コンテナdexcsCfdSolverFoam.py の、class _CfdSolverFoam / def __init__() セクション
において、表示させたくないプロパティに相当する部分を一旦コメントアウトする。FreeCADで動作確認。エラー無く実行可能、もしくは削除したことにより、エラーが表示される場合に、それが単に被参照エラーで、その参照部分をコメントアウトするだけで、プログラム本体の実行に支障が来たすことがないようであれば、コメントアウトによる削除作業完了とした。
削除することによる影響が多くの箇所に及ぶものは、元に戻している。



なお、以上の再構築によって、dexcsCfdOFの動作に支障が無かったことは確認済みであるが、DEXCS標準チュートリアル問題での使い方でしか確認していないという点もお断りしておく。
以上で、4.5.2.で取り纏めた問題点のうちの表示上の問題の大半は解決したと考えているが、残された課題として、プロパティの値が空欄になっている箇所がある点は取り上げられるだろう。これに関しては、先に述べたように、これを削除すると、プログラム全体の多くの箇所に修正が必要になることがあげられるが、一方、CfdOF本来の使い方でなく、dexcsCfdOFとしての使い方を考えると、何らかの情報表示箇所として流用できそうな面もあった。⇒今後の課題としたい。
4.5.5 追加ウィジェットの機能拡張
前項で追加したウィジェットは大きく分けて2点。
- メッシュ作成タスク画面におけるCheckMesh ボタン
- ソルバータスク画面における、並列計算パラメタ
それぞれに必要な機能は説明するまでもないと思われ、これらを実装していくが、その前に後者についてはタスク画面で設定した値とコンテナ上で表示されるプロパティ値を一致させる仕組みが必要である。まずこれらのパラメタに相応させるプロパティの名前であるが、これは、dexcsCfdSolverFoam.py の、class _CfdSolverFoam / def __init__() セクションにおいて、
addObjectProperty(obj, "ParallelCores", 2, "App::PropertyInteger", "Solver",
"Number of cores on which to run parallel analysis")
known_method = ['scotch','simple','hierachical','metis','manual']
addObjectProperty(obj, "ParallelMethod", known_method, "App::PropertyEnumeration", "Solver",
"Method on which to run parallel analysis")
と定義した。ここに、ParallelCoresは、CfdOFオリジナルで定義されていたものを流用し、ParallelMethodは新規に追加したものである。ソルバータスク画面の起動時には、_dexcsTaskPanelCfdSolverControl.py の、class _dexcsTaskPanelCfdSolverControl / def __init__() セクションにおいて、上記プロパティと以下のように関連付けられて、画面が立ち上がる。
self.form.if_ncpu.setValue(self.solver_object.ParallelCores)
known_method = ['simple','hierachical','scotch','metis','manual']
self.form.cb_method.addItems(known_method)
index_method = self.form.cb_method.findText(self.solver_object.ParallelMethod)
self.form.cb_method.setCurrentIndex(index_method)
また、ソルバータスク画面で、write mesh ボタンを押すと、その時点で設定されていた値が、def UpdateUI(self)によって、プロパティの値として、
FreeCADGui.doCommand("FreeCAD.ActiveDocument.{}.ParallelMethod "
"= '{}'".format(self.solver_object.Name, self.form.cb_method.currentText()))
FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.ParallelCores "
"= {}".format(self.solver_object.Name, self.form.if_ncpu.value()))
として保存されるようにした。以上で、ソルバータスク画面上で新たに追加したパラメタとコンテナのプロパティ
- if_ncpu / ParrallelCores
- cb_method / ParallelMethod
の値が連動するようにはなっているが、プログラム的には2点ほど問題を残している箇所があることをお断りしておく。つまり、known_method を2箇所で定義しており、本来はどちらか一方で定義しておいて、他方は定義済みのそれを参照する形にしたかったが、どちらが先に定義されるのか、また他方の参照方法を調べることが必要で、その手間を惜しんで、便宜的にそのままの状態になっている。
また、もう1点は、[Write] ボタンを押さないとプロパティに反映されないということである。これも本来は、タスク画面上で変更し、タスク画面を閉じたらプロパティに反映されるようにしたかったが、そうなっていない。これは、タスク画面を閉じる時に発生するイベントを調べきれていない為で、これがわかれば、そこに上記コードを配置するだけであるという点もまたお断りしておく。
以上、とりあえず、GUI上の動作としては問題ないレベルになったので、追加ウィジェットに対する機能強化をコーディングする。
(1) checkMesh ボタン
このボタンを押したら、OpenFOAMのcheckMesh コマンドを実行し、そのログを表示できるようにすれば良いであろう。ただ、メッシュが存在しない場合には、ボタンを押せない状態にしておくのが望ましい。これは左隣の[Paraview]ボタンと同じなので、同様にコーディングできる。
_dexcsTaskPanelCfdMesh.py class _TaskPanelCfdMesh / def __init__(…)
self.form.pb_paraview.clicked.connect(self.openParaview)
self.form.pb_checkmesh.clicked.connect(self.runCheckMesh)
self.form.pb_paraview.setEnabled(False)
self.form.pb_checkmesh.setEnabled(False)
def updateUI(self)
self.form.pb_paraview.setEnabled(os.path.exists(os.path.join(case_path, "pv.foam")))
self.form.pb_checkmesh.setEnabled(os.path.exists(os.path.join(case_path, "pv.foam")))
def runMesh(self):
self.form.pb_paraview.setEnabled(False)
self.form.pb_checkmesh.setEnabled(False)
def meshFinished(…)
if exit_code == 0:
......
self.form.pb_paraview.setEnabled(True)
self.form.pb_checkmesh.setEnabled(True)
.....
else:
.....
self.form.pb_paraview.setEnabled(False)
self.form.pb_checkmesh.setEnabled(False)
最後に、def runCheckMesh(self)として、def runMesh(self) を雛形としてコピーして以下のように書き換えた。
def runCheckMesh(self):
self.Start = time.time()
cart_mesh = self.cart_mesh
try:
QApplication.setOverrideCursor(Qt.WaitCursor)
self.consoleMessage("Running {} ...".format(self.mesh_obj.MeshUtility))
cart_mesh.error = False
cmd = dexcsCfdTools.makeRunCommand('./Allcheck', cart_mesh.meshCaseDir, source_env=False)
FreeCAD.Console.PrintMessage("Executing: " + ' '.join(cmd) + "\n")
env_vars = dexcsCfdTools.getRunEnvironment()
self.mesh_process.start(cmd, env_vars=env_vars)
if self.mesh_process.waitForStarted():
self.form.pb_run_mesh.setEnabled(False) # Prevent user running a second instance
self.form.pb_stop_mesh.setEnabled(True)
self.form.pb_paraview.setEnabled(False)
self.form.pb_checkmesh.setEnabled(False)
#self.form.pb_load_mesh.setEnabled(False)
self.consoleMessage("Mesher started")
else:
self.consoleMessage("Error starting meshing process", "#FF0000")
cart_mesh.error = True
except Exception as ex:
self.consoleMessage("Error " + type(e).__name__ + ": " + str(ex), '#FF0000')
raise
finally:
QApplication.restoreOverrideCursor()
書き換えた部分のAllcheckに相当する部分のスクリプトがないと動かないのであるが、これはAllmeshスクリプトを作成している箇所で、同時に作成しておけば良いであろう。すなわち、dexcsCfdMeshTools.py のdef perform(self, CaseFilePath):セクションの最後辺りに、Allmeshを作成している箇所があるので、途中からまるごとコピーして、以下改変追加した。
solverSet = "checkMesh | tee checkMesh.log\n"
sleep = "sleep 2\n"
cont = title + envSet + solverSet + sleep
f=open("./Allcheck","w")
f.write(cont)
f.close()
#実行権付与
os.system("chmod a+x Allcheck")
以上、本改変(checkMesh機能の組み込み)は、ほとんどコピペ作業だけで完成することが出来た。
(2) 並列計算パラメタ
並列計算については、並列数に応じてソルバーの実行コマンドを変更する設定を追加する点と、分割方法に応じてdecomposeParDict ファイルを変更する必要がある。
前者については、実行用のAllrunスクリプトを作成している箇所(dexcsCfdCaseWriterFoam.py の、def_writeAllrun(…)セクション)で、これまで、プログラムの実行本体として、
solverSet = solver + " | tee solve.log"
としていた箇所を、以下のように変更
self.ParallelCores = self.solver_obj.ParallelCores
#print(self.ParallelCores)
if self.ParallelCores == 1:
solverSet = solver + " | tee solve.log"
else:
solverSet = "decomposePar | tee decomposePar.log\n"
solverSet = solverSet + "mpirun -np " + str(self.ParallelCores) + " " + solver + " -parallel | tee solve.log"
して、対処できた。但し、プロセッサ数の変更は、前項で記したように、Writeボタンを押した後のタイミングで、しかもスクリプトを作成後のタイミングになっていたので、_dexcsTaskPanelCfdSolverControl / def updateUI(self)セクションで追加した2行を、def write_input_file_handler_dexcs(self):において、実際にAllrunスクリプトが生成される前(冒頭)にも追加した。
並列分割方法の違いは、system/decomposeParDict ファイルを書き換えることになるが、前述のAllrunスクリプトを作成した後に、事前に .FreeCAD/Mod/CfdOF/data/dexcsフォルダ下に収納したファイルの書き換え処理を行っている箇所があるので、ここで併せて実行すればよいだろう。
つまり雛形ファイルとしては、 .FreeCAD/Mod/CfdOF/data/dexcs/system フォルダ下に、以下の内容でdecomposeParDictファイルを追加収納。
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object decomposeParDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
numberOfSubdomains %(solver/ParallelCores%);
method %(solver/ParallelMethod%);
// ************************************************************************* //
settings[]パラメタについては、以下追加するだけである。
settings['solver']['ParallelCores'] = self.solver_obj.ParallelCores
settings['solver']['ParallelMethod'] = self.solver_obj.ParallelMethod
なお、分割方法によって、サブパラメタの設定も必要になる。現時点ではまだサブパラメタを設定するためのGUIを用意できていないので、分割数の設定だけで済む方法(scotch または metis)でしか通用しないものであるという点はお断りしておく。
4.5.6. ソルバー実行タスク画面の再々構築
並列計算が実装できてみると、もう一つ不足しているものがあるのに気付いた。結果の再構築(reconstructPar)である。さらに並列計算用の2つのパラメタは、常時表示させるものでなく、並列計算するかどうかのチェックボックスを介して、チェックされた時のみ表示させた方が良いであろうと思われた(図53)。

このタスク画面を作成するに際しては、Parallelのチェックボックス如何で、表示を切り替えるパーツをQtFrameというウィジェットの中に収納しておく必要があると思われ、当初オリジナルのウィジェットをベースに改変を試みたが、何故か新たにQtFrameを追加することができなかった。そこでやむなく、新たにスクラッチでウィジェットを作成。最初にQtFrameを追加しておいてから、オリジナルのウィジェットから、すべてのパーツをコピペするという作業にて完成することができた。
追加したチェックボックス(オブジェクト名はcheck_parallel)については、メッシュ細分化タスク画面でレイヤーチェックボックスと同様にコーディング、つまり_dexcsTaskPanelCfdSolverControl.py の、class _dexcsTaskPanelCfdSolverControl / def __init__(…)において、
self.form.check_parallel.stateChanged.connect(self.updateUI)
self.form.check_parallel.setChecked(self.solver_object.ParallelCores > 1)
同じく、def updateUI(self) において
self.form.parallel_frame.setVisible(self.form.check_parallel.isChecked())
if self.form.check_parallel.isChecked():
if self.form.if_ncpu.value()==1:
self.form.if_ncpu.setValue(2)
else:
FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.ParallelCores "
"= {}".format(self.solver_object.Name, 1))
1行目で、追加したフレーム(parallel_frame)の表示/非表示を制御している。
なお、この改変に伴って、デフォルトでは並列計算しない(ParallelCores=1)としたいので、その初期値を変更した(dexcsCfdSolverFoam.py class _CfdSolverFoam / def __init__(…))。
addObjectProperty(obj, "ParallelCores", 1, "App::PropertyInteger", "Solver",
"Number of cores on which to run parallel analysis")
また、新たに追加した[reconstructPar]ボタンについて、その基本的な機能は、[Paraview]ボタンと同じで、実行内容を変更するだけである。これは、先に[checkMesh]ボタンを追加した際の_dexcsTaskPanelCfdMesh.pyにおける改変と同様の内容を、_dexcsTaskPanelCfdSolverControl.py において実施してやればよいということである。つまり、class _dexcsTaskPanelCfdSolverControl / def __init__(…)において、
self.form.pb_paraview.clicked.connect(self.openParaview)
self.form.pb_reconstruct.clicked.connect(self.runReconstruct)
def updateUI(self) において、
self.form.pb_paraview.setEnabled(os.path.exists(os.path.join(solverDirectory, "pv.foam")))
self.form.pb_reconstruct.setEnabled(os.path.exists(os.path.join(solverDirectory, "Allreconst")))
def write_input_file_handler_dexcs(self)
self.form.pb_paraview.setEnabled(False)
self.form.pb_reconstruct.setEnabled(False)
def runSolverProcess(self):
self.form.pb_paraview.setEnabled(True)
self.form.pb_reconstruct.setEnabled(True)
といった具合に、pb_paraviewについて記述された行をその下にコピペして、pb_paraviewを、pb_reconstructに、その他、手続き名など相応に変更。新たに追加した手続きブロックを、類似ブロックからコピペ改変することになる。
クリックした時の飛び先(self.runReconstruct)については、def runReconstruct(self):を新規作成する必要があるが、これはには、類似の関数として、def runSolverProcess(self):があるので、これをコピペして、以下朱字部分を改変。
def runReconstruct(self):
self.Start = time.time()
solverDirectory = os.path.join(self.working_dir, self.solver_object.InputCaseName)
solverDirectory = os.path.abspath(solverDirectory)
cmd = self.solver_runner.get_reconst_cmd(solverDirectory)
FreeCAD.Console.PrintMessage(' '.join(cmd) + '\n')
envVars = self.solver_runner.getRunEnvironment()
QApplication.setOverrideCursor(Qt.WaitCursor)
self.solver_run_process.start(cmd, env_vars=envVars)
if self.solver_run_process.waitForStarted():
# Setting solve button to inactive to ensure that two instances of the same simulation aren't started
# simultaneously
self.form.pb_write_inp.setEnabled(False)
self.form.pb_run_solver.setEnabled(False)
self.form.terminateSolver.setEnabled(True)
self.form.pb_paraview.setEnabled(True)
self.form.pb_reconstruct.setEnabled(True)
self.consoleMessage("Solver started")
else:
self.consoleMessage("Error starting solver")
QApplication.restoreOverrideCursor()
ここで変更した.get_reconst_cmdは、オリジナルでは get_solver_cmd となっていたもので、これは、dexcsCfdRunnableFoam.py にて、定義されている。そこでこの部分をコピペして、get_reconst_cmd を新たに追加してやればよい。
def get_reconst_cmd(self, case_dir):
# Environment is sourced in run script, so no need to include in run command
cmd = dexcsCfdTools.makeRunCommand('./Allreconst', case_dir, source_env=False)
FreeCAD.Console.PrintMessage("Solver run command: " + ' '.join(cmd) + "\n")
return cmd
また、Allreconstという用のスクリプトファイルが必要になるが、これはAllrunスクリプトを作成している箇所で、同様に作成すれば良い。すなわち、dexcsCfdCaseWriterFoam.py の、class dexcsCfdCaseWriterFoam: / def writeAllrun(self, progressCallback=None):において、Allrunを作成(f.write(cont))した後、以下朱字部を追加。
with p_new.open(mode='w') as f:
f.write(cont)
fname = os.path.join(self.case_folder, "Allreconst")
p_new = pathlib.Path(fname)
solverSet = "reconstructPar -latestTime | tee reconstructPar.log"
cont = title + envSet + solverSet
with p_new.open(mode='w') as f:
f.write(cont)
s = os.stat(fname)
os.chmod(fname, s.st_mode | stat.S_IEXEC)
4.6 まとめ改
- CfdOFを改造して、DEXCSランチャーv2.5のプロトタイプを作成した。
- 従来のDEXCSマクロにおける懸案事項(以下の第4,6項は除く)はほぼ解消され、操作性、GUIインタフェースも改善された(と思う)。
- スケール変換機能の組み込み
- meshDict インポート不具合対応
- オプションパラメタの GUI 化
- テンプレートケースの変更設定
- maxCellSize のロジック変更
- OF 端末起動
- このうち、第2項は、インポートが不要となり、メッシュ細分化情報をFreeCADのモデル情報として具備できるようになっている。
- 第6項はDEXCSツールバーにて実装済み。
- 第4項は、これから調査し、具体的課題を明確化 ⇒ ほぼ完了
- DEXCS2021でのリリース(2021/9〜10月)に向けて、出来たら良いなぁ・・・を以下列挙しておく。
- 上記取り組みの前に、次章のPlotワークベンチ応用の可能性を見極めたい。というか、既に3-1.でログファイルを対象に残渣図を描けているので、これをpostProcessフォルダ内のデータ対象に変更、最低限コンボボックス選択で個別にプロットするところまではやりたい ⇒ ほぼ完了
- マニュアル制作過程において発覚した事項に対する対処も必要であった。
- これによって、従来のDEXCSマクロにおいて出来ていたが、出来なくなった点もある事も記しておく必要が生じた。つまり、境界タイプの指定が patch(これがデフォルト) または、wall(レイヤー指定のある場合)しかないという点である。
最終的に、上記朱字部分は、DEXCS2021において積み残しになりそうです。