Femap API Results Browsing Object の SetColumns メソッドの不適切な挙動

FEMAP 2020.1 のAPIでは、以下のプログラムでFEMAPがフリーズします。

# coding: utf-8

import pythoncom
import Pyfemap

existObj = pythoncom.connect(Pyfemap.model.CLSID)
app = Pyfemap.model(existObj)

elLIST = [1,  2,  3,  4,  5,  6,  7]
pLIST0 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST1 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST2 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST3 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST4 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST5 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST6 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST7 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST8 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]

setID = 10
outSet = app.feOutputSet
outSet.title = "test"
outSet.value = 0
outSet.analysis = 0
outSet.Put (setID)
RBO = app.feResults
pLIST_ALL = [pLIST0, pLIST1, pLIST2, pLIST3, pLIST4, pLIST5, pLIST6, pLIST7, pLIST8]
ttl = "Corner Pressure Face 1 Set " + str(setID)
_, nCol = RBO.AddElemWithCornerColumnsV2(setID, 24000000, 24000001, 24000002, 24000003, 24000004, 24000005, 24000006, 24000007, 24000008, ttl, 4, True)
_ = RBO.SetColumns(len(nCol), nCol, len(elLIST), elLIST, pLIST_ALL)

RBO.Save()
_ = outSet.Put(-1)

しかし、以下のプログラムなら正常に動作します。

# coding: utf-8

import pythoncom
import Pyfemap

existObj = pythoncom.connect(Pyfemap.model.CLSID)
app = Pyfemap.model(existObj)

elLIST = [1,  2,  3,  4,  5,  6,  7,  8]
pLIST0 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]
pLIST1 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]
pLIST2 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]
pLIST3 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]
pLIST4 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]
pLIST5 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]
pLIST6 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]
pLIST7 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]
pLIST8 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]

setID = 10
outSet = app.feOutputSet
outSet.title = "test"
outSet.value = 0
outSet.analysis = 0
outSet.Put (setID)
RBO = app.feResults
pLIST_ALL = [pLIST0, pLIST1, pLIST2, pLIST3, pLIST4, pLIST5, pLIST6, pLIST7, pLIST8]
ttl = "Corner Pressure Face 1 Set " + str(setID)
_, nCol = RBO.AddElemWithCornerColumnsV2(setID, 24000000, 24000001, 24000002, 24000003, 24000004, 24000005, 24000006, 24000007, 24000008, ttl, 4, True)
_ = RBO.SetColumns(len(nCol), nCol, len(elLIST), elLIST, pLIST_ALL)

RBO.Save()
_ = outSet.Put(-1)

つまり、SetColumns メソッドは、値を設定する要素数が7以下の場合はFEMAPがフリーズし、8以上の場合は正常に動作する不適切な挙動があります。

これを回避するためには、以下のプログラムのように、SetColumn メソッドを使って、各列ごとに値を設定する必要があります。

# coding: utf-8

import pythoncom
import Pyfemap

existObj = pythoncom.connect(Pyfemap.model.CLSID)
app = Pyfemap.model(existObj)

elLIST = [1,  2,  3,  4,  5,  6,  7]
pLIST0 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST1 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST2 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST3 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST4 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST5 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST6 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST7 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]
pLIST8 = [1.0,2.0,3.0,4.0,5.0,6.0,7.0]

setID = 10
outSet = app.feOutputSet
outSet.title = "test"
outSet.value = 0
outSet.analysis = 0
outSet.Put (setID)
RBO = app.feResults
pLIST_ALL = [pLIST0, pLIST1, pLIST2, pLIST3, pLIST4, pLIST5, pLIST6, pLIST7, pLIST8]
ttl = "Corner Pressure Face 1 Set " + str(setID)
_, nCol = RBO.AddElemWithCornerColumnsV2(setID, 24000000, 24000001, 24000002, 24000003, 24000004, 24000005, 24000006, 24000007, 24000008, ttl, 4, True)
_ = RBO.SetColumn(nCol[0], len(elLIST), elLIST, pLIST0)
_ = RBO.SetColumn(nCol[1], len(elLIST), elLIST, pLIST1)
_ = RBO.SetColumn(nCol[2], len(elLIST), elLIST, pLIST2)
_ = RBO.SetColumn(nCol[3], len(elLIST), elLIST, pLIST3)
_ = RBO.SetColumn(nCol[4], len(elLIST), elLIST, pLIST4)
_ = RBO.SetColumn(nCol[5], len(elLIST), elLIST, pLIST5)
_ = RBO.SetColumn(nCol[6], len(elLIST), elLIST, pLIST6)
_ = RBO.SetColumn(nCol[7], len(elLIST), elLIST, pLIST7)
_ = RBO.SetColumn(nCol[8], len(elLIST), elLIST, pLIST8)

