DEXCSランチャー v2.5 製作メモ / ランチャーツールボタン



課題の背景

先の記事でDEXCSランチャーのツールボタンにおいて、解析ケース(出力先)を整合させる事が出来たので、ユーザー目線での問題は解決できた。しかし、次期DEXCS2021においてFreeCADのバージョン選定に際して、従来通り、FreeCAD-daily版を使用していくのであれば、このままでも使えそうだが、daily版は安定性に不安があり、なおかつFEMモジュールにおいて、Netgenメッシャーが使えないという問題がある。可能であれば、AppImage版を使いたいのだが、そうするとDEXCSツールボタンのうち、TreeFoamのサブプログラムを使用するボタンが機能しなくなってしまう。

今回、CfdOFをdexcsCfdFとして改変作業を実施した事によって、CfdOFのコードの中から、別プロセスを起動する方法を学ぶことができた。これを参考にすれば、上述の問題(AppImage版で動作しない)が解決できる可能性があったので、挑戦してみることとした。因みに、CfdOFは、AppImage版だけでなく、Windows版、Mac版でも動作することを前提としたプログラムになっている点を追記しておく(動作は確認していないが)。

着想

別プロセスを起動する方法は、CfdOFにおいても、DEXCSツールボタン(あるいはTreeFoam)においても、状況に応じた起動スクリプトをカレントディレクトリ内に作成し、そのスクリプトを起動するプロセスを立ち上げているのは変わりない。スクリプトの内容も取り立てて違いがあるわけでもなかった。違いはプロセスを起動する方法であった。

DEXCSツールボタン(あるいはTreeFoam)では、python で一般に使われる、os.system()なり、subprocess.run()を使っていた。一方、CfdOFでは、QProcessを使っていたという違いであった。

方策1

editConstantFolder.py を例にあげて説明する。以下の緑字部分を、朱字部に変更した。

f=open("./run","w")
f.write(cont)
f.close()
#実行権付与
os.system("chmod a+x run")
#実行
#comm = "xfce4-terminal --execute bash ./run"
#comm= "gnome-terminal --geometry=80x15 --zoom=0.9 -- bash --rcfile ./run"
#os.system(comm.encode("utf-8"))
cmd = dexcsCfdTools.makeRunCommand('./run', modelDir, source_env=False)
env = QtCore.QProcessEnvironment.systemEnvironment()
dexcsCfdTools.removeAppimageEnvironment(env)
process = QtCore.QProcess()
process.setProcessEnvironment(env)
process.start(cmd[0], cmd[1:])

このコード中のポイントは2点、朱字部最下行で、「着想」にて記したprocess(Qprocess)を実行している点と、朱字部3行目dexcsCfdTools.removeAppimageEnvironment(env)の、文字通りAppimage環境を除去している関数を使っているという点である。FreeCADのAppImage版でなければ、この行が無くとも実行されるが、AppImage版でこの行が無いと実行されない。また、この行だけ機能するようにしたとして、従来の緑字部分の起動方法を使っても実行してくれない。

このコードだけから読み取れるポイントは2つあったが、これ以外にもう1点ポイントがある。editConstantFolder.py を例にあげて説明したが、editSystemFolder.pyにおいても、プログラムの内容はほとんど同じで、 runの内容で、/constant を対象にするか、/systemを対象にするかの違いでしかなかった。したがって、上記と全く同じ変更にて実行できるものと思われた。しかし、、、動かないのであった。

対象フォルダの違いだけかと思っていたが、実はプログラム全体の構造にも若干の違いがあった。結論からいうと、defブロックの有無であった。editSystemFolder.pyは、defブロックを有しない、ベタのプログラムであった。最終的に、プログラムの最終行に、以下のダミーのdefブロックを追加すれば動くことを確認した。editSystemFolder.py以外のマクロで、defブロックの無いものは、同様の変更が必要であった。

def dummyFunction(): # 何故かこれがないとうまく動かない      
    pass

余談になるが、最初にeditConstantFolder.pyの改造に取り組んだことがラッキーであった。editSystemFolder.pyを先に取り組んでいたとしたら、この解決法(ダミーのdefブロック追加)は有りえなかっただろう。逆に言えば他の解決法はあるのかもしれないが、お手上げになっていた可能性大であった。

