外部コードへの接続
概要
FlexSimでは、内部のFlexScriptモデリング言語を使用するだけでなく、外部コードへの接続も可能です。外部のPythonコードやC/C++コードに接続できます。
コードエディタ
外部コードへの接続は、コードエディタを通じて行います。
ウィンドウの一番下には、外部(External)を表す ボタンがあります。コードノードを外部接続用に切り替えるには、このボタンを押します。このボタンを押すと、「外部コードへの接続には別のテキストフォーマットが必要」という内容のメッセージがダイアログに表示され、継続するかどうかを尋ねられます。
フォーマットの言語を選択し、[はい]または[いいえ]を押します。コードが変更され、外部接続用にフォーマットされます。
外部接続用にフォーマットされたコードは次の形式をとります。
<prefix> "<module_id>" "<function_id>"
このテキストの周囲にはグレーのマークアップコメントを配置できます。これにより、編集フィールドはテキストを読みやすい形で表示できます。マークアップは無視することも、削除することもできます。各種識別子とその意味は、接続先の言語によって異なります。詳細は以降の各セクションで説明します。
Pythonに接続する
Pythonに接続する場合、テキストは次のフォーマットをとる必要があります。
external python "<python_module_name>" "<python_function_name>"
接頭辞(最初の二重引用符の前のテキスト)は、マークアップやコロンなどの他のテキストで修飾できますが、external python
というテキストを含んでいる必要があります。
<python_module_name>
は、Pythonモジュール名、つまりPythonファイル名からファイル拡張子.pyを除いた名前にする必要があります。モジュール名として、現在アクティブなPython環境に含まれる標準のPythonモジュールを指定することも、モデルディレクトリまたはモデルのサブディレクトリに配置したPythonモジュールを指定することもできます。
<python_function_name>
には、Pythonモジュール内に定義されているグローバルにアクセス可能な関数の名前を指定する必要があります。
接続文字列を正しく定義すると、ノードが評価されるたびに、つまり、そのノードでtreenode.evaluate()が呼び出されるたびに、FlexSimは定義されたPython関数を呼び出します。これは、OnEntryまたはOnExitトリガーなどの標準ライブラリオブジェクトフィールド内で設定することも、ノードを独自に設定してFlexScriptから直接呼び出すこともできます。たとえば、Pythonに接続するユーザーコマンドを定義することも、この接続文字列を持つラベルノードを定義し、単に次の関数を呼び出すこともできます。
Variant decision = current.labels["PythonCode"].evaluate()
この関数にパラメータを渡し、戻り値を取得した後、FlexScriptロジックを続行することができます。
PythonでのFlexSim APIは最小限
FlexSimは、PythonからFlexSimのクラスとコマンドにアクセスするための強力なプログラミングAPIを提供していません。これは意図的なものです。Pythonからのアクセスを提供する目的は、本稼働システムで使用する予定のアルゴリズムをユーザーがPythonで実装できるようにすることです。そのため、FlexSimは、本稼働システムに展開する前に機能をしっかりとテストする仮想の試運転環境となります。つまり、PythonからFlexSim固有のコマンドとメソッドを呼び出すということは、PythonとFlexSimとの間で強力な結合要件が形成されることになり、Pythonを使用する目的を無に帰してしまいます。
FlexSimは、Pythonとの間に弱い結合が形成されるように設計されています。1つの統合機能が、FlexSimとPythonとの間のタイプ変換です。Pythonの関数がFlexSimから呼び出されると、FlexSimは渡されたパラメータをPythonのネイティブオブジェクトに変換します。MapはPythonのdictに、ArrayはPythonのlistに、stringはPythonのstringに、numberはPythonのfloatに変換されます。その後、Python関数からの戻り値は、FlexSimのネイティブタイプに変換されます。
PythonとFlexScriptのどちらを使用すべきか
Pythonに提供されているFlexSimプログラミングAPIは最小限なので、どの状況でどちらの言語を選択すべきかが重要です。選択の際には、次のガイドラインを参考にしてください。
FlexScriptを使用すべき状況:
- 大きなコードブロックを作成する - FlexScriptの未加工コードの実行速度はPythonとは桁違いに高速であり、Pythonのネイティブタイプとの間の単純な変換でも、計算量が多くなります。そのため、ルーピングのネストなどを含む多くのロジックを作成する場合、FlexScriptの使用をお勧めします。
- FlexSim APIに直接アクセスする - 前述のように、PythonはFlexScriptのクラスとコマンドへのアクセスを提供していません。そのため、これらへのアクセスが必要な場合は、FlexScriptを使用してください。
Pythonを使用すべき状況:
- 本稼働システムで使用する予定の機能を実装する - 後で工場やシステムに直接統合する機能を実装する場合、Pythonで実装することをお勧めします。
- 最適な判断をするためにPythonライブラリを使用する - たとえば、gurobiやcplexなどのソルバーを使用して、モデルで最適な判断をしたい場合があります。これは、一日の最適なスケジュールを見つけることかもしれませんし、サプライチェーンのシミュレーションで、どのサプライヤーからどの小売業者に注文資材をどれだけ出荷するかを判断することかもしれません。この目標は上記の最初の理由と重なります。つまり、本稼働システムで使用するのと同じ判断をシミュレーションで使用したいという理由です。この場合、Pythonを使用してこの機能を実装することをお勧めします。
- データ処理やデータ交換のためにPythonライブラリを使用する - たとえば、FlexSim内でサポートされていないフォーマット(HDF5、Parquetなど)との間でデータのエクスポートまたはインポートを行うために、pandasなどのライブラリを使用できます。
C/C++ DLLに接続する
FlexSimでは、コードフィールドを外部のC/C++ dllに接続することもできます。この方法には2つの長所があります。おそらく最も重要である第1の長所は、実行速度、サードパーティ機能への接続性、C++の標準テンプレートライブラリなど、C/C++をフル活用できる点です。第2の長所は、特定の知的財産の保護を希望する場合にコードを非表示にできる点です。
dllに接続する場合、接続テキストは次のフォーマットをとる必要があります。
"relative/path/to/mydll.dll" "function_id"
引用符で囲まれた2つのテキストの前後または間には、任意の文字列を挿入できます(つまり、Pythonのように、<prefix>
などの特定の文字列は不要です)。最初の引用符の中には、モデルを起点とするdllの相対パスを指定します。第2の引用符の中には、DLL内にある、グローバルにアクセス可能で名前修飾が行われていない関数の名前を指定します。この関数は、以下に説明するように、特定のシグネチャを持つ必要があります。
DLLを構築する
DLLを構築し、FlexSimと正しく接続できるようにするには、いくつかの段階が必要です。まず、DLL Maker Visual Studioプロジェクトをダウンロードします。このプロジェクトには、FlexSimのアカウントページのダウンロードセクションからアクセスできます。次に、プロジェクト内のC++ソースファイルに関数を追加します。関数の例は、DLL Makerプロジェクトに用意されています。
#include "FlexsimDefs.h"
visible double mydllfunction1(FLEXSIMINTERFACE)
{
pt("This will print to the Output Console");pr();
return 0;
}
まず、flexsimdefs.hをインクルードする必要があります。これは、特定のマクロを定義するだけでなく、FlexSimコマンドにアクセスできるようにそれらのコマンドを宣言します。宣言は、次の形式で行います。
visible double the_function_name(FLEXSIMINTERFACE)
関数を正しく宣言すると、FlexSimでトリガーなどのコードを作成するときと同様に、パラメータにアクセスし、コードを作成できます。渡されたパラメータにアクセスするには、parnode()やparval()などを使用します。
DLLを正しい場所に配置する
dllの配置先は非常に重要です。そのため、DLLを正しい場所に配置するようにVisual Studioプロジェクトを設定する必要があります。ここで、構築するdllを特定のモデルにのみ使用する場合のVisual Studioプロジェクトの設定方法を紹介します。
- 保存したモデルファイル(.fsm)と同じディレクトリにDLL Makerのフォルダを配置します。次にDLL Maker\DLL Maker.vcxprojをダブルクリックしてVisual Studioを開きます。
- 左側の[ソリューション エクスプローラー]にあるDLL Makerプロジェクト([ソリューション 'DLL Maker']ではなく、その下のプロジェクトアイコン)を右クリックし、[プロパティ]を選択します。
- 上部の[構成]ドロップダウンから[すべての構成]を選択します。
- 左側のツリーで、[構成プロパティ]>[リンカー]>[全般]に移動します。
- [出力ファイル]フィールドに../dllname.dllと入力します(「dllname.dll」の部分は、任意のdll名を指定します)。[OK]をクリックします。
これで、プロジェクトは、dllをモデルディレクトリに配置します。そのため、FlexSimでdllのパスを設定するとき、「dllname.dll」と指定すればよいことになります。なぜなら、このファイルはすでにモデルと同じディレクトリにあるためです。
dll側で関数を定義し、dllを構築して正しい場所に配置すると、以前設定したコードノードはそのdllに正しく接続します。
FlexSimを開いたままDLLを再構築する
FlexSimをDLLに接続した後で、DLLを再構築したい場合があります。これらのdllからFlexSimを明示的に切断しない場合、dllファイルへの書き込みができないことを示す構築エラーがVisual Studioで表示されます。切断するには、FlexSimのメニューで、[ファイル]|[システム]|[DLLの接続を解除]の順に選択します。dllに接続する描画コードがある場合、まずすべての正投影/透視ウィンドウを最小化し、その後で[ファイル]|[システム]|[DLLの接続を解除]を選択してください。