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



4.5 まとめ

以上で、CfdOFを改変して、DEXCSランチャーの機能の肩代わりと、予定していた機能追加を凡そ実現できたと考えている(次章のpost処理機能は、CfdOFの改変とは直接関係ない)。

ここで改めて、DEXCS標準チュートリアルを題材に改変したdexcsCfdOFの動作を確認し、表示や操作方法の面で問題になるかもしれない項目を(これまでの取り組みで今後の課題とした項目も含めて)取り纏めておくことにした。

4.5.1 動作確認

先に、3.7. 中間まとめで実施したものと比較しながら説明する。ワークベンチを切り替え、[CfdAnalysisis]ボタンをクリックするまでは同じであるが、ここでは、この段階で、

図42

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

図43

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

図44

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

図45

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.pydexcsCfdAnalysis.py
CfdCaseWriterFoam.pydexcsCfdCaseWriterFoam.py
CfdConsoleProcess.pydexcsCfdConsoleProcess.py
CfdFaceSelectWidget.pyCfdFaceSelectWidget.py
CfdFluidBoundary.py
CfdFluidMaterial.py
CfdInitialiseFlowField.py
CfdMesh.pydexcsCfdMesh.py
CfdMeshRefinement.pydexcsCfdMeshRefinement.py
CfdMeshTools.py
CfdPhysicsSelection.pydexcsCfdMeshTools.py
CfdPreferencePage.pydexcsCfdPreferencePage.py
CfdPreferencePage.uiCfdPreferencePage.ui
CfdResidualPlot.pyCfdResidualPlot.py
CfdRunnableFoam.pydexcsCfdRunnableFoam.py
CfdSolverFoam.pydexcsCfdSolverFoam.py
CfdTools.pydexcsCfdTools.py
CfdZone.py
Init.pyInit.py
InitGui.pyInitGui.py
README.mdREADME.md
TaskPanelCfdFluidBoundary.ui
TaskPanelCfdFluidProperties.ui
TaskPanelCfdInitialiseInternalField.ui
TaskPanelCfdListOfFaces.uiTaskPanelCfdListOfFaces.ui
TaskPanelCfdMesh.uidexcsTaskPanelCfdMesh.ui
TaskPanelCfdMeshRefinement.uidexcsTaskPanelCfdMeshRefinement.ui
TaskPanelCfdSolverControl.uiTaskPanelCfdSolverControl.ui
TaskPanelCfdZone.ui
TaskPanelPhysics.ui
TemplateBuilder.pyTemplateBuilder.py
TestCfd.py
WindowsRunWrapper.pyWindowsRunWrapper.py
_TaskPanelCfdFluidBoundary.py
_TaskPanelCfdFluidProperties.py
_TaskPanelCfdInitialiseInternalFlowField.py
_TaskPanelCfdMesh.py_dexcsTaskPanelCfdMesh.py
_TaskPanelCfdMeshRefinement.py_dexcsTaskPanelCfdMeshRefinement.py
_TaskPanelCfdPhysicsSelection.py
_TaskPanelCfdSolverControl.py_dexcsTaskPanelCfdSolverControl.py
_TaskPanelCfdZone.py
metadata.txtmetadata.txt
GuiGui
data/CfdFluidMaterialProperties
data/defaults
data/defaultsMesh
data/dexcs
data/dexcsMesh
testFiles
dexcsCfMeshTools.py
表 CfdOFオリジナルソースとdexcsCfdOF でのファイル名対応表

右欄黒字以外のファイルは、左欄のオリジナルファイルをベースに改変が施されている。また最下行の、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ツールが立ち上がることがわかった(図)。

図46. Qt Designer

これを使って、

  • ボタンやテキストなどのウィジェットの位置や表示名を変更して保存すれば、FreeCAD上で何の問題もなく反映される。
  • 新たにウィジェットを追加しても、FreeCAD上のタスク画面には問題なく反映される。
  • ウィジェットを削除する場合は、objectNameの名前を覚えておく。削除したことで問題があるようなら、FreeCAD上のタスク画面操作をした際にそのオブジェクトに関するエラーが表示される。単に未定義エラーであればプログラムの該当箇所をコメントアウトするなりの対処ができる。
  • これら一連の操作をするに際して、.uiファイルの実体については、何ら参照や編集の必要は生じなかった。

ということがわかったので、以降は、これを使ってタスク画面を再構築した。

(1) タスク画面の再構築

以下に、再構築前後のタスク画面を比較表示しておくが、改変後の図中で、赤枠で括った部分は、ウィジェットを追加したというだけで、この時点で機能は実装していない。

図47. メッシュ作成タスク画面の再構築
図48. メッシュ細分化タスク画面の再構築
図49. ソルバー実行タスク画面の再構築

(2) プロパティリストの再構築

コンテナを選択した時にプロパティリストに表示される項目については、それが定義されるコード箇所、すなわち

  • メッシュコンテナ dexcsCfdMesh.py の、class _CfMesh / def initProperties() セクション
  • メッシュ細分化コンテナ dexcsCfdMeshRefinement.py の、class _CfMeshRefinement / def initProperties() セクション
  • ソルバー実行コンテナdexcsCfdSolverFoam.py の、class _CfdSolverFoam / def __init__() セクション

において、表示させたくないプロパティに相当する部分を一旦コメントアウトする。FreeCADで動作確認。エラー無く実行可能、もしくは削除したことにより、エラーが表示される場合に、それが単に被参照エラーで、その参照部分をコメントアウトするだけで、プログラム本体の実行に支障が来たすことがないようであれば、コメントアウトによる削除作業完了とした。

削除することによる影響が多くの箇所に及ぶものは、元に戻している。

図50. メッシュ作成コンテナ
図51. メッシュ細分化コンテナ
図52. ソルバー実行コンテナ