他にも、ifブロックのネスト深さの違いもあったが、これは関係無かった。

方策2

方策1によって、DEXCSツールボタンのrunSolver.py以外の全てが機能する(ボタンを押せば所定の画面が現れる)ようにはなった。

ただ、runSolver.pyも、従来のように、端末画面が現れて、計算ログが表示されることはないのであるが、計算そのものは実行してくれている。また、そもそもDEXCSワークベンチで実行すれば良いので、これは無くす方向で考えているので、当面問題無いこととした。

問題は、runTreeFoam.pyとrunGridEditor.pyであり、根は同じ現象に至った。初期画面は現れるのであるが、肝心なGridEditor画面が表示されないのであった。runGridEditor.pyでは、TreeFoamモジュールのopenGridEditorDialog.pyが起動され、以下の画面が立ち上がる。

ここで、「開く」ボタンを押せば、おなじみの表形式画面が現れるはずなのだが、これがあがってこないということである。TreeFoamも同じで、TreeFoam本体は立ち上がるが、GridEditorを起動できない(他のボタンは問題無さそうであったが)。これを解決するには、TreeFoam本体の改造が必要になった。「開く」ボタンを押した時に実行されていたのは、

        pyTreeFoam.run(caseDir).command(comm)

であり、pyTreeFoam.py中の関数が使用されている。この実体は、

    def command(self, comm):
        """ commandを実行する。"""
        os.chdir(self.caseDir)
        dummy_proc = subprocess.run(comm, shell=True) 

という簡単なものであったが、この内容が問題であった。方策1で問題になったのと類似で、こちらはsubprocess.run にてプロセスを実行していた。

したがって、方策1と同様の対策によって解決するのではないかと思って対処したところ、GridEditorの表形式画面が現れるようになった。

めでたし、めでたし、となるはずであったが、、、

方策3

今度は、editConstantFolder.pyや、editSystemFolder.pyの挙動がおかしくなった。起動画面は問題無かったが、実際にエディタ画面が表示された段階にて、中味が真っ白な画面になってしまった。

これも調べると、上述のpyTreeFoam.py 中の同じ関数を経由してエディターを起動している事がわかった。この関数を変更した結果が、こちらには災いしたということであった。

諸々試行錯誤の末、今の所下記変更にて、問題は生じていないようである。

    def command(self, comm):
        """ commandを実行する。"""
        os.chdir(self.caseDir)
        #print('comm = ',comm)
        if comm[0] == '.':
            from PyQt5 import QtCore
            process = QtCore.QProcess()
            working_dir = self.caseDir
            if working_dir:
                process.setWorkingDirectory(working_dir)
            qcomm = 'bash -c ' + '"' + comm + '"'
            ret = process.startDetached(qcomm)
        else:
            dummy_proc = subprocess.run(comm, shell=True) 

つまり、スクリプトを作成して実行するタイプのもの(というか、環境変数を変更して実行するもの)は、Qprocessを使って起動する必要がありそうで、そうでないもの(エディターを起動するなど)は、subprocess.run で問題なく動きそうだということと、かつスクリプトで動くものは、最初に「.」という環境変数組み込みが記述されているという前提での処置である。逆に言うと、スクリプトの内容で、最初に「.」以外の文字があると、AppImage版では動かない可能性があることになる。

DEXCSランチャーから起動するTreeFoamのサブモジュール(プログラム)については、GridEditorの表形式画面が出る前に一瞬ダイヤログ画面が現れてすぐ消滅するという問題以外は、今の所、致命的問題が表出していないが、TreeFoamトータルの観点から問題があるかもしれない。このあたり、

  • 上記改造をDEXCS版固有で適用していくしかないのか
  • 上記改造をTreeFoam本体に適用する可能性
  • 他にもう少し手は無いか

など、TreeFoamの作者さんに問い合わせてみることとしたい。

方策4

方策3について、TreeFoam作者さんにも動作検証してもらったところ、FreeCADのランチャーボタンから起動したTreeFoamを使うと、いくつか問題が生じる事が判明した。

1.並列処理のdecomposeParによるメッシュ分割が機能しない。(分割できない。)
2.メッシュ作成時の特徴線(featureEdge)が抽出できない。

