|
|
@@ -33,6 +33,9 @@ class Clock:
|
|
|
"""
|
|
|
return self.__time
|
|
|
|
|
|
+ def setTime(self, time):
|
|
|
+ self.__time = time
|
|
|
+
|
|
|
def getStartTime(self):
|
|
|
"""
|
|
|
Gets the starting simulation time.
|
|
|
@@ -45,6 +48,18 @@ class Clock:
|
|
|
"""
|
|
|
self.__time = self.__time + self.__delta_t
|
|
|
|
|
|
+ def _rewind(self):
|
|
|
+ """
|
|
|
+ Rewinds the simulation clock to the previous iteration, assuming the delta
|
|
|
+ has not been changed.
|
|
|
+
|
|
|
+ Danger:
|
|
|
+ Normally, this function should only be used by the internal mechanisms
|
|
|
+ of the CBD simulator, **not** by a user. Using this function without a
|
|
|
+ full understanding of the simulator may result in undefined behaviour.
|
|
|
+ """
|
|
|
+ self.__time = self.__time - self.__delta_t
|
|
|
+
|
|
|
def setDeltaT(self, new_delta_t):
|
|
|
"""
|
|
|
Sets the delta in-between timesteps.
|
|
|
@@ -92,6 +107,9 @@ class Simulator:
|
|
|
# simulation data [dep graph, strong components, curIt]
|
|
|
self.__sim_data = [None, None, 0]
|
|
|
|
|
|
+ self.__stepsize_backend = Fixed(self.__deltaT)
|
|
|
+ self.__deltas = []
|
|
|
+
|
|
|
self.__threading_backend = None
|
|
|
self.__threading_backend_subsystem = Platform.PYTHON
|
|
|
self.__threading_backend_args = []
|
|
|
@@ -112,6 +130,9 @@ class Simulator:
|
|
|
# TODO: make this variable, given more solver implementations
|
|
|
self.__solver = GaussianJordanLinearSolver(self.__logger)
|
|
|
|
|
|
+ def setBackend(self, back):
|
|
|
+ self.__stepsize_backend = back
|
|
|
+
|
|
|
def run(self, term_time=None, start_time=0.0):
|
|
|
"""
|
|
|
Simulates the model.
|
|
|
@@ -248,6 +269,7 @@ class Simulator:
|
|
|
clock = self.getClock()
|
|
|
if clock is not None:
|
|
|
clock.setDeltaT(delta_t)
|
|
|
+ self.__stepsize_backend.delta_t = delta_t
|
|
|
|
|
|
def getDeltaT(self):
|
|
|
"""
|
|
|
@@ -262,6 +284,9 @@ class Simulator:
|
|
|
"""
|
|
|
return self.__deltaT
|
|
|
|
|
|
+ def setSimData(self, data):
|
|
|
+ self.__sim_data = data
|
|
|
+
|
|
|
def setRealTime(self, enabled=True, scale=1.0):
|
|
|
"""
|
|
|
Makes the simulation run in (scaled) real time.
|
|
|
@@ -416,6 +441,37 @@ class Simulator:
|
|
|
"""
|
|
|
self.__threading_backend.step(time)
|
|
|
|
|
|
+ def do_single_step(self):
|
|
|
+ curIt = self.__sim_data[2]
|
|
|
+ # 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.__sim_data[0].getStrongComponents(curIt)
|
|
|
+ self.__computeBlocks(self.__sim_data[1], self.__sim_data[0], self.__sim_data[2])
|
|
|
+ self.__sim_data[2] += 1
|
|
|
+
|
|
|
+ def update_clock(self):
|
|
|
+ if self.__sim_data[2] > 0:
|
|
|
+ new_dt = self.__stepsize_backend.getNextStepSize(self)
|
|
|
+ self.setDeltaT(new_dt)
|
|
|
+ self.__deltas.append(new_dt)
|
|
|
+ self.getClock().step()
|
|
|
+
|
|
|
+ def step_back(self):
|
|
|
+ """
|
|
|
+ Rewinds the simulator to the previous iteration.
|
|
|
+
|
|
|
+ Danger:
|
|
|
+ Normally, this function should only be used by the internal mechanisms
|
|
|
+ of the CBD simulator, **not** by a user. Using this function without a
|
|
|
+ full understanding of the simulator may result in undefined behaviour.
|
|
|
+ """
|
|
|
+ self.getClock()._rewind()
|
|
|
+ self.model._rewind()
|
|
|
+ self.__sim_data[2] -= 1
|
|
|
+
|
|
|
def getDurationLog(self):
|
|
|
"""
|
|
|
Get the list of timings for every iteration.
|
|
|
@@ -425,6 +481,9 @@ class Simulator:
|
|
|
"""
|
|
|
return self.__duration_log
|
|
|
|
|
|
+ def getDeltaLog(self):
|
|
|
+ return self.__deltas
|
|
|
+
|
|
|
def __realtimeWait(self):
|
|
|
"""
|
|
|
Wait until next realtime event.
|
|
|
@@ -467,16 +526,10 @@ class Simulator:
|
|
|
self.__finish()
|
|
|
break
|
|
|
|
|
|
+ self.update_clock()
|
|
|
+
|
|
|
before = time.time()
|
|
|
- # Efficiency reasons: dep graph only changes at these times
|
|
|
- # in the given set of library blocks.
|
|
|
- # TODO: Must be set to "every time" instead.
|
|
|
- curIt = self.__sim_data[2]
|
|
|
- if curIt < 2:
|
|
|
- self.__sim_data[0] = createDepGraph(self.model, curIt)
|
|
|
- self.__sim_data[1] = self.__sim_data[0].getStrongComponents(curIt)
|
|
|
- self.__step(*self.__sim_data)
|
|
|
- self.__sim_data[2] += 1
|
|
|
+ self.do_single_step()
|
|
|
self.__duration_log.append(time.time() - before)
|
|
|
|
|
|
if self.__threading_backend_subsystem == Platform.GLA:
|
|
|
@@ -487,19 +540,6 @@ class Simulator:
|
|
|
# Next event has been scheduled, kill this process
|
|
|
break
|
|
|
|
|
|
- def __step(self, depGraph, sortedGraph, curIteration):
|
|
|
- """
|
|
|
- Executes a single step on all blocks that must be computed.
|
|
|
-
|
|
|
- Args:
|
|
|
- depGraph: A dependency graph.
|
|
|
- sortedGraph: The set of strong components.
|
|
|
- curIteration (int): Current simulation iteration.
|
|
|
- """
|
|
|
- self.__computeBlocks(sortedGraph, depGraph, curIteration)
|
|
|
- self.setDeltaT(self.getDeltaT())
|
|
|
- self.getClock().step()
|
|
|
-
|
|
|
def __computeBlocks(self, sortedGraph, depGraph, curIteration):
|
|
|
"""
|
|
|
Compute the new state of the model.
|
|
|
@@ -605,3 +645,5 @@ class Simulator:
|
|
|
raise ValueError("Invalid signal '%s' in Simulator." % name)
|
|
|
for evt in self.__events[name]:
|
|
|
evt(*args)
|
|
|
+
|
|
|
+from .stepsize import *
|