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製作メモ 4

4. DEXCSワークベンチ / CfdOFのGUIを改変

メッシュ作成に関して、オリジナルのCfdOFでは、cfMesh だけでなく、snappyHexMesh, gmsh にも対応できるフレームになっているが、DEXCSランチャーでは、このフレームは残す(将来的にcfMesh以外も使えるようにする)が、当面はcfMeshを作成するとして、現行DEXCSランチャーに対する不足分と、機能追加予定分を実装していくこととする。



なお、cfMesh作成用のパラメタとして、globalパラメタとlocalパラメタがあるので、前者はメッシュコンテナ、後者はメッシュ細分化コンテナ上で設定変更できるようにするのが常識的なアプローチであろう。

4-1. メッシュコンテナの改変

図34. メッシュコンテナの改変イメージ

メッシュコンテナの改変イメージを図に示す。赤枠部が追加されており、具体的には、

  1. Feature Angle
    • STLファイルをfmsファイルへ変換する際の、特徴(輪郭線)抽出角度
  2. Scale to Meter
    • FreeCAD上のモデルサイズ(通常はミリメートル)をメートルに変換する際の係数
  3. KeepCellsIntersectingBoundary
  4. optimeizeLayer
    • レイヤーの最適化オプション(6つ)
  5. workFlowControl
    • (デバッグ用)メッシュ作成ステップを途中で止める

である。現行のDEXCSマクロと比較すると、このうち、2番目が新設、4番目については詳細パラメタの設定変更が、5番目についても任意の段階が選択可能になるという事である。

(1) GUI画面作成部分の変更

メッシュコンテナ上のGUIパーツ(文字や、ボタン、テキスト入力欄など)を、Qtのwidget, frame にどうやってレイアウトするかの情報は、dexcsTaskPanelCfdMesh.ui というファイルにまとめて記述されている(これそのものは多分、GUIツールで自動作成されたものである)。この内容は、実際に生成されるGUI画面とコードを対比しながら眺めれば容易に理解できる(図35)。

図35. メッシュ作成タスク画面と、その生成コード

したがって、手作業による改変はさほど難しくはない。図36.に改変例を示しておく。なお、実際に追加したコードはスクラッチで記述したものではなく、類似のパラメタブロックをコピーして貼り付け。名前など必要部分のみ手修正するというやり方で実施できている。

図36. 改変(追加)の具体例

この画面情報(dexcsTaskPanelCfdMesh.ui)は、_dexcsTaskPanelCfdMesh.pyが起動されると、def __init__()において、

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

として読み込まれ、その少し下で、ボタンや編集可能アイテムがクリックされた時のイベントが割り付けられているので、追加したボタンやチェックボックス、リストセレクションに関しては、以下朱字部分を追加。

self.form.pb_write_mesh.clicked.connect(self.writeMesh)
self.form.pb_edit_mesh.clicked.connect(self.editMesh)
self.form.pb_run_mesh.clicked.connect(self.runMesh)
self.form.pb_stop_mesh.clicked.connect(self.killMeshProcess)
self.form.pb_paraview.clicked.connect(self.openParaview)
self.form.pb_load_mesh.clicked.connect(self.pbLoadMeshClicked)
self.form.pb_clear_mesh.clicked.connect(self.pbClearMeshClicked)
self.form.pb_searchPointInMesh.clicked.connect(self.searchPointInMesh)
self.form.pb_stop_mesh.setEnabled(False)
self.form.pb_paraview.setEnabled(False)
self.form.snappySpecificProperties.setVisible(False)
self.form.optimizer_frame.setVisible(False)
self.form.check_reCalculateNormals.setChecked(True)

self.form.cb_dimension.addItems(_CfdMesh.known_element_dimensions)
self.form.cb_utility.addItems(_CfdMesh.known_mesh_utility)
self.form.cb_workflowControls.addItems(_CfdMesh.known_workflowControls)

self.form.if_max.setToolTip("Enter 0 to use default value")
self.form.pb_searchPointInMesh.setToolTip("Specify below a point vector inside of the mesh or press 'Search' "
                                                  "to try to automatically find a point")
self.form.if_cellsbetweenlevels.setToolTip("Number of cells between each of level of refinement")
self.form.if_edgerefine.setToolTip("Number of refinement levels for all edges")

self.form.check_optimiseLayer.stateChanged.connect(self.updateUI)

また、def_updateUI()での更新において、

if self.form.check_optimiseLayer.isChecked():
    self.form.optimizer_frame.setVisible(True)
