291 lines
8.5 KiB
Text
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
|
|
}
|