RBO.Save()
_ = outSet.Put(-1)

FEMAP API で行う処理の性能を向上する

brown hourglass on brown wooden table
Photo by Mike on Pexels.com

FEMAPのAPIを使用して処理を行う際、対象とする要素や節点の数が多いとかなり時間がかかることがあります。

FEMAPはユーザインタフェースが表示されている間は、モデルの状態を反映するために絶えずアップデートされています。

処理実行中にアップデートの必要がなければ feAppVisible(False) でユーザインタフェース自体を非表示にしてしまうか、 feAppLock でロックしてしまうかのどちらかで処理速度を改善できます。

処理の内容により改善の度合いは異なりますが、多くの場合10倍〜20倍程度の改善が見込めます。

処理完了後は feAppVisible(True) や feAppUnlock の呼び出しをお忘れなく。

Femap API Results Browsing Object のサンプル

簡単なサンプルです。

◆特定のアウトプットベクトルの値を取得する
アウトプットセット1、アウトプットベクトル8006の値を取得する

import pythoncom
import Pyfemap as Pyfemap
from Pyfemap import constants

existObj = pythoncom.connect(Pyfemap.model.CLSID)
app = Pyfemap.model(existObj)

ID_list = []
entity_set = app.feSet
RBO = app.feResults
RBO.VectorEntitiesV2(1, 8006, entity_set.ID, True)

entity_count = entity_set.Count()
_ = entity_set.First()
count = 0
while count < entity_count:
    ID_list.append(entity_set.CurrentID)
    _ = entity_set.Next()
    count += 1

for ID in ID_list:
    _, f = RBO.EntityValueV2(1, 8006, ID)
    print(ID, f)

◆変位ベクトルを格納する
アウトプットセット1、節点1と2に変位ベクトル(9,000,001、9,000,002、9,000,003、9,000,004)を格納する

import pythoncom
import Pyfemap as Pyfemap
from Pyfemap import constants

existObj = pythoncom.connect(Pyfemap.model.CLSID)
app = Pyfemap.model(existObj)

node = []
disp_x = []
disp_y = []
disp_z = []

node.append(1)
node.append(2)

disp_x.append(1.0)
disp_x.append(0.5)

disp_y.append(1.0)
disp_y.append(2.0)

disp_z.append(0.5)
disp_z.append(3.0)

RBO = app.feResults

nCol = RBO.AddVectorAtNodeColumnsV2(1, 9000001, 9000002, 9000003, 9000004, "USER Displacement", 1, True)
_ = RBO.SetVectorAtNodeColumnsV2(nCol[1], len(node), node, disp_x, disp_y, disp_z)
RBO.Save()

◆BEAM要素のA端、B端のアウトプットベクトルを格納する
要素番号1,2のBEAM要素に端部の応力を格納する

import pythoncom
import Pyfemap as Pyfemap
from Pyfemap import constants

existObj = pythoncom.connect(Pyfemap.model.CLSID)
app = Pyfemap.model(existObj)

elem = []
stressA = []
stressB = []

elem.append(1)
elem.append(2)

stressA.append(-10.0)
stressB.append(10.0)
stressA.append(-20.0)
stressB.append(20.0)

RBO = app.feResults

_, nCol = RBO.AddScalarAtBeamColumnsV2(1, 9000101, 9000102, "USER Stress", 2, 4, True, False)
print(nCol)
rc = RBO.SetColumn(nCol[0], len(elem), elem, stressA)
rc = RBO.SetColumn(nCol[1], len(elem), elem, stressB)
RBO.Save()

pygubuでpythonのGUIアプリを作る

pythonで手間なくGUIアプリを作ろうと思ったら、標準でインストールされているtkinterを使うことが良いかもしれません。

先に投稿した、Femapに独自開発の簡単なアプリを埋め込む際もtkinterを利用すれば良いと思います。

簡単なアプリなら、GUIのデザイナーツールを使うまでもないですが、機能を並べながらインタフェースを設計していくならpygubuのようなツールを使うと便利です。

