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

3.3 その他の変更



CfdOF をベースに DEXCS ワークベンチ化する際、ソルバー選択等のコンテナは不要になると記した。当
面これを実現する(ツールボタンが出てこないようにする)のに、
InitGui.py 中、以下の 66 〜 69 行を削除

64: cmdlst = [’Cfd_Analysis’,
65:         ’Cfd_MeshFromShape’, ’Cfd_MeshRegion’,
66:         ’Cfd_PhysicsModel’, ’Cfd_FluidMaterial’,
67:         ’Cfd_InitialiseInternal’,
68:         ’Cfd_FluidBoundary’, ’Cfd_InitialisationZone’, 
69:
70:         ’Cfd_SolverControl’]

CfdAnalysis.py 中、以下の 88 〜 98 行は削除(コメントアウト)した。

88: # Add physics object when CfdAnalysis container is created
89: #FreeCADGui.addModule("CfdPhysicsSelection")
90: #FreeCADGui.doCommand("analysis.addObject(CfdPhysicsSelection.makeCfdPhysicsSelection())
91:
92: # Add fluid properties object when CfdAnalysis container is created
93: #FreeCADGui.addModule("CfdFluidMaterial")
94: #FreeCADGui.doCommand("analysis.addObject(CfdFluidMaterial.makeCfdFluidMaterial(’FluidPr
95:
96: # Add initialisation object when CfdAnalysis container is created
97: #FreeCADGui.addModule("CfdInitialiseFlowField")
98: #FreeCADGui.doCommand("analysis.addObject(CfdInitialiseFlowField.makeCfdInitialFlowField
99:
100: # Add solver object when CfdAnalysis container is created
101: FreeCADGui.addModule("CfdSolverFoam")
102: FreeCADGui.doCommand("analysis.addObject(CfdSolverFoam.makeCfdSolverFoam())")

これら以外にも不要なコード、箇所はたくさん存在するが、全体として一通りに動作するようになってから
削除予定。

3.4 CfdOF ⇒dexcsCfdOF 改変の基本方針

メッシュ作成画面を改変するに当たり、ここに改変の基本方針(当面の考え方)を記しておく。すなわち、


CfdOF を改変した dexcsCfdOF ワークベンチから、現行 DEXCS マクロで実装した機能を呼び出せる
ようにして、かつ CfdOF のメッシュ細分化コンテナを拡張し、細分化コンテナから得られるパラメタ
を現行 DEXCS マクロから meshDict ファイルを作成する仕組みの中に組込めるようにする

というものである。

当面と記したのは、 CfdOF のメッシュ作成方法の仕組みが開発元によって改良され、 DEXCS マクロと同
等以上に使えるものになったら置き換えるのも有りだという点と、meshDictファイルを作成するのにTemplateBuilderを使って書き換える方法も有り得るということである。

前へ 目次 次へ

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

3.5 メッシュ作成方法(細分化指定無し)の変更(DEXCS化) 1



現行の CfdOF では、メッシュ領域(閉じた領域)を定義した Part オブジェクトを選択しないと、メッシュ
作成画面を表示することが出来ない(ボタンが有効にならない)が、 DEXCS では、 Patr オブジェクトの組み
合わせとしてメッシュ領域を定義するので、何も選択しなくともこの画面が表示できるよう改変したい。
しかし(今の所、その方法がわからないので)、当面は任意のオブジェクトを選択してメッシュ作成画面を

表示できるようにして、この画面とその機能を改変していく事とする。またその際に、メッシュ作成は基本的
に現行の DEXCS 方式を採用するものとして考える。さらに、次節以降のメッシュ細分化パラメタをいかに
組み込むかという課題もあるので、ここではまず細分化パラメタを必要とせず、基本パラメタだけでメッシュ
作成できるケース(backstepSimple)を対象に考えることとした。かように考えるのであれば、図 12 に示すように、

図 12 メッシュ作成画面の改変 1

現行 DEXCS マクロの

  • ExportDict ボタン
  • MakeMesh ボタン
  • ViewMesh ボタン
  • maxCellSize の数値カラム