else:
    self.form.optimizer_frame.setVisible(False)

を追加した。

以上で、新規にメッシュコンテナを作成した場合の初期画面を作り直すことができた。

(2) コンテナプロパティの追加

編集可能アイテムに関しては、そのプロパティを定義する必要がある。これらプロパティは、CfdMesh.py中の、 def initProperties(…) のブロックで定義されているので、既に定義済のパラメタの記述方法を参考にして、以下追加した。

addObjectProperty(obj, "FeatureAngle", 30, "App::PropertyFloat", "Mesh Parameters",
                  "Feature Angle of STL parts")
addObjectProperty(obj, "ScaleToMeter", 1, "App::PropertyFloat", "Mesh Parameters",
                  "Scale Factor to meter")
addObjectProperty(obj, "keepCellsIntersectingBoundary", False, "App::PropertyBool", "Mesh Parameters",
                  "activates smoothing of boundary layers")
addObjectProperty(obj, "optimiseLayer", False, "App::PropertyBool", "Mesh Parameters",
                  "keep template cells intersecting boundary")
addObjectProperty(obj, "opt_nSmoothNormals", 3, "App::PropertyInteger", "Mesh Parameters",
                  "number of iterations in the procedure for reducing normal variation")
addObjectProperty(obj, "opt_maxNumIterations", 5, "App::PropertyInteger", "Mesh Parameters",
                  "maximum number of iterations of the whole procedure")
addObjectProperty(obj, "opt_featureSizeFactor", 0.4, "App::PropertyFloat", "Mesh Parameters",
                  "ratio between the maximum layer thickness and the estimated feature size")
addObjectProperty(obj, "opt_reCalculateNormals", True, "App::PropertyBool", "Mesh Parameters",
                  "activale 1 or deactivate 0 calculation of normal")
addObjectProperty(obj, "opt_relThicknessTol", 0.01, "App::PropertyFloat", "Mesh Parameters",
                  "maximum allowed thickness variation of thickness between two neighbouring points, devided by the distance between the points")
addObjectProperty(obj, "workflowControls", _CfdMesh.known_workflowControls, "App::PropertyEnumeration",
                     "Mesh Parameters", "workflowControls")

但し、これだけでは、ここで追加したプロパティとメッシュ作成タスク画面に表示される変数との関連付けが出来ていない。これには、_dexcsTaskPanelCfdMesh.py中の、def __load__(self) と、def __store__(self)を使っている。つまり、メッシュ作成コンテナをダブルクリックすると、 def __load__(self)に従って、プロパティの値がメッシュ作成タスク画面のパラメタ値に反映され、メッシュ作成タスク画面を閉じると、その時点での設定値が、def __store__(self)に従ってプロパティの値として収納されるという仕組みになっている。

したがって、def __load__(self) 中に、以下追加。

self.form.if_featureAngle.setValue(self.mesh_obj.FeatureAngle) 
self.form.if_scaleToMeter.setValue(self.mesh_obj.ScaleToMeter) 
self.form.check_keepCells.setChecked(self.mesh_obj.keepCellsIntersectingBoundary) 
self.form.check_optimiseLayer.setChecked(self.mesh_obj.optimiseLayer) 
self.form.if_nSmoothNormals.setValue(self.mesh_obj.opt_nSmoothNormals) 
self.form.if_maxNumIterations.setValue(self.mesh_obj.opt_maxNumIterations) 
self.form.if_featureSizeFactor.setValue(self.mesh_obj.opt_featureSizeFactor) 
self.form.check_reCalculateNormals.setChecked(self.mesh_obj.opt_reCalculateNormals) 
self.form.if_relThicknessTol.setValue(self.mesh_obj.opt_relThicknessTol) 
index_utility = self.form.cb_workflowControls.findText(self.mesh_obj.MeshUtility)
self.form.cb_workflowControls.setCurrentIndex(index_utility)

def __store__(self)中に、以下追加

FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.FeatureAngle "
                     "= {}".format(self.mesh_obj.Name, self.form.if_featureAngle.value()))
FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.ScaleToMeter "
                     "= {}".format(self.mesh_obj.Name, self.form.if_scaleToMeter.value()))
FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.keepCellsIntersectingBoundary "
                     "= {}".format(self.mesh_obj.Name, self.form.check_keepCells.isChecked()))
FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.optimiseLayer "
                     "= {}".format(self.mesh_obj.Name, self.form.check_optimiseLayer.isChecked()))
FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.opt_nSmoothNormals "
                     "= {}".format(self.mesh_obj.Name, self.form.if_nSmoothNormals.value()))
FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.opt_maxNumIterations "
                     "= {}".format(self.mesh_obj.Name, self.form.if_maxNumIterations.value()))
FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.opt_featureSizeFactor "
                     "= {}".format(self.mesh_obj.Name, self.form.if_featureSizeFactor.value()))
FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.opt_reCalculateNormals "
                     "= {}".format(self.mesh_obj.Name, self.form.check_reCalculateNormals.isChecked()))
FreeCADGui.doCommand("\nFreeCAD.ActiveDocument.{}.opt_relThicknessTol "
                     "= {}".format(self.mesh_obj.Name, self.form.if_relThicknessTol.value()))
FreeCADGui.doCommand("FreeCAD.ActiveDocument.{}.workflowControls "
                     "= '{}'".format(self.mesh_obj.Name, self.form.cb_workflowControls.currentText()))

することにより、コンポーネントツリー上で、CfdMeshコンテナを選択した際、プロパティ画面の中に追加したパラメタセットとその値が表示されるで、メッシュ作成タスク画面での設定値と整合していることを確認しながら上記コードを修正した。もちろんここでも、類似のコードブロックをコピーして貼り付け。名前など必要部分のみ手修正するというやり方で実施できている。

以上で、追加したグローバルパラメタをモデルプロパティとして参照できるようになったので、meshDict作成プログラムに反映(改変)する。

(3) meshDict作成プログラムの変更

追加したグローバルパラメタを改めて以下に取り纏めておく。

  1. Feature Angle
    • STLファイルをfmsファイルへ変換する際の、特徴(輪郭線)抽出角度
  2. Scale to Meter
    • FreeCAD上のモデルサイズ(通常はミリメートル)をメートルに変換する際の係数
  3. KeepCellsIntersectingBoundary
  4. optimeizeLayer
    • レイヤーの最適化オプション(6つ)
  5. workFlowControl
    • (デバッグ用)メッシュ作成ステップを途中で止める

meshDictファイルの書き換えというのは、厳密には、3番面以降の項目について実施することになる。dexcsCfdMeshTools.py の def meshDict(…) において、meshDictファイルをほとんどベタ書きしているだけなので、

(3-1)FeatureAngle

dexcsCfdMeshTools.py の def perform(…) において

command = command + MainControl.SPACE_STR + self.viewControl.get_featureAngleValue()

としていたのを、3-5節では暫定的に

command = command + MainControl.SPACE_STR + " 30 "

と変更していた部分である。これを、

_featureAngle = self.mesh_obj.FeatureAngle
command = command + MainControl.SPACE_STR + " " + str(_featureAngle)

と変更すれば良いことになる。ここに、self.mesh_obj.FeatureAngle として、プロパティの値を取得しているが、対象となるオブジェクトself.mesh_objは、3-5-(4)で得られた知見を使って、class MainControl() の def __init__(self) において、

for obj in FreeCAD.ActiveDocument.Objects:
    if hasattr(obj, "Proxy") and isinstance(obj.Proxy, _CfdMesh):
       self.mesh_obj = obj

として取得するようにした。こうしておけば、他の関数ブロック内でも参照できるようになるので、併せて、3-5-(4)で記したメッシュ基本サイズ(CharacteristicLengthMax)の取得方法も、上記を参照して利用するよう変更した。

(3-2) ScaleToMeter

モデルサイズのスケール変更は、OpenFOAMの transformPoints コマンドを使って、出来上がったメッシュデータのサイズを変更する方法もあるが、これだとParaview上でメッシュデータとstlファイルとの直接比較ができなくなってしまう。stlファイルそのもののスケール変更は、cfMeshのsurfaceTransformPoints コマンドを使って実施できるので、(3-1)がclass MainControl():の冒頭で定義した

SURFACE_FEATURE_EDGES = "surfaceFeatureEdges -angle"

として、surfaceFeatureEdges コマンドを実行するものであったので、これを実行する前にclass MainControl():の冒頭に同様に

SURFACE_FEATURE_TRANS = "surfaceTransformPoints -scale"

定義しておいて、最終的に、fmsファイルを作成するまでの処理を以下のように変更した。

