Skip to content

Discrete Event Simulation in Python with Py-DES

In this section we’ll explore the Py-DES basic objects and its main capabilities.

Setup

Easiest way to setup Py-DES is to install it using pip with the following command.

$ pip install py-des-lib

Hello-World

from pydes import Component, Simulator

class Process(Component):
    def __init__(self, sim: Simulator):
        self.sim = sim

    def main(self):
        for _ in range(10):
            print(self.sim.now(),"waiting")
            self.sim.sleep(2)
            print(self.sim.now(),"waiting")

Now schedule the main process object and run simulation

1
2
3
4
5
sim = Simulator()
p = Process(sim)
sim.schedule(p.main)
sim.schedule(p.main)
sim.run()

Simulator Object

Simulator is the central object of Py-DES and is used to model all the process and events of the system.

Its main objective is to schedule process and events and then execute them in a time-ordered way.

Parameters:

Name Type Description Default
init int | float | datetime

The initial simulation time specified as a float or datetime object.

0
trace bool

Indicates whether tracing is enabled or not.

True

Simulators can be instantiated either using numeric time (float or int) or datetime time.

To create a Simulator with numeric time units simply ommit the argument or pass a specific until argument.

sim = Simulator(until=10)

If you prefer to use datetime objects, you can pass to the until argument a datetime object.

from datetime import datetime
sim = Simulator(until=datetime.max)

Once you created the Simulator object you can start modeling your procesess using its differents methods.

Methods:

Name Description
sleep

Sleep for the given duration.

sleep_until

Sleep until the given simulation time.

wait_for

Suspends the process until a condition becomes true.

schedule

Activates a process either immediately (if both at and after are None) or after a delay.

run

Starts simulation.

record

records an event by passing a component a value and optionally a description.

records

returns a list with all the recors that were saved during the simulation.

record(name, value, description=None)

Record a simulation event.

Parameters:

Name Type Description Default
name str

The name associated with the event.

required
value Any

Value associated with the event.

required
description str | None

Description of the event.

None

records()

Get recorded simulation events.

Returns:

Type Description
list[Record]

list of Record objects

schedule(func, at=None, after=None)

Schedules a function either immediately (if both at and after are None) or after a delay.

Parameters:

Name Type Description Default
func Callable[[], None]

A function to be scheduled and runned during the simulation.

required
at int | float | datetime | None

Simulation time to activate the process, default is None.

None
after int | float | timedelta | None

Delay activation with specified time, default is None.

None
sim = Simulator(until=10)

class Process:
    def __init__(self, sim:Simulation):
        self.sim = sim
    def main(self):
        while True:
            print("this is my process running")
            self.sim.sleep(10)

process = Process(sim)
sim.schedule(proc.main)

wait_for(cond, timeout=None)

Wait for a condition to become true.

Suspends this process until the condition becomes true.

Parameters:

Name Type Description Default
cond Callable[[], bool]

Function to test.

required
timeout int | float | timedelta | None

Maximum simulation time to wait for condition to become true, default is None.

None

sleep(duration=None)

Sleep for the given duration.

Parameters:

Name Type Description Default
duration int | float | timedelta | None

Duration to sleep for.

None

sleep_until(until=None)

Sleep until the given simulation time.

Parameters:

Name Type Description Default
until int | float | datetime | None

Simulation time to sleep until.

None

now()

Return current simulation time.

Returns:

Type Description
float | datetime

current time expressed as float or datetime depending on the initial simulation time.

run(until=inf)

Start simulation.

Parameters:

Name Type Description Default
until int | float | datetime

maximum simulation time expressed as datetime or float.

inf

options: show_object_full_path: false show_root_toc_entry: false show_root_heading: false members: - init options: show_object_full_path: false show_root_toc_entry: false show_root_heading: false members: - init

Component Object

Base class for components in the simulation.

Components are just an utility base class that tracks how many instances of itself are created. Its id property will be unique during the simulation.

This property is usefull to identify different components in the simulation without having to set an explicit name for them, however is not a requirement for the Simulation to run.

from pydes.process import Component, Simulator

# define the component with a main method
class Process(Component):
    def __init__(self, sim: Simulator):
        self.sim = sim

    def main(self):
        for _ in range(10):
            print(self.sim.now(),"waiting")
            self.sim.sleep(2)
            print(self.sim.now(),"waiting")

# create the simulator object
sim = Simulator()

# create an instance of the Component
process = Process(sim)

# schedule the process in the simulator
sim.schedule(process.main)

# now you can run the simulation
sim.run()

options: show_object_full_path: false show_root_toc_entry: false show_root_heading: false members: - init options: show_object_full_path: false show_root_toc_entry: false show_root_heading: false members: - init

Recording Events

The Monitor is simply a convenient class to record different events or moments during the simulation. Simulation without data analytics is useless.

The Monitor is used internally by the Simulator and is not ment to be used outside this context.

To record an event you simply have to call the record method o the simulator and pass 2 required parameters and optionally a third one.

from pydes.process import Component, Simulator

class Process(Component):
    def __init__(self, sim: Simulator):
        self.sim = sim

    def main(self):
        for _ in range(10):
            self.sim.record(self,"start waiting")
            self.sim.sleep(2)
            self.sim.record(self,"end waiting","this is an aditional description")

When the simulation runs, you'll see all you recorded events printed out. Besides, these records can be retreived for further analysis using the records from the Simulator.

To turn off the printing of the records during simulation, you can pass 'trace=False' to the Simulator constructor.

Parameters:

Name Type Description Default
sim Simulator

The simulator instance.

required
trace bool

Indicates whether tracing is enabled or not.

required

record(name, value, description)

Record a simulation event.

Parameters:

Name Type Description Default
name str

The name associated with the event.

required
value Any

Value associated with the event.

required
description str | None

Description of the event.

required

values()

Get recorded simulation events.

Returns:

Type Description
list[Record]

list of Record objects.

options: show_object_full_path: false show_root_toc_entry: false show_root_heading: false members: - init options: show_object_full_path: false show_root_toc_entry: false show_root_heading: false members: - init