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 FSI マクロの改良

DEXCS FSI マクロとは

DEXCSアドバンス版に同梱され、FreeCADのFEMワークベンチで作成した静解析用のinpファイルをDEXCS for preCICEで使用するFSI用のinpファイルに変換するツール(下図)。



FSIマクロの仕組み

DEXCSツールバーのボタンをクリックすると、exportFSIInp.FCMacro が起動して、QtDialogのGUI画面が現れるので、必要に応じてパラメタを変更し、最下段の[make inpfile for FSI]ボタンをクリックすると、dexcsFunctions.pyを使って静解析用のinpファイル(SolverCcxTools/FEMMeshGmds.inp)をFSI用のinpファイル(flap.inp + interface.nam)に変換するという仕組みになっている。

FSIマクロの課題

これまでに、

  1. 変換対象モデルは1つだけ
  2. 出力間隔の指定が手入力
  3. スケーリング出力機能が欲しい
  4. ヤング率の単位?
  5. plotWatcher

といった課題が認識されていたが、ここで上記第4番目の項目まで解消した。5番目については、別途DEXCSランチャーを改造中であり、その取り組みの結果を反映することになる(かもしれない)。

改良前後の画面イメージ比較

その他の変更

SolverCcxToolsコンテナを選択した状態からでないと起動出来ないようにした(下図左)

静解析用のinpファイルが存在しない場合にも起動できないようにした(下図右)

変換が終了したら、設定画面も閉じるようにした。

ソースコード

https://gitlab.com/E.Mogura/dexcs-fc-macro

より、以下のファイルを更新すればよい

  • exportFSIinp.FCMacro
  • dexcsFunctions.py

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"

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

前へ 目次 次へ