などである。特に1.については、FreeCADのランチャーボタンから起動した並列処理画面においても同様であった。

一方、FreeCAD-Daily版であるが、最新版は ver-0.20となっており、

起動オプションのカスタマイズが柔軟になった。すなわち、これまでDEXCSツールバーのダウングレードアイコンを使えるようにするには、一旦、ドラフトワークベンチを表示させる必要があった。今回のDEXCSワークベンチにおいてもスタート画面をDEXCSワークベンチにしておくとDEXCSツールバーのダウングレードアイコンが表示されないのは同様であったが、FreeCAD-Daily の新板を使うとこの問題が解消された。DEXCSランチャーボタンの挙動も問題無い。さらに、FEMワークベンチにおいて、様々な境界条件設定ツールが追加されていたという発見もあった。

一方で、今回のDEXCS2021においては、OpenFOAMのバイナリインストールや、Helyx-OSの搭載中止によって、isoイメージのサイズに余裕が出来ており、FreeCADについてDaily版とAppImage版の両方を収納する事も可能であることを確認できた。

また、CfdOFのソース中には、FreeCADがAppImage版であるかどうかを判定するコードがあったので、これを活用すれば、上述の問題に対する場合分けも可能となる。そこで、最終的に、以下の方針であたることとした。つまり、

DEXCS2021の標準では最新Daily版(ver-0.20)を使う設定とし、ニッチユーザー向けにAppImage(ver-0.19)に切り替えられるようにする。AppImageで使う場合には、DEXCSツールバーから、TreeFoamのボタンと、並列ボタンを押した場合に、正常に動作しない旨の警告を出すようにする、というものである。なお、念の為に記しておくが、FreeCADはDaily版を使おうが、AppImage版を使おうが、FreeCADのマクロやワークベンチ(一式がホームディレクトリ下の.FreeCAD中に収納される)は同じものを使うことになる。

具体的に、AppImage版からTreeFoamの起動ボタンを押すと、以下の警告メッセージが表示され、Daily版ではこのメッセージが現れないるようにした。

因みにこのメッセージは、以下のようにしてAppImage版かどうかの判定をした結果次第で表示されることになる。

env = QtCore.QProcessEnvironment.systemEnvironment()

if env.contains("APPIMAGE"):
    message = (_("this FreeCAD is AppImage version.\n  some function of TreeFoam doesen't work.\n if you want utilize the function, use normal TreeFoam clicked by dock-launcher button.")) 
    ans = QtGui.QMessageBox.critical(None, _("AppImage Warning"), message, QtGui.QMessageBox.Yes)
    dexcsCfdTools.removeAppimageEnvironment(env)

また、FreeCADをDaily版/AppImage版 切り替える方法は、それぞれの起動コマンドを、

/usr/bin/freecad-daily -> /etc/alternatives/freecad-daily
/usr/bin/freecad-AppImage -> /opt/freecad

として、/usr/bin フォルダ下に収納しておく。FreeCADの起動コマンドを、freecad として以下がデフォルトの状態。

/usr/bin/freecad -> /bin/freecad-daily

AppImage版に切り替えたい時は、

$ sudo rm /usr/bin/freecad
$ sudo ln -s /usr/bin/freecad-AppImage /usr/bin/freecad

として使ってもらおうというものである。少々面倒だが、どうしてもAppImage版を使いたい人というのは、ある程度オープンCAEを使い慣れた人に特化されるであろうので我慢してもらうことにする。

前へ 目次

DEXCSランチャー v2.5 製作メモ / 解析・雛形ケースの設定



課題の背景

これまでFreeCADモデルの存在するディレクトリが解析ケースフォルダであるとして様々なツールを作成・動作確認してきた。また最初にFreeCADモデルの存在するディレクトリがケースファイルでない場合には、DEXCSの標準チュートリアル問題の設定ファイル(/opt/DEXCS/template/dexcs)を雛形ファイルとしてケースファイルを作成していた。

最終的に、解析ケースフォルダと、雛形ケースファイルは任意に変更できるようにしたいと考えるのが普通であろう。従来のDEXCSマクロにおいては、解析ケースフォルダを変更する機能は有していたが、雛形ケースファイルを選択変更する機能はなかったので、特定のケースファイル内へ出力するという使い方で対処してきており、実質的な使い方の上で大きな違いはないが、内部仕様を知らない人から見た上での解り易さが大きく違うので、ここでは雛形ケースファイルを変更する機能も実装したい。

