如何在SimPy

时间:2016-04-06 13:31:14

标签: simpy

我想实现离散事件维护调度模拟,其中一些维护活动必须在另一个维护活动发生时发生。

例如,如果墙壁每5年重新粉刷一次,并且每14年更换一次干衬里,那么每当更换干衬里并重新开始计时时,必须重新粉刷墙壁。

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

我不确定是否应该将每个活动实现为引用依赖过程的过程,或者“墙维护”应该是内部处理逻辑的过程,还是其他方式。

我所拥有的代码将每个活动作为一个进程,将依赖进程存储为属性,但我觉得我可能错过了正确的方法,因为我看到事件在同一年发生了两次。 / p>

2 个答案:

答案 0 :(得分:1)

你应该总是从一个非常简单(和错误)的实现开始,只是为了更好地理解你的用例和感觉如何工作,例如:

import simpy


def paint_walls(env, interval):
    while True:
        yield env.timeout(interval)
        print('yr %2d: paint walls' % env.now)


def replace_dry_lining(env, interval):
    while True:
        yield env.timeout(interval)
        print('yr %d: replace dry-lining' % env.now)


env = simpy.Environment()
env.process(paint_walls(env, interval=5))
env.process(replace_dry_lining(env, interval=14))
env.run(until=20)

输出:

yr  5: paint walls
yr 10: paint walls
yr 14: replace dry-lining
yr 15: paint walls

然后您可以开始扩展/修改模拟。以下是您可以如何建模问题的两种可能性:

变体A

我们继续使用两个独立的流程,但需要一种方法来交换它们之间的“干衬里更换”事件,这样我们也可以画墙:

import simpy


class Maintenance:
    PAINT_WALL_INTERVAL = 5
    REPLACE_DRY_LINING_INTERVAL= 14

    def __init__(self, env):
        self.env = env
        self.dry_lining_replaced = env.event()

        self.p_paint_walls = env.process(self.paint_walls())
        self.p_replace_dry_lining = env.process(self.replace_dry_lining())

    def paint_walls(self):
        timeout = self.PAINT_WALL_INTERVAL
        while True:
            yield self.env.timeout(timeout) | self.dry_lining_replaced
            print('yr %2d: paint walls' % self.env.now)

    def replace_dry_lining(self):
        timeout = self.REPLACE_DRY_LINING_INTERVAL
        while True:
            yield self.env.timeout(timeout)
            print('yr %2d: replace dry-lining' % self.env.now)
            self.dry_lining_replaced.succeed()
            self.dry_lining_replaced = self.env.event()


env = simpy.Environment()
m = Maintenance(env)
env.run(until=20)

输出:

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

变体B

我们也可以通过一个等待“油漆墙”或“替换干衬”事件的过程对其进行建模:

import simpy


def maintenance(env):
    PAINT_WALL_INTERVAL = 5
    REPLACE_DRY_LINING_INTERVAL = 14

    paint_wall = env.timeout(PAINT_WALL_INTERVAL)
    replace_dry_lining = env.timeout(REPLACE_DRY_LINING_INTERVAL)

    while True:
        results = yield paint_wall | replace_dry_lining
        do_paint = paint_wall in results
        do_replace = replace_dry_lining in results

        if do_replace:
            print('yr %2d: replace dry-lining' % env.now)
            replace_dry_lining = env.timeout(REPLACE_DRY_LINING_INTERVAL)

        if do_paint or do_replace:
            print('yr %2d: paint walls' % env.now)
            paint_wall = env.timeout(PAINT_WALL_INTERVAL)


env = simpy.Environment()
env.process(maintenance(env))
env.run(until=20)

输出:

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

答案 1 :(得分:0)

这是我最终采用的方法:

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)