sccd_classic.xml 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. <?xml version="1.0" ?>
  2. <diagram author="Yentl Van Tendeloo" name="DEVS simulator">
  3. <description>
  4. A restricted PythonPDEVS simulator modelled in SCCD for classic, dynamic structure DEVS models.
  5. </description>
  6. <top>
  7. import cPickle as pickle
  8. import time
  9. # We basically just interface with the basesimulator
  10. from scheduler import Scheduler
  11. from DEVS import directConnect, CoupledDEVS, AtomicDEVS, RootDEVS
  12. from classicDEVSWrapper import ClassicDEVSWrapper
  13. from tracer import trace
  14. class Breakpoint(object):
  15. def __init__(self, breakpoint_id, function, enabled, disable_on_trigger):
  16. self.id = breakpoint_id
  17. self.function = function
  18. self.enabled = enabled
  19. self.disable_on_trigger = disable_on_trigger
  20. </top>
  21. <inport name="request"/>
  22. <outport name="reply"/>
  23. <class name="SCCDSimulator" default="true">
  24. <!-- Define the constructor, taking the model to simulate as a parameter -->
  25. <constructor>
  26. <parameter name="model"/>
  27. <body>
  28. <![CDATA[
  29. # Simulation variables
  30. self.termination_time = None
  31. self.termination_condition = None
  32. self.simulation_time = (0.0, 0)
  33. self.model = model
  34. self.listeners = {}
  35. self.root_model = model
  36. self.realtime_scale = 1.0
  37. # Values to be set during simulation
  38. self.realtime_starttime = None
  39. self.inject_queue = []
  40. # Model initialization
  41. self.model_ids = []
  42. self.model.finalize(name="", model_counter=0, model_ids=self.model_ids, locations={None: []}, select_hierarchy=[])
  43. # Direct connection
  44. if isinstance(self.model, CoupledDEVS):
  45. self.model.component_set = directConnect(self.model.component_set, self.listeners)
  46. self.model = RootDEVS(self.model.component_set, self.model.component_set, None)
  47. for m in self.model.component_set:
  48. m.timeLast = (-m.elapsed, 1)
  49. ta = m.timeAdvance()
  50. m.time_next = (m.timeLast[0] + ta, 1)
  51. m.old_states = [(m.timeLast, pickle.dumps(m.state))]
  52. elif isinstance(self.model, AtomicDEVS):
  53. for p in self.model.IPorts:
  54. p.routing_inline = []
  55. p.routing_outline = []
  56. for p in self.model.OPorts:
  57. p.routing_inline = []
  58. p.routing_outline = []
  59. self.model = RootDEVS([self.model], [self.model], None)
  60. self.model.timeLast = (-self.model.elapsed, 1)
  61. ta = self.model.timeAdvance()
  62. self.model.time_next = (self.model.timeLast[0] + ta, 1)
  63. # Fixed configuration options
  64. self.model.scheduler = Scheduler(self.model.component_set, 1e-6, len(self.model.component_set))
  65. self.time_next = self.model.scheduler.readFirst()
  66. # Cached values
  67. self.imminents = None
  68. self.outbag = None
  69. self.inbags = None
  70. self.transitioning = None
  71. self.new_states = None
  72. self.new_tn = None
  73. # Verbose trace file
  74. self.trace_file = None
  75. # Breakpoint management
  76. self.breakpoints = []
  77. # For a reset
  78. self.save_model = {model: (model.elapsed, pickle.dumps(model.state, pickle.HIGHEST_PROTOCOL)) for model in self.model.component_set}
  79. self.transition_times = []
  80. ]]>
  81. </body>
  82. </constructor>
  83. <!-- Serialize the output values in something human-readable instead of internal objects.
  84. Note that this doesn't alter the internal structure, as that is still used for simulation. -->
  85. <method name="serialize">
  86. <parameter name="type"/>
  87. <parameter name="object"/>
  88. <body>
  89. <![CDATA[
  90. if type == "imminents":
  91. return [m.getModelFullName() for m in object]
  92. elif type == "imminent":
  93. return object.getModelFullName()
  94. elif type == "inbags" or type == "outbag":
  95. return {m.getPortFullName(): object[m] for m in object}
  96. elif type == "new_tn" or type == "new_states":
  97. return {m.getModelFullName(): object[m] for m in object}
  98. elif type == "transitioning":
  99. return {m.getModelFullName(): {1: "INTERNAL", 2: "EXTERNAL"}[object[m]] for m in object}
  100. ]]>
  101. </body>
  102. </method>
  103. <!-- Find a port based on a fully qualified name. -->
  104. <method name="find_port_with_name">
  105. <parameter name="name"/>
  106. <body>
  107. <![CDATA[
  108. for model in self.model.component_set:
  109. if name.startswith(model.getModelFullName()):
  110. # Found a potential model
  111. # We can't simply check for equality, as portnames might contain dots too
  112. for port in model.IPorts:
  113. if port.getPortFullName() == name:
  114. # Now everything matches
  115. return port
  116. # Nothing found
  117. return None
  118. ]]>
  119. </body>
  120. </method>
  121. <!-- Find a model based on a fully qualified name. -->
  122. <method name="find_model_with_name">
  123. <parameter name="name"/>
  124. <body>
  125. <![CDATA[
  126. for model in self.model.component_set:
  127. if name == model.getModelFullName():
  128. # Found exact match
  129. return model
  130. return None
  131. ]]>
  132. </body>
  133. </method>
  134. <!-- Calculate the time to wait before triggering the next transition.
  135. This method is also called in non-realtime simulation, so make sure that it returns infinity in that case. -->
  136. <method name="calculate_after">
  137. <body>
  138. <![CDATA[
  139. try:
  140. # Process in parts of 100 milliseconds to repeatedly check the termination condition
  141. nexttime = (self.time_next[0] - (time.time() - self.realtime_starttime) / self.realtime_scale) * self.realtime_scale
  142. x = min(0.1, nexttime)
  143. return x
  144. except TypeError, AttributeError:
  145. # We are probably not simulating in realtime...
  146. return float('inf')
  147. ]]>
  148. </body>
  149. </method>
  150. <!-- Parse a list of options that can be passed together with the request -->
  151. <method name="parse_options">
  152. <parameter name="configuration"/>
  153. <body>
  154. <![CDATA[
  155. self.termination_condition = None if "termination_condition" not in configuration else configuration["termination_condition"]
  156. self.termination_time = None if "termination_time" not in configuration else configuration["termination_time"]
  157. self.realtime_scale = 1.0 if "realtime_scale" not in configuration else 1.0/configuration["realtime_scale"]
  158. # Subtract the current simulation time to allow for pausing
  159. self.realtime_starttime = (time.time() - self.simulation_time[0]*self.realtime_scale)
  160. # Reset the time used in the waiting, as it might not get recomputed
  161. self.the_time = 0.00001
  162. ]]>
  163. </body>
  164. </method>
  165. <!-- Utility function to determine whether or not simulation is finished. -->
  166. <method name="should_terminate">
  167. <parameter name="realtime"/>
  168. <body>
  169. <![CDATA[
  170. # Now that it includes breakpoints, results are to be interpretted as follows:
  171. # -2 --> continue simulation
  172. # -1 --> termination condition
  173. # else --> breakpoint
  174. if realtime:
  175. check_time = self.simulation_time
  176. else:
  177. self.compute_timeNext()
  178. check_time = self.time_next
  179. # Just access the 'transitioned' dictionary
  180. # Kind of dirty though...
  181. if self.transitioning is None:
  182. transitioned = set()
  183. else:
  184. transitioned = set(self.transitioning.keys())
  185. if check_time[0] == float('inf'):
  186. # Always terminate if we have reached infinity
  187. terminate = True
  188. elif self.termination_condition is not None:
  189. terminate = self.termination_condition(check_time, self.root_model, transitioned)
  190. else:
  191. terminate = self.termination_time < check_time[0]
  192. if terminate:
  193. # Always terminate, so don't check breakpoints
  194. return -1
  195. else:
  196. # Have to check breakpoints for termination
  197. for bp in self.breakpoints:
  198. if not bp.enabled:
  199. continue
  200. # Include the function in the scope
  201. exec(bp.function)
  202. # And execute it, note that the breakpoint thus has to start with "def breakpoint("
  203. if breakpoint(check_time, self.root_model, transitioned):
  204. # Triggered!
  205. return bp.id
  206. else:
  207. # Not triggered, so continue
  208. continue
  209. return -2
  210. ]]>
  211. </body>
  212. </method>
  213. <!-- Compute all models of which the internal transition function has to be triggered. -->
  214. <method name="find_internal_imminents">
  215. <body>
  216. <![CDATA[
  217. self.imminents = self.model.scheduler.getImminent(self.simulation_time)
  218. self.reschedule = set(self.imminents)
  219. self.transition_times.append(self.simulation_time)
  220. for model in self.imminents:
  221. model.time_next = (model.time_next[0], model.time_next[1] + 1)
  222. ]]>
  223. </body>
  224. </method>
  225. <!-- Select one of the imminent components -->
  226. <method name="select_imminent">
  227. <body>
  228. <![CDATA[
  229. self.imminent = None
  230. if len(self.imminents) > 1:
  231. # Perform all selects
  232. self.imminents.sort()
  233. pending = self.imminents
  234. level = 1
  235. while len(pending) > 1:
  236. # Take the model each time, as we need to make sure that the selectHierarchy is valid everywhere
  237. model = pending[0]
  238. # Make a set first to remove duplicates
  239. colliding = list(set([m.select_hierarchy[level] for m in pending]))
  240. chosen = model.select_hierarchy[level-1].select(
  241. sorted(colliding, key=lambda i:i.getModelFullName()))
  242. pending = [m for m in pending
  243. if m.select_hierarchy[level] == chosen]
  244. level += 1
  245. self.imminent = pending[0]
  246. else:
  247. self.imminent = self.imminents[0]
  248. self.imminent.time_next = (self.imminent.time_next[0], self.imminent.time_next[1] - 1)
  249. ]]>
  250. </body>
  251. </method>
  252. <!-- Trigger all output functions of imminent models. -->
  253. <method name="compute_outputfunction">
  254. <body>
  255. <![CDATA[
  256. self.outbag = ClassicDEVSWrapper(self.imminent).outputFnc()
  257. ]]>
  258. </body>
  259. </method>
  260. <!-- Route all messages and apply the required transfer functions. -->
  261. <method name="route_messages">
  262. <body>
  263. <![CDATA[
  264. self.inbags = {}
  265. for outport in self.outbag:
  266. payload = self.outbag[outport]
  267. for inport, z in outport.routing_outline:
  268. if z is not None:
  269. payload = [z(pickle.loads(pickle.dumps(m))) for m in payload]
  270. self.inbags.setdefault(inport, []).extend(payload)
  271. ]]>
  272. </body>
  273. </method>
  274. <!-- Process the injects on the inject_queue.
  275. TODO: What about events injected on a port which already has an event, or on a time at which a transition was scheduled? Should this be seen as a separate component that needs priority? -->
  276. <method name="process_injects">
  277. <body>
  278. <![CDATA[
  279. while self.inject_queue:
  280. if self.inject_queue[0]["time"] > self.simulation_time:
  281. break
  282. config = self.inject_queue.pop(0)
  283. portname = config["port"]
  284. event = config["event"]
  285. port = self.find_port_with_name(portname)
  286. self.inbags.setdefault(port, []).append(event)
  287. ]]>
  288. </body>
  289. </method>
  290. <!-- Combine the information from the routed messages to determine the external, internal and confluent transition functions to trigger. -->
  291. <method name="find_all_imminents">
  292. <body>
  293. <![CDATA[
  294. # Internal codes:
  295. # 1 --> internal transition
  296. # 2 --> external transition
  297. # 3 --> confluent transition
  298. # These codes are a legacy of efficient PyPDEVS, but is kept here for consistency
  299. self.transitioning = {self.imminent: 1}
  300. for inport in self.inbags:
  301. aDEVS = inport.host_DEVS
  302. aDEVS.my_input[inport] = self.inbags[inport]
  303. self.transitioning[aDEVS] = 2
  304. self.reschedule.add(aDEVS)
  305. self.transitioning = {ClassicDEVSWrapper(m): self.transitioning[m]
  306. for m in self.transitioning}
  307. ]]>
  308. </body>
  309. </method>
  310. <!-- Trigger all transition functions. -->
  311. <method name="compute_transitions">
  312. <body>
  313. <![CDATA[
  314. self.new_states = {}
  315. for aDEVS in self.transitioning:
  316. aDEVS.my_input = {key: pickle.loads(pickle.dumps(aDEVS.my_input[key], pickle.HIGHEST_PROTOCOL)) for key in aDEVS.my_input}
  317. if self.transitioning[aDEVS] == 1:
  318. aDEVS.state = aDEVS.intTransition()
  319. elif self.transitioning[aDEVS] == 2:
  320. aDEVS.elapsed = self.simulation_time[0] - aDEVS.timeLast[0]
  321. aDEVS.state = aDEVS.extTransition(aDEVS.my_input)
  322. aDEVS.old_states.append((self.simulation_time, pickle.dumps(aDEVS.state)))
  323. aDEVS.my_input = {}
  324. self.new_states[aDEVS] = aDEVS.state
  325. ]]>
  326. </body>
  327. </method>
  328. <!-- Trigger all timeAdvance functions. -->
  329. <method name="compute_ta">
  330. <body>
  331. <![CDATA[
  332. self.new_tn = {}
  333. t, age = self.simulation_time
  334. for aDEVS in self.transitioning:
  335. ta = aDEVS.timeAdvance()
  336. aDEVS.timeLast = self.simulation_time
  337. aDEVS.time_next = (t + ta, 1 if ta else (age + 1))
  338. self.new_tn[aDEVS] = aDEVS.time_next
  339. trace(self.trace_file, self.transitioning[aDEVS], aDEVS)
  340. self.model.scheduler.massReschedule(self.reschedule)
  341. self.time_next = self.model.scheduler.readFirst()
  342. ]]>
  343. </body>
  344. </method>
  345. <method name="flush_file">
  346. <body>
  347. <![CDATA[
  348. if self.trace_file is not None:
  349. self.trace_file.flush()
  350. ]]>
  351. </body>
  352. </method>
  353. <method name="process_breakpoints">
  354. <parameter name="realtime"/>
  355. <body>
  356. <![CDATA[
  357. breakpoint_id = self.should_terminate(realtime)
  358. for breakpoint in self.breakpoints:
  359. if breakpoint.id == breakpoint_id:
  360. if breakpoint.disable_on_trigger:
  361. breakpoint.enabled = False
  362. return breakpoint_id
  363. ]]>
  364. </body>
  365. </method>
  366. <method name="compute_timeNext">
  367. <body>
  368. <![CDATA[
  369. model_timeNext = self.model.scheduler.readFirst()
  370. if len(self.inject_queue) > 0:
  371. self.time_next = min(model_timeNext, self.inject_queue[0]["time"])
  372. else:
  373. self.time_next = model_timeNext
  374. ]]>
  375. </body>
  376. </method>
  377. <method name="rollback_step">
  378. <body>
  379. <![CDATA[
  380. if len(self.transition_times) == 0:
  381. return
  382. new_time = self.transition_times.pop()
  383. for model in self.model.component_set:
  384. if model.old_states[-1][0] == new_time:
  385. # Remove the current state
  386. del model.old_states[-1]
  387. # Set the new (old...) state
  388. new_state = model.old_states[-1]
  389. model.state = pickle.loads(new_state[1])
  390. model.timeLast = new_state[0]
  391. ta = model.timeAdvance()
  392. model.time_next = (model.timeLast[0] + ta, model.timeLast[1] + 1 if ta == 0 else 0)
  393. self.model.scheduler.massReschedule([model])
  394. self.simulation_time = self.transition_times[-1] if len(self.transition_times) > 0 else (0.0, 0)
  395. ]]>
  396. </body>
  397. </method>
  398. <scxml initial="main">
  399. <!-- Parallel states: one of them controls the simulation flow, the other the type of simulation being performed. -->
  400. <parallel id="main">
  401. <!-- When an injection is received, just append it to the list of pending injections.
  402. These will be processed as soon as the current simulation step is finished.
  403. Afterwards, return to the previous state, as there was no change of state. -->
  404. <state id="injection_monitor">
  405. <state id="inject">
  406. <transition port="request" event="inject" target=".">
  407. <parameter name="configuration"/>
  408. <script>
  409. configuration["time"] = (configuration["time"], 1)
  410. self.inject_queue.append(configuration)
  411. self.inject_queue.sort(key=lambda i: i["time"])
  412. </script>
  413. <raise scope="output" port="reply" event="inject_ok"/>
  414. </transition>
  415. </state>
  416. </state>
  417. <state id="tracer_monitor">
  418. <state id="trace">
  419. <transition port="request" event="trace" target=".">
  420. <parameter name="filename"/>
  421. <script>
  422. if filename is not None:
  423. self.trace_file = open(filename, 'w')
  424. else:
  425. self.trace_file = None
  426. </script>
  427. <raise scope="output" port="reply" event="trace_config_ok"/>
  428. </transition>
  429. </state>
  430. </state>
  431. <!-- The main parallel component: the simulation flow. -->
  432. <state id="simulation_flow" initial="initialize">
  433. <state id="initialize">
  434. <transition target="../check_termination">
  435. <raise scope="output" port="reply" event="all_states">
  436. <parameter expr="self.simulation_time"/>
  437. <parameter expr="{m.getModelFullName(): (m.time_next, m.state) for m in self.model.component_set}"/>
  438. </raise>
  439. </transition>
  440. </state>
  441. <state id="check_termination" initial="workaround">
  442. <onexit>
  443. <script>
  444. self.simulation_time = self.time_next
  445. </script>
  446. </onexit>
  447. <state id="workaround">
  448. <transition after="0" target="../check_termination"/>
  449. </state>
  450. <state id="wait">
  451. <onexit>
  452. <script>
  453. diff = time.time() - self.realtime_starttime
  454. self.simulation_time = (diff / self.realtime_scale, 1)
  455. </script>
  456. </onexit>
  457. <transition after="self.calculate_after()" target="../check_termination"/>
  458. <transition cond="INSTATE('../../../simulation_state/paused')" target="../check_termination"/>
  459. </state>
  460. <state id="small_step_check">
  461. <transition cond="self.should_terminate(False) == -2" target="../../do_simulation"/>
  462. <transition cond="self.should_terminate(False) == -1" target="../check_termination">
  463. <raise event="termination_condition"/>
  464. </transition>
  465. <transition cond="self.should_terminate(False) &gt; -1" target="../check_termination">
  466. <script>
  467. breakpoint_id = self.process_breakpoints(False)
  468. </script>
  469. <raise scope="output" port="reply" event="breakpoint_triggered">
  470. <parameter expr="breakpoint_id"/>
  471. </raise>
  472. <raise event="termination_condition"/>
  473. </transition>
  474. </state>
  475. <state id="check_termination">
  476. <onentry>
  477. <script>
  478. self.compute_timeNext()
  479. self.the_time = self.calculate_after()
  480. </script>
  481. </onentry>
  482. <!-- Continue simulation -->
  483. <transition cond="INSTATE('../../../simulation_state/continuous') and (self.should_terminate(False) == -2)" target="../../do_simulation"/>
  484. <transition cond="INSTATE('../../../simulation_state/big_step') and (self.should_terminate(False) == -2)" target="../../do_simulation"/>
  485. <!-- Realtime and didn't reach the required time_next yet -->
  486. <transition cond="INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) == -2) and (self.the_time &gt; 0.0)" target="../wait"/>
  487. <transition cond="INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) == -2) and (self.the_time &lt;= 0.0)" target="../../do_simulation"/>
  488. <transition port="request" event="small_step" target="../small_step_check">
  489. <parameter name="configuration" type="dict" default="{}"/>
  490. <script>
  491. self.parse_options(configuration)
  492. </script>
  493. </transition>
  494. <!-- Pause simulation -->
  495. <transition cond="(not INSTATE('../../../simulation_state/paused') and INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) == -1))" target="../workaround">
  496. <raise event="termination_condition"/>
  497. </transition>
  498. <transition cond="(not INSTATE('../../../simulation_state/paused') and not INSTATE('../../../simulation_state/realtime') and (self.should_terminate(False) == -1))" target="../workaround">
  499. <raise event="termination_condition"/>
  500. </transition>
  501. <transition cond="(not INSTATE('../../../simulation_state/paused')) and INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) &gt; -1)" target="../workaround">
  502. <script>
  503. breakpoint_id = self.process_breakpoints(True)
  504. </script>
  505. <raise scope="output" port="reply" event="breakpoint_triggered">
  506. <parameter expr="breakpoint_id"/>
  507. </raise>
  508. <raise event="termination_condition"/>
  509. </transition>
  510. <transition cond="(not INSTATE('../../../simulation_state/paused')) and not INSTATE('../../../simulation_state/realtime') and (self.should_terminate(False) &gt; -1)" target="../workaround">
  511. <script>
  512. breakpoint_id = self.process_breakpoints(False)
  513. </script>
  514. <raise scope="output" port="reply" event="breakpoint_triggered">
  515. <parameter expr="breakpoint_id"/>
  516. </raise>
  517. <raise event="termination_condition"/>
  518. </transition>
  519. <!-- Process god event -->
  520. <transition cond="INSTATE('../../../simulation_state/paused')" port="request" event="god_event" target="../workaround">
  521. <parameter name="configuration"/>
  522. <script>
  523. modelname = configuration["model"]
  524. state_attribute = configuration["attribute"]
  525. new_value = configuration["value"]
  526. model = self.find_model_with_name(modelname)
  527. setattr(model.state, state_attribute, new_value)
  528. # Call the timeadvance method again and compute new ta
  529. ta = model.timeAdvance()
  530. model.time_next = (model.timeLast[0] + ta, 1 if ta else (model.timeLast[1] + 1))
  531. self.model.scheduler.massReschedule([model])
  532. # self.simulation_time = self.model.scheduler.readFirst()
  533. </script>
  534. <raise scope="output" port="reply" event="god_event_ok">
  535. <parameter expr="{model.getModelFullName(): str(model.state)}"/>
  536. </raise>
  537. <raise scope="output" port="reply" event="new_tn">
  538. <parameter expr="self.simulation_time"/>
  539. <parameter expr="{model.getModelFullName(): model.time_next}"/>
  540. </raise>
  541. </transition>
  542. <!-- Omniscient debugging -->
  543. <transition cond="INSTATE('../../../simulation_state/paused')" port="request" event="backwards_step" target="../workaround">
  544. <script>
  545. self.rollback_step()
  546. </script>
  547. <raise scope="output" port="reply" event="all_states">
  548. <parameter expr="self.simulation_time"/>
  549. <parameter expr="{m.getModelFullName(): (m.time_next, m.state) for m in self.model.component_set}"/>
  550. </raise>
  551. </transition>
  552. </state>
  553. </state>
  554. <state id="do_simulation" initial="init">
  555. <state id="init">
  556. <onexit>
  557. <script>
  558. self.find_internal_imminents()
  559. </script>
  560. </onexit>
  561. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../found_internal_imminents"/>
  562. <!-- Always output this if paused, as we only got here because a small step was fired previously -->
  563. <transition cond="INSTATE('../../../simulation_state/paused')" target="../found_internal_imminents">
  564. <raise scope="output" port="reply" event="imminents">
  565. <parameter expr="self.simulation_time"/>
  566. <parameter expr="self.serialize('imminents', self.imminents)"/>
  567. </raise>
  568. </transition>
  569. </state>
  570. <state id="found_internal_imminents">
  571. <onexit>
  572. <script>
  573. self.select_imminent()
  574. </script>
  575. </onexit>
  576. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../selected_imminent"/>
  577. <transition port="request" event="small_step" target="../selected_imminent">
  578. <raise scope="output" port="reply" event="selected_imminent">
  579. <parameter expr="self.simulation_time"/>
  580. <parameter expr="self.serialize('imminent', self.imminent)"/>
  581. </raise>
  582. </transition>
  583. </state>
  584. <state id="selected_imminent">
  585. <onexit>
  586. <script>
  587. self.compute_outputfunction()
  588. </script>
  589. </onexit>
  590. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../computed_outputfunction"/>
  591. <transition port="request" event="small_step" target="../computed_outputfunction">
  592. <raise scope="output" port="reply" event="outbag">
  593. <parameter expr="self.simulation_time"/>
  594. <parameter expr="self.serialize('outbag', self.outbag)"/>
  595. </raise>
  596. </transition>
  597. </state>
  598. <state id="computed_outputfunction">
  599. <onexit>
  600. <script>
  601. self.route_messages()
  602. self.process_injects()
  603. </script>
  604. </onexit>
  605. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../routed_messages">
  606. </transition>
  607. <transition port="request" event="small_step" target="../routed_messages">
  608. <raise scope="output" port="reply" event="inbags">
  609. <parameter expr="self.simulation_time"/>
  610. <parameter expr="self.serialize('inbags', self.inbags)"/>
  611. </raise>
  612. </transition>
  613. </state>
  614. <state id="routed_messages">
  615. <onexit>
  616. <script>
  617. self.find_all_imminents()
  618. </script>
  619. </onexit>
  620. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../found_all_imminents">
  621. </transition>
  622. <transition port="request" event="small_step" target="../found_all_imminents">
  623. <raise scope="output" port="reply" event="transitioning">
  624. <parameter expr="self.simulation_time"/>
  625. <parameter expr="self.serialize('transitioning', self.transitioning)"/>
  626. </raise>
  627. </transition>
  628. </state>
  629. <state id="found_all_imminents">
  630. <onexit>
  631. <script>
  632. self.compute_transitions()
  633. </script>
  634. </onexit>
  635. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../computed_transitions"/>
  636. <transition port="request" event="small_step" target="../computed_transitions">
  637. <raise scope="output" port="reply" event="new_states">
  638. <parameter expr="self.simulation_time"/>
  639. <parameter expr="self.serialize('new_states', self.new_states)"/>
  640. </raise>
  641. </transition>
  642. </state>
  643. <state id="computed_transitions">
  644. <onexit>
  645. <script>
  646. self.compute_ta()
  647. </script>
  648. </onexit>
  649. <transition cond="INSTATE('../../../simulation_state/continuous')" target="../../check_termination"/>
  650. <transition port="request" event="small_step" target="../../check_termination">
  651. <raise scope="output" port="reply" event="new_tn">
  652. <parameter expr="self.simulation_time"/>
  653. <parameter expr="self.serialize('new_tn', self.new_tn)"/>
  654. </raise>
  655. </transition>
  656. <transition cond="INSTATE('../../../simulation_state/realtime') or INSTATE('../../../simulation_state/big_step')" target="../../check_termination">
  657. <raise event="big_step_done"/>
  658. <raise scope="output" port="reply" event="new_states">
  659. <parameter expr="self.simulation_time"/>
  660. <parameter expr="self.serialize('new_states', self.new_states)"/>
  661. </raise>
  662. <raise scope="output" port="reply" event="new_tn">
  663. <parameter expr="self.simulation_time"/>
  664. <parameter expr="self.serialize('new_tn', self.new_tn)"/>
  665. </raise>
  666. </transition>
  667. </state>
  668. </state>
  669. </state>
  670. <state id="simulation_state" initial="paused">
  671. <state id="paused">
  672. <transition port="request" event="simulate" target="../continuous">
  673. <parameter name="configuration" type="dict" default="{}"/>
  674. <script>
  675. self.parse_options(configuration)
  676. </script>
  677. </transition>
  678. <transition port="request" event="realtime" target="../realtime">
  679. <parameter name="configuration" type="dict" default="{}"/>
  680. <script>
  681. self.parse_options(configuration)
  682. </script>
  683. </transition>
  684. <transition port="request" event="big_step" target="../big_step">
  685. <parameter name="configuration" type="dict" default="{}"/>
  686. <script>
  687. self.parse_options(configuration)
  688. </script>
  689. </transition>
  690. </state>
  691. <state id="continuous">
  692. <transition port="request" event="pause" target=".">
  693. <script>
  694. # Just override termination condition
  695. self.termination_condition = lambda i, j, k : True
  696. self.termination_time = None
  697. </script>
  698. </transition>
  699. <transition event="termination_condition" target="../paused">
  700. <raise port="reply" event="terminate">
  701. <parameter expr="self.simulation_time"/>
  702. </raise>
  703. <script>
  704. self.flush_file()
  705. </script>
  706. <raise scope="output" port="reply" event="all_states">
  707. <parameter expr="self.simulation_time"/>
  708. <parameter expr="{m.getModelFullName(): (m.time_next, m.state) for m in self.model.component_set}"/>
  709. </raise>
  710. </transition>
  711. </state>
  712. <state id="realtime">
  713. <transition port="request" event="pause" target=".">
  714. <script>
  715. # Just override termination condition
  716. self.termination_condition = lambda i, j, k : True
  717. self.termination_time = None
  718. # Don't forget to correctly set the simulation time
  719. diff = time.time() - self.realtime_starttime
  720. self.simulation_time = (diff / self.realtime_scale, 1)
  721. </script>
  722. </transition>
  723. <transition event="termination_condition" target="../paused">
  724. <raise port="reply" event="terminate">
  725. <parameter expr="self.simulation_time"/>
  726. </raise>
  727. <script>
  728. self.flush_file()
  729. </script>
  730. </transition>
  731. </state>
  732. <state id="big_step">
  733. <transition event="big_step_done" target="../paused"/>
  734. <transition event="termination_condition" target="../paused">
  735. <raise port="reply" event="terminate">
  736. <parameter expr="self.simulation_time"/>
  737. </raise>
  738. <script>
  739. self.flush_file()
  740. </script>
  741. </transition>
  742. </state>
  743. </state>
  744. <state id="breakpoint_manager">
  745. <state id="breakpoint_manage">
  746. <transition port="request" event="add_breakpoint" target=".">
  747. <parameter name="breakpoint_id"/>
  748. <parameter name="function"/>
  749. <parameter name="enabled"/>
  750. <parameter name="disable_on_trigger"/>
  751. <script>
  752. self.breakpoints.append(Breakpoint(breakpoint_id, function, enabled, disable_on_trigger))
  753. </script>
  754. </transition>
  755. <transition port="request" event="del_breakpoint" target=".">
  756. <parameter name="del_breakpoint_id"/>
  757. <script>
  758. self.breakpoints = [breakpoint for breakpoint in self.breakpoints if breakpoint.id != del_breakpoint_id]
  759. </script>
  760. </transition>
  761. <transition port="request" event="toggle_breakpoint" target=".">
  762. <parameter name="breakpoint_id"/>
  763. <parameter name="enabled"/>
  764. <script>
  765. for breakpoint in self.breakpoints:
  766. if breakpoint.id == breakpoint_id:
  767. breakpoint.enabled = enabled
  768. break
  769. </script>
  770. </transition>
  771. </state>
  772. </state>
  773. <state id="reset">
  774. <state id="reset">
  775. <transition port="request" event="reset" target=".">
  776. <script>
  777. for model in self.model.component_set:
  778. model.state = pickle.loads(self.save_model[model][1])
  779. model.elapsed = self.save_model[model][0]
  780. model.timeLast = (-model.elapsed, 1)
  781. ta = model.timeAdvance()
  782. model.time_next = (model.timeLast[0] + ta, 1)
  783. self.simulation_time = (0.0, 0)
  784. self.model.scheduler.massReschedule(self.model.component_set)
  785. # Reset trace file
  786. if self.trace_file is not None:
  787. self.trace_file = open(self.trace_file.name, 'w')
  788. </script>
  789. <raise scope="output" port="reply" event="all_states">
  790. <parameter expr="(0.0, 0)"/>
  791. <parameter expr="{m.getModelFullName(): (m.time_next, m.state) for m in self.model.component_set}"/>
  792. </raise>
  793. </transition>
  794. </state>
  795. </state>
  796. </parallel>
  797. </scxml>
  798. </class>
  799. </diagram>