少し余談になるが、この雛形ケースファイルを変更するメニューが出来たとして、将来的な拡張機能として、TreeFoamの「newCaseの作成」メニュー援用して、ここで選んだケースを採用する方法が考えられるが、一通りの機能が実装できた後の課題としたい。

現状確認

コンボビューにおいて、解析コンテナ(dexcsCfdAnalysis)を選択すると、プロパティ欄に[Output Path]が表示されている。

この表示テキスト欄右端のボタンを押すと、フォルダ選択ダイヤログが現れて、任意のフォルダを選択できる。この選択は有効で、以下メッシュ作成〜ソルバー実行は指定したフォルダで実行してくれる事は確認できている。但し、このワークベンチ上での操作に限定されるもので、DEXCSツールボタンによる操作には反映されす、エラーになってしまう(のは現段階では仕方無い)。

一方、「編集」⇒「設定」画面において[CfdOF]を選択すると、以下の設定画面が現れる。

ここに、[Default output directory]とあり、これも同様に変更することができるようになっている。しかしながら、ここで変更したとしても、先のプロパティには反映されない。

以上の状況から、課題は以下のように整理される。

  1. 雛形ケースファイルを変更する方法を実装する必要がある。これには、Output directory に関する上記2つの設定欄に併記される形で、Template Case を変更できるようにしておくのが普通であろう。
  2. 解析コンテナのプロパティ欄で設定した値と、「設定画面」で設定したこれらの値を連動させる仕組みが必要。
  3. DEXCSツールボタンで、Output directory のプロパティを認識させる方法が必要。
  4. 「設定画面」をCfdOF オリジナルから、dexcsCfdOF に変更したい。機能面で本質的な問題ではないが。

以下、上述の順とは不同であるが、改造点を記しておく。

設定画面(initGui.py ⇒dexcsCfdPreferencePage.py)

initGui.py において、

from dexcsCfdPreferencePage import dexcsCfdPreferencePage
ICONS_PATH = os.path.join(dexcsCfdTools.get_module_path(), "Gui", "Resources", "icons")
QtCore.QDir.addSearchPath("icons", ICONS_PATH)
FreeCADGui.addPreferencePage(dexcsCfdPreferencePage, "dexcsCfdOF")

アイコンは、Gui/Resources/iconsフォルダ中に収納されて、CfdOFのオリジナルアイコン(preference-cfdof.png)そのものを変更するのは躊躇われたので、新たにpreference-dexcscfdof.pngを用意して収納した。

dexcsCfdPreferencePage.py においては、Template Case を変更できるようにしたいが、デフォルトはDEXCS標準チュートリアル(/opt/DEXCS/template/dexcs)としたいので、最初にグローバルパラメタとして、

DEXCS_TEMPLATE = "/opt/DEXCS/template/dexcs"

定義しておく。以下、OutputDirectoryについて記述している箇所を見つけて、その下にTemplateCaseについて同様に追加しただけである。

(103行目あたり)
self.form.tb_choose_output_dir.clicked.connect(self.chooseOutputDir)
self.form.le_output_dir.textChanged.connect(self.outputDirChanged)
self.form.tb_choose_template_case.clicked.connect(self.chooseTemplateCase)
self.form.le_template_case.setText(DEXCS_TEMPLATE)
self.form.le_template_case.textChanged.connect(self.templateCaseChanged)
(209行目あたり)
def outputDirChanged(self, text):
    self.output_dir = text

def templateCaseChanged(self, text):
    self.template_case = text

以上の変更によって、改変された設定画面を以下に示す。

なお、画面データ(dexcsCfdPreferencePage.ui)は、QtDesignerを使って、オリジナルデータ(CfdReferencePage.ui)を改変したものである。その際に、HISAなるSoftwareに関する設定項目があり、dexcsCfdOfでは使用することがないので、削除を試みたが、FreeCADの起動時にエラー表示で立ち上がらなくなってしまう。その原因解明は当面ペンディングして先へ進めることとした。

