Browse Source

Initial commit

Yentl Van Tendeloo 9 years ago
commit
66a6860316
100 changed files with 5343 additions and 0 deletions
  1. 10 0
      .gitignore
  2. 203 0
      LICENSE
  3. 14 0
      NOTICE
  4. 39 0
      build.sh
  5. 22 0
      doc/ADEVS.rst
  6. 20 0
      doc/ADEVS_int.rst
  7. 21 0
      doc/BaseDEVS_int.rst
  8. 22 0
      doc/CDEVS.rst
  9. 21 0
      doc/CDEVS_int.rst
  10. 25 0
      doc/DEVS.rst
  11. 27 0
      doc/DEVS_int.rst
  12. 154 0
      doc/Makefile
  13. 20 0
      doc/RootDEVS_int.rst
  14. BIN
      doc/activity.png
  15. 100 0
      doc/activity.rst
  16. 30 0
      doc/activity_relocation.rst
  17. 40 0
      doc/activityprediction.rst
  18. 31 0
      doc/activitytracking.rst
  19. 21 0
      doc/activityvisualisation_int.rst
  20. 5 0
      doc/addAllDocs.sh
  21. 48 0
      doc/advanced.rst
  22. 23 0
      doc/allocators_int.rst
  23. 21 0
      doc/asynchronouscombogenerator_int.rst
  24. 21 0
      doc/autoallocator_int.rst
  25. 45 0
      doc/base_dsdevs.py
  26. 21 0
      doc/basesimulator_int.rst
  27. 21 0
      doc/basicboundaryrelocator_int.rst
  28. 21 0
      doc/boundaryrelocator_int.rst
  29. BIN
      doc/celldevs.gif
  30. BIN
      doc/celldevs.png
  31. 111 0
      doc/celltracing.rst
  32. 21 0
      doc/changelog.rst
  33. 51 0
      doc/checkpoint.rst
  34. 22 0
      doc/classicdevswrapper_int.rst
  35. 23 0
      doc/colors_int.rst
  36. 252 0
      doc/conf.py
  37. 47 0
      doc/continuing.rst
  38. 21 0
      doc/controller_int.rst
  39. 39 0
      doc/customactivitytracking.rst
  40. 105 0
      doc/customscheduler.rst
  41. 162 0
      doc/differences.rst
  42. 103 0
      doc/distributedtermination.rst
  43. 102 0
      doc/distribution.rst
  44. BIN
      doc/distribution_local_model.png
  45. 44 0
      doc/dynamicallocator.rst
  46. 76 0
      doc/dynamicstructure.rst
  47. 17 0
      doc/elapsed_time.rst
  48. 296 0
      doc/examples.rst
  49. 297 0
      doc/examples_classic.rst
  50. 223 0
      doc/examples_ds.rst
  51. 22 0
      doc/experiment_fast.py
  52. 34 0
      doc/experiment_loop.py
  53. 33 0
      doc/experiment_threads.py
  54. 90 0
      doc/experiment_tk.py
  55. 21 0
      doc/greedyallocator_int.rst
  56. 74 0
      doc/howto.rst
  57. 44 0
      doc/index.rst
  58. 20 0
      doc/infinity.rst
  59. 192 0
      doc/injection.py
  60. 49 0
      doc/install_mpi4py.sh
  61. 95 0
      doc/installation.rst
  62. 29 0
      doc/interface.rst
  63. 49 0
      doc/internal.rst
  64. 42 0
      doc/listener.rst
  65. BIN
      doc/location.png
  66. 47 0
      doc/location.rst
  67. BIN
      doc/location_normal.png
  68. 20 0
      doc/locationscheduler.rst
  69. 21 0
      doc/logger_int.rst
  70. 21 0
      doc/manualrelocator_int.rst
  71. 113 0
      doc/memoization.rst
  72. 21 0
      doc/message_int.rst
  73. 20 0
      doc/messagescheduler_int.rst
  74. 21 0
      doc/middleware_int.rst
  75. 39 0
      doc/minimal.rst
  76. 21 0
      doc/minimal_int.rst
  77. BIN
      doc/model.png
  78. 22 0
      doc/mpiredirect_int.rst
  79. 40 0
      doc/multisim.rst
  80. 72 0
      doc/nesting.rst
  81. 113 0
      doc/problems.rst
  82. 69 0
      doc/queue_example.py
  83. 71 0
      doc/queue_example_classic.py
  84. 81 0
      doc/random.rst
  85. 22 0
      doc/randomgenerator.rst
  86. 22 0
      doc/randomgenerator_int.rst
  87. 309 0
      doc/realtime.rst
  88. 62 0
      doc/reinitialisation.rst
  89. 40 0
      doc/relocation.rst
  90. 24 0
      doc/relocators_int.rst
  91. 32 0
      doc/rewrite_documentation.sh
  92. 21 0
      doc/schedulerAH_int.rst
  93. 21 0
      doc/schedulerAuto_int.rst
  94. 21 0
      doc/schedulerDH_int.rst
  95. 21 0
      doc/schedulerDT_int.rst
  96. 21 0
      doc/schedulerHS_int.rst
  97. 21 0
      doc/schedulerML_int.rst
  98. 21 0
      doc/schedulerNA_int.rst
  99. 21 0
      doc/schedulerSL_int.rst
  100. 0 0
      doc/schedulers.rst

+ 10 - 0
.gitignore

@@ -0,0 +1,10 @@
+*.aux
+*.bbl
+*.blg
+*.log
+*.out
+*.tmp
+*-converted-to.pdf
+*.dms
+*.pyc
+*build*

+ 203 - 0
LICENSE

@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+

+ 14 - 0
NOTICE

@@ -0,0 +1,14 @@
+Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at               
+McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 39 - 0
build.sh

