A full model#
We will now build a full simpy process model. In this example we will build a 111 call centre queuing model. We will include random arrivals and resources. We will keep this simple, and gradually add in detail and flexibility to our design.
1. Imports#
import simpy
import numpy as np
import itertools
2. Problem background#
Call operators in an 111 (urgent care) service receive calls at a rate of 100 per hour. Call length can be represented by a triangular distribution. Calls last between 5 minutes and 15 minutes. Most calls last 7 minutes. There are 13 call operators.
We will build a
simpymodel of the process.
3. simpy resources#
To model the call centre we need to introduce a resource. If a resource is not available then a process will pause. We create a resource as follows:
operators = simpy.Resource(env, capacity=20)
When we want to request a resource in our process we create a with block as follows:
with operators.request() as req:
yield req
This tells simpy that your process needs an operator resource to progress. The code will pause until a resource is yielded. This gives us our queuing effect. If a resource is not available immediately then the process will wait until one becomes available. We will practice this a lot in the course so do not worry if this does not make sense immediately.
4. The service function.#
We will first build the service function. We need to do this because our arrival/generator function will be required to call it.
We need to include the following logic:
Request and if necessary wait for a call operator
Undergo phone triage (a delay). This is a sample from the Triangular distribution.
Exit the system.
We will build this as a simple python function that we will call service. Each patient caller that arrives to the simulation will execute service as a simpy process. We will pass a unique patient identifier, a pool of operator resources and the environment to the function.
def service(identifier, operators, env):
'''
simulates the service process for a call operator
1. request and wait for a call operator
2. phone triage (triangular)
3. exit system
Params:
------
identifier: int
A unique identifer for this caller
operators: simpy.Resource
The pool of call operators that answer calls
These are shared across resources.
env: simpy.Environment
The current environent the simulation is running in
We use this to pause and restart the process after a delay.
'''
# record the time that call entered the queue
start_wait = env.now
# request an operator
with operators.request() as req:
yield req
# record the waiting time for call to be answered
waiting_time = env.now - start_wait
print(f'operator answered call {identifier} at ' \
+ f'{env.now:.3f}')
# sample call duration.
call_duration = np.random.triangular(left=5.0, mode=7.0,
right=10.0)
# schedule process to begin again after call_duration
yield env.timeout(call_duration)
# print out information for patient.
print(f'call {identifier} ended {env.now:.3f}; ' \
+ f'waiting time was {waiting_time:.3f}')
5. The generator function.#
The generator function is very similar to the pharamacy example. In fact you can just cut, paste and modify.
def arrivals_generator(env, operators):
'''
IAT is exponentially distributed
Parameters:
------
env: simpy.Environment
The simpy environment for the simulation
operators: simpy.Resource
the pool of call operators.
'''
# use itertools as it provides an infinite loop
# with a counter variable that we can use for unique Ids
for caller_count in itertools.count(start=1):
# 100 calls per hour (units = hours).
# Time between calls is 1/100
inter_arrival_time = np.random.exponential(60/100)
yield env.timeout(inter_arrival_time)
print(f'call arrives at: {env.now:.3f}')
# create a new simpy process for this caller.
# we pass in the caller id, the operator resources, and env.
env.process(service(caller_count, operators, env))
6. Run the model#
# model parameters
RUN_LENGTH = 100
N_OPERATORS = 13
# create simpy environment and operator resources
env = simpy.Environment()
operators = simpy.Resource(env, capacity=N_OPERATORS)
env.process(arrivals_generator(env, operators))
env.run(until=RUN_LENGTH)
print(f'end of run. simulation clock time = {env.now}')
call arrives at: 0.110
operator answered call 1 at 0.110
call arrives at: 0.152
operator answered call 2 at 0.152
call arrives at: 0.475
operator answered call 3 at 0.475
call arrives at: 2.611
operator answered call 4 at 2.611
call arrives at: 2.667
operator answered call 5 at 2.667
call arrives at: 2.979
operator answered call 6 at 2.979
call arrives at: 4.775
operator answered call 7 at 4.775
call arrives at: 5.075
operator answered call 8 at 5.075
call arrives at: 5.640
operator answered call 9 at 5.640
call arrives at: 6.196
operator answered call 10 at 6.196
call 1 ended 6.583; waiting time was 0.000
call arrives at: 6.813
operator answered call 11 at 6.813
call 2 ended 7.099; waiting time was 0.000
call 3 ended 7.392; waiting time was 0.000
call arrives at: 7.882
operator answered call 12 at 7.882
call arrives at: 8.288
operator answered call 13 at 8.288
call 4 ended 8.305; waiting time was 0.000
call arrives at: 8.633
operator answered call 14 at 8.633
call arrives at: 8.912
operator answered call 15 at 8.912
call arrives at: 9.710
operator answered call 16 at 9.710
call arrives at: 10.121
operator answered call 17 at 10.121
call 5 ended 10.899; waiting time was 0.000
call 7 ended 11.246; waiting time was 0.000
call arrives at: 11.387
operator answered call 18 at 11.387
call 8 ended 11.477; waiting time was 0.000
call 6 ended 11.788; waiting time was 0.000
call arrives at: 11.931
operator answered call 19 at 11.931
call 11 ended 12.391; waiting time was 0.000
call 9 ended 12.413; waiting time was 0.000
call 10 ended 12.672; waiting time was 0.000
call arrives at: 13.947
operator answered call 20 at 13.947
call arrives at: 14.278
operator answered call 21 at 14.278
call arrives at: 14.451
operator answered call 22 at 14.451
call arrives at: 15.307
operator answered call 23 at 15.307
call 13 ended 15.372; waiting time was 0.000
call arrives at: 15.484
operator answered call 24 at 15.484
call 15 ended 16.091; waiting time was 0.000
call 12 ended 16.468; waiting time was 0.000
call arrives at: 16.498
operator answered call 25 at 16.498
call 14 ended 16.678; waiting time was 0.000
call arrives at: 16.956
operator answered call 26 at 16.956
call 16 ended 17.183; waiting time was 0.000
call arrives at: 17.571
operator answered call 27 at 17.571
call arrives at: 17.763
operator answered call 28 at 17.763
call arrives at: 17.802
operator answered call 29 at 17.802
call arrives at: 18.064
call 19 ended 18.128; waiting time was 0.000
operator answered call 30 at 18.128
call 17 ended 18.296; waiting time was 0.000
call arrives at: 18.650
operator answered call 31 at 18.650
call 18 ended 18.680; waiting time was 0.000
call 20 ended 19.987; waiting time was 0.000
call arrives at: 20.304
operator answered call 32 at 20.304
call arrives at: 20.487
operator answered call 33 at 20.487
call 24 ended 21.420; waiting time was 0.000
call 23 ended 21.584; waiting time was 0.000
call arrives at: 21.846
operator answered call 34 at 21.846
call arrives at: 21.948
operator answered call 35 at 21.948
call 21 ended 22.471; waiting time was 0.000
call arrives at: 22.609
operator answered call 36 at 22.609
call 25 ended 22.849; waiting time was 0.000
call 22 ended 23.408; waiting time was 0.000
call arrives at: 23.420
operator answered call 37 at 23.420
call 30 ended 23.854; waiting time was 0.063
call 27 ended 23.907; waiting time was 0.000
call 31 ended 24.143; waiting time was 0.000
call 29 ended 24.447; waiting time was 0.000
call arrives at: 24.532
operator answered call 38 at 24.532
call arrives at: 24.760
operator answered call 39 at 24.760
call 26 ended 24.812; waiting time was 0.000
call 28 ended 25.106; waiting time was 0.000
call arrives at: 25.535
operator answered call 40 at 25.535
call arrives at: 27.140
operator answered call 41 at 27.140
call 32 ended 27.739; waiting time was 0.000
call arrives at: 27.763
operator answered call 42 at 27.763
call 34 ended 28.392; waiting time was 0.000
call 33 ended 28.551; waiting time was 0.000
call 35 ended 28.847; waiting time was 0.000
call arrives at: 28.970
operator answered call 43 at 28.970
call arrives at: 29.150
operator answered call 44 at 29.150
call arrives at: 29.190
operator answered call 45 at 29.190
call 37 ended 29.391; waiting time was 0.000
call arrives at: 29.611
operator answered call 46 at 29.611
call arrives at: 29.917
operator answered call 47 at 29.917
call 36 ended 30.414; waiting time was 0.000
call 38 ended 30.829; waiting time was 0.000
call arrives at: 31.122
operator answered call 48 at 31.122
call 40 ended 31.488; waiting time was 0.000
call arrives at: 32.469
operator answered call 49 at 32.469
call arrives at: 33.205
operator answered call 50 at 33.205
call 42 ended 33.849; waiting time was 0.000
call 39 ended 33.893; waiting time was 0.000
call arrives at: 34.272
operator answered call 51 at 34.272
call 44 ended 34.443; waiting time was 0.000
call arrives at: 34.982
operator answered call 52 at 34.982
call 41 ended 35.043; waiting time was 0.000
call arrives at: 35.349
operator answered call 53 at 35.349
call 47 ended 35.973; waiting time was 0.000
call arrives at: 36.096
operator answered call 54 at 36.096
call 43 ended 36.462; waiting time was 0.000
call arrives at: 36.694
operator answered call 55 at 36.694
call 46 ended 36.821; waiting time was 0.000
call arrives at: 37.158
operator answered call 56 at 37.158
call arrives at: 37.315
operator answered call 57 at 37.315
call arrives at: 37.367
operator answered call 58 at 37.367
call 48 ended 37.455; waiting time was 0.000
call 45 ended 37.569; waiting time was 0.000
call arrives at: 38.130
operator answered call 59 at 38.130
call arrives at: 38.397
operator answered call 60 at 38.397
call arrives at: 38.760
operator answered call 61 at 38.760
call arrives at: 38.793
call 49 ended 38.984; waiting time was 0.000
operator answered call 62 at 38.984
call arrives at: 39.126
call arrives at: 39.561
call arrives at: 40.269
call arrives at: 41.075
call 51 ended 41.508; waiting time was 0.000
operator answered call 63 at 41.508
call 52 ended 41.667; waiting time was 0.000
operator answered call 64 at 41.667
call 50 ended 41.971; waiting time was 0.000
operator answered call 65 at 41.971
call arrives at: 42.519
call 58 ended 42.873; waiting time was 0.000
operator answered call 66 at 42.873
call 57 ended 43.012; waiting time was 0.000
operator answered call 67 at 43.012
call arrives at: 43.059
call 56 ended 43.737; waiting time was 0.000
operator answered call 68 at 43.737
call 53 ended 43.837; waiting time was 0.000
call 54 ended 43.840; waiting time was 0.000
call 60 ended 44.772; waiting time was 0.000
call arrives at: 45.005
operator answered call 69 at 45.005
call arrives at: 45.322
operator answered call 70 at 45.322
call 59 ended 45.573; waiting time was 0.000
call arrives at: 45.645
operator answered call 71 at 45.645
call arrives at: 45.658
operator answered call 72 at 45.658
call 55 ended 45.667; waiting time was 0.000
call arrives at: 45.691
operator answered call 73 at 45.691
call arrives at: 46.306
call 62 ended 46.623; waiting time was 0.191
operator answered call 74 at 46.623
call 61 ended 46.663; waiting time was 0.000
call arrives at: 47.828
operator answered call 75 at 47.828
call arrives at: 47.873
call arrives at: 48.138
call arrives at: 48.256
call 64 ended 48.995; waiting time was 2.106
operator answered call 76 at 48.995
call 66 ended 49.193; waiting time was 1.798
operator answered call 77 at 49.193
call arrives at: 49.221
call arrives at: 49.672
call 65 ended 50.212; waiting time was 1.703
operator answered call 78 at 50.212
call 68 ended 50.505; waiting time was 0.678
operator answered call 79 at 50.505
call 67 ended 50.830; waiting time was 0.493
operator answered call 80 at 50.830
call 63 ended 50.925; waiting time was 2.382
call 70 ended 50.947; waiting time was 0.000
call 73 ended 51.100; waiting time was 0.000
call 69 ended 51.289; waiting time was 0.000
call arrives at: 51.804
operator answered call 81 at 51.804
call arrives at: 51.806
operator answered call 82 at 51.806
call arrives at: 52.104
operator answered call 83 at 52.104
call 71 ended 52.259; waiting time was 0.000
call arrives at: 52.608
operator answered call 84 at 52.608
call 72 ended 52.619; waiting time was 0.000
call 74 ended 53.703; waiting time was 0.317
call arrives at: 54.768
operator answered call 85 at 54.768
call 76 ended 54.917; waiting time was 1.123
call arrives at: 54.971
operator answered call 86 at 54.971
call arrives at: 55.237
operator answered call 87 at 55.237
call arrives at: 55.374
operator answered call 88 at 55.374
call arrives at: 56.063
call arrives at: 56.366
call 77 ended 56.816; waiting time was 1.055
operator answered call 89 at 56.816
call arrives at: 57.290
call 75 ended 57.316; waiting time was 0.000
operator answered call 90 at 57.316
call 78 ended 57.505; waiting time was 1.956
operator answered call 91 at 57.505
call arrives at: 57.868
call 79 ended 57.915; waiting time was 1.284
operator answered call 92 at 57.915
call 80 ended 58.115; waiting time was 1.157
call 81 ended 58.314; waiting time was 0.000
call 84 ended 58.948; waiting time was 0.000
call 82 ended 59.116; waiting time was 0.000
call arrives at: 59.486
operator answered call 93 at 59.486
call arrives at: 59.833
operator answered call 94 at 59.833
call 83 ended 60.138; waiting time was 0.000
call 85 ended 60.199; waiting time was 0.000
call 87 ended 61.280; waiting time was 0.000
call arrives at: 61.703
operator answered call 95 at 61.703
call arrives at: 61.983
operator answered call 96 at 61.983
call 86 ended 63.478; waiting time was 0.000
call 88 ended 63.523; waiting time was 0.000
call 89 ended 63.825; waiting time was 0.752
call arrives at: 63.914
operator answered call 97 at 63.914
call arrives at: 64.134
operator answered call 98 at 64.134
call 91 ended 64.411; waiting time was 0.215
call 90 ended 64.900; waiting time was 0.950
call arrives at: 65.756
operator answered call 99 at 65.756
call arrives at: 65.818
operator answered call 100 at 65.818
call 92 ended 66.331; waiting time was 0.047
call arrives at: 67.195
operator answered call 101 at 67.195
call 94 ended 67.555; waiting time was 0.000
call arrives at: 67.916
operator answered call 102 at 67.916
call 93 ended 68.739; waiting time was 0.000
call arrives at: 69.110
operator answered call 103 at 69.110
call 95 ended 69.145; waiting time was 0.000
call 96 ended 69.675; waiting time was 0.000
call arrives at: 70.208
operator answered call 104 at 70.208
call arrives at: 70.564
operator answered call 105 at 70.564
call arrives at: 70.619
operator answered call 106 at 70.619
call 97 ended 70.929; waiting time was 0.000
call arrives at: 70.957
operator answered call 107 at 70.957
call arrives at: 70.998
operator answered call 108 at 70.998
call arrives at: 71.191
operator answered call 109 at 71.191
call arrives at: 72.073
operator answered call 110 at 72.073
call arrives at: 72.167
call arrives at: 72.182
call 99 ended 72.794; waiting time was 0.000
operator answered call 111 at 72.794
call arrives at: 72.987
call arrives at: 73.056
call 98 ended 73.155; waiting time was 0.000
operator answered call 112 at 73.155
call arrives at: 73.550
call arrives at: 73.631
call 100 ended 73.929; waiting time was 0.000
operator answered call 113 at 73.929
call arrives at: 74.159
call arrives at: 75.167
call arrives at: 75.224
call arrives at: 75.309
call arrives at: 75.320
call 102 ended 75.536; waiting time was 0.000
operator answered call 114 at 75.536
call arrives at: 75.657
call 103 ended 75.694; waiting time was 0.000
operator answered call 115 at 75.694
call 101 ended 75.919; waiting time was 0.000
operator answered call 116 at 75.919
call arrives at: 76.087
call arrives at: 76.302
call 105 ended 77.033; waiting time was 0.000
operator answered call 117 at 77.033
call arrives at: 77.523
call 106 ended 77.946; waiting time was 0.000
operator answered call 118 at 77.946
call 107 ended 78.349; waiting time was 0.000
operator answered call 119 at 78.349
call arrives at: 78.840
call 104 ended 79.079; waiting time was 0.000
operator answered call 120 at 79.079
call 108 ended 79.183; waiting time was 0.000
operator answered call 121 at 79.183
call arrives at: 79.650
call 109 ended 79.739; waiting time was 0.000
operator answered call 122 at 79.739
call 110 ended 79.827; waiting time was 0.000
operator answered call 123 at 79.827
call arrives at: 79.902
call arrives at: 80.075
call 111 ended 80.403; waiting time was 0.627
operator answered call 124 at 80.403
call arrives at: 80.852
call arrives at: 81.271
call 113 ended 82.182; waiting time was 0.942
operator answered call 125 at 82.182
call 112 ended 82.235; waiting time was 0.973
operator answered call 126 at 82.235
call 114 ended 82.493; waiting time was 2.480
operator answered call 127 at 82.493
call arrives at: 82.652
call 116 ended 82.921; waiting time was 2.288
operator answered call 128 at 82.921
call arrives at: 83.699
call arrives at: 83.781
call 115 ended 83.982; waiting time was 2.144
operator answered call 129 at 83.982
call arrives at: 83.991
call arrives at: 84.611
call arrives at: 84.803
call 119 ended 84.899; waiting time was 3.126
operator answered call 130 at 84.899
call arrives at: 85.208
call 118 ended 85.284; waiting time was 2.779
operator answered call 131 at 85.284
call arrives at: 85.606
call 117 ended 86.471; waiting time was 2.875
operator answered call 132 at 86.471
call arrives at: 86.556
call arrives at: 86.745
call 122 ended 86.891; waiting time was 4.082
operator answered call 133 at 86.891
call 121 ended 86.893; waiting time was 3.863
operator answered call 134 at 86.893
call arrives at: 87.223
call 120 ended 87.556; waiting time was 3.770
operator answered call 135 at 87.556
call 126 ended 88.296; waiting time was 3.396
operator answered call 136 at 88.296
call arrives at: 88.665
call 123 ended 89.056; waiting time was 3.740
operator answered call 137 at 89.056
call arrives at: 89.090
call 125 ended 89.232; waiting time was 4.659
operator answered call 138 at 89.232
call arrives at: 89.263
call arrives at: 89.346
call arrives at: 89.479
call arrives at: 89.680
call arrives at: 90.046
call 124 ended 90.109; waiting time was 4.101
operator answered call 139 at 90.109
call 129 ended 90.386; waiting time was 3.906
operator answered call 140 at 90.386
call arrives at: 90.590
call 130 ended 90.609; waiting time was 4.047
operator answered call 141 at 90.609
call 127 ended 90.614; waiting time was 2.843
operator answered call 142 at 90.614
call arrives at: 90.722
call arrives at: 91.379
call 128 ended 91.590; waiting time was 3.019
operator answered call 143 at 91.590
call arrives at: 91.726
call arrives at: 91.794
call 131 ended 92.211; waiting time was 4.013
operator answered call 144 at 92.211
call arrives at: 93.092
call arrives at: 93.497
call 134 ended 93.762; waiting time was 3.112
operator answered call 145 at 93.762
call arrives at: 93.868
call 132 ended 94.005; waiting time was 3.819
operator answered call 146 at 94.005
call 133 ended 94.256; waiting time was 3.191
operator answered call 147 at 94.256
call 137 ended 94.472; waiting time was 4.253
operator answered call 148 at 94.472
call arrives at: 94.720
call arrives at: 94.815
call 136 ended 95.252; waiting time was 3.685
operator answered call 149 at 95.252
call arrives at: 95.336
call 138 ended 95.663; waiting time was 4.024
operator answered call 150 at 95.663
call 135 ended 95.703; waiting time was 3.565
operator answered call 151 at 95.703
call arrives at: 96.469
call 139 ended 97.079; waiting time was 4.503
operator answered call 152 at 97.079
call 142 ended 97.689; waiting time was 3.391
operator answered call 153 at 97.689
call 141 ended 97.965; waiting time was 3.864
operator answered call 154 at 97.965
call 140 ended 98.617; waiting time was 3.830
operator answered call 155 at 98.617
call 143 ended 98.776; waiting time was 2.925
operator answered call 156 at 98.776
call arrives at: 99.300
call arrives at: 99.745
call 147 ended 99.888; waiting time was 4.777
operator answered call 157 at 99.888
end of run. simulation clock time = 100