をクリックした際に呼び出される関数を、 CfdOF のメッシュ作成画面上

  • Write mesh case ボタン
  • Run mesher ボタン
  • Paraview ボタン
  • Base element size の数値カラム

から呼び出すようにして機能するように改変する事を当面の目標とした。素人プログラマの目論見通りに動いてくれるようになってくれればハッキング与太話も現実的なものになる。逆にこれが出来ない事には、作成状況(実行ログ)を Status カラムに表示させ、中途停止ボタンを機能するようにできるようにする事や、 cfMeshの基本パラメタ( optimize Layer や keepCellsInter… )を追加する事など考えられるが、先へ進むのは尚早である。

(1) dexcs CFD Mesh 画面

_TaskPanelCfdMesh.py をコピーして、_ dexcsTaskPanelCfdMesh.py と名前を変更、この中身を改変して
いくこととした。
また、_TaskPanelCfdMesh.py を呼び出しているのは、 CfdMesh.py からで、この部分を、

163: import _dexcsTaskPanelCfdMesh
164: taskd = _dexcsTaskPanelCfdMesh._TaskPanelCfdMesh(self.Object)

と変更すると共に、メッシュ作成コンテナにおいてメッシュ作成用の CaseName がデフォルトで meshCase
とされているので、これを、

94: addObjectProperty(obj, ’CaseName’, "./", "App::PropertyString", "",
95: "Name of directory in which the mesh is created")

自身の( FreeCAD モデルの存在する)ディレクトリ (.) に変更する。
さらに、タスク画面の GUI デザインはいずれ変更したい。これは TaskPanelCfdMesh.ui にて定義される
ので、これもコピーして名前を変更( dexcsTaskPanelCfdMesh.ui )し、_dexcsTaskPanelCfdMesh.py 中、こ
れを呼び出す部分を以下のように変更した。

51: self.form = FreeCADGui.PySideUic.loadUi(os.path.join(os.path.dirname(__file__), "dexcsTaskPanelCfdMesh.ui"))

(2) _dexcsTaskPanelCfdMesh.py

タスク画面中、 [Write mesh case] ボタンを押した時に実行される関数( writeMesh )は、

