Skip to content

Commit 24683ad

Browse files
committed
fix(model): Fixed bug in MonitoredResource where activities scheduled to occur at end of run length didn't happen, by making them happen after env.run()
1 parent 1144800 commit 24683ad

File tree

7 files changed

+197
-209
lines changed

7 files changed

+197
-209
lines changed

notebooks/analysis.ipynb

Lines changed: 112 additions & 112 deletions
Large diffs are not rendered by default.

notebooks/generate_exp_results.ipynb

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@
336336
" <td>2.065396</td>\n",
337337
" <td>9.622971</td>\n",
338338
" <td>0.643006</td>\n",
339-
" <td>0.642751</td>\n",
339+
" <td>0.643006</td>\n",
340340
" <td>0.554903</td>\n",
341341
" </tr>\n",
342342
" <tr>\n",
@@ -347,7 +347,7 @@
347347
" <td>1.396755</td>\n",
348348
" <td>10.186235</td>\n",
349349
" <td>0.645640</td>\n",
350-
" <td>0.646154</td>\n",
350+
" <td>0.647690</td>\n",
351351
" <td>0.355707</td>\n",
352352
" </tr>\n",
353353
" <tr>\n",
@@ -358,7 +358,7 @@
358358
" <td>3.484284</td>\n",
359359
" <td>10.733822</td>\n",
360360
" <td>0.660790</td>\n",
361-
" <td>0.666590</td>\n",
361+
" <td>0.668319</td>\n",
362362
" <td>0.858219</td>\n",
363363
" </tr>\n",
364364
" <tr>\n",
@@ -369,7 +369,7 @@
369369
" <td>2.050522</td>\n",
370370
" <td>10.511447</td>\n",
371371
" <td>0.634541</td>\n",
372-
" <td>0.638077</td>\n",
372+
" <td>0.638407</td>\n",
373373
" <td>0.502188</td>\n",
374374
" </tr>\n",
375375
" <tr>\n",
@@ -380,7 +380,7 @@
380380
" <td>1.836706</td>\n",
381381
" <td>9.742127</td>\n",
382382
" <td>0.597097</td>\n",
383-
" <td>0.599347</td>\n",
383+
" <td>0.601461</td>\n",
384384
" <td>0.451830</td>\n",
385385
" </tr>\n",
386386
" </tbody>\n",
@@ -396,11 +396,11 @@
396396
"4 4 0 369 1.836706 9.742127 \n",
397397
"\n",
398398
" mean_nurse_utilisation mean_nurse_utilisation_tw mean_nurse_q_length \n",
399-
"0 0.643006 0.642751 0.554903 \n",
400-
"1 0.645640 0.646154 0.355707 \n",
401-
"2 0.660790 0.666590 0.858219 \n",
402-
"3 0.634541 0.638077 0.502188 \n",
403-
"4 0.597097 0.599347 0.451830 "
399+
"0 0.643006 0.643006 0.554903 \n",
400+
"1 0.645640 0.647690 0.355707 \n",
401+
"2 0.660790 0.668319 0.858219 \n",
402+
"3 0.634541 0.638407 0.502188 \n",
403+
"4 0.597097 0.601461 0.451830 "
404404
]
405405
},
406406
"metadata": {},
@@ -635,7 +635,7 @@
635635
" <td>2.166733</td>\n",
636636
" <td>10.159320</td>\n",
637637
" <td>0.636215</td>\n",
638-
" <td>0.638584</td>\n",
638+
" <td>0.639776</td>\n",
639639
" <td>0.544569</td>\n",
640640
" </tr>\n",
641641
" <tr>\n",
@@ -644,7 +644,7 @@
644644
" <td>0.784458</td>\n",
645645
" <td>0.478668</td>\n",
646646
" <td>0.023832</td>\n",
647-
" <td>0.024489</td>\n",
647+
" <td>0.024278</td>\n",
648648
" <td>0.190098</td>\n",
649649
" </tr>\n",
650650
" <tr>\n",
@@ -653,7 +653,7 @@
653653
" <td>1.192699</td>\n",
654654
" <td>9.564976</td>\n",
655655
" <td>0.606623</td>\n",
656-
" <td>0.608177</td>\n",
656+
" <td>0.609631</td>\n",
657657
" <td>0.308532</td>\n",
658658
" </tr>\n",
659659
" <tr>\n",
@@ -662,7 +662,7 @@
662662
" <td>3.140766</td>\n",
663663
" <td>10.753665</td>\n",
664664
" <td>0.665806</td>\n",
665-
" <td>0.668991</td>\n",
665+
" <td>0.669921</td>\n",
666666
" <td>0.780607</td>\n",
667667
" </tr>\n",
668668
" </tbody>\n",
@@ -677,10 +677,10 @@
677677
"upper_95_ci 396.871659 3.140766 10.753665 \n",
678678
"\n",
679679
" mean_nurse_utilisation mean_nurse_utilisation_tw \\\n",
680-
"mean 0.636215 0.638584 \n",
681-
"std_dev 0.023832 0.024489 \n",
682-
"lower_95_ci 0.606623 0.608177 \n",
683-
"upper_95_ci 0.665806 0.668991 \n",
680+
"mean 0.636215 0.639776 \n",
681+
"std_dev 0.023832 0.024278 \n",
682+
"lower_95_ci 0.606623 0.609631 \n",
683+
"upper_95_ci 0.665806 0.669921 \n",
684684
"\n",
685685
" mean_nurse_q_length \n",
686686
"mean 0.544569 \n",

