Skip to content

Commit f04e310

Browse files
committed
feat(model): add resources with infinite capacity, which then facilitated calculation of occupancy (as needed arrivals per_resource so could distinguish times in the output table for ASU unit vs rehab unit, as patients arriving to ASU can transfer to rehab)
1 parent 3dff1f3 commit f04e310

6 files changed

Lines changed: 117 additions & 49 deletions

File tree

NAMESPACE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ export(sample_routing)
1515
export(transform_to_lnorm)
1616
importFrom(dplyr,filter)
1717
importFrom(simmer,add_generator)
18+
importFrom(simmer,add_resource)
1819
importFrom(simmer,branch)
1920
importFrom(simmer,get_attribute)
2021
importFrom(simmer,get_mon_arrivals)
2122
importFrom(simmer,get_mon_resources)
2223
importFrom(simmer,log_)
24+
importFrom(simmer,release)
25+
importFrom(simmer,seize)
2326
importFrom(simmer,set_attribute)
2427
importFrom(simmer,simmer)
2528
importFrom(simmer,timeout)

R/create_asu_trajectory.R

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
#' of routing to each destination (e.g.
1414
#' \code{param$asu_routing$stroke$rehab = 0.24}).
1515
#'
16-
#' @importFrom simmer branch get_attribute log_ set_attribute timeout trajectory
16+
#' @importFrom simmer branch get_attribute log_ release seize set_attribute
17+
#' @importFrom simmer timeout trajectory
1718
#' @importFrom stats rlnorm
1819
#'
1920
#' @return Simmer trajectory object. Defines patient journey logic through the
@@ -27,6 +28,8 @@ create_asu_trajectory <- function(env, patient_type, param) {
2728

2829
log_("🚶 Arrived at ASU") |>
2930

31+
seize("asu_bed", 1L) |>
32+
3033
# Sample destination after ASU (as destination influences length of stay)
3134
set_attribute("post_asu_destination", function() {
3235
sample_routing(prob_list = param[["asu_routing"]][[patient_type]])
@@ -78,6 +81,8 @@ create_asu_trajectory <- function(env, patient_type, param) {
7881

7982
log_("🏁 ASU stay completed") |>
8083

84+
release("asu_bed", 1L) |>
85+
8186
# If that patient's destination is rehab, then start on that trajectory
8287
branch(
8388
option = function() {

R/create_rehab_trajectory.R

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
#' probability of routing to each destination (e.g.
1414
#' \code{param$rehab_routing$stroke$esd = 0.40}).
1515
#'
16-
#' @importFrom simmer get_attribute log_ set_attribute timeout trajectory
16+
#' @importFrom simmer get_attribute log_ release seize set_attribute timeout
17+
#' @importFrom simmer trajectory
1718
#' @importFrom stats rlnorm
1819
#'
1920
#' @return Simmer trajectory object. Defines patient journey logic through the
@@ -27,6 +28,8 @@ create_rehab_trajectory <- function(env, patient_type, param) {
2728

2829
log_("🚶 Arrived at rehab") |>
2930

31+
seize("rehab_bed", 1L) |>
32+
3033
# Sample destination after rehab (as destination influences length of stay)
3134
set_attribute("post_rehab_destination", function() {
3235
sample_routing(prob_list = param[["rehab_routing"]][[patient_type]])
@@ -75,5 +78,7 @@ create_rehab_trajectory <- function(env, patient_type, param) {
7578

7679
timeout(function() get_attribute(env, "rehab_los")) |>
7780

78-
log_("🏁 Rehab stay completed")
81+
log_("🏁 Rehab stay completed") |>
82+
83+
release("rehab_bed", 1L)
7984
}

R/model.R

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
#' Default is TRUE.
88
#'
99
#' @importFrom dplyr filter
10-
#' @importFrom simmer get_mon_arrivals get_mon_resources simmer wrap
10+
#' @importFrom simmer add_resource get_mon_arrivals get_mon_resources simmer
11+
#' @importFrom simmer wrap
1112
#' @importFrom utils capture.output
1213
#'
1314
#' @return TBC
@@ -33,6 +34,13 @@ model <- function(run_number, param, set_seed = TRUE) {
3334

3435
# Add ASU and rehab direct admission patient generators
3536
for (unit in c("asu", "rehab")) {
37+
38+
# Add beds resource with inifinite capacity (required so we can get metrics
39+
# on occupancy etc. based on count of patients with each resource)
40+
env <- add_resource(
41+
.env = env, name = paste0(unit, "_bed"), capacity = Inf
42+
)
43+
3644
for (patient_type in names(param[[paste0(unit, "_arrivals")]])) {
3745

3846
# Create patient trajectory
@@ -54,9 +62,11 @@ model <- function(run_number, param, set_seed = TRUE) {
5462
}
5563

5664
# Run the model
65+
sim_length <- 20L
66+
# sim_length <- param[["data_collection_period"]] + param[["warm_up_period"]]
5767
sim_log <- capture.output(
5868
env <- env |> # nolint
59-
simmer::run(20L) |>
69+
simmer::run(sim_length) |>
6070
wrap()
6171
)
6272

@@ -77,9 +87,32 @@ model <- function(run_number, param, set_seed = TRUE) {
7787

7888
# Extract the monitored arrivals info from the simmer environment object.
7989
# Remove patients with start time of -1, as they are patients whose arrival
80-
# was sampled but falls after the end of the smiulation.
81-
result <- get_mon_arrivals(env, ongoing = TRUE) |>
90+
# was sampled but falls after the end of the simulation.
91+
arrivals <- get_mon_arrivals(env, per_resource = TRUE, ongoing = TRUE) |>
8292
filter(.data[["start_time"]] != -1L)
8393

84-
return(result)
94+
# Create sequence of days from 0 to end of simulation
95+
days <- seq(0L, ceiling(sim_length))
96+
97+
# Calculate occupancy at end of each day (i.e. at time 1, 2, 3, 4...)
98+
# Make dataframe with one row per resource per day to count patients
99+
occupancy <- expand.grid(
100+
resource = unique(arrivals$resource),
101+
time = days
102+
) |>
103+
rowwise() |>
104+
mutate(
105+
# For each resource and day, count patients who:
106+
# - Arrived on or before this day (start_time <= time)
107+
# - Have not yet left by this day (end_time > time), or have NA end_time
108+
# (still present at simulation end)
109+
occupancy = sum(
110+
arrivals$resource == .data[["resource"]] &
111+
arrivals$start_time <= time &
112+
(is.na(arrivals$end_time) | arrivals$end_time > time)
113+
)
114+
) |>
115+
ungroup()
116+
117+
return(list(arrivals = arrivals, occupancy = occupancy))
85118
}

rmarkdown/analysis.Rmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ library(simulation)
2424
```{r}
2525
param <- create_parameters(log_to_console = TRUE)
2626
result <- model(run_number = 1L, param = param, set_seed = TRUE)
27-
arrange(result, start_time)
27+
result
2828
```

rmarkdown/analysis.md

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -192,45 +192,67 @@ result <- model(run_number = 1L, param = param, set_seed = TRUE)
192192
## [153] "19.8821: asu_stroke19: ⏳ ASU length of stay: 1.819"
193193

194194
``` r
195-
arrange(result, start_time)
195+
result
196196
```
197197

198-
## name start_time end_time activity_time finished replication
199-
## 1 asu_other0 0.4473448 2.676165 2.2288198 TRUE 1
200-
## 2 asu_neuro0 0.5245442 4.171772 3.6472278 TRUE 1
201-
## 3 asu_stroke0 0.9062182 1.422308 0.5160899 TRUE 1
202-
## 4 asu_stroke1 1.1893125 5.509324 4.3200113 TRUE 1
203-
## 5 asu_other1 1.2902898 6.502389 5.2120987 TRUE 1
204-
## 6 asu_stroke2 1.9750085 12.640820 10.6658111 TRUE 1
205-
## 7 asu_stroke3 2.6540471 7.370079 4.7160317 TRUE 1
206-
## 8 asu_other2 2.7220399 6.960086 4.2380463 TRUE 1
207-
## 9 asu_neuro1 3.2678517 3.867813 0.5999612 TRUE 1
208-
## 10 asu_other3 5.9118414 9.356139 3.4442981 TRUE 1
209-
## 11 asu_other4 6.5630745 9.901922 3.3388479 TRUE 1
210-
## 12 asu_neuro2 6.7174941 NA NA FALSE 1
211-
## 13 asu_stroke4 7.4047666 11.548437 4.1436706 TRUE 1
212-
## 14 asu_stroke5 7.7291507 10.492783 2.7636327 TRUE 1
213-
## 15 asu_other5 8.9680111 9.644429 0.6764179 TRUE 1
214-
## 16 asu_stroke6 9.2809003 10.249020 0.9681194 TRUE 1
215-
## 17 rehab_stroke0 9.5062960 NA NA FALSE 1
216-
## 18 asu_stroke7 9.9287833 18.114076 8.1852931 TRUE 1
217-
## 19 asu_stroke8 10.0363922 NA NA FALSE 1
218-
## 20 asu_stroke9 10.3331093 10.844631 0.5115214 TRUE 1
219-
## 21 asu_neuro3 10.6050662 14.143857 3.5387909 TRUE 1
220-
## 22 asu_tia0 10.9892778 12.129621 1.1403433 TRUE 1
221-
## 23 asu_neuro4 13.5331919 NA NA FALSE 1
222-
## 24 asu_stroke10 13.6095765 16.845102 3.2355256 TRUE 1
223-
## 25 asu_neuro5 13.7205915 15.051997 1.3314053 TRUE 1
224-
## 26 asu_stroke11 13.8532754 NA NA FALSE 1
225-
## 27 asu_other6 13.8727452 15.859368 1.9866225 TRUE 1
226-
## 28 asu_stroke12 13.9904583 15.084152 1.0936941 TRUE 1
227-
## 29 rehab_stroke1 14.0813875 NA NA FALSE 1
228-
## 30 asu_stroke13 15.8908936 18.801468 2.9105743 TRUE 1
229-
## 31 asu_neuro6 16.6529204 NA NA FALSE 1
230-
## 32 asu_stroke14 17.1432238 NA NA FALSE 1
231-
## 33 asu_stroke15 18.1849052 NA NA FALSE 1
232-
## 34 asu_stroke16 18.3422720 NA NA FALSE 1
233-
## 35 asu_stroke17 18.8504573 NA NA FALSE 1
234-
## 36 asu_other7 19.7390660 NA NA FALSE 1
235-
## 37 asu_stroke18 19.8417499 NA NA FALSE 1
236-
## 38 asu_stroke19 19.8820623 NA NA FALSE 1
198+
## $arrivals
199+
## name start_time end_time activity_time resource replication
200+
## 1 asu_stroke0 0.9062182 1.422308 0.5160899 asu_bed 1
201+
## 2 asu_other0 0.4473448 2.676165 2.2288198 asu_bed 1
202+
## 3 asu_neuro1 3.2678517 3.867813 0.5999612 asu_bed 1
203+
## 4 asu_neuro0 0.5245442 4.171772 3.6472278 asu_bed 1
204+
## 5 asu_stroke1 1.1893125 5.509324 4.3200113 asu_bed 1
205+
## 6 asu_other1 1.2902898 6.502389 5.2120987 asu_bed 1
206+
## 7 asu_other2 2.7220399 6.960086 4.2380463 asu_bed 1
207+
## 8 asu_stroke3 2.6540471 7.370079 4.7160317 asu_bed 1
208+
## 9 asu_neuro2 6.7174941 8.388190 1.6706957 asu_bed 1
209+
## 10 asu_other3 5.9118414 9.356139 3.4442981 asu_bed 1
210+
## 11 asu_other5 8.9680111 9.644429 0.6764179 asu_bed 1
211+
## 12 asu_other4 6.5630745 9.901922 3.3388479 asu_bed 1
212+
## 13 asu_stroke6 9.2809003 10.249020 0.9681194 asu_bed 1
213+
## 14 asu_stroke5 7.7291507 10.492783 2.7636327 asu_bed 1
214+
## 15 asu_stroke9 10.3331093 10.844631 0.5115214 asu_bed 1
215+
## 16 asu_stroke4 7.4047666 11.548437 4.1436706 asu_bed 1
216+
## 17 asu_tia0 10.9892778 12.129621 1.1403433 asu_bed 1
217+
## 18 asu_stroke2 1.9750085 12.640820 10.6658111 asu_bed 1
218+
## 19 asu_stroke7 9.9287833 13.332754 3.4039708 asu_bed 1
219+
## 20 asu_neuro3 10.6050662 14.143857 3.5387909 asu_bed 1
220+
## 21 asu_neuro5 13.7205915 15.051997 1.3314053 asu_bed 1
221+
## 22 asu_stroke12 13.9904583 15.084152 1.0936941 asu_bed 1
222+
## 23 asu_other6 13.8727452 15.859368 1.9866225 asu_bed 1
223+
## 24 asu_neuro4 13.5331919 16.712850 3.1796580 asu_bed 1
224+
## 25 asu_stroke10 13.6095765 16.845102 3.2355256 asu_bed 1
225+
## 26 asu_stroke7 13.3327542 18.114076 4.7813223 rehab_bed 1
226+
## 27 asu_stroke13 15.8908936 18.801468 2.9105743 asu_bed 1
227+
## 28 asu_stroke19 19.8820623 NA NA asu_bed 1
228+
## 29 asu_stroke18 19.8417499 NA NA asu_bed 1
229+
## 30 asu_stroke16 18.3422720 NA NA asu_bed 1
230+
## 31 asu_stroke15 18.1849052 NA NA asu_bed 1
231+
## 32 asu_stroke11 13.8532754 NA NA asu_bed 1
232+
## 33 asu_neuro4 13.5331919 NA NA asu_bed 1
233+
## 34 asu_neuro4 16.7128499 NA NA rehab_bed 1
234+
## 35 asu_stroke8 10.0363922 NA NA asu_bed 1
235+
## 36 asu_stroke14 17.1432238 NA NA asu_bed 1
236+
## 37 asu_neuro2 6.7174941 NA NA asu_bed 1
237+
## 38 asu_neuro2 8.3881898 NA NA rehab_bed 1
238+
## 39 asu_other7 19.7390660 NA NA asu_bed 1
239+
## 40 rehab_stroke0 9.5062960 NA NA rehab_bed 1
240+
## 41 asu_stroke17 18.8504573 NA NA asu_bed 1
241+
## 42 asu_neuro6 16.6529204 NA NA asu_bed 1
242+
## 43 rehab_stroke1 14.0813875 NA NA rehab_bed 1
243+
##
244+
## $occupancy
245+
## # A tibble: 42 × 3
246+
## resource time occupancy
247+
## <fct> <int> <int>
248+
## 1 asu_bed 0 0
249+
## 2 rehab_bed 0 0
250+
## 3 asu_bed 1 3
251+
## 4 rehab_bed 1 0
252+
## 5 asu_bed 2 5
253+
## 6 rehab_bed 2 0
254+
## 7 asu_bed 3 6
255+
## 8 rehab_bed 3 0
256+
## 9 asu_bed 4 6
257+
## 10 rehab_bed 4 0
258+
## # ℹ 32 more rows

0 commit comments

Comments
 (0)