なお、以上の再構築によって、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)。

図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インタフェースも改善された(と思う)。
    1. スケール変換機能の組み込み
    2. meshDict インポート不具合対応
    3. オプションパラメタの GUI 化
    4. テンプレートケースの変更設定
    5. maxCellSize のロジック変更
    6. OF 端末起動
  • このうち、第2項は、インポートが不要となり、メッシュ細分化情報をFreeCADのモデル情報として具備できるようになっている。
  • 第6項はDEXCSツールバーにて実装済み。
  • 第4項は、これから調査し、具体的課題を明確化 ⇒ ほぼ完了
  • DEXCS2021でのリリース(2021/9〜10月)に向けて、出来たら良いなぁ・・・を以下列挙しておく。
    • 日本語化 ⇒ ほぼ完了
    • 並列分割サブメニュー
    • メッシュ細分化タスク画面での細分化対象面の選択時に複リストが出ないようにする
    • テンプレートケース、実行ケースの変更方法を明確化⇒ ほぼ完了
    • CfdOFフォルダ名を変更 ⇒ dexcsCfMesh ⇒ 済み
    • アイコンも変更 ⇒ 済み
    • ソースコード中、不要箇所を削除
    • ちなみにFreeCADのアドオンソフトとして正式登録して欲しいという期待はあるだろうが、DEXCSツールバーと併せてワークベンチ化しないと意味が無さそう。これはもうちょっと先になる。
  • 上記取り組みの前に、次章のPlotワークベンチ応用の可能性を見極めたい。というか、既に3-1.でログファイルを対象に残渣図を描けているので、これをpostProcessフォルダ内のデータ対象に変更、最低限コンボボックス選択で個別にプロットするところまではやりたい ⇒ ほぼ完了
  • マニュアル制作過程において発覚した事項に対する対処も必要であった。
    • これによって、従来のDEXCSマクロにおいて出来ていたが、出来なくなった点もある事も記しておく必要が生じた。つまり、境界タイプの指定が patch(これがデフォルト) または、wall(レイヤー指定のある場合)しかないという点である。

最終的に、上記朱字部分は、DEXCS2021において積み残しになりそうです。

 前へ 目次 次へ

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

4.4 FreeCAD基本形状を使った細分化領域設定

図40.FreeCADの基本形状を使った細分化領域設定



