流行病和诊所
我们将创建一个简单的基于代理的流行病模型,并将其与一个简单的离散事件诊所模型联系起来。
当一个病人发现症状时,他将要求在能力有限的诊所接受治疗。我们将探讨诊所的能力如何影响疾病的动态发展。
第一阶段:创建代理群体
- 创建一个新的模型,将模型的时间单位设置为 minutes
- 把 Agent Population 拖到 Main 的编辑器上
- 将 agent class name 改为 Patient
- 设置动画为 none
- 设置 initial number of agents(代理的初始数量)为 2000
- 设置 continue space 宽度为 650,高度为 200
- 选择应用随机布局
- 设置 network type为 distance based , 范围为 30
- 在 main 的编辑器中,打开 patients 的属性页。在 Advanced 中选择 “Show presentation”
- 在 " Patient "编辑器中,从 palette 中拖出一个 oval,设置半径为2。 把椭圆放在坐标原点附近
- 运行模型,agents 随机地分布在矩形空间中,到目前为止,没有活动
第二阶段:定义病人的行为
- 病人最初处于易感状态,他可以被感染。疾病的传播是由一个病人向另一个病人发送的 "感染 "信息来模拟的。
- 在收到这样的信息后,病人过渡到暴露状态,他已经被感染,但没有症状。
- 经过一个随机的潜伏期,病人发现了症状并进入感染状态。
- 之所以区分暴露状态和感染状态,是因为病人发现症状前后的接触行为不同:感染状态下的接触率为每天1次,而暴露状态下为5次。感染率为7%。
- 感染状态有两种可能的退出方式。病人可以在诊所接受治疗(然后,他被保证会康复),或者疾病可能在没有干预的情况下自然发展。
- 在后一种情况下,病人仍然可以在疾病期限(20天)内以较高的概率(90%)恢复,或者死亡。如果病人死亡,他将从模型中删除自己。治疗的完成是由发送给代理人的信息 "已治疗 "来模拟的。
- 康复的病人需要对疾病有暂时的免疫力(60天)。我们在模型中通过恢复状态来反映这一点,在这个状态下,病人对可能到来的 "感染 "信息没有反应。在免疫期结束时,过渡期 ImmunityLost 将病人带回易感状态。
- 打开 patient 的编辑器,设置参数
ContactRate | 5 |
---|---|
ContactRateInfected | 1 |
Infectivity | 0.07 |
IncubationPeriod | 3 |
IllnessDuration | 20 |
SurvivalProbability | 0.9 |
ImmunityDuration | 60 |
- 创建状态图
oval.setFillColor(yellow);
"Infection"
oval.setFillColor(darkOrange);
ContactRate * Infectivity
send( "Infection", RANDOM_CONNECTED );
IncubationPeriod*uniform(0.5,2)
Infected
oval.setFillColor(red);
transition1
ContactRateInfected * Infectivity
send( "Infection", RANDOM_CONNECTED );
Treated
"Treated"
NotTreated
IllnessDuration * uniform( 0.5, 2 )
Died
Survived
randomTrue( SurvivalProbability )
Recovered
oval.setFillColor( green );
ImmunityLost
ImmunityDuration * uniform( 0.5, 2 )
- 设置初始感染
打开 Main 的属性,在 On Startup 字段中输入以下代码
for( int i=0; i<5; i++ )
patients.random().receive( "Infection" );
- 运行模型
收集统计资料和图表显示
打开 Main 的编辑器,选择 patients 并打开其属性中的统计页面(Statistics)
添加名为 NSusceptible 的统计数据,类型为 count ,条件为
item.statechart.isStateActive(item.Susceptible)
这将产生人口的 NSusceptible() 函数,它将计算并返回处于 Susceptible 状态的病人数量
分别为 Exposed, Infected, and Recovered 添加另外三个统计数据
item.statechart.isStateActive(item.Exposed)
item.statechart.isStateActive(item.Infected)
item.statechart.isStateActive(item.Recovered)
从 Analysis palette 中拖动 Time stack chart 到 Main 上,并把它放在 agents 所占区域的下面
将图表的 Time window 设置为 500,并 Display Up 最多 500 个最新样本
在图表中添加四个数据项,对应于你所创建的四个统计功能。例如,第一个项目的标题是 Infected,颜色为 orangeRed ,value 为 patients.NInfected()
Exposed
patients.NExposed()
Recovered
patients.NRecovered()
Susceptible
patients.NSusceptible()
在项目树中选择 Simulation experiment,并打开其属性中的 Model time
设置执行模式为 Real time with scale,规模为 25 , 这将使事情发生得更快
运行模型
第三阶段:增加诊所
诊所将通过一个非常简单的离散事件模型进行建模。等待治疗的病人的队列和实际治疗的延时模型。与纯离散事件模型不同,这个过程中的实体不是由 Source 产生的,而是由 agents 注入的。
一旦病人发现症状,就会创建一个实体(治疗请求)并添加到诊所流程中。一旦治疗完成,该实体将向病人发送一个 "已治疗 "的消息,病人将过渡到恢复状态。然而,如果病人被治愈(在 IllnessDuration 之后)或在治疗完成之前死亡,他将从诊所消失。
条件如下:
诊所的等候室有无限的容量
治疗需要七天时间
诊所里只有20张床
如果病人在等待治疗或治疗期间自行恢复或因病死亡,他就会从诊所中消失
创建新的实体类型 TreatmentRequest
右键单击项目树中的模型项目,并从上下文菜单中选择
新建 ——> Java class
在向导中,将该类命名为 TreatmentRequest,并将其 Superclass 设置为 Entity
点击 Next
在下一个向导页面中,添加一个字段,名称为 patient ,类型为 Patient
点击 Finish,并关闭打开的 Java 编辑器
在 Main 的编辑器中添加流程图
打开Main的编辑器,把流程图放在一起。使用 Enterprise library palette(old) 中的对象
拖动 Enter,Queue,Delay 和 Sink,分别命名为 requestTreatment,wait,treatment 和 finished
设置 wait 的容量为 infinite ,选择 TreatmentRequest 作为实体类
设置治疗的延迟时间为 7,容量为 20,选择 TreatmentRequest 作为实体类
finished
选择 TreatmentRequest 作为实体类,进入时向病人发送 “Treated” 信息
在 Main 的编辑器中创建 cancelTreatmentRequest 函数
函数 cancelTreatmentRequest(),它将被那些自行痊愈或在得到治疗机会前死亡的病人调用
for( int i=0; i<wait.size(); i++ ) {
TreatmentRequest tr = wait.get( i );
if( tr.patient == patient ) {
wait.remove( tr );
return;
}
}
for( int i=0; i<treatment.size(); i++ ) {
TreatmentRequest tr = treatment.get( i );
if( tr.patient == patient ) {
treatment.remove( tr );
return;
}
}
error( "Entity not found" );
return;
将诊所中的治疗纳入病人的行为
将行动添加到状态图的转换中
Symptoms
get_Main().requestTreatment.take( new TreatmentRequest( this ) );
NotTreated
get_Main().cancelTreatmentRequest( this );
在 Main 中增加感染按钮
patients.random().receive( "Infection" );