diff --git a/content/02_model_code/04_model.ipynb b/content/02_model_code/04_model.ipynb index 078b224..0a42e4b 100644 --- a/content/02_model_code/04_model.ipynb +++ b/content/02_model_code/04_model.ipynb @@ -492,22 +492,110 @@ " \n", " Passed to a model and its process classes\n", " '''\n", - " def __init__(self, random_number_set=DEFAULT_RNG_SET):\n", + " def __init__(self, random_number_set=DEFAULT_RNG_SET,\n", + " n_triage=DEFAULT_N_TRIAGE,\n", + " n_reg=DEFAULT_N_REG,\n", + " n_exam=DEFAULT_N_EXAM,\n", + " n_trauma=DEFAULT_N_TRAUMA,\n", + " n_cubicles_1=DEFAULT_N_CUBICLES_1,\n", + " n_cubicles_2=DEFAULT_N_CUBICLES_2,\n", + " triage_mean=DEFAULT_TRIAGE_MEAN,\n", + " reg_mean=DEFAULT_REG_MEAN,\n", + " reg_var=DEFAULT_REG_VAR,\n", + " exam_mean=DEFAULT_EXAM_MEAN,\n", + " exam_var=DEFAULT_EXAM_VAR,\n", + " trauma_mean=DEFAULT_TRAUMA_MEAN,\n", + " trauma_treat_mean=DEFAULT_TRAUMA_TREAT_MEAN,\n", + " trauma_treat_var=DEFAULT_TRAUMA_TREAT_VAR,\n", + " non_trauma_treat_mean=DEFAULT_NON_TRAUMA_TREAT_MEAN,\n", + " non_trauma_treat_var=DEFAULT_NON_TRAUMA_TREAT_VAR,\n", + " non_trauma_treat_p=DEFAULT_NON_TRAUMA_TREAT_P,\n", + " prob_trauma=DEFAULT_PROB_TRAUMA):\n", " '''\n", - " The init method sets up our defaults.\n", + " Create a scenario to parameterise the simulation model\n", " \n", " Parameters:\n", " -----------\n", " random_number_set: int, optional (default=DEFAULT_RNG_SET)\n", " Set to control the initial seeds of each stream of pseudo\n", " random numbers used in the model.\n", + " \n", + " n_triage: int\n", + " The number of triage cubicles\n", + " \n", + " n_reg: int\n", + " The number of registration clerks\n", + " \n", + " n_exam: int\n", + " The number of examination rooms\n", + " \n", + " n_trauma: int\n", + " The number of trauma bays for stablisation\n", + " \n", + " n_cubicles_1: int\n", + " The number of non-trauma treatment cubicles\n", + " \n", + " n_cubicles_2: int\n", + " The number of trauma treatment cubicles\n", + " \n", + " triage_mean: float\n", + " Mean duration of the triage distribution (Exponential)\n", + " \n", + " reg_mean: float\n", + " Mean duration of the registration distribution (Lognormal)\n", + " \n", + " reg_var: float\n", + " Variance of the registration distribution (Lognormal)\n", + " \n", + " exam_mean: float\n", + " Mean of the examination distribution (Normal)\n", + " \n", + " exam_var: float\n", + " Variance of the examination distribution (Normal)\n", + " \n", + " trauma_mean: float\n", + " Mean of the trauma stabilisation distribution (Exponential)\n", + " \n", + " trauma_treat_mean: float\n", + " Mean of the trauma cubicle treatment distribution (Lognormal)\n", + " \n", + " trauma_treat_var: float\n", + " Variance of the trauma cubicle treatment distribution (Lognormal)\n", + " \n", + " non_trauma_treat_mean: float\n", + " Mean of the non trauma treatment distribution\n", + " \n", + " non_trauma_treat_var: float\n", + " Variance of the non trauma treatment distribution\n", + " \n", + " non_trauma_treat_p: float\n", + " Probability non trauma patient requires treatment\n", + " \n", + " prob_trauma: float\n", + " probability that a new arrival is a trauma patient.\n", " '''\n", " # sampling\n", " self.random_number_set = random_number_set\n", + " \n", + " # store parameters for sampling\n", + " self.triage_mean = triage_mean\n", + " self.reg_mean = reg_mean\n", + " self.reg_var = reg_var\n", + " self.exam_mean= exam_mean\n", + " self.exam_var = exam_var\n", + " self.trauma_mean = trauma_mean\n", + " self.trauma_treat_mean = trauma_treat_mean\n", + " self.trauma_treat_var = trauma_treat_var\n", + " self.non_trauma_treat_mean = non_trauma_treat_mean\n", + " self.non_trauma_treat_var = non_trauma_treat_var\n", + " self.non_trauma_treat_p = non_trauma_treat_p\n", + " self.prob_trauma = prob_trauma\n", + " \n", " self.init_sampling()\n", " \n", " # count of each type of resource\n", - " self.init_resourse_counts()\n", + " self.init_resourse_counts(n_triage, n_reg, n_exam, n_trauma,\n", + " n_cubicles_1, n_cubicles_2)\n", " \n", " def set_random_no_set(self, random_number_set):\n", " '''\n", @@ -521,18 +609,19 @@ " self.random_number_set = random_number_set\n", " self.init_sampling()\n", "\n", - " def init_resourse_counts(self):\n", + " def init_resourse_counts(self, n_triage, n_reg, n_exam, n_trauma,\n", + " n_cubicles_1, n_cubicles_2):\n", " '''\n", " Init the counts of resources to default values...\n", " '''\n", - " self.n_triage = DEFAULT_N_TRIAGE\n", - " self.n_reg = DEFAULT_N_REG\n", - " self.n_exam = DEFAULT_N_EXAM\n", - " self.n_trauma = DEFAULT_N_TRAUMA\n", + " self.n_triage = n_triage\n", + " self.n_reg = n_reg\n", + " self.n_exam = n_exam\n", + " self.n_trauma = n_trauma\n", " \n", " # non-trauma (1), trauma (2) treatment cubicles\n", - " self.n_cubicles_1 = DEFAULT_N_CUBICLES_1\n", - " self.n_cubicles_2 = DEFAULT_N_CUBICLES_2\n", + " self.n_cubicles_1 = n_cubicles_1\n", + " self.n_cubicles_2 = n_cubicles_2\n", "\n", " def init_sampling(self):\n", " '''\n", @@ -546,40 +635,40 @@ " # create distributions\n", " \n", " # Triage duration\n", - " self.triage_dist = Exponential(DEFAULT_TRIAGE_MEAN, \n", + " self.triage_dist = Exponential(self.triage_mean, \n", " random_seed=self.seeds[0])\n", " \n", " # Registration duration (non-trauma only)\n", - " self.reg_dist = Lognormal(DEFAULT_REG_MEAN, \n", - " np.sqrt(DEFAULT_REG_VAR),\n", + " self.reg_dist = Lognormal(self.reg_mean, \n", + " np.sqrt(self.reg_var),\n", " random_seed=self.seeds[1])\n", " \n", " # Evaluation (non-trauma only)\n", - " self.exam_dist = Normal(DEFAULT_EXAM_MEAN,\n", - " np.sqrt(DEFAULT_EXAM_VAR),\n", + " self.exam_dist = Normal(self.exam_mean,\n", + " np.sqrt(self.exam_var),\n", " random_seed=self.seeds[2])\n", " \n", " # Trauma/stablisation duration (trauma only)\n", - " self.trauma_dist = Exponential(DEFAULT_TRAUMA_MEAN, \n", + " self.trauma_dist = Exponential(self.trauma_mean, \n", " random_seed=self.seeds[3])\n", " \n", " # Non-trauma treatment\n", - " self.nt_treat_dist = Lognormal(DEFAULT_NON_TRAUMA_TREAT_MEAN, \n", - " np.sqrt(DEFAULT_NON_TRAUMA_TREAT_VAR),\n", + " self.nt_treat_dist = Lognormal(self.non_trauma_treat_mean, \n", + " np.sqrt(self.non_trauma_treat_var),\n", " random_seed=self.seeds[4])\n", " \n", " # treatment of trauma patients\n", - " self.treat_dist = Lognormal(DEFAULT_TRAUMA_TREAT_MEAN, \n", - " np.sqrt(DEFAULT_TRAUMA_TREAT_VAR),\n", + " self.treat_dist = Lognormal(self.trauma_treat_mean, \n", + " np.sqrt(self.non_trauma_treat_var),\n", " random_seed=self.seeds[5])\n", " \n", " # probability of non-trauma patient requiring treatment\n", - " self.nt_p_treat_dist = Bernoulli(DEFAULT_NON_TRAUMA_TREAT_P, \n", + " self.nt_p_treat_dist = Bernoulli(self.non_trauma_treat_p, \n", " random_seed=self.seeds[6])\n", " \n", " \n", " # probability of non-trauma versus trauma patient\n", - " self.p_trauma_dist = Bernoulli(DEFAULT_PROB_TRAUMA, \n", + " self.p_trauma_dist = Bernoulli(self.prob_trauma, \n", " random_seed=self.seeds[7])\n", " \n", " # init sampling for non-stationary poisson process\n", @@ -752,7 +841,7 @@ "metadata": {}, "outputs": [], "source": [ - "class NonTraumaPathway(object):\n", + "class NonTraumaPathway:\n", " '''\n", " Encapsulates the process a patient with minor injuries and illness.\n", " \n", @@ -1536,8 +1625,8 @@ "text": [ "Running multiple replications => done.\n", "\n", - "CPU times: user 2.52 s, sys: 42.7 ms, total: 2.56 s\n", - "Wall time: 3.88 s\n" + "CPU times: user 2.09 s, sys: 12.9 ms, total: 2.11 s\n", + "Wall time: 3.46 s\n" ] }, { @@ -1821,20 +1910,16 @@ " scenarios['base'] = Scenario()\n", " \n", " # extra triage capacity\n", - " scenarios['triage+1'] = Scenario()\n", - " scenarios['triage+1'].n_triage += 1\n", + " scenarios['triage+1'] = Scenario(n_triage=DEFAULT_N_TRIAGE+1)\n", " \n", " # extra examination capacity\n", - " scenarios['exam+1'] = Scenario()\n", - " scenarios['exam+1'].n_exam += 1\n", + " scenarios['exam+1'] = Scenario(n_exam=DEFAULT_N_EXAM+1)\n", " \n", " # extra non-trauma treatment capacity\n", - " scenarios['treat+1'] = Scenario()\n", - " scenarios['treat+1'].n_cubicles_1 += 1\n", + " scenarios['treat+1'] = Scenario(n_cubicles_1=DEFAULT_N_CUBICLES_1+1)\n", " \n", - " scenarios['triage+exam'] = Scenario()\n", - " scenarios['triage+exam'].n_triage += 1\n", - " scenarios['triage+exam'].n_exam += 1\n", + " scenarios['triage+exam'] = Scenario(n_triage=DEFAULT_N_TRIAGE+1,\n", + " n_exam=DEFAULT_N_EXAM+1)\n", " \n", " return scenarios" ] @@ -2170,7 +2255,7 @@ }, { "cell_type": "code", - "execution_count": 91, + "execution_count": 26, "id": "4d2d0e59", "metadata": {}, "outputs": [ @@ -2272,7 +2357,7 @@ "5 Trauma treatment 168.27 209.12 195.16 150.37 193.69" ] }, - "execution_count": 91, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -2298,7 +2383,7 @@ }, { "cell_type": "code", - "execution_count": 123, + "execution_count": 27, "id": "e6453c53", "metadata": {}, "outputs": [ diff --git a/src/requirements.txt b/src/requirements.txt index 39f94b1..1dfdeff 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,5 +1,5 @@ - matplotlib==3.3.4 - numpy==1.19.2 - pandas==1.2.3 - scipy==1.6.1 - simpy==4.0.1 + matplotlib>=3.3.4 + numpy>=1.19.2 + pandas>=1.2.3 + scipy>=1.6.1 + simpy>=4.0.1 diff --git a/src/test_pacakge.ipynb b/src/test_pacakge.ipynb deleted file mode 100644 index e69de29..0000000 diff --git a/src/test_package.ipynb b/src/test_package.ipynb new file mode 100644 index 0000000..a492577 --- /dev/null +++ b/src/test_package.ipynb @@ -0,0 +1,613 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6b983b2d-37be-4418-a71c-3f61bcd09f82", + "metadata": {}, + "source": [ + "# Test package\n", + "\n", + "This notebook is a simple test script for the simulation model." + ] + }, + { + "cell_type": "markdown", + "id": "b67e319d-7f3f-42a2-9f2e-176a6bbb0a43", + "metadata": {}, + "source": [ + "# Aggregate test: run all scenarios" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "cf77eab0-8038-4e89-b0a8-abae02c61046", + "metadata": {}, + "outputs": [], + "source": [ + "from treat_sim.model import (get_scenarios, run_scenario_analysis,\n", + " scenario_summary_frame, \n", + " DEFAULT_RESULTS_COLLECTION_PERIOD)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "a4427a5c-a048-4e78-81ad-9a72a62b982f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Scenario Analysis\n", + "No. Scenario: 6\n", + "Replications: 50\n", + "Running base => done.\n", + "\n", + "Running triage+1 => done.\n", + "\n", + "Running exam+1 => done.\n", + "\n", + "Running treat+1 => done.\n", + "\n", + "Running swap_exam_treat => done.\n", + "\n", + "Running short_exam => done.\n", + "\n", + "Scenario analysis complete.\n" + ] + } + ], + "source": [ + "results = run_scenario_analysis(get_scenarios(), DEFAULT_RESULTS_COLLECTION_PERIOD,\n", + " n_reps=50)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "42d1d046-102e-4edc-8f22-98ea40429e27", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
basetriage+1exam+1treat+1swap_exam_treatshort_exam
00_arrivals223.900000223.900000223.900000223.900000223.900000223.900000
01a_triage_wait35.2726401.59108235.27264035.2726401.5910821.591082
01b_triage_util0.5839450.2919720.5839450.5839450.2919720.291972
02a_registration_wait106.992158136.547677106.992158106.992158136.547677136.547677
02b_registration_util0.8305710.8372940.8305710.8305710.8372940.837294
03a_examination_wait27.52711928.2386460.15053327.527119156.24335470.804411
03b_examination_util0.8420100.8449210.6624850.8420100.8854130.865748
04a_treatment_wait(non_trauma)141.596946145.386882158.2896412.53900733.407448116.539079
04b_treatment_util(non_trauma)0.8511110.8521510.8532780.6274360.8305020.855542
05_total_time(non-trauma)240.195093237.010351228.377890195.550827288.135496251.677548
06a_trauma_wait100.379713123.372108100.379713100.379713123.372108123.372108
06b_trauma_util0.7868210.7866660.7868210.7868210.7866660.786666
07a_treatment_wait(trauma)199.937931233.482451199.937931199.937931233.482451233.482451
07b_treatment_util(trauma)0.8792200.8991720.8792200.8792200.8991720.899172
08_total_time(trauma)418.140509430.158680418.140509418.140509430.158680430.158680
09_throughput151.500000151.400000155.500000185.700000127.800000145.400000
\n", + "
" + ], + "text/plain": [ + " base triage+1 exam+1 \\\n", + "00_arrivals 223.900000 223.900000 223.900000 \n", + "01a_triage_wait 35.272640 1.591082 35.272640 \n", + "01b_triage_util 0.583945 0.291972 0.583945 \n", + "02a_registration_wait 106.992158 136.547677 106.992158 \n", + "02b_registration_util 0.830571 0.837294 0.830571 \n", + "03a_examination_wait 27.527119 28.238646 0.150533 \n", + "03b_examination_util 0.842010 0.844921 0.662485 \n", + "04a_treatment_wait(non_trauma) 141.596946 145.386882 158.289641 \n", + "04b_treatment_util(non_trauma) 0.851111 0.852151 0.853278 \n", + "05_total_time(non-trauma) 240.195093 237.010351 228.377890 \n", + "06a_trauma_wait 100.379713 123.372108 100.379713 \n", + "06b_trauma_util 0.786821 0.786666 0.786821 \n", + "07a_treatment_wait(trauma) 199.937931 233.482451 199.937931 \n", + "07b_treatment_util(trauma) 0.879220 0.899172 0.879220 \n", + "08_total_time(trauma) 418.140509 430.158680 418.140509 \n", + "09_throughput 151.500000 151.400000 155.500000 \n", + "\n", + " treat+1 swap_exam_treat short_exam \n", + "00_arrivals 223.900000 223.900000 223.900000 \n", + "01a_triage_wait 35.272640 1.591082 1.591082 \n", + "01b_triage_util 0.583945 0.291972 0.291972 \n", + "02a_registration_wait 106.992158 136.547677 136.547677 \n", + "02b_registration_util 0.830571 0.837294 0.837294 \n", + "03a_examination_wait 27.527119 156.243354 70.804411 \n", + "03b_examination_util 0.842010 0.885413 0.865748 \n", + "04a_treatment_wait(non_trauma) 2.539007 33.407448 116.539079 \n", + "04b_treatment_util(non_trauma) 0.627436 0.830502 0.855542 \n", + "05_total_time(non-trauma) 195.550827 288.135496 251.677548 \n", + "06a_trauma_wait 100.379713 123.372108 123.372108 \n", + "06b_trauma_util 0.786821 0.786666 0.786666 \n", + "07a_treatment_wait(trauma) 199.937931 233.482451 233.482451 \n", + "07b_treatment_util(trauma) 0.879220 0.899172 0.899172 \n", + "08_total_time(trauma) 418.140509 430.158680 430.158680 \n", + "09_throughput 185.700000 127.800000 145.400000 " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "scenario_summary_frame(results)" + ] + }, + { + "cell_type": "markdown", + "id": "9dacbdbe-2d3a-4eb9-b6d4-6976291ddec3", + "metadata": {}, + "source": [ + "## Test: single scenario" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "cda7e07f-7ab7-45a9-9559-62073c3a4fc0", + "metadata": {}, + "outputs": [], + "source": [ + "from treat_sim.model import Scenario, multiple_replications" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "cdb93109-1054-4493-b4c6-743d70be8a8c", + "metadata": {}, + "outputs": [], + "source": [ + "base_case = Scenario()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "f1b2bdd9-4015-49db-9ca7-92c32c70935e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
countmeanstdmin25%50%75%max
00_arrivals5.0224.2022.59188.00218.00233.00236.00246.00
01a_triage_wait5.027.7923.653.2413.0428.0129.2565.41
01b_triage_util5.00.560.070.480.530.540.620.65
02a_registration_wait5.0112.5334.7163.3191.14128.49130.09149.64
02b_registration_util5.00.830.050.750.830.840.850.88
03a_examination_wait5.026.989.3116.3318.4028.4835.4236.25
03b_examination_util5.00.840.030.800.820.850.850.88
04a_treatment_wait(non_trauma)5.0145.0116.96125.02134.20145.41150.89169.50
04b_treatment_util(non_trauma)5.00.850.010.830.840.850.850.86
05_total_time(non-trauma)5.0236.6443.75178.80206.95247.87260.80288.80
06a_trauma_wait5.0109.0786.618.6065.1578.13168.01225.47
06b_trauma_util5.00.780.240.370.820.840.880.98
07a_treatment_wait(trauma)5.0161.30102.6813.2495.60214.20231.60251.84
07b_treatment_util(trauma)5.00.960.240.650.780.981.191.19
08_total_time(trauma)5.0377.2223.66339.82369.28385.75392.06399.20
09_throughput5.0151.408.08139.00148.00154.00157.00159.00
\n", + "
" + ], + "text/plain": [ + " count mean std min 25% 50% \\\n", + "00_arrivals 5.0 224.20 22.59 188.00 218.00 233.00 \n", + "01a_triage_wait 5.0 27.79 23.65 3.24 13.04 28.01 \n", + "01b_triage_util 5.0 0.56 0.07 0.48 0.53 0.54 \n", + "02a_registration_wait 5.0 112.53 34.71 63.31 91.14 128.49 \n", + "02b_registration_util 5.0 0.83 0.05 0.75 0.83 0.84 \n", + "03a_examination_wait 5.0 26.98 9.31 16.33 18.40 28.48 \n", + "03b_examination_util 5.0 0.84 0.03 0.80 0.82 0.85 \n", + "04a_treatment_wait(non_trauma) 5.0 145.01 16.96 125.02 134.20 145.41 \n", + "04b_treatment_util(non_trauma) 5.0 0.85 0.01 0.83 0.84 0.85 \n", + "05_total_time(non-trauma) 5.0 236.64 43.75 178.80 206.95 247.87 \n", + "06a_trauma_wait 5.0 109.07 86.61 8.60 65.15 78.13 \n", + "06b_trauma_util 5.0 0.78 0.24 0.37 0.82 0.84 \n", + "07a_treatment_wait(trauma) 5.0 161.30 102.68 13.24 95.60 214.20 \n", + "07b_treatment_util(trauma) 5.0 0.96 0.24 0.65 0.78 0.98 \n", + "08_total_time(trauma) 5.0 377.22 23.66 339.82 369.28 385.75 \n", + "09_throughput 5.0 151.40 8.08 139.00 148.00 154.00 \n", + "\n", + " 75% max \n", + "00_arrivals 236.00 246.00 \n", + "01a_triage_wait 29.25 65.41 \n", + "01b_triage_util 0.62 0.65 \n", + "02a_registration_wait 130.09 149.64 \n", + "02b_registration_util 0.85 0.88 \n", + "03a_examination_wait 35.42 36.25 \n", + "03b_examination_util 0.85 0.88 \n", + "04a_treatment_wait(non_trauma) 150.89 169.50 \n", + "04b_treatment_util(non_trauma) 0.85 0.86 \n", + "05_total_time(non-trauma) 260.80 288.80 \n", + "06a_trauma_wait 168.01 225.47 \n", + "06b_trauma_util 0.88 0.98 \n", + "07a_treatment_wait(trauma) 231.60 251.84 \n", + "07b_treatment_util(trauma) 1.19 1.19 \n", + "08_total_time(trauma) 392.06 399.20 \n", + "09_throughput 157.00 159.00 " + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "multiple_replications(base_case).describe().round(2).T" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.8.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/src/treat_sim/__init__.py b/src/treat_sim/__init__.py index 63755d2..986ae5e 100644 --- a/src/treat_sim/__init__.py +++ b/src/treat_sim/__init__.py @@ -1,2 +1,2 @@ __author__ = 'T.Monks' -__version__ = '0.1.0' +__version__ = '1.0.0' diff --git a/src/treat_sim/model.py b/src/treat_sim/model.py index 086cb94..d911574 100644 --- a/src/treat_sim/model.py +++ b/src/treat_sim/model.py @@ -159,39 +159,117 @@ def trace(msg): # ## Model parameterisation - class Scenario: ''' Container class for scenario parameters/arguments - - For convienience a container class is used to hold the large number of model - parameters. The `Scenario` class includes defaults these can easily be - changed and at runtime to experiments with different designs. Passed to a model and its process classes ''' - def __init__(self, random_number_set=DEFAULT_RNG_SET): + def __init__(self, random_number_set=DEFAULT_RNG_SET, + n_triage=DEFAULT_N_TRIAGE, + n_reg=DEFAULT_N_REG, + n_exam=DEFAULT_N_EXAM, + n_trauma=DEFAULT_N_TRAUMA, + n_cubicles_1=DEFAULT_N_CUBICLES_1, + n_cubicles_2=DEFAULT_N_CUBICLES_2, + triage_mean=DEFAULT_TRIAGE_MEAN, + reg_mean=DEFAULT_REG_MEAN, + reg_var=DEFAULT_REG_VAR, + exam_mean=DEFAULT_EXAM_MEAN, + exam_var=DEFAULT_EXAM_VAR, + trauma_mean=DEFAULT_TRAUMA_MEAN, + trauma_treat_mean=DEFAULT_TRAUMA_TREAT_MEAN, + trauma_treat_var=DEFAULT_TRAUMA_TREAT_VAR, + non_trauma_treat_mean=DEFAULT_NON_TRAUMA_TREAT_MEAN, + non_trauma_treat_var=DEFAULT_NON_TRAUMA_TREAT_VAR, + non_trauma_treat_p=DEFAULT_NON_TRAUMA_TREAT_P, + prob_trauma=DEFAULT_PROB_TRAUMA): ''' - The init method sets up our defaults. + Create a scenario to parameterise the simulation model Parameters: ----------- random_number_set: int, optional (default=DEFAULT_RNG_SET) Set to control the initial seeds of each stream of pseudo random numbers used in the model. + + n_triage: int + The number of triage cubicles + + n_reg: int + The number of registration clerks + + n_exam: int + The number of examination rooms + + n_trauma: int + The number of trauma bays for stablisation + + n_cubicles_1: int + The number of non-trauma treatment cubicles + + n_cubicles_2: int + The number of trauma treatment cubicles + + triage_mean: float + Mean duration of the triage distribution (Exponential) + + reg_mean: float + Mean duration of the registration distribution (Lognormal) + + reg_var: float + Variance of the registration distribution (Lognormal) + + exam_mean: float + Mean of the examination distribution (Normal) + + exam_var: float + Variance of the examination distribution (Normal) + + trauma_mean: float + Mean of the trauma stabilisation distribution (Exponential) + + trauma_treat_mean: float + Mean of the trauma cubicle treatment distribution (Lognormal) + + trauma_treat_var: float + Variance of the trauma cubicle treatment distribution (Lognormal) + + non_trauma_treat_mean: float + Mean of the non trauma treatment distribution + + non_trauma_treat_var: float + Variance of the non trauma treatment distribution + + non_trauma_treat_p: float + Probability non trauma patient requires treatment + + prob_trauma: float + probability that a new arrival is a trauma patient. ''' # sampling self.random_number_set = random_number_set - - # count of each type of resource - self.init_resourse_counts() - - # pathway variables - self.init_pathway_variables() - - # sampling distributions + + # store parameters for sampling + self.triage_mean = triage_mean + self.reg_mean = reg_mean + self.reg_var = reg_var + self.exam_mean= exam_mean + self.exam_var = exam_var + self.trauma_mean = trauma_mean + self.trauma_treat_mean = trauma_treat_mean + self.trauma_treat_var = trauma_treat_var + self.non_trauma_treat_mean = non_trauma_treat_mean + self.non_trauma_treat_var = non_trauma_treat_var + self.non_trauma_treat_p = non_trauma_treat_p + self.prob_trauma = prob_trauma + self.init_sampling() - + + # count of each type of resource + self.init_resourse_counts(n_triage, n_reg, n_exam, n_trauma, + n_cubicles_1, n_cubicles_2) + def set_random_no_set(self, random_number_set): ''' Controls the random sampling @@ -204,65 +282,19 @@ def set_random_no_set(self, random_number_set): self.random_number_set = random_number_set self.init_sampling() - def init_resourse_counts(self): + def init_resourse_counts(self, n_triage, n_reg, n_exam, n_trauma, + n_cubicles_1, n_cubicles_2): ''' Init the counts of resources to default values... ''' - self.n_triage = DEFAULT_N_TRIAGE - self.n_reg = DEFAULT_N_REG - self.n_exam = DEFAULT_N_EXAM - self.n_trauma = DEFAULT_N_TRAUMA + self.n_triage = n_triage + self.n_reg = n_reg + self.n_exam = n_exam + self.n_trauma = n_trauma # non-trauma (1), trauma (2) treatment cubicles - self.n_cubicles_1 = DEFAULT_N_CUBICLES_1 - self.n_cubicles_2 = DEFAULT_N_CUBICLES_2 - - def init_pathway_variables(self): - # trauma pathway - self.prob_trauma = DEFAULT_PROB_TRAUMA - self.treat_trauma_mean = DEFAULT_TRAUMA_TREAT_MEAN - self.treat_trauma_var = DEFAULT_TRAUMA_TREAT_VAR - - #non trauma pathway - self.exam_mean = DEFAULT_EXAM_MEAN - self.exam_var = DEFAULT_EXAM_VAR - - self.nt_treat_prob = DEFAULT_NON_TRAUMA_TREAT_P - self.nt_treat_mean = DEFAULT_NON_TRAUMA_TREAT_MEAN - self.nt_treat_var = DEFAULT_NON_TRAUMA_TREAT_VAR - - # def __eq__(self, other): - # return self.n_triage == other.n_triage and \ - # self.n_reg == other.n_reg and \ - # self.n_exam == other.n_exam and \ - # self.n_trauma == other.n_trauma and \ - # self.n_cubicles_1 == other.n_cubicles_1 and \ - # self.n_cubicles_2 == other.n_cubicles_2 and \ - # self.prob_trauma == other.prob_trauma and \ - # self.treat_trauma_mean == other.treat_trauma_mean and \ - # self.treat_trauma_var == other.treat_trauma_var and \ - # self.exam_mean == other.exam_mean and \ - # self.exam_var == other.exam_var and \ - # self.nt_treat_prob == other.nt_treat_prob and \ - # self.nt_treat_mean == other.self.nt_treat_mean and \ - # self.nt_treat_var == other.nt_treat_var - - # def __hash__(self): - # '''''' - # return hash((self.n_triage, - # self.n_reg, - # self.n_exam, - # self.n_trauma, - # self.n_cubicles_1, - # self.n_cubicles_2, - # self.prob_trauma, - # self.treat_trauma_mean, - # self.treat_trauma_var, - # self.exam_mean, - # self.exam_var, - # self.nt_treat_prob, - # self.nt_treat_mean, - # self.nt_treat_var)) + self.n_cubicles_1 = n_cubicles_1 + self.n_cubicles_2 = n_cubicles_2 def init_sampling(self): ''' @@ -276,12 +308,12 @@ def init_sampling(self): # create distributions # Triage duration - self.triage_dist = Exponential(DEFAULT_TRIAGE_MEAN, + self.triage_dist = Exponential(self.triage_mean, random_seed=self.seeds[0]) # Registration duration (non-trauma only) - self.reg_dist = Lognormal(DEFAULT_REG_MEAN, - np.sqrt(DEFAULT_REG_VAR), + self.reg_dist = Lognormal(self.reg_mean, + np.sqrt(self.reg_var), random_seed=self.seeds[1]) # Evaluation (non-trauma only) @@ -290,21 +322,21 @@ def init_sampling(self): random_seed=self.seeds[2]) # Trauma/stablisation duration (trauma only) - self.trauma_dist = Exponential(DEFAULT_TRAUMA_MEAN, + self.trauma_dist = Exponential(self.trauma_mean, random_seed=self.seeds[3]) # Non-trauma treatment - self.nt_treat_dist = Lognormal(self.nt_treat_mean, - np.sqrt(self.nt_treat_var), + self.nt_treat_dist = Lognormal(self.non_trauma_treat_mean, + np.sqrt(self.non_trauma_treat_var), random_seed=self.seeds[4]) # treatment of trauma patients - self.treat_dist = Lognormal(self.treat_trauma_mean, - np.sqrt(self.treat_trauma_var), + self.treat_dist = Lognormal(self.trauma_treat_mean, + np.sqrt(self.non_trauma_treat_var), random_seed=self.seeds[5]) # probability of non-trauma patient requiring treatment - self.nt_p_treat_dist = Bernoulli(self.nt_treat_prob, + self.nt_p_treat_dist = Bernoulli(self.non_trauma_treat_p, random_seed=self.seeds[6]) @@ -314,8 +346,7 @@ def init_sampling(self): # init sampling for non-stationary poisson process self.init_nspp() - - + def init_nspp(self): # read arrival profile @@ -1028,31 +1059,26 @@ def get_scenarios(): scenarios['base'] = Scenario() # extra triage capacity - scenarios['triage+1'] = Scenario() - scenarios['triage+1'].n_triage += 1 + scenarios['triage+1'] = Scenario(n_triage=DEFAULT_N_TRIAGE+1) # extra examination capacity - scenarios['exam+1'] = Scenario() - scenarios['exam+1'].n_exam += 1 + scenarios['exam+1'] = Scenario(n_exam=DEFAULT_N_EXAM+1) # extra non-trauma treatment capacity - scenarios['treat+1'] = Scenario() - scenarios['treat+1'].n_cubicles_1 += 1 + scenarios['treat+1'] = Scenario(n_cubicles_1=DEFAULT_N_CUBICLES_1+1) - #swap over 1 exam room for extra treat cubicle - scenarios['swap_exam_treat'] = Scenario() - scenarios['swap_exam_treat'].n_cubicles_1 += 1 - scenarios['swap_exam_treat'].n_exam -= 1 - - #scenario + 3 min short mean exam times. - scenarios['short_exam'] = Scenario() - scenarios['short_exam'].n_cubicles_1 += 1 - scenarios['short_exam'].n_exam -= 1 - scenarios['short_exam'].exam_mean = 12.0 + # swap over 1 exam room for extra treat cubicle + scenarios['swap_exam_treat'] = Scenario(n_triage=DEFAULT_N_TRIAGE+1, + n_exam=DEFAULT_N_EXAM-1) + # scenario + 3 min short mean exam times. + scenarios['short_exam'] = Scenario(n_triage=DEFAULT_N_TRIAGE+1, + n_exam=DEFAULT_N_EXAM-1, + exam_mean=12.0) return scenarios + def run_scenario_analysis(scenarios, rc_period, n_reps): ''' Run each of the scenarios for a specified results