simulator.xml 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. <?xml version="1.0" ?>
  2. <diagram author="Simon Van Mierlo" name="NetLogo debugging-enhanced simulator">
  3. <description>
  4. A NetLogo simulator (enhanced with debugging support).
  5. </description>
  6. <top>
  7. import pyNetLogo
  8. import pprint, time
  9. class Breakpoint(object):
  10. def __init__(self, breakpoint_id, function, enabled, disable_on_trigger):
  11. self.id = breakpoint_id
  12. self.function = function
  13. self.enabled = enabled
  14. self.disable_on_trigger = disable_on_trigger
  15. </top>
  16. <inport name="request"/>
  17. <outport name="reply"/>
  18. <class name="NetLogoSimulator" default="true">
  19. <constructor>
  20. <parameter name="model"/>
  21. <body>
  22. <![CDATA[
  23. self.link = pyNetLogo.NetLogoLink(gui=True,
  24. netlogo_home="C:\\Program Files\\NetLogo 6.0.3",
  25. netlogo_version="6")
  26. self.link.load_model(model)
  27. self.attr_names = self.link.report('last last reflection:breeds')
  28. self.link.command("setup")
  29. self.ignored_attributes = set(["WHO", "HEADING", "SHAPE", "LABEL", "LABEL-COLOR", "BREED", "HIDDEN?", "PEN-SIZE", "PEN-MODE"])
  30. self.breakpoints = []
  31. self.realtime_scale = 1.0
  32. self.simulation_time = 0
  33. self.time_next = 1
  34. self.turtles = {}
  35. # Values to be set during simulation
  36. self.realtime_starttime = None
  37. ]]>
  38. </body>
  39. </constructor>
  40. <method name="turtles_created">
  41. <parameter name="new_turtles" />
  42. <body>
  43. return set(new_turtles.keys()) - set(self.turtles.keys())
  44. </body>
  45. </method>
  46. <method name="turtles_deleted">
  47. <parameter name="new_turtles" />
  48. <body>
  49. return set(self.turtles.keys()) - set(new_turtles.keys())
  50. </body>
  51. </method>
  52. <method name="get_all_turtles">
  53. <body>
  54. try:
  55. all_turtle_attributes = self.link.report("reflection:turtles")
  56. except:
  57. all_turtle_attributes = {}
  58. turtles = {}
  59. for turtle_attributes in all_turtle_attributes:
  60. the_turtle = dict(zip(self.attr_names, turtle_attributes.getResultAsObject()))
  61. turtles[int(float(the_turtle["WHO"]))] = the_turtle
  62. turtles = {k: {ak: av for ak, av in turtles[k].iteritems() if ak not in self.ignored_attributes} for k in turtles.keys()}
  63. return turtles
  64. </body>
  65. </method>
  66. <method name="breakpoint_triggers">
  67. <body>
  68. <![CDATA[
  69. breakpoint_id = -1
  70. for bp in self.breakpoints:
  71. if not bp.enabled:
  72. continue
  73. # Include the function in the scope
  74. exec(bp.function)
  75. # And execute it, note that the breakpoint thus has to start with "def breakpoint("
  76. if breakpoint(self.link.report("ticks"), self.turtles):
  77. # Triggered!
  78. breakpoint_id = bp.id
  79. else:
  80. # Not triggered, so continue
  81. continue
  82. return breakpoint_id
  83. ]]>
  84. </body>
  85. </method>
  86. <method name="process_breakpoints">
  87. <body>
  88. <![CDATA[
  89. breakpoint_id = self.breakpoint_triggers()
  90. if (breakpoint_id != -1):
  91. for breakpoint in self.breakpoints:
  92. if breakpoint.id == breakpoint_id:
  93. if breakpoint.disable_on_trigger:
  94. breakpoint.enabled = False
  95. return breakpoint_id
  96. ]]>
  97. </body>
  98. </method>
  99. <!-- Calculate the time to wait before triggering the next transition.
  100. This method is also called in non-realtime simulation, so make sure that it returns infinity in that case. -->
  101. <method name="calculate_after">
  102. <body>
  103. <![CDATA[
  104. try:
  105. # Process in parts of 100 milliseconds to repeatedly check the termination condition
  106. nexttime = (self.time_next - (time.time() - self.realtime_starttime) / self.realtime_scale) * self.realtime_scale
  107. x = min(0.1, nexttime)
  108. return x
  109. except (TypeError, AttributeError) as e:
  110. # We are probably not simulating in realtime...
  111. return float('inf')
  112. ]]>
  113. </body>
  114. </method>
  115. <!-- Parse a list of options that can be passed together with the request -->
  116. <method name="parse_options">
  117. <parameter name="configuration"/>
  118. <body>
  119. <![CDATA[
  120. self.realtime_scale = 1.0 if "realtime_scale" not in configuration else 1.0/configuration["realtime_scale"]
  121. # Subtract the current simulation time to allow for pausing
  122. self.realtime_starttime = (time.time() - self.simulation_time * self.realtime_scale)
  123. # Reset the time used in the waiting, as it might not get recomputed
  124. self.the_time = 0.00001
  125. ]]>
  126. </body>
  127. </method>
  128. <scxml initial="main">
  129. <parallel id="main">
  130. <state id="simulation_flow" initial="initialize">
  131. <state id="initialize">
  132. <transition target="../check_termination">
  133. <script>
  134. self.new_turtles = self.get_all_turtles()
  135. </script>
  136. <raise scope="output" port="reply" event="all_states">
  137. <parameter expr="self.simulation_time" />
  138. <parameter expr="self.new_turtles" />
  139. <parameter expr="{'CREATED_TURTLES': self.turtles_created(self.new_turtles),
  140. 'DELETED_TURTLES': self.turtles_deleted(self.new_turtles)}" />
  141. </raise>
  142. <script>
  143. self.turtles = self.new_turtles
  144. </script>
  145. </transition>
  146. </state>
  147. <state id="check_termination" initial="workaround">
  148. <onexit>
  149. <script>
  150. self.simulation_time = self.time_next
  151. </script>
  152. </onexit>
  153. <state id="workaround">
  154. <transition after="self.sccd_yield()" target="../check_termination"/>
  155. </state>
  156. <state id="wait">
  157. <onexit>
  158. <script>
  159. diff = time.time() - self.realtime_starttime
  160. self.simulation_time = diff / self.realtime_scale
  161. </script>
  162. </onexit>
  163. <transition after="self.calculate_after()" target="../check_termination"/>
  164. <transition cond="INSTATE('../../../simulation_state/paused')" target="../check_termination"/>
  165. </state>
  166. <state id="check_termination">
  167. <onentry>
  168. <script>
  169. self.the_time = self.calculate_after()
  170. </script>
  171. </onentry>
  172. <transition cond="(not INSTATE('../../../simulation_state/paused')) and (self.breakpoint_triggers() &gt; -1)" target="../workaround">
  173. <script>
  174. breakpoint_id = self.process_breakpoints()
  175. </script>
  176. <raise scope="output" port="reply" event="breakpoint_triggered">
  177. <parameter expr="breakpoint_id"/>
  178. </raise>
  179. <raise event="termination_condition"/>
  180. </transition>
  181. <transition target="../../execute_step" cond="INSTATE('../../../simulation_state/continuous')" />
  182. <transition target="../../execute_step" event="step" port="request" />
  183. <transition target="../wait" cond="INSTATE('../../../simulation_state/realtime') and (self.the_time &gt; 0.0)"/>
  184. <transition target="../../execute_step" cond="INSTATE('../../../simulation_state/realtime') and (self.the_time &lt;= 0.0)"/>
  185. <transition cond="INSTATE('../../../simulation_state/paused')" port="request" event="god_event" target="../workaround">
  186. <parameter name="configuration"/>
  187. <script>
  188. turtle_id = configuration["turtle"]
  189. state_attribute = configuration["attribute"]
  190. new_value = configuration["value"]
  191. askstring = "ask turtle %i [set %s %s]" % (int(turtle_id), state_attribute, new_value)
  192. self.link.command(askstring)
  193. self.new_turtles = self.get_all_turtles()
  194. </script>
  195. <raise scope="output" port="reply" event="god_event_ok" />
  196. <raise scope="output" port="reply" event="all_states">
  197. <parameter expr="self.simulation_time" />
  198. <parameter expr="self.new_turtles" />
  199. <parameter expr="{'CREATED_TURTLES': self.turtles_created(self.new_turtles),
  200. 'DELETED_TURTLES': self.turtles_deleted(self.new_turtles)}" />
  201. </raise>
  202. <script>
  203. self.turtles = self.new_turtles
  204. </script>
  205. </transition>
  206. </state>
  207. </state>
  208. <state id="execute_step" initial="executing_step">
  209. <onentry>
  210. <script>
  211. self.link.command("go")
  212. self.new_turtles = self.get_all_turtles()
  213. </script>
  214. </onentry>
  215. <state id="executing_step">
  216. <transition target="../../check_termination" cond="INSTATE('../../../simulation_state/continuous')">
  217. <script>
  218. self.time_next = self.time_next + 1
  219. </script>
  220. </transition>
  221. <transition target="../../check_termination" cond="ELSE">
  222. <raise scope="output" port="reply" event="all_states">
  223. <parameter expr="self.simulation_time" />
  224. <parameter expr="self.new_turtles" />
  225. <parameter expr="{'CREATED_TURTLES': self.turtles_created(self.new_turtles),
  226. 'DELETED_TURTLES': self.turtles_deleted(self.new_turtles)}" />
  227. </raise>
  228. <script>
  229. self.time_next = self.time_next + 1
  230. self.turtles = self.new_turtles
  231. </script>
  232. </transition>
  233. </state>
  234. </state>
  235. </state>
  236. <state id="simulation_state" initial="paused">
  237. <state id="paused">
  238. <transition target="../continuous" event="continuous" port="request" />
  239. <transition target="../realtime" event="realtime" port="request">
  240. <parameter name="configuration" />
  241. <script>
  242. self.parse_options(configuration)
  243. </script>
  244. </transition>
  245. </state>
  246. <state id="continuous">
  247. <transition target="../paused" event="pause">
  248. <raise scope="output" port="reply" event="all_states">
  249. <parameter expr="self.simulation_time" />
  250. <parameter expr="self.new_turtles" />
  251. <parameter expr="{'CREATED_TURTLES': self.turtles_created(self.new_turtles),
  252. 'DELETED_TURTLES': self.turtles_deleted(self.new_turtles)}" />
  253. </raise>
  254. <script>
  255. self.turtles = self.new_turtles
  256. </script>
  257. </transition>
  258. <transition event="termination_condition" target="../paused">
  259. <raise port="reply" event="terminate">
  260. <parameter expr="self.simulation_time"/>
  261. </raise>
  262. </transition>
  263. </state>
  264. <state id="realtime">
  265. <transition target="../paused" event="pause">
  266. <script>
  267. diff = time.time() - self.realtime_starttime
  268. self.simulation_time = diff / self.realtime_scale
  269. self.new_turtles = self.get_all_turtles()
  270. </script>
  271. <raise scope="output" port="reply" event="all_states">
  272. <parameter expr="self.simulation_time" />
  273. <parameter expr="self.new_turtles" />
  274. <parameter expr="{'CREATED_TURTLES': self.turtles_created(self.new_turtles),
  275. 'DELETED_TURTLES': self.turtles_deleted(self.new_turtles)}" />
  276. </raise>
  277. <script>
  278. self.turtles = self.new_turtles
  279. </script>
  280. </transition>
  281. <transition event="termination_condition" target="../paused">
  282. <raise port="reply" event="terminate">
  283. <parameter expr="self.simulation_time"/>
  284. </raise>
  285. </transition>
  286. </state>
  287. </state>
  288. <state id="reset_manager" initial="listening">
  289. <state id="listening">
  290. <transition port="request" event="reset" target="." cond="INSTATE('../../simulation_state/paused')">
  291. <script>
  292. self.link.command("setup")
  293. self.new_turtles = self.get_all_turtles()
  294. self.simulation_time = 0
  295. self.realtime_scale = 1.0
  296. self.realtime_starttime = None
  297. self.time_next = 1
  298. </script>
  299. <raise scope="output" port="reply" event="all_states">
  300. <parameter expr="self.simulation_time"/>
  301. <parameter expr="self.new_turtles"/>
  302. <parameter expr="{'CREATED_TURTLES': self.turtles_created(self.new_turtles),
  303. 'DELETED_TURTLES': self.turtles_deleted(self.new_turtles)}" />
  304. </raise>
  305. <script>
  306. self.turtles = self.new_turtles
  307. </script>
  308. </transition>
  309. </state>
  310. </state>
  311. <state id="breakpoint_manager">
  312. <state id="breakpoint_manage">
  313. <transition port="request" event="add_breakpoint" target=".">
  314. <parameter name="breakpoint_id"/>
  315. <parameter name="function"/>
  316. <parameter name="enabled"/>
  317. <parameter name="disable_on_trigger"/>
  318. <script>
  319. self.breakpoints.append(Breakpoint(breakpoint_id, function, enabled, disable_on_trigger))
  320. </script>
  321. </transition>
  322. <transition port="request" event="del_breakpoint" target=".">
  323. <parameter name="del_breakpoint_id"/>
  324. <script>
  325. self.breakpoints = [breakpoint for breakpoint in self.breakpoints if breakpoint.id != del_breakpoint_id]
  326. </script>
  327. </transition>
  328. <transition port="request" event="toggle_breakpoint" target=".">
  329. <parameter name="breakpoint_id"/>
  330. <parameter name="enabled"/>
  331. <script>
  332. for breakpoint in self.breakpoints:
  333. if breakpoint.id == breakpoint_id:
  334. breakpoint.enabled = enabled
  335. break
  336. </script>
  337. </transition>
  338. </state>
  339. </state>
  340. </parallel>
  341. </scxml>
  342. </class>
  343. </diagram>