- HOME
- S4コーディング入門(第1回)プロジェクトの生成コードとカスタマイズ方法
本記事は当社が発行しているシミュレーションメールマガジンVol. 14の記事です。
シミュレーションメールマガジンの詳細・購読申込はこちら
のサポートページから
- S4コーディング入門(第1回)プロジェクトの生成コードとカスタマイズ方法
- S4コーディング入門(第2回)S4シミュレーションモデルとpsimとの関係性を理解する
- S4コーディング入門(第3回)具体的なモデルでテクニックを紹介
はじめに
本連載「S4コーディング入門」は、S4のプロジェクトにおけるPythonコーディングのために役立つ情報についてお伝えすることを目的としています。S4プロジェクトを思い通りにカスタマイズする一助となれば幸いです。
セミナーやチュートリアルを通してS4に触れたり、S4を購入したあとのステップとして「S4プロジェクトを思い通りにカスタマイズする」があります。そして既存のプロジェクトをいじったり、0からプロジェクトを作成してアイコンを並べたり、設定の数字を変えたりしますが、S4の機能上それだけでは望んだモデルを実現できない場合があります。またコード編集を通して生成コードを直接編集することも検討しますが、Python自体の理解が無かったり、理解できていたとしてもS4の生成コードの構造や実行時の扱いについてはS4自体への理解が必要になります。本連載では「S4プロジェクトを思い通りにカスタマイズする」を目標として、様々なS4の知識やテクニックをお伝えする予定です。
今回は最初の記事として、主にプロジェクトの生成コードとモデル上の設定の関係について説明いたします。
※S4はPython言語で書かれ、生成コードもPythonで記述されますが、本連載はPython自体の入門書ではありません。Python自体の知識は入門程度で問題ありませんが、最初の記事からS4自体の知識を主に扱い、言語については必要に応じて補うのみとなります。
生成コードについて
S4プロジェクトを実行すると、その時点での生成コードがPythonスクリプトとして作成され、コンピューター上でS4とは異なるPythonプロセスとしてシミュレーションが実行されます。S4側ではプロセス間通信を用いてPythonプロセスと情報をやりとりし、標準出力、エラーや目的関数値といった情報を受け取ってS4側に表示します。
メニュー「モデル」→「コードを表示する」で表示できる生成コードにはユーザーがプロジェクトに対して行ったほぼすべての設定が反映されています。例えば配置したアイコン1つ1つが別々のクラスとして生成コード上で表現されます。生成コードは設定を行うたびに更新されるため、アイコンを配置してから生成コードのウィンドウを開き直すといま置いたアイコンに対応するコードが挿入されていることを確認できます。
「S4プロジェクトを思い通りにカスタマイズする」という目的に照らして考えると、プロジェクト設定の操作が生成コードにどのように反映されるかを把握することが肝要となります。シミュレーション自体の実装がほぼすべてユーザーに見えることはS4の隠れた特徴であり、Python言語の知識がそのままS4シミュレーションモデル構築に活かせます。
スコープ、特に param について
メニューの「モデル」→「パラメータを編集する」で開けるパラメータウィンドウの「パラメータ設定」タブでパラメータ x
を作成すると、後々 param.x
で値を参照できます。ユーザーがあるアイコンのテキスト設定欄で param.x
と書くと、それは生成コードに差し込まれます。
# シミュレーションパラメータの定義 class SimulationParam: def __init__(self, inputDir = u"input\\default", outputDir = u"output\\default"): self.x = next(constantValue(1.0)) #
パラメータ自体は生成コードの冒頭付近にて定義されるクラス SimulationParam
のインスタンス変数として定義されます。そして生成コードの下の方にあるシミュレーター Simulator
のインスタンス化箇所にてパラメータ引数 param = SimulationParam()
として渡されます。
if __name__ == "__main__": # 実行時の処理 simulator = Simulator(param = SimulationParam(), (略)
ユーザーが参照する param
はこの param
です。実はユーザーが設定するアイコンのコードはすべてこの初期化( __init__
)のスコープの下に置かれます。そのため、 param
でパラメータを参照できることになります。
# シミュレーターの定義 class Simulator (SimulatorBase): def __init__(self, param = SimulationParam(), (略) dataDir = u"data"): SimulatorBase.__init__(self, param, inputDir, outputDir, showGraph, start, warm, until, odesolver, dataDir) # 資源の定義 # 通過 の定義 class Pass (Widget): (略) # 動作の定義 def run(self): self.param # このselfはrunメソッドの第一引数になる。paramが無いという AttributeError になりがち。
また、 param
は Simulator.__init__
の冒頭で初期化 SimulatorBase.__init__
に渡されています。内部の処理により param
は Simulator
クラスのインスタンス変数になるため、実は self.param
でも参照できます。しかしながら、 self
は Simulator.__init__
の中で定義されるクラスが持つメソッドの第一引数として使われているため、そこで self.param
と書くと self
の意味が変わってしまいます。
※ 上記のコードは通過部品を置いて編集画面を開き、「コード編集」タブの冒頭で self.param と書いた場合の生成コードになります。
※ self
は頻出するため Python の予約語のように思われがちですが、実は単なる慣習であり他の名前も利用できます。それでも self
以外の名前を使うことは基本的に無いため、衝突の問題について考える必要が出てまいります。
以上のように、S4のアイコンの設定画面であっても、Pythonのスコープを意識することでテキスト欄に記述しうる内容について考えやすくなります。
他アイコン参照について
モデル上に置いたアイコンやリンクの設定は、基本的にすべて Simulator.__init__
メソッド内の文としてコード生成されます。チュートリアルの「銀行の窓口」プロジェクトを例にしますと、生成部品は Generate
クラスとして定義されています。 Generate
は Simulator.__init__
で定義されるローカル変数になります。また、生成部品のインスタンス化の文も Simulator.__init__
のより下の方にあります。
self.wGenerate = Generate(self)
この変数名 wGenerate
は生成部品のインスタンスが持つデフォルトのインスタンス変数名であり、実はユーザーが設定可能です。生成部品の編集画面の「共通設定」タブにある「オブジェクト名」がここに挿入されます。
self.wGenerate
は param
と同じ Simulator.__init__
直下にあります。従って param
と同様に参照が可能なのですが、 self.param
でも説明した通り、大抵のクラスが持つ第一引数 self
と衝突するため、素直に self.wGenerate
と書いても参照できません。この場合、以下で説明する parent
を経由して参照することができます。
# 通過 の定義 class Pass (Widget): """アイテムを無条件で通過させます。""" def __init__(self, parent): Widget.__init__(self, parent, u"通過", nthread = 1) (略) # オブジェクトの生成 self.wPass = Pass(self)
ほとんどのアイコンに対応するクラスは、 Simulator.__init__
でインスタンス化する際に self
を渡します。これはアイコンに対応するクラスの __init__
側では parent
という仮引数で受け取ります。従って、 __init__
内では parent.wGenerate
という形で parent
を通して生成部品を参照できます。通常、 __init__
冒頭の Widget.__init__
呼び出しの内部で parent
はインスタンス属性にもなります。そのため __init__
以外のメソッドでも self.parent.wGenerate
で生成部品を参照できます。
※parentはPythonでクラス間の関係性を表現する際によく使われるテクニックの一つです。例えばS4が利用しているGUIライブラリ wxPython でも同様の属性が用いられます。
この手法は分岐アイコンの条件部を記述する際に利用することが多いです。例えばサンプルプロジェクトの 離散-ミニマル\制限区間.s4 を見ると、「分岐」アイコンの条件部は以下のような形になっています。
self.parent.rFacilityInner1.sizeBuffer() < self.parent.rFacilityInner1.capacity
ファシリティは部品ではなく資源ですが、 Simulator.__init__
内で初期化されるインスタンス属性であることに変わりないため、 self.parent
経由で参照できます。
おわりに
「S4プロジェクトを思い通りにカスタマイズする」という目標を掲げ、初回は生成コードの見方や param
, parent
といった要素との関係について説明いたしました。今回の範囲で行えるカスタマイズはそれほど多くないかもしれませんが、実際にプロジェクトのカスタマイズを行うときは、このような個々の知識の総合としてなすべき作業が決まって参ります。そのため連載を積み重ねていくうちに、S4プロジェクトを改造する能力は少しづつ上昇していきますので、今後もお付き合いいただけますと幸いです。

http://www.msi.co.jp NTTデータ数理システムができること