Skip to content

Removal of pharmacy example #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,36 @@ This tutorial has been set up to run on your browser without the need to install

### 2.2 Running notebooks locally on your machine

You can also run the notebooks in `content/` locally on your machine. You'll need to install the provided conda environment `environment.yml`.
#### 2.2.1 Downloading the code

Either clone the repository using git or click on the green "code" button and select "Download Zip".

```bash
git clone https://github.com/pythonhealthdatascience/intro-open-sim.git
```

#### 2.2.2 Installing dependencies and running JupyterLab

All dependencies can be found in [`binder/environment.yml`]() and are pulled from conda-forge. To run the code locally, we recommend installing [miniforge](https://github.com/conda-forge/miniforge);

> miniforge is FOSS alternative to Anaconda and miniconda that uses conda-forge as the default channel for packages. It installs both conda and mamba (a drop in replacement for conda) package managers. We recommend mamba for faster resolving of dependencies and installation of packages.

navigating your terminal (or cmd prompt) to the directory containing the repo and issuing the following command:

```
mamba env create -f binder/environment.yml
```

Activate the mamba environment using the following command:

```
mamba activate simpy_tutorial
```

You can then run the notebooks in `content/` locally on your machine using JupyterLab. Issue the following command and JupyterLab will open in your browser. Notebooks are in the `content/` directory.

```
conda env create --name xeus-python-kernel --file environment.yml
conda activate xeus-python-kernel
jupyter-lab
```

## 📝 3. Citation
Expand Down
7 changes: 4 additions & 3 deletions binder/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ name: simpy_tutorial
channels:
- conda-forge
dependencies:
- python=3.11
- simpy=4.1.1
- jupyterlab=4.2.4
- matplotlib=3.8.4
- numpy<2
- pandas=1.5.3
- matplotlib=3.8.4
- python=3.11
- simpy=4.1.1
2 changes: 1 addition & 1 deletion content/01_sampling.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.1.-1"
"version": "3.11.10"
}
},
"nbformat": 4,
Expand Down
68 changes: 43 additions & 25 deletions content/02_basic_simpy.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,9 @@
"id": "968d7a3d-763d-48a0-9915-421631d1f650",
"metadata": {},
"source": [
"## 3. An example: a hospital pharmacy\n",
"# 3. An example: a urgent care call sample\n",
"\n",
"In this first example, let's assume (unrealistically) that prescriptions arrive **exactly** 5 minutes apart.\n",
"\n",
"![Pharmacy with prescriptions every 5 minutes](./img/pharmacy.png)\n",
"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",
"\n",
"## 4. The model building blocks\n",
"\n",
Expand All @@ -72,19 +70,19 @@
"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",
"\n",
"```python\n",
"env.timeout(5.0)\n",
"env.timeout(1.0)\n",
"```\n",
"\n",
"### 4.3 Generators\n",
"\n",
"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",
"\n",
"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",
"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",
"\n",
"```python\n",
"def prescription_arrival_generator(env):\n",
"def arrivals_generator(env):\n",
" while True:\n",
" yield env.timeout(5.0)\n",
" yield env.timeout(1.0)\n",
"```\n",
"\n",
"### 4.4 SimPy process and run\n",
Expand All @@ -94,7 +92,7 @@
"1. Set the generator up as a **SimPy process** using `env.process()`\n",
"\n",
"```python\n",
"env.process(prescription_arrival_generator(env))\n",
"env.process(arrivals_generator(env))\n",
"```\n",
"\n",
"2. Run the environment for a user specified **run length** using `env.run()`\n",
Expand All @@ -103,23 +101,23 @@
"env.run(until=25)\n",
"```\n",
"\n",
"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",
"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",
"\n",
"## 5. Create the model\n",
"\n",
"**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."
"**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."
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 22,
"id": "a6fd524c-7dc4-41c0-876d-3507ce480dfb",
"metadata": {},
"outputs": [],
"source": [
"def prescription_arrival_generator(env):\n",
"def arrivals_generator(env):\n",
" '''\n",
" Prescriptions arrive with a fixed duration of 5 minutes.\n",
" Callers arrive with a fixed inter-arrival time of 1.0 minutes.\n",
"\n",
" Parameters:\n",
" ------\n",
Expand All @@ -131,13 +129,13 @@
" while True:\n",
" \n",
" # sample an inter-arrival time.\n",
" inter_arrival_time = 5.0\n",
" inter_arrival_time = 1.0\n",
" \n",
" # we use the yield keyword instead of return\n",
" yield env.timeout(inter_arrival_time)\n",
" \n",
" # print out the time of the arrival\n",
" print(f'Prescription arrives at: {env.now}')"
" print(f'Call arrives at: {env.now}')"
]
},
{
Expand All @@ -152,18 +150,38 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 23,
"id": "f6f74ff5-4c95-400e-8494-42e438b18b90",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Prescription arrives at: 5.0\n",
"Prescription arrives at: 10.0\n",
"Prescription arrives at: 15.0\n",
"Prescription arrives at: 20.0\n",
"Call arrives at: 1.0\n",
"Call arrives at: 2.0\n",
"Call arrives at: 3.0\n",
"Call arrives at: 4.0\n",
"Call arrives at: 5.0\n",
"Call arrives at: 6.0\n",
"Call arrives at: 7.0\n",
"Call arrives at: 8.0\n",
"Call arrives at: 9.0\n",
"Call arrives at: 10.0\n",
"Call arrives at: 11.0\n",
"Call arrives at: 12.0\n",
"Call arrives at: 13.0\n",
"Call arrives at: 14.0\n",
"Call arrives at: 15.0\n",
"Call arrives at: 16.0\n",
"Call arrives at: 17.0\n",
"Call arrives at: 18.0\n",
"Call arrives at: 19.0\n",
"Call arrives at: 20.0\n",
"Call arrives at: 21.0\n",
"Call arrives at: 22.0\n",
"Call arrives at: 23.0\n",
"Call arrives at: 24.0\n",
"end of run. simulation clock time = 25\n"
]
}
Expand All @@ -175,8 +193,8 @@
"# create the simpy environment object\n",
"env = simpy.Environment()\n",
"\n",
"# tell simpy that the `prescription_arrival_generator` is a process\n",
"env.process(prescription_arrival_generator(env))\n",
"# tell simpy that the `arrivals_generator` is a process\n",
"env.process(arrivals_generator(env))\n",
"\n",
"# run the simulation model\n",
"env.run(until=RUN_LENGTH)\n",
Expand All @@ -192,7 +210,7 @@
"\n",
"Before we learn anything more about `simpy`, have a go at the [generators exercise](./03a_exercise1.ipynb).\n",
"\n",
"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"
"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"
]
}
],
Expand All @@ -212,7 +230,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.6"
"version": "3.11.10"
}
},
"nbformat": 4,
Expand Down
49 changes: 18 additions & 31 deletions content/03a_exercise1.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"id": "f2147e34-ce39-4d8c-a7db-e8acec2b63e0",
"metadata": {},
"source": [
"# Generator exercise\n",
"# Solutions for the generator exercise\n",
"\n",
"🧐 For the solutions, please see the [generator exercise solutions notebook](./03b_exercise1_solutions.ipynb)\n"
"🧐 For the solutions, please see the [generator exercise solutions notebook](./03b_exercise1_solutions.ipynb)"
]
},
{
Expand All @@ -20,7 +20,7 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"id": "85fd4a85-bb77-498c-96ee-c14de89994a2",
"metadata": {},
"outputs": [],
Expand All @@ -34,22 +34,21 @@
"id": "bfab7f97-9cad-419a-8d75-a2ba190edee8",
"metadata": {},
"source": [
"## 2. Example code\n",
"## Example code\n",
"\n",
"The code below is taken from the simple pharmacy example. In this code arrivals occur with an inter-arrival time (IAT) of exactly 5 minutes."
"The code below is taken from the simple call centre example. In this code arrivals occur with an inter-arrival time (IAT) of exactly 1 minute."
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"id": "ee2439f2-0d35-41fd-a5e2-4b95954dd5c5",
"metadata": {},
"outputs": [],
"source": [
"def prescription_arrival_generator(env):\n",
"def arrivals_generator(env):\n",
" '''\n",
" Prescriptions arrive with a fixed duration of\n",
" 5 minutes.\n",
" Prescriptions arrive with a fixed duration of 1 minute.\n",
"\n",
" Parameters:\n",
" ------\n",
Expand All @@ -61,42 +60,30 @@
" while True:\n",
" \n",
" # sample an inter-arrival time.\n",
" inter_arrival_time = 5.0\n",
" inter_arrival_time = 1.0\n",
" \n",
" # we use the yield keyword instead of return\n",
" yield env.timeout(inter_arrival_time)\n",
" \n",
" # print out the time of the arrival\n",
" print(f'Prescription arrives at: {env.now}')"
" print(f'Call arrives at: {env.now}')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": null,
"id": "40c495d5-6f55-4c93-99e3-5bfa6cdff36d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Prescription arrives at: 5.0\n",
"Prescription arrives at: 10.0\n",
"Prescription arrives at: 15.0\n",
"Prescription arrives at: 20.0\n",
"end of run. simulation clock time = 25\n"
]
}
],
"outputs": [],
"source": [
"# model parameters\n",
"RUN_LENGTH = 25\n",
"\n",
"# create the simpy environment object\n",
"env = simpy.Environment()\n",
"\n",
"# tell simpy that the `prescription_arrival_generator` is a process\n",
"env.process(prescription_arrival_generator(env))\n",
"# tell simpy that the `arrivals_generator` is a process\n",
"env.process(arrivals_generator(env))\n",
"\n",
"# run the simulation model\n",
"env.run(until=RUN_LENGTH)\n",
Expand All @@ -112,7 +99,7 @@
"\n",
"**Task:**\n",
"\n",
"Update `prescription_arrival_generator()` so that inter-arrival times follow an **exponential distribution** with a mean of 5.0 minutes between arrivals. Use a run length of 25 minutes.\n",
"Update `arrivals_generator()` so that inter-arrival times follow an **exponential distribution** with a mean inter-arrival time of 60.0 / 100 minutes between arrivals (i.e. 100 arrivals per hour). Use a run length of 25 minutes.\n",
"\n",
"**Bonus challenge:**\n",
"\n",
Expand All @@ -130,12 +117,12 @@
},
{
"cell_type": "code",
"execution_count": 4,
"id": "65823eff-8d0f-4eaf-a531-173c8ab6290c",
"execution_count": null,
"id": "49dcec06-cf80-47d0-befd-66bc842f2e6e",
"metadata": {},
"outputs": [],
"source": [
"# your code here."
"# your code here..."
]
}
],
Expand Down
Loading
Loading