sccd_fixed_reset.xml 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082
  1. <?xml version="1.0" ?>
  2. <diagram author="Simon Van Mierlo/Yentl Van Tendeloo" name="Dynamic Structure 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. import copy
  10. # We basically just interface with the basesimulator
  11. from scheduler import Scheduler
  12. from DEVS import directConnect, CoupledDEVS, AtomicDEVS, RootDEVS
  13. from classicDEVSWrapper import ClassicDEVSWrapper
  14. from tracer import trace
  15. class Breakpoint(object):
  16. def __init__(self, breakpoint_id, function, enabled, disable_on_trigger):
  17. self.id = breakpoint_id
  18. self.function = function
  19. self.enabled = enabled
  20. self.disable_on_trigger = disable_on_trigger
  21. </top>
  22. <inport name="request"/>
  23. <outport name="reply"/>
  24. <class name="SCCDSimulator" default="true">
  25. <!-- Define the constructor, taking the model to simulate as a parameter -->
  26. <constructor>
  27. <parameter name="model"/>
  28. <body>
  29. <![CDATA[
  30. self.model = model
  31. self.save_model = pickle.dumps(self.model, pickle.HIGHEST_PROTOCOL)
  32. self.listeners_by_string = {}
  33. # Simulation variables
  34. self.termination_time = None
  35. self.termination_condition = None
  36. self.simulation_time = (0.0, 0)
  37. self.listeners = {}
  38. self.root_model = model
  39. self.realtime_scale = 1.0
  40. # Values to be set during simulation
  41. self.realtime_starttime = None
  42. self.inject_queue = []
  43. # Model initialization
  44. self.model_ids = []
  45. self.model.finalize(name="", model_counter=0, model_ids=self.model_ids, locations={None: []}, select_hierarchy=[])
  46. ]]>
  47. </body>
  48. </constructor>
  49. <!-- Serialize the output values in something human-readable instead of internal objects.
  50. Note that this doesn't alter the internal structure, as that is still used for simulation. -->
  51. <method name="serialize">
  52. <parameter name="type"/>
  53. <parameter name="object"/>
  54. <body>
  55. <![CDATA[
  56. if type == "imminents":
  57. return [m.getModelFullName() for m in object]
  58. elif type == "imminent":
  59. return object.getModelFullName()
  60. elif type == "inbags" or type == "outbag":
  61. return {m.getPortFullName(): object[m] for m in object}
  62. elif type == "new_tn" or type == "new_states":
  63. return {m.getModelFullName(): object[m] for m in object if m.model_id is not None}
  64. elif type == "transitioning":
  65. return {m.getModelFullName(): {1: "INTERNAL", 2: "EXTERNAL"}[object[m]] for m in object if m.model_id is not None}
  66. ]]>
  67. </body>
  68. </method>
  69. <!-- Find a port based on a fully qualified name. -->
  70. <method name="find_port_with_name">
  71. <parameter name="name"/>
  72. <body>
  73. <![CDATA[
  74. for model in self.model.component_set:
  75. if name.startswith(model.getModelFullName()):
  76. # Found a potential model
  77. # We can't simply check for equality, as portnames might contain dots too
  78. for port in model.IPorts:
  79. if port.getPortFullName() == name:
  80. # Now everything matches
  81. return port
  82. # Nothing found
  83. return None
  84. ]]>
  85. </body>
  86. </method>
  87. <!-- Find a model based on a fully qualified name. -->
  88. <method name="find_model_with_name">
  89. <parameter name="name"/>
  90. <body>
  91. <![CDATA[
  92. for model in self.model.component_set:
  93. if name == model.getModelFullName():
  94. # Found exact match
  95. return model
  96. return None
  97. ]]>
  98. </body>
  99. </method>
  100. <!-- Calculate the time to wait before triggering the next transition.
  101. This method is also called in non-realtime simulation, so make sure that it returns infinity in that case. -->
  102. <method name="calculate_after">
  103. <body>
  104. <![CDATA[
  105. try:
  106. # Process in parts of 100 milliseconds to repeatedly check the termination condition
  107. if self.interrupt_string:
  108. nexttime = 0.0
  109. else:
  110. nexttime = (self.time_next[0] - (time.time() - self.realtime_starttime) / self.realtime_scale) * self.realtime_scale
  111. x = min(0.1, nexttime)
  112. return x
  113. except TypeError, AttributeError:
  114. # We are probably not simulating in realtime...
  115. return float('inf')
  116. ]]>
  117. </body>
  118. </method>
  119. <!-- Parse a list of options that can be passed together with the request -->
  120. <method name="parse_options">
  121. <parameter name="configuration"/>
  122. <body>
  123. <![CDATA[
  124. self.termination_condition = None if "termination_condition" not in configuration else configuration["termination_condition"]
  125. self.termination_time = None if "termination_time" not in configuration else configuration["termination_time"]
  126. self.realtime_scale = 1.0 if "realtime_scale" not in configuration else 1.0/configuration["realtime_scale"]
  127. # Subtract the current simulation time to allow for pausing
  128. self.realtime_starttime = (time.time() - self.simulation_time[0]*self.realtime_scale)
  129. # Reset the time used in the waiting, as it might not get recomputed
  130. self.the_time = 0.00001
  131. ]]>
  132. </body>
  133. </method>
  134. <!-- Utility function to determine whether or not simulation is finished. -->
  135. <method name="should_terminate">
  136. <parameter name="realtime"/>
  137. <body>
  138. <![CDATA[
  139. # Now that it includes breakpoints, results are to be interpretted as follows:
  140. # -2 --> continue simulation
  141. # -1 --> termination condition
  142. # else --> breakpoint
  143. if realtime:
  144. check_time = self.simulation_time
  145. else:
  146. self.compute_timeNext()
  147. check_time = self.time_next
  148. # Just access the 'transitioned' dictionary
  149. # Kind of dirty though...
  150. if self.transitioning is None:
  151. transitioned = set()
  152. else:
  153. transitioned = set(self.transitioning.keys())
  154. if check_time[0] == float('inf'):
  155. # Always terminate if we have reached infinity
  156. terminate = True
  157. elif self.termination_condition is not None:
  158. terminate = self.termination_condition(check_time, self.root_model, transitioned)
  159. else:
  160. terminate = self.termination_time < check_time[0]
  161. if terminate:
  162. # Always terminate, so don't check breakpoints
  163. return -1
  164. else:
  165. # Have to check breakpoints for termination
  166. for bp in self.breakpoints:
  167. if not bp.enabled:
  168. continue
  169. # Include the function in the scope
  170. exec(bp.function)
  171. # And execute it, note that the breakpoint thus has to start with "def breakpoint("
  172. if breakpoint(check_time, self.root_model, transitioned):
  173. # Triggered!
  174. return bp.id
  175. else:
  176. # Not triggered, so continue
  177. continue
  178. return -2
  179. ]]>
  180. </body>
  181. </method>
  182. <!-- Compute all models of which the internal transition function has to be triggered. -->
  183. <method name="find_internal_imminents">
  184. <body>
  185. <![CDATA[
  186. self.imminents = self.model.scheduler.getImminent(self.simulation_time)
  187. self.reschedule = set(self.imminents)
  188. self.transition_times.append(self.simulation_time)
  189. for model in self.imminents:
  190. model.time_next = (model.time_next[0], model.time_next[1] + 1)
  191. ]]>
  192. </body>
  193. </method>
  194. <!-- Select one of the imminent components -->
  195. <method name="select_imminent">
  196. <body>
  197. <![CDATA[
  198. self.imminent = None
  199. if len(self.imminents) > 1:
  200. # Perform all selects
  201. self.imminents.sort()
  202. pending = self.imminents
  203. level = 1
  204. while len(pending) > 1:
  205. # Take the model each time, as we need to make sure that the selectHierarchy is valid everywhere
  206. model = pending[0]
  207. # Make a set first to remove duplicates
  208. colliding = list(set([m.select_hierarchy[level] for m in pending]))
  209. chosen = model.select_hierarchy[level-1].select(
  210. sorted(colliding, key=lambda i:i.getModelFullName()))
  211. pending = [m for m in pending
  212. if m.select_hierarchy[level] == chosen]
  213. level += 1
  214. self.imminent = pending[0]
  215. else:
  216. self.imminent = self.imminents[0]
  217. self.imminent.time_next = (self.imminent.time_next[0], self.imminent.time_next[1] - 1)
  218. ]]>
  219. </body>
  220. </method>
  221. <!-- Trigger all output functions of imminent models. -->
  222. <method name="compute_outputfunction">
  223. <body>
  224. <![CDATA[
  225. self.outbag = ClassicDEVSWrapper(self.imminent).outputFnc()
  226. ]]>
  227. </body>
  228. </method>
  229. <!-- Route all messages and apply the required transfer functions. -->
  230. <method name="route_messages">
  231. <body>
  232. <![CDATA[
  233. self.inbags = {}
  234. for outport in self.outbag:
  235. payload = self.outbag[outport]
  236. for inport, z in outport.routing_outline:
  237. if z is not None:
  238. payload = [z(pickle.loads(pickle.dumps(m))) for m in payload]
  239. self.inbags.setdefault(inport, []).extend(payload)
  240. ]]>
  241. </body>
  242. </method>
  243. <!-- Process the injects on the inject_queue.
  244. Also process realtime interrupts.
  245. 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? -->
  246. <method name="process_injects">
  247. <body>
  248. <![CDATA[
  249. while self.inject_queue:
  250. if self.inject_queue[0]["time"] > self.simulation_time:
  251. break
  252. config = self.inject_queue.pop(0)
  253. portname = config["port"]
  254. event = config["event"]
  255. port = self.find_port_with_name(portname)
  256. self.inbags.setdefault(port, []).append(event)
  257. if self.interrupt_string:
  258. portname, event_value = self.interrupt_string.split(" ")
  259. for inport, z in self.root_model.ports[portname].routing_outline:
  260. ev = event_value if z is None else z(event_value)
  261. self.inbags.setdefault(inport, []).append(ev)
  262. self.interrupt_string = None
  263. ]]>
  264. </body>
  265. </method>
  266. <!-- Combine the information from the routed messages to determine the external and internal transition functions to trigger. -->
  267. <method name="find_all_imminents">
  268. <body>
  269. <![CDATA[
  270. # Internal codes:
  271. # 1 --> internal transition
  272. # 2 --> external transition
  273. # 3 --> confluent transition
  274. # These codes are a legacy of efficient PyPDEVS, but is kept here for consistency
  275. self.transitioning = {self.imminent: 1}
  276. for inport in self.inbags:
  277. aDEVS = inport.host_DEVS
  278. aDEVS.my_input[inport] = self.inbags[inport]
  279. self.transitioning[aDEVS] = 2
  280. self.reschedule.add(aDEVS)
  281. self.transitioning = {ClassicDEVSWrapper(m): self.transitioning[m]
  282. for m in self.transitioning}
  283. ]]>
  284. </body>
  285. </method>
  286. <!-- Trigger all transition functions. -->
  287. <method name="compute_transitions">
  288. <body>
  289. <![CDATA[
  290. self.new_states = {}
  291. for aDEVS in self.transitioning:
  292. aDEVS.my_input = {key: pickle.loads(pickle.dumps(aDEVS.my_input[key], pickle.HIGHEST_PROTOCOL)) for key in aDEVS.my_input}
  293. if self.transitioning[aDEVS] == 1:
  294. aDEVS.state = aDEVS.intTransition()
  295. elif self.transitioning[aDEVS] == 2:
  296. aDEVS.elapsed = self.simulation_time[0] - aDEVS.time_last[0]
  297. aDEVS.state = aDEVS.extTransition(aDEVS.my_input)
  298. aDEVS.old_states.append((self.simulation_time, pickle.dumps(aDEVS.state)))
  299. aDEVS.my_input = {}
  300. self.new_states[aDEVS] = aDEVS.state
  301. ]]>
  302. </body>
  303. </method>
  304. <!-- Trigger all timeAdvance functions. -->
  305. <method name="compute_ta">
  306. <body>
  307. <![CDATA[
  308. self.new_tn = {}
  309. t, age = self.simulation_time
  310. for aDEVS in self.transitioning:
  311. ta = aDEVS.timeAdvance()
  312. aDEVS.time_last = self.simulation_time
  313. aDEVS.time_next = (t + ta, 1 if ta else (age + 1))
  314. self.new_tn[aDEVS] = aDEVS.time_next
  315. trace(self.trace_file, self.transitioning[aDEVS], aDEVS)
  316. self.model.scheduler.massReschedule(self.reschedule)
  317. self.time_next = self.model.scheduler.readFirst()
  318. ]]>
  319. </body>
  320. </method>
  321. <method name="dsRemovePort">
  322. <parameter name="port" />
  323. <body>
  324. <![CDATA[
  325. for iport in port.inline:
  326. iport.outline = [p for p in iport.outline if p != port]
  327. for oport in port.outline:
  328. oport.inline = [p for p in oport.inline if p != port]
  329. self.dc_altered.add(port)
  330. self.structural_changes.setdefault('REMOVED_PORTS', []).append(port)
  331. ]]>
  332. </body>
  333. </method>
  334. <method name="dsDisonnectPorts">
  335. <parameter name="p1" />
  336. <parameter name="p2" />
  337. <body>
  338. <![CDATA[
  339. self.dc_altered.add(p1)
  340. self.structural_changes.setdefault('DISCONNECTED_PORTS', []).append((p1, p2))
  341. ]]>
  342. </body>
  343. </method>
  344. <method name="dsConnectPorts">
  345. <parameter name="p1" />
  346. <parameter name="p2" />
  347. <body>
  348. <![CDATA[
  349. self.dc_altered.add(p1)
  350. self.structural_changes.setdefault('CONNECTED_PORTS', []).append((p1, p2))
  351. ]]>
  352. </body>
  353. </method>
  354. <method name="dsUnscheduleModel">
  355. <parameter name="model" />
  356. <body>
  357. <![CDATA[
  358. if isinstance(model, CoupledDEVS):
  359. for m in model.component_set:
  360. self.dsUnscheduleModel(m, False)
  361. for port in model.IPorts:
  362. self.dsRemovePort(port)
  363. for port in model.OPorts:
  364. self.dsRemovePort(port)
  365. elif isinstance(model, AtomicDEVS):
  366. self.model.component_set.remove(model)
  367. self.model.models.remove(model)
  368. # The model is removed, so remove it from the scheduler
  369. self.model.scheduler.unschedule(model)
  370. self.model_ids[model.model_id] = None
  371. self.model.local_model_ids.remove(model.model_id)
  372. for port in model.IPorts:
  373. self.dsRemovePort(port)
  374. for port in model.OPorts:
  375. self.dsRemovePort(port)
  376. else:
  377. raise DEVSException("Unknown model to schedule: %s" % model)
  378. self.structural_changes.setdefault('DELETED_MODELS', []).append(model)
  379. ]]>
  380. </body>
  381. </method>
  382. <method name="dsScheduleModel">
  383. <parameter name="model" />
  384. <body>
  385. <![CDATA[
  386. if isinstance(model, CoupledDEVS):
  387. model.full_name = model.parent.full_name + "." + model.getModelName()
  388. for m in model.component_set:
  389. self.dsScheduleModel(m)
  390. elif isinstance(model, AtomicDEVS):
  391. model.model_id = len(self.model_ids)
  392. model.full_name = model.parent.full_name + "." + model.getModelName()
  393. self.model_ids.append(model)
  394. self.model.component_set.append(model)
  395. self.model.models.append(model)
  396. self.model.local_model_ids.add(model.model_id)
  397. model.time_last = (self.simulation_time[0] - model.elapsed, 1)
  398. ta = model.timeAdvance()
  399. if ta < 0:
  400. raise DEVSException("Negative time advance in atomic model '" + \
  401. model.getModelFullName() + "' with value " + \
  402. str(ta) + " at initialisation")
  403. model.time_next = (model.time_last[0] + ta, 1)
  404. model.old_states.append((self.simulation_time, pickle.dumps(model.state)))
  405. p = model.parent
  406. model.select_hierarchy = [model]
  407. while p != None:
  408. model.select_hierarchy = [p] + model.select_hierarchy
  409. p = p.parent
  410. if model.time_next[0] == self.simulation_time[0]:
  411. model.time_next = (model.time_next[0], self.simulation_time[1])
  412. # If scheduled for 'now', update the age manually
  413. # It is a new model, so add it to the scheduler too
  414. self.model.scheduler.schedule(model)
  415. else:
  416. raise DEVSException("Unknown model to schedule: %s" % model)
  417. self.structural_changes.setdefault('CREATED_MODELS', []).append(model)
  418. ]]>
  419. </body>
  420. </method>
  421. <method name="getSelfProxy">
  422. <body>
  423. <![CDATA[
  424. return self
  425. ]]>
  426. </body>
  427. </method>
  428. <!-- Process dynamic structure changes. -->
  429. <method name="process_structure_changes">
  430. <body>
  431. <![CDATA[
  432. self.structural_changes = {}
  433. self.dc_altered = set()
  434. dsdevs_dict = {}
  435. for m in self.transitioning:
  436. m.server = self
  437. iterlist = [aDEVS.parent for aDEVS in self.transitioning
  438. if aDEVS.modelTransition(dsdevs_dict)]
  439. # Contains all models that are already checked, to prevent duplicate checking.
  440. # This was not necessary for atomic models, as they are guaranteed to only be called
  441. # once, as they have no children to induce a structural change on them
  442. checked = set()
  443. while iterlist:
  444. new_iterlist = []
  445. for cDEVS in iterlist:
  446. cDEVS.server = self
  447. if cDEVS is None:
  448. # Problematic
  449. #assert warning("Root DEVS returned True in the modelTransition method; ignoring")
  450. continue
  451. if cDEVS in checked:
  452. continue
  453. checked.add(cDEVS)
  454. if cDEVS.modelTransition(dsdevs_dict):
  455. new_iterlist.append(cDEVS.parent)
  456. cDEVS.server = None
  457. # Don't update the iterlist while we are iterating over it
  458. iterlist = new_iterlist
  459. if self.dc_altered:
  460. self.model.redoDirectConnection(self.dc_altered)
  461. for m in self.transitioning:
  462. m.server = None
  463. ]]>
  464. </body>
  465. </method>
  466. <method name="flush_file">
  467. <body>
  468. <![CDATA[
  469. if self.trace_file is not None:
  470. self.trace_file.flush()
  471. ]]>
  472. </body>
  473. </method>
  474. <method name="process_breakpoints">
  475. <parameter name="realtime"/>
  476. <body>
  477. <![CDATA[
  478. breakpoint_id = self.should_terminate(realtime)
  479. for breakpoint in self.breakpoints:
  480. if breakpoint.id == breakpoint_id:
  481. if breakpoint.disable_on_trigger:
  482. breakpoint.enabled = False
  483. return breakpoint_id
  484. ]]>
  485. </body>
  486. </method>
  487. <method name="compute_timeNext">
  488. <body>
  489. <![CDATA[
  490. model_timeNext = self.model.scheduler.readFirst()
  491. if len(self.inject_queue) > 0:
  492. self.time_next = min(model_timeNext, self.inject_queue[0]["time"])
  493. else:
  494. self.time_next = model_timeNext
  495. ]]>
  496. </body>
  497. </method>
  498. <method name="rollback_step">
  499. <body>
  500. <![CDATA[
  501. if len(self.transition_times) == 0:
  502. return
  503. new_time = self.transition_times.pop()
  504. for model in self.model.component_set:
  505. if model.old_states[-1][0] == new_time:
  506. # Remove the current state
  507. del model.old_states[-1]
  508. # Set the new (old...) state
  509. new_state = model.old_states[-1]
  510. model.state = pickle.loads(new_state[1])
  511. model.time_last = new_state[0]
  512. ta = model.timeAdvance()
  513. model.time_next = (model.time_last[0] + ta, model.time_last[1] + 1 if ta == 0 else 0)
  514. self.model.scheduler.massReschedule([model])
  515. self.simulation_time = self.transition_times[-1] if len(self.transition_times) > 0 else (0.0, 0)
  516. ]]>
  517. </body>
  518. </method>
  519. <scxml initial="initializing">
  520. <state id="initializing">
  521. <transition target="../main">
  522. <script>
  523. <![CDATA[
  524. # Direct connection
  525. if isinstance(self.model, CoupledDEVS):
  526. self.model.component_set = directConnect(self.model.component_set, self.listeners)
  527. self.model = RootDEVS(self.model.component_set, self.model.component_set, None)
  528. self.model.listeners = self.listeners
  529. for m in self.model.component_set:
  530. m.time_last = (-m.elapsed, 1)
  531. ta = m.timeAdvance()
  532. m.time_next = (m.time_last[0] + ta, 1)
  533. m.old_states = [(m.time_last, pickle.dumps(m.state))]
  534. elif isinstance(self.model, AtomicDEVS):
  535. for p in self.model.IPorts:
  536. p.routing_inline = []
  537. p.routing_outline = []
  538. for p in self.model.OPorts:
  539. p.routing_inline = []
  540. p.routing_outline = []
  541. self.model = RootDEVS([self.model], [self.model], None)
  542. self.model.time_last = (-self.model.elapsed, 1)
  543. ta = self.model.timeAdvance()
  544. self.model.time_next = (self.model.time_last[0] + ta, 1)
  545. # Fixed configuration options
  546. self.model.scheduler = Scheduler(self.model.component_set, 1e-6, len(self.model.component_set))
  547. self.time_next = self.model.scheduler.readFirst()
  548. # Cached values
  549. self.imminents = None
  550. self.outbag = None
  551. self.inbags = None
  552. self.transitioning = None
  553. self.new_states = None
  554. self.new_tn = None
  555. # Verbose trace file
  556. self.trace_file = None
  557. # Breakpoint management
  558. self.breakpoints = []
  559. # For a reset
  560. # self.save_model = {model: (model.elapsed, pickle.dumps(model.state, pickle.HIGHEST_PROTOCOL)) for model in self.model.component_set}
  561. # self.save_model = pickle.dumps(self.model, pickle.HIGHEST_PROTOCOL)
  562. self.transition_times = []
  563. self.interrupt_string = None
  564. ]]>
  565. </script>
  566. </transition>
  567. </state>
  568. <!-- Parallel states: one of them controls the simulation flow, the other the type of simulation being performed. -->
  569. <parallel id="main">
  570. <!-- When an injection is received, just append it to the list of pending injections.
  571. These will be processed as soon as the current simulation step is finished.
  572. Afterwards, return to the previous state, as there was no change of state. -->
  573. <state id="injection_monitor">
  574. <state id="inject">
  575. <transition port="request" event="inject" target=".">
  576. <parameter name="configuration"/>
  577. <script>
  578. configuration["time"] = (configuration["time"], 1)
  579. self.inject_queue.append(configuration)
  580. self.inject_queue.sort(key=lambda i: i["time"])
  581. </script>
  582. <raise scope="output" port="reply" event="inject_ok"/>
  583. </transition>
  584. </state>
  585. </state>
  586. <state id="tracer_monitor">
  587. <state id="trace">
  588. <transition port="request" event="trace" target=".">
  589. <parameter name="filename"/>
  590. <script>
  591. if filename is not None:
  592. self.trace_file = open(filename, 'w')
  593. else:
  594. self.trace_file = None
  595. </script>
  596. <raise scope="output" port="reply" event="trace_config_ok"/>
  597. </transition>
  598. </state>
  599. </state>
  600. <state id="realtime_interrupt_monitor">
  601. <state id="realtime_interrupt">
  602. <transition target="." port="request" event="realtime_interrupt">
  603. <parameter name="interrupt_string" />
  604. <script>
  605. self.interrupt_string = interrupt_string
  606. </script>
  607. </transition>
  608. </state>
  609. </state>
  610. <!-- The main parallel component: the simulation flow. -->
  611. <state id="simulation_flow" initial="initialize">
  612. <state id="initialize">
  613. <transition target="../check_termination">
  614. <raise scope="output" port="reply" event="all_states">
  615. <parameter expr="self.simulation_time"/>
  616. <parameter expr="{m.getModelFullName(): (m.time_next, m.state) for m in self.model.component_set}"/>
  617. </raise>
  618. </transition>
  619. </state>
  620. <state id="check_termination" initial="workaround">
  621. <onexit>
  622. <script>
  623. self.simulation_time = self.time_next
  624. </script>
  625. </onexit>
  626. <state id="workaround">
  627. <transition after="0" target="../check_termination"/>
  628. </state>
  629. <state id="wait">
  630. <onexit>
  631. <script>
  632. diff = time.time() - self.realtime_starttime
  633. self.simulation_time = (diff / self.realtime_scale, 1)
  634. </script>
  635. </onexit>
  636. <transition after="self.calculate_after()" target="../check_termination"/>
  637. <transition cond="INSTATE('../../../simulation_state/paused')" target="../check_termination"/>
  638. </state>
  639. <state id="small_step_check">
  640. <transition cond="self.should_terminate(False) == -2" target="../../do_simulation"/>
  641. <transition cond="self.should_terminate(False) == -1" target="../check_termination">
  642. <raise event="termination_condition"/>
  643. </transition>
  644. <transition cond="self.should_terminate(False) &gt; -1" target="../check_termination">
  645. <script>
  646. breakpoint_id = self.process_breakpoints(False)
  647. </script>
  648. <raise scope="output" port="reply" event="breakpoint_triggered">
  649. <parameter expr="breakpoint_id"/>
  650. </raise>
  651. <raise event="termination_condition"/>
  652. </transition>
  653. </state>
  654. <state id="check_termination">
  655. <onentry>
  656. <script>
  657. self.compute_timeNext()
  658. self.the_time = self.calculate_after()
  659. </script>
  660. </onentry>
  661. <!-- Continue simulation -->
  662. <transition cond="INSTATE('../../../simulation_state/continuous') and (self.should_terminate(False) == -2)" target="../../do_simulation"/>
  663. <transition cond="INSTATE('../../../simulation_state/big_step') and (self.should_terminate(False) == -2)" target="../../do_simulation"/>
  664. <!-- Realtime and didn't reach the required time_next yet -->
  665. <transition cond="INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) == -2) and (self.the_time &gt; 0.0)" target="../wait"/>
  666. <transition cond="INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) == -2) and (self.the_time &lt;= 0.0)" target="../../do_simulation"/>
  667. <transition port="request" event="small_step" target="../small_step_check">
  668. <parameter name="configuration" type="dict" default="{}"/>
  669. <script>
  670. self.parse_options(configuration)
  671. </script>
  672. </transition>
  673. <!-- Pause simulation -->
  674. <transition cond="(not INSTATE('../../../simulation_state/paused') and INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) == -1))" target="../workaround">
  675. <raise event="termination_condition"/>
  676. </transition>
  677. <transition cond="(not INSTATE('../../../simulation_state/paused') and not INSTATE('../../../simulation_state/realtime') and (self.should_terminate(False) == -1))" target="../workaround">
  678. <raise event="termination_condition"/>
  679. </transition>
  680. <transition cond="(not INSTATE('../../../simulation_state/paused')) and INSTATE('../../../simulation_state/realtime') and (self.should_terminate(True) &gt; -1)" target="../workaround">
  681. <script>
  682. breakpoint_id = self.process_breakpoints(True)
  683. </script>
  684. <raise scope="output" port="reply" event="breakpoint_triggered">
  685. <parameter expr="breakpoint_id"/>
  686. </raise>
  687. <raise event="termination_condition"/>
  688. </transition>
  689. <transition cond="(not INSTATE('../../../simulation_state/paused')) and not INSTATE('../../../simulation_state/realtime') and (self.should_terminate(False) &gt; -1)" target="../workaround">
  690. <script>
  691. breakpoint_id = self.process_breakpoints(False)
  692. </script>
  693. <raise scope="output" port="reply" event="breakpoint_triggered">
  694. <parameter expr="breakpoint_id"/>
  695. </raise>
  696. <raise event="termination_condition"/>
  697. </transition>
  698. <!-- Process god event -->
  699. <transition cond="INSTATE('../../../simulation_state/paused')" port="request" event="god_event" target="../workaround">
  700. <parameter name="configuration"/>
  701. <script>
  702. modelname = configuration["model"]
  703. state_attribute = configuration["attribute"]
  704. new_value = configuration["value"]
  705. model = self.find_model_with_name(modelname)
  706. setattr(model.state, state_attribute, new_value)
  707. # Call the timeadvance method again and compute new ta
  708. ta = model.timeAdvance()
  709. model.time_next = (model.time_last[0] + ta, 1 if ta else (model.time_last[1] + 1))
  710. self.model.scheduler.massReschedule([model])
  711. # self.simulation_time = self.model.scheduler.readFirst()
  712. </script>
  713. <raise scope="output" port="reply" event="god_event_ok">
  714. <parameter expr="{model.getModelFullName(): str(model.state)}"/>
  715. </raise>
  716. <raise scope="output" port="reply" event="new_tn">
  717. <parameter expr="self.simulation_time"/>
  718. <parameter expr="{model.getModelFullName(): model.time_next}"/>
  719. </raise>
  720. </transition>
  721. <!-- Omniscient debugging -->
  722. <transition cond="INSTATE('../../../simulation_state/paused')" port="request" event="backwards_step" target="../workaround">
  723. <script>
  724. self.rollback_step()
  725. </script>
  726. <raise scope="output" port="reply" event="all_states">
  727. <parameter expr="self.simulation_time"/>
  728. <parameter expr="{m.getModelFullName(): (m.time_next, m.state) for m in self.model.component_set}"/>
  729. </raise>
  730. </transition>
  731. </state>
  732. </state>
  733. <state id="do_simulation" initial="init">
  734. <state id="init">
  735. <onexit>
  736. <script>
  737. self.find_internal_imminents()
  738. </script>
  739. </onexit>
  740. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../found_internal_imminents"/>
  741. <!-- Always output this if paused, as we only got here because a small step was fired previously -->
  742. <transition cond="INSTATE('../../../simulation_state/paused')" target="../found_internal_imminents">
  743. <raise scope="output" port="reply" event="imminents">
  744. <parameter expr="self.simulation_time"/>
  745. <parameter expr="self.serialize('imminents', self.imminents)"/>
  746. </raise>
  747. </transition>
  748. </state>
  749. <state id="found_internal_imminents">
  750. <onexit>
  751. <script>
  752. self.select_imminent()
  753. </script>
  754. </onexit>
  755. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../selected_imminent"/>
  756. <transition port="request" event="small_step" target="../selected_imminent">
  757. <raise scope="output" port="reply" event="selected_imminent">
  758. <parameter expr="self.simulation_time"/>
  759. <parameter expr="self.serialize('imminent', self.imminent)"/>
  760. </raise>
  761. </transition>
  762. </state>
  763. <state id="selected_imminent">
  764. <onexit>
  765. <script>
  766. self.compute_outputfunction()
  767. </script>
  768. </onexit>
  769. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../computed_outputfunction"/>
  770. <transition port="request" event="small_step" target="../computed_outputfunction">
  771. <raise scope="output" port="reply" event="outbag">
  772. <parameter expr="self.simulation_time"/>
  773. <parameter expr="self.serialize('outbag', self.outbag)"/>
  774. </raise>
  775. </transition>
  776. </state>
  777. <state id="computed_outputfunction">
  778. <onexit>
  779. <script>
  780. self.route_messages()
  781. self.process_injects()
  782. </script>
  783. </onexit>
  784. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../routed_messages">
  785. </transition>
  786. <transition port="request" event="small_step" target="../routed_messages">
  787. <raise scope="output" port="reply" event="inbags">
  788. <parameter expr="self.simulation_time"/>
  789. <parameter expr="self.serialize('inbags', self.inbags)"/>
  790. </raise>
  791. </transition>
  792. </state>
  793. <state id="routed_messages">
  794. <onexit>
  795. <script>
  796. self.find_all_imminents()
  797. </script>
  798. </onexit>
  799. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../found_all_imminents">
  800. </transition>
  801. <transition port="request" event="small_step" target="../found_all_imminents">
  802. <raise scope="output" port="reply" event="transitioning">
  803. <parameter expr="self.simulation_time"/>
  804. <parameter expr="self.serialize('transitioning', self.transitioning)"/>
  805. </raise>
  806. </transition>
  807. </state>
  808. <state id="found_all_imminents">
  809. <onexit>
  810. <script>
  811. self.compute_transitions()
  812. </script>
  813. </onexit>
  814. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../computed_transitions"/>
  815. <transition port="request" event="small_step" target="../computed_transitions">
  816. <raise scope="output" port="reply" event="new_states">
  817. <parameter expr="self.simulation_time"/>
  818. <parameter expr="self.serialize('new_states', self.new_states)"/>
  819. </raise>
  820. </transition>
  821. </state>
  822. <state id="computed_transitions">
  823. <onexit>
  824. <script>
  825. self.compute_ta()
  826. </script>
  827. </onexit>
  828. <transition cond="not INSTATE('../../../simulation_state/paused')" target="../computed_ta"/>
  829. <transition port="request" event="small_step" target="../computed_ta">
  830. <raise scope="output" port="reply" event="new_tn">
  831. <parameter expr="self.simulation_time"/>
  832. <parameter expr="self.serialize('new_tn', self.new_tn)"/>
  833. </raise>
  834. </transition>
  835. </state>
  836. <state id="computed_ta">
  837. <onexit>
  838. <script>
  839. self.process_structure_changes()
  840. </script>
  841. </onexit>
  842. <transition cond="INSTATE('../../../simulation_state/continuous')" target="../../check_termination"/>
  843. <transition port="request" event="small_step" target="../../check_termination">
  844. <raise scope="output" port="reply" event="structural_changes">
  845. <parameter expr="self.structural_changes"/>
  846. </raise>
  847. </transition>
  848. <transition cond="INSTATE('../../../simulation_state/realtime') or INSTATE('../../../simulation_state/big_step')" target="../../check_termination">
  849. <raise event="big_step_done"/>
  850. <raise scope="output" port="reply" event="new_states">
  851. <parameter expr="self.simulation_time"/>
  852. <parameter expr="self.serialize('new_states', self.new_states)"/>
  853. <parameter expr="self.serialize('new_tn', self.new_tn)"/>
  854. <parameter expr="self.structural_changes"/>
  855. </raise>
  856. </transition>
  857. </state>
  858. </state>
  859. </state>
  860. <state id="simulation_state" initial="paused">
  861. <state id="paused">
  862. <transition port="request" event="simulate" target="../continuous">
  863. <parameter name="configuration" type="dict" default="{}"/>
  864. <script>
  865. self.parse_options(configuration)
  866. </script>
  867. </transition>
  868. <transition port="request" event="realtime" target="../realtime">
  869. <parameter name="configuration" type="dict" default="{}"/>
  870. <script>
  871. self.parse_options(configuration)
  872. </script>
  873. </transition>
  874. <transition port="request" event="big_step" target="../big_step">
  875. <parameter name="configuration" type="dict" default="{}"/>
  876. <script>
  877. self.parse_options(configuration)
  878. </script>
  879. </transition>
  880. </state>
  881. <state id="continuous">
  882. <onentry>
  883. <script>
  884. #self.model.listeners = {}
  885. #self.model.directConnect()
  886. self.model.listeners = {}
  887. self.model.component_set = directConnect(self.model.models, {})
  888. </script>
  889. </onentry>
  890. <transition port="request" event="pause" target=".">
  891. <script>
  892. # Just override termination condition
  893. self.termination_condition = lambda i, j, k : True
  894. self.termination_time = None
  895. </script>
  896. </transition>
  897. <transition event="termination_condition" target="../paused">
  898. <raise port="reply" event="terminate">
  899. <parameter expr="self.simulation_time"/>
  900. </raise>
  901. <script>
  902. self.flush_file()
  903. </script>
  904. <raise scope="output" port="reply" event="all_states">
  905. <parameter expr="self.simulation_time"/>
  906. <parameter expr="{m.getModelFullName(): (m.time_next, m.state) for m in self.model.component_set}"/>
  907. </raise>
  908. </transition>
  909. </state>
  910. <state id="realtime">
  911. <onentry>
  912. <script>
  913. #self.model.listeners = self.listeners
  914. #self.model.directConnect()
  915. self.listeners = {getattr(self.root_model, portname): listener for (portname, listener) in self.listeners_by_string.iteritems()}
  916. self.model.listeners = self.listeners
  917. self.model.component_set = directConnect(self.model.models, self.listeners)
  918. </script>
  919. </onentry>
  920. <transition port="request" event="pause" target=".">
  921. <script>
  922. # Just override termination condition
  923. self.termination_condition = lambda i, j, k : True
  924. self.termination_time = None
  925. # Don't forget to correctly set the simulation time
  926. # diff = time.time() - self.realtime_starttime
  927. # self.simulation_time = (diff / self.realtime_scale, 1)
  928. </script>
  929. </transition>
  930. <transition event="termination_condition" target="../paused">
  931. <raise port="reply" event="terminate">
  932. <parameter expr="self.simulation_time"/>
  933. </raise>
  934. <script>
  935. self.flush_file()
  936. </script>
  937. </transition>
  938. </state>
  939. <state id="big_step">
  940. <onentry>
  941. <script>
  942. #self.model.listeners = self.listeners
  943. #self.model.directConnect()
  944. self.listeners = {getattr(self.root_model, portname): listener for (portname, listener) in self.listeners_by_string.iteritems()}
  945. self.model.listeners = self.listeners
  946. self.model.component_set = directConnect(self.model.models, self.listeners)
  947. </script>
  948. </onentry>
  949. <transition event="big_step_done" target="../paused"/>
  950. <transition event="termination_condition" target="../paused">
  951. <raise port="reply" event="terminate">
  952. <parameter expr="self.simulation_time"/>
  953. </raise>
  954. <script>
  955. self.flush_file()
  956. </script>
  957. </transition>
  958. </state>
  959. </state>
  960. <state id="breakpoint_manager">
  961. <state id="breakpoint_manage">
  962. <transition port="request" event="add_breakpoint" target=".">
  963. <parameter name="breakpoint_id"/>
  964. <parameter name="function"/>
  965. <parameter name="enabled"/>
  966. <parameter name="disable_on_trigger"/>
  967. <script>
  968. self.breakpoints.append(Breakpoint(breakpoint_id, function, enabled, disable_on_trigger))
  969. </script>
  970. </transition>
  971. <transition port="request" event="del_breakpoint" target=".">
  972. <parameter name="del_breakpoint_id"/>
  973. <script>
  974. self.breakpoints = [breakpoint for breakpoint in self.breakpoints if breakpoint.id != del_breakpoint_id]
  975. </script>
  976. </transition>
  977. <transition port="request" event="toggle_breakpoint" target=".">
  978. <parameter name="breakpoint_id"/>
  979. <parameter name="enabled"/>
  980. <script>
  981. for breakpoint in self.breakpoints:
  982. if breakpoint.id == breakpoint_id:
  983. breakpoint.enabled = enabled
  984. break
  985. </script>
  986. </transition>
  987. </state>
  988. </state>
  989. <!--state id="reset">
  990. <state id="reset">
  991. <transition port="request" event="reset" target=".">
  992. <script>
  993. '''
  994. for model in self.model.component_set:
  995. model.state = pickle.loads(self.save_model[model][1])
  996. model.elapsed = self.save_model[model][0]
  997. model.time_last = (-model.elapsed, 1)
  998. ta = model.timeAdvance()
  999. model.time_next = (model.time_last[0] + ta, 1)
  1000. '''
  1001. self.model_ids = []
  1002. self.model = pickle.loads(self.save_model)
  1003. self.simulation_time = (0.0, 0)
  1004. print self.listeners
  1005. self.model.listeners = self.listeners
  1006. self.model.component_set = directConnect(self.model.models, self.listeners)
  1007. self.model.scheduler.massReschedule(self.model.component_set)
  1008. # Reset trace file
  1009. if self.trace_file is not None:
  1010. self.trace_file = open(self.trace_file.name, 'w')
  1011. </script>
  1012. <raise scope="output" port="reply" event="all_states">
  1013. <parameter expr="(0.0, 0)"/>
  1014. <parameter expr="{m.getModelFullName(): (m.time_next, m.state) for m in self.model.component_set}"/>
  1015. </raise>
  1016. </transition>
  1017. </state>
  1018. </state-->
  1019. <state id="listeners">
  1020. <state id="listening">
  1021. <transition target="." event="set_listen_ports">
  1022. <parameter name="port" />
  1023. <parameter name="function" />
  1024. <script>
  1025. self.listeners_by_string[port] = function
  1026. </script>
  1027. </transition>
  1028. </state>
  1029. </state>
  1030. <state id="reset">
  1031. <state id="reset">
  1032. <transition port="request" event="reset" target="../../../initializing">
  1033. <script>
  1034. self.model_ids = []
  1035. self.model = pickle.loads(self.save_model)
  1036. # Simulation variables
  1037. self.termination_time = None
  1038. self.termination_condition = None
  1039. self.simulation_time = (0.0, 0)
  1040. self.listeners = {}
  1041. self.root_model = self.model
  1042. self.realtime_scale = 1.0
  1043. # Values to be set during simulation
  1044. self.realtime_starttime = None
  1045. self.inject_queue = []
  1046. # Model initialization
  1047. self.model_ids = []
  1048. self.model.finalize(name="", model_counter=0, model_ids=self.model_ids, locations={None: []}, select_hierarchy=[])
  1049. print 'resetting'
  1050. </script>
  1051. </transition>
  1052. </state>
  1053. </state>
  1054. </parallel>
  1055. </scxml>
  1056. </class>
  1057. </diagram>