|
|
@@ -28,22 +28,23 @@ class CBDRunner(AtomicDEVS):
|
|
|
progress. Useful when in combination with
|
|
|
multiple ODEs. Defaults to :code:`False`.
|
|
|
"""
|
|
|
- def __init__(self, name, cbd, initials, stopped=False, crossings=None):
|
|
|
+ def __init__(self, name, cbd, initials=None, stopped=False, crossings=None):
|
|
|
AtomicDEVS.__init__(self, name)
|
|
|
- self.initials = initials
|
|
|
+ self.initials = {} if initials is None else initials
|
|
|
self.original_model, self.Hname = prepare_cbd(cbd.clone(), initials)
|
|
|
self.crossings = {} if crossings is None else crossings
|
|
|
|
|
|
self.state = {
|
|
|
"CBD": None,
|
|
|
+ "curIt": 0,
|
|
|
"delta_t": 0.0,
|
|
|
- "initials": initials,
|
|
|
+ "initials": self.initials,
|
|
|
"request_output": False,
|
|
|
"request_compute": True,
|
|
|
"zero_crossing": None,
|
|
|
"time": 0.0,
|
|
|
"stopped": stopped,
|
|
|
- "zcd": { k: None for k in self.crossings }
|
|
|
+ # "zcd": { k: None for k in self.crossings }
|
|
|
}
|
|
|
|
|
|
self.simulator = None
|
|
|
@@ -63,7 +64,7 @@ class CBDRunner(AtomicDEVS):
|
|
|
def timeAdvance(self):
|
|
|
if self.state["stopped"]:
|
|
|
return INFINITY
|
|
|
- if self.state["request_output"] or self.state["request_compute"]:
|
|
|
+ if self.state["request_compute"]:
|
|
|
return 0.0
|
|
|
return max(0.0, self.state["delta_t"])
|
|
|
|
|
|
@@ -82,55 +83,60 @@ class CBDRunner(AtomicDEVS):
|
|
|
return res
|
|
|
|
|
|
def intTransition(self):
|
|
|
+ ta = self.timeAdvance()
|
|
|
+ self.state["time"] += ta
|
|
|
if self.state["request_output"]:
|
|
|
self.state["request_output"] = False
|
|
|
+ self.state["request_compute"] = True
|
|
|
return self.state
|
|
|
|
|
|
- ta = self.timeAdvance()
|
|
|
-
|
|
|
- self.state["time"] += ta
|
|
|
+ self.state["request_output"] = True
|
|
|
self.state["request_compute"] = False
|
|
|
self.state["zero_crossing"] = None
|
|
|
|
|
|
+ self.state["curIt"] += 1
|
|
|
+ if self.state["curIt"] == 1:
|
|
|
+ self.simulator._do_single_step()
|
|
|
+ self.state["request_output"] = True
|
|
|
+ return self.state
|
|
|
+
|
|
|
+ old = {}
|
|
|
+ for c in self.crossings:
|
|
|
+ # print("PRE", c, self.state["CBD"].getBlockByName(c).getSignal("OUT1")[-1])
|
|
|
+ old[c] = self.get_signal(c)
|
|
|
+
|
|
|
+ self.state["delta_t"] = self.get_delta()
|
|
|
self.simulator._do_single_step()
|
|
|
|
|
|
- crsc = {}
|
|
|
+ cds = {}
|
|
|
for z, y in self.crossings.items():
|
|
|
value = self.get_signal(z)
|
|
|
- if self.state["zcd"][z] is None:
|
|
|
- self.state["zcd"][z] = value
|
|
|
- else:
|
|
|
- old = self.state["zcd"][z]
|
|
|
- if (old - y) * (value - y) < 0:
|
|
|
- cd = self.crossing_detection(z, y, ta)
|
|
|
- if cd in crsc:
|
|
|
- crsc[cd].append(z)
|
|
|
- else:
|
|
|
- crsc[cd] = [z]
|
|
|
-
|
|
|
- if len(tzc) > 0:
|
|
|
+ # print("POST", z, self.state["CBD"].getBlockByName(z).getSignal("OUT1")[-1])
|
|
|
+ if (old[z] - y) * (value - y) < 0:
|
|
|
+ # A crossing will happen!
|
|
|
+ # print("CROSSING:", old[z], value, y)
|
|
|
+ cds.setdefault(self.crossing_detection(z, y, old[z]), []).append(z)
|
|
|
+ if len(cds) > 0:
|
|
|
+ oh = self.get_delta()
|
|
|
+ self.simulator._rewind()
|
|
|
self.simulator._rewind()
|
|
|
- self.state["time"] -= ta
|
|
|
- mtzc = min(crsc)
|
|
|
- h = mtzc[1] - self.state["time"]
|
|
|
+ fzc = min(cds)
|
|
|
+ self.state["zero_crossing"] = cds[fzc]
|
|
|
+ h = fzc - self.state["time"]
|
|
|
+ self.state["delta_t"] = h
|
|
|
self.set_delta(h)
|
|
|
+ p = self.simulator.getClock().getBlockByName("Past")
|
|
|
+ p.setValue(p.getValue() + oh)
|
|
|
self.simulator._do_single_step()
|
|
|
- self.state["time"] += h
|
|
|
+ p.setValue(p.getValue() + oh)
|
|
|
+ self.simulator._do_single_step()
|
|
|
+ # print("CROSSING:", self.state["CBD"].getBlockByName("v").getSignal("OUT1")[-1])
|
|
|
+ else:
|
|
|
self.set_delta(float('inf'))
|
|
|
- self.state["request_output"] = True
|
|
|
- self.state["request_compute"] = True
|
|
|
- self.state["zero_crossing"] = crsc[mtzc]
|
|
|
- # self.simulator._do_single_step()
|
|
|
-
|
|
|
- self.state["delta_t"] = self.get_delta()
|
|
|
- self.set_delta(self.state["delta_t"])
|
|
|
-
|
|
|
- self.state["request_output"] = True
|
|
|
return self.state
|
|
|
|
|
|
def extTransition(self, inputs):
|
|
|
self.state["time"] += self.elapsed
|
|
|
- self.state["delta_t"] -= self.elapsed
|
|
|
|
|
|
if not self.state["stopped"]:
|
|
|
self.state["delta_t"] -= self.elapsed
|
|
|
@@ -143,31 +149,16 @@ class CBDRunner(AtomicDEVS):
|
|
|
self.state["stopped"] = True
|
|
|
return self.state
|
|
|
|
|
|
- # if self.rewind in inputs:
|
|
|
- # H = self.state["delta_t"]
|
|
|
- # h = inputs[self.rewind]
|
|
|
- # self.simulator._rewind()
|
|
|
- # # TODO: set delay to h
|
|
|
- # self.simulator._do_single_step()
|
|
|
- # # TODO: set delay to H - h
|
|
|
- # self.simulator._do_single_step()
|
|
|
- # # TODO: set delay to H
|
|
|
- # else:
|
|
|
for inport, value in inputs.items():
|
|
|
if inport.name in self.initials:
|
|
|
self.state["initials"][inport.name] = value
|
|
|
|
|
|
self.reinit()
|
|
|
- self.set_delta(self.state["delta_t"])
|
|
|
|
|
|
- self.simulator._do_single_step()
|
|
|
-
|
|
|
- self.set_delta(float('inf'))
|
|
|
-
|
|
|
- ###
|
|
|
- self.state["request_compute"] = False
|
|
|
- self.state["request_output"] = True
|
|
|
+ self.state["request_compute"] = True
|
|
|
+ self.state["request_output"] = False
|
|
|
self.state["stopped"] = False
|
|
|
+ self.state["curIt"] = 0
|
|
|
return self.state
|
|
|
|
|
|
def __del__(self):
|
|
|
@@ -177,6 +168,8 @@ class CBDRunner(AtomicDEVS):
|
|
|
self.state["CBD"] = self.original_model.clone()
|
|
|
self.apply_initials()
|
|
|
self.simulator = Simulator(self.state["CBD"])
|
|
|
+ self.simulator.getClock().setStartTime(self.state["time"])
|
|
|
+ self.set_delta(float('inf'))
|
|
|
|
|
|
def apply_initials(self):
|
|
|
for k, v in self.state["initials"].items():
|
|
|
@@ -185,10 +178,9 @@ class CBDRunner(AtomicDEVS):
|
|
|
def get_signal(self, pname):
|
|
|
return self.state["CBD"].getBlockByName(pname).getSignal("OUT1")[-1].value
|
|
|
|
|
|
- def crossing_detection(self, signal, y, ta):
|
|
|
- t2 = self.state["time"]
|
|
|
- t1 = t2 - ta
|
|
|
- y1 = self.state["zcd"][signal]
|
|
|
+ def crossing_detection(self, signal, y, y1):
|
|
|
+ t1 = self.state["time"]
|
|
|
+ t2 = t1 + self.state["delta_t"]
|
|
|
y2 = self.get_signal(signal)
|
|
|
return (t2 - t1) / (y2 - y1) * (y - y1) + t1
|
|
|
|