領域内部を細分化指定する際に、DEXCSマクロではBOX領域指定しかできなかったが、cfMesh本来の設定では、球や円錐といった基本形状で領域を指定する事ができる。しかしこの機能を使いたい場合には、出力されたmeshDict中、下記のコメント行(冒頭に//のある行)の冒頭の//を削除して、数値を手修正して使うという方法しかなかった。

	//coneExample
	//{
	//	type		cone;
	//	cellSize	7.51;
	//	p0			(-100 1873 -320);
	//	p1			(-560 1400 0);
	//	radius0		200;
	//	radius1		300;
	//}
	//hollowConeExample
	//{
	//	type				hollowCone;
	//	additionalRefinementLevels	2;
	//	dditional refinement relative to maxCellSize
	//	p0					(-100 1873 -320);
	//	p1					(-560 1400 0);
	//	radius0_Inner		200;
	//	radius0_Outer		300;
	//	radius1_Inner		200;
	//	radius1_Outer		300;
	//}
	//sphereExample
	//{
	//	type			sphere;
	//	cellSize		7.51;
	//	centre			(0 700 0);
	//	radius			200;
	//	refinementThickness	40;
	//}
	//lineExample
	//{
	//	type		line;
	//	cellSize	7.51;
	//	p0			(-750 1000 450);
	//	p1			(-750 1500 450);
	//	refinementThickness	40;
	//}

一方、FreeCADを使えば、これらの基本形状は容易に作成することが出来て、今回の改変したメッシュ細分化コンテナを使って細分化領域対象パーツとして容易に指定できるようになる(図40)。したがって、選択したパーツの種類に応じた特徴量を取得してmeshDictに反映できるようコード改変を試みた。

これまで、3-6-(2)において、領域内部を細分化対象とするリージョン名リスト(__region__)を取得できているが、さらにその対象オブジェクト(obj)が基本形状であるかどうかを判定して、基本形状である場合はそのタイプに応じて出力書式を変更することにした(以下の朱字部分を追加)。

       if __region__ :
            regionNumber = 0
            for objList in __region__ :
                for obj in doc.Objects:
                    if obj.Label == objList :
                        RefStr = str(__reflevel__[regionNumber])
                        if obj.isDerivedFrom("Part::Box"):
               (Box用 Dict作成)
                         elif obj.isDerivedFrom("Part::Spher"):
               (Sphere用 Dict作成)
                         elif obj.isDerivedFrom("Part::Cylinder"):
               (Cylinder用 Dict作成)
                         elif obj.isDerivedFrom("Part::Cone"):
               (Cone用 Dict作成)
                         else:
                               (DEXCSマクロオリジナルのDict作成)

(1) Box

DEXCSオリジナルマクロでもBoxタイプで指定しているが、Boxタイプということがわかっていれば、中心座標の計算方法が簡略化される(朱字部分)。

centerX = obj.Placement.Base.x + obj.Length.Value * 0.5
centerY = obj.Placement.Base.y + obj.Width.Value * 0.5
centerZ = obj.Placement.Base.z + obj.Height.Value * 0.5
strings7 = [
'\t' + objList + '\n',
'\t{\n',
'\t\ttype box;\n',
'\t\tadditionalRefinementLevels\t' + RefStr + ';\n',
'\t\tcentre (' + str(centerX) + MainControl.SPACE_STR + str(centerY) + MainControl.SPACE_STR + str(centerZ) + ');\n',
'\t\tlengthX\t' + str(obj.Length.Value) + ';\n',
'\t\tlengthY\t' + str(obj.Width.Value) + ';\n',
'\t\tlengthZ\t' + str(obj.Height.Value) + ';\n',
'\t}\n'
           ]

ちなみに、DEXCSオリジナルマクロでは、中心座標を以下のようにして取得しており、これだと対象パーツ(obj)がShape属性を有しているものであれば何であってもよかった。

xmax = obj.Shape.BoundBox.XMax
xmin = obj.Shape.BoundBox.XMin
ymax = obj.Shape.BoundBox.YMax
ymin = obj.Shape.BoundBox.YMin
zmax = obj.Shape.BoundBox.ZMax
zmin = obj.Shape.BoundBox.ZMin
centerX = 0.5*(xmax+xmin)
centerY = 0.5*(ymax+ymin)
centerZ = 0.5*(zmax+zmin)

(2) Sphere

球(Sphere)の場合は、FreeCADにおける球の基準座標(obj.Placement.Base)と、cfMeshで定義する球の中心座標は同じであるので、もっと簡単である。

centerX = obj.Placement.Base.x 
centerY = obj.Placement.Base.y 
centerZ = obj.Placement.Base.z 
strings7 = [
'\t' + objList + '\n',
'\t{\n',
'\t\ttype sphere;\n',
'\t\tadditionalRefinementLevels\t' + RefStr + ';\n',
'\t\tcentre (' + str(centerX) + MainControl.SPACE_STR + str(centerY) + MainControl.SPACE_STR + str(centerZ) + ');\n',
'\t\tradius\t' + str(obj.Radius.Value) + ';\n',
'\t\trefinementThickness\t' + '0' + ';\n',
'\t}\n'
             ]

なお、パラメタとして、refinementThickness も指定できるが、球の径を大きくすることと同じになり、2つのパラメタに区分して定義することにあまり意味があるとも思えなかったので、この値は0としてこれを変更する方法までは考えていない(手作業での変更は可能)。

(3) Cylinder

円柱(Cylinder)を使って、cfMesh のtype line; セクションを作成することができる。但し、円柱は平行移動だけでなく、傾けて配置する(注記1)ことができ、平行移動量の取得は容易であるが、傾けた時の円柱上面の中心座標を求めるのには多大な試行錯誤が必要であった。

pos = FreeCAD.Vector(obj.Placement.Base.x, obj.Placement.Base.y, obj.Placement.Base.z + obj.Height.Value)
center = FreeCAD.Vector(0, 0, - obj.Height.Value)
rot = FreeCAD.Rotation(obj.Placement.Rotation)
cylinderHead = FreeCAD.Placement(pos, rot, center)
p0X = obj.Placement.Base.x
p0Y = obj.Placement.Base.y
p0Z = obj.Placement.Base.z
p1X = cylinderHead.Base.x
p1Y = cylinderHead.Base.y
p1Z = cylinderHead.Base.z
strings7 = [
'\t' + objList + '\n',
'\t{\n',
'\t\ttype line;\n',
'\t\tadditionalRefinementLevels\t' + RefStr + ';\n',
'\t\tp0 (' + str(p0X) + MainControl.SPACE_STR + str(p0Y) + MainControl.SPACE_STR + str(p0Z) + ');\n',
'\t\tp1 (' + str(p1X) + MainControl.SPACE_STR + str(p1Y) + MainControl.SPACE_STR + str(p1Z) + ');\n',
'\t\trefinementThickness\t' + str(obj.Radius.Value) + ';\n',
'\t}\n'
            ]

回転前の円柱上面の中心座標(pos)を円柱下面の中心座標(center)を回転中心として、モデルの回転角(rot)相当回転移動して、回展後の円柱状面の中心座標(cylinderhead)を求めれば良いということであるが、centerは、posに対する相対移動量を指定するところがミソであった。

(4) Cone

円錐(Cone)は、円柱の上面と下面で径が異なるだけであるので、Cylinderの座標指定と同じ方法が使える。2つの径を指定する必要があるというだけの違いである。

center = FreeCAD.Vector(0, 0, - obj.Height.Value)
pos = FreeCAD.Vector(obj.Placement.Base.x, obj.Placement.Base.y, obj.Placement.Base.z + obj.Height.Value)
rot = FreeCAD.Rotation(obj.Placement.Rotation)
cylinderHead = FreeCAD.Placement(pos, rot, center)
p0X = obj.Placement.Base.x
p0Y = obj.Placement.Base.y
p0Z = obj.Placement.Base.z
p1X = cylinderHead.Base.x
p1Y = cylinderHead.Base.y
p1Z = cylinderHead.Base.z
strings7 = [
'\t' + objList + '\n',
'\t{\n',
'\t\ttype cone;\n',
'\t\tadditionalRefinementLevels\t' + RefStr + ';\n',
'\t\tp0 (' + str(p0X) + MainControl.SPACE_STR + str(p0Y) + MainControl.SPACE_STR + str(p0Z) + ');\n',
'\t\tp1 (' + str(p1X) + MainControl.SPACE_STR + str(p1Y) + MainControl.SPACE_STR + str(p1Z) + ');\n',
'\t\tradius0\t' + str(obj.Radius1.Value) + ';\n',
'\t\tradius1\t' + str(obj.Radius2.Value) + ';\n',
'\t}\n'
            ]

以上、4種類の基本形状以外に、cfMeshで定義できるものとして、hollowConeタイプが存在するが、FreeCAD上で相応する基本形状が存在しないので、これについては実装を見送って、従来通りコメントアウト出力を残すようにした。また、内側か外側のどちらかのConeを作成しておいて、両端面における外側または内側の径だけを手作業で追加することはさほど面倒な作業にはならないと思われ、これが実装できていないからといって致命的ではないと考えている。

メッシュ確認例

図41.メッシュ確認例

注記1

傾けるに関しては、BoxタイプであってもFreeCAD上では傾けることはできるが、cfMeshでは傾きを考慮したBox指定ができないので、傾いたBoxタイプを指定すると、傾いていない状態のデータで設定されることになるという点はお断りしておく。

前へ 目次 次へ

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

4.3 メッシュ細分化タスク画面の改変その2

図38.追加したメッシュ細分化パラメタ



パーツを対象として設定可能なパラメタとして、これまで組み込みが出来ていなかったパラメタを新たに3つ設定できるようにした(図38.における赤枠部分)。すなわち、

  1. keepCellsIntersectingPatches
  2. removeCellsIntersectingPatches
  3. allowDiscontinuity

であり、いずれも使用するかどうかをチェックボックスで設定すれば良いので、GUIの実装やプロパティ化はこれまでのやり方を流用でき、簡単であった。

(1) GUIコンポーネントの追加(dexcsTaskPanelCfdMeshrefinement.ui)

  • keepCellsIntersectingPatches
      <!-- checkBox (keepCellsIntersectingPatches) -->
      <item row="11" column="0" colspan="2">
       <widget class="QCheckBox" name="check_keepCells">
        <property name="text">
         <string>keepCellsIntersectingPatches</string>
        </property>
       </widget>
      </item>
  • removeCellsIntersectingPatches
      <!-- checkBox (removeCellsIntersectingPatches) -->
      <item row="12" column="0" colspan="2">
       <widget class="QCheckBox" name="check_removeCells">
        <property name="text">
         <string>removeCellsIntersectingPatches</string>
        </property>
       </widget>
      </item>
  • allowDiscontinuity
            <!-- checkBox (allowDiscontinuity) -->
            <item row="3" column="0" colspan="2">
            <widget class="QCheckBox" name="check_allowdiscont">
                <property name="text">
                <string>allowDiscontinuity</string>
                </property>
            </widget>
            </item>

(2) プロパティの追加(CfdMeshRfinement.py)

def initProperties(…)に以下追加。

        addObjectProperty(obj, "KeepCell", False, "App::PropertyBool", "",
                          "Keep cells in the mesh template which intersect selected objects)"
        addObjectProperty(obj, "RemoveCell", False, "App::PropertyBool", "",
                          "Remove cells the cells intersecte by the selected objects")
        addObjectProperty(obj, "AllowDiscont", True, "App::PropertyBool", "",
                          "Allow discontinuity of boundary layers")

これにより、プロパティリストが以下のように赤枠部が追加表示される。

図39.追加したプロパティ

(3) メッシュ作成タスク画面とプロパティの関連付け(_dexcsTaskPanelCfdMeshRefinement.py)

def accept(sel)にて、メッシュタスク画面の状態をプロパティリストに反映

        FreeCADGui.doCommand("FreeCAD.ActiveDocument.{}.KeepCell "
                             "= {}".format(self.obj.Name, self.form.check_keepCells.isChecked()))
        FreeCADGui.doCommand("FreeCAD.ActiveDocument.{}.RemoveCell "
                             "= {}".format(self.obj.Name, self.form.check_removeCells.isChecked()))
        FreeCADGui.doCommand("FreeCAD.ActiveDocument.{}.AllowDiscont "
                             "= {}".format(self.obj.Name, self.form.check_allowdiscont.isChecked()))

def load(self) にて、プロパティリストの値をメッシュタスク画面に反映

        self.form.check_keepCells.setChecked(self.obj.KeepCell)
        self.form.check_removeCells.setChecked(self.obj.RemoveCell)
        self.form.check_allowdiscont.setChecked(self.obj.AllowDiscont)

(4) meshDict作成(dexcsCfdNeshTools.py)

  • allowDiscontinuity

3-6-(3) で実施した改変に、以下の朱字部分を追加。

        __patch__ = []
        __nLayer__ = []
        __expRatio__ = []
        __firstLayerHeight__ = []
        __allowDiscont__ = []
        __keepCells__ = []
        __removeCells__ = []
        doc = FreeCAD.activeDocument()
        for obj in doc.Objects:
            if obj.ViewObject.Visibility:
                if hasattr(obj, "Proxy") and isinstance(obj.Proxy, _CfdMeshRefinement):
                    if obj.NumberLayers > 1 :                    
                        for objList in(obj.LinkedObjects):
                            __patch__.append(objList.Label) 
                            __nLayer__.append(obj.NumberLayers) 
                            __expRatio__.append(obj.ExpansionRatio) 
                            __firstLayerHeight__.append(obj.FirstLayerHeight) 
                            if obj.AllowDiscont == 1:
                                __allowDiscont__.append('1')
                            else: 
                                __allowDiscont__.append('0') 
                    if obj.KeepCell == 1:
                        for objList in(obj.LinkedObjects):
                            __keepCells__.append(objList.Label)
                    if obj.RemoveCell == 1:
                        for objList in(obj.LinkedObjects):
                            __removeCells__.append(objList.Label)

紫色部分は、この後の keepCellsIntersectingPatches、にて使用する。

FirstLayerHeight = str(__firstLayerHeight__[patchNumber]).replace('m','') 
FirstLayerHeight = str(float(FirstLayerHeight)*self.mesh_obj.ScaleToMeter)

strings3 = [         
'\t\t'                 + objList + '\n',
'\t\t{\n',
'\t\t\t// number of layers (optional)\n',
'\t\t\tnLayers    '    + str(__nLayer__[patchNumber]) + ';\n',
'\t\t\n',
'\t\t\t// thickness ratio (optional)\n',
'\t\t\tthicknessRatio ' + str(__expRatio__[patchNumber]) + ';\n',
'\t\t\n',
'\t\t\t// max thickness of the first layer (optional)\n',
'\t\t\tmaxFirstLayerThickness ' + FirstLayerHeight + '; // [m]\n',
'\t\t\n',
'\t\t\t// active 1 or inactive 0\n',
'\t\t\tallowDiscontinuity ' + __allowDiscont__[patchNumber] + ';\n',
'\t\t}\n'

なお、青字部分は、3-6-(3) 以降、スケール変更機能を追加したことを踏まえて、それに対応した処置である。

  • keepCellsIntersectingPatches
  • removeCellsIntersectingPatches

どちらもほとんど同じやり方で出来た。基本は、string4[]を定義するブロックにおいて、

        'keepCellsIntersectingPatches\n',
        '{\n',
        #'// patchName\n',
        #'//\t{\n',
        #'//\t\tkeepCells 1; // 1 active or 0 inactive\n',
        #'//\t}\n',
        keepCellsListString,
        '}\n',
        '\n',
        '// remove cells where distinct parts of the mesh are joined together (optional)\n',
        '// active only when keepCellsIntersectingBoundary is active\n',
        '// checkForGluedMesh    0; // 1 active or 0 inactive\n',
        '\n',
        '// remove cells the cells intersected\n',
        '// by the selected patched/subsets\n',
        '// from the mesh template (optional)\n',
        '// it is active when keepCellsIntersectingBoundary\n',
        '// is switched on\n',
        'removeCellsIntersectingPatches\n',
        '{\n',
        #'// patchName\n',
        #'//\t{\n',
        #'//\t\tkeepCells 1; // 0 remove or 1 keep\n',
        #'//\t}\n',
        removeCellsListString,
        '}\n',

緑色部のコメント行として出力していた部分をコメントアウト(削除でもOK)し、予め下記に作成しておいたkeepCellsListStringremoveCellsListString に置き換えるようにした。

keepCellsListString = ""
if __keepCells__ :
    for objList in __keepCells__:
        keepCellsListString = keepCellsListString + "\t" + objList + "\n\t{\n\t\tkeepCells 1; //1 active or 0 inactive \n\t}\n"
else:
    keepCellsListString = keepCellsListString + "//\t" + "patchName" + "\n//\t{\n//\t\tkeepCells 1; //1 active or 0 inactive \n//\t}\n"

removeCellsListString = ""
if __removeCells__ :
    for objList in __removeCells__:
        removeCellsListString = removeCellsListString + "\t" + objList + "\n\t{\n\t\tkeepCells 0; //0 remove or 1 keep \n\t}\n"
else:
    removeCellsListString = removeCellsListString + "//\t" + "patchName" + "\n//\t{\n//\t\tkeepCells 1; //0 remove or 1 keep \n//\t}\n"

また、__keepCells__、__removeCells__のパッチ名リストは、少し上に記した紫色部分で取得してある。

前へ 目次 次へ

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

4.2. メッシュ細分化タスク画面の改変その1



CfdOFでの細分化指定方法は、相対サイズ(Relative element size)を指定するというもので、実際にDEXCSランチャーの標準モデルで使ってみたのであるが、数値の指定方法として悩ましい面が多々あった。そこで、これをDEXCS方式(セルサイズを直接指定または二分木法の細分化レベルを指定)に変更することを懸案としていたので、まずはこれを実施することとした。

変更イメージを図37.に示す。

図37. 細分化指定方法の変更イメージ

赤枠部分で細分化指定するが、デフォルトでは、[Refinement level:]に[1]が入り、[Real cell size:] には、メッシュ作成パネルで設定した[Base element size:](基本メッシュサイズ)の1/2の値が入るようにしておく。[Real cell size:] と、[Refinement level:]のどちらも変更可能にしておき、一方を変更したら、他方の項目は相応の値に自動変更されるようになっていれば使いやすくなりそうだ。

ここで、1点注意したいのは、数値入力欄にチェックマークとmmという単位の入っているものと、そうでないものがあるという点である。後者は単純な数値入力欄で、プロパティーが、App::PropertyFloat とか、App::PropertyIntegerであり、通常の数字を扱う方法が通用するのに対して、前者はApp::PropertyLengthとなっており、長さの単位も併記して寸法を解釈するもので、参照や値をセットする際の方法が異なってくるという点である。ここでは、便宜的にCfdOfオリジナルの[Refinement level:]相当部分を、[Real cell size:] に置き換えて、入力欄を変更したので、参照や設定部の名前だけでなくメソッドも変更する必要が生じてくるという点である。最終的に[Refinement level:]相当部分で使用していた変数名”if_rellen”は、”if_cellsize”に、相応するプロパティ名RelativeLengthをCellSizeに変更したが、最初からこれを行ってしまうと、“if_rellen”に相応するプロパティを見失ってしまうことになりかねない。変数名”if_rellen”をそのまま使っていれば、相応するプロパティの参照や設定の際にエラーとなり、その箇所は明示されるので、必要な変更を実施しておいて、最終的にちゃんと動くようになってから変数名を変更したというのが改変作業の実態である。

dexcsTaskPanelCfdMeshRefinement.ui で、新たに追加した[Refinement level:]に関しては、CfdOfオリジナルの[Refinement level:]相当部分をコピーして、以下朱字部分と青字の数値入力部を変更しただけであるが、

      </item>
      <!-- Label (Relative element size) -->
      <item row="0" column="0">
       <widget class="QLabel" name="label_reflevel">
        <property name="text">
         <string>Refinement level:</string>
        </property>
       </widget>
      </item>
      <!-- value (Relative element size) -->
      <item row="0" column="1">
       <widget class="QDoubleSpinBox" name="if_reflevel">
        <property name="minimum">
          <number>1</number>
        </property>
       </widget>
      </item>

[Real cell size:] 部分は、CfdOfオリジナルの[Refinement level:]部分を直接以下のように変更した。

      <!-- Label (Relative element size) -->
      <item row="1" column="0">
       <widget class="QLabel" name="label_cellsize">
        <property name="text">
         <string>Real cell size:</string>
        </property>
       </widget>
      </item>
      <!-- value (Relative element size) -->
      <item row="1" column="1">
       <widget class="Gui::InputField" name="if_cellsize">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
          <horstretch>0</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
        <property name="toolTip">
         <string extracomment="Select 0 to use default value"/>
        </property>
        <property name="text">
         <string>0.0</string>
        </property>
        <property name="alignment">
         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
        </property>
        <property name="singleStep" stdset="0">
         <double>0.010000000000000</double>
        </property>
        <property name="maximum" stdset="0">
         <double>1000000000.000000000000000</double>
        </property>
        <property name="unit" stdset="0">
         <string notr="true">mm</string>
        </property>
        <property name="format" stdset="0">
         <string>2</string>
        </property>
       </widget>
 

青字部分は、App::PropertyLength用に使われる入力欄を作成するwidgetで、類似のものをブロック毎コピーして、数値部分をカスタマイズしただけである。

一方、これら入力欄に相応するコンテナプロパティは、CfdMeshRefinement.py の def initProperties(…) において、

        # Common to all
        #addObjectProperty(obj, "RelativeLength", 0.75, "App::PropertyFloat", "",
        #                  "Set relative length of the elements for this region")
        addObjectProperty(obj, "CellSize", "0 m", "App::PropertyLength", "",
                          "Set cell size for selected object(s)")
        addObjectProperty(obj, "RefinementLevel", 1, "App::PropertyInteger", "",
                          "Set refinement level for for selected object(s)")

定義されるので、オリジナルの緑字の部分をコメントアウトして、その下に、App::PropertyLengthに変更したもの(CellSize)を追加したのと、“if_reflevel“に相応するもの(RefinementLevel)を追加した。

メッシュ細分化タスク画面の起動は、_dexcsTaskPanelCfdMeshRefinement.py が動くので、その def __init__(…)を経てdef load(self)が起動されるようになっているので、def load(self): が起動する前に、

        self.baseMeshSize = Units.Quantity(self.mesh_obj.CharacteristicLengthMax).Value
        if self.obj.CellSize == 0 :
             self.obj.CellSize = self.baseMeshSize * 0.5

        self.load()

        self.form.if_reflevel.valueChanged.connect(self.changeCellSize)
        self.form.if_cellsize.valueChanged.connect(self.changeBaseCellSize)

としておけば、メッシュコンテナ中の、CharacteristicLengthMax(基本メッシュサイズ)を取得して、デフォルトで(Cellsize==0で、何も指定がなかった場合には)その半分(RefLevel=1相当)の値をCellsizeプロパティに設定したことになる。また、self.load()が終わった後の2行は、メッシュ細分化タスク画面上の数値欄の値が変化した時の処置を定義したもので、以下の内容を新設した。

つまり、if_reflevelの値が変化したら、baseMeshSizeとf_reflevelの値を使って、セルサイズを計算し直す。

    def changeCellSize(self):
        setQuantity(self.form.if_cellsize, self.baseMeshSize/2**(self.form.if_reflevel.value()))
        return True

if_cellsizeの値が変化したら、その値とif_reflevelの値を使って、CharacteristicLengthMaxを計算し直す。

    def changeBaseCellSize(self):
        cellLength = getQuantity(self.form.if_cellsize)
        cellLength = re.findall("\d+\.\d+", str(cellLength))[0]
        self.mesh_obj.CharacteristicLengthMax = float(cellLength) * 2**(self.form.if_reflevel.value())
        return True

コンテナプロパティとメッシュ細分化タスク画面に表示される変数との関連付は、def load(self):

        self.form.if_reflevel.setValue(self.obj.RefinementLevel)
        setQuantity(self.form.if_cellsize, self.obj.CellSize)

にてコンテナ⇒タスク画面、

def accept(self)にて、

        FreeCADGui.doCommand("FreeCAD.ActiveDocument.{}.CellSize "
                             "= '{}'".format(self.obj.Name, getQuantity(self.form.if_cellsize)))
        FreeCADGui.doCommand("FreeCAD.ActiveDocument.{}.RefinementLevel "
                             "= {}".format(self.obj.Name, self.form.if_reflevel.value()))

タスク画面から、コンテナへ収納されるようになっている。

以上で、細分化指定方法を改良することが出来た、しかしこのままでは、CfdOFのオリジナルパラメタを流用していたcfMeshのmeshDictを作成するプログラム(dexcsCfdMeshTools.py)が動かなくなってしまう。つまり、CfdOFでは、RelativeLengthというパラメタがあって、この値をベースに細分化レベルを計算し直していた。今回の改変で、RefinementLevelという細分化レベルそのものの値をパラメタ化したので、これを使うようにするということである。

これは、たとえば、3-6-(2)において、暫定的に

RefStr = str(int( 1.0 / __relativeLength__[regionNumber])-1)

としていた部分を、以下のように変更、

RefStr = str(__reflevel__[regionNumber])-1)

併せて、__relativeLength__としてあった箇所を__reflevel__に変更するとともに、モデルコンテナからパラメタ取得していた部分、たとえば、

__relativeLength__.append(obj.RelativeLength) 

を、以下のように変更するだけであった。

__reflevel__.append(obj.RefinementLevel) 

複数ヶ所存在するが、ほとんど機械的な作業であった。

前へ 目次 次へ

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

3-7.中間まとめ



前節までの取り組みで、CfdOFのGUIを使って、DEXCSランチャーの一部(ソルバー実行と残渣グラフ表示)とDEXCSマクロの主要プログラムを起動できるようになったはずである。そこでDEXCSの標準チュートリアルケースを題材に、一連の動作確認を実施し、今後に必要な改善項目を取り纏めた。

(1) FreeCADモデル

モデルは任意のフォルダに収納しておく。

図18. 解析フォルダ

これをダブルクリックすれば、普通にCADモデルが表示される。

図19. DEXCS標準チュートリアル問題

(2) dexcsCfdOFワークベンチ

ワークベンチを切り替える

図20. dexcsCfdOFワークベンチ

ツールバーが現れるので、[CfdAnalysis]ボタンをクリック。

図21. CfdAnalysis解析コンテナ

コンボビューのモデルツリー下部に、[dexcsCfdAnalysis]と、その下に階層を下げて[CfdSolver]というコンテナが作成される。

ここで、一旦、「編集」→「設定」メニューを起動して、

図22. Default output directory の設定

Default output directory が、モデル収納フォルダになるようにしておく。他のフォルダでも実行は可能だが、これがDEXCS流。

(3)メッシュ作成コンテナ

設定を終わったら、前の画面に戻り、表示パーツ(のどれでも良い)を選択すると、

図23.メッシュ作成コンテナ

dexcsCfdOFツールバー中の[メッシュ作成]ボタンが有効になるので、これをクリック。

図24.メッシュ作成タスク画面

タスク画面が現れるが、最下段にBase element size として 0.27 の数字があり、これはDEXCS方式で計算した推奨パラメタである。

このモデルでは、このままでは適切なメッシュとならないので、一旦この画面は「閉じる」

図25.メッシュ作成コンテナ

モデルツリー上、最下段にBlock_meshというコンテナができているが、この名前は[メッシュ作成]ボタンを押した時に選択対象としたパーツによって変わってくる。今の所、気にしなくてよい。

(4)メッシュ細分化コンテナ

メッシュ作成[block_Mesh]コンテナを選択すると、[メッシュ細分化]ボタンが有効になるので、これをクリックすると、

図26.メッシュ細分化タスク画面

Mesh refinement のタスク画面が開くので、この画面を使って細分化の詳細を設定する。

図27.細分化対象パーツの選択(1/2)

細分化対象としたいパーツは、[select from list]ボタンをクリックすると、[Select Object]の選択リストが有効になるので、このリストの中から選択する。[Dexcs]を選択すると、少し待ち時間があって後、長大なFaceリストが現れる。これはDexcsを構成する全Faceを示しており、これを取得する為時間がかかっているのである。それぞれのFace…の名前の先頭にチェックボックスが表示されており、これの選択如何で、細分化対象をさらに詳細に設定することができるようになっているというのがCfdOF本来の使い方であるが、DEXCSではそういうことはしない。したがって、ここでFaceリストを表示させるのでなく、単に選択パーツを表示させたかったのであるが、その為の工夫が容易ではなさそうであったので、当面はCfdOF本来の選択表示方法を流用していくこととした。

図28.細分化対象パーツの選択(2/2)

ここで、[Select all]ボタンを押せば、全Faceにチェックマークが付くので、ここで[Done]ボタンを押す。そうすると、Dexcs:Face…というリスト表示が得られるので、選択はこれで完了である。

レイヤーを作成したい場合には[Boundary Layer]のチェックボックスにチェックを入れると、レイヤーの詳細設定メニューが現れるので、

図29.パッチ毎の細分化設定1

レイヤー数が2以上になるように変更すれが、これが有効になる。設定が完了したら[OK]ボタンをクリック。なお、以上の説明では、Dexcsの構成Faceを全選択したが、どれか一つのFaceを選択しただけであっても良い(下図)。CfdOF本来のメッシュ作成法ではDEXCSフォントのほんの一部分しか細分化されない事になるが、中身はDEXCS方式でメッシュ作成しており、このリスト中のパーツ名(Dexcs)を使っているにすぎないからである。

図30.パッチ毎の細分化設定2(略式)

Dexcsフォントに対する細分化が終わったら、改めて[Block_mesh]コンポーネントを選択して、ボタンをクリック。今度は、regionBoxに対する細分化設定を行う。こちらは内部領域の細分化であるので[internal Volume]にチェックする。

図31.領域内部の細分化設定

パーツの選択方法として、[Select from list]ボタンを押してリストから選択することはSurface(パッチ)の場合と同じであるが、inletやoutletを選択してもSolidではないので、選択欄にリストアップされない。間違い防止にはなっている。

[Relative element size:]の値は任意に変更して良いが、一応この値(0.3)でRefLevel=2相当になる。

(5)メッシュ作成

細分化設定が終わったら、改めて[Block_Mesh]のメッシュ作成コンテナをダブルクリックして、メッシュ作成のタスク画面を開き、[Write mesh case]ボタンを押す。設定に問題が無ければ、[Run mesher]ボタンが有効になるので、これをクリックしてメッシュ作成が実行される。[Paraview]ボタンでメッシュ確認、問題なければ[閉じる]ボタンをクリック。

Paraviewによる確認においては、起動画面において既にモデルがロードされた状態で表示される(図32)。

図32.Paraviewの起動画面

Decompose polyhedra のチェックボタンも非有効となっているので、メッシュ確認までの手間が省けている。

(6)計算実行

メッシュが完成したら、[CfdSolver]コンテナをダブルクリック。[Analysis control]タスク画面が開くので、[Write]ボタン→[Run]ボタンクリックにて計算が始まり、残渣プロットが表示される。

図33.計算実行状況

計算終了後のParaview確認においても、メッシュ確認の場合と同様、モデルがロードされた状態で起動する(Applyボタンを押さなくともよい)ので、手間が省けている。

(7)まとめ

  • dexcsCfdOF(CfdOFの名前を変更し不要機能を除外したもの)のGUIを使って、DEXCSマクロによるDEXCS式メッシュ作成を実現し、DEXCSランチャーの一部(ソルバー実行と残渣グラフ表示)を代替することができた。
  • 現状では、Default output directoryをケース変更の都度変更する必要があり、これはモデルの存在するディレクトリがデフォルトになるよう変更したい。→ 解決1
  • メッシュ作成コンテナを作成するのに、3Dパーツを選択する必要があり、選択したパーツによって、コンテナの名前が変わってしまう。→3Dパーツを選択せずとも、[CfdAnalysis]ボタンを押した時に、[CfdSolver]コンテナと同時に作成されるようにしたい。→ 解決2
  • メッシュ作成の際に生成される形状ファイルの名前が.stl, .fmsになってしまっている(meshDict中の名前もそうなっているので、メッシュ生成には支障ない)が、DEXCS標準(FreeCADモデル名と同じ)としたい。→ 解決3
  • 現行DEXCSマクロで設定出来ているパラメタセットと比べて、不足・問題になるものは以下の通り。
    • featureAngle
    • optimise_Layer
    • keepCellsIntersectingBoundary
    • stopAfterEdgeExtraction
    • 細分化方法の CellSize / RefLevel  切り替え
    • RefLevel をRelative element size より算出している点
  • 一方、現行DEXCSマクロで設定出来ていない以下の機能を組み込むことができた。
    • Refinement thickness
    • Max first cell height

解決1

CfdTools.py中、 def getDefaultPath()

def getDefaultOutputPath():
    prefs = getPreferencesLocation()
    output_path = FreeCAD.ParamGet(prefs).GetString("DefaultOutputPath", "")
    if not output_path:
        #output_path = tempfile.gettempdir()
        output_path = os.path.dirname(FreeCAD.ActiveDocument.FileName) 
    output_path = os.path.normpath(output_path)
    return output_path

ただし、モデルが変更になった時には、先のモデル情報が残ってしまうので、起動時にはその設定を読み込まないようにした。CfdPreferencePage.py中、 def __init__(self) セクション中、最後に以下の2行を追加した。

        prefs = CfdTools.getPreferencesLocation()
        FreeCAD.ParamGet(prefs).SetString("DefaultOutputPath", "")

通常はFreeCADモデルが存在するディレクトリがケースファイルとされる。何らかの事情によって、メッシュを特別なディレクトリに出力したい場合には、編集→設定により、出力先を変更できるが、この設定はその場限りで有効になるという使い方を想定している。

DEXCS方式では、ケースフォルダ中に隠しファイルを収納し、その有無と内容如何で出力先を変更しているので、その方式に変更する可能性は残してあるのと、dexcsCfdAnalysisコンテナの [Output Path]プロパティを直接編集して出力先を変更することができて、この場合はここに指定した出力先が優先されるという点もあるので、もう少しわかりやすくしたほうがよいかも。

また、出力先を変更した場合に、DEXCSランチャーのGridEditor等の起動ボタンが使えなくなる(ケース情報が伝わらない)点もあり、今後の課題となる。

解決2

[CfdAnalysis]ボタンを押した時に、コンテナが作成されるのは、CfdAnalysis.py 中の、def Activated(sel) セクションであるので、この中に、以下の2行を追加した。

        # Add mesh object when CfdAnalysis container is created
        FreeCADGui.addModule("CfdMesh")
        FreeCADGui.doCommand("analysis.addObject(CfdMesh.makeCfdMesh())")

但し、コンテナは作成されるものの、このままでは、これをダブルクリックして設定画面を開こうとすると、エラーになった。これはこのコンテナのプロパティを初期化する部分(CfdMesh.py 中の、def initProperties(self, obj):)において、メッシュ作成用の CaseName を以下のように

__caseName__ = ""
addObjectProperty(obj, 'CaseName', __caseName__, "App::PropertyString", "",
                          "Name of directory in which the mesh is created")

再変更する必要があった。これは、上記の解決1によって、解析ケース名を変更しているので、それに応じた対応ということである。

また、CfdMeshTools.py の、def getFilePaths(self,output_dir) において、else: 以下の最終行でCfdOFオリジナルのSTLファイルを作成するためのファイル名を作成しているが、このままだと参照エラー等生じてしまうので、ダミーのファイル名(geometry)を割り当てた。

        else:
            #self.temp_file_geo = os.path.join(self.constantDir, 'triSurface', self.part_obj.Name + '_Geometry.stl')
            self.temp_file_geo = 'geometry.stl'

解決3

stlファイルの名前を作成しているのは、 dexcsCfdMeshTools.py 中、def makeStlfile(…)

self.caseFilePath = CaseFilePath
self.fileStem = os.path.splitext(self.caseFilePath)[0]
self.fileStem = self.fileStem.split(MainControl.SLASH_STR)[-1]
self.stlFileName = CaseFilePath + MainControl.SLASH_STR + self.fileStem + '.stl'
self.fileName = CaseFilePath + MainControl.SLASH_STR + self.fileStem

としていた部分を、

modelName = os.path.splitext(os.path.basename(FreeCAD.ActiveDocument.FileName))[0]
self.stlFileName = CaseFilePath + modelName + '.stl'
self.fileName = CaseFilePath

と変更。

同様に、fmsファイルの名前は、def perform(…)において

self.fmsFileName = CaseFilePath + MainControl.SLASH_STR + self.fileStem + MainControl.DOT_FMS_STR

としていた部分を、

modelName = os.path.splitext(os.path.basename(FreeCAD.ActiveDocument.FileName))[0]
self.fmsFileName = CaseFilePath + modelName + ".fms"

と変更することにより実現できた。

前へ 目次 次へ