modelName = os.path.splitext(os.path.basename(FreeCAD.ActiveDocument.FileName))[0]
self.makeStlFile(CaseFilePath)
### step2 ### convert stl to fms file ##############################
self.fmsFileName = CaseFilePath + modelName + ".fms"
_ScaleToMeter = MainControl.SPACE_STR + str(self.mesh_obj.ScaleToMeter)
_featureAngle = MainControl.SPACE_STR + str(self.mesh_obj.FeatureAngle)
command = '. ' + MainControl.BASHRC_PATH_4_OPENFOAM + ";" + MainControl.SURFACE_FEATURE_TRANS
command = command + MainControl.SPACE_STR + "'(" + _ScaleToMeter + _ScaleToMeter + _ScaleToMeter + ")'"
command = command + MainControl.SPACE_STR + self.stlFileName + MainControl.SPACE_STR + self.stlFileName + ";"
command = command + MainControl.SURFACE_FEATURE_EDGES
command = command + _featureAngle              
command = command + MainControl.SPACE_STR + self.stlFileName + MainControl.SPACE_STR
command = command + self.fmsFileName
os.system(command)

と変更した(オリジナルのDEXCSマクロと比べると、朱字部分が追加・変更されたことになる)。もう1点重要なのは、ベースメッシュサイズもあわせて変更する必要のある点である。これは、def makeMeshDict(…) 中、以下のように変更すれば良かった(朱字部を追加)。

testDict_maxCellSize = self.mesh_obj.CharacteristicLengthMax * self.mesh_obj.ScaleToMeter

(3-3) keepCellsIntersectingBoundary

testDict_keepCellsIntersectingBoundaryCHKOption = self.mesh_obj.keepCellsIntersectingBoundary

(3-4) optimiseLayer

optimiseLayer オプションについては、使用するかどうかのチェックボックスを含めて、パラメタが6つあるので、これらを以下のように取得しておいて、

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)