outputs/example_overall.csv

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
arrivals,mean_q_time_nurse,mean_time_with_nurse,mean_nurse_utilisation,mean_nurse_utilisation_tw,mean_nurse_q_length
2-
10776.741935483871,0.499036905566402,9.978456743390534,0.49767035119563796,0.49778467447803937,0.12458802034117737
3-
115.80327218806197,0.06739346957542013,0.11513823236530764,0.007524465631261531,0.007540597007787788,0.01720568342578357
4-
10734.264952313013,0.47431678135150124,9.936223698796068,0.4949103549196282,0.4950187611653494,0.11827692470880834
5-
10819.21891865473,0.5237570297813028,10.020689787985,0.5004303474716477,0.5005505877907294,0.1308991159735464
2+
10776.741935483871,0.499036905566402,9.978456743390534,0.49767035119563796,0.497804034286856,0.12459850290556283
3+
115.80327218806197,0.06739346957542013,0.11513823236530764,0.007524465631261531,0.0075405891452702024,0.017212719807337778
4+
10734.264952313013,0.47431678135150124,9.936223698796068,0.4949103549196282,0.4950381238581607,0.11828482630760263
5+
10819.21891865473,0.5237570297813028,10.020689787985,0.5004303474716477,0.5005699447155513,0.13091217950352302

