revent-simulation

R simmer resource not dropping arrival when capacity --> 0


In my simulation, certain resources are on a capacity schedule, which alternates between 0 and 1 based on the time of day. If a resource cannot complete its task by the time its capacity goes to zero, the arrival should be dropped, wait a short period, and rollback to try to select an available resource. If no resource is available, the arrival goes through a timeout --> rollback loop until a resource becomes available.

The relevant code is as follows:

# Use a reject trajectory used to go back and select a new resource if the
# current resource runs out of time (i.e., its shift ends)
... |> 
simmer::seize_selected(
  continue = TRUE,
  reject = simmer::trajectory('dropped') |>
    simmer::timeout(\() runif(1, min = 0.07, max = 0.1)) |>
    simmer::rollback(target = 'select_resource')
  ) |>

# Clear the queue of the selected resource when its capacity is zero
simmer::renege_if(
  signal = 'clear_queue'
  ) |>
simmer::send(
  signals =  \() {
    cap <- simmer::get_capacity_selected(env)

    res_name <- simmer::get_selected(env)
    now <- simmer::now(env)

    queue_count <- simmer::get_queue_count_selected(env)
    if (res_name == 'Operator_Bill' & now > 41 & queue_count > 0) {
      browser()
    }

    if (cap == 0) {
      'clear_queue'
      } else {
        ''
      }
    }
  ) |> ...

The debug condition is never triggered for some reason, but on inspecting mon_resources it shows that arrivals are being served/in queue when capacity == 0. What would be the correct code to handle this situation?

mon_resources

usage_plot


Solution

  • Here's a simplified example of your question:

    library(simmer)
    
    t <- trajectory() %>%
      seize("res") %>%
      timeout(Inf)
    
    simmer() %>%
      add_resource("res", capacity=schedule(c(0, 5), c(1, 0))) %>%
      add_generator("dummy", t, at(0)) %>%
      run(10)
    #> simmer environment: anonymous | now: 10 | next: Inf
    #> { Monitor: in memory }
    #> { Resource: res | monitored: TRUE | server status: 1(0) | queue status: 0(Inf) }
    #> { Source: dummy | monitored: 1 | n_generated: 1 }
    

    In the example above, an arrival seizes a resource and stays there. The resource "closes" at t=5 thanks to the specified schedule. But then in the simulation status at t=10 we can see that the arrival is still in the server. And this is what you are trying to achieve:

    t <- trajectory() %>%
      handle_unfinished(trajectory() %>% log_("dropped!")) %>%
      seize("res") %>%
      timeout(Inf)
    
    simmer() %>%
      add_resource("res", capacity=schedule(c(0, 5), c(1, 0)),
                   queue_size=0, queue_size_strict=TRUE, preemptive=TRUE) %>%
      add_generator("dummy", t, at(0)) %>%
      run(10)
    #> 5: dummy0: dropped!
    #> simmer environment: anonymous | now: 5 | next: 
    #> { Monitor: in memory }
    #> { Resource: res | monitored: TRUE | server status: 0(0) | queue status: 0(0) }
    #> { Source: dummy | monitored: 1 | n_generated: 1 }
    

    And now the arrival is dropped. Several things to note: