Select Output模块(和其他一些模块)有一个特殊功能,有时甚至会让高级用户感到困惑。如果您使用过流程建模库或行人库,那可能您已经遇到过,或者将要遇到类似问题。
希望能够通过这篇文章能帮助您在将来发现并解决这类问题。
假设我们有一个模型,行人从A点移动到B点,之后,需要从select output的5个输出中选择1个,然后退出。我们希望行人在5种可能的出口中随机选择。
在出口选择上,我们从随机分布中采样,并将所选的出口编号保存到自定义行人智能体中的变量exitNumber中。
当行人到达SelectOutput时,它将根据变量的值选择出口。我们还将跟踪行人的exitNumber变量,以再次检查他们存储的数字是否与他们选择的出口匹配。
按照上面的设计,我们预计,当行人离开GoTo模块时,它会对一个出口编号进行采样,然后在select output模块,它会根据采样的出口编号离开。
但是在运行模型时,意外发生了!
所有行人从第一个出口出来!
注意:当智能体到达Select Output模块时,我们正在向控制台打印出口编号,我们可以看到每个智能体都有一个随机分配的出口编号。
也就是说每个出口都会被正常取样,那为什么所有行人都会从1号出口通过?
也许有点违反直觉,但AnyLogic首先会检查行人将去哪里——从SelectOutput模块中选择一个输出——然后才触发GoTo块的离开时代码。之所以如此,实际上是有道理的,因为如果行人还没有确定要去哪里,甚至可以去任何地方,那么他们怎么才能从GoTo模块出来呢?如果在SelectOutput后有Hold模块又该怎么办?
简而言之,当检查下一步要去哪里时,智能体还没有定义他的出口,并且在没有决定使用哪个SelectOutput模块的出口前,会保留一个整数的默认值,即0。
总结了几种选择:
这可以在GoTo模块的进入时代码上完成,甚至可以在创建行人时完成。这完全取决于选择出口背后的特定逻辑。
这可能是其中最合乎逻辑的地方,但同样取决于您的特定模型和条件。
虽然并非在所有模块中都可用,但大多数流程建模库模块都有一个选项,可以在智能体即将退出但尚未退出模块时执行代码
在Select Output模块的前方放置一个延迟时间为0的Delay模块。
这种方式不是首选选项,因为它在流程流中添加了一个不必要的块。
请看下面的示例模型:
/uploads/editor/20220812/d18c7fa578dd716a3c7bece9f51346d4.zip
或者在此处规划并下载AnyLogic云上的模型
在Stack Overflow上有用户也遇到相同的问题,这里有一个链接,可以查看更多类似问题
必须记住:
如果您有一个select output模块(或其变体),则 “智能体将选择哪个出口?”,将在执行离开时代码之前进行评估
按时间顺序,模型执行过程如下:
1. 智能体进入模块(在我们的示例中就是GoTo模块),并触发“进入时”的代码
2. 执行特定于模块的操作后,下一个模块是Select Output,因此智能体会计算下一步要去哪里(在我们的示例中,它计算了exit number变量)
3. 智能体执行“离开时”的代码(在我们的示例中,它对出口编号进行了采样)
这种细微差别导致的问题,在经过经过数小时的调试后,甚至会让我们怀疑自己的头脑,但是现在你就会知道问题在哪了;)