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 simpy model 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:

  1. Request and if necessary wait for a call operator

  2. Undergo phone triage (a delay). This is a sample from the Triangular distribution.

  3. 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.353
operator answered call 1 at 0.353
call arrives at: 0.563
operator answered call 2 at 0.563
call arrives at: 0.818
operator answered call 3 at 0.818
call arrives at: 2.162
operator answered call 4 at 2.162
call arrives at: 2.605
operator answered call 5 at 2.605
call arrives at: 2.826
operator answered call 6 at 2.826
call arrives at: 2.841
operator answered call 7 at 2.841
call arrives at: 3.266
operator answered call 8 at 3.266
call arrives at: 4.287
operator answered call 9 at 4.287
call arrives at: 4.688
operator answered call 10 at 4.688
call arrives at: 5.008
operator answered call 11 at 5.008
call arrives at: 5.453
operator answered call 12 at 5.453
call arrives at: 5.573
operator answered call 13 at 5.573
call arrives at: 6.115
call 1 ended 6.436; waiting time was 0.000
operator answered call 14 at 6.436
call arrives at: 6.899
call arrives at: 6.978
call 2 ended 7.060; waiting time was 0.000
operator answered call 15 at 7.060
call arrives at: 7.674
call arrives at: 7.724
call 7 ended 8.295; waiting time was 0.000
operator answered call 16 at 8.295
call 3 ended 8.540; waiting time was 0.000
operator answered call 17 at 8.540
call 6 ended 8.561; waiting time was 0.000
operator answered call 18 at 8.561
call 5 ended 8.721; waiting time was 0.000
call 8 ended 9.559; waiting time was 0.000
call arrives at: 10.502
operator answered call 19 at 10.502
call 9 ended 10.807; waiting time was 0.000
call arrives at: 10.827
operator answered call 20 at 10.827
call 4 ended 11.167; waiting time was 0.000
call arrives at: 11.245
operator answered call 21 at 11.245
call arrives at: 11.303
operator answered call 22 at 11.303
call 10 ended 11.736; waiting time was 0.000
call arrives at: 11.925
operator answered call 23 at 11.925
call arrives at: 12.426
call 13 ended 12.817; waiting time was 0.000
operator answered call 24 at 12.817
call arrives at: 13.287
call 12 ended 13.479; waiting time was 0.000
operator answered call 25 at 13.479
call 14 ended 13.569; waiting time was 0.321
call arrives at: 13.725
operator answered call 26 at 13.725
call arrives at: 13.877
call arrives at: 14.482
call 15 ended 14.712; waiting time was 0.162
operator answered call 27 at 14.712
call arrives at: 14.723
call 17 ended 14.732; waiting time was 0.866
operator answered call 28 at 14.732
call arrives at: 14.740
call 11 ended 14.833; waiting time was 0.000
operator answered call 29 at 14.833
call arrives at: 15.025
call arrives at: 15.038
call arrives at: 15.442
call 16 ended 15.492; waiting time was 1.318
operator answered call 30 at 15.492
call 18 ended 15.835; waiting time was 0.837
operator answered call 31 at 15.835
call arrives at: 16.766
call arrives at: 16.916
call 19 ended 17.242; waiting time was 0.000
operator answered call 32 at 17.242
call arrives at: 17.373
call 20 ended 17.530; waiting time was 0.000
operator answered call 33 at 17.530
call arrives at: 18.093
call arrives at: 18.124
call arrives at: 18.365
call arrives at: 18.974
call arrives at: 19.176
call 24 ended 19.517; waiting time was 0.391
operator answered call 34 at 19.517
call 21 ended 19.715; waiting time was 0.000
operator answered call 35 at 19.715
call 22 ended 20.286; waiting time was 0.000
operator answered call 36 at 20.286
call 23 ended 20.325; waiting time was 0.000
operator answered call 37 at 20.325
call 25 ended 21.080; waiting time was 0.192
operator answered call 38 at 21.080
call 26 ended 21.187; waiting time was 0.000
operator answered call 39 at 21.187
call 27 ended 22.205; waiting time was 0.835
operator answered call 40 at 22.205
call 29 ended 22.294; waiting time was 0.110
operator answered call 41 at 22.294
call arrives at: 22.349
call arrives at: 22.353
call arrives at: 22.391
call 28 ended 22.746; waiting time was 0.250
operator answered call 42 at 22.746
call 30 ended 22.900; waiting time was 0.752
operator answered call 43 at 22.900
call arrives at: 23.513
call arrives at: 23.568
call 31 ended 23.655; waiting time was 0.810
operator answered call 44 at 23.655
call arrives at: 24.349
call 33 ended 24.426; waiting time was 2.088
operator answered call 45 at 24.426
call 32 ended 25.108; waiting time was 2.204
operator answered call 46 at 25.108
call arrives at: 25.114
call arrives at: 25.392
call arrives at: 25.738
call arrives at: 25.912
call arrives at: 26.583
call arrives at: 27.098
call 39 ended 27.446; waiting time was 2.822
operator answered call 47 at 27.446
call 37 ended 27.591; waiting time was 2.231
operator answered call 48 at 27.591
call 36 ended 27.756; waiting time was 2.914
operator answered call 49 at 27.756
call 38 ended 27.761; waiting time was 2.957
operator answered call 50 at 27.761
call 34 ended 28.041; waiting time was 2.751
operator answered call 51 at 28.041
call arrives at: 29.114
call 35 ended 29.404; waiting time was 2.799
operator answered call 52 at 29.404
call arrives at: 29.442
call arrives at: 30.013
call 46 ended 30.560; waiting time was 1.539
operator answered call 53 at 30.560
call arrives at: 30.629
call 40 ended 31.042; waiting time was 3.231
operator answered call 54 at 31.042
call 43 ended 31.046; waiting time was 0.547
operator answered call 55 at 31.046
call arrives at: 31.155
call arrives at: 31.349
call 44 ended 31.352; waiting time was 1.264
operator answered call 56 at 31.352
call 42 ended 31.450; waiting time was 0.396
operator answered call 57 at 31.450
call 41 ended 31.575; waiting time was 3.118
operator answered call 58 at 31.575
call 45 ended 31.654; waiting time was 0.913
operator answered call 59 at 31.654
call arrives at: 31.700
call arrives at: 32.724
call arrives at: 33.006
call arrives at: 33.563
call 48 ended 33.865; waiting time was 2.477
operator answered call 60 at 33.865
call 52 ended 34.633; waiting time was 2.821
operator answered call 61 at 34.633
call 50 ended 35.076; waiting time was 2.023
operator answered call 62 at 35.076
call arrives at: 35.384
call 49 ended 35.414; waiting time was 2.364
operator answered call 63 at 35.414
call 47 ended 35.887; waiting time was 3.097
operator answered call 64 at 35.887
call arrives at: 35.927
call arrives at: 35.958
call 51 ended 36.232; waiting time was 2.129
operator answered call 65 at 36.232
call arrives at: 36.530
call 55 ended 37.244; waiting time was 1.604
operator answered call 66 at 37.244
call arrives at: 37.579
call 59 ended 37.889; waiting time was 0.305
operator answered call 67 at 37.889
call 53 ended 38.059; waiting time was 3.462
operator answered call 68 at 38.059
call arrives at: 38.312
call 57 ended 38.422; waiting time was 0.822
operator answered call 69 at 38.422
call arrives at: 38.781
call arrives at: 38.847
call 56 ended 39.290; waiting time was 1.339
operator answered call 70 at 39.290
call arrives at: 39.365
call 58 ended 39.439; waiting time was 0.419
operator answered call 71 at 39.439
call arrives at: 39.713
call 54 ended 40.409; waiting time was 1.928
operator answered call 72 at 40.409
call 60 ended 40.766; waiting time was 2.164
operator answered call 73 at 40.766
call arrives at: 40.827
call arrives at: 41.911
call 62 ended 41.950; waiting time was 2.070
operator answered call 74 at 41.950
call 61 ended 42.030; waiting time was 1.909
operator answered call 75 at 42.030
call arrives at: 42.277
call arrives at: 42.425
call arrives at: 42.534
call arrives at: 42.692
call 65 ended 42.919; waiting time was 0.305
operator answered call 76 at 42.919
call 63 ended 43.275; waiting time was 1.851
operator answered call 77 at 43.275
call arrives at: 43.596
call arrives at: 43.667
call arrives at: 43.698
call 69 ended 43.958; waiting time was 0.110
operator answered call 78 at 43.958
call 64 ended 44.068; waiting time was 0.502
operator answered call 79 at 44.068
call arrives at: 44.632
call arrives at: 45.166
call 72 ended 45.899; waiting time was 1.044
operator answered call 80 at 45.899
call 66 ended 46.178; waiting time was 1.286
operator answered call 81 at 46.178
call 71 ended 46.884; waiting time was 0.592
operator answered call 82 at 46.884
call 68 ended 46.946; waiting time was 0.481
operator answered call 83 at 46.946
call 67 ended 47.097; waiting time was 1.359
operator answered call 84 at 47.097
call 73 ended 47.864; waiting time was 1.053
call 70 ended 47.925; waiting time was 0.509
call arrives at: 48.751
operator answered call 85 at 48.751
call 75 ended 48.808; waiting time was 0.119
call arrives at: 48.810
operator answered call 86 at 48.810
call arrives at: 48.829
operator answered call 87 at 48.829
call 74 ended 49.590; waiting time was 1.123
call arrives at: 49.700
operator answered call 88 at 49.700
call 79 ended 49.917; waiting time was 1.375
call arrives at: 50.229
operator answered call 89 at 50.229
call arrives at: 50.303
call arrives at: 50.574
call arrives at: 50.587
call arrives at: 50.597
call arrives at: 50.624
call arrives at: 50.656
call 76 ended 50.891; waiting time was 0.642
operator answered call 90 at 50.891
call arrives at: 51.075
call arrives at: 51.478
call 78 ended 51.581; waiting time was 1.423
operator answered call 91 at 51.581
call 80 ended 51.781; waiting time was 2.303
operator answered call 92 at 51.781
call arrives at: 51.870
call 81 ended 51.896; waiting time was 2.510
operator answered call 93 at 51.896
call 84 ended 52.591; waiting time was 1.931
operator answered call 94 at 52.591
call arrives at: 52.859
call 77 ended 53.073; waiting time was 0.850
operator answered call 95 at 53.073
call 83 ended 53.137; waiting time was 2.314
operator answered call 96 at 53.137
call arrives at: 53.406
call arrives at: 53.478
call arrives at: 54.162
call arrives at: 54.557
call 82 ended 54.617; waiting time was 3.186
operator answered call 97 at 54.617
call arrives at: 54.911
call arrives at: 55.219
call arrives at: 55.224
call 88 ended 55.423; waiting time was 0.000
operator answered call 98 at 55.423
call arrives at: 55.989
call arrives at: 56.019
call 86 ended 56.332; waiting time was 0.000
operator answered call 99 at 56.332
call 87 ended 56.341; waiting time was 0.000
operator answered call 100 at 56.341
call 89 ended 56.921; waiting time was 0.000
operator answered call 101 at 56.921
call 85 ended 56.982; waiting time was 0.000
operator answered call 102 at 56.982
call arrives at: 57.128
call arrives at: 57.660
call 92 ended 57.782; waiting time was 1.195
operator answered call 103 at 57.782
call 90 ended 58.046; waiting time was 0.588
operator answered call 104 at 58.046
call 94 ended 58.821; waiting time was 1.967
operator answered call 105 at 58.821
call arrives at: 59.501
call 91 ended 59.506; waiting time was 1.007
operator answered call 106 at 59.506
call 96 ended 60.114; waiting time was 2.062
operator answered call 107 at 60.114
call arrives at: 60.478
call 93 ended 60.670; waiting time was 1.299
operator answered call 108 at 60.670
call arrives at: 60.697
call arrives at: 61.057
call arrives at: 61.538
call 97 ended 61.608; waiting time was 3.139
operator answered call 109 at 61.608
call 95 ended 61.739; waiting time was 2.417
operator answered call 110 at 61.739
call arrives at: 61.740
call 98 ended 61.807; waiting time was 3.553
operator answered call 111 at 61.807
call arrives at: 62.556
call 100 ended 62.852; waiting time was 2.934
operator answered call 112 at 62.852
call arrives at: 63.862
call arrives at: 63.864
call arrives at: 64.037
call arrives at: 64.439
call 103 ended 64.771; waiting time was 3.225
operator answered call 113 at 64.771
call 102 ended 65.140; waiting time was 2.820
operator answered call 114 at 65.140
call 101 ended 65.524; waiting time was 3.443
operator answered call 115 at 65.524
call 106 ended 65.583; waiting time was 4.281
operator answered call 116 at 65.583
call arrives at: 65.617
call 104 ended 65.657; waiting time was 3.135
operator answered call 117 at 65.657
call 105 ended 66.033; waiting time was 3.602
operator answered call 118 at 66.033
call 99 ended 66.243; waiting time was 3.474
operator answered call 119 at 66.243
call 108 ended 66.735; waiting time was 4.651
operator answered call 120 at 66.735
call 107 ended 67.467; waiting time was 4.126
operator answered call 121 at 67.467
call arrives at: 67.577
call arrives at: 68.133
call arrives at: 68.295
call arrives at: 68.748
call arrives at: 68.870
call 110 ended 69.092; waiting time was 4.080
operator answered call 122 at 69.092
call 111 ended 69.107; waiting time was 2.305
operator answered call 123 at 69.107
call arrives at: 69.450
call arrives at: 69.948
call 112 ended 69.955; waiting time was 2.374
operator answered call 124 at 69.955
call 109 ended 70.173; waiting time was 4.480
operator answered call 125 at 70.173
call arrives at: 70.219
call 114 ended 70.702; waiting time was 4.083
operator answered call 126 at 70.702
call arrives at: 70.977
call arrives at: 72.263
call 116 ended 72.566; waiting time was 3.843
operator answered call 127 at 72.566
call 113 ended 72.660; waiting time was 4.074
operator answered call 128 at 72.660
call 119 ended 72.727; waiting time was 2.379
operator answered call 129 at 72.727
call 117 ended 73.009; waiting time was 3.101
operator answered call 130 at 73.009
call 115 ended 73.298; waiting time was 3.986
operator answered call 131 at 73.298
call arrives at: 73.441
call 121 ended 74.212; waiting time was 3.028
operator answered call 132 at 74.212
call 120 ended 75.298; waiting time was 2.698
operator answered call 133 at 75.298
call 118 ended 75.327; waiting time was 2.171
call arrives at: 76.069
operator answered call 134 at 76.069
call arrives at: 76.086
call arrives at: 76.870
call arrives at: 76.957
call 125 ended 77.219; waiting time was 1.878
operator answered call 135 at 77.219
call 123 ended 77.247; waiting time was 1.530
operator answered call 136 at 77.247
call 122 ended 77.307; waiting time was 3.475
operator answered call 137 at 77.307
call 124 ended 77.328; waiting time was 1.822
call 126 ended 78.097; waiting time was 1.954
call 127 ended 78.229; waiting time was 3.696
call arrives at: 78.296
operator answered call 138 at 78.296
call arrives at: 78.534
operator answered call 139 at 78.534
call 130 ended 79.157; waiting time was 2.790
call arrives at: 79.185
operator answered call 140 at 79.185
call arrives at: 79.201
operator answered call 141 at 79.201
call arrives at: 79.663
call 131 ended 80.250; waiting time was 2.320
operator answered call 142 at 80.250
call arrives at: 80.263
call 129 ended 81.060; waiting time was 2.780
operator answered call 143 at 81.060
call 133 ended 81.534; waiting time was 1.858
call 132 ended 81.596; waiting time was 1.949
call arrives at: 81.782
operator answered call 144 at 81.782
call 128 ended 81.848; waiting time was 3.209
call arrives at: 81.874
operator answered call 145 at 81.874
call arrives at: 82.625
operator answered call 146 at 82.625
call 134 ended 82.697; waiting time was 0.000
call arrives at: 82.957
operator answered call 147 at 82.957
call arrives at: 83.006
call 136 ended 84.760; waiting time was 0.377
operator answered call 148 at 84.760
call arrives at: 84.836
call 138 ended 85.090; waiting time was 0.000
operator answered call 149 at 85.090
call 140 ended 85.393; waiting time was 0.000
call 139 ended 85.630; waiting time was 0.000
call 137 ended 85.947; waiting time was 0.350
call arrives at: 86.295
operator answered call 150 at 86.295
call 135 ended 86.365; waiting time was 1.132
call 141 ended 86.530; waiting time was 0.000
call 145 ended 87.815; waiting time was 0.000
call arrives at: 87.852
operator answered call 151 at 87.852
call arrives at: 87.875
operator answered call 152 at 87.875
call arrives at: 88.270
operator answered call 153 at 88.270
call arrives at: 88.773
operator answered call 154 at 88.773
call 147 ended 89.211; waiting time was 0.000
call 144 ended 89.233; waiting time was 0.000
call 142 ended 89.248; waiting time was 0.587
call arrives at: 89.865
operator answered call 155 at 89.865
call arrives at: 89.962
operator answered call 156 at 89.962
call 143 ended 90.239; waiting time was 0.797
call 146 ended 90.393; waiting time was 0.000
call arrives at: 90.580
operator answered call 157 at 90.580
call arrives at: 90.947
operator answered call 158 at 90.947
call arrives at: 91.893
operator answered call 159 at 91.893
call arrives at: 92.071
operator answered call 160 at 92.071
call 149 ended 92.593; waiting time was 0.254
call 148 ended 92.612; waiting time was 1.754
call arrives at: 92.651
operator answered call 161 at 92.651
call 150 ended 93.366; waiting time was 0.000
call arrives at: 94.296
operator answered call 162 at 94.296
call 151 ended 94.972; waiting time was 0.000
call arrives at: 95.339
operator answered call 163 at 95.339
call 156 ended 95.660; waiting time was 0.000
call 152 ended 95.769; waiting time was 0.000
call arrives at: 95.893
operator answered call 164 at 95.893
call 153 ended 96.571; waiting time was 0.000
call 157 ended 96.651; waiting time was 0.000
call 154 ended 96.895; waiting time was 0.000
call 158 ended 97.407; waiting time was 0.000
call arrives at: 97.494
operator answered call 165 at 97.494
call arrives at: 97.581
operator answered call 166 at 97.581
call arrives at: 97.691
operator answered call 167 at 97.691
call 155 ended 98.448; waiting time was 0.000
call 159 ended 98.651; waiting time was 0.000
call 161 ended 98.814; waiting time was 0.000
call arrives at: 99.144
operator answered call 168 at 99.144
call 160 ended 99.484; waiting time was 0.000
end of run. simulation clock time = 100