diff --git a/docs/run.md b/docs/run.md
index 36906182..d91ab8f0 100644
--- a/docs/run.md
+++ b/docs/run.md
@@ -4,6 +4,10 @@ The two basic ways to run the simulation are a Python package and command line
interface. Both interfaces take simulation parameters as a configuration file
and several other user inputs as function arguments or command line arguments.
+For a quick start option, use the Jupyter notebook
+[run_from_xlsx.ipynb](run_from_xlsx.ipynb) with the provided Excel spreadsheet
+template to configure the simulation.
+
## Configuration
The configuration file contains all parameters needed for a single simulation
diff --git a/examples/notebooks/data/scenarios.csv b/examples/notebooks/data/scenarios.csv
new file mode 100644
index 00000000..78a6053b
--- /dev/null
+++ b/examples/notebooks/data/scenarios.csv
@@ -0,0 +1,5 @@
+name,inspection/sample_strategy,inspection/hypergeometric/detection_level
+hypergeometric 0.01,hypergeometric,0.01
+hypergeometric 0.05,hypergeometric,0.05
+hypergeometric 0.1,hypergeometric,0.1
+proportion 0.02,proportion,
diff --git a/examples/notebooks/data/scenarios_config.csv b/examples/notebooks/data/scenarios_long.csv
similarity index 100%
rename from examples/notebooks/data/scenarios_config.csv
rename to examples/notebooks/data/scenarios_long.csv
diff --git a/examples/notebooks/data/user_friendly_config.xlsx b/examples/notebooks/data/user_friendly_config.xlsx
new file mode 100644
index 00000000..1a6ad998
Binary files /dev/null and b/examples/notebooks/data/user_friendly_config.xlsx differ
diff --git a/examples/notebooks/results/user_friendly_config_results.xlsx b/examples/notebooks/results/user_friendly_config_results.xlsx
new file mode 100644
index 00000000..0e917143
Binary files /dev/null and b/examples/notebooks/results/user_friendly_config_results.xlsx differ
diff --git a/examples/notebooks/run_from_xlsx.ipynb b/examples/notebooks/run_from_xlsx.ipynb
index 54a99950..12c10757 100644
--- a/examples/notebooks/run_from_xlsx.ipynb
+++ b/examples/notebooks/run_from_xlsx.ipynb
@@ -1,6 +1,7 @@
{
"cells": [
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -8,7 +9,7 @@
"\n",
"## Test example \n",
"\n",
- "First, we complete the Excel template `data/small_config.xlsx` with the minimal configuration parameter required to run the simulation.\n",
+ "First, we complete the Excel template `data/user_friendly_config.xlsx` with the configuration parameters required to run the simulation.\n",
"\n",
"The Excel configuration should include all parameters related to:\n",
"1. [consignments](../../docs/consignments.md) (what is imported, from where, in what amounts), \n",
@@ -29,14 +30,15 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# Load required functions and packages\n",
"\n",
"from popsborder.simulation import run_simulation\n",
- "from popsborder.inputs import load_configuration\n"
+ "from popsborder.inputs import load_configuration\n",
+ "from popsborder.outputs import print_totals_as_text"
]
},
{
@@ -48,11 +50,11 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
- "xlsx_loc = \"data/small_config.xlsx\""
+ "xlsx_loc = \"data/user_friendly_config.xlsx\""
]
},
{
@@ -64,11 +66,11 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
- "base_config = load_configuration(xlsx_loc)"
+ "base_config = load_configuration(xlsx_loc, sheet=None, key_column=\"D\", value_column=\"B\")"
]
},
{
@@ -82,6 +84,16 @@
"We can include the `pretty` and `verbose` parameters below to visualize the contamination and output directly in the notebook."
]
},
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "num_simulations=1\n",
+ "num_consignments=4"
+ ]
+ },
{
"cell_type": "code",
"execution_count": 5,
@@ -91,17 +103,17 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "━━ Consignment ━━ Boxes: 3 ━━ Items: 60 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n",
- "🐛 ✿ ✿ 🐛 ✿ 🐛 🐛 🐛 🐛 🐛 ✿ ✿ 🐛 🐛 ✿ ✿ 🐛 🐛 ✿ ✿ | ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ 🐛 ✿ ✿ 🐛 🐛 ✿ ✿ ✿ ✿ ✿ | 🐛 🐛 🐛 ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿\n",
- "Inspection worked, found contaminant [TP]\n",
- "━━ Consignment ━━ Boxes: 2 ━━ Items: 40 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n",
- "🐛 🐛 🐛 ✿ 🐛 🐛 🐛 ✿ 🐛 ✿ 🐛 🐛 ✿ ✿ ✿ ✿ 🐛 ✿ 🐛 🐛 | ✿ 🐛 ✿ 🐛 ✿ ✿ 🐛 🐛 ✿ ✿ ✿ ✿ 🐛 ✿ 🐛 ✿ 🐛 🐛 🐛 🐛\n",
- "Inspection worked, found contaminant [TP]\n",
- "━━ Consignment ━━ Boxes: 5 ━━ Items: 100 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n",
- "✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ 🐛 ✿ 🐛 🐛 ✿ | 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 | ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ 🐛 ✿ ✿ 🐛 🐛 🐛 ✿ ✿ ✿ ✿ ✿ ✿ | ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ 🐛 ✿ ✿\n",
- "Inspection worked, found contaminant [TP]\n",
- "━━ Consignment ━━ Boxes: 4 ━━ Items: 80 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n",
- "✿ ✿ ✿ 🐛 ✿ 🐛 ✿ 🐛 ✿ 🐛 ✿ ✿ 🐛 🐛 🐛 ✿ ✿ ✿ ✿ ✿ | 🐛 ✿ ✿ ✿ ✿ ✿ 🐛 ✿ 🐛 ✿ ✿ ✿ ✿ 🐛 ✿ ✿ 🐛 ✿ ✿ ✿ | ✿ ✿ ✿ 🐛 🐛 🐛 🐛 🐛 ✿ 🐛 ✿ ✿ 🐛 🐛 ✿ ✿ ✿ 🐛 ✿ ✿ | ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 🐛 🐛 ✿\n",
+ "━━ Consignment ━━ Boxes: 5 ━━ Items: 250 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n",
+ "✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ | ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ | 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿\n",
+ "Inspection failed, missed 5 boxes with contaminants [FN]\n",
+ "━━ Consignment ━━ Boxes: 1 ━━ Items: 50 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n",
+ "✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿\n",
+ "Inspection failed, missed 1 boxes with contaminants [FN]\n",
+ "━━ Consignment ━━ Boxes: 10 ━━ Items: 500 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n",
+ "✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ | ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ | 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 | ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿\n",
+ "Inspection failed, missed 10 boxes with contaminants [FN]\n",
+ "━━ Consignment ━━ Boxes: 7 ━━ Items: 350 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n",
+ "✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ | ✿ 🐛 ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ | ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ 🐛 ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ ✿ 🐛 ✿ ✿ ✿ ✿ ✿\n",
"Inspection worked, found contaminant [TP]\n",
"Missing {missing:.0f}% of contaminated consignments.\n"
]
@@ -111,13 +123,72 @@
"result = run_simulation(\n",
" config=base_config,\n",
" seed=42,\n",
- " num_simulations=1,\n",
- " num_consignments=4,\n",
+ " num_simulations=num_simulations,\n",
+ " num_consignments=num_consignments,\n",
" pretty=\"boxes\",\n",
" verbose=True\n",
" )\n"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "\n",
+ "Simulation parameters:\n",
+ "----------------------------------------------------------\n",
+ "consignments:\n",
+ "\t Number consignments simulated: 4\n",
+ "\t Avg. number of boxes per consignment: 6\n",
+ "\t Avg. number of items per consignment: 288\n",
+ "contamination:\n",
+ "\t unit: item\n",
+ "\t type: fixed_value\n",
+ "\t\t contamination rate: 0.05\n",
+ "\t contaminant arrangement: random\n",
+ "inspection:\n",
+ "\t unit: item\n",
+ "\t sample strategy: proportion\n",
+ "\t\t value: 0.02\n",
+ "\t selection strategy: random\n",
+ "\t tolerance level: 0\n",
+ "\n",
+ "\n",
+ "Simulation results: (averaged across all simulation runs)\n",
+ "----------------------------------------------------------\n",
+ "Avg. % contaminated consignments slipped: 75.00%\n",
+ "Adjusted avg. % contaminated consignments slipped (excluding slipped consignments with contamination rates below tolerance level): 75.00%\n",
+ "Avg. num. consignments slipped: 3\n",
+ "Avg. num. slipped consignments within tolerance level: 0\n",
+ "Avg. num. consignments intercepted: 1\n",
+ "Total number of slipped contaminants: 39\n",
+ "Total number of intercepted contaminants: 18\n",
+ "Contamination rate:\n",
+ "\tOverall avg: 0.047\n",
+ "\tSlipped consignments avg.: 0.046\n",
+ "\tSlipped consignments max.: 0.050\n",
+ "\tIntercepted consignments avg.: 0.051\n",
+ "\tIntercepted consignments max.: 0.051\n",
+ "Avg. number of boxes opened per consignment:\n",
+ "\t to completion: 4\n",
+ "\t to detection: 3\n",
+ "Avg. number of items inspected per consignment:\n",
+ "\t to completion: 6\n",
+ "\t to detection: 5\n",
+ "Avg. % contaminated items unreported if sample ends at detection: 0.00%\n"
+ ]
+ }
+ ],
+ "source": [
+ "print_totals_as_text(num_consignments, base_config, totals=result)"
+ ]
+ },
{
"cell_type": "markdown",
"metadata": {},
@@ -131,12 +202,11 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
- "from popsborder.outputs import save_simulation_result_to_pandas \n",
- "import pandas"
+ "from popsborder.outputs import save_simulation_result_to_pandas "
]
},
{
@@ -148,7 +218,7 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
@@ -164,7 +234,7 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 9,
"metadata": {},
"outputs": [
{
@@ -214,27 +284,27 @@
"
\n",
" \n",
" 0 | \n",
+ " 75.0 | \n",
+ " 3.0 | \n",
" 0.0 | \n",
- " 0.0 | \n",
- " 0.0 | \n",
- " 4.0 | \n",
+ " 1.0 | \n",
" 4.0 | \n",
- " 14.0 | \n",
- " 280.0 | \n",
+ " 23.0 | \n",
+ " 1150.0 | \n",
" 3.5 | \n",
- " 1.25 | \n",
- " 100.0 | \n",
+ " 3.0 | \n",
+ " 60.869565 | \n",
" ... | \n",
- " 53.333333 | \n",
- " 0.345625 | \n",
- " None | \n",
- " None | \n",
- " 0.55 | \n",
- " 0.345625 | \n",
- " 0 | \n",
- " 1 | \n",
- " 85.0 | \n",
" 0.0 | \n",
+ " 0.047357 | \n",
+ " 0.05 | \n",
+ " 0.046 | \n",
+ " 0.051429 | \n",
+ " 0.051429 | \n",
+ " 1 | \n",
+ " 1 | \n",
+ " 18.0 | \n",
+ " 39.0 | \n",
"
\n",
" \n",
"\n",
@@ -243,33 +313,33 @@
],
"text/plain": [
" missing false_neg missed_within_tolerance intercepted num_inspections \\\n",
- "0 0.0 0.0 0.0 4.0 4.0 \n",
+ "0 75.0 3.0 0.0 1.0 4.0 \n",
"\n",
" num_boxes num_items avg_boxes_opened_completion \\\n",
- "0 14.0 280.0 3.5 \n",
+ "0 23.0 1150.0 3.5 \n",
"\n",
" avg_boxes_opened_detection pct_boxes_opened_completion ... \\\n",
- "0 1.25 100.0 ... \n",
+ "0 3.0 60.869565 ... \n",
"\n",
" pct_contaminant_unreported_if_detection true_contamination_rate \\\n",
- "0 53.333333 0.345625 \n",
+ "0 0.0 0.047357 \n",
"\n",
" max_missed_contamination_rate avg_missed_contamination_rate \\\n",
- "0 None None \n",
+ "0 0.05 0.046 \n",
"\n",
" max_intercepted_contamination_rate avg_intercepted_contamination_rate \\\n",
- "0 0.55 0.345625 \n",
+ "0 0.051429 0.051429 \n",
"\n",
- " false_negative_present true_positive_present \\\n",
- "0 0 1 \n",
+ " false_negative_present true_positive_present \\\n",
+ "0 1 1 \n",
"\n",
- " total_intercepted_contaminants total_missed_contaminants \n",
- "0 85.0 0.0 \n",
+ " total_intercepted_contaminants total_missed_contaminants \n",
+ "0 18.0 39.0 \n",
"\n",
"[1 rows x 25 columns]"
]
},
- "execution_count": 8,
+ "execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
@@ -291,8 +361,251 @@
"metadata": {},
"outputs": [],
"source": [
- "results_pd.to_excel('data/small_config_results.xlsx')"
+ "results_pd.to_excel('results/user_friendly_config_results.xlsx')"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Run multiple scenarios\n",
+ "\n",
+ "Run the simulation for multiple scenarios at once to compare outcomes."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from popsborder.scenarios import run_scenarios\n",
+ "from popsborder.inputs import load_scenario_table\n",
+ "from popsborder.outputs import save_scenario_result_to_pandas\n",
+ "import matplotlib.pyplot as plt"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Load a CSV with the scenarios to run. Each row in the table is a scenario and the columns store the parameters to change for each scenario."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "scenarios_path = \"data/scenarios.csv\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "scenario_table=load_scenario_table(scenarios_path)"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Each scenario uses a common base configuration file but the parameters in the scenario table are overwritten with the values specified for each scenario."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "num_simulations=10\n",
+ "num_consignments=100"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Running scenario: hypergeometric 0.01\n",
+ "Running scenario: hypergeometric 0.05\n",
+ "Running scenario: hypergeometric 0.1\n",
+ "Running scenario: proportion 0.02\n"
+ ]
+ }
+ ],
+ "source": [
+ "results = run_scenarios(\n",
+ " config=base_config,\n",
+ " scenario_table=scenario_table,\n",
+ " seed=42,\n",
+ " num_simulations=num_simulations,\n",
+ " num_consignments=num_consignments,\n",
+ " detailed=False,\n",
+ ")"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Save scenario results to a pandas dataframe"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "results_df = save_scenario_result_to_pandas(\n",
+ " results,\n",
+ " config_columns=[\n",
+ " \"name\",\n",
+ " \"contamination/contamination_rate/value\",\n",
+ " \"contamination/arrangement\",\n",
+ " \"inspection/selection_strategy\",\n",
+ " \"inspection/unit\",\n",
+ " \"inspection/sample_strategy\",\n",
+ " \"inspection/hypergeometric/detection_level\",\n",
+ " ],\n",
+ " result_columns=[\n",
+ " \"true_contamination_rate\",\n",
+ " \"max_missed_contamination_rate\",\n",
+ " \"avg_missed_contamination_rate\",\n",
+ " \"max_intercepted_contamination_rate\",\n",
+ " \"avg_intercepted_contamination_rate\",\n",
+ " \"avg_boxes_opened_completion\",\n",
+ " \"pct_boxes_opened_completion\",\n",
+ " \"avg_boxes_opened_detection\",\n",
+ " \"pct_boxes_opened_detection\",\n",
+ " \"avg_items_inspected_completion\",\n",
+ " \"pct_items_inspected_completion\",\n",
+ " \"avg_items_inspected_detection\",\n",
+ " \"pct_items_inspected_detection\",\n",
+ " \"false_neg\",\n",
+ " \"intercepted\",\n",
+ " \"total_missed_contaminants\",\n",
+ " \"total_intercepted_contaminants\",\n",
+ " \"num_boxes\",\n",
+ " \"num_items\",\n",
+ " ],\n",
+ ")"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Compute a few additional results metrics"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "results_df['action rate'] = results_df[\"intercepted\"] / num_consignments\n",
+ "contaminated_consignments = results_df[\"false_neg\"] + results_df[\"intercepted\"]\n",
+ "results_df[\"interception rate\"] = results_df[\"intercepted\"] / contaminated_consignments\n",
+ "results_df[\"% missed contaminants\"] = (results_df[\"total_missed_contaminants\"] / (results_df[\"total_missed_contaminants\"] + results_df[\"total_intercepted_contaminants\"])) * 100"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Plot metrics to compare scenario outcomes"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Text(0.5, 0, 'Pct. missed contaminants')"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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CgMuEREREckKAy4RERERyQoDLhERERHJCgMuEREREckKAy4RERERyQoDLhERERHJCgMuEREREckKAy4RERERyQoDLhERERHJCgMuEREREckKAy4RERERyQoDLhERERHJCgMuEREREckKAy4RERERyQoDLhERERHJCgMuEREREckKAy4RERERyQoDLhERERHJCgMuEREREckKAy4RERERyQoDLhERERHJCgMuEREREckKA245ExUVBYVCgQcPHpR1KURERERvBAOujPn7+2PUqFFqbU2bNkVqaiosLCze+PmXLVsGV1dXGBoaolGjRvjzzz9fuk90dDQaNWoEQ0NDVK1aFStWrFDbvnr1ajRr1gwVKlRAhQoVEBAQgL/++utNvQUiIiJ6DzHgviHZ2dlldu6cnJwitxkYGMDOzg4KheKN1rBp0yaMGjUKEydOxOnTp9GsWTO0b98eSUlJRe6TkJCADh06oFmzZjh9+jS++eYbjBgxAlu3bpX6REVF4ZNPPkFkZCRiYmJQpUoVtGnTBsnJyW/0/RAREdH7gwG3BPz9/TFs2DAMGzYMlpaWsLa2xrfffgshhNTHxcUF06ZNw+effw4LCwsMHDgQALB161bUqVMHSqUSLi4umDdvntqxXVxcEBYWhr59+8LU1BQODg5YsmSJWp+kpCR07doVpqamMDc3R69evfDvv/9K20NDQ9GgQQOEh4ejatWqUCqVCAoKQnR0NBYtWgSFQgGFQoEbN24UukShJDXOmDEDwcHBMDMzQ5UqVbBq1apix2z+/Pn4z3/+gwEDBqBWrVpYuHAhnJycsHz58iL3WbFiBapUqYKFCxeiVq1aGDBgAIKDgzF37lypz88//4yhQ4eiQYMGcHd3x+rVq6FSqXDw4MFi6yEiIqLygwG3hNavXw89PT2cOHECixcvxoIFC7BmzRq1Pt9//z3q1q2LuLg4TJo0CXFxcejVqxf69OmDs2fPIjQ0FJMmTcK6des09vPw8MCpU6cQEhKCr776Cvv37wcACCHQrVs33Lt3D9HR0di/fz+uXbuG3r17qx3j6tWr2Lx5M7Zu3Yr4+HgsXrwYPj4+GDhwIFJTU5GamgonJyeN91XSGufNmwcvLy+cPn0aQ4cOxRdffIGLFy8WOlbZ2dmIi4tDmzZt1NrbtGmDY8eOFTnGMTExGvu0bdsWJ0+eLHJWOisr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KlECbd68ORQKBYyNjdVeExERERG9a3iRGZU7vMiMiIjo/fPGLzI7fPgw4uPjtdmViIiIiOiN0irgtmjRAqtXry7tWoiIiIiIXptWAbdSpUowMDAo7VqIiIiIiF6bVrc5aNu2LaKjoyGE4MVm9N6qO3kvdJTGZXb+G7M6ltm5iYiI5EyrGdwZM2bg7t27GDRoEO7du1faNRERERERaU2rGdxPP/0UlpaWCA8Px08//QRXV1fY2tpqzOYqFAocPHiwVAolIiIiIioJrQJuVFSU9O9nz57h4sWLuHjxokY/Ll8gIiIiordNq4CrUqlKuw4iIiIiolKh1RpcIiIiIqJ3FQMuEREREcmKVksU8t26dQuRkZFISUnBs2fPNLYrFApMmjTpdU5BRERERPRKtA64Y8eOxaJFi5CXlye1Fbwvbv6/GXCJiIiI6G3SaonC6tWrMW/ePLRo0QJbtmyBEAJBQUH49ddfMWTIEOjp6eHjjz/GoUOHSrteIiIiIqJiaTWDu2rVKri4uOCPP/6Ajs7zjOzi4oLevXujd+/e6NWrF1q3bo1evXqVarFERERERC+j1QzuxYsX0a5dOyncAkBubq70bz8/P3Ts2BFz5859/QqJiIiIiF6B1ndRsLS0lP5tYmKCu3fvqm2vWbMmzp07p3VhRERERETa0CrgOjo64tatW9LratWq4cSJE2p9/vnnH5iYmLxedUREREREr0irgOvr64vjx49Lr7t27YrTp09jyJAh+P333xESEoI//vgDzZs3L7VCiYiIiIhKQquLzD777DOkpKQgMTERzs7OGDt2LHbt2oVVq1Zh9erVEELAxcUF33//fWnXS0RERERULK0Crr+/P/z9/aXXpqamOH78OP773//i2rVrcHZ2RufOnblEgYiIiIjeutd6kllB+vr6+Pjjj0vrcEREREREWtH6LgpERERERO8irWdwb9++jYiICMTGxuLBgwdqj+zNp1AocPDgwdcqkIiIiIjoVWgVcM+cOYOWLVvi/v37EEIU2U+hUGhdGBERERGRNrRaojBmzBjcu3cPEydOREJCAnJycqBSqTS+CpvVJSIiIiJ6k7SawY2JiUG3bt0wderU0q6HiIiIiOi1aDWDa2BggGrVqpV2LUREREREr02rgNuyZUucPHmytGshIiIiInptWgXc77//HufOncPcuXNLux4iIiIi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SEhAeHg4Ll++rLFt165dcHR0lGZz7e3tsXnz5lItlIiIiIioJEoccFevXo2BAwdCqVSqtV+9ehW9evXC7du3UaVKFbi7u+P+/fvo168fTp8+XeoFExEREREVp8QB98iRI6hfvz6cnZ3V2hctWoSnT5/iyy+/REJCAs6dO4f/+7//Q15eHpYuXVrqBRMRERERFeeVlijUqVNHo33Pnj0wMDDAjBkzpLYePXqgWbNm+PPPP0unSiIiIiKiEipxwL1z5w6cnJzU2h48eIBr167B29sbZmZmatsaNGiA5OTk0qmSiIiIiKiEShxw9fT08ODBA7W2/DW2hd0mzNTU9PUqIyIiIiLSQokDbo0aNXDw4EG1tn379kGhUKBp06Ya/VNSUmBvb//6FRIRERERvYISB9yPPvoIV65cweDBg3HmzBls27YNy5cvh6mpKdq1a6fR/+jRo6hevXqpFktERERE9DIlDrhfffUV6tWrh9WrV6Nhw4bo2bMnMjMz8d1338HExESt78mTJ3H16lW0bt261AsmIiIiIipOiZ9kZmRkhKNHj2LBggU4fvw4rKys0LNnT3Tp0kWj76lTp9C1a9dCtxERERERvUkKIYQo6yKI3qbMzExYWFjAadRm6CiNy6yOG7M6ltm5iYiI3jf5P78zMjJgbm5ebN8SL1EgIiIiInofMOASERERkaww4BIRERGRrDDgEhEREZGsMOASERERkaww4BIRERGRrJT4PrhEcvPPlLYvvc0IERERvX84g0tEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESy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UlISXF1dUblyZaxbtw56em/3LeTk5OCbb77B9evXYWZmhqZNm+Lnn3/WuPMDEREREZWN93aJApG2uESBiIjo/fMqP7/f24vMiIiIiIgKw4BLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREssKAS0RERESywoBLRERERLLCgEtEREREsqJX1gUQvW1CCABAZmZmGVdCREREJZX/czv/53hxGHCp3Ll79y4AwMnJqYwrISIiolf18OFDWFhYFNuHAZfKHSsrKwBAUlLSS/8DKQ8yMzPh5OSEmzdvwtzcvKzLKXMcD3UcD3UcD3Ucj//hWKh7E+MhhMDDhw/h4ODw0r4MuFTu6Og8X3puYWHB/xMqwNzcnONRAMdDHcdDHcdDHcfjfzgW6kp7PEo6McWLzIiIiIhIVhhwiYiIiEhWGHCp3FEqlZg8eTKUSmVZl/JO4Hio43io43io43io43j8D8dCXVmPh0KU5F4LRERERETvCc7gEhEREZGsMOASERERkaww4BIRERGRrDDgEhEREZGsMOBSubNs2TK4urrC0NAQjRo1wp9//lnWJb0Vhw8fRufOneHg4ACFQoEdO3aobRdCIDQ0FA4ODjAyMoK/vz/OnTtXNsW+YTNnzsQHH3wAMzMzVKpUCd26dcOlS5fU+pSn8Vi+fDk8PDykG7L7+Pjgjz/+kLaXp7EozMyZM6FQKDBq1CiprTyNSWhoKBQKhdqXnZ2dtL08jUW+5ORkfPrpp7C2toaxsTEaNGiAuLg4aXt5GhMXFxeN7w+FQoEvv/wSQNmNBQMulSubNm3CqFGjMHHiRJw+fRrNmjVD+/btkZSUVNalvXGPHz9G/fr1sXTp0kK3z5kzB/Pnz8fSpUsRGxsLOzs7tG7dGg8fPnzLlb550dHR+PLLL3H8+HHs378fubm5aNOmDR4/fiz1KU/jUblyZcyaNQsnT57EyZMn0bJlS3Tt2lX6IVSexuJFsbGxWLVqFTw8PNTay9uY1KlTB6mpqdLX2bNnpW3lbSzu378PX19f6Ovr448//sD58+cxb948WFpaSn3K05jExsaqfW/s378fANCzZ08AZTgWgqgcady4sRgyZIham7u7u5gwYUIZVVQ2AIjt27dLr1UqlbCzsxOzZs2S2p4+fSosLCzEihUryqDCtys9PV0AENHR0UIIjocQQlSoUEGsWbOmXI/Fw4cPhZubm9i/f7/w8/MTI0eOFEKUv++PyZMni/r16xe6rbyNhRBCjB8/Xnz44YdFbi+PY1LQyJEjRbVq1YRKpSrTseAMLpUb2dnZiIuLQ5s2bdTa27Rpg2PHjpVRVe+GhIQEpKWlqY2NUqmEn59fuRibjIwMAICVlRWA8j0eeXl52LhxIx4/fgwfH59yPRZffvklOnbsiICAALX28jgmV65cgYODA1xdXdGnTx9cv34dQPkci99++w1eXl7o2bMnKlWqhIYNG2L16tXS9vI4Jvmys7Px008/ITg4GAqFokzHggGXyo07d+4gLy8Ptra2au22trZIS0sro6reDfnvvzyOjRACo0ePxocffoi6desCKJ/jcfbsWZiamkKpVGLIkCHYvn07ateuXS7HAgA2btyIU6dOYebMmRrbytuYeHt7Y8OGDdi7dy9Wr16NtLQ0NG3aFHfv3i13YwEA169fx/Lly+Hm5oa9e/diyJAhGDFiBDZs2ACg/H1/FLRjxw48ePAAn3/+OYCyHQu9N3p0oneQQqFQey2E0Ggrr8rj2AwbNgxnzpzBkSNHNLaVp/GoWbMm4uPj8eDBA2zduhVBQUGIjo6Wtpensbh58yZGjhyJffv2wdDQsMh+5WVM2rdvL/27Xr168PHxQbVq1bB+/Xo0adIEQPkZCwBQqVTw8vLCjBkzAAANGzbEuXPnsHz5cgQGBkr9ytOY5Fu7di3at28PBwcHtfayGAvO4FK5UbFiRejq6mr81pienq7x22V5k39FdHkbm+HDh+O3335DZGQkKleuLLWXx/EwMDBA9erV4eXlhZkzZ6J+/fpYtGhRuRyLuLg4pKeno1GjRtDT04Oenh6io6OxePFi6OnpSe+7PI1JQSYmJqhXrx6uXLlSLr8/7O3tUbt2bbW2WrVqSRcrl8cxAYDExEQcOHAAAwYMkNrKciwYcKncMDAwQKNGjaQrPPPt378fTZs2LaOq3g2urq6ws7NTG5vs7GxER0fLcmyEEBg2bBi2bduGQ4cOwdXVVW17eRuPwggh8OzZs3I5Fq1atcLZs2cRHx8vfXl5eaFfv36Ij49H1apVy92YFPTs2TNcuHAB9vb25fL7w9fXV+O2gpcvX4azszOA8vv/HxEREahUqRI6duwotZXpWLzRS9iI3jEbN24U+vr6Yu3ateL8+fNi1KhRwsTERNy4caOsS3vjHj58KE6fPi1Onz4tAIj58+eL06dPi8TERCGEELNmzRIWFhZi27Zt4uzZs+KTTz4R9vb2IjMzs4wrL31ffPGFsLCwEFFRUSI1NVX6ysrKkvqUp/EICQkRhw8fFgkJCeLMmTPim2++ETo6OmLfvn1CiPI1FkUpeBcFIcrXmIwZM0ZERUWJ69evi+PHj4tOnToJMzMz6f83y9NYCCHEX3/9JfT09MT06dPFlStXxM8//yyMjY3FTz/9JPUpb2OSl5cnqlSpIsaPH6+xrazGggGXyp0ffvhBODs7CwMDA+Hp6SndGkruIiMjBQCNr6CgICHE81vbTJ48WdjZ2QmlUimaN28uzp49W7ZFvyGFjQMAERERIfUpT+MRHBws/TdhY2MjWrVqJYVbIcrXWBTlxYBbnsakd+/ewt7eXujr6wsHBwfRo0cPce7cOWl7eRqLfDt37hR169YVSqVSuLu7i1WrVqltL29jsnfvXgFAXLp0SWNbWY2FQggh3uwcMRERERHR28M1uEREREQkKwy4RERERCQrDLhEREREJCsMuEREREQkKwy4RERERCQrDLhEREREJCsMuEREREQkKwy4REQy5eLiAhcXl7Iuo8Ru3LgBhUKBzz//vKxLkY2oqCgoFAqEhoaWdSlEbxUDLhHJXn5wKvhlYGAAJycn9O3bF2fOnNH62O9biKQ3w9/fHwqFoqzLeG+FhoZCoVAgKiqqrEshmdAr6wKIiN6WatWq4dNPPwUAPHr0CMePH8evv/6Kbdu24dChQ2jatGkZV1i6Dh48WNYlUBlr3LgxLly4gIoVK5Z1KURvFQMuEZUb1atX1/hT7bfffovp06dj4sSJiIyMLJvC3pBq1aqVdQlUxoyNjeHu7l7WZRC9dVyiQETl2vDhwwEAsbGxau3Z2dlYtGgRGjduDDMzM5iamqJ27doYPXo07t+/Ly17SExMRGJiotryh9dZ75i/5CEjIwNffPEF7O3tYWJigubNm+PUqVMAgLS0NAQFBaFSpUowNjZG27ZtcfXq1SKPVdDTp08xb9481K9fHxYWFjA1NUW1atXwySef4OzZs1I/lUqFNWvWoHHjxrCysoKxsTFcXFzQrVs3HD58WONchw8fRufOnVGxYkUolUq4ubnh22+/RVZWlkbfvLw8zJ49G9WrV4ehoSGqV6+OmTNnQqVSvfJ4PXz4EFOnToWHhwdMTExgYWGBhg0bYtKkScjJyVHre+zYMXTs2BFWVlYwNDSEu7s7QkNDC61RoVDA398ft2/fRnBwMCpVqgQjIyM0adJE48/oCoUC0dHR0r/zvwquJQ4PD0fXrl3h4uICQ0NDWFlZoW3btoX+UlVw3eyxY8fQokULmJmZwcbGBkOHDsWTJ08AAHv27IGvry9MTExga2uL8ePHIy8vr8hjFZT/vfH48WOMHj0ajo6OUCqV8PDwwJYtWzRqunz5MsaNGwdPT09YW1vD0NAQNWrUwIQJE/Do0SON/vlLNnJzcxEWFgZXV1colUrUqFEDy5Yt0+g7ZcoUAECLFi2k8Sv4vXvlyhX0798frq6uMDQ0RMWKFeHp6YkxY8ZonJsI4AwuEZVzha2bfPr0Kdq2bYvDhw/Dzc0N/fv3h1KpxJUrV7BixQoEBgbCxcUFkydPxsKFCwEAo0aNkvb39/d/rZqys7PRunVrPH36FL1798a///6LzZs3IyAgAMeOHUO7du1gZ2eHTz/9FFevXsXOnTvRqVMnnDt3Drq6usUeOygoCJs3b4aHh4f0vpKSkhAZGYm2bduiXr16AICQkBDMmTMH1apVQ9++fWFmZobk5GT8+eefOHToEJo3by4dc8WKFRg6dCgqVKiAzp07w8bGBrGxsZg+fToiIyMRGRkJAwMDqf+gQYMQHh4OV1dXfPnll3j69Cnmz5+PY8eOvdI43blzB35+fjh//jwaNGiAIUOGQKVS4eLFi5g9ezbGjBkDS0tLAMDWrVvRp08fGBgYoHfv3qhUqRIOHDiAKVOmYN++fYiMjIRSqVQ7/oMHD+Dr6wtzc3P069cP6enp2LRpE9q2bYu4uDjUrVsXADB58mSsW7cOiYmJmDx5srR/gwYNpH9/+eWXqF+/PgICAmBjY4Pk5GTs2LEDAQEB2LZtG7p27arx/k6cOIHZs2ejbdu2GDx4MCIjI7F8+XJkZmaia9euCAoKQpcuXeDt7Y3ff/8dc+bMgbm5OSZOnFii8cvJyUGbNm1w79499OjRA1lZWdi4cSN69eqFPXv2oE2bNlLfbdu2Ye3atWjRogX8/f2hUqlw/PhxzJ49G9HR0Th8+DD09fU1zvHJJ5/gxIkTaN++PXR1dbF582Z8+eWX0NfXx8CBAwFA+kUgOjoaQUFBUrDN/+xSUlLQuHFjPH78GB07dkTv3r3x6NEjXLlyBUuWLMG8efNK9H6pnBFERDKXkJAgAIi2bdtqbJs4caIAIPz9/aW2sWPHCgDis88+E7m5uWr9Hzx4IB4+fCi9dnZ2Fs7OzqVWq7OzswAgevbsKXJycqT2WbNmCQDC0tJSfPXVV0KlUknbvvjiCwFAbNu2TeNYBWt78OCBUCgUwsvLS+N95ebmivv370uvrayshKOjo3j8+LFaP5VKJe7evSu9PnfunNDT0xMNGzZUaxdCiJkzZwoAYu7cuVJbZGSkACDq168vHj16JLXfunVLVKxYUQAQQUFBLx8oIUTPnj0FAPHNN99obEtLS5PGLzMzU1haWgqlUin+/vtvtffSt29fAUCEhYWp7Q9AABBDhw4VeXl5UvuaNWsEADF48GC1/n5+fqK4H6nXr1/XaEtJSREODg7Czc1NrT1/jACIHTt2SO3Z2dnCw8NDKBQKUbFiRfHXX39J2zIzM0WlSpWEtbW12vdN/rEmT56sdo7877OuXbuKZ8+eSe0HDhwo9L+VW7duqfXLN2XKFAFA/PTTT4WOh7e3t8jIyJDaL168KPT09ETNmjXV+k+ePFkAEJGRkRrnWLx4sQAgFi1apLHt9u3bGm1EQgjBgEtEspcfcKtVqyYmT54sJk+eLMaMGSN8fX0FAGFoaCiOHTsmhHge9MzNzYWFhYW4d+/eS4/9pgLujRs31NqTkpIEAGFqaqoWDIUQ4vDhw0WGmIK1ZWRkCADC19f3pXVYWVkJV1fXQkNNQSNGjBAAxJ9//qmxLS8vT9jY2IhGjRpJbf379xcAxNatWzX6h4WFlTjgpqWlCYVCIapVqyays7OL7bthwwYBQHzxxRca25KSkoSenp6oVq2aWjsAYWJiovbLjBBC5OTkCD09PeHp6anW/rKAW5Thw4drfN75obTgL135pk6dKgCI/v37a2wLDg4WAERCQoLGsYoKuIUFb2dnZ2FlZVWi+u/evSsAiM8//1ytPX88Dh06pLFP/rbMzEyprSQBd9WqVSWqiUgIIbhEgYjKjWvXrklr/fT19WFra4u+fftiwoQJ0p/mL168iMzMTAQEBKBChQplUqelpSWcnZ3V2uzt7QEAbm5uMDExKXRbcnJyscc1NzdHu3btsGfPHnh6euLjjz9Gs2bN4O3trbaEAAB69eqFFStWoG7duujduzf8/Pzg4+Ojce7jx48DeL4e9MCBAxrn1NfXx8WLF6XXf//9NwCgWbNmGn0LayvKyZMnIYRAixYtCv3TeEGnT58GUPjSEScnJ1SrVg2XLl3Cw4cPYWZmJm1zc3ODqampWn89PT3Y2triwYMHJa4VAK5fv46ZM2fi0KFDSE5OxrNnz9S2p6SkaHzmDRs21DhO/mddcPnDi9uSk5NLdOs6S0tLuLq6arRXrlwZMTExam1CCERERGDdunX4559/kJGRobZmOiUlpdBzeHp6Fnp84PkSkILjXZROnTphwoQJ+PLLL7F//360a9cOH374IWrUqPHSfan8YsAlonKjbdu22LNnT7F98oOLo6PjW6iocBYWFhptenrP/+/a3Ny8yG0vXlRVmC1btmDGjBn49ddfpbWaZmZmCA4OxowZM2BsbAwAWLx4MapWrYp169Zh2rRpmDZtGgwNDdGrVy/MmzdPuu3UvXv3AADTp08v0XvLyMiAjo5OobetsrW1LdExgFf7nDIzM4s9vp2dHS5duoTMzEy1wFXY5wA8H+8XL+YqztWrV9G4cWNkZmaiRYsW6Ny5M8zNzaGjo4OoqChER0drBF6g+M/6db8PgOLf34sX/I0YMQJLly6Fk5MTunTpAnt7e2nN8pQpUwqtv6hz5NdZ0jF0dXVFTEwMpkyZgj/++AP/93//BwCoWbMmwsLC0LNnzxIdh8oXBlwiogLyL2x52Wzo+8rExATTp0/H9OnTkZCQgMjISKxYsQKLFi3CkydPsHLlSgDPZ17Hjh2LsWPHIiUlBdHR0YiIiMCGDRuQlpaGvXv3Avhf0HoxHBbFwsICKpUKd+7cgY2Njdq2f//9t8Tv41U+p/waizp+fnthobE0LFiwAPfv38dPP/2Efv36qW0bMmSIdAeGd1V6ejp++OEHeHh4ICYmRvolCHh+R4/8v4q8SR4eHti6dStycnIQFxeHP/74A4sXL0bv3r3h4OAAX1/fN14DvV94mzAiogJq1qwJc3NzxMbG4v79+y/tr6ur+0qzee8SV1dXBAcHIzo6Gqampvjtt98K7efg4IBPPvkEe/bsgZubGw4cOCDdqsrb2xvA/5YqvEz9+vUBAH/++afGtsLaiuLl5QUdHR1ERka+dMYy/0/9hT0lKzk5GdeuXUPVqlVLFNCLkn/3isK+F65duwYA6NKli1q7SqXC0aNHtT7n23L9+nUIIRAQEKAWboFX+8yKU9z4FaSvr48mTZpgypQpWLx4MYQQ2LVrV6nUQPLCgEtEVICenh4GDx6MjIwMjBw5UuMHbkZGhtp9P62srHDnzh08ffq00ONdu3YNFy9eLPGfjd+k27dv46+//tJov3//Pp49ewYjIyMAwLNnz3Do0CEIIdT6PX78GA8fPoS+vr4USIYOHQo9PT0MHz4cN2/e1Dj2gwcPpDWwABAYGAgAmDp1Kh4/fiy1JycnY9GiRSV+L7a2tvjoo4/U1lUXlJ6ejtzcXABA165dYWFhgYiICJw7d07qI4RASEgIcnJy1O5Zqw0rKysAwK1btzS25a+tPXLkiFr77Nmz8c8//7zWed+G/PqPHTumtnTh1q1bmDBhQqmco7jxi42NRXp6ukZ7/sx7/vctUUFcokBE9IKpU6fi+PHj+PHHH3H8+HG0b98eSqUS169fx549e3DkyBHpIp+WLVvi5MmT6Ny5M5o1awYDAwN8+OGH+PDDDwEArVq1QmJiIhISEkp04c+blJycDG9vb9SpUweenp5wdHTE3bt38d///hc5OTkYN24cAODJkydo1aoVqlatCm9vb1SpUgWPHj3Crl27kJaWhvHjx0sXpdWtWxfLli3DF198gZo1a6JDhw6oVq0aMjMzcf36dURHR+Pzzz/HihUrADy/0Kt///6IiIhAvXr10L17dzx79gybNm1CkyZNXmk2btmyZfjnn38wffp07N69Gy1btoQQApcvX8a+ffvw77//wtLSEubm5li9ejU++eQTeHt7o3fv3rCxscHBgwdx8uRJNG7cGGPHjn2tsW3ZsiW2bNmCnj17okOHDjA0NES9evXQsWNHDBkyBBEREejRowd69+4Na2trHD9+HKdOnULHjh3x+++/v9a53zR7e3t89NFH2Lp1K7y8vNCqVSv8+++/2LVrF1q2bInr16+/9jnyH/AwceJEXLx4ERYWFrCwsMAXX3yBn3/+GcuWLYO/vz+qV68Oc3NznD9/Hrt370bFihURHBxcCu+SZKcM7+BARPRWFHcf3KI8ffpUzJ07VzRo0EAYGRkJU1NTUbt2bTFmzBi1+8U+fPhQDBw4UNjb2wsdHR2NWzLl346p4K2bilPcbccACD8/vyLf34u313rxWPfv3xehoaGiefPmwt7eXhgYGAgHBwfRrl07sXfvXqlfdna2mD17tmjTpo2oXLmyMDAwELa2tsLPz09s3Lix0Nr++usv0adPH+Hg4CD09fVFxYoVhaenp5gwYYK4cOGCWt/c3Fwxc+ZMUbVqVWFgYCCqVq0qZsyYIa5evfpK98EV4vmtzyZNmiTc3d2FUqkUFhYWokGDBuK7777TuH3Y4cOHRfv27YWlpaUwMDAQNWrUEJMmTdK47ZoQRY+1EIV/Rjk5OWLcuHGiSpUqQk9PT+N9REZGCl9fX2FmZiYsLS1Fhw4dRFxcXKG3xyrq1l5CCBERESEAiIiICI1tr3Ks4r7PCrvl2cOHD8WYMWOEi4uLUCqVws3NTYSFhYns7OxCx6q426YFBQUV+t/EunXrRL169YRSqRQApPqOHz8uBg8eLOrWrSssLS2FkZGRcHNzEyNGjBBJSUmFnoNIIcQLf4MiIiIiInqPcQ0uEREREckKAy4RERERyQoDLhERERHJCgMuEREREckKAy4RERERyQoDLhERERHJCgMuEREREckKAy4RERERyQoDLhERERHJCgMuEREREckKAy4RERERyQoDLhERERHJCgMuEREREcnK/wPK3dOg9IdEyAAAAABJRU5ErkJggg==",
+ "text/plain": [
+ "