strings2 = [… を定義するブロック中、ベタ書きしていた緑字部分をコメントアウトして、朱字にて置き換える

'\t// activates smoothing of boundary layers (optional)\n' , 
'\t// deactivated by default \n' ,
#'\t// optimiseLayer		1; // \n' 
optimiseLayerString , 
'\t\n',
'\toptimisationParameters \n' 
'\t{\n'
'  \t\t// number of iterations in the procedure\n'
'  \t\t// for reducing normal variation (optional)\n'
#'  \t\tnSmoothNormals\t3;\n'
'  \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'

(3-5) workflowControls

workflowControls についても、以下のようにstopAfterStringsを定義して、

if self.mesh_obj.workflowControls == 'none':
    stopAfterString = '\t//\tstopAfter\tedgeExtraction;\n'
else:
    stopAfterString = '\t\tstopAfter\t' + self.mesh_obj.workflowControls +';\n'

strings8 = [… のセクションにおいて、そのまま使えば良い。

'workflowControls\n',
'{\n',
'\t//\t1.templateGeneration\n',
'\t//\t2.surfaceTopology\n',
'\t//\t3.surfaceProjection\n',
'\t//\t4.patchAssignment\n',
'\t//\t5.edgeExtraction\n',
'\t//\t6.boundaryLayerGeneration\n',
'\t//\t7.meshOptimisation\n',
'\t//\t8.boundaryLayerRefinement\n',
'\n',
#'\t//\tstopAfter\tedgeExtraction;\n',
stopAfterString ,
'\n',

前へ 目次 次へ

DEXCSアドバンス版でCalculiXの並列計算

DEXCSアドバンス版を作成した当初においては、CalculiXの並列計算までは考慮していなかったというのが実態です。同梱したAllrun-parallelにおいても、OpenFOAMの並列計算を考慮した内容でしかありません。

その後、Allrunスクリプト中に、CalculiX(実体はccx_preCICE) を起動する際に、

    export OMP_NUM_THREADS=1
    export CCX_NPROC_EQUATION_SOLVER=1

という環境変数がある事に気付き、どうやらこの数字で並列度を変えられそうだとなりました。しかしながら、この数字を大きくすると、確かに速くはなるんですが、その効果は僅かなものでしかなかったというのが実状でした。

最近、比較的規模が大きく、なおかつCalculiXの計算時間が、OpenFOAMの計算時間より長くなってしまうような事例に遭遇する事となり、改めてなんとかならないものかと調べ直しました。そこで、よくよく計算ログ(Solve.log)を見直すと・・・

 iteration 1

 Using up to 4 cpu(s) for the stress calculation.

 Using up to 4 cpu(s) for the symmetric stiffness/mass contributions.

 Factoring the system of equations using the symmetric spooles solver
 Using 1 cpu for spooles.

 Using up to 4 cpu(s) for the stress calculation.

スレッド数を4にして計算しているので、確かに 4 cpu(s) というログになっているのですが、もっとよく見ると、spooles solver の部分では、1 cpu にしかなっていないという点に、今更ながら気付いたという事です。つまり、一番肝心な逆行列を計算するところで、マルチスレッド計算出来ていなかったという事です。

CalculiX(ccx本体)については、マルチスレッド計算用に、spoolesをマルチスレッド対応すれば良い・・・的な情報はたくさん存在するので、色々調べたのですがピンと来るものがありません。よくよく考えたら、ccx本体は関係なくて、ccx_preCICEをマルチスレッド対応させる必要があるんだということでした。そこで、調べ直すと、ようやくズバリの記事が見つかりました!

https://precice.discourse.group/t/calculix-parallelization/167

これはpreCICEのディスカッションボードの記事で、しかも時期的には2020年3月ということで、DEXCSアドバンス版に仕掛かっていた当時には既にわかっていた情報でした。これが当時のインストール情報ページには反映されていなかったという事です。ちなみに、このインストール情報ページも現在では、当時のものとは全く別物になってしまっています。これがpreCICEワールド!

何はともあれ、当時の calculix-adapter(ccx_preCICE)のビルド方法をベースに考えると、以下の2点につき、ビルド追加・変更すればよいということです。

SPOOLES

$ cd $HOME/CalculiX
$ cd SPOOLES.2.2/MT
$ make

これにて、MT/src/spoolesMT.a が生成される。

calculix-adapter

$HOME/preCICE/calculix-adapter-2.15_preCICE2.x/Makefileを、以下変更(朱字部分を追記)して

LIBS = \
        \$(SPOOLES)/MT/src/spoolesMT.a \
        \$(SPOOLES)/spooles.a \
        \$(PKGCONF_LIBS) \
        -lstdc++ \
        -L$(YAML)/build -lyaml-cpp \

CFLAGS = -Wall -O3 -fopenmp $(INCLUDES) -DARCH="Linux" -DSPOOLES -DARPACK -DMATRIXSTORAGE -DUSE_MT

コンパイルし、バイナリをコピーし直せば良いということです。

$ cd $HOME/preCICE/calculix-adapter-2.15_preCICE2.x
$ make clean
$ make
$ sudo cp bin/ccx_preCICE /usr/bin

つまり、当初のビルド方法では、spoolesMT(マルチスレッド)が組み込まれていなかったということです。

計算速度について

計算対象と計算内容について、現時点では公開できませんが、メッシュ規模と計算時間について比較した数値は公表しても問題無さそうなので以下に示しておきます。

計算規模は表中に記したNp(節点数)Nc(要素数)の通りで、計算の時間送りステップ数は850、陰解法による繰り返し計算があって総ステップ数としては3730回の計算をしている。また、計算機のスペックは、Core i9-11900K @ 3.50GHz(Cores: 8)でメモリーは十分に余裕のある状態での結果です。

case2が、従来の方法によるもので、CalculiXのスレッド数を4に指定したものの、ccx_preCICEがMT対応していなかった為、case1 に比べてほんのわずか(10%以下)しかスピードアップしていなかった。case3以降が、MT対応のccx_preCICEで計算をやり直したもので、case5を除いて、スレッド数を増やすことによるスピードアップが得られた(とはいうもの、最大で2倍弱程度だが・・・)。

case5において、悪化しているのは、計算機の総コア数が8であり、OpenFOAMの占有分4を除いた4コアに対して6スレッドの処理には無理があるということのようです。

念の為、別のメニーコアの計算機(Xeon Gold 6130 @ 2.10GHz,16Core×2)にてやり直してみました。

但し、こちらはベースクロックが遅いので、計算の総ステップ数は1601回と少なくして実施したもの。総コア数に余裕があれば、先のような極端な速度低下はなく、基本的にコア数に応じて速度アップするが、6以上でほとんど頭打ち状態になる(2倍弱のスピードアップにしかならない)ことも確認できました。

但し、メッシュ数が変わった場合や、今回はCalculiXのメッシュがテトラの(2次要素でメッシュ作成が困難であった為)1次要素で作成してあるが通常は2次要素で計算したいところであり、このあたりの状況が変わった時の並列速度がどうなるかは、今後改めて調査する予定です。