Hi Inaki,
Thank you and I have tried with global dynamic attributes as your direction. The problem is that I have to make a waiting loop in each resource trajectory. This is because when a resource is seized while the others are not then the resource has to wait until all seized. After the waiting loop the resource will time out for the remaining time. The problem is how to make the waiting loop asyn?
The code below is working well but the waiting loop seems not to be well programmed. Any suggestions would be much appreciated:
library(simmer)
library(simmer.bricks)
library(simmer.plot)
library(tidyverse)
library(tictoc)
set.seed(1234)
TIME_TOGETHER<-2 # doctor and nurse have to share 2 minutes
TIME_NURSE<-c(5,.1) # 5 minutes +/- 0.1
TIME_DOCTOR<-c(3,.1) # 3 minutes +/- 0.1
TIME_CLEANING<-1 # room cleaning after treatment
NUM_OF_RES<-2 # two resources: nurse and doctor
###function to generate unique patient arrival id
get_patient_id <- function() {
patient_id<<- -1
function() {
patient_id <<- patient_id+1
patient_id
}
}
### calculate time to constraint time share together
time_to_run<-function(res_time=TIME_DOCTOR)
{
duration_time_from_seized<-now(env)- get_attribute(env,'time_seized')
mean_time<-rnorm(1,res_time[1],res_time[2])
return(ifelse( TIME_TOGETHER + duration_time_from_seized> mean_time,
TIME_TOGETHER,
mean_time- duration_time_from_seized)
)
}
### common path for doctor and nurse
common_path<-function(res_name='doctor',res_time=TIME_DOCTOR)
{
trajectory(res_name) %>%
seize(res_name) %>%
log_(function() paste0(res_name,' seized')) %>%
#mark when the resource is seized
set_attribute('time_seized',function() now(env)) %>%
#increasing global dynamic counter id (each patient has 1 unique id)
set_global(function() paste0('num_res_seized_',get_attribute(env,'patient_id')),1,mod='+')%>%
### loop waiting until all resources are seized: using dynamic counter id
branch(option=function() ifelse( get_global(env, paste0('num_res_seized_',get_attribute(env,'patient_id')))==NUM_OF_RES,0,1),continue=TRUE,
trajectory() %>%
timeout(0.1) %>% ### the smaller number the smaller error but simulation time is large
rollback(2)
)%>%
## when all resources are seized, check time at all resources, they must be the same!
log_(function() paste0('Time now at ',res_name,'=',now(env))) %>%
## then now calculate the time need to be shared
timeout( function() time_to_run(res_time) )%>%
release(res_name) %>%
log_(function() paste0(res_name,' released'))
}
get_id<-get_patient_id()
env<-simmer()
doctor_path<-common_path('doctor',TIME_DOCTOR)
nurse_path<-common_path('nurse',TIME_NURSE)
seize("room") %>%
## get unique id
set_attribute('patient_id',function() get_id()) %>%
## create a global-unique counter for each patient
set_global(function() paste0('num_res_seized_',get_attribute(env,'patient_id')),0) %>%
do_parallel(
doctor_path,
nurse_path,
.env=env,wait=TRUE
)%>%
timeout(TIME_CLEANING)%>%
release("room",1) %>%
log_("room released")
tic()
test1<-env %>%
add_resource("room",3) %>%
add_resource("doctor",2) %>%
add_resource("nurse",2) %>%
add_generator("visit", t, at(seq(1,1000))) %>%
run() %>% invisible
test1 %>% get_mon_arrivals(per_resource=TRUE) %>% arrange(name)
toc()