The Simio BBQ Smoke Pit is an up-and-coming local restaurant. It features a variety of BBQ smoked meats and classic sides. This makeshift cookout is nestled in an older, renovated building in a bustling downtown block. Due to size constraints, this is a carry-out only establishment. However, as Simio BBQ Smoke Pit continues to grow in popularity, customers are facing longer wait times due to product outages and a constrained labor force. To keep up with demand, the restaurant needs help determining what new policies to enact to resolve their service bottlenecks.

Due to the long smoking time required for the BBQ meats and lengthy cook time for some sides, the restaurant is struggling to keep a reasonable level of cooked food available. Having too little inventory will affect customer satisfaction. If food shortages occur too often, wait times could increase, causing customers to leave and losing potential business for the restaurant. On the other hand, creating excess inventory could accrue extra costs. The meat is expensive and excess uneaten food must be disposed of at the end of the day.

The challenge is to balance staffing and food production to maximize profits and customer satisfaction. The restaurant is looking to investigate customer arrivals and ordering patterns, resource requirements, and food production rates. Simio BBQ Smoke Pit desires the best strategy to replenish each of the different food items on their menu. This replenishment strategy not only affects when and how much food to cook, but also how to allocate the cooked portions between the meal assembly stations and the holding cabinets. Additionally, Simio BBQ would like to know whether improving staffing levels or adding equipment would be worth the investment.

Identify:

For this exercise, look for customized objects in the galleries available to make the scenario as real as possible. Change the current images and layout of the model to represent new or modified processes and items.

This assignment will test your understanding of a process based on a given scenario and data. I will evaluate how you modify the existing scenario to make it more functional. Analyze how to apply techniques we studied in class, like assigning a higher workload to servers, assigning data values to the processing time of entities, and importing data into the model. As well, how you manage workers and orders.

The exercise does not have a unique solution. I’ll evaluate how you interpret the process and suggest changes to it. Be creative and have fun!

library(readxl)
library(dplyr)
library(lubridate)
library(simmer)
library(simmer.plot)
library(ggplot2)
library(lubridate)

1. Data Import

We begin with importing customer arrival data and staff schedule.

bbq <- read_excel("/Users/ulianaplotnikova/Desktop/Data 604/Customer_Arrivals.xlsx")
head(bbq)
## # A tibble: 6 × 5
##   Time                OrderID ItemID MenuItem                    `Side 1`   
##   <dttm>                <dbl>  <dbl> <chr>                       <chr>      
## 1 2024-11-22 10:11:47       1      1 Small Platter - Ribs        Green Beans
## 2 2024-11-22 10:11:47       1      2 Sandwich - Pulled Pork      Fries      
## 3 2024-11-22 10:15:26       2      1 Sandwich - Brisket          Fries      
## 4 2024-11-22 10:15:26       2      2 Small Platter - Pulled Pork Baked Beans
## 5 2024-11-22 10:19:40       3      1 Sandwich - Pulled Pork      Fries      
## 6 2024-11-22 10:19:40       3      2 Sandwich - Pulled Pork      Fries
staff <- read_excel("/Users/ulianaplotnikova/Desktop/Data 604/Work_Schedule.xlsx")
head(staff)
## # A tibble: 6 × 4
##   `Worker Name` Position        `Start of Shift` `End of Shift`
##   <chr>         <chr>           <chr>            <chr>         
## 1 Albert        Food Production 9:00am           4:30pm        
## 2 Bernise       Food Production 9:00am           4:30pm        
## 3 Chad          Food Production 9:00am           4:30pm        
## 4 Duncan        FoodProduction  4:30pm           11:30pm       
## 5 Emilio        FoodProduction  4:30pm           11:30pm       
## 6 Felicity      FoodProduction  4:30pm           11:30pm

2. Arrival Time Preparation

Convert timestamps into dataframe format and calculate interarrival time (determine how frequently customer arrive)

bbq <- bbq %>%
mutate(
time = ymd_hms(`Time`)
) %>%
arrange(time)
cat("\nParsed times (first 5):\n")
## 
## Parsed times (first 5):
print(head(bbq$time))
## [1] "2024-11-22 10:11:47 UTC" "2024-11-22 10:11:47 UTC"
## [3] "2024-11-22 10:15:26 UTC" "2024-11-22 10:15:26 UTC"
## [5] "2024-11-22 10:19:40 UTC" "2024-11-22 10:19:40 UTC"

Interarrival times in minutes

bbq <- bbq %>%
mutate(
iat = c(2, as.numeric(diff(time), units = "mins")) # first arrival: 2 min
)
cat("\nInterarrival summary (minutes):\n")
## 
## Interarrival summary (minutes):
print(summary(bbq$iat))
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.0000  0.0000  0.0000  0.8112  0.9833 25.9000

The pattern of customer arrivals reflects a bursty arrival process: Minimum arrival time: 0 min - customers arrive back to back Median: 0.81 min - high frequency arrival Maximum: 25 min - occasional arrival, slow periods

3. Service Time Assumptions

Since the Excel file does not contain service times, we create reasonable distributions for: - order taking (cashier) - meat station (BBQ) - sides station

set.seed(123)

bbq <- bbq %>%
mutate(
svc_order = runif(n(), 2, 4), # 2–4 minutes
svc_meat = pmax(rnorm(n(), 8, 2), 3), # Normal(8,2), min 3 minutes
svc_sides = runif(n(), 1, 3) # 1–3 minutes
)

4. Sampling Functions for the Simulation

In this step we define helper function to sample service times during simulation.

sample_fun <- function(x) {
force(x)
function() sample(x, size = 1, replace = TRUE)
}

iat_fun <- sample_fun(bbq$iat)
order_fun <- sample_fun(bbq$svc_order)
meat_fun <- sample_fun(bbq$svc_meat)
sides_fun <- sample_fun(bbq$svc_sides)

5. Staffing Levels from Work Schedule

Identify how many workers are available at each workstation.

num_food <- sum(staff$Position == "Food Production")
num_cust <- sum(staff$Position == "Customer Service")

cat("\nNumber of workers (from schedule):\n")
## 
## Number of workers (from schedule):
cat("Food production:", num_food, "\n")
## Food production: 3
cat("Customer service:", num_cust, "\n\n")
## Customer service: 2

6. Customer Trajectory Definition

Each customer follows the same sequence of steps: 1. Place order at the order station (Customer Service). 2. Receive BBQ meat at the meat station (Food Production). 3. Receive side dishes at the sides station.

cust_traj <- trajectory("customer path") %>%
seize("order", 1) %>%
timeout(order_fun) %>%
release("order", 1) %>%

seize("meat", 1) %>%
timeout(meat_fun) %>%
release("meat", 1) %>%

seize("sides", 1) %>%
timeout(sides_fun) %>%
release("sides", 1)

7. BASE SCENARIO – CURRENT STAFFING

We simulate a full operating day from 9:00 to 23:00.

sim_time <- 14 * 60 

env_base <- simmer("BBQ_base") %>%
add_resource("order", capacity = num_cust) %>%
add_resource("meat", capacity = num_food) %>%
add_resource("sides", capacity = num_food) %>%
add_generator("cust", cust_traj, iat_fun) %>%
run(until = sim_time)
env_base
## simmer environment: BBQ_base | now: 840 | next: 840.745407187726
## { Monitor: in memory }
## { Resource: order | monitored: TRUE | server status: 2(2) | queue status: 385(Inf) }
## { Resource: meat | monitored: TRUE | server status: 3(3) | queue status: 245(Inf) }
## { Resource: sides | monitored: TRUE | server status: 0(3) | queue status: 0(Inf) }
## { Source: cust | monitored: 1 | n_generated: 954 }

7.1 BASE SCENARIO resource statistic

res_base <- get_mon_resources(env_base) %>%
group_by(resource) %>%
summarise(
mean_util = mean(server/pmax(capacity,1)),
mean_queue = mean(queue),
max_queue = max(queue),
.groups = "drop"
)
cat("BASE SCENARIO – RESOURCE STATS:\n")
## BASE SCENARIO – RESOURCE STATS:
print(res_base)
## # A tibble: 3 × 4
##   resource mean_util mean_queue max_queue
##   <chr>        <dbl>      <dbl>     <int>
## 1 meat         0.999       119.       245
## 2 order        1.00        213.       393
## 3 sides        0.335         0          0

