-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbuild_contact_trees_json.py
1732 lines (1636 loc) · 95.9 KB
/
build_contact_trees_json.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import load_contact_data
import numpy as np
import numpy.random
import scipy
import scipy.stats
import load_contact_data
import fit_dist
import code
import matplotlib
import matplotlib.pyplot as plt
import numba
from multiprocessing import Pool
import math
import random
import scipy.optimize
import json
age_intervals = [(0, 14), (15, 24), (25, 54), (55, 64), (65, np.inf)]
age_specific_IFRs = np.array([0.0001, 0.0001, 0.0013, 0.007, 0.068])
age_vector_US = np.array([0.1862, 0.1312, 0.3929, 0.1294, 0.1603])
age_vector_US = age_vector_US / np.sum(age_vector_US)
false_positive_rate = 0.0
frac_asymptoms = 0.20
asymp_infectiousness = 0.35
presymp_infectiousness = 0.63
""" relative transmission rate of asymptoms individual """
days_infectious_before_symptoms = 2
days_infectious_after_symptoms = 5
total_infectious_days = days_infectious_before_symptoms + days_infectious_after_symptoms
asymp_quarantine_length = 14
symp_quarantine_length = 10
symptoms_household_SAR = 0.2
symptoms_external_SAR = 0.06
superspreader_SAR_ratio = 10
# frac_infs_from_SS = 0.9
index_R0 = 2.548934288671604
raw_R0 = 2.5
# raw_R0 = 1.48 # 50% reduction
quarantine_dropout_rate_default = 0.05
length_of_sympts_to_track = 30
symptom_false_positive_chance = 0.01
pooling_max = 20
dropout_reduction_for_symptoms = 0.5
frac_self_isolate = 0.9
frac_SS_cal = 1 / (1 + np.exp(2.1))
base_household_cal = 1 / (1 + np.exp(3.3))
base_external_cal = 1 / (1 + np.exp(5.))
SS_mult_cal = 1 + np.log(1 + np.exp(23.4))
phys_mult_cal = 1 + np.log(1 + np.exp(4.2))
fraction_household_physical = [0.] # filled in by get_contacts_per_age
fraction_external_physical = [0.] # filled in by get_contacts_per_age
n_processes = 1
def distancing_from_R0_squared(R0_squared_obs):
# return 1 - math.sqrt(1 / R0_squared_obs)
return 1 - raw_R0 / R0_squared_obs
def reduction_from_R0_squared(R0_squared_obs):
return 1 - (R0_squared_obs / index_R0) / raw_R0
""" convert raw numeric age into age interval """
def raw_age_to_interval(age, age_intervals):
for i in range(len(age_intervals)):
if age >= age_intervals[i][0] and age <= age_intervals[i][1]:
return i
""" process POLYMOD data into dict of contacts by age """
def get_contacts_per_age():
total_household = 0
total_external = 0
age_to_id_dict = {}
age_to_contacts_dict = {}
for i in range(len(age_intervals)):
age_to_contacts_dict[i] = []
age_i = np.logical_and(load_contact_data.raw_participants["part_age"]
>= age_intervals[i][0], load_contact_data.raw_participants["part_age"] <= age_intervals[i][1])
age_to_id_dict[i] = list(load_contact_data.raw_participants[age_i]['part_id'])
for j in age_to_id_dict[i]:
contacts_j = load_contact_data.raw_contacts[load_contact_data.raw_contacts['part_id'] == j]
contacts = []
contacts.append((1, True, True, True, True))
contacts.pop()
""" contact format: (age of contact, gender, is_household, is_daily, duration, is_physical) """
contacts_numpy = contacts_j.to_numpy()
for row in range(np.shape(contacts_numpy)[0]):
if contacts_numpy[row][14] <= 2:
continue
# assert(contacts_numpy[row][5] == 'F' or contacts_numpy[row][5] == 'M')
try:
contacts.append((raw_age_to_interval(int(contacts_numpy[row][2]), age_intervals),
contacts_numpy[row][5] == 'F',
bool(contacts_numpy[row][6]),
int(contacts_numpy[row][12]) == 1,
int(contacts_numpy[row][13]) == 1))
if bool(contacts_numpy[row][6]):
total_household += 1
if int(contacts_numpy[row][12]) == 1:
fraction_household_physical[0] += 1
else:
total_external += 1
if int(contacts_numpy[row][12]) == 1:
fraction_external_physical[0] += 1
except Exception:
pass
age_to_contacts_dict[i].append(contacts)
fraction_external_physical[0] = fraction_external_physical[0] / total_external
fraction_household_physical[0] = fraction_household_physical[0] / total_household
return age_to_contacts_dict
# @njit
# def true_positive_test_rate(test_time_rel_to_symptoms):
# if test_time_rel_to_symptoms <= -3:
# return 0.0
# if test_time_rel_to_symptoms == -2:
# return 0.0
# if test_time_rel_to_symptoms == -1:
# return 0.0
# if test_time_rel_to_symptoms == 0:
# return 0.0
# else:
# return 0.0
def false_negative_test_rate(test_time_rel_to_symptoms):
if test_time_rel_to_symptoms <= -3:
return 1.0
if test_time_rel_to_symptoms == -2:
return 0.95
if test_time_rel_to_symptoms == -1:
return 0.7
if test_time_rel_to_symptoms == 0:
return 0.4
if test_time_rel_to_symptoms <= 4:
return 0.25
else:
return min(0.25 + (test_time_rel_to_symptoms - 4) * 0.0375, 1.)
def calc_test_results(num_individuals, test_time_rel_to_symptoms, I_COVID, seed=0):
test_results = np.zeros(num_individuals)
for i in range(num_individuals):
test_results[i] = calc_test_single(test_time_rel_to_symptoms[i], I_COVID[i])
return test_results
def calc_test_single(test_time_rel_to_symptoms, I_COVID):
if I_COVID:
return np.random.binomial(n=1, p=1 - false_negative_test_rate(int(round(test_time_rel_to_symptoms))))
else:
return 0
""" draw properties of seed index cases """
def draw_seed_index_cases(num_individuals, age_vector, cases_contacted=1.0,
t_exposure=None, fpr=false_positive_rate, initial=False, skip_days=False,
random_testing=False, test_freq=0., test_delay=0.,
frac_SS=frac_SS_cal, frac_vacc=0., seed=0):
np.random.seed(seed)
if t_exposure is None:
t_exposure = np.zeros(num_individuals)
params = {}
n_ages = scipy.stats.multinomial.rvs(num_individuals, age_vector)
if t_exposure is None:
params['t_exposure'] = np.zeros(num_individuals)
else:
params['t_exposure'] = t_exposure
params['t_last_exposure'] = params['t_exposure']
params['I_contacted'] = scipy.stats.bernoulli.rvs(p=cases_contacted, size=num_individuals)
params['n_age'] = np.sum([[i] * n_ages[i] for i in range(len(n_ages))])
params['I_COVID'] = scipy.stats.bernoulli.rvs(p=1 - fpr, size=num_individuals)
if not initial:
params['I_asymptoms'] = scipy.stats.bernoulli.rvs(p=frac_asymptoms, size=num_individuals) * params['I_COVID']
else:
params['I_asymptoms'] = np.zeros(num_individuals)
params['I_symptoms'] = 1 - params['I_asymptoms']
if not initial:
params['I_vacc'] = scipy.stats.bernoulli.rvs(p=frac_vacc, size=num_individuals)
else:
params['I_vacc'] = np.zeros(num_individuals) # TODO: HACK
params['t_incubation'] = np.maximum(scipy.stats.lognorm.rvs(s=0.65, scale=np.exp(1.57), size=num_individuals), 0) + t_exposure
params['t_incubation_infect'] = np.maximum(params['t_incubation'] - days_infectious_before_symptoms, 0)
if initial:
params['I_self_isolate'] = np.ones(num_individuals) * params['I_symptoms']
else:
params['I_self_isolate'] = scipy.stats.bernoulli.rvs(p=frac_self_isolate, size=num_individuals) * params['I_symptoms']
params['t_false_positive'] = np.random.geometric(p=symptom_false_positive_chance, size=num_individuals) + t_exposure
params['t_self_isolate'] = scipy.stats.gamma.rvs(loc=days_infectious_before_symptoms, scale=1.22, a=1/0.78, size=num_individuals) + params['t_incubation_infect']
params['r_dropout_props'] = np.random.uniform(size=num_individuals)
if skip_days:
params['n_transmission_days'] = (
params['I_asymptoms'] * total_infectious_days +
params['I_symptoms'] * (1 - params['I_self_isolate']) * total_infectious_days +
params['I_symptoms'] * params['I_self_isolate'] * (params['t_self_isolate'] - params['t_incubation_infect']))
params['n_quarantine_days'] = np.zeros(num_individuals)
params['n_isolation_days'] = params['I_self_isolate'] * symp_quarantine_length
params['n_tests'] = np.zeros(num_individuals)
else:
(params['n_quarantine_days'], params['n_transmission_days'],
params['n_isolation_days'], params['n_tests'],
params['n_monitoring_days'], params['n_false_positive_isolation_days'],
params['n_billed_tracer_days'], params['summaries']) = get_transmission_days(
t_exposure=params['t_exposure'], t_last_exposure=params['t_last_exposure'],
I_isolation=params['I_self_isolate'], t_isolation=params['t_self_isolate'],
t_infectious=params['t_incubation_infect'],
I_symptoms=params['I_symptoms'], t_symptoms=params['t_incubation'],
I_random_testing=random_testing, test_freq=test_freq,
test_delay=test_delay, t_false_positive=params['t_false_positive'])
params['id_original_case'] = (np.ones(num_individuals) * -1).astype(int)
params['id_infected_by'] = (np.ones(num_individuals) * -1).astype(int)
params['I_superspreader'] = scipy.stats.bernoulli.rvs(p=frac_SS, size=num_individuals) * params['I_COVID']
if initial:
params['I_test_positive'] = np.ones(num_individuals)
else:
params['I_test_positive'] = calc_test_results(num_individuals,
params['t_self_isolate'] - params['t_incubation_infect'],
params['I_COVID'], seed=seed)
params['I_infected_by_presymp'] = np.ones(num_individuals) * -1
params['I_infected_by_asymp'] = np.ones(num_individuals) * -1
return params
def draw_contacts(contact_days, n_transmission_days, t_incubation_infect, index, base_reduction=0., get_dummy=False, frac_vacc=0.,
seed=0):
np.random.seed(seed)
contact_list = []
contacts = []
exposure_days_list = []
selection = np.random.choice(len(contact_days))
for day in range(int(n_transmission_days)):
contacts.append(contact_days[selection])
for day in range(int(n_transmission_days)):
for (i, contact) in enumerate(contacts[day]):
# if (day == 0 or not contact[3] or np.random.binomial(n=1, p=(1. - 5./7.) ** day)) or get_dummy:
# if (day == 0 or not contact[3] or np.random.binomial(n=1, p=0.5)) or get_dummy:
if day == 0 or not contact[3] or get_dummy:
if not get_dummy:
if not contact[2] and not contact[3]:
if not np.random.binomial(n=1, p=1 - base_reduction):
continue
""" contact format: (age of contact, gender, is_household, is_daily,
t_exposure, index of infector, t_last_exposure,
is_physical, contact_is_vacc) """
contact_ext = {}
contact_ext[0] = contact[0]
contact_ext[1] = contact[1]
contact_ext[2] = contact[2]
contact_ext[3] = contact[3]
if contact[3]:
contact_days_mask = np.random.binomial(n=1, p=1 - base_reduction, size=int(n_transmission_days))
else:
contact_days_mask = np.zeros(int(n_transmission_days))
contact_days_mask[day] = 1
if contact[3]:
if np.max(contact_days_mask) < 0.01:
continue
infection_days = np.where(contact_days_mask > 0.99)[0]
day_of_infection = infection_days[np.random.randint(len(infection_days))]
contact_ext[6] = t_incubation_infect + np.max(infection_days)
else:
day_of_infection = day
contact_ext[6] = day + t_incubation_infect
contact_ext[4] = day_of_infection + t_incubation_infect
contact_ext[5] = index
contact_ext[7] = contact[4]
contact_ext[8] = np.random.binomial(n=1, p=frac_vacc)
contact_ext['exposure_days'] = contact_days_mask
contact_list.append(contact_ext)
return contact_list
def draw_all_contacts(contacts_by_age, n_transmission_days, t_incubation_infect, num_individuals, base_reduction=0.0,
frac_vacc=0., seed=0):
np.random.seed(seed)
contact_dict = []
for i in range(num_individuals):
a = draw_contacts(contact_days=contacts_by_age[0],
n_transmission_days=n_transmission_days[0],
t_incubation_infect=t_incubation_infect[0],
index=i, frac_vacc=frac_vacc, get_dummy=True)
if len(a) > 0:
break
for i in range(num_individuals):
contact_dict.append(a)
for i in range(num_individuals):
contact_dict[i] = draw_contacts(contact_days=contacts_by_age[i],
n_transmission_days=n_transmission_days[i],
t_incubation_infect=t_incubation_infect[i],
frac_vacc=frac_vacc,
index=i, base_reduction=base_reduction)
return contact_dict
""" draw index cases assuming uniform attack rate. draw contacts from POLYMOD """
def draw_contact_generation(index_cases, base_reduction=0.0, frac_vacc=0.0, seed=0):
num_individuals = len(index_cases['I_COVID'])
if num_individuals == 0:
return []
contacts_by_age = [age_to_contact_dict[index_cases['n_age'][i]] for i in range(num_individuals)]
contact_dict = draw_all_contacts(contacts_by_age=contacts_by_age,
n_transmission_days=index_cases['n_transmission_days'],
t_incubation_infect=index_cases['t_incubation_infect'],
num_individuals=num_individuals,
base_reduction=base_reduction,
frac_vacc=frac_vacc,
seed=seed)
return contact_dict
def fill_QII(t_exposure, t_last_exposure, trace_delay, test_delay, t_self_isolate,
I_self_isolate, t_incubation_infect,
t_incubation, I_symptoms, I_household, t_false_positive,
id_infected_by, num_g1_cases, g0_I_self_isolate, g0_t_self_isolate,
g0_I_test_positive, g0_I_symptoms, g0_I_contacted,
g0_I_superspreader, false_negative_traces, trace=False, ttq=False,
quarantine_by_parent_case_release=False,
early_release_by_parent_case=np.zeros(1), early_release=False,
wait_before_testing=0, wait_until_testing=0,
ttq_double=False, dropouts=np.zeros(1).reshape(1, -1),
precalc_dropout=0,
monitor=False, seed=0, hold_hh=False,
quarantine_dropout_rate=quarantine_dropout_rate_default):
np.random.seed(seed)
n_quarantine_days = np.zeros(num_g1_cases)
n_transmission_days = np.zeros(num_g1_cases)
n_isolation_days = np.zeros(num_g1_cases)
n_monitoring_days = np.zeros(num_g1_cases)
n_billed_tracer_days = np.zeros(num_g1_cases)
n_tests = np.zeros(num_g1_cases)
n_false_positive_isolation_days = np.zeros(num_g1_cases)
secondary_cases_traced = 0
secondary_cases_monitored = 0
summaries = []
I_bidirectionally_traced = np.zeros(len(g0_I_self_isolate))
earliest_self_isolates = np.ones(len(g0_I_self_isolate)) * 10000
# if bidirectional_SS:
# for i in range(num_g1_cases):
# parent_case = int(id_infected_by[i])
# if not g0_I_test_positive[parent_case] and g0_I_symptoms[parent_case] and I_self_isolate[i]:
# if not I_bidirectionally_traced[parent_case]:
# I_bidirectionally_traced[parent_case] = 1
# earliest_self_isolates[parent_case] = t_self_isolate[i]
# earliest_self_isolates[parent_case] = min(t_self_isolate[i], earliest_self_isolates[parent_case])
# for i in range(len(g0_I_self_isolate)):
# if I_bidirectionally_traced[i] and not g0_I_self_isolate[i]:
# g0_I_test_positive[i] = calc_test_single(earliest_self_isolates[i], True)
# if ttq:
# for i in range(num_g1_cases):
# parent_case = int(id_infected_by[i])
# if g0_I_test_positive[parent_case]:
# I_test_positive[i] = calc_test_single(g0_t_self_isolate[parent_case] + trace_delay - t_incubation[i], True)
for i in range(num_g1_cases):
""" did the parent case test positive? """
parent_case = int(id_infected_by[i])
if (g0_I_test_positive[parent_case] and g0_I_self_isolate[parent_case] and g0_I_contacted[parent_case]
and trace and not false_negative_traces[i]):
secondary_cases_traced += 1
t_quarantine_start = g0_t_self_isolate[parent_case] + trace_delay + test_delay
I_test = False
t_test_day = -1
t_quarantine_end = max(t_last_exposure[i] + asymp_quarantine_length, t_quarantine_start)
if early_release and quarantine_by_parent_case_release[parent_case] and not ttq and not (hold_hh and I_household[i]):
t_quarantine_end = min(t_quarantine_end, t_quarantine_start + early_release_by_parent_case[parent_case])
if ttq:
if not early_release:
I_test = True
t_test_day = max(t_quarantine_start + wait_before_testing, t_last_exposure[i] + wait_until_testing + wait_before_testing)
elif early_release and quarantine_by_parent_case_release[parent_case] and not (hold_hh and I_household[i]):
I_test = True
t_test_day = t_quarantine_start + early_release_by_parent_case[parent_case]
else:
I_test = False
tmp = calculate_QII_days(t_exposure=t_exposure[i],
t_last_exposure=t_last_exposure[i],
t_quarantine=t_quarantine_start,
t_quarantine_end=t_quarantine_end,
I_quarantine=True,
t_isolation=t_self_isolate[i],
I_isolation=I_self_isolate[i],
t_false_positive=t_false_positive[i],
t_infectious=t_incubation_infect[i],
t_symptoms=t_incubation[i],
I_symptoms=I_symptoms[i],
I_monitor=monitor,
t_monitor=t_quarantine_start,
t_monitor_end=t_quarantine_end,
I_test=I_test,
t_test_day=t_test_day,
test_delay=test_delay,
I_double_test=ttq_double,
wait_before_testing=wait_before_testing,
I_early_release=early_release,
early_release_day=t_quarantine_start + early_release_by_parent_case[parent_case],
dropouts=dropouts[i].reshape(1, -1),
precalc_dropout=precalc_dropout,
quarantine_dropout_rate=quarantine_dropout_rate)
else:
tmp = calculate_QII_days(t_exposure=t_exposure[i],
t_last_exposure=t_last_exposure[i],
t_quarantine=0,
I_quarantine=False,
t_quarantine_end=0,
t_isolation=t_self_isolate[i],
I_isolation=I_self_isolate[i],
t_false_positive=t_false_positive[i],
t_infectious=t_incubation_infect[i],
t_symptoms=t_incubation[i],
I_symptoms=I_symptoms[i],
I_monitor=False,
t_monitor=-1,
I_test=False,
t_test_day=-1,
test_delay=test_delay,
quarantine_dropout_rate=quarantine_dropout_rate)
n_quarantine_days[i] += tmp[0]
n_isolation_days[i] += tmp[1]
n_transmission_days[i] += tmp[2]
n_tests[i] += tmp[3]
n_monitoring_days[i] += tmp[4]
n_false_positive_isolation_days[i] += tmp[5]
n_billed_tracer_days[i] += tmp[6]
summaries.append(tmp[7])
return (n_quarantine_days, n_transmission_days, n_isolation_days, secondary_cases_traced, secondary_cases_monitored, n_monitoring_days,
n_tests, n_false_positive_isolation_days, n_billed_tracer_days, summaries)
# positives = [0]
# negatives = [0]
# days_rel_to_sympts = []
def calculate_QII_days(t_exposure, t_last_exposure,
t_infectious, t_false_positive,
I_quarantine=False, t_quarantine=0., t_quarantine_end=0.,
I_isolation=False, t_isolation=0.,
I_symptoms=False, t_symptoms=0.,
I_monitor=False, t_monitor=0., t_monitor_end=0.,
I_test=False, t_test_day=0., test_delay=0.,
I_random_testing=False, test_freq=0.,
I_double_test=False, wait_before_testing=0,
early_release_day=0, I_early_release=False,
dropouts=np.zeros(1).reshape(1, -1), precalc_dropout=0,
quarantine_dropout_rate=quarantine_dropout_rate_default):
# if I_random_testing and test_freq > 0.0:
# test_interval = 1 / test_freq
# else:
# test_interval = 10000
# first_test = t_infectious + np.random.uniform(0.0, test_interval)
quarantine_days = 0
isolation_days = 0
transmission_days = 0
monitoring_days = 0
false_isolation_days = 0
n_tests = 0
t_isolation_end = t_isolation + symp_quarantine_length
t_monitor_end = t_monitor + asymp_quarantine_length
if I_quarantine and I_isolation:
if t_quarantine_end > t_isolation_end:
t_quarantine_end = t_isolation_end
t_infectious_end = t_infectious + total_infectious_days
day = t_exposure
I_test_positive = False
symptoms_observed = False
tested = False
last_test_result = True
test_results_day_exists = False
test_results_day = 0
I_false_isolation = False
t_false_isolation = t_exposure
t_false_isolation_end = t_exposure
billed_tracer_days = 0
quarantine_dropout_chance = quarantine_dropout_rate
quarantine_dropout_rate_pos_test = 0.0 * quarantine_dropout_rate
quarantine_dropout_rate_not_released = quarantine_dropout_rate * (1 - dropout_reduction_for_symptoms)
quarantine_dropout_rate_neg_test = quarantine_dropout_rate * 2
summary = []
seen_symptoms = False
# print("infected ", quarantine_dropout_chance)
while not (day >= t_quarantine_end and day >= t_isolation_end and day >= t_isolation_end and day >= t_infectious_end and day >= t_false_isolation_end):
# code.interact(local=locals())
# symptoms are developed during quarantine or already exist when quarantine started
if I_symptoms and day >= t_symptoms and ((I_quarantine and t_quarantine <= day < t_quarantine_end) or (I_monitor and t_monitor <= day < t_monitor_end)) and not symptoms_observed:
if I_isolation:
t_isolation = min(t_isolation, day + 1)
else:
t_isolation = day
I_isolation = True
t_isolation_end = t_isolation + symp_quarantine_length
t_quarantine_end = min(t_quarantine_end, t_isolation_end)
symptoms_observed = True
# is this a billed tracer day
if (I_quarantine and t_quarantine <= day < t_quarantine_end) or (I_monitor and t_monitor <= day < t_monitor_end):
billed_tracer_days += 1
# is this person quarantined today? do they drop out?
# print(day - t_exposure, t_infectious <= day < t_infectious_end, (not I_quarantine or not (t_quarantine <= day < t_quarantine_end)) and (not I_isolation or not (t_isolation <= day < t_isolation_end)) and (not I_false_isolation or not (t_false_isolation <= day < t_false_isolation_end)), summary)
if t_infectious <= day < t_infectious_end:
if (not I_quarantine or not (t_quarantine <= day < t_quarantine_end)) and (not I_isolation or not (t_isolation <= day < t_isolation_end)) and (not I_false_isolation or not (t_false_isolation <= day < t_false_isolation_end)):
transmission_days += 1
if I_symptoms and day >= t_symptoms:
summary.append('symp. transmit')
else:
summary.append('asymp. transmit')
else:
isolation_days += 1
summary.append('isolation')
elif I_quarantine and t_quarantine <= day < t_quarantine_end:
if (I_isolation and t_isolation <= day < t_isolation_end):
isolation_days += 1
summary.append('isolation')
elif I_false_isolation and t_false_isolation <= day < t_false_isolation_end:
false_isolation_days += 1
summary.append('false isolation')
else:
quarantine_days += 1
summary.append('quarantine')
elif I_isolation and t_isolation <= day < t_isolation_end:
isolation_days += 1
summary.append('isolation')
elif I_false_isolation and t_false_isolation <= day < t_false_isolation_end:
false_isolation_days += 1
summary.append('false isolation')
elif I_monitor and t_monitor <= day < t_monitor_end:
monitoring_days += 1
if day >= t_false_positive and not I_false_isolation:
I_false_isolation = True
t_false_isolation = day
t_false_isolation_end = day + symp_quarantine_length
# print(day - t_exposure, t_infectious <= day < t_infectious_end, (not I_quarantine or not (t_quarantine <= day < t_quarantine_end)) and (not I_isolation or not (t_isolation <= day < t_isolation_end)) and (not I_false_isolation or not (t_false_isolation <= day < t_false_isolation_end)), summary)
# adjust quarantine dropout chance
# print("day, dropout ", day, quarantine_dropout_chance)
if I_early_release and early_release_day <= day < early_release_day + 1:
quarantine_dropout_chance = quarantine_dropout_rate_not_released
if test_results_day_exists and test_results_day <= day < test_results_day + 1:
if I_test_positive:
quarantine_dropout_chance = quarantine_dropout_rate_pos_test
else:
quarantine_dropout_chance = quarantine_dropout_rate_neg_test
# drop out of quarantine
if I_quarantine and t_quarantine <= day < t_quarantine_end and not (
(I_isolation and t_isolation <= day < t_isolation_end) or
(I_false_isolation and t_false_isolation <= day <= t_false_isolation_end)):
if day - t_quarantine < precalc_dropout and quarantine_dropout_chance == quarantine_dropout_rate:
if dropouts[0][int(day - t_quarantine)] > 0.:
t_quarantine_end = day
t_monitor_end = day
elif np.random.binomial(n=1, p=quarantine_dropout_chance):
t_quarantine_end = day
t_monitor_end = day
# is this person tested today?
if I_double_test and day >= t_test_day and t_quarantine <= day < t_quarantine_end - test_delay:
I_test_positive = calc_test_single(day - t_symptoms, True)
test_results_day = day + test_delay
test_results_day_exists = True
tested = True
n_tests += 1
if not last_test_result and not I_test_positive:
t_quarantine_end = min(day + test_delay, t_quarantine_end)
I_double_test = False
else:
last_test_result = I_test_positive
t_test_day = day + test_delay + wait_before_testing
# print(I_test and day >= t_test_day and not tested and t_quarantine <= day < t_quarantine_end - test_delay)
if I_test and day >= t_test_day and not tested and t_quarantine <= day < t_quarantine_end - test_delay:
# if I_test and day >= t_test_day and not tested and (day - t_symptoms >= target_test_day):
I_test_positive = calc_test_single(day - t_symptoms, True)
test_results_day = day + test_delay
test_results_day_exists = True
# days_rel_to_sympts.append(day - t_symptoms)
if not I_test_positive:
# negatives[0] += 1
t_quarantine_end = min(day + test_delay, t_quarantine_end)
else:
pass
# positives[0] += 1
tested = True
n_tests += 1
# code.interact(local=locals())
if I_random_testing and not I_test_positive and np.random.binomial(n=1, p=test_freq):
# if I_random_testing and not I_test_positive and first_test <= day < t_infectious_end and 0 <= (day - first_test) % test_interval < 1:
I_test_positive = calc_test_single(day - t_symptoms, True)
if I_test_positive:
if I_isolation:
t_isolation = min(t_isolation, day)
else:
t_isolation = day
I_isolation = True
t_isolation_end = t_isolation + symp_quarantine_length
t_quarantine_end = min(t_quarantine_end, t_isolation_end)
tested = True
n_tests += 1
if int(round(day - t_exposure) + 1) > len(summary):
summary.append('inactive')
# if len(summary) >= 2 and (summary[-2] == 'asymp. transmit'):
# print(t_infectious <= day < t_infectious_end, (not I_quarantine or not (t_quarantine <= day < t_quarantine_end)) and (not I_isolation or not (t_isolation <= day < t_isolation_end)), t_quarantine <= day < t_quarantine_end, t_isolation <= day < t_isolation_end)
# print(summary)
# print('\n')
# infectious, but not quarantined or isolated
day += 1
# print("billed tracer days", billed_tracer_days, quarantine_days, isolation_days, t_isolation_end - t_isolation)
print(summary)
return (quarantine_days, isolation_days, transmission_days, n_tests, monitoring_days, false_isolation_days, billed_tracer_days, summary)
def draw_infections_from_contacts(num_individuals, g0_COVID, g0_symptoms,
g0_original_case, g0_superspreader,
g0_test_positive, g0_incubation_infect,
g0_t_self_isolate, g0_I_contacted,
g0_contacts, trace_delay=0, test_delay=0,
trace=False, trace_superspreader=False,
ttq=False, early_release=False, vacc_eff=0.,
tfn=0.0, wait_before_testing=0, ttq_double=False,
household_SAR=base_household_cal, external_SAR=base_external_cal,
SS_mult=SS_mult_cal, phys_mult=phys_mult_cal,
monitor=False, seed=0):
np.random.seed(seed)
n_age = []
t_exposure = []
t_last_exposure = []
t_exposure_days = []
original_case = []
infected_by = []
I_COVID = []
I_household = []
infected_by_presymp = []
infected_by_asymp = []
successful_traces = []
quarantine_days_of_uninfected = 0
tests_of_uninfected = 0
monitoring_days_of_uninfected = 0
# SAR_SS_household = max(min(frac_infs_from_SS * symptoms_household_SAR / ((1 + frac_infs_from_SS) / (1 + 1 / freq_superspreaders)), 1), 0)
# SAR_SS_ext = max(min(frac_infs_from_SS * symptoms_external_SAR / ((1 + frac_infs_from_SS) / (1 + 1 / freq_superspreaders)), 1), 0)
# SAR_reg_household = max(min((symptoms_household_SAR - SAR_SS_household * freq_superspreaders) / (1 - freq_superspreaders), 1), 0)
# SAR_reg_ext = max(min((symptoms_external_SAR - SAR_SS_ext * freq_superspreaders) / (1 - freq_superspreaders), 1), 0)
uninfected_source = []
uninfected_exposure = []
uninfected_household = []
uninfected_exposure_days = []
household_exposures = 0
household_infections = 0
external_exposures = 0
external_infections = 0
num_downstream_contacts_by_id = np.zeros(num_individuals)
num_downstream_traces_by_id = np.zeros(num_individuals)
SARS = []
for i in range(num_individuals):
if not g0_COVID[i]:
continue
for j in range(len(g0_contacts[i])):
num_downstream_contacts_by_id[i] += 1
traced = np.random.binomial(n=1, p=1 - tfn) > 0.99
if traced and g0_I_contacted[i] and trace:
num_downstream_traces_by_id[i] += 1
infected = False
SAR = 1.0
if g0_contacts[i][j][2]:
SAR = household_SAR
household_exposures += 1
else:
SAR = external_SAR
external_exposures += 1
if g0_contacts[i][j][7]:
SAR = SAR * phys_mult
if g0_superspreader[i]:
SAR = SAR * SS_mult
if not g0_symptoms[i]: # or g0_contacts[i][j][6] < days_infectious_before_symptoms:
SAR = SAR * asymp_infectiousness
if g0_symptoms[i] and g0_contacts[i][j][4] < g0_incubation_infect[i] + days_infectious_before_symptoms:
SAR = SAR * presymp_infectiousness
SAR = min(max(SAR, 0.), 1.)
if i == 0:
SARS.append(SAR)
infected = np.random.binomial(n=1, p=SAR)
if infected and g0_contacts[i][j][8]:
if np.random.binomial(n=1, p=vacc_eff):
infected = False
if infected:
if g0_contacts[i][j][2]:
household_infections += 1
else:
external_infections += 1
if g0_contacts[i][j][4] < g0_incubation_infect[i] + days_infectious_before_symptoms and g0_symptoms[i]:
infected_by_presymp.append(True)
else:
infected_by_presymp.append(False)
if not g0_symptoms[i]:
infected_by_asymp.append(True)
else:
infected_by_asymp.append(False)
successful_traces.append(traced)
n_age.append(g0_contacts[i][j][0])
t_exposure.append(g0_contacts[i][j][4])
t_last_exposure.append(g0_contacts[i][j][6])
t_exposure_days.append(g0_contacts[i][j]['exposure_days'])
infected_by.append(g0_contacts[i][j][5])
I_household.append(g0_contacts[i][j][2])
I_COVID.append(1)
if g0_original_case[i] == -1:
original_case.append(g0_contacts[i][j][5])
else:
original_case.append(g0_original_case[i])
g0_contacts[i][j]['transmit'] = True
else:
g0_contacts[i][j]['transmit'] = False
if g0_I_contacted[i] and trace and traced:
# trace_start = g0_t_self_isolate[i] + trace_delay + test_delay
# quarantine_end = asymp_quarantine_length + g0_contacts[i][j][6]
uninfected_source.append(i)
uninfected_exposure.append(g0_contacts[i][j][6])
uninfected_exposure_days.append(g0_contacts[i][j]['exposure_days'])
uninfected_household.append(g0_contacts[i][j][2])
g0_contacts[i][j]['I_contacted'] = True
else:
g0_contacts[i][j]['I_contacted'] = False
# print('SARS', SARS)
# print(g0_contacts[0])
return (n_age, t_exposure, t_last_exposure, t_exposure_days, original_case, infected_by, I_COVID, I_household, successful_traces,
quarantine_days_of_uninfected, tests_of_uninfected, monitoring_days_of_uninfected,
infected_by_presymp, infected_by_asymp, uninfected_source, uninfected_exposure, uninfected_household, uninfected_exposure_days,
num_downstream_contacts_by_id, num_downstream_traces_by_id, household_infections / household_exposures if household_exposures > 0 else 0.,
external_infections / external_exposures if external_exposures > 0 else 0.)
def calc_pooled_tests(g1_infected_by, g1_t_incubation, g0_I_contacted,
g0_t_self_isolate, successful_traces, trace_delay, test_delay,
dropouts, test_day, seed=0):
positive_tests = np.zeros(len(g0_t_self_isolate))
dropout_sum = np.sum(dropouts, axis=1)
tests_per_parent_case = np.zeros(len(g0_t_self_isolate))
tests_per_case = np.zeros(len(g1_t_incubation))
for i in range(len(g1_I_symptoms)):
if not successful_traces[i] or dropout_sum[i] > 0. or not g0_I_contacted[parent_case]:
continue
parent_case = int(g1_infected_by[i])
if tests_per_parent_case[i] >= pooling_max:
continue
time_of_symptoms_rel_to_monitoring = g1_t_incubation[i] - (g0_t_self_isolate[parent_case] + trace_delay + test_delay)
positive_tests[parent_case] += calc_test_single(test_day - time_of_symptoms_rel_to_monitoring, True)
tests_per_parent_case[parent_case] += 1
if tests_per_parent_case[parent_case] < 2.:
tests_per_case[i] += 1
return (positive_tests, tests_per_case)
def calc_symptoms_by_day(g1_I_symptoms, g1_infected_by, g1_t_incubation, g1_false_positive, g0_I_contacted,
g0_t_self_isolate, successful_traces, trace_delay, test_delay,
uninf_g1_source, uninf_g1_false_positive,
dropouts, tracking_days):
symptoms_by_day = np.zeros((len(g0_t_self_isolate), tracking_days))
symptoms_by_day_infected = np.zeros((len(g0_t_self_isolate), tracking_days))
symptoms_by_day_uninf = np.zeros((len(g0_t_self_isolate), tracking_days))
time_of_symptoms_rel_to_monitoring = np.ones(len(g1_I_symptoms)) * -1
time_of_symptoms = np.ones(len(g1_I_symptoms)) * -1
# the infected
# print('initial', tracking_days, symptoms_by_day, dropouts)
for i in range(len(g1_I_symptoms)):
if not successful_traces[i]:
continue
seen_symptoms = False
dropped_out = False
parent_case = int(g1_infected_by[i])
if not g0_I_contacted[parent_case]:
continue
time_of_symptoms[i] = g1_false_positive[i]
if g1_I_symptoms[i]:
time_of_symptoms[i] = min(g1_false_positive[i], g1_t_incubation[i])
time_of_symptoms_rel_to_monitoring[i] = time_of_symptoms[i] - (g0_t_self_isolate[parent_case] + trace_delay + test_delay)
for j in range(tracking_days):
# print("sanity", i, parent_case, j)
if dropouts[i, j]:
dropped_out = True
if seen_symptoms:
symptoms_by_day[parent_case, j] += 1
symptoms_by_day_infected[parent_case, j] += 1
elif not dropped_out and j + g0_t_self_isolate[parent_case] + trace_delay + test_delay >= time_of_symptoms[i]:
seen_symptoms = True
symptoms_by_day[parent_case, j] += 1
symptoms_by_day_infected[parent_case, j] += 1
# print("stats", i, parent_case, g1_I_symptoms[i], time_of_symptoms[i], g1_false_positive[i], g1_t_incubation[i], 0 + g0_t_self_isolate[parent_case] + trace_delay + test_delay, symptoms_by_day)
# uninfected
for i in range(len(uninf_g1_source)):
seen_symptoms = False
dropped_out = False
parent_case = int(uninf_g1_source[i])
for j in range(tracking_days):
if dropouts[i + len(g1_I_symptoms), j]:
dropped_out = True
if seen_symptoms:
symptoms_by_day[parent_case, j] += 1
symptoms_by_day_uninf[parent_case, j] += 1
elif not dropped_out and j + g0_t_self_isolate[parent_case] + trace_delay + test_delay >= uninf_g1_false_positive[i]:
symptoms_by_day[parent_case, j] += 1
symptoms_by_day_uninf[parent_case, j] += 1
seen_symptoms = True
# print("trace starts", g0_t_self_isolate + trace_delay + test_delay)
# print("time of symptoms inf", time_of_symptoms_rel_to_monitoring)
# print("time of genuine symptoms", g1_t_incubation)
# print("infected symptoms by day", symptoms_by_day_infected)
# # print("inf dropouts", dropouts[:len(g1_t_incubation)])
# print("time of symptoms uninf", uninf_g1_false_positive)
# print("uninfected symptoms by day", symptoms_by_day_uninf)
# # print("uninf dropouts", dropouts[len(g1_t_incubation):])
return symptoms_by_day
def calc_quarantine_uninfected(trace_start, quarantine_end, t_exposure,
wait_before_testing=0, test_day=0,
test_delay=0,
early_release_day=0, early_release=False,
n_consec_test=0, test_release=False,
I_monitor=False, monitor_start=0,
monitor_end=0, symptom_false_positive=0,
dropouts=np.zeros(1).reshape(1, -1), precalc_dropout=0,
quarantine_dropout_rate=quarantine_dropout_rate_default):
day = trace_start
tests = 0
consec_negative_tests = 0
quarantine_dropout_chance = quarantine_dropout_rate
quarantine_dropout_rate_pos_test = 0.0 * quarantine_dropout_rate
quarantine_dropout_rate_not_released = quarantine_dropout_rate * (1 - dropout_reduction_for_symptoms)
quarantine_dropout_rate_neg_test = quarantine_dropout_rate * 2
quarantine_days = 0
monitor_days = 0
end = quarantine_end
test_results_day = 0
false_positive_isolation_days = 0
I_self_isolate = False
t_self_isolate = 0
t_self_isolate_end = -1
# print("np.shape", np.shape(dropouts), np.shape(dropouts)[0], day - trace_start, day - trace_start < precalc_dropout)
if I_monitor:
end = max(quarantine_end, monitor_end)
while day < quarantine_end or (I_monitor and day < monitor_end) or (I_self_isolate and day < t_self_isolate_end):
if trace_start <= day < quarantine_end:
quarantine_days += 1
elif I_self_isolate and t_self_isolate <= day < t_self_isolate_end:
false_positive_isolation_days += 1
elif I_monitor and monitor_start <= day < monitor_end:
monitor_days += 1
# print("monitoring sub", day, t_exposure, symptom_false_positive, not I_self_isolate)
if day >= t_exposure + symptom_false_positive and not I_self_isolate:
I_self_isolate = True
t_self_isolate = day
t_self_isolate_end = t_self_isolate + symp_quarantine_length
if test_release and day >= test_results_day and tests >= 1:
if consec_negative_tests >= n_consec_test:
quarantine_end = day
quarantine_dropout_chance = quarantine_dropout_rate_neg_test
if trace_start <= day < quarantine_end:
if precalc_dropout > 0 and day - trace_start < precalc_dropout:
if quarantine_dropout_chance == quarantine_dropout_rate and dropouts[0][int(math.floor(day - trace_start))] > 0.:
quarantine_end = day
if I_monitor:
monitor_end = day
elif np.random.binomial(n=1, p=quarantine_dropout_chance):
quarantine_end = day
if I_monitor:
monitor_end = day
if test_release and day - test_results_day >= wait_before_testing and day >= test_day and trace_start <= day < quarantine_end:
test_results_day = day + test_delay
tests += 1
consec_negative_tests += 1
if early_release and day >= early_release_day:
quarantine_dropout_chance = quarantine_dropout_rate_not_released
day += 1
# print(n_consec_test, test_release, initial_quarantine_length, quarantine_days)
# if report:
# print("monitoring", day, I_monitor, monitor_end, quarantine_end, trace_start, false_positive_isolation_days)
# print("quarantine", t_exposure, trace_start, quarantine_end)
return (quarantine_days, tests, monitor_days, false_positive_isolation_days)
def calc_quarantine_days_of_uninfected(uninf_g1_source, uninf_g1_exposure_day, uninf_g1_household,
symptom_false_positive,
g1_I_symptoms, g1_t_symptoms,
g0_t_self_isolate, g0_test_positive,
g0_I_contacted, g0_superspreader, ttq=False,
ttq_double=False, trace=False,
trace_delay=0, test_delay=0, wait_before_testing=0,
wait_until_testing=0,
early_release=False,
quarantine_by_parent_case_release=np.zeros(1),
early_release_by_parent_case=np.zeros(1),
monitor=False, dropouts=np.zeros(1).reshape(1, -1),
precalc_dropout=0, quarantine_dropout_rate=quarantine_dropout_rate_default,
hold_hh=False,
seed=0):
np.random.seed(seed)
quarantine_days_of_uninfected = np.zeros(len(g0_t_self_isolate))
tests_of_uninfected = np.zeros(len(g0_t_self_isolate))
monitoring_days_of_uninfected = np.zeros(len(g0_t_self_isolate))
isolation_days_of_uninfected = np.zeros(len(g0_t_self_isolate))
total_contacts = 0.
released_contacts = 0.
isolation_events = 0.
# print("uninfected ", quarantine_dropout_rate)
for i in range(len(uninf_g1_source)):
parent_case = int(uninf_g1_source[i])
if g0_I_contacted[parent_case] and trace:
total_contacts += 1
trace_start = g0_t_self_isolate[parent_case] + trace_delay + test_delay
quarantine_end = asymp_quarantine_length + uninf_g1_exposure_day[i]
test_day = max(uninf_g1_exposure_day[i] + wait_before_testing + wait_until_testing, trace_start + wait_before_testing)
monitor_start = trace_start
monitor_end = quarantine_end
if early_release:
if (not quarantine_by_parent_case_release[parent_case]) or (hold_hh and uninf_g1_household[i]):
tmp = calc_quarantine_uninfected(trace_start=trace_start,
quarantine_end=quarantine_end,
early_release=True,
early_release_day=early_release_by_parent_case[parent_case] + trace_start,
I_monitor=monitor,
monitor_start=monitor_start,
monitor_end=monitor_end,
symptom_false_positive=symptom_false_positive[i],
t_exposure=uninf_g1_exposure_day[i],
dropouts=dropouts[i].reshape(1, -1),
precalc_dropout=precalc_dropout,
quarantine_dropout_rate=quarantine_dropout_rate)
elif ttq:
tmp = calc_quarantine_uninfected(trace_start=trace_start,
quarantine_end=quarantine_end,
I_monitor=monitor,
n_consec_test=1, test_release=True,
test_delay=test_delay,
test_day=test_day,
wait_before_testing=wait_before_testing,
monitor_start=monitor_start,
monitor_end=monitor_end,
symptom_false_positive=symptom_false_positive[i],
t_exposure=uninf_g1_exposure_day[i],
dropouts=dropouts[i].reshape(1, -1),
precalc_dropout=precalc_dropout,
quarantine_dropout_rate=quarantine_dropout_rate)
released_contacts += 1
else:
tmp = calc_quarantine_uninfected(trace_start=trace_start,
quarantine_end=min(quarantine_end,
trace_start + early_release_by_parent_case[parent_case]),
I_monitor=monitor,
monitor_start=monitor_start,
monitor_end=monitor_end,
symptom_false_positive=symptom_false_positive[i],
t_exposure=uninf_g1_exposure_day[i],
dropouts=dropouts[i].reshape(1, -1),
precalc_dropout=precalc_dropout,
quarantine_dropout_rate=quarantine_dropout_rate)
released_contacts += 1
elif ttq:
tmp = calc_quarantine_uninfected(trace_start=trace_start, quarantine_end=quarantine_end,
wait_before_testing=wait_before_testing,
test_delay=test_delay,
test_day=test_day,
n_consec_test=1, test_release=True, I_monitor=monitor,
monitor_start=monitor_start,
monitor_end=monitor_end,
symptom_false_positive=symptom_false_positive[i],
t_exposure=uninf_g1_exposure_day[i],
quarantine_dropout_rate=quarantine_dropout_rate)
elif ttq_double:
tmp = calc_quarantine_uninfected(trace_start=trace_start, quarantine_end=quarantine_end,
wait_before_testing=wait_before_testing, test_delay=test_delay,
n_consec_test=2, test_release=True, I_monitor=monitor,
test_day=test_day,
monitor_start=monitor_start,
monitor_end=monitor_end,
symptom_false_positive=symptom_false_positive[i],
t_exposure=uninf_g1_exposure_day[i],
quarantine_dropout_rate=quarantine_dropout_rate)
else:
tmp = calc_quarantine_uninfected(trace_start=trace_start,
quarantine_end=quarantine_end, I_monitor=monitor,
monitor_start=monitor_start,
monitor_end=monitor_end,
symptom_false_positive=symptom_false_positive[i],
t_exposure=uninf_g1_exposure_day[i],
quarantine_dropout_rate=quarantine_dropout_rate)
quarantine_days_of_uninfected[parent_case] += tmp[0]
tests_of_uninfected[parent_case] += tmp[1]
monitoring_days_of_uninfected[parent_case] += tmp[2]