outputs/example_run.csv

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
run_number,scenario,arrivals,mean_q_time_nurse,mean_time_with_nurse,mean_nurse_utilisation,mean_nurse_utilisation_tw,mean_nurse_q_length
2-
0,0,10972,0.504541081338615,9.84226781662332,0.4996386466177992,0.4997094613610211,0.12814409130665008
3-
1,0,10784,0.514150649003393,10.060480983450425,0.5019905433327594,0.502064256550978,0.1283472360845507
4-
2,0,10854,0.5232349226016817,9.925024519746302,0.4981297032213408,0.49823133874707154,0.1324071941666391
5-
3,0,10831,0.4791488631810612,9.9370571543943,0.49822049332297624,0.4982638436545642,0.12013104947023319
6-
4,0,10720,0.46145745726579823,10.015904147971671,0.4968703372055205,0.4971000995404679,0.11450981346966105
7-
5,0,10772,0.3882646868128185,9.884995942861282,0.492904233058074,0.49304721268899043,0.09681451866545558
8-
6,0,10831,0.4669381081669874,10.041799654744745,0.503356251584998,0.5033169859948308,0.11706959836936667
9-
7,0,10781,0.625888360901447,10.086979128063648,0.5034489381047406,0.5037349298112143,0.15619681525181714
2+
0,0,10972,0.504541081338615,9.84226781662332,0.4996386466177992,0.4997404525127849,0.12814409130665008
3+
1,0,10784,0.514150649003393,10.060480983450425,0.5019905433327594,0.502069010098797,0.1283472360845507
4+
2,0,10854,0.5232349226016817,9.925024519746302,0.4981297032213408,0.4982604514269931,0.1326692082859329
5+
3,0,10831,0.4791488631810612,9.9370571543943,0.49822049332297624,0.4982689502894135,0.12013104947023319
6+
4,0,10720,0.46145745726579823,10.015904147971671,0.4968703372055205,0.4971055007588973,0.11450981346966105
7+
5,0,10772,0.3882646868128185,9.884995942861282,0.492904233058074,0.4930559758823053,0.09681451866545558
8+
6,0,10831,0.4669381081669874,10.041799654744745,0.503356251584998,0.5034005361957391,0.11706959836936667
9+
7,0,10781,0.625888360901447,10.086979128063648,0.5034489381047406,0.5037422085180931,0.15619681525181714
1010
8,0,10772,0.4684971326393017,10.202270228377186,0.508790994907774,0.5089130015618383,0.11682062761089254
11-
9,0,10705,0.5634349862001105,10.09260227901333,0.49997178325917613,0.5002042408148075,0.1399966447950717
12-
10,0,10927,0.562585969190057,10.083553615426284,0.5098373896503802,0.5099831780480953,0.14230039086434612
13-
11,0,10688,0.39781182403365434,9.893334037740962,0.4895233535105571,0.4896102199835747,0.09842159202017818
14-
12,0,11092,0.44530362984867583,9.810905063859671,0.5034276977164731,0.5034560301359091,0.11436285729213683
15-
13,0,10640,0.4397605749351992,9.933879963761742,0.48925457544062534,0.4892243098930909,0.10831140086366944
16-
14,0,10904,0.6107822771635987,10.167683587926042,0.513130373051619,0.5135275707547177,0.1541659710692565
17-
15,0,10849,0.47670998312351787,9.975581276412813,0.5009629889699926,0.5010211453918623,0.11971820849321864
18-
16,0,10719,0.428336230071242,9.809804967118032,0.4866947365248423,0.48682230223169853,0.10628092708642692
19-
17,0,10713,0.505574486075843,9.989154604862323,0.4954087210793937,0.49570388412668587,0.1253754506789469
20-
18,0,10568,0.3615821082986753,9.800182515281657,0.4793715775153063,0.4795651069171014,0.08845369723380557
21-
19,0,10707,0.4191589720392036,9.9193906381964,0.4915291568180775,0.49170197747337024,0.10388738688943873
22-
20,0,10845,0.6120142008002236,9.813774247048583,0.49261944375555833,0.492666922309052,0.15364106499255614
23-
21,0,10726,0.5173212645251098,9.858186468091487,0.48940978932654106,0.4895469034983069,0.1284441639651928
24-
22,0,10618,0.5316566599495316,9.969891296475984,0.4892835610032433,0.48936990129569896,0.13067431517000294
25-
23,0,10914,0.5270546197660896,9.925291785145637,0.5013818263178943,0.501432376992062,0.1331544935214607
26-
24,0,10660,0.5029697553047842,9.96454608027881,0.49160360886911897,0.4916211282340966,0.12411244424881943
27-
25,0,10685,0.6270646900660448,10.236338445072258,0.5060501169430693,0.5060869246801079,0.155101882934466
11+
9,0,10705,0.5634349862001105,10.09260227901333,0.49997178325917613,0.5002278075946729,0.1399966447950717
12+
10,0,10927,0.562585969190057,10.083553615426284,0.5098373896503802,0.5099889270180503,0.14230039086434612
13+
11,0,10688,0.39781182403365434,9.893334037740962,0.4895233535105571,0.48962710728052056,0.09842159202017818
14+
12,0,11092,0.44530362984867583,9.810905063859671,0.5034276977164731,0.5034590643983867,0.11437196007956935
15+
13,0,10640,0.4397605749351992,9.933879963761742,0.48925457544062534,0.4892677288083271,0.10831140086366944
16+
14,0,10904,0.6107822771635987,10.167683587926042,0.513130373051619,0.5135294499218972,0.1541659710692565
17+
15,0,10849,0.47670998312351787,9.975581276412813,0.5009629889699926,0.5010455334069686,0.11971820849321864
18+
16,0,10719,0.428336230071242,9.809804967118032,0.4866947365248423,0.4868274499224406,0.10628092708642692
19+
17,0,10713,0.505574486075843,9.989154604862323,0.4954087210793937,0.4957697619501451,0.1253754506789469
20+
18,0,10568,0.3615821082986753,9.800182515281657,0.4793715775153063,0.4795652084277097,0.08845369723380557
21+
19,0,10707,0.4191589720392036,9.9193906381964,0.4915291568180775,0.4917635127186296,0.10388738688943873
22+
20,0,10845,0.6120142008002236,9.813774247048583,0.49261944375555833,0.49267201493881163,0.15364106499255614
23+
21,0,10726,0.5173212645251098,9.858186468091487,0.48940978932654106,0.4895612849605359,0.1284441639651928
24+
22,0,10618,0.5316566599495316,9.969891296475984,0.4892835610032433,0.4893719186906082,0.13067431517000294
25+
23,0,10914,0.5270546197660896,9.925291785145637,0.5013818263178943,0.501433800156172,0.1331544935214607
26+
24,0,10660,0.5029697553047842,9.96454608027881,0.49160360886911897,0.49162164437257694,0.12411244424881943
27+
25,0,10685,0.6270646900660448,10.236338445072258,0.5060501169430693,0.5061407672693311,0.15515572552368928
2828
26,0,10806,0.5061794260886525,10.039653295082593,0.5022615440123254,0.5023039700989318,0.126615159220231
29-
27,0,10748,0.4925537687951073,10.050997027592315,0.4999546777219452,0.5000883223037053,0.12254555340300495
30-
28,0,10589,0.4577189216542841,10.044180668559221,0.4923573694687436,0.49234245205738814,0.11219411253234293
31-
29,0,10863,0.5422405738480466,10.034383892923174,0.5046064549261675,0.504719890581045,0.13635091096554006
32-
30,0,10796,0.5102078888697092,9.922063713004379,0.49578999982774674,0.4959450210869338,0.12767905794112022
29+
27,0,10748,0.4925537687951073,10.050997027592315,0.4999546777219452,0.5001183558252156,0.12254555340300495
30+
28,0,10589,0.4577189216542841,10.044180668559221,0.4923573694687436,0.4923672645089264,0.11219411253234293
31+
29,0,10863,0.5422405738480466,10.034383892923174,0.5046064549261675,0.5047331518468727,0.13635091096554006
32+
30,0,10796,0.5102078888697092,9.922063713004379,0.49578999982774674,0.49597325153194355,0.12767905794112022