解析コンテナにおけるプロパティ追加(dexcsCfdAnalysis.py)

こちらもOutput…について記述されている箇所に続けて、Templateに係る記述に変更しただけである(朱字部)。

(54行目あたり)
model = FreeCAD.ActiveDocument.FileName
#print(model)
modelDir = os.path.dirname(model)
templateCase = "/opt/DEXCS/template/dexcs"
addObjectProperty(obj, "OutputPath", modelDir, "App::PropertyPath", "",
                  "Path to which cases are written (blank to use system default)")
addObjectProperty(obj, "TemplateCase", templateCase, "App::PropertyPath", "",
                  "Path to Template case Dir (blank to use system default)")

なお、この時点では、先の「設定」画面で設定した値との連動までは考えていない。とりあえずこの画面で変更したパラメタを使って、メッシュ作成や解析実行が、所定の動作するかどうか確認していく。

また、OutputDirectoryに関するパラメタの用語は、必ずしも統一されていない(Pathが使われていたり、小文字で始まっていたりする)が、当面、これはこれで合わせておく必要はある。

解析ケースの作成

解析ケースはメッシュ作成タスク画面(_dexcsTaskPanelCfdMsh.py)で[Write]ボタンを押すと作成される。

#cart_mesh = self.cart_mesh
self.analysis = dexcsCfdTools.getParentAnalysisObject(self.mesh_obj)
output_path = dexcsCfdTools.getOutputPath(self.analysis) + os.path.sep
template_case = dexcsCfdTools.getTemplateCase(self.analysis)
try:
    QApplication.setOverrideCursor(Qt.WaitCursor)
    FreeCADGui.doCommand("dexcsCfMesh = dexcsCfMeshTools.MainControl()")
    #FreeCADGui.doCommand("dexcsCfMesh.perform("+ "'" + cart_mesh.meshCaseDir + "'" + ")")
    FreeCADGui.doCommand("dexcsCfMesh.perform("+ "'" + output_path + "', '" + template_case + "'" + ")")       

緑字でコメントアウトした部分を、朱字に変更した。ポイントは、dexcsCfMesh(オリジナルのDEXCSマクロを改造したもの)のperform()関数にてケースファイルを作成しているのであるが、これまで出力先(output_path)だけを指定していたのに対し、併せてtemplate_caseも引数に加えたという点。そして、解析コンテナにて指定したプロパティ値の取得方法である。

解析の出力先(output_case)を取得するのに、オリジナルでは、cart_mesh.meshCaseDir という形で、別途定義してある関数を使用していた。これに合わせてtemplate_caseを取得する関数を作成する事も考えられたが、その方法がよく分からなかった。そこで試行錯誤の末、ここに記した方法に辿り着いた。

解析コンテナ上のtemplate_caseを取得するのに、dexcsCfdTools.getTemplateCase(self.analysis)を使っているが、output_path を取得するdexcsCfdTools.getOutputPath(self.analysis)に倣って、dexcsCfdTools.py 中の、def getDefaultOutputPath():と、def getOutputPath(analysis):ブロックの下に、変数名が異なるだけで全く同じ手続のdef getDefaultTemplateCase(): と、def getTemplateCase(analysis):を追加した。

(75行目あたり)
DEXCS_TEMPLATE = "/opt/DEXCS/template"

def getDefaultOutputPath():
    prefs = getPreferencesLocation()
    output_path = FreeCAD.ParamGet(prefs).GetString("DefaultOutputPath", "")
    #print('output_path = ' + output_path)
    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

def getDefaultTemplateCase():
    prefs = getPreferencesLocation()
    template_case = FreeCAD.ParamGet(prefs).GetString("DefaultTemplateCase", "")
    #print('template_case = ' + template_case)
    if not template_case:
        #template_case = tempfile.gettempdir()
        template_case = DEXCS_TEMPLATE
    template_case = os.path.normpath(template_case)
    return template_case

def getOutputPath(analysis):
    if analysis and 'OutputPath' in analysis.PropertiesList:
        output_path = analysis.OutputPath
    else:
        output_path = ""
    if not output_path:
        output_path = getDefaultOutputPath()
    output_path = os.path.normpath(output_path)
    return output_path

