{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"*This notebook contains material from [CBE40455-2020](https://jckantor.github.io/CBE40455-2020);\n",
"content is available [on Github](https://github.com/jckantor/CBE40455-2020.git).*\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"< [3.3 Agent Based Models](https://jckantor.github.io/CBE40455-2020/03.03-Agent-Based-Models.html) | [Contents](toc.html) | [3.5 Assignment](https://jckantor.github.io/CBE40455-2020/03.05-Assignment.html) >
"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 1,
"link": "[3.4 Modeling Events](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4-Modeling-Events)",
"section": "3.4 Modeling Events"
}
},
"source": [
"# 3.4 Modeling Events"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[3.4.1 Learning Objectives](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.1-Learning-Objectives)",
"section": "3.4.1 Learning Objectives"
}
},
"source": [
"## 3.4.1 Learning Objectives\n",
"\n",
"* Key performance indicators\n",
"* Visualization with Gannt charts\n",
"* Adding 'state' to models\n",
"* Combining events with `AnyOf` and `AllOf`\n",
"* Deterministic versus stochastic models"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[3.4.2 Example: A room full of Roombas](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.2-Example:-A-room-full-of-Roombas)",
"section": "3.4.2 Example: A room full of Roombas"
}
},
"source": [
"## 3.4.2 Example: A room full of Roombas\n",
"\n",
"Let's imagine a large facility that is being cleaned by a collection of Roomba-type robotic cleaning units. Each unit is characterized by time required to charge, and an amount of time it can clean before needing to be recharged. The facility must be cleaned during a 16 hour overnight shift. On average, 3 units must be operating continuously to meet the cleaning requirements, i.e., 3 x 16 = 48 hours machine cleaning each night. We would like to determine how many charging stations will be required.\n",
"\n",
"| Unit | Charge Time (hrs) | Clean Time (hrs) |\n",
"| :--: | :--: | :--: |\n",
"| A | 1.0 | 2.5 |\n",
"| B | 0.5 | 1.5 |\n",
"| C | 0.8 | 2.0 |\n",
"| D | 1.4 | 3.5 |\n",
"| E | 0.5 | 1.2 |"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[3.4.3 Shared resource](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.3-Shared-resource)",
"section": "3.4.3 Shared resource"
}
},
"source": [
"## 3.4.3 Shared resource"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[3.4.3.1 Installation, Import, and Setup section](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.3.1-Installation,-Import,-and-Setup-section)",
"section": "3.4.3.1 Installation, Import, and Setup section"
}
},
"source": [
"### 3.4.3.1 Installation, Import, and Setup section"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"nbpages": {
"level": 3,
"link": "[3.4.3.1 Installation, Import, and Setup section](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.3.1-Installation,-Import,-and-Setup-section)",
"section": "3.4.3.1 Installation, Import, and Setup section"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: simpy in /Users/jeff/opt/anaconda3/lib/python3.7/site-packages (4.0.1)\n"
]
}
],
"source": [
"# necessary installations\n",
"!pip install simpy\n",
"\n",
"# import section\n",
"import simpy \n",
"import pandas as pd\n",
"import numpy as np"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[3.4.3.2 Data section](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.3.2-Data-section)",
"section": "3.4.3.2 Data section"
}
},
"source": [
"### 3.4.3.2 Data section"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"nbpages": {
"level": 3,
"link": "[3.4.3.2 Data section](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.3.2-Data-section)",
"section": "3.4.3.2 Data section"
}
},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
id
\n",
"
charge_time
\n",
"
clean_time
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
A
\n",
"
1.0
\n",
"
2.5
\n",
"
\n",
"
\n",
"
1
\n",
"
B
\n",
"
0.5
\n",
"
1.5
\n",
"
\n",
"
\n",
"
2
\n",
"
C
\n",
"
0.8
\n",
"
2.0
\n",
"
\n",
"
\n",
"
3
\n",
"
D
\n",
"
1.4
\n",
"
3.5
\n",
"
\n",
"
\n",
"
4
\n",
"
E
\n",
"
0.5
\n",
"
1.2
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id charge_time clean_time\n",
"0 A 1.0 2.5\n",
"1 B 0.5 1.5\n",
"2 C 0.8 2.0\n",
"3 D 1.4 3.5\n",
"4 E 0.5 1.2"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# data section\n",
"\n",
"roomba_data = [\n",
" [\"A\", 1.0, 2.5],\n",
" [\"B\", 0.5, 1.5],\n",
" [\"C\", 0.8, 2.0],\n",
" [\"D\", 1.4, 3.5],\n",
" [\"E\", 0.5, 1.2],\n",
"]\n",
"\n",
"roomba_df = pd.DataFrame(roomba_data, columns=[\"id\", \"charge_time\", \"clean_time\"])\n",
"display(roomba_df)"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[3.4.3.3 Modeling and simulation section](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.3.3-Modeling-and-simulation-section)",
"section": "3.4.3.3 Modeling and simulation section"
}
},
"source": [
"### 3.4.3.3 Modeling and simulation section\n",
"\n",
"The output of the modeling and simulation is a Pandas DataFrame giving a complete history of the events occuring during a simulation."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"nbpages": {
"level": 3,
"link": "[3.4.3.3 Modeling and simulation section](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.3.3-Modeling-and-simulation-section)",
"section": "3.4.3.3 Modeling and simulation section"
}
},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
id
\n",
"
event
\n",
"
begin
\n",
"
end
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
A
\n",
"
charging
\n",
"
0.0
\n",
"
1.0
\n",
"
\n",
"
\n",
"
1
\n",
"
B
\n",
"
charging
\n",
"
1.0
\n",
"
1.5
\n",
"
\n",
"
\n",
"
2
\n",
"
C
\n",
"
charging
\n",
"
1.5
\n",
"
2.3
\n",
"
\n",
"
\n",
"
3
\n",
"
B
\n",
"
cleaning
\n",
"
1.5
\n",
"
3.0
\n",
"
\n",
"
\n",
"
4
\n",
"
A
\n",
"
cleaning
\n",
"
1.0
\n",
"
3.5
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id event begin end\n",
"0 A charging 0.0 1.0\n",
"1 B charging 1.0 1.5\n",
"2 C charging 1.5 2.3\n",
"3 B cleaning 1.5 3.0\n",
"4 A cleaning 1.0 3.5"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def roomba_model(id, charge_time, clean_time):\n",
" while True:\n",
" with chargers.request() as request:\n",
" yield request\n",
" tic = env.now\n",
" yield env.timeout(charge_time)\n",
" toc = env.now\n",
" data_log.append([id, \"charging\", tic, toc])\n",
" \n",
" tic = env.now\n",
" yield env.timeout(clean_time)\n",
" toc = env.now\n",
" data_log.append([id, \"cleaning\", tic, toc])\n",
"\n",
"data_log = []\n",
"\n",
"env = simpy.Environment()\n",
"chargers = simpy.Resource(env, capacity=1)\n",
"for r in roomba_df.index:\n",
" env.process(roomba_model(roomba_df[\"id\"][r], roomba_df[\"charge_time\"][r], roomba_df[\"clean_time\"][r]))\n",
"env.run(until=16)\n",
"\n",
"df = pd.DataFrame(data_log, columns=[\"id\", \"event\", \"begin\", \"end\"])\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[3.4.3.4 Key performance indictors](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.3.4-Key-performance-indictors)",
"section": "3.4.3.4 Key performance indictors"
}
},
"source": [
"### 3.4.3.4 Key performance indictors\n",
"\n",
"Key Performance Indicators (KPI) is a commonly used termed to denote quantitative measures important to the performance of an organization, unit, or system."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"nbpages": {
"level": 3,
"link": "[3.4.3.4 Key performance indictors](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.3.4-Key-performance-indictors)",
"section": "3.4.3.4 Key performance indictors"
}
},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
time
\n",
"
\n",
"
\n",
"
event
\n",
"
\n",
"
\n",
" \n",
" \n",
"
\n",
"
charging
\n",
"
15.4
\n",
"
\n",
"
\n",
"
cleaning
\n",
"
31.3
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" time\n",
"event \n",
"charging 15.4\n",
"cleaning 31.3"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def kpi(df):\n",
" df[\"time\"] = df[\"end\"] - df[\"begin\"]\n",
" return pd.pivot_table(df, index=[\"event\"], values=\"time\", aggfunc={\"time\":np.sum} )\n",
" \n",
"kpi(df)"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[3.4.3.5 Visualization with Gantt charts](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.3.5-Visualization-with-Gantt-charts)",
"section": "3.4.3.5 Visualization with Gantt charts"
}
},
"source": [
"### 3.4.3.5 Visualization with Gantt charts\n",
"\n",
"Designed circa 1910-1915 by Henry Gantt, an American mechanical engineer who worked with Frederick W. Taylor, one of the first management consultants and a leader in the Efficiency Movement of the late 19th century.\n",
"\n",
"Gantt charts provide a convenient method to display complex schedules and the time-dependent allocation of resources."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"nbpages": {
"level": 3,
"link": "[3.4.3.5 Visualization with Gantt charts](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.3.5-Visualization-with-Gantt-charts)",
"section": "3.4.3.5 Visualization with Gantt charts"
}
},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"
"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt\n",
"from matplotlib.lines import Line2D\n",
"\n",
"def gantt(df, lw=10):\n",
" \n",
" # create sorted lists of the unique ids and events appearing in the data log\n",
" ids = sorted(list(set(df[\"id\"])))\n",
" events = sorted(list(set(df[\"event\"])))\n",
" \n",
" # create list of unique colors for each event\n",
" colors = [f\"C{i}\" for i in range(len(events))]\n",
" \n",
" # create plot window\n",
" fig, ax = plt.subplots(1, 1, figsize=(12, 3))\n",
" \n",
" # for each event and id, find entries in the data log and plot the begin and end points\n",
" for i, event in enumerate(events):\n",
" for j, id in enumerate(ids): \n",
" for k in df[(df[\"id\"]==id) & (df[\"event\"]==event)].index:\n",
" ax.plot([df[\"begin\"][k], df[\"end\"][k]], [j,j], \n",
" colors[i], solid_capstyle=\"butt\", lw=lw)\n",
" \n",
" # create legend\n",
" lines = [Line2D([0], [0], lw=lw, color=colors[i]) for i in range(len(events))]\n",
" ax.legend(lines, events, bbox_to_anchor=(0.0, 1.1), loc=\"lower left\")\n",
" \n",
" # annotate the axes\n",
" ax.set_yticks(range(len(ids)))\n",
" ax.set_yticklabels(ids)\n",
" ax.grid(True)\n",
" ax.set_xlabel(\"Time\")\n",
" ax.set_title(\"Gannt Chart\")\n",
" for sp in ['top', 'bottom', 'right', 'left']:\n",
" ax.spines[sp].set_visible(False)\n",
" \n",
"gantt(df)"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[3.4.4 Assignment Review](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.4-Assignment-Review)",
"section": "3.4.4 Assignment Review"
}
},
"source": [
"## 3.4.4 Assignment Review"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 3,
"link": "[3.4.4.1 Exercise 1. ](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.4.1-Exercise-1.)",
"section": "3.4.4.1 Exercise 1. "
}
},
"source": [
"### 3.4.4.1 Exercise 1. \n",
"\n",
"Answer the question posed above: How many charging stations are needed to provide 48 hours cleaning services in the overnight shift?"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 4,
"link": "[3.4.4.1.1 Solution](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.4.1.1-Solution)",
"section": "3.4.4.1.1 Solution"
}
},
"source": [
"#### 3.4.4.1.1 Solution"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"nbpages": {
"level": 4,
"link": "[3.4.4.1.1 Solution](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.4.1.1-Solution)",
"section": "3.4.4.1.1 Solution"
}
},
"outputs": [
{
"data": {
"text/html": [
"
"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"def roomba_model(id, charge_time, clean_time):\n",
" while True:\n",
" tic = env.now\n",
" yield env.timeout(clean_time)\n",
" toc = env.now\n",
" data_log.append([id, \"cleaning\", tic, toc])\n",
" with chargers.request() as request:\n",
" yield request\n",
" tic = env.now\n",
" yield env.timeout(charge_time)\n",
" toc = env.now\n",
" data_log.append([id, \"charging\", tic, toc])\n",
" \n",
"data_log = []\n",
"\n",
"env = simpy.Environment()\n",
"chargers = simpy.Resource(env, capacity=2)\n",
"for r in roomba_df.index:\n",
" env.process(roomba_model(roomba_df[\"id\"][r], roomba_df[\"charge_time\"][r], roomba_df[\"clean_time\"][r]))\n",
"env.run(until=16)\n",
"\n",
"df = pd.DataFrame(data_log, columns=[\"id\", \"event\", \"begin\", \"end\"])\n",
"display(kpi(df))\n",
"gantt(df)"
]
},
{
"cell_type": "markdown",
"metadata": {
"nbpages": {
"level": 2,
"link": "[3.4.5 Introducing State Variables](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.5-Introducing-State-Variables)",
"section": "3.4.5 Introducing State Variables"
}
},
"source": [
"## 3.4.5 Introducing State Variables\n",
"\n",
"The solution to this exercise can be generalized by introducing a state variable `soc` denoting the 'state of charge'. The state of charge is the fraction of charge remaining in the device battery. The state of charge is reduced during cleaning operations, and restored during charging operation, in proportion to the time spent cleaning and charging, respectively.\n",
"\n",
"Given an initial full charge, let parameter $\\tau_{clean}$ denote the maximum time the device can clean before completely exhausting the battery. Let $\\text{SOC}_{k}$ be the state of charge after the $k_{th}$ cleaning cycle. Then\n",
"\n",
"$$\\text{SOC}_{k+1} = \\max(0, \\text{SOC}_k - \\frac{t_{k, clean}}{\\tau_{clean}})$$\n",
"\n",
"where $t_{k,clean}$ is the period of the $k_{th}$ cleaning cycle.\n",
"\n",
"An additional parameter is introduced to represent the minimum battery reserve that would be allowed for normal operations.\n",
"\n",
"Similarly, the state of charge following a charging cycle is given by\n",
"\n",
"$$\\text{SOC}_{k+1} = \\min(1, \\text{SOC}_k + \\frac{t_{k, charge}}{\\tau_{charge}})$$\n",
"\n",
"It is interesting to explore the behavior of this system as a function of the initial state of charge and reserve requirements. Take time to explore the role of these two parameters. See if you find any surprising behaviors."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"nbpages": {
"level": 2,
"link": "[3.4.5 Introducing State Variables](https://jckantor.github.io/CBE40455-2020/03.04-Modeling-Events.html#3.4.5-Introducing-State-Variables)",
"section": "3.4.5 Introducing State Variables"
}
},
"outputs": [
{
"data": {
"text/html": [
"