simulation/model.py

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,11 @@ class MonitoredResource(simpy.Resource):
200200
Attributes:
201201
time_last_event (float):
202202
Time of last resource request or release.
203-
queue_time (float):
203+
area_n_in_queue (float):
204204
Total time that patients have spent queueing for the resource
205205
(i.e. sum of the times each patient spent waiting). Used to
206206
calculate the average queue length.
207-
resource_busy_time (float):
207+
area_resource_busy (float):
208208
Total time that resources have been in use during the simulation
209209
(i.e. sum of the times each individual resource was busy). Used
210210
to calculated utilisation.
@@ -230,8 +230,8 @@ def init_results(self):
230230
Resets monitoring attributes to initial values.
231231
"""
232232
self.time_last_event = self._env.now
233-
self.queue_time = 0.0
234-
self.resource_busy_time = 0.0
233+
self.area_n_in_queue = 0.0
234+
self.area_resource_busy = 0.0
235235

236236
def request(self, *args, **kwargs):
237237
"""
@@ -277,7 +277,7 @@ def update_time_weighted_stats(self):
277277
278278
Between every request or release of the resource, it calculates the
279279
relevant statistics - e.g.:
280-
- Total waiting times (number of requests in queue * time)
280+
- Total queue time (number of requests in queue * time)
281281
- Total resource use (number of resources in use * time)
282282
These are summed to return the totals from across the whole simulation.
283283
In Runner.run_single(), these are then used to calculate utilisation.
@@ -296,28 +296,9 @@ def update_time_weighted_stats(self):
296296

297297
# Update the statistics
298298
# len(self.queue) is the number of requests queued
299-
self.queue_time += len(self.queue) * time_since_last_event
299+
self.area_n_in_queue += len(self.queue) * time_since_last_event
300300
# self.count is the number of resources in use
301-
self.resource_busy_time += self.count * time_since_last_event
302-
303-
def end_of_run_cleanup(self, run_length):
304-
"""
305-
Cleans up and finalises statistics at the end of the simulation run.
306-
307-
If the simulation ends while resources are still in use or requests are
308-
still in the queue, the time between the last recorded event and the
309-
simulation end will not have been accounted for. This method fills
310-
in that gap, avoiding underestimation of resource usage and queue
311-
sizes.
312-
313-
Arguments:
314-
run_length (float):
315-
Duration of the simulation run.
316-
"""
317-
# Delay clean up until the entire simulation has completed
318-
yield self._env.timeout(run_length)
319-
# Update the time-weighted statistics
320-
self.update_time_weighted_stats()
301+
self.area_resource_busy += self.count * time_since_last_event
321302

322303