def getTemplateCase(analysis):
    if analysis and 'TemplateCase' in analysis.PropertiesList:
        template_case = analysis.TemplateCase
    else:
        template_case = ""
    if not template_case:
        template_case = getDefaultTemplateCase()
    template_case = os.path.normpath(template_case)
    return template_case

この変更に伴って、dexcsCfMesh(オリジナルのDEXCSマクロを改造したもの)のperform()関数の変更が必要になるが、変更はわずかで、以下朱字部を追加するだけであった。

(1601行目あたり)
def perform(self, CaseFilePath, TemplateCase):
(1648行目あたり)        
if TemplateCase:
    templateSolver =  TemplateCase
else:   
    templateSolver = self.SOLVER_PATH_TEMPLATE

以上で、解析コンテナのプロパティ値にて、解析ケース(出力先)、雛形ケースファイルを任意に設定できるようになり、メッシュ作成、解析実行できることを確認した。あとは、

  1. プレファレンスの設定画面での設定値と上記プロパティ値を連動させる
  2. DEXCSランチャーのツールボタンの動作を整合させる

プレファレンス設定画面再考

プレファレンスの設定画面での設定値と解析コンテナのプロパティ値が連動していない点が問題ではあったが、ユースケースを考えると、単に連動すれば良いというものでもなさそうだ。つまり、プレファレンスの設定画面は常時利用するものではないということである。解析コンテナで出力フォルダを変更したからといって、それが恒久的な設定になってしまうのも考えものである。そこで、解析フォルダと雛形ケースファイル(フォルダ)については、使用方法とし、以下の考え方を基本にするとした。

解析コンテナを新規作成した場合にプレファレンスの設定画面で設定したものをデフォルトとし、その設定を引き継ぐ。その後解析コンテナにて変更することは可能だが、変更したからといってプレファレンスまでは変更しない(一方向の連動のみ)。

プレファレンス設定の初期値は、user.cfg に記載されているものを使用するが、解析ケースについては、実在するディレクトリの場合にのみそれを採用する。そうでない場合には、[model_dir]が採用され、モデルの存在するディレクトリである事を示すようにする(下図参照)。

これを実現するのに、これまでオリジナルのCfdOFでは解析フォルダは特定のフォルダを使用する事を想定していた為、本改造では暫定的にInitGui.py def __init__(self) において、

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

として、user.cfg の値に依らないで、ここでデータをクリアしていたが、この部分を元に戻した。また、プレファレンス設定画面の表示には、

(156行目あたり)
self.output_dir = dexcsCfdTools.getDefaultOutputPath()

が使われるので、

def getDefaultOutputPath():
    prefs = getPreferencesLocation()
    output_path = FreeCAD.ParamGet(prefs).GetString("DefaultOutputPath", "")
    if not output_path:
        output_path = 'model_dir'
    output_path = os.path.normpath(output_path)
    return output_path

とし、さらに解析コンテナがロードされた際に設定される出力フォルダ名を、以下のように

    def initProperties(self, obj):
        model = FreeCAD.ActiveDocument.FileName
        prefs = dexcsCfdTools.getPreferencesLocation()
        model_Dir = FreeCAD.ParamGet(prefs).GetString("DefaultOutputPath", "")
        if os.path.exists(model_Dir):
            modelDir = model_Dir
        else:
            modelDir = os.path.dirname(model)
        templateCase = FreeCAD.ParamGet(prefs).GetString("DefaultTemplateCase", "")

プレファレンス設定画面(user.cfgに記載)の表示にて指定したディレクトリが、実在するかどうかの判定をして、実在する場合にのみ採用するようにした。

DEXCSランチャーツールボタン

解析ケース(出力先)をモデルが収納されたディレクトリ以外に設定した場合に、DEXCSランチャーのツールボタンが起動しないのは、この時点ではそういう仕様であるので仕方ない。DEXCSランチャーでは、モデルが収納されたディレクトリに、.CaseFileDictを収納して、ここに出力先を記すようにしており、この時点で、このファイルが存在しないからということである。

そこで、メッシュ作成タスク画面(_dexcsTaskPanelCfdMsh.py)で[Write]ボタンを押した時に、出力先が確定した後で、以下の朱字部分を追加して、.CaseFileDict を作成するようにした。

