|
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