上述の FMI_BouncingBall.ipynb では、BouncingBallモデルの入力信号である反発係数 e をPythonの関数で作成しました。 この反発係数を出力する部分をMSLに含まれる Modelica.Blocks.Sources.Step でモデル化し、FMUを作成します。
FMI1.0 for Co-Simulationの簡単な例として、この反発係数を出力するモデル(model1)とBouncingBallモデル(model2)の2つのサブシステムモデルがデータ交換を行うCo-SimulationモデルをPythonスクリプトで構成します。
JModelica.org で生成できる FMU はスタンドアロン型と呼ばれ、FMUの中にサブシステムモデルとソルバーが含まれています。FMI1.0 for Co-Simulation のサブシステムには次のような状態があります。
Pythonスクリプトで、load_fmu でサブシステムモデルをインスタンス化し、モデルの状態を遷移させる関数(model.initialize, model.do_step など)やデータ交換関数(model.get, model.set など)を使用して Co-Simulationプロセスを実現します。
BouncingBall モデルのソースコードを作成します。入力信号は反発係数e、出力信号は高さy=hです。
%%writefile BouncingBall.mo
model BouncingBall
import SI = Modelica.SIunits;
Modelica.Blocks.Interfaces.RealInput e(start=0.8);
Modelica.Blocks.Interfaces.RealOutput y;
SI.Length h;
SI.Velocity v;
parameter SI.Acceleration g = Modelica.Constants.g_n;
parameter SI.Height h0 = 1.0;
initial equation
h = h0;
equation
v = der(h);
der(v) = -g;
y = h;
when h < 0 then
reinit(v, -e * pre(v));
end when;
end BouncingBall;
Overwriting BouncingBall.mo
FMI1.0 for Co-Simualtion の規格に従う BouncingBall モデルの FMU を生成します。
from pymodelica import compile_fmu
fmu = compile_fmu("BouncingBall","BouncingBall.mo", version='1.0', target='cs',compile_to = "BouncingBallCS10.fmu")
同様に、Modelica.Blocks.Souces.Step から入力信号モデルの FMU を生成します。
fmu = compile_fmu("Modelica.Blocks.Sources.Step", version='1.0', target='cs', compile_to = "Step.fmu")
シミュレーションの開始時刻、終了時刻、communication step を決めます。
t_start = 0.0
t_end = 3.0
dt = (t_end - t_start)/500
Co-Simualation モデルを構成し、シミュレーションを実行します。このモデルでは、model1のコミュニケーションステップが終了してからmodel2のコミュニケーションステップを実行しています。より実用的なモデルでは、サブモデルのコミュニケーションステップが同時に進行するように非同期的な処理が必要です。また、StepFailed や StepIncomplete に対する処理も省いてエラーで停止します。
# load models (instantiate)
import pyfmi
model1 = pyfmi.load_fmu("Step.fmu")
model2 = pyfmi.load_fmu("BouncingBallCS10.fmu")
t = t_start
# initialize result data array
t_res = []
e_res = []
h_res = []
# initialize model1 with input parameters
model1.set("height", -0.3)
model1.set("offset", 1.0)
model1.set("startTime", 1.0)
model1.initialize()
y1 = model1.get("y")
# initialize model2 with initial input data
model2.set("e",y1[0])
model2.initialize()
y2 = model2.get("y")
t_res.append(t)
e_res.append(y1[0])
h_res.append(y2[0])
while t <= t_end:
status = model1.do_step(t,dt)
if status == pyfmi.fmi.FMI_OK:
status = model2.do_step(t,dt)
if status == pyfmi.fmi.FMI_OK:
## succeed to simulate communication step!
# get data
y1 = model1.get("y")
y2 = model2.get("y")
# set data
model2.set("e",y1[0])
# calculate next communication step
t += dt
# restore result data
e_res.append(y1[0])
h_res.append(y2[0])
t_res.append(t)
else:
print("model2 error")
break
else:
print("model1 error")
break
%matplotlib inline
import matplotlib.pyplot as plt
plt.figure(1)
plt.plot(t_res,e_res,t_res,h_res)
[<matplotlib.lines.Line2D at 0x7f1a3e684490>, <matplotlib.lines.Line2D at 0x7f1a3e6845d0>]