output_path = dexcsCfdTools.getOutputPath(self.analysis) + os.path.sep

if output_path[-1] == os.path.sep:
    output_path1 = output_path[:-1] 
else:
    output_path1 = output_path
dictName = os.path.dirname(FreeCAD.ActiveDocument.FileName)  + "/.CaseFileDict"
writeDict = open(dictName , 'w')
writeDict.writelines(output_path1)
writeDict.close()

なお、出力先パス名の最後の文字がos.path.sep(パス分離記号)の場合、それを含まないようにしているのは、これが残っていると、TreeFoamが起動しなくなってしまう為であった(その他のランチャーボタンは、あってもなくても正常に起動する)。

旧版DEXCSマクロ

DEXCS2021では、旧版のDEXCSマクロも混在させた状態でリリースすることを考えているが、それとDEXCSツールバーボタンの動作を確認した。

DEXCSワークベンチによる解析コンテナを使用しない状態であれば、基本的に旧版での操作方法の通りで動作する。基本的にと記したのは、plotWatcherと、ポスト処理においてPlotモジュールが起動されるようになった点である。特にplotWatcher機能は、このボタンで使用する限り自動更新されない点は、今の所仕方無いとしておく。

一方、DEXCSワークベンチによる解析コンテナを作成した状態において、旧版DEXCSマクロを起動すると、エラーで起動できない。エラーの内容は、解析コンテナがShapeオブジェクトを有していないというものであったので、ここは、以下のように、朱字部で例外処理させることで回避できた。

            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

これにより、解析コンテナを非表示状態にしてマクロを立ち上げれば、旧版DEXCSマクロの挙動は全く同一のものになる。解析コンテナを表示状態のままマクロを立ち上げると、解析コンテナも含めてマクロ画面にリストアップされることになり、そのまま無理やりエクスポートすると、解析コンテナからastファイルが作れないとなって立ち行かなくなる。これはそういう仕様なので仕方無い。

何はともあれ、解析・雛形ケースを任意に設定可能となり、旧版DEXCSマクロや、DEXCSランチャーボタンでの動作とも整合するようにはなった(と思う)。

前へ 目次

DEXCSランチャー v2.5 製作メモ / 日本語化

タスク画面の原版と日本語化版を、以下に対比して表示した。



日本語化方法

FreeCADの拡張モジュールを多言語化する方法があるだろう事は、CfdOFの元本ソースInitGui.py中(71行目)に、

        # enable QtCore translation here, todo

なるコメント行があり、ここで何らかの方法を組み込む仕組みがありそうな点は推察できているが、現時点では不明であったので、当面従来のDEXCSランチャーで実施している方法に倣って実施した。

とはいうもの、従来の方法は、pythonでは一般的な方法と考えられているgettextを使う方法で、これはソース中の変換したいテキスト部分(通常はダブルクオーテーションによって括られている)を、_(“text”) といった形で括っておくもので、この部分が変換対象になって、変換辞書に一致したテキストが見つかれば、そのテキストに対応した訳語に変換してくれるというものであった。しかるにCfdOFにおけるタスク画面は、QtDesignerによって作成された .ui ファイルをインポートする形のpythonプログラムにて作成されており、画面中に表示される名前は全て.uiファイル中に定義されている。そしてこの.uiファイル中での定義方法は、

    <string>Edit</string>

となっており、テキストそのものがダブルクオーテーションによって括られていないという事がわかった。従って、この部分を_()で括ったところで、表示が_(Edit) に変更されることにしかならない。

QtDesignerによって作成された .ui ファイルをインポートするでなく、pythonプログラムに変換する方法(ネット検索ではこの方法が上位でヒットする)であればこういうことにはならない(別途作成中の、Plotメニューでも確認済み)であるので、タスク画面作成プログラムそのものも、.ui ファイルをインポートするでなく、変換方式に変更する事も考えられなくもなかったが、単純な作業にはなりそうにないので躊躇われた。

そこで、以下の方法を考えた。つまり、いずれのタスク画面も、def __init__() ブロックにおいて、.uiファイルをインポートしたその直後において、タスク画面を、self.form = … という呼び出しで作成しているので、その直後に変換したいテキストラベルやボタンの名前を、再度、

     self.form.label.setText(_("Text"))