応答解析の結果をFemapで分析する支援ツールとして、こんな機能のアプリはどうでしょうか。

pygubuインタフェース

Femap API の feOutput が廃止になる?

Femap API の WinWrap Basic では動作するのに、Pyfemap.py では動作しないメソッドがあり、SIEMENSのコミュニティに質問を投稿していたところ、SIEMENSの社員の方から回答をいただき、無事にプログラムを完成することができました。

その時に、feOutput は 2020.1 のリリースから非推奨になる旨のコメントもいただきました。
API開発者は feResults のみを使用するように移行を開始する必要があるとのことです。

Femap API はマニュアルにもいくつか「廃止予定」と書かれた機能があり、開発したプログラムも継続的にメンテナンスが必要だろうと思います。

2021/1/7追記
代替となるfeResultsオブジェクトの簡単な使用方法はこちら

Femapのウィンドウ内に別のアプリを埋め込むAPI

以下は、Femapの「モデル情報」ウィンドウの下方にWindowsのメモアプリを埋め込む例です。

import sys
import subprocess
import ctypes
import time
import pythoncom
import Pyfemap
from Pyfemap import constants

existObj = pythoncom.connect(Pyfemap.model.CLSID)
app = Pyfemap.model(existObj)

subprocess.Popen("notepad.exe")
time.sleep(2)
    
handle = ctypes.windll.user32.FindWindowW(0, "無題 - メモ帳")
app.feAppRegisterAddInPaneWithFrame(True, int(handle), int(handle), False, True, 4, 2)

Femapのウィンドウ内にメモアプリを表示しても無意味ですし、モデル情報ウィンドウの下方はスペースも狭いので、ここに埋め込んで有益なアプリは限られます。

しかし、自社開発のプログラムへの引き渡しのインタフェースや、ビューに表示されている解析結果を分析するようなアプリを埋め込むことは便利なカスタマイズと思います。

Pyfemap(Python版、FEMAPのAPI)でグループ毎のリナンバー

以下、サンプルです。

existObj = pythoncom.connect(Pyfemap.model.CLSID)
app = Pyfemap.model(existObj)
xyz = list()
xyz.append(6)
xyz.append(2)
xyz.append(4)

elemSET = app.feSet
gr = app.feGroup
gr.Get(1) #グループ番号1
rc = gr.GetList(constants.FGR_ELEM, elemSET.ID)
rc =  app.feRenumberOpt2(constants.FT_ELEM, elemSET.ID, 1001, 6, 0, False, False, False, xyz) # 1001を先頭にして要素番号をリナンバー
rc = app.feSetFree(elemSET.ID)

Pyfemap(Femap API)でNastranのf06を読込む

PythonからFemapのAPIに接続するパッケージ、PyFemapを使用して標準入力からf06ファイル名を受け取り、Femapのアウトプットセットに読込みます。
dirコマンドと組み合わせれば一度に大量の解析結果を読込むことができます。
アウトプットセットのタイトルはf06のファイル名としていますが、他の情報と組み合わせれば自由に設定できます。

# coding: utf—8

import pythoncom
import Pyfemap
from Pyfemap import constants
Import sys
import os

def main():
    existObj = pythoncom.connect(Pyfemap.model.CLSID)
    app = Pyfemap.model(existObj)

    OutSet = app.feOutputSet

    lines = sys.stdin.readlines()

    for f in lines:
        f = f.strip()
        OID = OutSet.NextEmptyID()
        absf = os.path.abspath(f)
        print(absf)
        rc = app.feAppMessage(0,'Python API MSC f06 Read Started ' + absf)
        rc = app feFiIeReadNastranResuIts(0,absf)
        OutSet.Get(OID)
        OutSet.title = os.path.basename(f)
        OutSet.Put(OID)

if __name__ == '__main__':
    main() 

PythonからFemapのAPIに接続する

以下のサイトがとても参考になります。

https://community.plm.automation.siemens.com/t5/CAE-Simulation-Knowledge-Base/Writing-the-FEMAP-API-in-Python/ta-p/378038

FemapのAPIインターフェース、femap.tlbに接続するために先ずpywin32が必要です。
これを使って、femap.tlbからPyfemap.pyを作成し、これをimportしてfemapに接続します。

実際の接続は以下のとおりです。

import pythoncom
import Pyfemap
import sys

existObj = pythoncom.connect(Pyfemap.model.CLSID)
app = Pyfemap.model(existObj)

rc = app.feAppMessage(0,"Python API Example Started")