Introducing simmer: Discrete Event Simulation for R

[This article was first published on FishyOperations, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

This post has been transferred from another blog platform and could have dead links / incorrect lay-out.

Please note: the syntax described here is no longer up-to-date, please refer to the readme at simmer’s GitHub page.

The simmer package grew out of a personal need for a simple rapid development discrete event simulation (DES) framework. I work in the hospital sector and at times use a DES approach to simulate hospital processes / patient trajectories. DES can give you a quick look at process bottlenecks and test out the impact of alternative process set-ups.

Tools such as SimPy and SimJulia.jl served as inspiration for this package. What I wanted to achieve most was to develop a simple rapid development DES environment which had all (or most) important analysis/plotting functions easily at hand. Aiming for this rapid development DES package and working from a specific business process background has most likely tainted the development of the package to an extent that it won’t be as dynamic to be applicable to everyone’s specific needs.

Speed & performance

While R is arguably not known as a fast language the current performance bottleneck of the simmer package is in simmer‘s own design. Future development will focus more on the performance of the package, where there is definitely room for improvement. If the package will gain popularity, I might be persuaded to move some of the fundamental parts of the simulation engine to C++ to achieve further performance gains.

An example

Let’s say we want to simulate a very simple patient trajectory; a patient enters the hospital and has to register at the desk, next, is seen by a nurse for an intake and finally is met by the doctor for a consult.

Below this trajectory is written as a ‘trajectory dataframe’.

trajectory <- read.table(header=T, text=
	"event_id  description   resource        amount  duration          successor
	1         registration  administration  1       runif(1,3,10)     2
	2         intake        nurse           1       runif(1,10,20)    3
	3         consultation  doctor          1       runif(1,5,15)     NA"  )

This gives the following data frame:

ENT_ID DESCRIPTION RESOURCE AMOUNT DURATION SUCCESSOR
1 registration administration 1 runif(1,3,10) 2
2 intake nurse 1 runif(1,10,20) 3
3 consultation doctor 1 runif(1,5,15) N

As you can see, the durations given here are in the form of an R command. Any function call or value which generates a (single) number can be used for the duration and sucessor values. These values are re-evaluated for every entity that get assigned to this trajectory.

Next we build up a simple simulation with 10 patients, each starting about 10 minutes apart, to be precise rnorm(1,10) apart. We decide let this run for 15 replications to get a view on the variability.

library(simmer)

sim <-
  create_simulator(name = "SuperDuperSim") %>%
  add_trajectory(name = "simple_trajectory", trajectory_df = trajectory) %>%
  add_resource(name = "administration", capacity = 1) %>%
  add_resource(name = "nurse", capacity = 1) %>%
  add_resource(name = "doctor", capacity = 2) %>%
  add_entities_with_interval(n = 10, name_prefix = "patient", trajectory_name = "simple_trajectory", interval = "rnorm(1,10)") %>%
  replicator(15)

All resources required have to be added using the add_resource command. Note that we add 2 doctors to the simulation here. Once the simulation object sim has been built up, we can start up the simulation and let it simmer for a while.

sim<-
  simmer(sim)

Once the simmering stops we can plot some of the results. We can for example have a look at the resource utilization of the doctor resource.

plot_resource_usage(sim, resource_name = "doctor")

Or have a look at the utilization of the different resources in the simulation.

plot_resource_utilization(sim)

Maybe we want a view on the evolution of the entities’ flow, waiting or activity times.

plot_evolution_entity_times(sim, type = "flow_time")

plot_evolution_entity_times(sim, type = "activity_time")

plot_evolution_entity_times(sim, type = "waiting_time")

Try it out!

Installation instructions, further documentation and extra examples can be found at https://github.com/Bart6114/simmer. For issues / bugs / improvement suggestions create an issue on GitHub or send me a mail at [email protected].

Have fun with it: feedback & tips are always welcome!

To leave a comment for the author, please follow the link and comment on their blog: FishyOperations.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)