|
49 | 49 | "id": "968d7a3d-763d-48a0-9915-421631d1f650", |
50 | 50 | "metadata": {}, |
51 | 51 | "source": [ |
52 | | - "## 3. An example: a hospital pharmacy\n", |
| 52 | + "# 3. An example: a urgent care call sample\n", |
53 | 53 | "\n", |
54 | | - "In this first example, let's assume (unrealistically) that prescriptions arrive **exactly** 5 minutes apart.\n", |
55 | | - "\n", |
56 | | - "\n", |
| 54 | + "This case study uses a simple model of an urgent care telephone call centre, similar to the NHS 111 service in the UK. To learn `simpy` we will first build a very simple model. In our first iteration of this model, calls to the centre arrive **deterministically**. For now we will ignore resources and activities in the model and just model a deterministic arrival process. The simulation time units are in minutes. Let's assume there are 60 new callers per hour (an fixed inter-arrival time of 1.0 per minute).\n", |
57 | 55 | "\n", |
58 | 56 | "## 4. The model building blocks\n", |
59 | 57 | "\n", |
|
72 | 70 | "We can introduce **delays** or **activities** into a process. For example these might be the duration of a stay on a ward, or the duration of a operation - or, in this case, a **delay between arrivals (inter-arrival time)**. In `simpy` you control this with the following method:\n", |
73 | 71 | "\n", |
74 | 72 | "```python\n", |
75 | | - "env.timeout(5.0)\n", |
| 73 | + "env.timeout(1.0)\n", |
76 | 74 | "```\n", |
77 | 75 | "\n", |
78 | 76 | "### 4.3 Generators\n", |
79 | 77 | "\n", |
80 | 78 | "The events in the DES are modelled and scheduled in `simpy` using python **generators** (i.e. they are the \"event-processing mechanism\"). A generator is a function that behaves like an iterator, meaning it can yield a **sequence of values** when iterated over.\n", |
81 | 79 | "\n", |
82 | | - "For example, below is a basic generator function that yields a new arrival every 5 minutes. It takes the **environment** as a parameter. It then internally calls the `env.timeout()` method in an infinite loop.\n", |
| 80 | + "For example, below is a basic generator function that yields a new arrival every 1 minute. It takes the **environment** as a parameter. It then internally calls the `env.timeout()` method in an infinite loop.\n", |
83 | 81 | "\n", |
84 | 82 | "```python\n", |
85 | | - "def prescription_arrival_generator(env):\n", |
| 83 | + "def arrivals_generator(env):\n", |
86 | 84 | " while True:\n", |
87 | | - " yield env.timeout(5.0)\n", |
| 85 | + " yield env.timeout(1.0)\n", |
88 | 86 | "```\n", |
89 | 87 | "\n", |
90 | 88 | "### 4.4 SimPy process and run\n", |
|
94 | 92 | "1. Set the generator up as a **SimPy process** using `env.process()`\n", |
95 | 93 | "\n", |
96 | 94 | "```python\n", |
97 | | - "env.process(prescription_arrival_generator(env))\n", |
| 95 | + "env.process(arrivals_generator(env))\n", |
98 | 96 | "```\n", |
99 | 97 | "\n", |
100 | 98 | "2. Run the environment for a user specified **run length** using `env.run()`\n", |
|
103 | 101 | "env.run(until=25)\n", |
104 | 102 | "```\n", |
105 | 103 | "\n", |
106 | | - "The run method handle the infinite loop we set up in `prescription_arrival_generator`. The simulation model has an internal concept of time. It will end execution when its internal clock reaches 25 time units.\n", |
| 104 | + "The run method handle the infinite loop we set up in `arrivals_generator`. The simulation model has an internal concept of time. It will end execution when its internal clock reaches 25 time units.\n", |
107 | 105 | "\n", |
108 | 106 | "## 5. Create the model\n", |
109 | 107 | "\n", |
110 | | - "**Now that we have covered the basic building blocks, let's code the actual model.** It makes sense to create our model logic first. The code below will generate arrivals every 5 minutes. Note that the function takes an environment object as a parameter." |
| 108 | + "**Now that we have covered the basic building blocks, let's code the actual model.** It makes sense to create our model logic first. The code below will generate arrivals every 60.0 / 100.0 minutes. Note that the function takes an environment object as a parameter." |
111 | 109 | ] |
112 | 110 | }, |
113 | 111 | { |
114 | 112 | "cell_type": "code", |
115 | | - "execution_count": 2, |
| 113 | + "execution_count": 22, |
116 | 114 | "id": "a6fd524c-7dc4-41c0-876d-3507ce480dfb", |
117 | 115 | "metadata": {}, |
118 | 116 | "outputs": [], |
119 | 117 | "source": [ |
120 | | - "def prescription_arrival_generator(env):\n", |
| 118 | + "def arrivals_generator(env):\n", |
121 | 119 | " '''\n", |
122 | | - " Prescriptions arrive with a fixed duration of 5 minutes.\n", |
| 120 | + " Callers arrive with a fixed inter-arrival time of 1.0 minutes.\n", |
123 | 121 | "\n", |
124 | 122 | " Parameters:\n", |
125 | 123 | " ------\n", |
|
131 | 129 | " while True:\n", |
132 | 130 | " \n", |
133 | 131 | " # sample an inter-arrival time.\n", |
134 | | - " inter_arrival_time = 5.0\n", |
| 132 | + " inter_arrival_time = 1.0\n", |
135 | 133 | " \n", |
136 | 134 | " # we use the yield keyword instead of return\n", |
137 | 135 | " yield env.timeout(inter_arrival_time)\n", |
138 | 136 | " \n", |
139 | 137 | " # print out the time of the arrival\n", |
140 | | - " print(f'Prescription arrives at: {env.now}')" |
| 138 | + " print(f'Call arrives at: {env.now}')" |
141 | 139 | ] |
142 | 140 | }, |
143 | 141 | { |
|
152 | 150 | }, |
153 | 151 | { |
154 | 152 | "cell_type": "code", |
155 | | - "execution_count": 3, |
| 153 | + "execution_count": 23, |
156 | 154 | "id": "f6f74ff5-4c95-400e-8494-42e438b18b90", |
157 | 155 | "metadata": {}, |
158 | 156 | "outputs": [ |
159 | 157 | { |
160 | 158 | "name": "stdout", |
161 | 159 | "output_type": "stream", |
162 | 160 | "text": [ |
163 | | - "Prescription arrives at: 5.0\n", |
164 | | - "Prescription arrives at: 10.0\n", |
165 | | - "Prescription arrives at: 15.0\n", |
166 | | - "Prescription arrives at: 20.0\n", |
| 161 | + "Call arrives at: 1.0\n", |
| 162 | + "Call arrives at: 2.0\n", |
| 163 | + "Call arrives at: 3.0\n", |
| 164 | + "Call arrives at: 4.0\n", |
| 165 | + "Call arrives at: 5.0\n", |
| 166 | + "Call arrives at: 6.0\n", |
| 167 | + "Call arrives at: 7.0\n", |
| 168 | + "Call arrives at: 8.0\n", |
| 169 | + "Call arrives at: 9.0\n", |
| 170 | + "Call arrives at: 10.0\n", |
| 171 | + "Call arrives at: 11.0\n", |
| 172 | + "Call arrives at: 12.0\n", |
| 173 | + "Call arrives at: 13.0\n", |
| 174 | + "Call arrives at: 14.0\n", |
| 175 | + "Call arrives at: 15.0\n", |
| 176 | + "Call arrives at: 16.0\n", |
| 177 | + "Call arrives at: 17.0\n", |
| 178 | + "Call arrives at: 18.0\n", |
| 179 | + "Call arrives at: 19.0\n", |
| 180 | + "Call arrives at: 20.0\n", |
| 181 | + "Call arrives at: 21.0\n", |
| 182 | + "Call arrives at: 22.0\n", |
| 183 | + "Call arrives at: 23.0\n", |
| 184 | + "Call arrives at: 24.0\n", |
167 | 185 | "end of run. simulation clock time = 25\n" |
168 | 186 | ] |
169 | 187 | } |
|
175 | 193 | "# create the simpy environment object\n", |
176 | 194 | "env = simpy.Environment()\n", |
177 | 195 | "\n", |
178 | | - "# tell simpy that the `prescription_arrival_generator` is a process\n", |
179 | | - "env.process(prescription_arrival_generator(env))\n", |
| 196 | + "# tell simpy that the `arrivals_generator` is a process\n", |
| 197 | + "env.process(arrivals_generator(env))\n", |
180 | 198 | "\n", |
181 | 199 | "# run the simulation model\n", |
182 | 200 | "env.run(until=RUN_LENGTH)\n", |
|
192 | 210 | "\n", |
193 | 211 | "Before we learn anything more about `simpy`, have a go at the [generators exercise](./03a_exercise1.ipynb).\n", |
194 | 212 | "\n", |
195 | | - "In the exercise you will need to modify the `prescription_arrival_generator` so that it has random arrivals. This exercise tests that you have understood the basics of `simpy` and random sampling in `numpy`\n" |
| 213 | + "In the exercise you will need to modify the `arrivals_generator` so that it has random arrivals. This exercise tests that you have understood the basics of `simpy` and random sampling in `numpy`\n" |
196 | 214 | ] |
197 | 215 | } |
198 | 216 | ], |
|
212 | 230 | "name": "python", |
213 | 231 | "nbconvert_exporter": "python", |
214 | 232 | "pygments_lexer": "ipython3", |
215 | | - "version": "3.12.6" |
| 233 | + "version": "3.11.10" |
216 | 234 | } |
217 | 235 | }, |
218 | 236 | "nbformat": 4, |
|
0 commit comments