问题描述
我正在探索 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)