@@ -0,0 +1,39 @@
+#!/bin/bash
+###########
+# Creates a package of PyPDEVS: strips of most useless data and tars it all up
+###########
+
+mkdir pypdevs
+cp notes.txt pypdevs/releasenotes.txt
+cp install_mpi4py.sh pypdevs/install_mpi4py.sh
+cd doc/sphinx
+rm -r _build/html
+make html
+./rewrite_documentation.sh
+cd ../..
+cp -R doc/sphinx/_build/html/ pypdevs/doc
+cp -R src/ pypdevs/
+cp -R examples/ pypdevs/
+rm test/output/*
+cp -R test/ pypdevs/
+cp LICENSE pypdevs/
+cp NOTICE pypdevs/
+mkdir pypdevs/tests/output
+rm pypdevs/src/pypdevs/*.pyc
+rm pypdevs/examples/*/*.pyc
+rm pypdevs/examples/*/*.pyo
+rm pypdevs/src/pypdevs/*.pyo
+rm pypdevs/src/pypdevs/*/*.pyc
+rm pypdevs/src/pypdevs/*/*.pyo
+rm pypdevs/tests/tests/*.pyc
+rm pypdevs/tests/tests/*.pyo
+rm pypdevs/tests/expected/normal_long
+rm pypdevs/tests/expected/checkpoint
+rm pypdevs/*.pyc
+rm pypdevs/*.pyo
+rm -R pypdevs/src/build
+rm -R pypdevs/src/__pycache__
+rm -R pypdevs/src/pypdevs/__pycache__
+
+tar -czf pypdevs.tgz pypdevs
+rm -R pypdevs

+ 22 - 0
doc/ADEVS.rst

@@ -0,0 +1,22 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+AtomicDEVS User Interface
+=========================
+
+.. autoclass:: DEVS.AtomicDEVS
+   :members: __init__, extTransition, intTransition, confTransition, outputFnc, timeAdvance, simSettings, addInPort, addOutPort, removePort, modelTransition, preActivityCalculation, postActivityCalculation
+   :noindex:

+ 20 - 0
doc/ADEVS_int.rst

@@ -0,0 +1,20 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+AtomicDEVS
+==========
+.. autoclass:: DEVS.AtomicDEVS
+   :members:

+ 21 - 0
doc/BaseDEVS_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+BaseDEVS
+========
+
+.. autoclass:: DEVS.BaseDEVS
+   :members:

+ 22 - 0
doc/CDEVS.rst

@@ -0,0 +1,22 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+CoupledDEVS User Interface
+==========================
+
+.. autoclass:: DEVS.CoupledDEVS
+   :members: __init__, simSettings, addInPort, addOutPort, select, removePort, addSubModel, removeSubModel, connectPorts, disconnectPorts, modelTransition
+   :noindex:

+ 21 - 0
doc/CDEVS_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+CoupledDEVS
+===========
+
+.. autoclass:: DEVS.CoupledDEVS
+   :members:

+ 25 - 0
doc/DEVS.rst

@@ -0,0 +1,25 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+DEVS User Interface
+===================
+
+.. automodule:: DEVS
+
+.. toctree::
+   
+   Atomic DEVS <ADEVS>
+   Coupled DEVS <CDEVS>

+ 27 - 0
doc/DEVS_int.rst

@@ -0,0 +1,27 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+DEVS models
+===========
+
+.. automodule:: DEVS
+
+.. toctree::
+   
+   Base DEVS <BaseDEVS_int>
+   Atomic DEVS <ADEVS_int>
+   Coupled DEVS <CDEVS_int>
+   Root DEVS <RootDEVS_int>

+ 154 - 0
doc/Makefile

@@ -0,0 +1,154 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+#SPHINXBUILD   = sphinx-build
+SPHINXBUILD   = python -m sphinx
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	-rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PythonPDEVS.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PythonPDEVS.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/PythonPDEVS"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PythonPDEVS"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."

+ 20 - 0
doc/RootDEVS_int.rst

@@ -0,0 +1,20 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+RootDEVS
+=========
+.. autoclass:: DEVS.RootDEVS
+   :members:

BIN
doc/activity.png


+ 100 - 0
doc/activity.rst

@@ -0,0 +1,100 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Activity Tracking
+=================
+
+.. note:: This feature is still being worked on and all information is therefore prone to change.
+
+*Activity Tracking* is a feature that will have the simulator time the invocation of each user-defined function, being the *intTransition*, *extTransition*, *confTransition*, *outputFnc* and *timeAdvance* functions. At the end, all this timing information is gathered and a list of all timings is shown to the user. In its current state, there is not really a big use for *Activity Tracking* apart from the user being aware of the load of every seperate model.
+
+Two different output variants are currently supported:
+
+* List view: this will simply show a flat list of the name of the model, followed by its activity (in seconds). Depending on the configuration options, this will either be sorted on model name or on activity.
+* Cell view: this present the same information as the list view, only in a visual way. It will create a matrix-style file that contains the activity for that specific cell. This file can then be visualised using for example *Gnuplot*.
+
+The following configuration options are related to this functionality:
+
+* *setActivityTracking(at, sortOnActivity)*: enables or disables the printing of activity tracking information. Note that activity tracking is **always** performed internally, so disabling this will not increase performance.
+* *setActivityTrackingCellMap(cellmap, x, y)*: when activity tracking is enabled, setting this to *True* will result in a matrix-style file instead of a (printed) flat list. The resulting file will be called *activity*.
+
+In this example, we will create an activity Cell view, as this is a lot nicer than the other (more statistical) variant. Our model will be something more complex as the previous examples, but the model itself isn't really that important. A *fire spread* model was chosen, as this nicely reduces to a map and is thus perfect for Cell view.
+
+.. note:: The Cell view furthermore requires models that are to be plotted have an *x* and *y* attribute. This value will determine their location in the map. Models without such attributes will simply be ignored.
+
+This image was created by using the *experiment* file containing::
+
+    x, y = 20, 20
+    model = FireSpread(x, y)
+    sim = Simulator(model)
+    sim.setTerminationTime(1000.0)
+    sim.setActivityTrackingVisualisation(True, x, y)
+    sim.simulate()
+
+After simulation, a file called *activity* was created. This file was plotted using *gnuplot* with the commands
+
+.. code-block:: gnuplot
+
+    set view map
+    splot 'activity' matrix with image
+
+.. image:: activity.png
+   :alt: Activity Tracking cell view
+   :width: 100%
+
+.. note:: In order to make some more visually pleasing maps, the computation in the transition functions was severely increased. This is due to our transition function being rather small by default, which doesn't provide very accurate timings.
+
+.. warning:: Don't forget to take the word of caution (see below) into account when analyzing the results.
+
+Word of caution
+---------------
+
+The *Activity Tracking* feature uses the *time.time()* function from the Python *time* library. This means that it measures *wall clock* time instead of actual *CPU* time. Should the CPU be overloaded with work, these timings will thus be inaccurate due to possible interruptions of the simulation. Most of the time however, such interrupts should arrive either outside of the timed code. Otherwise, the interrupted models should be somewhat evenly spread out, thus reducing the impact.
+
+Of course, Python provides functions to fetch the actual *CPU* time spend. These alternatives were checked, but were *insufficient* for our purpose for several reasons. The alternatives are mentioned below:
+
+* Python *time.clock()* function: this has a very low granularity on Linux, which would show total nonsense in case the transition functions are small.
+* Python *resource* library: this has the same problem as the *time.clock()* approach and furthermore is a lot slower
+* External *psutil* library: this alternative has the same problems as the above alternatives, with the additional disadvantage that it is **extremely** slow.
+
+Since *Activity Tracking* is done at every model, in every simulation step, performance of this call is critical. To show the difference between these alternatives, a *timeit* comparison is shown below:
+
+.. code-block:: bash
+
+    yentl ~ $ python -m timeit -s "import time" -- "time.time()"
+    10000000 loops, best of 3: 0.0801 usec per loop
+    yentl ~ $ python -m timeit -s "import time" -- "time.clock()"
+    10000000 loops, best of 3: 0.199 usec per loop
+    yentl ~ $ python -m timeit -s "import resource" -- "resource.getrusage(resource.RUSAGE_SELF).ru_utime"
+    1000000 loops, best of 3: 0.642 usec per loop
+    yentl ~ $ python -m timeit -s "import psutil" -- "psutil.cpu_times().user"
+    10000 loops, best of 3: 25.9 usec per loop
+
+As can be seen from this comparison, we have the following performance statistics:
+
++----------+---------------+----------------------------+
+| method   | time per loop | times slower than *time()* |
++----------+---------------+----------------------------+
+| time()   | 0.08 usec     |                         1x |
++----------+---------------+----------------------------+
+| clock()  | 0.199 usec    |                       2.5x |
++----------+---------------+----------------------------+
+| resource | 0.642 usec    |                         8x |
++----------+---------------+----------------------------+
+| psutil   | 25.9 usec     |                       324x |
++----------+---------------+----------------------------+
+
+Since this function will be called twice for every transition that happens, using one of the slower methods would have an immense difference on the actual simulation time. The main purpose of *Activity  Tracking* is to increase performance, but when when e.g. *psutil* is used, the simulation is already slowed down by a massive factor, removing any chance for improvement in general situations.

+ 30 - 0
doc/activity_relocation.rst

@@ -0,0 +1,30 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Automatic activity-based relocation
+===================================
+
+As was mentioned in the previous section, manual relocation is possible in PyPDEVS. However, the knowledge of the modeler about which models need to be moved and at what time exactly, might be rather vague or even non-existent. Clearly, slightly altering the models parameters could completely alter the time at which relocation would be ideal. Additionally, such manual relocation is time consuming to write and benchmark.
+
+In order to automate the approach, PyPDEVS can use *activity* to guide it into making autonomous decisions. Since activity is a rather broad concept, several options are possible, most of them also offering the modeller the possibility to plug in its own relocators or activity definitions. Together with custom modules, comes also the possibility for inserting domain specific knowledge.
+
+We distinguish several different situations:
+
+.. toctree::
+    
+   Activity Tracking <activitytracking>
+   Custom Activity Tracking <customactivitytracking>
+   Custom Activity Prediction <activityprediction>

File diff suppressed because it is too large
+ 40 - 0
doc/activityprediction.rst


+ 31 - 0
doc/activitytracking.rst

@@ -0,0 +1,31 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Activity Tracking
+=================
+
+Activity tracking will perform the most generic approach available: measuring the time every transition function takes, accumulating all these values and calculating the complete load of the node.
+
+When using the *basic boundary relocator*, the current allocation will be mutated in such a way that every node gets approximately the same load. Sometimes this will not yield decent results, since the approach is too general and uses a greedy algorithm. It should therefore only be used in very simple situations where the number of possible mutations is rather limited. A simple example of this is a queue which has only one input and one output port.
+
+The *basic boundary relocator* takes a single argument: the swappiness. This simply defines what threshold to use for 'unacceptable load distribution'. A swappiness of 2 for example, will only try to offload nodes that have an activity twice as big as the average activity. Setting a too low swappiness will cause many (often unnecessary) relocations, while setting a too high swappiness will prevent relocations completely.
+
+To start a distributed simulation with *general activity tracking*, the configuration is::
+
+    sim = Simulator(CQueue())
+    swappiness = 1.3
+    sim.setActivityRelocatorBasicBoundary(swappiness)
+    sim.simulate()

+ 21 - 0
doc/activityvisualisation_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Activity-aware utility functions
+================================
+
+.. automodule:: activityVisualisation
+   :members:

+ 5 - 0
doc/addAllDocs.sh

@@ -0,0 +1,5 @@
+#!/bin/bash
+svn add *.rst
+svn add _build/html/*.html
+svn add _build/html/sources/*.txt
+svn add _build/html/modules/*.html

+ 48 - 0
doc/advanced.rst

@@ -0,0 +1,48 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Advanced examples
+=================
+
+In this section, we will continue using the model from the previous section wherever possible. We will extend it in several ways, each demonstrating another feature of the PyPDEVS simulator that will first be briefly explained. All examples are sorted based on complexity of both usage and implementation, but also with dependencies in mind.
+
+.. toctree::
+   :maxdepth: 1
+
+   Reinitialisation <reinitialisation>
+   Continuing a simulation <continuing>
+   Minimal simulation kernel <minimal>
+   Multiple Simulations <multisim>
+   Transfer Functions <transferfunction>
+   Dynamic Structure DEVS <dynamicstructure>
+   Nesting <nesting>
+   Realtime simulation <realtime>
+   Listening to realtime simulation <listener>
+   Cell tracing <celltracing>
+   Custom scheduler <customscheduler>
+   Distribution <distribution>
+   Location-specific scheduler <locationscheduler>
+   Random number generation <random>
+   Distributed termination condition <distributedtermination>
+   Checkpointing <checkpoint>
+   Location tracking <location>
+   Memoization <memoization>
+   Manual relocation <relocation>
+   Activity tracking <activity>
+   Automatic relocation <activity_relocation>
+   Activity visualisation <visualisation>
+   Static allocator <staticallocator>
+   Dynamic allocator <dynamicallocator>

+ 23 - 0
doc/allocators_int.rst

@@ -0,0 +1,23 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Allocators
+==========
+
+.. toctree::
+
+   Auto Allocator <autoallocator_int>
+   Greedy Allocator <greedyallocator_int>

+ 21 - 0
doc/asynchronouscombogenerator_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Asynchronous Combo Generator
+============================
+
+.. autoclass:: realtime.asynchronousComboGenerator.AsynchronousComboGenerator
+   :members:

+ 21 - 0
doc/autoallocator_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+AutoAllocator
+=============
+
+.. autoclass:: allocators.autoAllocator.AutoAllocator
+   :members:

+ 45 - 0
doc/base_dsdevs.py

@@ -0,0 +1,45 @@
+from pypdevs.DEVS import AtomicDEVS, CoupledDEVS
+from pypdevs.simulator import Simulator
+
+class Root(CoupledDEVS):
+    def __init__(self):
+        CoupledDEVS.__init__(self, "Root")
+        self.models = []
+        # First model
+        self.models.append(self.addSubModel(Generator()))
+        # Second model
+        self.models.append(self.addSubModel(Consumer(0)))
+        # And connect them
+        self.connectPorts(self.models[0].outport, self.models[1].inport)
+
+class Generator(AtomicDEVS):
+    def __init__(self):
+        AtomicDEVS.__init__(self, "Generator")
+        # Keep a counter of how many events were sent
+        self.outport = self.addOutPort("outport")
+        self.state = 0
+
+    def intTransition(self):
+        # Increment counter
+        return self.state + 1
+
+    def outputFnc(self):
+        # Send the amount of messages sent on the output port
+        return {self.outport: [self.state]}
+
+    def timeAdvance(self):
+        # Fixed 1.0
+        return 1.0
+
+class Consumer(AtomicDEVS):
+    def __init__(self, count):
+        AtomicDEVS.__init__(self, "Consumer_%i" % count)
+        self.inport = self.addInPort("inport")
+
+    def extTransition(self, inputs):
+        for inp in inputs[self.inport]:
+            print("Got input %i on model %s" % (inp, self.name))
+
+sim = Simulator(Root())
+sim.setTerminationTime(5)
+sim.simulate()

+ 21 - 0
doc/basesimulator_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+BaseSimulator: the DEVS kernel
+==============================
+
+.. autoclass:: basesimulator.BaseSimulator
+   :members:

+ 21 - 0
doc/basicboundaryrelocator_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Basic Boundary Relocator
+========================
+
+.. automodule:: relocators.basicBoundaryRelocator
+   :members:

+ 21 - 0
doc/boundaryrelocator_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Boundary Relocator
+==================
+
+.. automodule:: relocators.boundaryRelocator
+   :members:

BIN
doc/celldevs.gif


BIN
doc/celldevs.png


+ 111 - 0
doc/celltracing.rst

@@ -0,0 +1,111 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Cell Tracing
+============
+
+Cell tracing is somewhat different from the *verbose* and *XML* tracers, in that it is only applicable for several models. The models that support it however, can profit from it, as this is a very visual and easy to understand tracer.
+
+.. note:: For those familiar with Cell DEVS (and particularly CD++): this tracer aims at providing the same tracing functionality for 2D DEVS models as CD++ provides for them. This does introduce parts of Cell DEVS in Parallel DEVS, but of course the only affected parts are the actual tracing and not model construction and simulation.
+
+There are only 2 requirements on the model for Cell tracing:
+
+* The models have an *x* and *y* attribute, which signify the location where the cell will be drawn.
+* The states have an *toCellState()* method, which should return the value to be shown in the matrix.
+
+.. note:: If two models have unique coordinates, only one of them will be considered in the tracing. There is no support for dimensions above 2D.
+
+Thus a very simple cell would look like this::
+
+    class CellState(object):
+        def __init__(self, value):
+            self.value = value
+
+        def toCellState(self):
+            # Simply return the value, but could also first 
+            # perform some operations on the value
+            return value
+
+    class Cell(AtomicDEVS):
+        def __init__(self, x, y):
+            AtomicDEVS.__init__(self, 'Cell(%i, %i)' % (x, y))
+            self.x = x
+            self.y = y
+            self.state = CellState()
+
+The coupled model would then be responsible for assigning unique coordinates to every cell. The following configurations now still need to be set in the experiment file::
+
+    # Save the coordinates of the model somewhere, as we need them later
+    x, y = 20, 20
+    model = MyCoupledCellModel(x, y)
+    sim = Simulator(model)
+    sim.setCell(True, x, y, cell_file="celltrace", multifile=False)
+    sim.simulate()
+
+This will then generate a file with a matrix of the current state at every timestep. The matrices are simply appended with a delimiter between them. Sadly, this kind of data is not directly usable in gnuplot, which is why the *multifile* option comes in handy.
+
+When setting *multifile=True*, every timestep will have its own file, which contains only the matrix and can be directly drawn using *gnuplot*. Simulator-defined files are not that handy, because you probably want it in a slightly different format. For this reason, the *cell_file* parameter will be interpreted as a *format string* when *multifile* is set to *True*. An example invocation of this could be::
+    
+    sim.setCell(True, x, y, cell_file="celltrace-%05d", multifile=True)
+
+This will then create the files *celltrace-00001*, *celltrace-00002*, ... until the termination time is reached.
+
+.. note:: Remember that the *cell_file* parameter will be used as a format string if *multifile* is *True*!
+
+After these files are generated, we can simply plot them with e.g. *gnuplot* as follows:
+
+.. code-block:: gnuplot
+
+   set pm3d map
+   set pm3d interpolate 0, 0
+   splot 'celltrace-00001' matrix
+
+This will generate in interpolated version (which is slightly nicer than the original version). Naturally, scripting immediately comes to mind when a lot of files with similar data are created. It is now even possible to create an animation of the simulation, thus visualizing the change over time. This can be done in e.g. bash as follows:
+
+.. code-block:: bash
+
+   for f in `ls -1 celltrace-*`
+   do
+       echo "set view map" > plot
+       echo "set terminal png size 400, 300 enhanced" >> plot
+       echo "set pm3d map" >> plot
+       echo "set pm3d interpolate 0, 0" >> plot
+       echo "set output '$f.png'" >> plot
+       echo "splot '$f' matrix" >> plot
+       gnuplot plot
+       rm plot
+   done
+   avconv -i celltrace-%5d.png out.avi
+
+Which will create an animation visualizing e.g. a *fire spread* model. Since *gnuplot* will automatically determine the range of colors to use, it might be interesting to provide this range yourself, as to keep it consistent between all different images. This can be done by adding the following line right before the *splot* line:
+
+.. code-block:: bash
+
+   echo "set cbrange [27:800]" >> plot
+
+Each individual file will then look something like:
+
+.. image:: celldevs.png
+   :alt: Cell view
+   :width: 100%
+
+And an animated version looks like:
+
+.. image:: celldevs.gif
+   :alt: Cell view animation
+   :width: 100%
+
+.. note:: It is technically possible to visualize this data in (semi)-realtime. If local simulation is done, each trace file will be written as soon as possible. It would require some additional lines of scripting to actually poll for these files and render them of course. In distributed simulation, visualisation at run time is not so simple, as these files will only be written at GVT boundaries.

+ 21 - 0
doc/changelog.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Changelog
+=========
+
+.. literalinclude:: ../../notes.txt
+

File diff suppressed because it is too large
+ 51 - 0
doc/checkpoint.rst


+ 22 - 0
doc/classicdevswrapper_int.rst

@@ -0,0 +1,22 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Classic DEVS Wrapper
+====================
+
+.. automodule:: classicDEVSWrapper
+   :members:
+   :special-members:

+ 23 - 0
doc/colors_int.rst

@@ -0,0 +1,23 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Colors
+=========
+.. automodule:: colors
+   :members:
+
+.. autodata:: colors.colors
+

+ 252 - 0
doc/conf.py

@@ -0,0 +1,252 @@
+# -*- coding: utf-8 -*-
+#
+# PythonPDEVS documentation build configuration file, created by
+# sphinx-quickstart on Sat Sep 28 20:20:40 2013.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('../../src/pypdevs/'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+#extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'PythonPDEVS'
+copyright = u'2016, Yentl Van Tendeloo'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '2.4'
+# The full version, including alpha/beta/rc tags.
+release = '2.4.0'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+htmlstatic_path = ['static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'PythonPDEVSdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'PythonPDEVS.tex', u'PythonPDEVS Documentation',
+   u'Yentl Van Tendeloo', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'pythonpdevs', u'PythonPDEVS Documentation',
+     [u'Yentl Van Tendeloo'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('index', 'PythonPDEVS', u'PythonPDEVS Documentation',
+   u'Yentl Van Tendeloo', 'PythonPDEVS', 'One line description of project.',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# Include the __init__ function (http://stackoverflow.com/questions/5599254/how-to-use-sphinxs-autodoc-to-document-a-classs-init-self-method)
+def skip(app, what, name, obj, skip, options):
+    if name == "__init__":
+        return False
+    return skip
+
+def setup(app):
+    app.connect("autodoc-skip-member", skip)

+ 47 - 0
doc/continuing.rst

@@ -0,0 +1,47 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Continuing a stopped simulation
+===============================
+
+It is possible to continue a terminated simulation from the current state. An example use case of this is splitting the simulation in two 'phases'. The first phase is a kind of warmup period, in which tracing might not be necessary. If this phase only takes until a certain time, the termination time can be set to this time. As soon as the *simulate()* call returns, it is possible to perform some alterations to the model and to the simulation methods.
+
+The syntax is as simple as recalling the *simulate()* method. Of course, if the termination time (or condition) is not altered, simulation will halt immediately. If this is changed, simulation will run until this condition is satisfied. All tracers from the original run will still be in effect and possible new tracers will be added. These new tracers wil only contain the data from the simulation run that happens after they are created. 
+
+A small example, in which a model is contructed and runs until simulation time 100 is reached. After this, a tracer is set and simulation will runn up until simulation time 200::
+
+    sim = Simulator(MyModel())
+    sim.setTerminationTime(100)
+    sim.simulate() # First simulation run; no tracers
+
+    # We are at simulation time 100 now
+    sim.setTerminationTime(200)
+    sim.setVerbose() # Now add a tracer at time 100
+    sim.simulate() # Simulate it for a second time; using the tracer
+
+Altering the state
+------------------
+
+It is also possible to alter the state in between two calls to the simulate method. This allows you to e.g. enable internal logging only after a certain time, or clear all gathered statistics for the warm-up period. This uses the exact same syntax (and internally, it uses exactly the same methods) as the reinitialisation with the exception that no *reinit()* is called.
+
+The available methods are:
+* *setModelState(model, newState)*: modify the state of *model* and set it to *newState*. Use this to set a completely new state for the model. This is an optimized version of *setModelAttribute*.
+* *setModelStateAttr(model, attr, value)*: modify the attribute *attr* of the state of *model* and set it to *value*. This will keep the original initialisation state, but alters only a single attribute.
+* *setModelAttribute(model, attr, value)*: modify the attribute *attr* of the *model* and set it to *value*. This can be done to modify read-only attributes of the simulation model.
+
+Such alterations will be visible in the *Verbose* logger as 'user events', signifying the attribute that was altered and to which value. This is done to prevent inconsistent trace files.
+
+.. warning:: The time advance is **not** recalculated after a change to the state. This is because if no significant change happens and the timeAdvance returns the same value (as it should), it would signify a different absolute time due to the time advance function returning a relative file.

+ 21 - 0
doc/controller_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Controller
+==========
+
+.. automodule:: controller
+   :members:

File diff suppressed because it is too large
+ 39 - 0
doc/customactivitytracking.rst


+ 105 - 0
doc/customscheduler.rst

@@ -0,0 +1,105 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Writing a custom scheduler
+==========================
+
+.. warning:: Writing a custom scheduler is potentially dangerous, as you could easily violate the DEVS formalism. Only trust your own schedulers after rigorous testing **and** (if you violate DEVS formalisms in the general case) make sure that such violating situations never happen.
+
+A scheduler requires a simple interface, which will be explained here. If you require the scheduler to work distributed, you should allow for some kind of rollback to happen. This should be handled by the *massReschedule* method automatically.
+
+Interface
+---------
+
+The interface, and thus the methods that need to be implemented, is rather small. Some of them might be skipped if you only want your scheduler to work for static structure without relocation. However, it is advised to implement all of them for future compliance.
+
+.. function:: __init__(models, epsilon, totalModels)
+
+   The constructor to be used for the scheduler. The argument *models* will contain a list of all models that are local to this scheduler. Argument *epsilon* contains the allowed floating point deviation when searching for imminent children. The *totalModels* argument can be ignored most of the time and is only useful if the scheduler needs some global information about all models, even those running remotely.
+
+.. function:: schedule(model)
+
+   Add a new model to the scheduler. The provided model will **not** have been passed in the constructor. It is only used in dynamic structure (when creating a new model) and distributed simulation with relocation (where a model is relocated to our node).
+
+.. function:: unschedule(model)
+
+   Remove a model from the scheduler. The provided model will have been either passed in the constructor or by the *schedule* method. Unscheduling a model should have the effect that it will never be returned by the *getImminent* method unless it is scheduled again.
+
+.. function:: massReschedule(reschedule_set)
+
+   Reschedules all models in the reschedule_set. This method is used to notify the scheduler that there is the possibility that the *timeNext* value of these models has been changed. Models that are not mentioned in the reschedule_set are guaranteed to have the same *timeNext* value. All models that are provided are guaranteed to either be passed in the constructor, or have the schedule method called for them. Performance wise, this is one of the most time-critical pieces of code.
+
+.. function:: readFirst()
+
+   Returns the time of the first model that is scheduled, as a tuple of the form (simulationtime, age). Since this is a read operation, nothing should change to the scheduled models and their order.
+
+.. function:: getImminent(time)
+
+   Return an iterable containing all models that are scheduled for this specific time, with an allowed deviation of *epsilon* (passed in the constructor). It is possible that there will be no imminent models! The internal state of the returned models is irrelevant, as they will afterwards have the *massReschedule* method called with (among others) them in the iterable.
+
+   .. note:: The time should agree in both parts of the tuple: the simulation time (up to an *epsilon*) and the age field (*exact* equality only)
+
+Example: sorted list scheduler
+------------------------------
+
+As an example, the sorted list scheduler is shown below. It simply contains an internal list of all models it has to take into account, sorts the list based on timeNext and returns the first elements that match.
+
+.. code-block:: python
+
+    class SchedulerSL(object):
+        def __init__(self, models, epsilon, totalModels):
+            self.models = list(models)
+            self.epsilon = epsilon
+
+        def schedule(self, model):
+            self.models.append(model)
+            self.models.sort(key=lambda i: i.timeNext)
+
+        def unschedule(self, model):
+            self.models.remove(model)
+
+        def massReschedule(self, reschedule_set):
+            self.models.sort(key=lambda i: i.timeNext)
+
+        def readFirst(self):
+            return self.models[0].timeNext
+
+        def getImminent(self, time):
+            immChildren = []
+            t, age = time
+            try:
+                # Age must be exactly the same
+                count = 0
+                while (abs(self.models[count].timeNext[0] - t) < self.epsilon) and (self.models[count].timeNext[1] == age):
+                    # Don't pop, as we want to keep all models in the list
+                    immChildren.append(self.models[count])
+                    count += 1
+            except IndexError:
+                pass
+            return immChildren
+
+Using your own scheduler
+------------------------
+
+Since the name of your custom scheduler is not known by me, there is no simple utility function like *setSchedulerSortedList()* provided, but you will have to use the more advanced interface. Note that all of these *setSchedulerX()* methods are simply utility functions which make exactly the same calls as you will be making. They are only provided to make the life of most users simpler.
+
+Setting the custom scheduler requires 2 bits of information: the filename in which the class is defined and the name of the class. Take for example that we created the '*CustomScheduler*' class in the file '*myFirstScheduler*'. Using the scheduler is then as simple as::
+
+    sim = Simulator(Queue())
+    # Internally, this is evaluated as an import statement of the form
+    #   from myFirstScheduler import CustomScheduler
+    sim.setSchedulerCustom('myFirstScheduler', 'CustomScheduler')
+    sim.simulate()

File diff suppressed because it is too large
+ 162 - 0
doc/differences.rst


+ 103 - 0
doc/distributedtermination.rst

@@ -0,0 +1,103 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Distributed Termination
+=======================
+
+Termination was simple in local, sequential simulation. All that had to be done was placing a simple check before each step in the simulation and check whether or not this simulation step should still be executed.
+
+Distributed simulation on the other hand, should only terminate as soon as all nodes are able to quit. But due to the use of time warp, even if a node has stopped running, it might have to start again some time later. Clearly a global termination time is still relatively simple to use, as all nodes just compare their clocks to it, but a termination condition is a lot more difficult.
+
+In this section, the two different ways of termination in a distributed setting will be discussed.
+
+Termination time
+----------------
+
+A global termination time is clearly the most efficient solution. All nodes will receive this time at startup and will simply compare to it. It requires no inter-node communication whatsoever because every node can determine for itself whether or not simulation is finished. If at all possible, this approach is highly recommended over the other option.
+
+Due to its simplicity, the exact same methods and semantics can be used as in sequential simulation::
+    
+    sim = Simulator(Model())
+    sim.setTerminationTime(50.0)
+    sim.simulate()
+
+Termination condition: frequent state checks
+--------------------------------------------
+
+.. warning:: Due to the use of time warp, the *time* parameter of the function now returns a **tuple** instead of a **float**. Most often, only the first value of the tuple is used, which contains the actual simulation time. The second value is the so called *age* field, which indicates how often this exact same simulation time has already happened.
+
+A termination condition is still possible in distributed simulation, albeit in a reduced form. First of all, the granularity of a termination condition is not guaranteed in distributed simulation. Since DEVS takes non-fixed timesteps, they are depending on the models that are present on the current node. This means that the termination condition will also be checked only at these steps. Generally, this should not be a big problem, though it is something to keep in mind.
+
+Only a single node can be responsible for the termination condition, due to the model being completely distributed. This node is always the controller. The controller should thus have all models involved in the termination condition running, as otherwise invalid states will be read.
+
+.. note:: PyPDEVS will **not** complain when reading an invalid state, as such readings are done behind the back of PyPDEVS. If you want certainty that the state you are accessing is local, check whether or not the *location* attribute is equal to zero.
+
+To be able to cope with allocation and relocation, the simulator should have its *setTerminationModel(model)* method be called. This will mark the model as being used in the termination condition and will guarantee that this model stays on the controller, whatever allocation or relocation is given. Note though, that this could potentially move a single atomic model from a remote coupled model, causing many revertions.
+
+As soon as the termination condition triggers the end of the simulation, the controller will send a termination message to all other nodes, which will then keep running until they have reached the same time as passed in the termination condition. Should the controller be reverted, its termination messages will also be cancelled.
+
+If we want the generator atomic model of the queue to be used in the termination condition, we could write::
+
+    def generatedEnough(time, model):
+        return model.generator.state.generated > 5
+
+    myQueue = CQueue()
+    sim = Simulator(myQueue)
+    sim.setTerminationCondition(generatedEnough)
+    sim.setTerminationModel(myQueue.generator)
+    sim.simulate()
+
+Termination condition: sporadic state checks
+--------------------------------------------
+
+.. warning:: The complete *time* tuple should be passed to the *getState(time)* method!
+
+If the model state is only required sporadically, it would be wasteful to run the model at the controller, simply for this one access. To cope with this, a *pull based* method is possible. Every atomic DEVS model will have a *getState(time)* method. If the model is non-local, this method can be called to retrieve the state of the model at that specific time. If this approach is used, the model need not be marked as a termination model.
+
+.. note:: This time attribute is necessary due to time warp being used: it is very unlikely that the remote model is at exactly the same time in simulated time, so the time at which this call was made should be passed.
+
+Such *getState(time)* calls are blocking, meaning that they will not return a result if the remote model is not yet at the simulated time that was requested. Furthermore, such requests cause artificial dependencies between different models. This pull based approach is thus only recommended if it is done (very) sporadically. It goes without saying that these remote calls also incur a latency due to the network delay.
+
+To write the same as the previous example, we can write::
+
+    def generatedEnough(time, model):
+        return model.generator.getState(time).generated > 5
+
+    myQueue = CQueue()
+    sim = Simulator(myQueue)
+    sim.setTerminationCondition(generatedEnough)
+    sim.simulate()
+
+Termination condition: mixed state checks
+-----------------------------------------
+
+Both approaches could be mixed if it is required, for example if the generator is checked at every iteration (and is running local). If the generator passed a certain check, then other remote models need to be checked, which will only be done very sporadically. This could give::
+
+    def generatedEnough(time, model):
+        # First a local check
+        if model.generator.state.generated <= 5:
+            return False
+        else:
+            # Now a remote check, but we know that this will only be called rarely
+            return model.processor2.getState(time).processed > 5
+
+    myQueue = CQueue()
+    sim = Simulator(myQueue)
+    sim.setTerminationCondition(generatedEnough)
+    # Only mark the generator as a termination model
+    sim.setTerminationModel(myQueue.generator)
+    sim.simulate()
+    

+ 102 - 0
doc/distribution.rst

@@ -0,0 +1,102 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Distribution
+============
+
+For the modeller, distribution of models is as simple as providing a model (either atomic or coupled) with the location where it should run and afterwards running it as a distributed simulation (as mentioned in :doc:`howto`).
+
+.. note:: Since version 2.1, model distribution was simplified and a lot of restrictions on the model were dropped. Every model that was valid in local simulation, should now also be valid in distributed simulation.
+
+Distributing the queue
+----------------------
+
+Let's extend the *CQueue* example from previous sections and add some distribution to it. Of course, this model only has two atomic models, which is clearly not an ideal model to distribute. Therefore, we will add some *Queue* atomic models in parallel, all taking the output from the single generator. Our model should look something like:
+
+.. image:: distribution_local_model.png
+   :alt: The model to distribute
+
+We will start of with implementing this model locally. This implementation is simple and shouldn't be more difficult than the model in :doc:`examples`. It should look something like::
+
+    class DQueue(CoupledDEVS):
+        def __init__(self):
+            CoupledDEVS.__init__(self, "DQueue")
+            self.generator = self.addSubModel(Generator())
+            self.queue1 = self.addSubModel(Queue())
+            self.queue2 = self.addSubModel(Queue())
+            self.connectPorts(self.generator.outport, self.queue1.inport)
+            self.connectPorts(self.generator.outport, self.queue2.inport)
+
+.. note:: Our original *Queue* atomic model was not written with multiple instances in mind. Therefore, the model name will **not** be unique in this simulation. In later versions of PyPDEVS, this doesn't pose a problem apart from possibly confusing trace output.
+
+Now all that is left is performing the actual distribution. Suppose we run 3 different nodes, with every atomic model on a seperate node. Thus the *Generator* runs on node 0, the first *Queue* runs on node 1 and the final *Queue* runs on node 2. This is as simple as altering the *addSubModel* method calls and add the desired node of the model being added. This results in::
+
+    class DQueue(CoupledDEVS):
+        def __init__(self):
+            CoupledDEVS.__init__(self, "DQueue")
+            self.generator = self.addSubModel(Generator(), 0)
+            self.queue1 = self.addSubModel(Queue(), 1)
+            self.queue2 = self.addSubModel(Queue(), 2)
+            self.connectPorts(self.generator.outport, self.queue1.inport)
+            self.connectPorts(self.generator.outport, self.queue2.inport)
+
+Setting the location of a model, will automatically set the location of all its submodels with an unspecified location to the same location.
+
+.. note:: Models for location 0 do not necessarily need to be specified, as the default is node 0. Leaving this option open (or specifying the location as *None*) means that it should take the location of the parent.
+
+Additional options
+------------------
+
+A *Simulator* object that is initialized with a distributed model has several extra options that can be configured. 
+
+More advanced options are elaborated further on in their own :doc:`advanced` subsection.
+
++------------------------------------+-------------------------------------------------------+
+|*setTerminationModel(model)*        | Marks *model* as being used in termination condition  |
++------------------------------------+-------------------------------------------------------+
+|*registerState(variable, model)*    | Register a state to be fetched after simulation       |
++------------------------------------+-------------------------------------------------------+
+|*setFetchAllAfterSimulation(fetch)* | Completely update the model after simulation          |
++------------------------------------+-------------------------------------------------------+
+|*setGVTInterval(gvt_int)*           | Calculate the GVT after every *gvt_int* seconds       |
++------------------------------------+-------------------------------------------------------+
+|*setCheckpointing(name, chk_int)*   | Create a checkpoint after every *chk_int* GVT creation|
++------------------------------------+-------------------------------------------------------+
+|*setStateSaving(state_saving)*      | Change the method for state saving to *state_saving*  |
++------------------------------------+-------------------------------------------------------+
+
+.. note:: If any of these options are set during a local simulation, they will either throw a Exception or will simply have no effect.
+
+Automatic allocation
+--------------------
+
+Some models are very simple, but tedious, to distribute. As long as the actual allocation has no real importance, there is an additional option *setAutoAllocation(autoAllocate)* which will have the simulator distribute the models automatically. This distribution is rather efficient, though it is often suboptimal. It will simply try to balance the amount of atomic models at every node, not taking into account the actual activity of these models. Furthermore, it only works at the root level.
+
+Even though it doesn't perform intelligent distribution, it will work in situations where root models can work in parallel without influencing each other. More information can be found in :doc:`Static Allocators <staticallocator>`
+
+General tips
+------------
+
+The distributed simulation algorithm that is being used is Time Warp. This means that every node will simulate *optimistically* in the assumption that other models have progressed as far as itself. As soon as a message from the past arrives, simulation at that node will be rolled back. This implies that nodes should have an equal load and that as few as messages should be exchanged between different nodes.
+
+Therefore, the following rules should be taken into account to maximize the performance in distributed simulation:
+
+* Models that exchange lots of messages should be on the same node
+* Balance the load between nodes, so that the deviation is minimal
+* Use homogeneous nodes
+* Use quantums where possible, thus reducing the amount of messages
+
+.. note:: Due to time warp's property of saving (nearly) everything, it is possible to quickly run out of memory. It is therefore adviced to set the GVT calculation time to a reasonable number. Running the GVT algorithm frequently yields slightly worse performance, though it will clean up a lot of memory.

BIN
doc/distribution_local_model.png


+ 44 - 0
doc/dynamicallocator.rst

@@ -0,0 +1,44 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Dynamic Allocator
+=================
+
+Dynamic allocators are almost the same as the static allocators, with the exception that they make their allocation at a GVT calculation step instead of at the beginning.
+
+Before the dynamic allocator gets to run, the model will have already simulated for some time. Due to this simulation, which will have happened completely locally, the simulator will have already collected activity information.
+
+Since the simulation ran locally and with the pure intention of finding a decent allocation, the simulator will gather a lot more statistics such as the amount of transferred messages over a connection.
+
+In dynamic allocation mode, the model drawing functionality will also mention the load on the connections.
+
+Writing a custom allocator
+--------------------------
+
+Writing a dynamic allocator is the same as writing a static allocator, with the exception that the 2 arguments which were always *None* will now be filled in.
+
+The *edges* argument will contain a dictionary with another dictionary in it. The value in it will be a message counter. This means that the value returned by *edges[a][b]* will be the amount of messages between *a* and *b*.
+
+The *totalActivities* argument will be a dictionary containing the accumulated activity of every model in the complete simulation.
+
+Which of this information is used (and how) is of course up to you.
+
+The *getTerminationTime()* method will now be used to indicate how long a *warm-up* period takes for the simulator. This will not be done perfectly, but up to the first GVT calculation that goes beyond this termination time. If this method returns *0*, it becomes a static allocator and will not be able to use the 2 parameters that are dependent on the simulation run.
+
+Using the allocator
+-------------------
+
+Using a dynamic allocator is identical to using a static one, so please refer to the explanation in the :doc:`previous section <staticallocator>`

File diff suppressed because it is too large
+ 76 - 0
doc/dynamicstructure.rst


+ 17 - 0
doc/elapsed_time.rst

@@ -0,0 +1,17 @@
+.. _elapsed_time:
+
+Elapsed time
+============
+
+In PythonPDEVS, the elapsed time is present in the attribute *elapsed*.
+While the attribute is always there, its value is only guaranteed to be correct during the execution of an external transition.
+For compatibility reasons, in Parallel DEVS, the confluent transition will also set the elapsed time to 0.
+
+It might seem strange to put the elapsed time as an attribute, instead of a parameter.
+The reason for this is that, during model initialization, it is possible to set the elapsed time to some value.
+The time at which that specific atomic model was initialized, will then be set to the negative elapsed time.
+This implies that the initial time advance is larger than the configured elapsed time.
+
+For example, if a model sets its elapsed time to -1.5 during model initialization, and has a time advance of 2, the first transition will happen at simulated time 0.5.
+Note, however, that for the model it will seem as if the actual 2 units of simulated time have passed.
+It thus merely allows for a fixed deviation between the starting point of different models.

+ 296 - 0
doc/examples.rst

@@ -0,0 +1,296 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Examples for Parallel DEVS
+==========================
+
+A small *trafficModel* and corresponding *trafficExperiment* file is included in the *examples* folder of the PyPDEVS distribution. This (completely working) example is slightly too big to use as a first introduction to PyPDEVS and therefore this page will start with a very simple example.
+
+For this, we will first introduce a simplified queue model, which will be used as the basis of all our examples. The complete model can be downloaded: :download:`queue_example.py <queue_example.py>`.
+
+This section should provide you with all necessary information to get you started with creating your very own PyPDEVS simulation. More advanced features are presented in the next section.
+
+Generator
+---------
+
+Somewhat simpler than a queue even, is a generator. It will simply create a message to send after a certain delay and then it will stop doing anything.
+
+Informally, this would result in a DEVS specification as:
+
+* Time advance function returns the waiting time to generate the message, infinity after the message was created
+* Output function outputs the generated message
+* Internal transition function marks the generator as done
+* External transition function will never happen (as there are no inputs)
+* Confluent transition function will never happen (as no external transition will ever happen)
+
+In PythonPDEVS, this simply becomes the class::
+
+    class Generator(AtomicDEVS):
+        def __init__(self):
+            AtomicDEVS.__init__(self, "Generator")
+            self.state = True
+            self.outport = self.addOutPort("outport")
+
+        def timeAdvance(self):
+            if self.state:
+                return 1.0
+            else:
+                return INFINITY
+
+        def outputFnc(self):
+            # Our message is simply the integer 5, though this could be anything
+            # It is mandatory to output lists (which signify the 'bag')
+            return {self.outport: [5]}
+
+        def intTransition(self):
+            self.state = False
+            return self.state
+
+Note that all functions have a *default* behaviour, which is sufficient if the function will never be called. In most situations, the *confTransition* function is sufficient and rarely requires to be overwritten.
+
+It is possible to simulate this model, though nothing spectacular will happen. For this reason, we will postpone actual simulation examples.
+
+Simple queue
+------------
+
+To couple the *Generator* model up to something useful, we will now create a simple queue model. It doesn't do any real computation and just forwards the message after a certain (fixed) time delay. For simplicity, we allow the queue to *drop* the previous message if a message was already being processed.
+
+Informally, this would result in a DEVS specification as:
+
+* Time advance function returns the processing time if a message is being processed, or INFINITY otherwise
+* Output function outputs the message
+* Internal transition function removes the message from the queue
+* External transition function adds the message to the queue
+* Confluent transition function can simply default to the internal transition function, immeditaly followed by the external transition function
+
+To implement this in PythonPDEVS, one simply has to write::
+
+  class Queue(AtomicDEVS):
+    def __init__(self):
+        AtomicDEVS.__init__(self, "Queue")
+        self.state = None
+        self.processing_time = 1.0
+        self.inport = self.addInPort("input")
+        self.outport = self.addOutPort("output")
+
+    def timeAdvance(self):
+        if self.state is None:
+            return INFINITY
+        else:
+            return self.processing_time
+
+    def outputFnc(self):
+        return {self.outport: [self.state]}
+
+    def extTransition(self, inputs):
+        # To access them, you will need to access each element seperately
+        # In this case, we only use the first element from the bag as we
+        # know that it will only contain one element
+        self.state = inputs[self.inport][0]
+        return self.state
+
+    def intTransition(self):
+        self.state = None
+        return self.state
+    
+And we are done with our basic queue model. 
+
+However, there is currently no means of testing it, as simply simulating this model will have no effect, due to no messages arriving. We will thus have to couple it with the *Generator* we previously made.
+
+Coupling
+--------
+
+To couple up the *Generator* to the *Queue*, all we have to do is create a *CoupledDEVS* class and simulate this class::
+
+    class CQueue(CoupledDEVS):
+        def __init__(self):
+            CoupledDEVS.__init__(self, "CQueue")
+            self.generator = self.addSubModel(Generator())
+            self.queue = self.addSubModel(Queue())
+            self.connectPorts(self.generator.outport, self.queue.inport)
+
+That is all for the coupled model. Note that it is not required for every port of a model to be connected to another port. For example the *outport* of the *Queue* is not connected. Any output that is put on this port is thus discarded.
+
+It is perfectly allowed to do model construction and connection in e.g. a loop or conditionally, as long as the required functions are called.
+
+.. note:: The DEVS formalism allows for an input-to-output translation function, but this is not implemented in PythonPDEVS.
+
+Simulation
+----------
+
+Now that we have an actual coupled model that does something remotely useful, it is time to simulate it. Simulation is as simple as constructing a *Simulator* object with the model and calling *simulate()* on the simulator::
+
+    model = CQueue()
+    sim = Simulator(model)
+    sim.simulate()
+
+Sadly, nothing seems to happen because no tracers are enabled. Note that it is possible to access the attributes of the model and see that they are actually changed as directed by the simulation::
+    
+    model = CQueue()
+    print(model.generator.state)
+    sim = Simulator(model)
+    sim.simulate()
+    print(model.generator.state)
+
+This code will simply print *True* in the beginning and *False* at the end, since the model is updated in-place in this situation. The model will **not** be simulated in-place if either simulation is distributed, or reinitialisation is enabled.
+
+Tracing
+-------
+
+To actually see some results from the simulation, it is advised to enable certain tracers. The simplest tracer is the *verbose* tracer, which will output some details in a human-readable format. Enabling the verbose tracer is as simple as setting the *setVerbose()* configuration to a destination file. For the verbose tracer, it is also possible to trace to stdout by using the *None* argument::
+
+    model = CQueue()
+    sim = Simulator(model)
+    sim.setVerbose(None)
+    sim.simulate()
+
+Saving the output to a file can de done by passing the file name as a string. Note that a file handle does **not** work::
+
+    model = CQueue()
+    sim = Simulator(model)
+    sim.setVerbose("myOutputFile")
+    sim.simulate()
+
+Multiple tracers can be defined simultaneously, all of which will be used. So to trace to the files *myOutputFile* and *myOutputFile* and simultaneously output to stdout, you could use::
+
+    model = CQueue()
+    sim = Simulator(model)
+    sim.setVerbose("myOutputFile")
+    sim.setVerbose(None)
+    sim.setVerbose("myOutputFile2")
+    sim.simulate()
+
+.. note:: There is no way to unset a single tracer. There is however a way to remove all currently registered tracers: *setRemoveTracers()*, though it is generally only useful in reinitialized simulations.
+
+An example output of the *verbose* tracer is::
+
+    __  Current Time:       0.00 __________________________________________
+
+        INITIAL CONDITIONS in model <CQueue.Generator>
+        Initial State: True
+        Next scheduled internal transition at time 1.00
+
+        INITIAL CONDITIONS in model <CQueue.Queue>
+        Initial State: None
+        Next scheduled internal transition at time inf
+
+    __  Current Time:       1.00 __________________________________________
+
+        EXTERNAL TRANSITION in model <CQueue.Queue>
+        Input Port Configuration:
+            port <input>:
+                5
+        New State: 5
+        Next scheduled internal transition at time 2.00
+
+        INTERNAL TRANSITION in model <CQueue.Generator>
+        New State: False
+        Output Port Configuration:
+            port <outport>:
+                5
+        Next scheduled internal transition at time inf
+
+    __  Current Time:       2.00 __________________________________________
+
+        INTERNAL TRANSITION in model <CQueue.Queue>
+        New State: None
+        Output Port Configuration:
+            port <output>:
+                5
+        Next scheduled internal transition at time inf
+
+.. note:: Several other tracers are available, such as *VCD*, *XML* and *Cell*. Their usage is very similar and is only useful in several situations. Only the *Cell* tracer requires further explanation and is mentioned in the *Advanced examples* section.
+
+Termination
+-----------
+
+Our previous example stopped simulation automatically, since both models returned a time advance equal to infinity.
+
+In several cases, it is desired to stop simulation after a certain period. The simplest example of this is when the *Generator* would keep generating messages after a certain delay. Without a termination condition, the simulation will keep going forever.
+
+Adding a termination time is as simple as setting one additional configuration option::
+    
+    sim.setTerminationTime(5.0)
+
+This will make the simulation stop as soon as simulation time 5.0 is reached. 
+
+A termination time is sufficient in most situations, though it is possible to use a more advanced approach: using a termination function. Using the option::
+
+    sim.setTerminationCondition(termFunc)
+
+With this additional option, the function *termFunc* will be evaluated at every timestep. If the function returns *True*, simulation will stop. The function will receive 2 parameters from the simulator: the model being simulated and the current simulation time.
+
+Should our generator save the number of messages it has generated, an example of such a termination function could be::
+
+    def termFunc(clock, model):
+        if model.generator.generated > 5:
+            # The generator has generated more than 5 events
+            # So stop
+            return True
+        elif clock[0] > 10:
+            # Or if the clock has progressed past simulation time 10
+            return True
+        else:
+            # Otherwise, we simply continue
+            return False
+
+The *clock* parameter in the termination condition will be a **tuple** instead of a simple floating point number. The first field of the tuple is the current simulation time (and can be used as such). The second field is a so-called *age* field, containing the number of times the same simulation time has occured. This is passed on in the termination condition as it is required in some cases for distributed simulation.
+
+.. note:: Using a termination function is a lot slower than simply using a termination time. This option should therefore be avoided if at all possible.
+
+.. warning:: It is **only** allowed to read from the model in the termination function. Performing write actions to the model has unpredictable consequences!
+
+.. warning:: Running a termination function in a distributed simulation is slightly different, so please refer to the advanced section for this!
+
+Simulation time
+---------------
+
+Accessing the global simulation time is a frequent operation, though it is not supported by DEVS out-of-the-box. Of course, the simulator internally keeps such a clock, though this is not meant to be accessed by the user directly as it is an implementation detail of PyPDEVS (and it might even change between releases!).
+
+If you require access to the simulation time, e.g. to put a timestamp on a message, this can be done by writing some additional code in the model that requires this time as follows::
+
+    class MyModelState():
+        def __init__(self):
+            self.actual_state = ...
+            self.current_time = 0.0
+        
+    class MyModel(AtomicDEVS):
+        def __init__(self, ...):
+            AtomicDEVS.__init__(self, "ExampleModel")
+            self.state = MyModelState()
+            ...
+
+        def extTransition(self, inputs):
+            self.state.current_time += self.elapsed
+            ...
+            return self.state
+
+        def intTransition(self):
+            self.state.current_time += self.timeAdvance()
+            ...
+            return self.state
+
+        def confTransition(self, inputs):
+            self.state.current_time += self.timeAdvance()
+            ...
+            return self.state
+
+In the *extTransition* method, we use the *elapsed* attribute to determine the time between the last transition and the current transition. However, in the *intTransition* we are **not** allowed to access it.
+A more detailed explanation can be found at :ref:`elapsed_time`.
+
+You are allowed to call the *timeAdvance* method again, as this is the time that was waited before calling the internal transition function (as defined in the DEVS formalism).
+This requires, however, that your timeAdvance is deterministic (as it should be).
+Deterministic timeAdvance functions are not trivial if you use random numbers, for which you should read up on :ref:`random_numbers` in PythonPDEVS.

+ 297 - 0
doc/examples_classic.rst

@@ -0,0 +1,297 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Examples
+========
+
+A small *trafficModel* and corresponding *trafficExperiment* file is included in the *examples* folder of the PyPDEVS distribution. This (completely working) example is slightly too big to use as a first introduction to PyPDEVS and therefore this page will start with a very simple example.
+
+For this, we will first introduce a simplified queue model, which will be used as the basis of all our examples. The complete model can be downloaded: :download:`queue_example_classic.py <queue_example_classic.py>`.
+
+This section should provide you with all necessary information to get you started with creating your very own PyPDEVS simulation. More advanced features are presented in the next section.
+
+Generator
+---------
+
+Somewhat simpler than a queue even, is a generator. It will simply create a message to send after a certain delay and then it will stop doing anything.
+
+Informally, this would result in a DEVS specification as:
+
+* Time advance function returns the waiting time to generate the message, infinity after the message was created
+* Output function outputs the generated message
+* Internal transition function marks the generator as done
+* External transition function will never happen (as there are no inputs)
+
+In PythonPDEVS, this simply becomes the class::
+
+    class Generator(AtomicDEVS):
+        def __init__(self):
+            AtomicDEVS.__init__(self, "Generator")
+            self.state = True
+            self.outport = self.addOutPort("outport")
+
+        def timeAdvance(self):
+            if self.state:
+                return 1.0
+            else:
+                return INFINITY
+
+        def outputFnc(self):
+            # Our message is simply the integer 5, though this could be anything
+            return {self.outport: 5}
+
+        def intTransition(self):
+            self.state = False
+            return self.state
+
+Note that all functions have a *default* behaviour, which is sufficient if the function will never be called.
+
+It is possible to simulate this model, though nothing spectacular will happen. For this reason, we will postpone actual simulation examples.
+
+Simple queue
+------------
+
+To couple the *Generator* model up to something useful, we will now create a simple queue model. It doesn't do any real computation and just forwards the message after a certain (fixed) time delay. For simplicity, we allow the queue to *drop* the previous message if a message was already being processed.
+
+Informally, this would result in a DEVS specification as:
+
+* Time advance function returns the processing time if a message is being processed, or INFINITY otherwise
+* Output function outputs the message
+* Internal transition function removes the message from the queue
+* External transition function adds the message to the queue
+
+To implement this in PythonPDEVS, one simply has to write::
+
+  class Queue(AtomicDEVS):
+    def __init__(self):
+        AtomicDEVS.__init__(self, "Queue")
+        self.state = None
+        self.processing_time = 1.0
+        self.inport = self.addInPort("input")
+        self.outport = self.addOutPort("output")
+
+    def timeAdvance(self):
+        if self.state is None:
+            return INFINITY
+        else:
+            return self.processing_time
+
+    def outputFnc(self):
+        return {self.outport: self.state}
+
+    def extTransition(self, inputs):
+        self.state = inputs[self.inport]
+        return self.state
+
+    def intTransition(self):
+        self.state = None
+        return self.state
+    
+And we are done with our basic queue model. 
+
+However, there is currently no means of testing it, as simply simulating this model will have no effect, due to no messages arriving. We will thus have to couple it with the *Generator* we previously made.
+
+Coupling
+--------
+
+To couple up the *Generator* to the *Queue*, all we have to do is create a *CoupledDEVS* class and simulate this class::
+
+    class CQueue(CoupledDEVS):
+        def __init__(self):
+            CoupledDEVS.__init__(self, "CQueue")
+            self.generator = self.addSubModel(Generator())
+            self.queue = self.addSubModel(Queue())
+            self.connectPorts(self.generator.outport, self.queue.inport)
+
+That is all for the coupled model. Note that it is not required for every port of a model to be connected to another port. For example the *outport* of the *Queue* is not connected. Any output that is put on this port is thus discarded.
+
+It is perfectly allowed to do model construction and connection in e.g. a loop or conditionally, as long as the required functions are called.
+
+.. note:: The DEVS formalism allows for an input-to-output translation function, but this is not implemented in PythonPDEVS.
+
+Simulation
+----------
+
+Now that we have an actual coupled model that does something remotely useful, it is time to simulate it. Simulation is as simple as constructing a *Simulator* object with the model and calling *simulate()* on the simulator::
+
+    model = CQueue()
+    sim = Simulator(model)
+    # Required to set Classic DEVS, as we simulate in Parallel DEVS otherwise
+    sim.setClassicDEVS()
+    sim.simulate()
+
+Be sure not to forget to call the *setClassicDEVS()* method, as otherwise your model will be simulated using Parallel DEVS (likely resulting into errors).
+
+Sadly, nothing seems to happen because no tracers are enabled. Note that it is possible to access the attributes of the model and see that they are actually changed as directed by the simulation::
+    
+    model = CQueue()
+    print(model.generator.state)
+    sim = Simulator(model)
+    # Required to set Classic DEVS, as we simulate in Parallel DEVS otherwise
+    sim.setClassicDEVS()
+    sim.simulate()
+    print(model.generator.state)
+
+This code will simply print *True* in the beginning and *False* at the end, since the model is updated in-place in this situation. The model will **not** be simulated in-place if reinitialisation is enabled.
+
+Tracing
+-------
+
+To actually see some results from the simulation, it is advised to enable certain tracers. The simplest tracer is the *verbose* tracer, which will output some details in a human-readable format. Enabling the verbose tracer is as simple as setting the *setVerbose()* configuration to a destination file. For the verbose tracer, it is also possible to trace to stdout by using the *None* argument::
+
+    model = CQueue()
+    sim = Simulator(model)
+    sim.setVerbose(None)
+    # Required to set Classic DEVS, as we simulate in Parallel DEVS otherwise
+    sim.setClassicDEVS()
+    sim.simulate()
+
+Saving the output to a file can de done by passing the file name as a string. Note that a file handle does **not** work::
+
+    model = CQueue()
+    sim = Simulator(model)
+    sim.setVerbose("myOutputFile")
+    # Required to set Classic DEVS, as we simulate in Parallel DEVS otherwise
+    sim.setClassicDEVS()
+    sim.simulate()
+
+Multiple tracers can be defined simultaneously, all of which will be used. So to trace to the files *myOutputFile* and *myOutputFile* and simultaneously output to stdout, you could use::
+
+    model = CQueue()
+    sim = Simulator(model)
+    sim.setVerbose("myOutputFile")
+    sim.setVerbose(None)
+    sim.setVerbose("myOutputFile2")
+    # Required to set Classic DEVS, as we simulate in Parallel DEVS otherwise
+    sim.setClassicDEVS()
+    sim.simulate()
+
+.. note:: There is no way to unset a single tracer. There is however a way to remove all currently registered tracers: *setRemoveTracers()*, though it is generally only useful in reinitialized simulations.
+
+An example output of the *verbose* tracer is::
+
+    __  Current Time:       0.00 __________________________________________
+
+        INITIAL CONDITIONS in model <CQueue.Generator>
+        Initial State: True
+        Next scheduled internal transition at time 1.00
+
+        INITIAL CONDITIONS in model <CQueue.Queue>
+        Initial State: None
+        Next scheduled internal transition at time inf
+
+    __  Current Time:       1.00 __________________________________________
+
+        EXTERNAL TRANSITION in model <CQueue.Queue>
+        Input Port Configuration:
+            port <input>:
+                5
+        New State: 5
+        Next scheduled internal transition at time 2.00
+
+        INTERNAL TRANSITION in model <CQueue.Generator>
+        New State: False
+        Output Port Configuration:
+            port <outport>:
+                5
+        Next scheduled internal transition at time inf
+
+    __  Current Time:       2.00 __________________________________________
+
+        INTERNAL TRANSITION in model <CQueue.Queue>
+        New State: None
+        Output Port Configuration:
+            port <output>:
+                5
+        Next scheduled internal transition at time inf
+
+.. note:: Several other tracers are available, such as *VCD*, *XML* and *Cell*. Their usage is very similar and is only useful in several situations. Only the *Cell* tracer requires further explanation and is mentioned in the *Advanced examples* section.
+
+Termination
+-----------
+
+Our previous example stopped simulation automatically, since both models returned a time advance equal to infinity.
+
+In several cases, it is desired to stop simulation after a certain period. The simplest example of this is when the *Generator* would keep generating messages after a certain delay. Without a termination condition, the simulation will keep going forever.
+
+Adding a termination time is as simple as setting one additional configuration option::
+    
+    sim.setTerminationTime(5.0)
+
+This will make the simulation stop as soon as simulation time 5.0 is reached. 
+
+A termination time is sufficient in most situations, though it is possible to use a more advanced approach: using a termination function. Using the option::
+
+    sim.setTerminationCondition(termFunc)
+
+With this additional option, the function *termFunc* will be evaluated at every timestep. If the function returns *True*, simulation will stop. The function will receive 2 parameters from the simulator: the model being simulated and the current simulation time.
+
+Should our generator save the number of messages it has generated, an example of such a termination function could be::
+
+    def termFunc(clock, model):
+        if model.generator.generated > 5:
+            # The generator has generated more than 5 events
+            # So stop
+            return True
+        elif clock[0] > 10:
+            # Or if the clock has progressed past simulation time 10
+            return True
+        else:
+            # Otherwise, we simply continue
+            return False
+
+The *clock* parameter in the termination condition will be a **tuple** instead of a simple floating point number. The first field of the tuple is the current simulation time (and can be used as such). The second field is a so-called *age* field, containing the number of times the same simulation time has occured. This is passed on in the termination condition as it is required in some cases for distributed simulation.
+
+.. note:: Using a termination function is a lot slower than simply using a termination time. This option should therefore be avoided if at all possible.
+
+.. warning:: It is **only** allowed to read from the model in the termination function. Performing write actions to the model has unpredictable consequences!
+
+.. warning:: Running a termination function in a distributed simulation is slightly different, so please refer to the advanced section for this!
+
+Simulation time
+---------------
+
+Accessing the global simulation time is a frequent operation, though it is not supported by DEVS out-of-the-box. Of course, the simulator internally keeps such a clock, though this is not meant to be accessed by the user directly as it is an implementation detail of PyPDEVS (and it might even change between releases!).
+
+If you require access to the simulation time, e.g. to put a timestamp on a message, this can be done by writing some additional code in the model that requires this time as follows::
+
+    class MyModelState():
+        def __init__(self):
+            self.actual_state = ...
+            self.current_time = 0.0
+        
+    class MyModel(AtomicDEVS):
+        def __init__(self, ...):
+            AtomicDEVS.__init__(self, "ExampleModel")
+            self.state = MyModelState()
+            ...
+
+        def extTransition(self, inputs):
+            self.state.current_time += self.elapsed
+            ...
+            return self.state
+
+        def intTransition(self):
+            self.state.current_time += self.timeAdvance()
+            ...
+            return self.state
+
+In the *extTransition* method, we use the *elapsed* attribute to determine the time between the last transition and the current transition. However, in the *intTransition* we are **not** allowed to access it.
+A more detailed explanation can be found at :ref:`elapsed_time`.
+
+You are allowed to call the *timeAdvance* method again, as this is the time that was waited before calling the internal transition function (as defined in the DEVS formalism).
+This requires, however, that your timeAdvance is deterministic (as it should be).
+Deterministic timeAdvance functions are not trivial if you use random numbers, for which you should read up on :ref:`random_numbers` in PythonPDEVS.

+ 223 - 0
doc/examples_ds.rst

@@ -0,0 +1,223 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Examples for Dynamic Structure DEVS
+===================================
+
+We used the same approach to Dynamic Structure as adevs, meaning that a *modelTransition* method will be called at every step in simulated time on every model that transitioned.
+
+A small *trafficLight* model is included in the *examples* folder of the PyPDEVS distribution. In this section, we introduce the use of the new constructs.
+
+Dynamic structure is possible for both Classic and Parallel DEVS, but only for local simulation.
+
+Starting point
+--------------
+
+We will start from a very simple Coupled DEVS model, which contains 2 Atomic DEVS models.
+The first model sends messages on its output port, which are then routed to the second model.
+Note that, for compactness, we include the experiment part in the same file as the model.
+
+This can be expressed as follows (:download:`base_dsdevs.py <base_dsdevs.py>`)::
+
+    from pypdevs.DEVS import AtomicDEVS, CoupledDEVS
+    from pypdevs.simulator import Simulator
+
+    class Root(CoupledDEVS):
+        def __init__(self):
+            CoupledDEVS.__init__(self, "Root")
+            self.models = []
+            # First model
+            self.models.append(self.addSubModel(Generator()))
+            # Second model
+            self.models.append(self.addSubModel(Consumer(0)))
+            # And connect them
+            self.connectPorts(self.models[0].outport, self.models[1].inport)
+
+    class Generator(AtomicDEVS):
+        def __init__(self):
+            AtomicDEVS.__init__(self, "Generator")
+            # Keep a counter of how many events were sent
+            self.outport = self.addOutPort("outport")
+            self.state = 0
+
+        def intTransition(self):
+            # Increment counter
+            return self.state + 1
+
+        def outputFnc(self):
+            # Send the amount of messages sent on the output port
+            return {self.outport: [self.state]}
+
+        def timeAdvance(self):
+            # Fixed 1.0
+            return 1.0
+
+    class Consumer(AtomicDEVS):
+        def __init__(self, count):
+            AtomicDEVS.__init__(self, "Consumer_%i" % count)
+            self.inport = self.addInPort("inport")
+
+        def extTransition(self, inputs):
+            for inp in inputs[self.inport]:
+                print("Got input %i on model %s" % (inp, self.name))
+
+    sim = Simulator(Root())
+    sim.setTerminationTime(5)
+    sim.simulate()
+
+All undefined functions will just use the default implementation.
+As such, this model will simply print messages::
+
+    Got input 0 on model Consumer_0
+    Got input 1 on model Consumer_0
+    Got input 2 on model Consumer_0
+    Got input 3 on model Consumer_0
+    Got input 4 on model Consumer_0
+
+We will now extend this model to include dynamic structure.
+
+Dynamic Structure
+-----------------
+
+To allow for dynamic structure, we need to augment both our experiment and our model.
+
+Experiment
+^^^^^^^^^^
+
+First, the dynamic structure configuration parameter should be enabled in the experiment.
+For performance reasons, this feature is disabled by default. It can be enabled as follows::
+
+    sim = Simulator(Root())
+    sim.setTerminationTime(5)
+    sim.setDSDEVS(True)
+    sim.simulate()
+
+Model
+^^^^^
+
+With dynamic structure enabled, models can define a new method: *modelTransition(state)*.
+This method is called on all Atomic DEVS models that executed a transition in that time step.
+
+This method is invoked on the model, and can thus access the state of the model.
+For now, ignore the *state* parameter.
+In this method, all modifications on the model are allowed, as it was during model construction.
+That is, it is possible to invoke the following methods::
+
+    setInPort(portname)
+    setOutPort(portname)
+    addSubModel(model)
+    connectPorts(output, input)
+
+But apart from these known methods, it is also possible to delete existing constructs, with the operations::
+
+    removePort(port)
+    removeSubModel(model)
+    disconnectPorts(output, input)
+
+On Atomic DEVS models, only the port operations are available. On Coupled DEVS models, all of these are available.
+Removing a port or submodel will automatically disconnect all its connections.
+
+The method will also return a boolean, indicating whether or not to propagate the structural changes on to the parent model.
+If it is *True*, the method is invoked on the parent as well. Note that the root model should not return *True*.
+Propagation is necessary, as models are only allowed to change the structure of their subtree.
+
+.. NOTE::
+   In the latest implementation, modifying the structure outside of your own subtree has no negative consequences. However, it should be seen as a best practice to only modify yourself.
+
+For example, to create a second receiver as soon as the generator has output 3 messages, you can modify the following methods (:download:`simple_dsdevs.py <simple_dsdevs.py>`)::
+
+    class Generator(AtomicDEVS):
+        ...
+        def modelTransition(self, state):
+            # Notify parent of structural change if state equals 3
+            return self.state == 3
+
+    class Root(CoupledDEVS):
+        ...
+        def modelTransition(self, state):
+            # We are notified, so are required to add a new model and link it
+            self.models.append(self.addSubModel(Consumer(1)))
+            self.connectPorts(self.models[0].outport, self.models[-1].inport)
+
+            ## Optionally, we could also remove the Consumer(0) instance as follows:
+            # self.removeSubModel(self.models[1])
+
+            # Always returns False, as this is top-level
+            return False
+
+This would give the following output (or similar, due to concurrency)::
+
+    Got input 0 on model Consumer_0
+    Got input 1 on model Consumer_0
+    Got input 2 on model Consumer_0
+    Got input 3 on model Consumer_0
+    Got input 3 on model Consumer_1
+    Got input 4 on model Consumer_0
+    Got input 4 on model Consumer_1
+
+.. NOTE::
+   As structural changes are not a common operation, their performance is not optimized extensively. To make matters worse, many structural optimizations done by PythonPDEVS will automatically be redone after each structural change.
+
+Passing state
+^^^^^^^^^^^^^
+
+Finally, we come to the *state* parameter of the modelTransition call.
+In some cases, it will be necessary to pass arguments to the parent, to notify it of how the structure should change.
+This is useful if the child knows information that is vital to the change.
+Since Coupled DEVS models cannot hold state, and should not directly access the state of their children, we can use the *state* parameter for this.
+
+The *state* parameter is simply a dictionary object, which is passed between all the different *modelTransition* calls.
+Simply put, it is an object shared by all calls.
+
+For example, if we would want the structural change from before to create a new consumer every time, with an ID provided by the Generator, this can be done as follows (:download:`state_dsdevs.py <state_dsdevs.py>`)::
+
+    class Generator(AtomicDEVS):
+        ...
+        def modelTransition(self, state):
+            # We pass on the ID that we would like to create, which is equal to our counter
+            state["ID"] = self.state
+            # Always create a new element
+            return True
+
+    class Root(CoupledDEVS):
+        ...
+        def modelTransition(self, state):
+            # We are notified, so are required to add a new model and link it
+            # We can use the ID provided by the model below us
+            self.models.append(self.addSubModel(Consumer(state["ID"])))
+            self.connectPorts(self.models[0].outport, self.models[-1].inport)
+
+            # Always returns False, as this is top-level
+            return False
+
+This would then create the output (or similar, due to concurrency)::
+
+    Got input 0 on model Consumer_0
+    Got input 1 on model Consumer_0
+    Got input 1 on model Consumer_1
+    Got input 2 on model Consumer_0
+    Got input 2 on model Consumer_1
+    Got input 2 on model Consumer_2
+    Got input 3 on model Consumer_0
+    Got input 3 on model Consumer_1
+    Got input 3 on model Consumer_2
+    Got input 3 on model Consumer_3
+
+More complex example
+====================
+
+In the PyPDEVS distribution, a more complex example is provided.
+That example provides a model of two traffic lights, with a policeman who periodically changes the traffic light he is interrupting.

+ 22 - 0
doc/experiment_fast.py

@@ -0,0 +1,22 @@
+# Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+# McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from pypdevs.simulator import Simulator
+from trafficLightModel import *
+model = TrafficLight(name="trafficLight")
+
+sim = Simulator(model)
+sim.setVerbose(None)
+sim.simulate()

+ 34 - 0
doc/experiment_loop.py

@@ -0,0 +1,34 @@
+# Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+# McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from pypdevs.simulator import Simulator
+from trafficLightModel import *
+model = TrafficLight(name="trafficLight")
+
+refs = {"INTERRUPT": model.INTERRUPT}
+sim = Simulator(model)
+sim.setRealTime(True)
+sim.setRealTimeInputFile(None)
+sim.setRealTimePorts(refs)
+sim.setVerbose(None)
+sim.setRealTimePlatformGameLoop()
+sim.simulate()
+
+import time
+while 1:
+    before = time.time()
+    sim.realtime_loop_call()
+    time.sleep(0.1 - (before - time.time()))
+    print("Current state: " + str(model.state.get()))

+ 33 - 0
doc/experiment_threads.py

@@ -0,0 +1,33 @@
+# Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+# McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from pypdevs.simulator import Simulator
+from trafficLightModel import *
+model = TrafficLight(name="trafficLight")
+
+refs = {"INTERRUPT": model.INTERRUPT}
+sim = Simulator(model)
+sim.setRealTime(True)
+sim.setRealTimeInputFile(None)
+sim.setRealTimePorts(refs)
+sim.setVerbose(None)
+sim.setRealTimePlatformThreads()
+sim.simulate()
+
+# If we get here, simulation will also end, as the sleep calls are daemon threads
+#  (otherwise, they would make the simulation unkillable)
+
+while 1:
+    sim.realtime_interrupt(raw_input())

+ 90 - 0
doc/experiment_tk.py

@@ -0,0 +1,90 @@
+# Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+# McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from pypdevs.simulator import Simulator
+
+from Tkinter import *
+from trafficLightModel import *
+
+isBlinking = None
+
+model = TrafficLight(name="trafficLight")
+refs = {"INTERRUPT": model.INTERRUPT}
+root = Tk()
+
+sim = Simulator(model)
+sim.setRealTime(True)
+sim.setRealTimeInputFile(None)
+sim.setRealTimePorts(refs)
+sim.setVerbose(None)
+sim.setRealTimePlatformTk(root)
+
+def toManual():
+    global isBlinking
+    isBlinking = False
+    sim.realtime_interrupt("INTERRUPT toManual")
+
+def toAutonomous():
+    global isBlinking
+    isBlinking = None
+    sim.realtime_interrupt("INTERRUPT toAutonomous")
+
+size = 50
+xbase = 10
+ybase = 10
+
+frame = Frame(root)
+canvas = Canvas(frame)
+canvas.create_oval(xbase, ybase, xbase+size, ybase+size, fill="black", tags="red_light")
+canvas.create_oval(xbase, ybase+size, xbase+size, ybase+2*size, fill="black", tags="yellow_light")
+canvas.create_oval(xbase, ybase+2*size, xbase+size, ybase+3*size, fill="black", tags="green_light")
+canvas.pack()
+frame.pack()
+
+def updateLights():
+    state = model.state.get()
+    if state == "red":
+        canvas.itemconfig("red_light", fill="red")
+        canvas.itemconfig("yellow_light", fill="black")
+        canvas.itemconfig("green_light", fill="black")
+    elif state == "yellow":
+        canvas.itemconfig("red_light", fill="black")
+        canvas.itemconfig("yellow_light", fill="yellow")
+        canvas.itemconfig("green_light", fill="black")
+    elif state == "green":
+        canvas.itemconfig("red_light", fill="black")
+        canvas.itemconfig("yellow_light", fill="black")
+        canvas.itemconfig("green_light", fill="green")
+    elif state == "manual":
+        canvas.itemconfig("red_light", fill="black")
+        global isBlinking
+        if isBlinking:
+            canvas.itemconfig("yellow_light", fill="yellow")
+            isBlinking = False
+        else:
+            canvas.itemconfig("yellow_light", fill="black")
+            isBlinking = True
+        canvas.itemconfig("green_light", fill="black")
+    root.after(500,  updateLights)
+
+b = Button(root, text="toManual", command=toManual)
+b.pack()
+c = Button(root, text="toAutonomous", command=toAutonomous)
+c.pack()
+
+root.after(100, updateLights)
+
+sim.simulate()
+root.mainloop()

+ 21 - 0
doc/greedyallocator_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Greedy Allocator
+================
+
+.. autoclass:: allocators.greedyAllocator.GreedyAllocator
+   :members:

+ 74 - 0
doc/howto.rst

@@ -0,0 +1,74 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+How to run PyPDEVS
+==================
+
+There are several ways to start up a PythonPDEVS simulation. The simplest of them all is simply by running the experiment file, as discussed in the :doc:`examples` section. For completeness, this method will also be mentioned as the first option.
+
+Local simulation
+----------------
+
+The simplest method is simply by running the experiment file, which looks something like::
+
+    model = MyModel()
+    sim = Simulator(model)
+    sim.simulate()
+
+For a more elaborate approach, please see the :doc:`examples` section.
+
+Distributed simulation with MPI
+-------------------------------
+
+Running the MPI version requires the *mpi4py* Python module.
+
+Since version 2.1, running the MPI version was completely redesigned and severely simplified. PyPDEVS will now automatically detect the usage of MPI when the correct invocation is done.
+
+.. code-block:: bash
+
+   mpirun -np 3 python experiment.py
+
+Depending on the MPI backend that is used, several additional options might be possible. Please consult the documentation of your MPI implementation for more information.
+
+Distributed simulation with PyRO
+--------------------------------
+
+.. versionchanged:: 2.2.0
+   PyRO support was dropped.
+
+.. note:: This method is no longer advised or actively developed. Most special features are **only** supported on MPI due to limitations in PyRO. Furthermore, PyRO is dramatically slow in comparison to MPI.
+
+Running the PyRO version requires the *PyRO4* Python module.
+
+Starting a simulation in PyRO is almost as simple as starting it as if it was a local simulation. The only difference is that we require both a nameserver and (possibly multiple) simulation node(s).
+
+A basic version of the nameserver can be started running:
+
+.. code-block:: bash
+
+   python -m Pyro4.naming
+
+As soon as this nameserver is started up, each simulation node still needs to be set up. This can be done by running the :doc:`server` file with the name of the server as a parameter. For example:
+
+.. code-block:: bash
+
+   user@node-1$ python server.py 1
+   user@node-2$ python server.py 2
+   user@node-3$ python server.py 3
+
+The name of the server should be incremental numbers, starting from 1. The server with name 0 is reserved for the controller, as is the common naming in MPI.
+
+.. warning:: PyRO simulation is possibly started from several different folders, which might cause import problems. PyRO transfers models as pickles, so the user should make sure that the **exact** same file structure is visible for the referenced files.

+ 44 - 0
doc/index.rst

@@ -0,0 +1,44 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+.. PythonPDEVS documentation master file, created by
+   sphinx-quickstart on Sat Sep 28 20:20:40 2013.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+Welcome to PythonPDEVS's documentation!
+=======================================
+
+The Interface section contains all information about the functions and methods that should be used by the modeller. Internal documentation shows the complete interface that is only supposed to be used by the simulator itself.
+
+.. warning:: Only the methods mentioned in the Interface subsection should be used by the user, all others can have unexpected side effects due to the use of Time-Warp!
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   Installation <installation>
+   How to run <howto>
+   Changelog <changelog>
+   Interface <interface>
+   Differences from PyDEVS <differences>
+   Examples (Classic DEVS) <examples_classic>
+   Examples (Parallel DEVS) <examples>
+   Examples (Dynamic Structure DEVS) <examples_ds>
+   Advanced examples <advanced>
+   Common problems and solutions <problems>
+   Internal documentation <internal>

+ 20 - 0
doc/infinity.rst

@@ -0,0 +1,20 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Infinity object
+===============
+
+.. autodata:: infinity.INFINITY

+ 192 - 0
doc/injection.py

@@ -0,0 +1,192 @@
+# Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+# McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+# 
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Import code for DEVS model representation:
+from pypdevs.infinity import *
+from pypdevs.DEVS import *
+
+#    ======================================================================    #
+
+class TrafficLightMode:
+
+  """Encapsulates the system's state
+  """
+
+  ###
+  def __init__(self, current="red"):
+    """Constructor (parameterizable).
+    """
+    self.set(current)
+
+  def set(self, value="red"):
+    self.__colour=value
+
+  def get(self):
+    return self.__colour
+
+  def __str__(self):
+    return self.get()
+
+class TrafficLight(AtomicDEVS):
+  """A traffic light 
+  """
+  
+  ###
+  def __init__(self, name=None):
+    """Constructor (parameterizable).
+    """
+    
+    # Always call parent class' constructor FIRST:
+    AtomicDEVS.__init__(self, name)
+    
+    # STATE:
+    #  Define 'state' attribute (initial sate):
+    self.state = TrafficLightMode("red") 
+
+    # PORTS:
+    #  Declare as many input and output ports as desired
+    #  (usually store returned references in local variables):
+    self.INTERRUPT = self.addInPort(name="INTERRUPT")
+    self.OBSERVED = self.addOutPort(name="OBSERVED")
+
+  ###
+  def extTransition(self, inputs):
+    """External Transition Function."""
+    
+    # Compute the new state 'Snew' based (typically) on current
+    # State, Elapsed time parameters and calls to 'self.peek(self.IN)'.
+    #input = self.peek(self.INTERRUPT)
+    input = inputs[self.INTERRUPT][0]
+
+    state = self.state.get()
+
+    if input == "toManual":
+      if state == "manual":
+       # staying in manual mode
+       return TrafficLightMode("manual")
+      if state in ("red", "green", "yellow"):
+       return TrafficLightMode("manual")
+      else:
+       raise DEVSException(\
+        "unknown state <%s> in TrafficLight external transition function"\
+        % state)
+    
+    if input == "toAutonomous":
+      if state == "manual":
+        return TrafficLightMode("red")
+      else:
+       raise DEVSException(\
+        "unknown state <%s> in TrafficLight external transition function"\
+        % state) 
+
+    raise DEVSException(\
+      "unknown input <%s> in TrafficLight external transition function"\
+      % input) 
+
+  ###
+  def intTransition(self):
+    """Internal Transition Function.
+    """
+
+    state = self.state.get()
+
+    if state == "red":
+      return TrafficLightMode("green")
+    elif state == "green":
+      return TrafficLightMode("yellow")
+    elif state == "yellow":
+      return TrafficLightMode("red")
+    else:
+      raise DEVSException(\
+        "unknown state <%s> in TrafficLight internal transition function"\
+        % state)
+  
+  ###
+  def outputFnc(self):
+    """Output Funtion.
+    """
+   
+    # A colourblind observer sees "grey" instead of "red" or "green".
+ 
+    # BEWARE: ouput is based on the OLD state
+    # and is produced BEFORE making the transition.
+    # We'll encode an "observation" of the state the
+    # system will transition to !
+
+    # Send messages (events) to a subset of the atomic-DEVS' 
+    # output ports by means of the 'poke' method, i.e.:
+    # The content of the messages is based (typically) on current State.
+ 
+    state = self.state.get()
+
+    if state == "red":
+      return {self.OBSERVED: ["grey"]}
+    elif state == "green":
+      return {self.OBSERVED: ["yellow"]}
+      # NOT return {self.OBSERVED: ["grey"]}
+    elif state == "yellow":
+      return {self.OBSERVED: ["grey"]}
+      # NOT return {self.OBSERVED: ["yellow"]}
+    else:
+      raise DEVSException(\
+        "unknown state <%s> in TrafficLight external transition function"\
+        % state)
+    
+  ###
+  def timeAdvance(self):
+    """Time-Advance Function.
+    """
+    
+    # Compute 'ta', the time to the next scheduled internal transition,
+    # based (typically) on current State.
+    
+    state = self.state.get()
+
+    if state == "red":
+      return 3
+    elif state == "green":
+      return 2
+    elif state == "yellow":
+      return 1
+    elif state == "manual":
+      return INFINITY 
+    else:
+      raise DEVSException(\
+        "unknown state <%s> in TrafficLight time advance transition function"\
+        % state)
+
+#    ======================================================================    #
+
+class TrafficLightSystem(CoupledDEVS):
+    def __init__(self):
+        CoupledDEVS.__init__(self, "System")
+        self.light = self.addSubModel(TrafficLight("Light"))
+        self.observed = self.addOutPort(name="observed")
+        self.connectPorts(self.light.OBSERVED, self.observed)
+
+def my_function(event):
+    print("Observed the following event: " + str(event))
+
+from pypdevs.simulator import Simulator
+
+model = TrafficLightSystem()
+sim = Simulator(model)
+sim.setRealTime()
+sim.setListenPorts(model.observed, my_function)
+sim.simulate()
+
+import time
+while 1:
+    time.sleep(0.1)

+ 49 - 0
doc/install_mpi4py.sh

@@ -0,0 +1,49 @@
+#!/bin/bash
+set -e
+rm -r build-mpi || true
+mkdir build-mpi
+cd build-mpi
+mkdir mpich-build
+mkdir mpich
+base=`pwd`
+cd mpich-build
+wget http://www.mpich.org/static/downloads/3.1.2/mpich-3.1.2.tar.gz
+tar -xvzf mpich-3.1.2.tar.gz
+cd mpich-3.1.2
+./configure --prefix=$base/mpich --with-device=ch3:sock --disable-fortran
+make -j5
+make install
+export PATH=$base/mpich/bin:$PATH
+cd ../..
+mkdir mpi4py
+cd mpi4py
+wget https://pypi.python.org/packages/source/m/mpi4py/mpi4py-1.3.1.tar.gz
+tar -xvzf mpi4py-1.3.1.tar.gz
+cd mpi4py-1.3.1
+# Force the correct MPI distribution
+rm mpi.cfg || true
+echo "[mpi]" >> mpi.cfg
+echo "" >> mpi.cfg
+echo "include_dirs = $base/mpich/include" >> mpi.cfg
+echo "libraries = mpi" >> mpi.cfg
+echo "library_dirs = $base/mpich/lib" >> mpi.cfg
+echo "runtime_library_dirs = $base/mpich/lib" >> mpi.cfg
+echo "mpicc = $base/mpich/bin/mpicc" >> mpi.cfg
+echo "mpicxx = $base/mpich/bin/mpicxx" >> mpi.cfg
+python setup.py build --mpi=mpi
+python setup.py install --user
+
+echo "=============================="
+echo "==        All done          =="
+echo "=============================="
+echo ""
+echo "Please add $base/mpich/bin to your PATH"
+echo "This is done by adding the line"
+echo "  export PATH=$base/mpich/bin:\$PATH"
+echo "to a file parsed at system startup, e.g. ~/.bashrc"
+echo "For example for Ubuntu: http://askubuntu.com/questions/60218/how-to-add-a-directory-to-my-path"
+echo ""
+echo "Alternative:"
+echo "A symbolic link can be made from /usr/local/bin/mpirun to $base/mpich/bin/mpirun (probably requires root)"
+echo "This is done with the command:"
+echo "  sudo ln -s $base/mpich/bin/mpirun /usr/local/bin/mpirun"

+ 95 - 0
doc/installation.rst

@@ -0,0 +1,95 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Installation
+============
+
+This section describes the necessary steps for installing PyPDEVS.
+
+Dependencies
+------------
+
+The following dependencies are mandatory:
+
+* python 2.7
+
+For parallel and distributed simulation, the following additional dependencies are required:
+
+* MPICH3 with socket device
+* mpi4py
+
+Installation instructions are given for these two dependencies further in this section.
+
+Realtime simulation using the Tk backend, obviously requires Tk.
+
+PyPDEVS Installation
+--------------------
+
+Execute the following command in the 'src' folder::
+    
+    python setup.py install --user
+
+Afterwards, PyPDEVS should be installed. This can easily be checked with the command::
+
+    python -c "import pypdevs"
+
+If this returns without errors, PyPDEVS is sucessfully installed.
+
+Parallel and distributed simulation with mpi4py
+-----------------------------------------------
+
+.. note:: An installation script for mpi4py and MPICH3 is provided in :download:`install_mpi4py.sh <install_mpi4py.sh>`. At the end, you will still need to add mpi to your PATH though, as explained by the script.
+
+First of all, an MPI middleware has to be installed, for which I recommend MPICH3.
+Due to some non-standard configuration options, it is required to install MPICH manually instead of using the one from the repositories.
+
+You can use either the official installation guide, or follow the steps below.
+Just make sure that the correct configuration options are used.
+
+The following commands should work on most systems, just replace the '/home/you' part with a location of your choosing::
+
+    mkdir mpich-build
+    mkdir mpich
+    base=`pwd`
+    cd mpich-build
+    wget http://www.mpich.org/static/downloads/3.1.2/mpich-3.1.2.tar.gz
+    tar -xvzf mpich-3.1.2.tar.gz
+    cd mpich-3.1.2
+    ./configure --prefix=$base/mpich --with-device=ch3:sock --disable-fortran
+    make
+    make install
+    export PATH=$base/mpich/bin:$PATH
+    cd ../..
+
+You will probably want to put this final export of PATH to your .bashrc file, to make sure that mpi is found in new terminals too.
+After that, make sure that the following command does not cause any errors and simply prints your hostname 4 times::
+
+    mpirun -np 4 hostname
+
+Now you just need to install mpi4py, which is easy if you have MPICH installed correctly::
+
+    mkdir mpi4py
+    cd mpi4py
+    wget https://pypi.python.org/packages/source/m/mpi4py/mpi4py-1.3.1.tar.gz
+    tar -xvzf mpi4py-1.3.1.tar.gz
+    cd mpi4py-1.3.1
+    python setup.py build --mpicc=../../mpich/bin/mpicc
+    python setup.py install --user
+    cd ../..
+
+Testing whether or not everything works can be done by making sure that the following command prints '4' four times::
+
+    mpirun -np 4 python -c "from mpi4py import MPI; print(MPI.COMM_WORLD.Get_size())"

+ 29 - 0
doc/interface.rst

@@ -0,0 +1,29 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Interface
+=========
+
+This section contains all constructors and methods necessary to setup, configure and simulate a DEVS model. See the next section for examples on usage.
+
+.. toctree::
+
+   Infinity <infinity>
+   Models <DEVS>
+   Simulator <simulator>
+   Server <server>
+   Random Number Generator <randomgenerator>
+   Elapsed Time <elapsed_time>

+ 49 - 0
doc/internal.rst

@@ -0,0 +1,49 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Internal documentation
+======================
+
+.. warning:: This section contains every function of PyPDEVS, most of which are **not** suited to be used by the modeller. This section should therefore only be used to understand the backend of the simulator, or as reference to developers wishing to modify the source code.
+
+.. toctree::
+
+   Activity Visualisation <activityvisualisation_int>
+   Allocators <allocators_int>
+   AsynchronousComboGenerator <asynchronouscombogenerator_int>
+   BaseSimulator <basesimulator_int>
+   Classic DEVS Wrapper <classicdevswrapper_int>
+   Colors <colors_int>
+   Controller <controller_int>
+   DEVS <DEVS_int>
+   Logger <logger_int>
+   Message <message_int>
+   Message Scheduler <messagescheduler_int>
+   Middleware Detection <middleware_int>
+   Minimal Simulation kernal <minimal_int>
+   MPIRedirect <mpiredirect_int>
+   Random number generator <randomgenerator_int>
+   Relocators <relocators_int>
+   Schedulers <schedulers>
+   Server <server_int>
+   Simulator <simulator_int>
+   SimulatorConfigurator <simconfig_int>
+   Solver <solver_int>
+   State Savers <statesavers_int>
+   Threading subsystems <threading>
+   Threadpool <threadpool_int>
+   Tracers <tracers>
+   Util <util_int>

+ 42 - 0
doc/listener.rst

@@ -0,0 +1,42 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Listening to realtime simulation
+================================
+
+During realtime simulation, there frequently exists the need to listen to specific ports, monitoring the events passing over them. In PythonPDEVS, it is possible to register a function that is invoked for each event passing over that port. This is called a *listener* in PythonPDEVS.
+
+Example model
+-------------
+
+We can simply reuse the traffic light model from the previous section on realtime simulation (:download:`trafficLightModel.py <trafficLightModel.py>`). All that needs to be changed now, is adding a listener on an output port of a *coupled* DEVS model. First and foremost, therefore, we must put our traffic light in a container::
+
+    class TrafficLightSystem(CoupledDEVS):
+        def __init__(self):
+            CoupledDEVS.__init__(self, "System")
+            self.light = self.addSubModel(TrafficLight("Light"))
+            self.observed = self.addOutPort(name="observed")
+
+In the experiment file, it is then possible to register a listener on this port as follows (:download:`injection.py <injection.py>`)::
+
+    def my_function(event):
+        print("Observed the following event: " + str(event))
+        
+    sim.setListenPorts(model.observed, my_function)
+
+Since this function is invoked with the complete bag, the received event will contain a list of events, exactly as how it would be invoked in the external transition function.
+
+.. note:: Listeners are only supported on output ports of Coupled DEVS models. This is because the listeners are invoked upon event routing, for which the source port is not checked.

BIN
doc/location.png


+ 47 - 0
doc/location.rst

@@ -0,0 +1,47 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Location tracing
+================
+
+.. note:: This feature is still being worked on and all information is therefore prone to change.
+
+Location tracing is closely linked to activity tracing. The only major difference is when the files are generated: an activity trace is only created at the end of the simulation run, whereas an location trace is created at the start of the simulation and at every GVT boundary where at least one migration happens. Location traces will always contain the time at which the location as it is presented actually went into effect.
+
+Enabling location tracing is as simple as::
+
+    x, y = 20, 20
+    model = FireSpread(x, y)
+    sim = Simulator(model)
+    sim.setTerminationTime(1000.0)
+    sim.setLocationCellMap(True, x, y)
+    sim.simulate()
+
+Note that this again shows the location in a Cell view. If this kind of visualisation is not desirable (or possible), you are advised to use standard :doc:`visualisation` using Graphviz.
+
+An example output of location tracing is given below. It isn't really spectacular, as it only shows you your allocations again.
+
+.. image:: location.png
+   :alt: Location cell view
+   :align: center
+   :width: 50%
+
+Cell view visualisation is completely different from the regular :doc:`visualisation`, as it contains some domain specific information and thus more closely resembles your interpretation of the model. Drawing a 6x6 grid with the generic visualisation, would generate something non-intuitive like the 'curly' graph below.
+
+.. image:: location_normal.png
+   :alt: Location normal view
+   :height: 2000px
+   :align: center

BIN
doc/location_normal.png


+ 20 - 0
doc/locationscheduler.rst

@@ -0,0 +1,20 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Location-specific scheduler
+===========================
+
+TODO

+ 21 - 0
doc/logger_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Logger
+======
+
+.. automodule:: logger
+   :members:

+ 21 - 0
doc/manualrelocator_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Manual Relocator
+================
+
+.. automodule:: relocators.manualRelocator
+   :members:

+ 113 - 0
doc/memoization.rst

@@ -0,0 +1,113 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Memoization
+===========
+
+PyPDEVS supports memoization for the most heavyweight functions that are called during simulation.
+
+What is memoization?
+--------------------
+
+Memoization simply means that the return values of a function call will be cached. 
+As soon as the function is called again with exactly the same parameters, the cached value will be 
+returned instead of the function being reevaluated again.
+The advantage is clearly that it has the potential to speed up computation in situations where
+the value is likely to be cached **and** if the function takes a relatively long time.
+
+How does it apply to PyPDEVS?
+-----------------------------
+
+The PyPDEVS code is significantly optimized, though a certain part of the code is inoptimizable by
+the simulator itself. This code is the *user code*, which defines e.g. the transition functions of
+the model. These transition functions have the potential to computationally intensive. For example,
+most distributed simulation benchmarks have a transition function which takes in the terms of milliseconds.
+
+The only remaining requirement is then that the value is *likely* to be cached. For this reason, memoization
+is only used in distributed simulation. In distributed simulation, a complete node might have to revert
+all of its computation due to another (unrelated) model requesting such a revertion. Most of the time,
+this model is not influenced by the change directly, therefore the input parameters of the function are
+likely to be identical.
+
+It is therefore possible to assume that distributed simulation is likely to profit from this optimization,
+certainly in the case of relocations. When a relocation happens, the node is reverted to the current GVT,
+even though no real causality violation happened. These transitions can then be recalculated immediately with
+the use of memoization.
+
+Why not enable it by default?
+-----------------------------
+
+Even though memoization seems a way to quickly increase performance, it also has several downsides. The most
+important downside is the high space complexity that it incurs. Time warp simulation is already extremely
+space consuming, so also caching the inputs and their response is not going to be of much help to that.
+This problem is partially mitigated by having time warp and memoization refer to the same state in memory,
+though this still requires additional lists, input dictionaries, ...
+
+Another problem is the datastructure management. As soon as a revertion happens, the list of old states is
+reverted and used to check for equality. Without memoization, this list would be discarded, freeing up lots
+of space. Therefore, this problem again relates to space complexity.
+
+A final problem is the requirement to check the states for equality. These checks can take arbitrarily long,
+depending on how the user defined the equality method. In the worst case, the user might not have defined such
+a method, causing every comparison to result in *False*. This is clearly problematic, as the memoization speedup 
+will then never be visible. Furthermore, memoization is unlikely to have an impact in simulations where nearly
+no revertions happen.
+
+For these reasons, memoization is not enabled by default, but only when the user enables it explicitly.
+
+Implementation hints
+--------------------
+
+Due to the way memoization is implemented in PyPDEVS, some considerations apply:
+
+1. As soon as an inequal state is found, memoization code is aborted because the chance of further equality becomes too small.
+2. Memoization code is only triggered after a revertion happened.
+3. Due to memoization, side-effects of the transition function are not performed. This includes printing, random number generation, ... Note that transition functions with side effects are already a bad idea in time warp simulationn.
+
+Requirements
+------------
+
+Two requirements exist to use memoization. The first one is simply to enable it in the configuration, the second one 
+requires a little more explanation.
+
+By default, Python provides equality methods on two objects, but they always return *False* if the objects are different 
+(even though their content might be equal). 
+The user should thus add the *__eq__(self, other)* and *__hash__(self)* function, to provide user-defined equality.
+
+Technically, it is required that the output is **exactly** the same when the current state (and input message, in case
+of *external* and *confluent transitions*) are equal according to these methods.
+
+Example
+-------
+
+Simply enabling memoization is not that difficult and is simply::
+
+    sim = Simulator(MyModel())
+    sim.setMemoization(True)
+    sim.simulate()
+
+Defining the equality method on a state can be::
+    
+    class MyState(object):
+        def __init__(self, var1, var2):
+            self.var1 = var1
+            self.var2 = var2
+
+        def __eq__(self, other):
+            return self.var1 == other.var1 and self.var2 == other.var2
+
+        def __hash__(self):
+            return hash(hash(self.var1) + hash(self.var2))

+ 21 - 0
doc/message_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Message object
+==============
+.. automodule:: message
+   :members:
+   :special-members:

+ 20 - 0
doc/messagescheduler_int.rst

@@ -0,0 +1,20 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+MessageScheduler
+================
+.. automodule:: messageScheduler
+   :members:

+ 21 - 0
doc/middleware_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Middleware Detection
+====================
+
+.. automodule:: middleware
+   :members:

+ 39 - 0
doc/minimal.rst

@@ -0,0 +1,39 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Minimal Simulation Kernel
+=========================
+
+Due to the many features that PythonPDEVS supports, the code is quite big and many additional steps need to be taken during simulation.
+Certainly with Python, this causes problems due to the lack of compilation (and consequently optimization).
+For this reason, but also to show the minimal simulation algorithm of PythonPDEVS, a minimal simulation kernel is added.
+
+Such a minimal kernel, even without any special features, is useful for benchmarking different algorithms, without needing to worry about the supported features.
+It can also be useful for end-users, if the user is only interested in the state of the simulated model.
+
+Its use is identical to the normal simulation kernel, but the import is different.
+Instead of importing *Simulator* from the file *simulator.py*, it needs to be imported from *minimal.py*.
+So the only change is the import, which becomes something like::
+
+    from pypdevs.minimal import Simulator
+
+All other code remains exactly the same.
+Unless configuration options (apart from *setTerminationTime*) are used, as these will no longer be possible.
+The only supported option is *setTerminationTime*, which works exactly the same as in the normal simulation kernel.
+While it is still possible to define transfer functions or define allocations in the model construction, these are ignored during simulation.
+
+The polymorphic scheduler is used automatically, so the performance will automatically be optimized to the different access patterns.
+There is thus no need to manually specify the scheduler.

+ 21 - 0
doc/minimal_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Minimal Simulation Kernel
+=========================
+.. autofunction:: minimal.directConnect
+.. autoclass:: minimal.Simulator
+   :members:

BIN
doc/model.png


+ 22 - 0
doc/mpiredirect_int.rst

@@ -0,0 +1,22 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+MPIRedirect class
+=================
+
+.. automodule:: MPIRedirect
+   :members:
+   :special-members:

+ 40 - 0
doc/multisim.rst

@@ -0,0 +1,40 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Multiple Simulators
+===================
+
+In some situations, having multiple models (and their respective simulator) in the same Python script is useful for comparing the performance. 
+
+Local simulation
+----------------
+
+In local simulation, it is possible to create multiple Simulator instances without any problems::
+    
+    sim1 = Simulator(Model1())
+    # Any configuration you want on sim1
+    sim1.simulate()
+
+    sim2 = Simulator(Model2())
+    # Any configuration you want on sim2
+    sim2.simulate()
+
+Distributed simulation
+----------------------
+
+Starting up multiple Simulator classes is not supported in distributed simulation. This is because starting a simulator will also impose the construction of different MPI servers, resulting in an inconsistency.
+
+It is supported in distributed simulation to use :doc:`reinitialisation <reinitialisation>`, simply because it is the same model and is coordinated by the same simulator.

+ 72 - 0
doc/nesting.rst

@@ -0,0 +1,72 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Nested simulation
+=================
+
+.. versionchanged:: 2.1.3
+   Nested simulation is only possible if **both** the nested simulation and the invoking simulation are **local** simulations.
+
+.. versionchanged:: 2.2.0
+   Allow nested local simulations in distributed simulations.
+
+Nested simulation allows a simulation to be influenced by the results of another simulation. This functionality is very simple to use, as it just works as expected. In one of the user-defined functions of the model, it is thus possible to create another model and another simulator and simulate that new simulator. The only difference is that some specific configurations do not work on the nested simulation, such as using a logging server.
+
+An example of nesting is provided in the remainder of this subsection.
+
+Suppose we want to create a *Processor* which has a state of how many messages it has already processed. This amount of messages is then used to determine the *timeAdvance*, but in a very specific way that is determined by another DEVS simulation. This example is somewhat contrived, though the example is supposed to be as small as possible to only show how it works, not the utility of the feature.
+
+The following code implements such behaviour::
+
+    class State(object):
+        def __init__(self):
+            self.processed = 0
+            self.processing = False
+
+    class NestedProcessor(AtomicDEVS):
+        def __init__(self):
+            AtomicDEVS.__init__(self, "Nested")
+            self.state = State()
+            self.inport = self.addInPort("inport")
+            self.outport = self.addOutPort("outport")
+
+        def extTransition(self, inputs):
+            self.state.processing = True
+            return self.state
+
+        def intTransition(self):
+            self.state.processed += 1
+            return self.state
+
+        def outputFnc(self):
+            return {self.outport: [1]}
+
+        def timeAdvance(self):
+            if self.state.processing:
+                # Determine the time based on another simulation
+                from simulator import Simulator
+                from myqueue import CQueue
+                model = CQueue()
+                # The processed attribute of the state is used to determine the processing time in our example
+                model.queue.processing_time = self.state.processed
+                sim = Simulator(model)
+                sim.setTerminationTime(5.0)
+                sim.simulate()
+                return max(1, model.queue.state)
+            else:
+                return INFINITY
+
+In our example, we only used nested simulation in the *timeAdvance* function, though it is possible everywhere.

File diff suppressed because it is too large
+ 113 - 0
doc/problems.rst


+ 69 - 0
doc/queue_example.py

@@ -0,0 +1,69 @@
+from pypdevs.DEVS import AtomicDEVS, CoupledDEVS
+from pypdevs.simulator import Simulator
+from pypdevs.infinity import INFINITY
+
+class Generator(AtomicDEVS):
+    def __init__(self):
+        AtomicDEVS.__init__(self, "Generator")
+        self.state = True
+        self.outport = self.addOutPort("outport")
+
+    def timeAdvance(self):
+        if self.state:
+            return 1.0
+        else:
+            return INFINITY
+
+    def outputFnc(self):
+        # Our message is simply the integer 5, though this could be anything
+        return {self.outport: [5]}
+
+    def intTransition(self):
+        self.state = False
+        return self.state
+
+class Queue(AtomicDEVS):
+  def __init__(self):
+      AtomicDEVS.__init__(self, "Queue")
+      self.state = None
+      self.processing_time = 1.0
+      self.inport = self.addInPort("input")
+      self.outport = self.addOutPort("output")
+
+  def timeAdvance(self):
+      if self.state is None:
+          return INFINITY
+      else:
+          return self.processing_time
+
+  def outputFnc(self):
+      return {self.outport: [self.state]}
+
+  def intTransition(self):
+      self.state = None
+      return self.state
+
+  def extTransition(self, inputs):
+      self.state = inputs[self.inport][0]
+      return self.state
+
+class CQueue(CoupledDEVS):
+    def __init__(self):
+        CoupledDEVS.__init__(self, "CQueue")
+        self.generator = self.addSubModel(Generator())
+        self.queue = self.addSubModel(Queue())
+        self.connectPorts(self.generator.outport, self.queue.inport)
+
+class DQueue(CoupledDEVS):
+    def __init__(self):
+        CoupledDEVS.__init__(self, "DQueue")
+        self.generator = self.addSubModel(Generator())
+        self.queue1 = self.addSubModel(Queue())
+        self.queue2 = self.addSubModel(Queue())
+        self.connectPorts(self.generator.outport, self.queue1.inport)
+        self.connectPorts(self.generator.outport, self.queue2.inport)
+
+model = CQueue()
+sim = Simulator(model)
+sim.setVerbose()
+sim.simulate()

+ 71 - 0
doc/queue_example_classic.py

@@ -0,0 +1,71 @@
+from pypdevs.DEVS import AtomicDEVS, CoupledDEVS
+from pypdevs.simulator import Simulator
+from pypdevs.infinity import INFINITY
+
+class Generator(AtomicDEVS):
+    def __init__(self):
+        AtomicDEVS.__init__(self, "Generator")
+        self.state = True
+        self.outport = self.addOutPort("outport")
+
+    def timeAdvance(self):
+        if self.state:
+            return 1.0
+        else:
+            return INFINITY
+
+    def outputFnc(self):
+        # Our message is simply the integer 5, though this could be anything
+        return {self.outport: 5}
+
+    def intTransition(self):
+        self.state = False
+        return self.state
+
+class Queue(AtomicDEVS):
+  def __init__(self):
+      AtomicDEVS.__init__(self, "Queue")
+      self.state = None
+      self.processing_time = 1.0
+      self.inport = self.addInPort("input")
+      self.outport = self.addOutPort("output")
+
+  def timeAdvance(self):
+      if self.state is None:
+          return INFINITY
+      else:
+          return self.processing_time
+
+  def outputFnc(self):
+      return {self.outport: self.state}
+
+  def intTransition(self):
+      self.state = None
+      return self.state
+
+  def extTransition(self, inputs):
+      self.state = inputs[self.inport]
+      return self.state
+
+class CQueue(CoupledDEVS):
+    def __init__(self):
+        CoupledDEVS.__init__(self, "CQueue")
+        self.generator = self.addSubModel(Generator())
+        self.queue = self.addSubModel(Queue())
+        self.connectPorts(self.generator.outport, self.queue.inport)
+
+class DQueue(CoupledDEVS):
+    def __init__(self):
+        CoupledDEVS.__init__(self, "DQueue")
+        self.generator = self.addSubModel(Generator())
+        self.queue1 = self.addSubModel(Queue())
+        self.queue2 = self.addSubModel(Queue())
+        self.connectPorts(self.generator.outport, self.queue1.inport)
+        self.connectPorts(self.generator.outport, self.queue2.inport)
+
+model = CQueue()
+sim = Simulator(model)
+sim.setClassicDEVS()
+sim.setTerminationTime(5.0)
+sim.setVerbose()
+sim.simulate()

File diff suppressed because it is too large
+ 81 - 0
doc/random.rst


+ 22 - 0
doc/randomgenerator.rst

@@ -0,0 +1,22 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Random Number Generator
+=======================
+
+.. automodule:: randomGenerator
+   :members:
+   :noindex:

+ 22 - 0
doc/randomgenerator_int.rst

@@ -0,0 +1,22 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Random Number Generator
+=======================
+
+.. automodule:: randomGenerator
+   :members:
+   :special-members:

+ 309 - 0
doc/realtime.rst

@@ -0,0 +1,309 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Realtime simulation
+===================
+
+Realtime simulation is closely linked to normal simulation, with the exception that simulation will not progress as fast as possible. The value returned by the time advance will be interpreted in seconds and the simulator will actually wait (not busy loop) until the requested time has passed. Several realtime backends are supported in PyPDEVS and are mentioned below.
+
+Example model
+-------------
+
+The example model will be something else than the *queue* from before, as this isn't really that interesting for realtime simulation. We will instead use the *trafficLight* model. It has a *trafficLight* that is either running autonomous or is in a manual mode. Normally, the traffic light will work autonomously, though it is possible to interrupt the traffic light and switch it to manual mode and back to autonomous again.
+
+This complete model is (:download:`trafficLightModel.py <trafficLightModel.py>`)::
+
+    class TrafficLightMode:
+        def __init__(self, current="red"):
+            self.set(current)
+
+        def set(self, value="red"):
+            self.__colour=value
+
+        def get(self):
+            return self.__colour
+
+        def __str__(self):
+            return self.get()
+
+    class TrafficLight(AtomicDEVS):
+        def __init__(self, name):
+            AtomicDEVS.__init__(self, name)
+            self.state = TrafficLightMode("red")
+            self.INTERRUPT = self.addInPort(name="INTERRUPT")
+            self.OBSERVED = self.addOutPort(name="OBSERVED")
+
+        def extTransition(self, inputs):
+            input = inputs[self.INTERRUPT][0]
+            if input == "toManual":
+                if state == "manual":
+                    # staying in manual mode
+                    return TrafficLightMode("manual")
+                if state in ("red", "green", "yellow"):
+                    return TrafficLightMode("manual")
+
+            elif input == "toAutonomous":
+                if state == "manual":
+                    return TrafficLightMode("red")
+
+            raise DEVSException("Unkown input in TrafficLight")
+
+        def intTransition(self):
+            state = self.state.get()
+            if state == "red":
+                return TrafficLightMode("green")
+            elif state == "green":
+                return TrafficLightMode("yellow")
+            elif state == "yellow":
+                return TrafficLightMode("red")
+            else:
+                raise DEVSException("Unkown state in TrafficLight")
+
+        def outputFnc(self):
+            state = self.state.get()
+            if state == "red":
+                return {self.OBSERVED: ["grey"]}
+            elif state == "green":
+                return {self.OBSERVED: ["yellow"]}
+            elif state == "yellow":
+                return {self.OBSERVED: ["grey"]}
+            else:
+                raise DEVSException("Unknown state in TrafficLight")
+
+        def timeAdvance(self):
+            if state == "red":
+                return 60
+            elif state == "green":
+                return 50
+            elif state == "yellow":
+                return 10
+            elif state == "manual":
+                return INFINITY
+            else:
+                raise DEVSException("Unknown state in TrafficLight")
+
+With our model being set up, we could run it as-fast-as-possible by starting it like::
+
+    model = TrafficLight("trafficLight")
+    sim = Simulator(model)
+    sim.simulate()
+
+To make it run in real time, we only need to do some minor changes. First, we need to define on which port we want to put some external input. We can choose a way to address this port, but lets assume that we choose the same name as the name of the port. This gives us::
+
+    refs = {"INTERRUPT": model.INTERRUPT}
+
+Now we only need to pass this mapping to the simulator, together with the choice for realtime simulation. This is done as follows::
+
+    refs = {"INTERRUPT": model.INTERRUPT}
+    sim.setRealTime(True)
+    sim.setRealTimePorts(refs)
+
+That is all extra configuration that is required for real time simulation. 
+
+As soon as the *simulate()* method is called, the simulation will be started as usual, though now several additional options are enabled. Specifically, the user can now input external data on the declared ports. This input should be of the form *portname data*.
+
+In our example, the model will respond to both *toManual* and *toAutonomous* and we chose *INTERRUPT* as portname in our mapping. So our model will react on the input *INTERRUPT toManual*. This input can then be given through the invocation of the *realtime_interrupt(string)* call as follows::
+
+    sim.realtime_interrupt("INTERRUPT toManual")
+
+Malformed input will cause an exception and simulation will be halted.
+
+.. note:: All input that is injected will be passed to the model as a *string*. If the model is thus supposed to process integers, a string to integer processing step should happen in the model itself.
+
+Input files
+-----------
+
+PyPDEVS also supports the use of input files together with input provided at run time. The input file will be parsed at startup and should be of the form *time port value*, with time being the simulation time at which this input should be injected. Again, this input will always be interpreted as a string. If a syntax error is detected while reading through this file, the error will immediately be shown.
+
+.. note:: The file input closely resembles the usual prompt, though it is not possible to define a termination at a certain time by simply stating the time at the end. For this, you should use the termination time as provided by the standard interface.
+
+An example input file for our example could be::
+
+    10 INTERRUPT toManual
+    20 INTERRUPT toAutonomous
+    30 INTERRUPT toManual
+
+Backends
+--------
+
+Several backends are provided for the realtime simulation, each serving a different purpose. The default backend is the best for most people who just want to simulate in realtime. Other options are for when PyPDEVS is coupled to TkInter, or used in the context of a game loop system.
+
+The following backends are currently supported:
+
+* Python threads: the default, provides simple threading and doesn't require any other programs. Activated with *setRealTimePlatformThreads()*.
+* TkInter: uses Tk for all of its waiting and delays (using the Tk event list). Activated with *setRealTimePlatformTk()*.
+* Game loop: requires an external program to call the simulator after a certain delay. Activated with *setRealTimePlatformGameLoop()*.
+
+For each of these backends, an example is given on how to use and invoke it, using the traffic light model presented above.
+
+Python Threads
+^^^^^^^^^^^^^^
+
+This is the simplest platform to use, and is used by default. After the invocation of *sim.simulate()*, simulation will happen in the background of the currently running application. The call to *sim.simulate()* will return immediately. Afterwards, users can do some other operations. Most interestingly, users can provide input to the running simulation by invoking the *realtime_interrupt(string)* method.
+
+Simulation runs as a daemon thread, so exiting the main thread will automatically terminate the simulation.
+
+.. warning:: Python threads can sometimes have a rather low granularity in CPython 2. So while we are simulating in soft realtime anyway, it is important to note that delays could potentially become significant.
+
+An example is given below (:download:`experiment_threads.py <experiment_threads.py>`)::
+
+    from pypdevs.simulator import Simulator
+    from trafficLightModel import *
+    model = TrafficLight(name="trafficLight")
+
+    refs = {"INTERRUPT": model.INTERRUPT}
+    sim = Simulator(model)
+    sim.setRealTime(True)
+    sim.setRealTimeInputFile(None)
+    sim.setRealTimePorts(refs)
+    sim.setVerbose(None)
+    sim.setRealTimePlatformThreads()
+    sim.simulate()
+
+    while 1:
+        sim.realtime_interrupt(raw_input())
+
+In this example, users are presented with a prompt where they can inject events in the simulation, for example by typing *INTERRUPT toManual* during simulation. Sending an empty input (*i.e.*, malformed), simulation will also terminate.
+
+TkInter
+^^^^^^^
+
+The TkInter event loop can be considered the most difficult one to master, as you will also need to interface with TkInter.
+
+Luckily, PythonPDEVS hides most of this complexity for you. You will, however, still need to define your GUI application and start PythonPDEVS. Upon configuration of PythonPDEVS, a reference to the root window needs to be passed to PythonPDEVS, such that it knows to which GUI to couple.
+
+Upon termination of the GUI, PythonPDEVS will automatically terminate simulation as well.
+
+The following example will create a simple TkInter GUI of a traffic light, visualizing the current state of the traffic light, and providing two buttons to send specific events. Despite the addition of TkInter code, the PythonPDEVS interface is still very similar.
+
+The experiment file is as follows (:download:`experiment_tk.py <experiment_tk.py>`)::
+
+    from pypdevs.simulator import Simulator
+
+    from Tkinter import *
+    from trafficLightModel import *
+
+    isBlinking = None
+
+    model = TrafficLight(name="trafficLight")
+    refs = {"INTERRUPT": model.INTERRUPT}
+    root = Tk()
+
+    sim = Simulator(model)
+    sim.setRealTime(True)
+    sim.setRealTimeInputFile(None)
+    sim.setRealTimePorts(refs)
+    sim.setVerbose(None)
+    sim.setRealTimePlatformTk(root)
+
+    def toManual():
+        global isBlinking
+        isBlinking = False
+        sim.realtime_interrupt("INTERRUPT toManual")
+
+    def toAutonomous():
+        global isBlinking
+        isBlinking = None
+        sim.realtime_interrupt("INTERRUPT toAutonomous")
+
+    size = 50
+    xbase = 10
+    ybase = 10
+
+    frame = Frame(root)
+    canvas = Canvas(frame)
+    canvas.create_oval(xbase, ybase, xbase+size, ybase+size, fill="black", tags="red_light")
+    canvas.create_oval(xbase, ybase+size, xbase+size, ybase+2*size, fill="black", tags="yellow_light")
+    canvas.create_oval(xbase, ybase+2*size, xbase+size, ybase+3*size, fill="black", tags="green_light")
+    canvas.pack()
+    frame.pack()
+
+    def updateLights():
+        state = model.state.get()
+        if state == "red":
+            canvas.itemconfig("red_light", fill="red")
+            canvas.itemconfig("yellow_light", fill="black")
+            canvas.itemconfig("green_light", fill="black")
+        elif state == "yellow":
+            canvas.itemconfig("red_light", fill="black")
+            canvas.itemconfig("yellow_light", fill="yellow")
+            canvas.itemconfig("green_light", fill="black")
+        elif state == "green":
+            canvas.itemconfig("red_light", fill="black")
+            canvas.itemconfig("yellow_light", fill="black")
+            canvas.itemconfig("green_light", fill="green")
+        elif state == "manual":
+            canvas.itemconfig("red_light", fill="black")
+            global isBlinking
+            if isBlinking:
+                canvas.itemconfig("yellow_light", fill="yellow")
+                isBlinking = False
+            else:
+                canvas.itemconfig("yellow_light", fill="black")
+                isBlinking = True
+            canvas.itemconfig("green_light", fill="black")
+        root.after(500,  updateLights)
+
+    b = Button(root, text="toManual", command=toManual)
+    b.pack()
+    c = Button(root, text="toAutonomous", command=toAutonomous)
+    c.pack()
+
+    root.after(100, updateLights)
+
+    sim.simulate()
+    root.mainloop()
+
+Game Loop
+^^^^^^^^^
+
+This mechanism will not block the main thread and if the main thread stops, so will the simulation. The caller can, after the invocation of *simulate()*, give control to PythonPDEVS to process all outstanding events. This methods is called *realtime_loop_call()*. A simple game loop would thus look like::
+
+    sim = Simulator(Model())
+    sim.simulate()
+    sim.setRealTimePlatformGameLoop()
+    while (True):
+        # Do rendering and such
+        ...
+
+        # Advance the state of the DEVS model, processing all input events
+        sim.realtime_loop_call()
+
+The game loop mechanism is thus closely linked to the invoker. The calls to the *realtime_loop_call()* function and the initializer are the only concept of time that this mechanism uses. Newer versions of PythonPDEVS will automatically detect the number of Frames per Second (FPS), so there is no longer any need to do this manually.
+
+An example is presented below (:download:`experiment_loop.py <experiment_loop.py>`)::
+
+    from pypdevs.simulator import Simulator
+    from trafficLightModel import *
+    model = TrafficLight(name="trafficLight")
+
+    refs = {"INTERRUPT": model.INTERRUPT}
+    sim = Simulator(model)
+    sim.setRealTime(True)
+    sim.setRealTimeInputFile(None)
+    sim.setRealTimePorts(refs)
+    sim.setVerbose(None)
+    sim.setRealTimePlatformGameLoop()
+    sim.simulate()
+
+    import time
+    while 1:
+        before = time.time()
+        sim.realtime_loop_call()
+        time.sleep(0.1 - (before - time.time()))
+        print("Current state: " + str(model.state.get()))
+
+It is important to remark here, that the time management (*i.e.*, invoking sleep and computing how long to sleep), is the responsibility of the invoking code, instead of PythonPDEVS. PythonPDEVS will simply poll for the current wall clock time when it is invoked, and progress simulated time up to that point in time (depending on the scale factor).

+ 62 - 0
doc/reinitialisation.rst

@@ -0,0 +1,62 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Reinitialisation
+================
+
+Starting from PyPDEVS 2.1.4, it is possible to run the *simulate()* method multiple times. If the *reinit()* method was called, the model will be restored to its initial state. This is done by completely saving the model in memory right before the actual simulation starts. Main problem with this approach is that it will require additional memory and for local simulation, it also increases the initialisation time as the copy will have to be made.
+
+For these reasons, local simulation will have reinitialisation disabled by default and calling the *reinit()* method will result in a *DEVSException* stating this fact (and how to resolve it). Distributed simulation does not have this additional overhead and therefore it is always enabled.
+
+So for remote simulation, it is as simple as::
+
+    sim = Simulator(DQueue())
+    sim.simulate() # Run it for the first time
+    sim.reinit()   # Reinitialize 
+    sim.simulate() # 'Continue' the simulation run (which was reset)
+
+In local simulation, the option to allow reinitialisation needs to be set first, which simply gives::
+
+    sim = Simulator(CQueue())
+    sim.setAllowLocalReinit(True)
+    sim.simulate() # Run it for the first time
+    sim.reinit()   # Reinitialize
+    sim.simulate() # 'Continue' the simulation run (which was reset)
+
+Altering the model
+------------------
+
+Of course, simply rerunning the simulation is not really useful. Most of the time, reinitialisation is done to try the exact same simulation, but with a slightly different configuration. As long as the model structure is not altered, simply reinitializing is the best option. Note that these alterations should happen **before** the reinitialize call is made, as it implies network communication that is best done in a batch.
+
+After a simulation run, the model will naturally still be in the post-simulation state and the model states will be the ones at the end of the simulation. Altering them has no effect on subsequent simulation runs, as the model will be reinitialised in a single step. Simply altering the model after a simulation run is not a viable option.
+
+For these reasons, the only way to alter a model after simulation is through three methods of the *Simulator* object. These methods all serve a similar goal, though they are optimized for specific goals. They are:
+
+* *setModelState(model, newState)*: modify the state of *model* and set it to *newState*. Use this to set a completely new state for the model. This is an optimized version of *setModelAttribute*.
+* *setModelStateAttr(model, attr, value)*: modify the attribute *attr* of the state of *model* and set it to *value*. This will keep the original initialisation state, but alters only a single attribute. 
+* *setModelAttribute(model, attr, value)*: modify the attribute *attr* of the *model* and set it to *value*. This can be done to modify read-only attributes of the simulation model.
+
+For example, if you want to change the *processing_time* attribute of the queue, you can simply::
+    
+    model = CQueue()
+    sim = Simulator(model)
+    sim.setAllowLocalReinit(True)
+    sim.simulate() # <-- Initial run with processing_time = 1.0
+    sim.reinit()   # <-- Perform reinitialisation and perform all changes
+    sim.setModelAttribute(model.queue, "processing_time", 2.0) # <-- Set it to 2.0
+    sim.simulate() # <-- Now run with processing_time = 2.0
+
+.. warning:: Altering the state should happen after reinitialisation, as otherwise your changes will be reverted too.

+ 40 - 0
doc/relocation.rst

@@ -0,0 +1,40 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Relocation directives
+=====================
+
+If your model is distributed, there is the possibility to move models to a different node. Model relocations only happen at the GVT boundaries, so the GVT interval that was configured previously will also be the interval for checking for relocation directives and actually performing them.
+
+Setting a relocation directive is as simple as using the configuration option *setRelocationDirective(time, model, destination)*. At the first GVT boundary where *time* is reached, the *model* will be transfered to node *destination*. The *model* can be both the internal *model_id*, or simply the model itself. The *destination* should be the integer specifying the node to send the model to.
+
+Since the model relocation directives are only checked sporadically, it is possible for several relocation directives to be in conflict. In that case, the latest relocation directive (in terms of requested time) will be used for that specific model. 
+
+The actual sending of a model is not that time consuming, but mainly the locking and unlocking cost of both models (and the subsequent revert). To maximize performance, transfer as many models simultaneously as possible, because the algorithm is optimised for such situations.
+
+A simple example to swap the location of the *generator* and the first *queue* from our previous example is::
+
+    model = DQueue()
+    sim = Simulator(model)
+    sim.setRelocationDirective(20, model.generator, 1)
+    sim.setRelocationDirective(20, model.queue1, 0)
+    sim.simulate()
+
+Of course, the GVT algorithm will probably never run in this small example and thus the relocation will also never happen. 
+
+Relocating a model to the node where it is currently running will not impose a revertion to the GVT. Such directives will simply be ignored.
+
+.. note:: Executing a relocation causes a revertion to the GVT on both nodes that are involved. This is to avoid transferring the complete state history and sent messages.

+ 24 - 0
doc/relocators_int.rst

@@ -0,0 +1,24 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Relocators
+==========
+
+.. toctree::
+   
+   ManualRelocator <manualrelocator_int>
+   BoundaryRelocator <boundaryrelocator_int>
+   BasicBoundaryRelocator <basicboundaryrelocator_int>

+ 32 - 0
doc/rewrite_documentation.sh

@@ -0,0 +1,32 @@
+#!/bin/bash
+
+function rewrite {
+    echo $1
+    sed -i.bak -e s/_downloads/downloads/g $1
+    sed -i.bak -e s/_static/static/g $1
+    sed -i.bak -e s/_images/images/g $1
+    sed -i.bak -e s/_modules/modules/g $1
+    sed -i.bak -e s/_sources/sources/g $1
+    rm ${1}.bak
+}
+
+echo `pwd`
+cd _build/html
+echo `pwd`
+
+rm -r downloads || true
+rm -r images || true
+rm -r modules || true
+rm -r sources || true
+rm -r static || true
+mv _downloads downloads 2> /dev/null
+mv _static static 2> /dev/null
+mv _images images 2> /dev/null
+mv _modules modules 2> /dev/null
+mv _sources sources 2> /dev/null
+
+export -f rewrite
+for f in `find . -type f`
+do
+    rewrite $f
+done

+ 21 - 0
doc/schedulerAH_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Activity Heap scheduler
+=======================
+
+.. automodule:: schedulers.schedulerAH
+   :members:

+ 21 - 0
doc/schedulerAuto_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Polymorphic scheduler
+=====================
+
+.. automodule:: schedulers.schedulerAuto
+   :members:

+ 21 - 0
doc/schedulerDH_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Dirty Heap scheduler
+=======================
+
+.. automodule:: schedulers.schedulerDH
+   :members:

+ 21 - 0
doc/schedulerDT_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+'Discrete Time' scheduler
+=========================
+
+.. automodule:: schedulers.schedulerDT
+   :members:

+ 21 - 0
doc/schedulerHS_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Heapset scheduler
+=================
+
+.. automodule:: schedulers.schedulerHS
+   :members:

+ 21 - 0
doc/schedulerML_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Minimal List scheduler
+======================
+
+.. automodule:: schedulers.schedulerML
+   :members:

+ 21 - 0
doc/schedulerNA_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+No Age scheduler
+================
+
+.. automodule:: schedulers.schedulerNA
+   :members:

+ 21 - 0
doc/schedulerSL_int.rst

@@ -0,0 +1,21 @@
+..
+    Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at 
+    McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+Sorted List scheduler
+=====================
+
+.. automodule:: schedulers.schedulerSL
+   :members:

+ 0 - 0
doc/schedulers.rst


Some files were not shown because too many files changed in this diff