rparedis 1 год назад
Родитель
Сommit
68a247654d

+ 4 - 2
build.sh

@@ -9,7 +9,7 @@ cp install_mpi4py.sh pypdevs/install_mpi4py.sh
 cd doc/sphinx
 rm -r _build/html
 make html
-./rewrite_documentation.sh
+#./rewrite_documentation.sh
 cd ../..
 cp -R doc/sphinx/_build/html/ pypdevs/doc
 cp -R src/ pypdevs/
@@ -18,7 +18,7 @@ rm test/output/*
 cp -R test/ pypdevs/
 cp LICENSE pypdevs/
 cp NOTICE pypdevs/
-mkdir pypdevs/tests/output
+mkdir -p pypdevs/tests/output
 rm pypdevs/src/pypdevs/*.pyc
 rm pypdevs/examples/*/*.pyc
 rm pypdevs/examples/*/*.pyo
@@ -37,3 +37,5 @@ rm -R pypdevs/src/pypdevs/__pycache__
 
 tar -czf pypdevs.tgz pypdevs
 rm -R pypdevs
+
+read -p "Press [Enter] key to continue..."

+ 1 - 1
doc/sphinx/changelog.rst

@@ -17,5 +17,5 @@
 Changelog
 =========
 
-.. literalinclude:: ../notes.txt
+.. literalinclude:: ../../notes.txt
 

+ 11 - 1
doc/sphinx/installation.rst

@@ -24,7 +24,7 @@ Dependencies
 
 The following dependencies are mandatory:
 
-* python 2.7
+* Python 2.7 **or** Python 3.6+
 
 For parallel and distributed simulation, the following additional dependencies are required:
 
@@ -35,6 +35,16 @@ Installation instructions are given for these two dependencies further in this s
 
 Realtime simulation using the Tk backend, obviously requires Tk.
 
+Download
+--------
+
+The most up-to-date version of PyPDEVS can be obtained from the git repository::
+
+    git clone https://msdl.uantwerpen.be/git/yentl/PythonPDEVS.git
+
+Alternatively, the latest release can be downloaded via:
+    https://msdl.uantwerpen.be/git/yentl/PythonPDEVS/archive/master.zip
+
 PyPDEVS Installation
 --------------------
 

+ 14 - 14
doc/sphinx/queueing.rst

@@ -41,9 +41,9 @@ While examples could be given purely in their formal description, they would not
 To specify this model, we first define the event exchanged between different examples: the Job.
 A job is coded as a class ``Job``.
 It has the attributes ``size`` (i.e., indicative of processing time) and ``creation time`` (i.e., time the event was created, for statistic gathering).
-The ``Job`` class definition is shown next and can de downloaded: :download:`job.py <../examples/queueing/job.py>`.
+The ``Job`` class definition is shown next and can de downloaded: :download:`job.py <../../examples/queueing/job.py>`.
 
-.. literalinclude:: ../examples/queueing/job.py
+.. literalinclude:: ../../examples/queueing/job.py
 
 We now focus on each atomic model seperately, starting at the event generator.
 
@@ -59,9 +59,9 @@ Finally, the output function returns a new customer event with a randomly define
 The job has an attribute containing the time at which it was generated.
 Recall, however, that the output function was invoked before the internal transition, so the current time has not yet been updated by the internal transition.
 Therefore, the output function also has to do this addition, without storing the result in the state (as it cannot write to the state).
-The ``Generator`` class definition is shown next and can de downloaded: :download:`generator.py <../examples/queueing/generator.py>`.
+The ``Generator`` class definition is shown next and can de downloaded: :download:`generator.py <../../examples/queueing/generator.py>`.
 
-.. literalinclude:: ../examples/queueing/generator.py
+.. literalinclude:: ../../examples/queueing/generator.py
 
 Next up is the queue, which is the most interesting component of the simulation, as it is the part we wish to analyze.
 The ``Queue`` implementation is similar in structure to the ``Generator``.
@@ -83,9 +83,9 @@ An important consideration in this model is the ``remaining\_time`` counter, whi
 We can't simply put the processing time of events in the time advance, as interrupts could happen during this time.
 When an interrupt happens (e.g., another event arrives), the time advance is invoked again, and would return the total processing time, instead of the remaining time to process the event.
 To solve this problem, we maintain a counter that explicitly gets decremented when an external interrupt happens.
-The ``Queue`` class definition is shown next and can de downloaded: :download:`queue.py <../examples/queueing/queue.py>`.
+The ``Queue`` class definition is shown next and can de downloaded: :download:`queue.py <../../examples/queueing/queue.py>`.
 
-.. literalinclude:: ../examples/queueing/queue.py
+.. literalinclude:: ../../examples/queueing/queue.py
 
 The next atomic model is the ``Processor`` class.
 It merely receives an incoming event and starts processing it.
@@ -95,32 +95,32 @@ We need to send out two events: one containing the job that was processed, and o
 For this, two different ports are used.
 Note that the definition of the processor would not be this simple in case there was no queue before it.
 We can now make the assumption that when we get an event, we are already idle and therefore don't need to queue new incoming events first.
-The ``Processor`` class definition is shown next and can de downloaded: :download:`processor.py <../examples/queueing/processor.py>`.
+The ``Processor`` class definition is shown next and can de downloaded: :download:`processor.py <../../examples/queueing/processor.py>`.
 
-.. literalinclude:: ../examples/queueing/processor.py
+.. literalinclude:: ../../examples/queueing/processor.py
 
 The processor finally sends the task to the ``Collector`` class.
 The collector is an artificial component that is not present in the system being modeled; it is only used for statistics gathering.
 For each job, it stores the time in the queue.
-The ``Collector`` class definition is shown next and can de downloaded: :download:`collector.py <../examples/queueing/collector.py>`.
+The ``Collector`` class definition is shown next and can de downloaded: :download:`collector.py <../../examples/queueing/collector.py>`.
 
-.. literalinclude:: ../examples/queueing/collector.py
+.. literalinclude:: ../../examples/queueing/collector.py
 
 With all atomic examples defined, we only have to couple them together in a coupled model: the ``System``.
 In this system, we instantiate a generator, queue, and collector, as well as a variable number of processors.
 The number of processors is variable, but is still static during simulation.
 The couplings also depend on the number of processors, as each processor is connected to the queue and the collector.
-The ``System`` class definition is shown next and can de downloaded: :download:`system.py <../examples/queueing/system.py>`.
+The ``System`` class definition is shown next and can de downloaded: :download:`system.py <../../examples/queueing/system.py>`.
 
-.. literalinclude:: ../examples/queueing/system.py
+.. literalinclude:: ../../examples/queueing/system.py
 
 Now that our DEVS model is completely specified, we can start running simulations on it.
 Simulation requires an *experiment* file though, which initializes the model with parameters and defines the simulation configuration.
 The experiment writes out the raw queueing times to a Comma Seperated Value (CSV) file.
 An experiment file often contains some configuration of the simulation tool, which differs for each tool.
-The experiment file is shown next and can de downloaded: :download:`experiment.py <../examples/queueing/experiment.py>`.
+The experiment file is shown next and can de downloaded: :download:`experiment.py <../../examples/queueing/experiment.py>`.
 
-.. literalinclude:: ../examples/queueing/experiment.py
+.. literalinclude:: ../../examples/queueing/experiment.py
 
 Performance Analysis
 --------------------


+ 4 - 1
src/pypdevs/basesimulator.py

@@ -1092,7 +1092,10 @@ class BaseSimulator(Solver):
             interrupt = self.threading_backend.getInterrupt()
             if interrupt is None:
                 self.realtime_counter = 100
-                self.threading_backend.wait(wait_time, self.runsim)
+                if wait_time == float('inf') and getattr(self, "accept_external_input", False):
+                    self.threading_backend.wait(0.01, self.runsim)
+                else:
+                    self.threading_backend.wait(wait_time, self.runsim)
                 return True
             try:
                 info = interrupt.split(" ")

+ 9 - 0
src/pypdevs/controller.py

@@ -51,6 +51,7 @@ class Controller(BaseSimulator):
         self.running_irreversible = None
         self.initial_allocator = None
         self.prev_termination_time = 0.0
+        self.accept_external_input = False
 
     def __setstate__(self, retdict):
         """
@@ -317,6 +318,14 @@ class Controller(BaseSimulator):
         self.termination_condition = termination_condition
         self.termination_time_check = False
 
+    def setAcceptExternalInputs(self, aei):
+        """
+        Sets the controller to accept external inputs.
+        When enabled, the "early-return" of the simulator when all components have an infinite
+        time-advance is ignored.
+        """
+        self.accept_external_input = aei
+
     def findAndPerformRelocations(self, gvt, activities, horizon):
         """
         First requests the relocator for relocations to perform, and afterwards actually perform them.

+ 1 - 1
src/pypdevs/realtime/threadingBackend.py

@@ -51,7 +51,7 @@ class ThreadingBackend(object):
 
     def interrupt(self, value):
         """
-        Interrupt a running wait call.
+        Interrupt a running wait call, overwriting any previous interrupts.
 
         :param value: the value that interrupts
         """

+ 1 - 0
src/pypdevs/simconfig.py

@@ -623,6 +623,7 @@ class SimulatorConfiguration(object):
         if not isinstance(ports, dict):
             raise DEVSException("Realtime input port references should be a dictionary")
         self.simulator.realtime_port_references = ports
+        self.simulator.accept_external_input = True
 
     def setModelState(self, model, new_state):
         """

+ 2 - 0
src/pypdevs/simulator.py

@@ -210,6 +210,7 @@ class Simulator(object):
         self.setSchedulerActivityHeap()
         self.locations_file = None
         self.allocator = None
+        self.accept_external_input = False
         self.realtime_extra = []
 
         self.model_ids = []
@@ -584,6 +585,7 @@ class Simulator(object):
         self.controller.setDSDEVS(self.dsdevs)
         self.controller.setActivityTracking(self.activity_tracking)
         self.controller.setClassicDEVS(self.classicDEVS)
+        self.controller.setAcceptExternalInputs(self.accept_external_input)
         self.controller.setCellLocationTracer(self.x_size, 
                                               self.y_size, 
                                               self.location_cell_view)