SimPy 中的接收器状态

问题描述

我正在探索 SimPy 以模拟患者在护理过程中的流程。在模拟模型中,患者要么接受治疗,要么死亡。显然,这些都是相互竞争的风险,患者死后不应该接受治疗。但是,我对 SimPy 非常陌生,我还没有发现如何对水槽建模,以便这些已故患者无法继续进行模拟。

我比较熟悉simmer中的R包,在里面可以branch()模型结构,指定模型结构的哪个分支是死胡同。 SimPy 中是否有类似的功能?或者还有其他优雅的选择吗?

为了说明我的意思,下面是模拟模型:

from random import seed,randint
seed(123)

MAX_CYCLES = 5
PROB_DEATH = 0.2

class Patient:
    def __init__(self,env,treatment_cycles = 0):
        self.env = env
        self.treatment_cycles = treatment_cycles
        self.treatment_proc = env.process(self.get_treatment(env))
                
    def get_treatment(self,env):
        while self.treatment_cycles < MAX_CYCLES:
            self.treatment_cycles += 1

            rand = random.uniform(0,1)           
            if (rand < PROB_DEATH):
                yield env.timeout(random.randint(20,40))
                print('I have died at {}'.format(env.Now))
                ### Once this point has been reached,patients should not be able to continue ###
            else:
                yield env.timeout(randint(20,80))
                print("I have completed a full cycle of treatment after {} days.".format(int(env.Now)))

        
env = simpy.Environment()
pat = Patient(env)
env.run(until=250)

这会导致明显不需要的输出

I have died at 22
I have completed a full cycle of treatment after 59 days.
I have died at 80
I have completed a full cycle of treatment after 135 days.
I have completed a full cycle of treatment after 209 days.

解决方法

模拟有两种主要类型 经典的实体流程,站拥有所有逻辑,实体很少,站决定实体的命运。 代理库,实体/代理拥有所有代码并决定自己的命运。

实体流的经典示例是制造生产线,其中工作站/机器决定对实体做什么以及下一步将其发送到哪里(分支到)。您的 R 代码听起来像是使用这种范例

您的示例更像是实体/患者控制自己行为的代理。

要解决此问题,您只需向类添加“状态”属性即可跟踪患者是生是死。然后在你的while循环中检查病人的状态

见下图:

"""
Show how to use a state variable to change behavior

programmer: Michael R. Gibbs
"""
from random import seed,randint,uniform
import simpy

seed(123)

MAX_CYCLES = 5
PROB_DEATH = 0.2

class Patient:
    """
    patient seeking treatment
    """
    def __init__(self,env,treatment_cycles = 0):
        self.state = 'Live' # starts out as a living patient

        self.env = env
        self.treatment_cycles = treatment_cycles
        self.treatment_proc = env.process(self.get_treatment(env))
                
    def get_treatment(self,env):
        """
        gets a treatment that can change the patient's
        state from live,to dead
        """

        while self.treatment_cycles < MAX_CYCLES and self.state=='Live':
            # treat untile done,or patient has died

            self.treatment_cycles += 1

            rand = uniform(0,1)           
            if (rand < PROB_DEATH):
                # patient has died
                yield env.timeout(randint(20,40))
                print('I have died at {}'.format(env.now))

                # update state to dead
                self.state = 'Dead'
                ### Once this point has been reached,patients should not be able to continue ###
            else:
                yield env.timeout(randint(20,80))
                print("I have completed a full cycle of treatment after {} days.".format(int(env.now)))

        
env = simpy.Environment()
pat = Patient(env)
env.run(until=250)
,

这是一个更多的过程和更少的代理基本方式来编码它 进程所在的站点

"""
Show how to use a state variable to change behavior
less agent,more process

programmer: Michael R. Gibbs
"""
from random import seed,uniform
import simpy

seed(123)

MAX_CYCLES = 5
PROB_DEATH = 0.2

def died(env,patient):
    """
    patien dies,and no more processing
    """

    yield env.timeout(randint(20,80))
    patient.sate = 'Dead'
    print(f"Patient {patient.id} has died on day {env.now}")

def provide_treatment(env,patient):
    """
    determine fate of patient
    if lives provide treatment and send to next treatment
    if dies,send to death process
    """

    if patient.treatment_cycles < MAX_CYCLES:
        patient.treatment_cycles += 1

        rand = uniform(0,1)           
        if (rand < PROB_DEATH):
            # patient has died
            env.process(died(env,patient))

        else:
            # patient lives
            yield env.timeout(randint(20,80))
            print(f"Patient {patient.id} completed a full cycle of treatment after {env.now} days.")
            
            # send to next treatment
            env.process(provide_treatment(env,patient))
    else:
        # done with all treatments,do not send anywhere
        print(f"Patient {patient.id} has completed all treatments after {env.now} days")



class Patient:
    """
    patient seeking treatment
    """
    next_id = 1

    def __init__(self,treatment_cycles = 0):

        self.state = 'Live' # starts out as a living patient

        self.id = Patient.next_id
        Patient.next_id += 1

        self.env = env
        self.treatment_cycles = treatment_cycles
                
        
env = simpy.Environment()
pat = Patient(env)
env.process(provide_treatment(env,pat))
pat = Patient(env)
env.process(provide_treatment(env,pat))
env.run(until=250)