Search code examples
simpy

How to split up dependent events in SimPy


I want to implement a discrete-event maintenance scheduling simulation in which some maintenance activities must happen whenever another one happens.

For example, if walls are repainted every 5 years, and dry-lining is replaced every 14 years, then walls must be repainted whenever the dry-lining is replaced and the clock restarted.

yr 5:  paint walls
yr 10: paint walls
yr 14: replace dry-lining
yr 14: paint walls
yr 19: paint walls
...

I'm not sure whether I should implement each activity as a process which refers to the dependent process, or if "wall maintenance" should be a process with the logic handled internally, or some other way of.

The code I have has each activity as a process with the dependent process stored as an attribute but I feel like I'm probably missing the correct way of doing this as I'm seeing events happen twice in the same year.


Solution

  • This is the approach I took in the end:

    import simpy
    from simpy.events import Interrupt
    
    
    class Construction(object):
    
        def __init__(self, name, components):
            self.name = name
            self.components = components
            self.link_components()
    
        def link_components(self):
            """Link each component to the next outermost component      
            """
            for i, component in enumerate(self.components):
                try:
                    component.dependent = self.components[i+1]
                except IndexError:
                    component.dependent = None                
    
    class Component(object):
    
        def __init__(self, env, name, lifespan):
            """Represents a component used in a construction.
    
            """
            self.env = env
            self.name = name
            self.lifespan = lifespan    
            self.action = env.process(self.run())
    
        def run(self):
            while True:
                try:
                    yield self.env.timeout(self.lifespan)
                    self.replace()
                except Interrupt:  # don't replace
                    pass
    
        def replace(self):
            print "yr %d:  replace %s" % (env.now, self.name)
            if self.dependent:
                self.dependent.action.interrupt()  # stop the dependent process
                self.dependent.replace()  # replace the dependent component
    
    
    env = simpy.Environment()
    components = [Component(env, 'structure', 60),
                  Component(env, 'dry-lining', 14),
                  Component(env, 'paint', 5)]
    wall = Construction('wall', components)
    env.run(until=65)