Simmer R中能否为每个到达实体设置独立超时时间?
问题描述
我正在开发车辆行驶路段的离散事件仿真,路段行驶时间取决于该路段上的已有车辆数量:前期进入的车辆应采用自由流速度,仅后期车辆会受到拥堵影响。但在示例代码中,vehicle0的活动时间采用了拥堵速度(120kph),而它本应使用自由流速度(60kph)。请问在simmer中能否为同一时间到达的每个实体设置独立的超时时间?
问题原因
问题出在调用get_server_count的时机:当100辆车同时到达时,第一个车辆seize资源后,服务器计数立刻变成1,但后续车辆会在同一仿真时刻依次执行seize操作;等到第一个车辆执行timeout时,服务器计数已经是100(所有车辆都完成了seize),所以计算出的是拥堵状态下的行驶时间,而非车辆进入时的实际车辆数。
解决方案
当然可以为同一时间到达的实体设置独立超时时间。核心是在车辆seize资源的瞬间记录当时的车辆数,而非等到执行timeout时再获取当前服务器计数。可以通过set_attribute为每个实体存储专属的行驶时间,后续timeout直接调用这个属性即可。
修改后的代码如下:
library(tidyverse) library(magrittr) library(simmer) library(simmer.plot) library(simmer.bricks) rm(list = ls()) # Globals ---- limit_freeflow_segment1 <- 20 # 自由流最大车辆数(拥堵阈值) limit_segment1 <- limit_freeflow_segment1 * 2 # 路段最大容纳车辆数 freeflow_speed_segment1 <- 60 # 自由流速度(km/h) kms_segment1 <- 60 # 路段长度(km) # Monitor object to collect results ---- mon <- monitor_csv() road_sim <- simmer(mon = mon) # Timeout functions ---- mins_segment1 <- function(vehicles) { if (vehicles < limit_freeflow_segment1) { speed <- freeflow_speed_segment1 } else { speed <- (limit_freeflow_segment1 / vehicles) * freeflow_speed_segment1 } mins <- kms_segment1 / speed * 60 return(mins) } # Trajectory ---- vehicle_traj <- trajectory() %>% # 路段1行驶逻辑 ---- seize("road_segment_1") %>% # 关键改动:在seize后立即记录当前服务器计数(即该车辆进入时的路段车辆数) set_attribute( "entry_vehicle_count", function() get_server_count(.env = road_sim, resources = "road_segment_1") ) %>% # 基于进入时的车辆数计算专属行驶时间并存储 set_attribute( "travel_mins", function() mins_segment1(vehicles = get_attribute(.env = road_sim, "entry_vehicle_count")) ) %>% # 使用专属的行驶时间作为超时 timeout(function() get_attribute(.env = road_sim, "travel_mins")) %>% release("road_segment_1") road_sim %>% add_generator( name_prefix = "vehicle", trajectory = vehicle_traj, at(sort(rep(1:1, 100))) # 100辆车同时在时刻1到达 ) %>% add_resource(name = "road_segment_1", capacity = limit_segment1) %>% run() # 获取结果 ---- arrivals <- road_sim %>% get_mon_arrivals() resources <- road_sim %>% get_mon_resources() attributes <- road_sim %>% get_mon_attributes() View(arrivals)
关键改动说明
- 用
set_attribute替代set_global:全局变量会被所有实体共享覆盖,而实体属性是每个车辆独有的,能保留该车辆进入路段时的车辆数。 timeout时调用实体自身的travel_mins属性:确保每个车辆使用的是自己进入路段时计算的行驶时间,而非当前时刻的拥堵状态。
这样修改后,前20辆车(vehicle0到vehicle19)会使用自由流速度计算的60分钟行驶时间,后续车辆则根据进入时的总车辆数计算拥堵后的行驶时间,完全符合需求。
内容的提问来源于stack exchange,提问作者jimbo
相关产品推荐
相关产品推荐