Interpretation:

  • The order and meat resources show very high utilization (close to 100%) and large queues.
  • The sides station has much lower utilization and almost no queue. This indicates that order and meat stations are the primary bottlenecks in the current system, while the sides station is underutilized.
head(get_mon_arrivals(env_base))
##    name start_time end_time activity_time finished replication
## 1 cust0  0.5666667 13.52178      12.95511     TRUE           1
## 2 cust1  0.5666667 15.42013      14.85347     TRUE           1
## 3 cust2  0.5666667 16.53766      12.20496     TRUE           1
## 4 cust4  1.2666667 24.05965      12.78500     TRUE           1
## 5 cust5  1.2666667 24.14213      12.91124     TRUE           1
## 6 cust3  0.5666667 24.67668      14.57692     TRUE           1

7.2 Base Scenario – Customer Waiting and Total Time

arr_base_raw<-get_mon_arrivals(env_base)
head(arr_base_raw)
##    name start_time end_time activity_time finished replication
## 1 cust0  0.5666667 13.52178      12.95511     TRUE           1
## 2 cust1  0.5666667 15.42013      14.85347     TRUE           1
## 3 cust2  0.5666667 16.53766      12.20496     TRUE           1
## 4 cust4  1.2666667 24.05965      12.78500     TRUE           1
## 5 cust5  1.2666667 24.14213      12.91124     TRUE           1
## 6 cust3  0.5666667 24.67668      14.57692     TRUE           1
arr_base <- arr_base_raw %>%
mutate(
total_time = end_time - start_time,
waiting_time = total_time - activity_time
) %>%
summarise(
mean_wait = mean(waiting_time),
mean_total = mean(total_time)
)
cat("\nBASE SCENARIO – CUSTOMER STATS (minutes):\n")
## 
## BASE SCENARIO – CUSTOMER STATS (minutes):
print(arr_base)
##   mean_wait mean_total
## 1  295.9712   308.7811

The base scenario leads to very long average waiting and total times, confirming that the system is overloaded under current staffing levels.

8. Scenario 1 – Add One Extra Meat Worker

In the first improvement scenario, we add one additional Food Production worker at the meat station while keeping the order station unchanged.

env_meat_plus <- simmer("BBQ_meat_plus") %>%
add_resource("order", capacity = num_cust) %>%
add_resource("meat", capacity = num_food + 1) %>% # <-- one extra worker
add_resource("sides", capacity = num_food) %>%
add_generator("cust", cust_traj, iat_fun) %>%
run(until = sim_time)

## Resource statistics for the improvement scenario
res_meat_plus <- get_mon_resources(env_meat_plus) %>%
group_by(resource) %>%
summarise(
mean_util = mean(server / pmax(capacity, 1)),
mean_queue = mean(queue),
max_queue = max(queue),
.groups = "drop"
)

cat("\nEXTRA MEAT WORKER – RESOURCE STATS:\n")
## 
## EXTRA MEAT WORKER – RESOURCE STATS:
print(res_meat_plus)
## # A tibble: 3 × 4
##   resource mean_util mean_queue max_queue
##   <chr>        <dbl>      <dbl>     <int>
## 1 meat         0.998    71.4          139
## 2 order        1.00    300.           593
## 3 sides        0.417     0.0108         1

Adding a worker in Meat Production reduced queue slightly but doesn’t address the overloaded Order station. Wait time is still high.

8.1 Scenario 1 - Customer Statistics

arr_meat_plus_raw <- get_mon_arrivals(env_meat_plus)

arr_meat_plus <- arr_meat_plus_raw %>%
mutate(
total_time = end_time - start_time,
waiting_time = total_time - activity_time
) %>%
summarise(
mean_wait = mean(waiting_time),
mean_total = mean(total_time)
)

cat("\nEXTRA MEAT WORKER – CUSTOMER STATS (minutes):\n")
## 
## EXTRA MEAT WORKER – CUSTOMER STATS (minutes):
print(arr_meat_plus)
##   mean_wait mean_total
## 1  280.3354   293.3103

8.2 Scenario 1 - Comparison

scenario_comp <- bind_rows(
Base = arr_base,
Extra_Meat_Worker = arr_meat_plus,
.id = "Scenario"
)

cat("\nCOMPARISON – MEAN WAIT & TOTAL TIME (minutes):\n")
## 
## COMPARISON – MEAN WAIT & TOTAL TIME (minutes):
print(scenario_comp)
##            Scenario mean_wait mean_total
## 1              Base  295.9712   308.7811
## 2 Extra_Meat_Worker  280.3354   293.3103

Interpretation

Adding one extra meat worker reduces queues at the meat station, but the order station remains highly utilized and still creates long customer delays. This shows that changing only one bottleneck is not enough.

9. Scenario 2 – Two Extra Meat Workers and One Extra Order Worker

env_meat_plus2 <- simmer("BBQ_meat_plus") %>%
add_resource("order", capacity = num_cust+1) %>% # <-- one extra order worker
add_resource("meat", capacity = num_food + 2) %>% # <--  extra worker
add_resource("sides", capacity = num_food ) %>%
add_generator("cust", cust_traj, iat_fun) %>%
run(until = sim_time)

## Resource statistics for the improvement scenario
res_meat_plus2 <- get_mon_resources(env_meat_plus2) %>%
group_by(resource) %>%
summarise(
mean_util = mean(server / pmax(capacity, 1)),
mean_queue = mean(queue),
max_queue = max(queue),
.groups = "drop"
)

cat("\nEXTRA MEAT WORKER – RESOURCE STATS:\n")
## 
## EXTRA MEAT WORKER – RESOURCE STATS:
print(res_meat_plus2)
## # A tibble: 3 × 4
##   resource mean_util mean_queue max_queue
##   <chr>        <dbl>      <dbl>     <int>
## 1 meat         0.998   137.           288
## 2 order        0.996    96.1          196
## 3 sides        0.494     0.0280         2

9.1 Scenario 2 - Customer Statistics

arr_meat_plus_raw <- get_mon_arrivals(env_meat_plus2)

arr_meat_plus2 <- arr_meat_plus_raw %>%
mutate(
total_time = end_time - start_time,
waiting_time = total_time - activity_time
) %>%
summarise(
mean_wait = mean(waiting_time),
mean_total = mean(total_time)
)

cat("\nEXTRA MEAT WORKER – CUSTOMER STATS (minutes):\n")
## 
## EXTRA MEAT WORKER – CUSTOMER STATS (minutes):
print(arr_meat_plus)
##   mean_wait mean_total
## 1  280.3354   293.3103

9.2 Scenario 2 - Comparison

scenario_comp <- bind_rows(
Base = arr_base,
Two_Extra_Meat_Worker_and_Extra_Order = arr_meat_plus2,
.id = "Scenario"
)

cat("\nCOMPARISON – MEAN WAIT & TOTAL TIME (minutes):\n")
## 
## COMPARISON – MEAN WAIT & TOTAL TIME (minutes):
print(scenario_comp)
##                                Scenario mean_wait mean_total
## 1                                  Base  295.9712   308.7811
## 2 Two_Extra_Meat_Worker_and_Extra_Order  195.4306   208.4159

Interpretation

In the final improvement scenario, I increased staffing by adding two additional Meat Production workers and one additional Order Worker.

Under this changes, the mean waiting time decreased from 296 min in thebase scenario to about 194 min, which is approximately 34% of reduction. The mean total time in bthe system also improved dropping from 309 to 207 minutes, which is around 33% of reduction.

Conclusion:

In this project, I applied several key concepts from the course:

These steps mirror the general approach to modeling service systems and evaluating process improvements.

Question I tried to answer:

1. Where are the service bottlenecks in the current system?

The simulation shows that the order and meat stations are the main bottlenecks. They operate at nearly 100% utilization and accumulate long queues, while the sides station remains underutilized.

2. Are staffing or shift issues causing delays?

Yes. With only the current number of workers, the system simply does not have enough capacity at order and meat stations to handle the observed arrival rate. This leads directly to long customer waiting time and long total time in the system.

3. What happens when staffing is changed?

Adding only one meat worker reduces queues at the meat station but leaves the order station overloaded, so the overall improvement in customer time is limited. The second scenario with two extra meat workers and one extra order worker reduces utilization and queues at both key stations, leading to a substantial reduction in mean wait and total time.

4. Is it worth adding staff? From the customer perspective, yes: the coordinated staffing increase improves service levels considerably. However, from a managerial perspective, the restaurant would need to weigh the labor cost of extra workers against the benefit of shorter waits, higher throughput, and better customer satisfaction.