|
|
@@ -1,14 +1,14 @@
|
|
|
import sys
|
|
|
-import time
|
|
|
import logging
|
|
|
import threading
|
|
|
-from . import naivelog
|
|
|
-from .depGraph import createDepGraph
|
|
|
-from .loopsolvers.linearsolver import LinearSolver
|
|
|
-from .realtime.threadingBackend import ThreadingBackend, Platform
|
|
|
-from .scheduling import TopologicalScheduler
|
|
|
-from .tracers import Tracers
|
|
|
-from .state_events.locators import RegulaFalsiStateEventLocator
|
|
|
+from CBD import naivelog
|
|
|
+from CBD.depGraph import createDepGraph
|
|
|
+from CBD.loopsolvers.linearsolver import LinearSolver
|
|
|
+from CBD.realtime.threadingBackend import ThreadingBackend, Platform
|
|
|
+from CBD.scheduling import TopologicalScheduler
|
|
|
+from CBD.tracers import Tracers
|
|
|
+from CBD.state_events.locators import RegulaFalsiStateEventLocator
|
|
|
+import CBD.realtime.accurate_time as time
|
|
|
|
|
|
_TQDM_FOUND = True
|
|
|
try:
|
|
|
@@ -101,12 +101,11 @@ class Simulator:
|
|
|
self.__progress_event = None
|
|
|
self.__progress_finished = True
|
|
|
self.__logger = naivelog.getLogger("CBD")
|
|
|
- self.__tracer = Tracers()
|
|
|
+ self.__tracer = Tracers(self)
|
|
|
|
|
|
self.__lasttime = None
|
|
|
|
|
|
self.__event_bus = []
|
|
|
- # self.__event_thread = threading.Thread(target=self.__event_thread_loop)
|
|
|
self.__events = {
|
|
|
"started": [],
|
|
|
"finished": [],
|
|
|
@@ -156,6 +155,7 @@ class Simulator:
|
|
|
self.__realtime_start_time = time.time()
|
|
|
self.__lasttime = 0.0
|
|
|
|
|
|
+ self.__threading_backend.wait(0.0, self.__tracer.thread_loop)
|
|
|
self.__threading_backend.wait(0.0, self.__event_thread_loop)
|
|
|
self.signal("started")
|
|
|
if self.__realtime:
|
|
|
@@ -181,6 +181,9 @@ class Simulator:
|
|
|
self.signal("finished")
|
|
|
self.__finished = True
|
|
|
|
|
|
+ # Make sure all events are executed
|
|
|
+ self.__threading_backend.wait(0.0, lambda: self.__event_thread_loop(10))
|
|
|
+
|
|
|
def __check(self):
|
|
|
"""
|
|
|
Checks if the simulation still needs to continue.
|
|
|
@@ -509,16 +512,18 @@ class Simulator:
|
|
|
sufficient to do a viable simulation. This function should only be
|
|
|
used by the inner workings of the simulator and its functional parts.
|
|
|
"""
|
|
|
- self.signal("prestep")
|
|
|
+ pre = time.time()
|
|
|
+ simT = self.getTime()
|
|
|
+ self.signal("prestep", pre, simT)
|
|
|
curIt = self.__sim_data[2]
|
|
|
- self.__threading_backend.wait(0, lambda: self.__tracer.traceNewIteration(curIt, self.getTime()))
|
|
|
+ self.__tracer.trace(self.__tracer.traceNewIteration, (curIt, simT))
|
|
|
|
|
|
# Efficiency reasons: dep graph only changes at these times
|
|
|
# in the given set of library blocks.
|
|
|
# TODO: Must be set to "every time" instead.
|
|
|
if curIt < 2 or self.__sim_data[0] is None:
|
|
|
self.__sim_data[0] = createDepGraph(self.model, curIt)
|
|
|
- self.__sim_data[1] = self.__scheduler.obtain(self.__sim_data[0], curIt, self.getTime())
|
|
|
+ self.__sim_data[1] = self.__scheduler.obtain(self.__sim_data[0], curIt, simT)
|
|
|
self.__computeBlocks(self.__sim_data[1], self.__sim_data[0], self.__sim_data[2])
|
|
|
self.__sim_data[2] += 1
|
|
|
# TODO: multiple LCC
|
|
|
@@ -538,7 +543,8 @@ class Simulator:
|
|
|
self.__sim_data[2] = 0
|
|
|
elif event.fired:
|
|
|
event.fired = False
|
|
|
- self.signal("poststep")
|
|
|
+ post = time.time()
|
|
|
+ self.signal("poststep", pre, post, self.getTime())
|
|
|
|
|
|
def _lcc_compute(self):
|
|
|
self.__computeBlocks(self.__sim_data[1], self.__sim_data[0], self.__sim_data[2])
|
|
|
@@ -615,7 +621,7 @@ class Simulator:
|
|
|
block = component[0] # the strongly connected component has a single element
|
|
|
if curIteration == 0 or self.__scheduler.mustCompute(block, self.getTime()):
|
|
|
block.compute(curIteration)
|
|
|
- self.__threading_backend.wait(0, lambda: self.__tracer.traceCompute(curIteration, block))
|
|
|
+ self.__tracer.trace(self.__tracer.traceCompute, (curIteration, block))
|
|
|
else:
|
|
|
# Detected a strongly connected component
|
|
|
self.__solver.checkValidity(self.model.getPath(), component)
|
|
|
@@ -625,7 +631,7 @@ class Simulator:
|
|
|
if curIteration == 0 or self.__scheduler.mustCompute(block, self.getTime()):
|
|
|
blockIndex = component.index(block)
|
|
|
block.appendToSignal(solutionVector[blockIndex])
|
|
|
- self.__threading_backend.wait(0, lambda: self.__tracer.traceCompute(curIteration, block))
|
|
|
+ self.__tracer.trace(self.__tracer.traceCompute, (curIteration, block))
|
|
|
|
|
|
def __hasCycle(self, component, depGraph):
|
|
|
"""
|
|
|
@@ -671,17 +677,25 @@ class Simulator:
|
|
|
It is expected that the passed function terminates at a certain point
|
|
|
in time, to prevent an infinitely running process.
|
|
|
|
|
|
+ Warning:
|
|
|
+ There is no guarantee that these functions will be executed in-order of
|
|
|
+ connection. For safety, it is best to see these events as not thread-safe.
|
|
|
+
|
|
|
The functions will be called in the order they were connected to the
|
|
|
events, with the associated arguments. The accepted signals are:
|
|
|
|
|
|
- - :code:`started`: Raised whenever the simulation setup has
|
|
|
- completed, but before the actual simulation
|
|
|
- begins.
|
|
|
+ - :code:`started`: Raised whenever the simulation setup has completed,
|
|
|
+ but before the actual simulation begins.
|
|
|
- :code:`finished`: Raised whenever the simulation finishes.
|
|
|
- - :code:`prestep`: Raised before a step is done.
|
|
|
- - :code:`poststep`: Raised after a step is done.
|
|
|
- - :code:`clock_update(delta)`: Raised whenever the clock updates. It takes
|
|
|
- the (new) delta for the simulation.
|
|
|
+ - :code:`prestep(t, st)`: Raised before a step is done. :code:`t` is the real
|
|
|
+ time before the step and :code:`st` is the simulation
|
|
|
+ time.
|
|
|
+ - :code:`poststep(o, t, st)`: Raised after a step is done. :code:`o` is the real
|
|
|
+ time before the step, :code:`t` is the real time after
|
|
|
+ the step and :code:`st` is the simulation time of the
|
|
|
+ step.
|
|
|
+ - :code:`clock_update(delta)`: Raised whenever the clock updates. It takes the (new)
|
|
|
+ delta for the simulation.
|
|
|
|
|
|
Args:
|
|
|
name (str): The name of the signal to raise.
|
|
|
@@ -721,13 +735,15 @@ class Simulator:
|
|
|
raise ValueError("Invalid signal '%s' in Simulator." % name)
|
|
|
self.__event_bus.append((name, args))
|
|
|
|
|
|
- def __event_thread_loop(self):
|
|
|
- if not self.__finished or len(self.__event_bus) > 0:
|
|
|
- while len(self.__event_bus) > 0:
|
|
|
+ def __event_thread_loop(self, cnt=-1):
|
|
|
+ i = 0
|
|
|
+ while (not self.__finished or len(self.__event_bus) > 0) and (cnt == -1 or cnt <= i):
|
|
|
+ i += 1
|
|
|
+ if len(self.__event_bus) > 0:
|
|
|
name, args = self.__event_bus.pop()
|
|
|
for evt in self.__events[name]:
|
|
|
- self.__threading_backend.wait(0.0, lambda: evt(*args))
|
|
|
- self.__threading_backend.wait(0.05, self.__event_thread_loop)
|
|
|
+ evt(*args)
|
|
|
+ time.sleep(0.05)
|
|
|
|
|
|
def setCustomTracer(self, *tracer):
|
|
|
"""
|