という形で書き換えてしまおうというものである。具体的に、メッシュ作成タスク画面作成プログラム(_dexcsTaskPanelCfdMesh.py)における変更(追加)コードを以下に示しておく。

まず、冒頭、

import sys
import gettext

localedir = os.path.expanduser("~") + "/.FreeCAD/Mod/dexcsCfMesh/locale"
if sys.version_info.major == 3:
	gettext.install("dexcsCfMeshSetting", localedir)
else:
	gettext.install("dexcsCfMeshSetting", localedir, unicode=True)

として、gettext処理(訳語変換)プログラムを実行。辞書ファイルが、FreeCAD/Mod/dexcsCfMesh/localeにあるという前提である。使用環境のpythonのバージョンに応じて呼び出し方法を変えている。

def __init__() ブロックにおいては、set.form = … の後、以下のように青字部分を追加している。

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

self.form.setWindowTitle(_("dexcsCFD Mesh"))
self.form.pb_write_mesh.setText(_("Write mesh case<"))
self.form.l_featureAngle.setText(_("Feature Angle(deg)"))
self.form.pb_stop_mesh.setText(_("Stop"))
self.form.l_scaleToMeter.setText(_("Scale to Meter:"))
self.form.pb_edit_mesh.setText(_("Edit"))
self.form.pb_run_mesh.setText(_("Run mesher"))
self.form.label_3.setText(_("Mesh verification<"))
self.form.label_5.setText(_("Mesher<"))
self.form.label_6.setText(_("Mesh<"))
self.form.pb_checkmesh.setText(_("CheckMesh"))
self.form.label.setText(_("Mesh Parameters<"))
self.form.check_optimiseLayer.setText(_("optimiseLayer"))
self.form.label_maxNumIterations.setText(_("maxNumIterations"))
self.form.label_maxAllowedThickness.setText(_("maximum allowed thickness:"))
self.form.label_featureSizeFactor.setText(_("featureSizeFactor"))
self.form.label_reCalculateNormals.setText(_("reCalculateNormals"))
self.form.label_nSmoothNormals.setText(_("Number of iterations:"))
self.form.check_keepCells.setText(_("keepCellsIntersectingBoundary"))
self.form.l_max.setText(_("Base element size:"))
#self.form.cb_workflowControls.setText(_("workflowControls"))
self.form.label_2.setText(_("Status"))

なお、ダブルクオーテーションで括られたテキスト名は、dexcsTaskPanelCfdMesh.ui 中,<string>…</string>で括られた該当箇所のテキスト名をカット&ペーストで転記したものであり、老眼一歩手前のマウス操作の手違いで、余分な箇所(<)まで転記されたものが何箇所か残っていた。本記事冒頭に掲載した英語版画面イメージにおいて、一部表記に不具合があるのはこの為である。訳語を作成する段階において気付いていたのだが、とりあえず動作確認を優先してそのまま進めた(もちろん今後手直し予定)。

また、下から2行目はコメントアウトしないとエラーになった為、これもとりあえず全体的な動作確認を優先しコメントアウトしたもので、この部分も今後手直し予定である。

また、日本語訳語において、一部原文のまま表記している箇所がいくつか存在する。これは闇雲に日本語化すれば良いというものでない。たとえば、Paraviewをパラビューとしても却って分かり難くなってしまう。また、cfMeshの設定パラメタの名前そのものである。設定ファイル(meshDict)中の名前と違う表記にしてしまうと、meshDict中の何処に相当する箇所のパラメタなのかわからなくなってしまう。

とはいうもの、現時点での表示で、境界線が曖昧である点も否めない。日本語化して分かり難くなる可能性のある語句は重複表記の方が良いかもしれないが、画面サイズ上の問題があるので、ToolsTipsで補完するのが良いかもしれない。

注意事項

英語表記と日本語表記の切り替えは、OSの設定言語に依存して自動的に切り替わる。FreeCAD本体には、OSの設定言語には依らず、独自に言語を設定できる仕組みが存在する(「編集」⇒「設定」⇒設定メニュー:言語を変更)が、これを使ってFreeCAD本体の表示言語を変更しても、ここで設定した言語表記には反映されないという点はお断りしておく。

前へ 目次