323304
class Exponential:
@@ -354,7 +335,7 @@ def sample(self, size=None):
354335
355336
Returns:
356337
float or numpy.ndarray:
357-
A single sample if size is None, or an array of samples if
338+
A single sample if size is None, or an array of samples if
358339
size is specified.
359340
"""
360341
return self.rand.exponential(self.mean, size=size)
@@ -576,16 +557,16 @@ def warm_up_complete(self):
576557
# Delay process until warm-up period has completed
577558
yield self.env.timeout(self.param.warm_up_period)
578559

560+
# Reset results collection variables
561+
self.init_results_variables()
562+
579563
# If there was a warm-up period, log that this time has passed so we
580564
# can distinguish between patients before and after warm-up in logs
581565
if self.param.warm_up_period > 0:
582566
self.param.logger.log('─' * 10)
583567
self.param.logger.log(f'{self.env.now:.2f}: Warm up complete.')
584568
self.param.logger.log('─' * 10)
585569

586-
# Reset results collection variables
587-
self.init_results_variables()
588-
589570
def run(self):
590571
"""
591572
Runs the simulation for the specified duration.
@@ -604,13 +585,21 @@ def run(self):
604585
self.env.process(
605586
self.interval_audit(interval=self.param.audit_interval))
606587

607-
# Schedule process which will clean up monitoring of resources at the
608-
# end of the run
609-
self.env.process(self.nurse.end_of_run_cleanup(run_length))
610-
611588
# Run the simulation
612589
self.env.run(until=run_length)
613590

591+
# If the simulation ends while resources are still in use or requests
592+
# are still in the queue, the time between the last recorded event and
593+
# the simulation end will not have been accounted for. Hence, we call
594+
# update_time_weighted_stats() to run for last event --> end.
595+
self.nurse.update_time_weighted_stats()
596+
597+
# Error handling - if there was no data collection period, the
598+
# simulation ends before it has a chance to reset the results,
599+
# so we do so manually
600+
if self.param.data_collection_period == 0:
601+
self.init_results_variables()
602+
614603
# Convert list of patient objects into a list that just contains the
615604
# attributes of each of those patients as dictionaries
616605
self.results_list = [x.__dict__ for x in self.patients]
@@ -674,7 +663,6 @@ def run_single(self, run):
674663

675664
# Create dictionary recording the run results
676665
# Currently has two alternative methods of measuring utilisation
677-
# TODO: Is mean_q_time_nurse and mean_nurse_q_length the same?
678666
run_results = {
679667
'run_number': run,
680668
'scenario': self.param.scenario_name,
@@ -684,10 +672,10 @@ def run_single(self, run):
684672
'mean_nurse_utilisation': (model.nurse_time_used /
685673
(self.param.number_of_nurses *
686674
self.param.data_collection_period)),
687-
'mean_nurse_utilisation_tw': (model.nurse.resource_busy_time /
675+
'mean_nurse_utilisation_tw': (model.nurse.area_resource_busy /
688676
(self.param.number_of_nurses *
689677
self.param.data_collection_period)),
690-
'mean_nurse_q_length': (model.nurse.queue_time /
678+
'mean_nurse_q_length': (model.nurse.area_n_in_queue /
691679
self.param.data_collection_period)
692680
}
693681

tests/exp_results/overall.csv

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
,arrivals,mean_q_time_nurse,mean_time_with_nurse,mean_nurse_utilisation,mean_nurse_utilisation_tw,mean_nurse_q_length
2-
mean,378.0,2.1667325673589564,10.159320371752361,0.6362147508884318,0.6385838493112572,0.5445692746656905
3-
std_dev,15.198684153570664,0.7844583147114635,0.4786676748781607,0.02383218108751965,0.024489056062460362,0.19009766156834382
4-
lower_95_ci,359.12834106644124,1.192698919890132,9.564975952752244,0.606623189633386,0.6081766700485065,0.3085318521535542
5-
upper_95_ci,396.87165893355876,3.1407662148277806,10.75366479075248,0.6658063121434776,0.6689910285740079,0.7806066971778267
2+
mean,378.0,2.1667325673589564,10.159320371752361,0.6362147508884318,0.6397764054245421,0.5445692746656905
3+
std_dev,15.198684153570664,0.7844583147114635,0.4786676748781607,0.02383218108751965,0.024277980144559095,0.19009766156834382
4+
lower_95_ci,359.12834106644124,1.192698919890132,9.564975952752244,0.606623189633386,0.6096313115299372,0.3085318521535542
5+
upper_95_ci,396.87165893355876,3.1407662148277806,10.75366479075248,0.6658063121434776,0.6699214993191469,0.7806066971778267

0 commit comments

Comments
 (0)