def writeMesh(self):
    import importlib
    importlib.reload(CfdMeshTools)
    self.console_message_cart = ’’
    self.Start = time.time()
    # Re-initialise CfdMeshTools with new parameters
    self.store()
    FreeCADGui.addModule("CfdMeshTools")
    FreeCADGui.addModule("CfdTools")
    FreeCADGui.doCommand("FreeCAD.ActiveDocument." + self.mesh_obj.Name + ".Proxy.cart_mesh = "
    "CfdMeshTools.CfdMeshTools(FreeCAD.ActiveDocument." + self.mesh_obj.Name + ")")
    FreeCADGui.doCommand("cart_mesh = FreeCAD.ActiveDocument." + self.mesh_obj.Name + ".Proxy.c
    cart_mesh = self.mesh_obj.Proxy.cart_mesh
    self.consoleMessage("Preparing meshing ...")
    try:
        QApplication.setOverrideCursor(Qt.WaitCursor)
        setQuantity(self.form.if_max, str(cart_mesh.getClmax()))
        print(’Part to mesh:\n
        Name: ’
        + cart_mesh.part_obj.Name + ’, Label: ’
        + cart_mesh.part_obj.Label + ’, ShapeType: ’
        + cart_mesh.part_obj.Shape.ShapeType)
        print(’
        CharacteristicLengthMax: ’ + str(cart_mesh.clmax))
        analysis = CfdTools.getParentAnalysisObject(self.mesh_obj)
        FreeCADGui.doCommand("cart_mesh.getFilePaths(CfdTools.getOutputPath(FreeCAD.ActiveD
        FreeCADGui.doCommand("cart_mesh.setupMeshCaseDir()")
        self.consoleMessage("Exporting mesh refinement data ...")
        FreeCADGui.doCommand("cart_mesh.processRefinements()")  # Writes stls so need file
        FreeCADGui.doCommand("cart_mesh.processDimension()")
        FreeCADGui.doCommand("cart_mesh.writeMeshCase()")
        self.consoleMessage("Exporting the part surfaces ...")
        FreeCADGui.doCommand("cart_mesh.writePartFile()")
        self.consoleMessage("Mesh case written to {}".format(self.cart_mesh.meshCaseDir))
   except Exception as ex:
        self.consoleMessage("Error " + type(ex).__name__ + ": " + str(ex), ’#FF0000’)
        raise
   finally:
        QApplication.restoreOverrideCursor()
   self.updateUI()

となっており、2行目の importlib.reload(CfdMeshTools) あたりの役割や、 FreeCADGui.doCommand()などの使い方が今ひとつはっきりしない部分はあったが、わからない部分はそのまま残し、以下のように改変した。

def writeMesh(self):
   import importlib
   importlib.reload(CfdMeshTools)
   self.console_message_cart = ’’
   self.Start = time.time()
   # Re-initialise CfdMeshTools with new parameters
   self.store()
   FreeCADGui.addModule("CfdMeshTools")
   FreeCADGui.addModule("dexcsCfdMeshTools")
   self.consoleMessage("Preparing meshing ...")
   cart_mesh = self.cart_mesh
   try:
        QApplication.setOverrideCursor(Qt.WaitCursor)
        FreeCADGui.doCommand("dexcsCfdMesh = dexcsCfdMeshTools.MainControl()")
        FreeCADGui.doCommand("dexcsCfdMesh.perform("+ "’" + cart_mesh.meshCaseDir + "’" + ")")
        self.consoleMessage("Exporting the part surfaces ...")
   except Exception as ex:
        self.consoleMessage("Error " + type(ex).__name__ + ": " + str(ex), ’#FF0000’)
    raise
   finally:
        QApplication.restoreOverrideCursor()
   self.updateUI()

変更は、
try: 以下のブロック朱字部分で、 DEXCS オリジナルのマクロを改変した dexcsCfdMeshTools.MainControl()
の、 perform を使って、 cfMesh 用のパラメタセットを作成し、かつメッシュ作成用の Allmesh コマンドも生
成するようにした ( マクロ改変の詳細は次節で説明 ) 。
なお、パラメタセットの作成に成功すると、 [Run mesher] ボタンが有効になる。これは self.updateUI() を
実行した際に、 Allmesh の存在が判定理由になっているので、上記 DEXCS マクロの改変の中で、 AllMesh
コマンド作成を追加した次第である。

def updateUI(self):
    case_path = self.cart_mesh.meshCaseDir
    print(case_path)
    self.form.pb_edit_mesh.setEnabled(os.path.exists(case_path))
    self.form.pb_run_mesh.setEnabled(os.path.exists(os.path.join(case_path, "Allmesh")))
    self.form.pb_paraview.setEnabled(os.path.exists(os.path.join(case_path, "pv.foam")))
    self.form.pb_load_mesh.setEnabled(os.path.exists(os.path.join(case_path, "mesh_outside.stl"
    utility = self.form.cb_utility.currentText()
    if utility == "snappyHexMesh":
        self.form.snappySpecificProperties.setVisible(True)
    elif utility == "cfMesh":
        self.form.snappySpecificProperties.setVisible(False)

Allmesh が所定の形式で作成されていれば、 [Run mesher] ボタンを押して実行される関数( runMesh )
をそのまま改変無しで使ってメッシュ作成ができる。メッシュ作成後の [Paraview] ボタンは下記関数( def
meshFinished )にて有効になるが、これ( openParaview )もそのまま改変無しで使えるようにするには、
pv.foam と pvScriptMesh.py の存在が前提となる。そこで、

def meshFinished(self, exit_code):
    if exit_code == 0:
        self.consoleMessage(’Meshing completed’)
        self.form.pb_run_mesh.setEnabled(True)
        self.form.pb_stop_mesh.setEnabled(False)
        self.form.pb_paraview.setEnabled(True)
        self.form.pb_load_mesh.setEnabled(True)
        self.template_path = os.path.join(CfdTools.get_module_path(), "data", "dexcsMesh")
        settings={}
        settings[’MeshPath’] = self.cart_mesh.meshCaseDir
        TemplateBuilder.TemplateBuilder(self.cart_mesh.meshCaseDir, self.template_path, set

上記引用ブロック中の下4行(朱字部)を追加した。これは、.FreeCAD/Mod/CfdOF/data/dexcsMeshフォルダ下に雛形ファイルを収納し、その内容(MeshPathで指定される部分)を書き換えて、所定の場所(self.cart_mesh.meshCaseDir)に収納するものである。

(3) DEXCS マクロの改変 1

FreeCADGui.doCommand("dexcsCfdMesh.perform("+ "’" + cart_mesh.meshCaseDir + "’" + ")")

にて、 DEXCS マクロ( dexcsCfdMeshTools.py ) Maincontrol() クラス中の def perform() が実行される。
その内容は以下の通り(あまり意味のないコメント行やデバッグ用の print 行は削除してある)。

def perform(self, CaseFilePath):
    self.makeStlFile(CaseFilePath)
    self.fmsFileName = CaseFilePath + MainControl.SLASH_STR + self.fileStem + MainControl.DOT_F
    command = ’. ’ + MainControl.BASHRC_PATH_4_OPENFOAM + ";" + MainControl.SURFACE_FEATURE_EDG
    command = command + MainControl.SPACE_STR + " 30 "
    command = command + MainControl.SPACE_STR + self.stlFileName + MainControl.SPACE_STR
    command = command + self.fmsFileName
    os.system(command)
    constantFolder = CaseFilePath + "/constant"
    templateSolver = self.SOLVER_PATH_TEMPLATE
    if not os.path.isdir(constantFolder):
        command = "cp -r " + templateSolver + "/constant " + CaseFilePath + "/"
        os.system(command)
        command = "rm -rf " + constantFolder + "/polyMesh"
        os.system(command)
    systemFolder = CaseFilePath + "/system"
    if not os.path.isdir(systemFolder):
        command = "cp -r " + templateSolver + "/system " + CaseFilePath + "/"
        os.system(command)
    zeroFolder = CaseFilePath + "/0"
    if not os.path.isdir(zeroFolder):
        command = "cp -rf " + templateSolver + "/0 " + CaseFilePath + "/"
        os.system(command)
    self.makeMeshDict(CaseFilePath)
    os.chdir(CaseFilePath)
    # cfmeshの実行ファイル作成 
    caseName = CaseFilePath
    title = "#!/bin/bash\n"
    envSet = ". " + MainControl.BASHRC_PATH_4_OPENFOAM + ";\n"
    solverSet = "cartesianMesh | tee cfmesh.log\n"
    sleep = "sleep 2\n"
    cont = title + envSet + solverSet + sleep
    f=open("./Allmesh","w")
    f.write(cont)
    f.close()
    # 実行権付与
    os.system("chmod a+x Allmesh")

最下段の朱字部を追加し、メッシュ作成用のスクリプト Allmesh を作成するようにした。この部分は、オリジナ
ルの DEXCS マクロでメッシュ作成を実行する関数def makeCartesianMeshPerform(self, CaseFilePath):
中にて run スクリプトを作成している部分で、名前を run から Allmesh に変更しただけである。
この perform 関数から、 2 つの関数( makeStlFilemakeMeshDict )が呼び出されており、これら 2 つの
関数の内容も変更する必要があった。
makeStlFile 関数は、読み込んだ CAD ファイルに格納されたデータのうち、 Type が region 以外のオブ
ジェクトを stl ファイルとして出力するもので、 DEXCS マクロのオリジナルでは、 region であるかどうかの
判定に ViewControl クラスを使用していたので、この部分は廃止。替わりに、メッシュ細分化オブジェクト
のプロパティを使用する事になるが、当面は region が無いモデルで実施するので、未組み込みとし、以下の
改変内容にて正常に動作する事を確認した。

1: def makeStlFile(self, CaseFilePath):
2:
3: self.caseFilePath = CaseFilePath
4: self.fileStem = os.path.splitext(self.caseFilePath)[0]
5: self.fileStem = self.fileStem.split(MainControl.SLASH_STR)[-1]
6: self.stlFileName = CaseFilePath + MainControl.SLASH_STR + self.fileStem + ’.stl’
7: self.fileName = CaseFilePath + MainControl.SLASH_STR + self.fileStem
8:
9: outputStlFile = open(self.stlFileName, ’w’)
10:
11: doc = FreeCAD.activeDocument()
12: for obj in doc.Objects:
13:     if obj.ViewObject.Visibility:
14:         __objs__=[]
15:         try:
16:             if obj.Shape:
17:                 # CfdSolver を除外
18:                 if obj.isDerivedFrom("Part::FeaturePython"):
19:                     pass
20:                 else:
21:                     __objs__.append(obj)
22:                     file=self.fileName+obj.Label+’.ast’
23:                     Mesh.export(__objs__,file)
24:                     importFile = open(file,’r’)
25:                     temp = importFile.readlines()
26:                     for line in temp:
27:                         if ’endsolid’ in line:
28:                             outputStlFile.write(’endsolid ’ + o
29:                         elif ’solid’ in line:
30:                             outputStlFile.write(’solid ’ + obj.
31:                         else:
32:                             outputStlFile.write(line)
33:                     importFile.close
34:                     os.remove(file)
35:         except AttributeError:
36:             pass
37: outputStlFile.close

13 行目で obj.ViewObject.Visibility (表示オブジェクト)だけを対象にしている点は従来通りである。ポ
イントは、 16 行目で obj.Shape に絞りこんでいる点であり、これにより、 dexcsCfdOF によって追加される
コンポーネントは、基本的に除外される事になる。但し、 CfdSolver のコンポーネントだけは、何故かプロパ
ティとして Placement を有しており、 obj.Shape として解釈されるようであった(図 13 )。当初これを除外せ
ずとも STL ファイルを作成する際に実害はなかったが、都度エラーメッセージが表示されるので鬱陶しい。
そこで、 18 行目の除外方法に至った。

図 13 dexcsCfdOF コンポーネントのプロパティ

makeMeshDict 関数は、基本的に cfMesh 用の meshDict ファイルを、マニュアルに記載通りに作成するも
ので、パラメタ変更が必要な部分は viewControl クラスから取得する仕組みとなっていた。そこでこのパラメ
タ変更部分を置き換えれば良いだけのはずである。当面の対象例題( backstepSimple )では、基本パラメタに
係る部分だけを変更対象にするので、パラメタの値を以下のように仮設定しておいて、

testDict_maxCellSize = 0.583
testDict_minCellSize = Model.EMPTY_STR
testDict_untangleLayerCHKOption = 0
testDict_optimiseLayerCHKOption = 0
testDict_keepCellsIntersectingBoundaryCHKOption = 0
testDict_stopAfterEdgeExtractionCHKOption = 0

これを使って、viewControl クラスから値を取得していた部分(例えば、 self.viewControl.get maxCellSizeValue() )
を、以下のように変更した( 6 箇所)。

#’maxCellSize\t’ + str(self.viewControl.get_maxCellSizeValue()) + ’;\n’
’maxCellSize\t’ + str(testDict_maxCellSize) + ’;\n’

さらに、パッチやリージョンをパーツ毎に細分化指定して追加する部分は当面使用しないので、全てコメン
トアウトした。

# local refinement // 指定されており、以外のもの cellSizeregion
# iRow=0
# while (self.viewControl.get_gridTableValue(iRow,0)):
#     iRow = iRow + 1
#     #print (’### ’, self.viewControl.get_gridTableValue(iRow-1,2) , self.viewControl.get_gridTabl
#     if (self.viewControl.get_gridTableValue(iRow-1,2) != Model.EMPTY_STR and
#         self.viewControl.get_gridTableValue(iRow-1,1) != MainControl.REGION_STR):
# (以下省略 )

以上の改変にて、当面の対象例題( backstepSimple )にて、 meshDict 作成から⇒メッシュ作成⇒ Paraview
によるメッシュ確認の一連の動作を確認する事が出来た。

(4) メッシュ基本サイズの自動計算と meshDict への反映方法

以上で、当初設定したマイルストーンに到達したことになるが、次のステップ(メッシュ細分化コンテナの
改変)に進む前に、コンテナで設定したパラメタを、従来の viewControl クラスを使わないで、どうやって
meshDict 作成プロセスに反映するかの方法を探った。その最初の手掛かりとして、メッシュ基本サイズにつ
いて、これを反映する方法について調査した。
まずは、メッシュ作成コンテナ中に記された値の取得方法であるが、試行錯誤の末、以下のようにして実現
できた。

#testDict_maxCellSize = 0.583
for obj in FreeCAD.ActiveDocument.Objects:
    if hasattr(obj, "Proxy") and isinstance(obj.Proxy, _CfdMesh):
        testDict_maxCellSize = obj.CharacteristicLengthMax

また、メッシュ作成コンテナ中の Base element size: の値そのものは、手入力で変更は可能である。し
かし、どうせならモデルを読み込んだ状態にてそのサイズを調べて自動計算した値を表示しておきたい。
CfdMeshTools.py にて、メッシュ作成コンテナが作成される際の def init ブロック中、

# Default to 2 % of bounding box characteristic length
self.clmax = Units.Quantity(self.mesh_obj.CharacteristicLengthMax).Value
if self.clmax <= 0.0:
    #shape = self.part_obj.Shape
    #cl_bound_mag = math.sqrt(shape.BoundBox.XLength**2 + shape.BoundBox.YLength**2 + shape.Bou
    #cl_bound_min = min(min(shape.BoundBox.XLength, shape.BoundBox.YLength), shape.BoundBox.ZLe
    #self.clmax = min(0.02*cl_bound_mag, 0.4*cl_bound_min)
    xmax = -1.0e+30
    xmin = 1.0e+30
    ymax = -1.0e+30
    ymin = 1.0e+30
    zmax = -1.0e+30
    zmin = 1.0e+30
    doc = FreeCAD.activeDocument()
    for obj in doc.Objects:
        try:
            if obj.Shape:
                if obj.Shape.BoundBox.XMax > xmax:
                    xmax = obj.Shape.BoundBox.XMax
                if obj.Shape.BoundBox.XMin < xmin:
                    xmin = obj.Shape.BoundBox.XMin
                if obj.Shape.BoundBox.YMax > ymax:
                    ymax = obj.Shape.BoundBox.YMax
                if obj.Shape.BoundBox.YMin < ymin:
                    ymin = obj.Shape.BoundBox.YMin
                if obj.Shape.BoundBox.ZMax > zmax:
                    zmax = obj.Shape.BoundBox.ZMax
                if obj.Shape.BoundBox.ZMin < zmin:
                    zmin = obj.Shape.BoundBox.ZMin
        except AttributeError:
            pass
    sumOf3Edges = (xmax-xmin+ymax-ymin+zmax-zmin)
    self.mesh_obj.CharacteristicLengthMax = sumOf3Edges / 60.0

と追加することで、変更した値が設定されておればそれをそのまま表示し、それが無い場合( self.clmax=0 )
には、現行 DEXCS マクロと同等の計算方式で算出した値を表示することになる。ちなみにこの最下行ロジックは、
今後改良する予定である。

(5) 残された課題

  • makeStlFile 関数において、 region タイプのパーツを除外する方法の組み込み
  • 作成されるstl / fmsファイルの名前が、.stl / .fms となっている
  • cfMesh の 2D 対応
  • スケール変換機能の組み込み
  • メッシャーとして、 snappyHexMesh や gmsh への対応は将来の課題として、当面はインタフェース部分を削除(もしくは見えないように)する。
  • 改変モジュール中、不要(使わなくなった)部分の削除

前へ 目次 次へ

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")

前へ 目次 次へ