cara/app/cara.ipynb
2020-10-27 16:06:39 +01:00

291 lines
8.5 KiB
Text

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<p style=\"color: red; font-weight: bold; font-size: xx-large; text-align: center;\" align=\"center\">\n",
" 'CARA' (COVID Airborne Risk Assessment)\n",
"</p>\n",
"\n",
"<p style=\"color: blue; font-weight: bold; font-size: x-large; text-align: center;\" align=\"center\">\n",
"Airborne Transmission of SARS-CoV-2\n",
"</p>"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib widget\n",
"import ipywidgets as widgets\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import typing"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"import cara.models\n",
"\n",
"\n",
"def prepare_model(volume, n_infected=1, n_exposed=10, mask='Type I') -> cara.models.Model:\n",
" \"\"\"\n",
" Transform configurable values into a cara model instance.\n",
" \n",
" \"\"\"\n",
" model = cara.models.Model(\n",
" room=cara.models.Room(volume=volume),\n",
" ventilation=cara.models.Ventilation(),\n",
" infected=cara.models.InfectedPerson(\n",
" virus=cara.models.Virus.types['SARS_CoV_2'],\n",
" present_times=((0, 4), (5, 8)),\n",
" mask=cara.models.Mask.types[mask],\n",
" activity=cara.models.Activity.types['Light exercise'],\n",
" expiration=cara.models.Expiration.types['Unmodulated Vocalization'],\n",
" ),\n",
" infected_occupants=n_infected,\n",
" exposed_occupants=n_exposed,\n",
" exposed_activity=cara.models.Activity.types['Light exercise'],\n",
" )\n",
" return model"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Setup our plotting environment.\n",
"plt.interactive(False)\n",
"fig_concentration_over_time = plt.figure()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Define some useful widget machinery.\n",
"\n",
"def collapsible(widgets_to_collapse: typing.List, title: str, start_collapsed=True):\n",
" collapsed = widgets.Accordion([widgets.VBox(widgets_to_collapse)])\n",
" collapsed.set_title(0, title)\n",
" if start_collapsed:\n",
" collapsed.selected_index = None\n",
" return collapsed\n",
"\n",
"\n",
"def widget_group(label_widget_pairs):\n",
" labels, widgets_ = zip(*label_widget_pairs) \n",
" labels_w = widgets.VBox(labels)\n",
" widgets_w = widgets.VBox(widgets_)\n",
" return widgets.HBox([labels_w, widgets_w])"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "eb109c0f63e149d69e763aec5d404db2",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Accordion(children=(VBox(children=(HBox(children=(VBox(children=(Label(value='Room volume'),)), VBox(children=…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"room_volume = widgets.IntSlider(value=75, min=10, max=150)\n",
"mask_used = widgets.Checkbox(value=True, description='Mask worn')\n",
"\n",
"collapsible(\n",
" [widget_group(\n",
" [[widgets.Label('Room volume'), room_volume]]\n",
" )],\n",
" title='Specification of workplace', start_collapsed=False,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "49ad604786f546f58dba54f1f6e7eded",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Accordion(children=(VBox(children=(HBox(children=(VBox(children=(Label(value='Ventilation type'),)), VBox(chil…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ventilation_widgets = {\n",
" 'Natural': widgets.Label('Currently hard-coded to 514.74 / volume'),\n",
" 'other': widgets.Label('Not yet implemented.')\n",
"}\n",
"for name, widget in ventilation_widgets.items():\n",
" widget.layout.visible = False\n",
"\n",
"ventilation_w = widgets.ToggleButtons(\n",
" options=['Natural'], # cara.models.Ventilation.types.keys(),\n",
")\n",
"def toggle_ventilation(value):\n",
" for name, widget in ventilation_widgets.items():\n",
" widget.layout.display = 'none'\n",
" other = ventilation_widgets['other']\n",
" widget = ventilation_widgets.get(value, other)\n",
" widget.layout.visible = True\n",
" widget.layout.display = 'block'\n",
"\n",
"ventilation_w.observe(lambda event: toggle_ventilation(event['new']), 'value')\n",
"toggle_ventilation(ventilation_w.value)\n",
"\n",
"\n",
"collapsible(\n",
" [widget_group([[widgets.Label('Ventilation type'), ventilation_w]])]\n",
" + list(ventilation_widgets.values()),\n",
" title='Ventilation scheme'\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "8e76a49d0212462d81200a3959dcd3ff",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Accordion(children=(VBox(children=(HBox(children=(Canvas(footer_visible=False, header_visible=False, toolbar=T…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"line = None\n",
"# plt.ioff()\n",
"# fig = plt.figure()\n",
"fig = fig_concentration_over_time\n",
"\n",
"def plot_concentrations(_):\n",
" global line\n",
" model = prepare_model(room_volume.value)\n",
"\n",
" ts = np.arange(0, 10., 0.01)\n",
" concentration = [model.concentration(t) for t in ts]\n",
"\n",
" ax = fig.gca()\n",
" \n",
" plt.text(0.5, 0.9, 'Without masks & window open', transform=ax.transAxes, ha='center')\n",
" if line is None:\n",
" ax.spines['right'].set_visible(False)\n",
" ax.spines['top'].set_visible(False)\n",
" [line] = plt.plot(ts, concentration)\n",
" ax.set_xlabel('Time (hours)')\n",
" ax.set_ylabel('Concentration ($q/m^3$)')\n",
" plt.title('Concentration of infectious quanta aerosols')\n",
" \n",
" ax.set_ymargin(0.2)\n",
" ax.set_ylim(bottom=0)\n",
" else:\n",
" line.set_data(ts, concentration)\n",
" ax.relim()\n",
" ax.autoscale_view()\n",
" \n",
" plt.draw()\n",
"\n",
"# print(f'Probability of infection: {np.round(model.[\"P\"], 1)}')\n",
"# print(f'Expected number of new cases: {prepared[\"R0\"]}')\n",
" \n",
"\n",
"# widgets.interact(\n",
"# plot_concentrations,\n",
"# volume=room_volume,\n",
"# n_exposed=widgets.IntSlider(value=10, min=0, max=25),\n",
"# n_infected=widgets.IntSlider(value=1, min=1, max=5),\n",
"# );\n",
"\n",
"\n",
"for observable in [room_volume]:\n",
" observable.observe(plot_concentrations)\n",
"\n",
"plot_concentrations(1)\n",
"\n",
"fig.canvas.toolbar_visible = True\n",
"fig.canvas.toolbar.collapsed = True\n",
"fig.canvas.footer_visible = False\n",
"fig.canvas.header_visible = False\n",
"\n",
"\n",
"collapsible([\n",
" widgets.HBox([\n",
" fig.canvas,\n",
" # text_report,\n",
" ])\n",
"], 'Report', start_collapsed=False)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.12"
}
},
"nbformat": 4,
"nbformat_minor": 4
}