-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCT_IBM_2021.m
4391 lines (3605 loc) · 212 KB
/
CT_IBM_2021.m
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
%% SIS model
% It can be used for single (nonAMR or AMR) or two-strain (nonAMR/AMR) coinfection
%
% ----------------------LABELS--------------------------------------
% In order to understand the code in a modular way. We have distinguished,
% using labels and respective colours,3 main process ordered by their
% importance. Every property and method in this class has at least one of
% these labels. The nomenclature for the labels is
%
% 1) (NET)(red) : Affecting the NETwork.
% 2) (DIS)(green) : Propagation of the DISease (without considering the treatment)
% 3) (TRE)(blue) : Affecting the propagation of the TREetment
% 4) (SIL)(maroon): Used by the computer (SILico) but not relevant for the model.
%--------------------------EXAMPLE---------------------------------------
%
% The CT model can be run using the script 'CTmodel_Test.m' in the local
% directory. The parameters are stored in 'params_het_CT.m'
%
%--------------------------------end of the update NVv
%
% This is the main class library - run model via the run_AMR.m script
%
% - Static, scale-free partnership network
%
% - Independent transmission of strains with rate BETA_[1,2]
%
% - Natural recovery with rate R (both strains independently)
%
% - Recovery via birth/death (all infections removed)
%
% - Recovery via intervention: - voluntary treatment seeking
% : for symptomatic patients
% (a proportion of which seek care)
%
% - screening with rate GAMMA
% : updates RECALL notifications for infectees
%
% - partner tracing
% : proportion PSI of infectees partners
% are traced with the correct nonAMR/AMR
% status
%
%
%
% Author of first MSM model: Adam Zienkiewicz, 2016 ([email protected])
% University of Bristol
% Last update: 20/10/16
%
% Author of initial heterosexual version model: Nicolas Verschueren, 2018
% University of Bristol
% Last update: May/18
%
% Author of CT model adaptation: Sandra Montes Olivas, 2021
% University of Bristol
% Last update: Sept/21
%
% The follwing class is an adaptation of the original code for the
% dynamics of gonorrhea with two strains in a network of men having sex
% with men (MSM). In this new version, a strictly heterosexual network
% considered. Mainly, the network was changaed into a bipartite one.
%
% The changes in the code for the heterogeneous model are:
%
% - Redifine the old properties:
% * ALPHA->ALPHA for females.
% * FULL_MAX_PARTNERS->max for females.
% - Add the new properties:
% * ALPHAM: alpha for males.
% * FULL_MAX_PARTNERSM: max for males.
% * Nm: number of males in the simulation
% * Nf: number of females in the simulation
% * GENDER:1XN index-VECTOR with 1/0 for f/m.
% - Properties replaced
% * 'pl_network'|--->'plhet_network'
%
% CAVEAT: THE RESTRICT_MAX_PARTNERS is the same for males and females.
%
% The changes in the code for the CT model are:
%
% - Add the new properties:
% * HR_PSI: partner tracing efficiency
% for a subpopulation (treatment
% seeking or high risk population).
% * SCREEN_SEEKED_HIGHRISK: follow-up
% screening for treatment seekers.
% * SCREEN_NumContacts_HIGHRISK:
% screening of high risk population
% according a rate (GAMMA)
% * TRACE_PARNTERS_NumContacts_HIGHRISK:
% ON/OFF function to trace
% partners of a specific
% subpopulation
% * HR_SCREEN_EFFICACY: probability of
% screen efficacy in follow-up
% screening only!; when using
% SCREEN_NumContacts_HIGHRISK, this
% variable is a rate similar to GAMMA
% for universal screening.
% * Re_Screening_Period: waiting period
% between attendance and screening
% for follow-up patients
% * highRisk_population: selected
% subpopulation, which may be high
% risk or follow-up treatment
% seekers
%
%
%
classdef CT_IBM_2021 < handle
properties
%Sexual partnership network parameters
% --------------------------------
% population size (number of individuals) <font color="red">(NET)</font>
%
% This is a Sexual partnership network parameter
%N corresponds to the number of the individuals in the sexual
%partnership, this number remains unchanged along the whole
%simulation.
N;
% Number of male individuals in the network <font color="red">(NET)</font> .
%
% This is a sexual partnership network parameter
% Nm corresponds to the number of male individuals. This number
% remains the same during the whole simulation. The number is
% determined in the function 'plhet_network'
%
Nm;
% Number of female individuals in the network <font color="red">(NET)</font> .
%
% This is a sexual partnership network parameter
% Nm corresponds to the number of female individuals. This number
% remains the same during the whole simulation. The number is
% given by Nf=N-Nm
%
Nf;
%Characteristic exponent for the female population <font color="red">(NET)</font>
%
% If the female distribution of partners obeys a power law
% P(k)~k^alpha
% The property alpha corresponds to this exponent for the female
% population
ALPHA;
%Characteristic exponent for the male population <font color="red">(NET)</font>
%
% If the male distribution of partners obeys a power law
% P(k)~k^alpham
% The property alpham corresponds to this exponent for the male
% population
ALPHAM;
% maximum number of partners on the full network for females <font color="red">(NET)</font> .
%
% This is a Sexual partnership network parameter
% This is the maximum number of partner for the full partnership
% in the female group.
%
%This property is used by the method
% 'plhet_network'
FULL_MAX_PARTNERS;
% maximum numSCREEN_NumContacts_HIGHRISKber of partners on the full network for males <font color="red">(NET)</font> .
%
% This is a Sexual partnership network parameter
% This is the maximum number of partner for the full partnership
% in the male group.
%
%This property is used by the method
% 'plhet_network'
FULL_MAX_PARTNERSM;
% SIS parameters (same for all strains)
% ----------------------------------------
% (SIS parameter) number of different disease strains <font color="green">(DIS)</font> .
%
% This property is used by the methods. CT_IBM_2021 (the constructor),
% Notice that the whole simulation is very sensitive to this number
% which is usually 2.
n_Strains;
% (SIS parameter) natural recovery rate (/day) <font color="green">(DIS)</font> .
%
%This rate is the same for all the strains.
%This property is used by the method 'natural_recovery'
R;
% (SIS parameter) birth / death rate (/day) <font color="green">(DIS)</font> .
%
% This property is used by the method 'birth_dead'
MU;
% (SIS parameter) transmission rate (/day) <font color="green">(DIS)</font> .
%
% This property is used by the method 'spread_infection'
BETA;
GAMMA; % screening rate (/day) <font color="blue">(TRE)</font>
PSI; % tracing efficiency <font color="blue">(TRE)</font>
HR_PSI; % tracing efficiency for high risk population only! (Added by SM)
MAX_TRACE; % max. number of partners who can be traced <font color="blue">(TRE)</font>
% per infected index patient
% initial infection prevalence <font color="green">(DIS)</font>
%
% p0(1) - overall prevalence (either strain)
% p0(2) - proportion of AMR to nonAMR strain
% e.g.
% If 40% of all gonorrhea cases are found to be AMR then p0(2) = 0.4
p0;
P_SYMPTOMS; % proportion of infected cases which are symptomatic <font color="green">(DIS)</font>
P_SEEKS_TREATMENT; % proportion of symptomatic individuals who will seek treatment <font color="blue">(TRE)</font>
% maximum delay between begin flagged as nonAMR (recall/trace) <font color="blue">(TRE)</font>
% and being treated as nonAMR
NON_AMR_MAX_DELAY;
% maximum # partners for a recalled/traced individual to be treated as nonAMR <font color="blue">(TRE)</font>
NON_AMR_MAX_PARTNERS;
RESTRICT_MAX_PARTNERS; % maximum number of partners in a given time-window. <font color="red">(NET)</font>
RESTRICT_RATE; % time-window duration for restricted partnership network (days). Typically a week. <font color="red">(NET)</font>
% Time delays (indays) for
% lab results / symptom onset / seek / recall and traces
LAB_DELAY_MEAN; % mean delay between being screened/treated and AMR risk being known <font color="blue">(TRE)</font>
LAB_DELAY_STD; % std. of above <font color="blue">(TRE)</font>
ONSET_DELAY_MEAN; % mean delay between becoming infected and showing symptoms (if any) <font color="green">(DIS)</font>
ONSET_DELAY_STD; % std. of above <font color="green">(DIS)</font>
SEEK_DELAY_MEAN; % mean number of days between symptom onset and treatment seeking (arrival) <font color="blue">(TRE)</font>
SEEK_DELAY_STD; % std. of above for normal dist. <font color="green">(DIS)</font>
RECALL_DELAY_MEAN; % mean number of days between recall notication and arrival <font color="blue">(TRE)</font>
RECALL_DELAY_STD; % std. of above for normal dist <font color="blue">(TRE)</font>
TRACE_DELAY_MEAN; % mean number of days between trace notication and arrival <font color="blue">(TRE)</font>
TRACE_DELAY_STD; % std. of above for normal dist <font color="blue">(TRE)</font>
% proportion currently treated with recommended dual <font color="blue">(TRE)</font>
% therapy (Ceft/A) at point of care, without prior
% knowledge of strain susceptibility
P_BLINDTREAT_AS_AMR;
% logical <font color="blue">(TRE)</font> . Allow the extra nonAMR treatment route using recall/trace data
% true / false
% (nonAMR treatment can still occur if P_BLINDTREAT_AS_AMR < 1)
ENABLE_nonAMR_RECALL;
ENABLE_nonAMR_TRACE; % logical <font color="blue">(TRE)</font>
% logical <font color="blue">(TRE)</font> require all traced individuals to be screened rather than treated
% on appointment (true/false)
PRESCREEN_TRACED;
% logical <font color="blue">(TRE)</font> :require all symptomatic voluntary treatment seeking individuals
% to be screened rather than treated on appointment (true/false)
PRESCREEN_SEEKED;
% logical <font color="blue">(TRE)</font> :require all symptomatic voluntary treatment seeking individuals
% to be screened again after 3 months from first treatment (true/false)
SCREEN_SEEKED_HIGHRISK;
SCREEN_NumContacts_HIGHRISK;
TRACE_PARNTERS_NumContacts_HIGHRISK;
HR_SCREEN_EFFICACY;
Re_Screening_Period;
% logical <font color="blue">(TRE)</font> : Enable POCT test for all treatment seekers (all routes)
ENABLE_POCT;
% logical <font color="blue">(TRE)</font> : Is POCT strain discriminatory - or 100% Ceft (FALSE)
DISCRIM_POCT;
% logical <font color="green">(DIS)</font> : if ALLOW_COINFECTION = true then individuals can be infected with
% both nonAMR and AMR strains simulteneously.
% if false, then an individual already infected with one strain,
% cannot contract the other
ALLOW_COINFECTION;
% logical <font color="blue">(TRE)</font> . ENABLE / DISABLE any form of treatment
ALLOW_TREAT;
% network toplogy
% ---------------
% Current sexual partnership network (adjacency matrix) <font color="red">(NET)</font>
%
% This is a NxN matrix. It grows for a week and then it is
% re-created using the method 'restric_adj3'
%
adj;
%partnership network including all relationships over a year <font color="red">(NET)</font>
%
% This matrix is either created with the constructor (using the
% method 'pl_network') or provided at the beginning to the
% constructor.
adj_full;
% integrated partnership network from day zero to today <font color="red">(NET)</font>
%
% This network is equal to the adj in the day zero and then is the
% "logical integration" (if the link already existed in the past is
% not erased nor counted twice) over the time. Eventually (in less than a year), it
% converges to adj_full.
%----
% This property is updated in the method 'adj
adj_int;
rel_list_full; % undirected list of relationships (node-node)) <font color="red">(NET)</font>
% degree sequence of full(annual) partnership network <font color="red">(NET)</font>
%
% This N-vector is obtained from the adjacency matrix 'adj_full' as:
% self.num_partners_full = full(sum(self.adj_full,2));
% in the method 'CT_IBM_2021' (the constructor).
%---------------------------------------------------------------
% Notice that in the heterosexual case, this means that the first
% Nm entries correspond to the degree sequence for males and the
% Nm+1:end to the females.
num_partners_full;
mean_degree_full; % mean degree (ave.# partners) <font color="red">(NET)</font>
% list of which nodes will require pruning / number of links to prung <font color="red">(NET)</font>
%
% Nx2 vector with the list of individuals with more partners than
% the threshold RESTRICT_MAX_PARTNERS. The syntax is:
%
% id_casuals(i)=[node extra_partners(above the threshold)]
%
% This property is defined in the constructor. The idea behind the
% name is that the partners above the threshold are "casual"
% partners. Defined in the method CT_IBM_2021 (the constructor)
id_casuals;
% Set of link consisting in the fixed relationships (R_f in the paper) <font color="red">(NET)</font> .
%
%links between nodes which both have
%
% degree <=RESTRICTED_MAX_PARTNERS
%
% this property is defined in the constructor (CT_IBM_2021)
fixed_rels;
% Complementary set to fixed_rels (R_c in the paper) <font color="red">(NET)</font>
%
% links between nodes, with at list one them has a
%
% degree > RESTRICTED_MAX_PARTNERS
%
% This property is defined in the constructor (CT_IBM_2021).
other_rels;
adj_xmin; %THIS PROPERTY IS EMPTY AFTER EVOLVING IN TIME (ASK ADAM)
adj_L; %THIS PROPERTY IS EMPTY AFTER EVOLVING IN TIME (ASK ADAM)
% degree sequence of current partnership network <font color="red">(NET)</font>
%
% This N-vector is obtained from the adjacency matrix adj as:
% self.num_partners = full(sum(self.adj,2));
% in the method 'restrict_adj3'
% Notice that in the heterosexual case, this means that the first
% Nm entries correspond to the degree sequence for males and the
% Nm+1:end to the females.
num_partners;
mean_degree_current; % mean degree of current partnership network (stored history) <font color="red">(NET)</font>
n_Comp; % number of connected network components <font color="red">(NET)</font>
comp_sizes; % sizes of connected components <font color="red">(NET)</font>
comp_members; % members of connected components <font color="red">(NET)</font>
% data arrays and counters (infection state etc.)
% ----------------------------------------------------
% state matrix (individuals infected by each strain over time) <font color="green">(DIS)</font>
%
% This matrix corresponds to \Omega and accounts for the infected individuals in the network. It is a logical variable and
% it has 3 dimensions as follows
% / 1 if the (i)ndividual is infected with the (s)train the (d)ay
% indiv_stat(i,s,d) = |
% \ 0 Otherwise.
% i in 1...N; s=1,2; d=1....today
% Hence,
%
% -The first dimension correspond to an individual (node) in the
% network.
%
% - The second to the strain of gonhorrea:
%
% * 1 non-AMR
% * 2 AMR
%
% -The third correspondto the historial to day. If the model is in the
% LOW_MEMORY regime, this is 1 and is the current state being overwritten. Otherwise the third
% dimension is the number of days (today) and for each day the
% index of infected can be accessed.
%
%---------------METHODS WHERE THIS PROPERTY IS INVOLVED.
%
%
indiv_state;
infected_since; % day last infection acquired (per strain) <font color="green">(DIS)</font>
infection_count; % number of times individual has had infection (per strain) <font color="green">(DIS)</font>
highRisk_population; %Vector to keep track of high risk population - nodes that have been previously infected
% whether current infection is symptomatic (single value) <font color="green">(DIS)</font>
%
% N- index vector accounting for symptomps
%-------Methods where this property is affected/used
%
%
symptoms;
seeks_treatment_on; % day a symptomatic patient will seek treatment <font color="green">(DIS)</font> (without waiting for recall/trace)
% screening (recall) and tracing notification arrays <font color="blue">(TRE)</font>
%
% This is a Nx3 vector with:
%
% col 1: day of notification (calculated considering delay)
% col 2: treatment day(calculated considering delay)
% col 3: AMR risk flag (logical)
%-------------METHODS WHERE THIS PROPERTY IS MODIFIED/USED.
%
%-screening:the screened and infected individuals receive a recall
%written in this array
%
%-seek_treatment: the individuals in recall_notify are one of the 3
%sources of patients looking for treatment
%
recall_notify;
%Tracking screened nodes
screened;
% <font color="blue">(TRE)</font>
%
% Nx3 vector, which is full of nans. I think is not being used.
trace_notify;
today; % number of days which have been simulated (ALL)
burn_in; % whether or not we are in a 'burn-in' cycle (IDN)
% to achieve a set AMR ratio etc.
% counters : structure array of counters (data outputs) <font color="red">(NET)</font> , <font color="blue">(TRE)</font> , <font color="green">(DIS)</font>
%
% with fields:
%
%-------NUMBER
% counters.N; % # individuals in the network (NET
%
%
%--------Cumulative bidimensional array (N,2)
%
% counters.infection_count; % # times the individuals have been infected with nonAMR/AMR (DIS)
% counters.drug_count; % # times each nonAMR/AMR drug prescribed to each patient (TRE)
%
%--------bidimensional array (day,numberof)
%
% counters.cefta; % # CEFT/A (AMR) prescriptions on each day of simulation (TRE)
% counters.cefta_notinf; % # CEFT/A prescriptions which weren't required (susceptible) (TRE)
% counters.cefta_nonAMR; % # CEFT/A prescriptions which weren't required (nonAMR) (TRE)
% counters.cefta_AMR; % # CEFT/A correct prescriptions(AMR infected) (TRE)
% counters.cipr; % Cipr (nonAMR) prescriptions on each day of simulation (TRE)
% counters.cipr_notinf; % # Cipr prescriptions which weren't required (susceptible) (TRE)
% counters.cipr_nonAMR; % # Cipr correct prescriptions (only nonAMR infected) (TRE)
% counters.cipr_AMR; % # Cipr prescriptions which were incorrect (leading to recalled AMR patient)(TRE)
% counters.prevalence; % prevalences - number of individuals with each strain over time (DIS)
% counters.prev_both; % prevalences - number of individuals with both strains (coinfected) over time (DIS)
% counters.prev_either; int8 % prevalence (either strainor both)(DIS)
% counters.incidence; % infection incidence (number of new infections each day, per strain) (DIS)
% counters.incidence_either; S % infection incidence (newinfections of either strain each day)(DIS)
% counters.n_attended_seeked; % number of attendees who voluntarily seeked treatment each time step (TRE)
% counters.n_attended_recalled;% number of attendees who were recalled each time step (TRE)
% counters.n_attended_traced; % number of attendees who were traced each time step (TRE)
% counters.n_attended_treated; % number of attendees who were actually treated each time step (TRE)
% counters.n_screened; % number of people screened at each time step (TRE)
% counters.n_traced; % number of people traced at each time step (TRE)
counters;
ipr; % infected partner ratio (per node degree) <font color="green">(DIS)</font>
% Other
% ------
param_updates; % list of commands and dates to update parameters during simulation (ALL)
DIR_NAME; % directory name for saving data files and plots<font color="maroon"> (SIL)</font>
fig_h; % figure handles <font color="maroon">(SIL)</font>
plot_names; % name of plot (for saviandng purposes) <font color="maroon">(SIL)</font>
VERBOSE; % for controlling console text output <font color="maroon">(SIL)</font>
LOW_MEM; % enable low memory mode (no state histories of each individual) <font color="maroon">(SIL)</font>
DEBUG; % extra console output for debugging <font color="maroon">(SIL)</font>
%--------------------------------------------------------------------------------------------------------
%New part added by nv.
% A 1xN vector with 0/1 (male/female) <font color="red">(NET)</font>
%
% The first Nm individuals are are male. This property is set
% using the proerty Nm, set in the constructor by the method
% 'plhet_network'
%
%
GENDER;
% Ratio of infections coming from the "source of gonhorrea" <font color="green">(DIS) </font>
%
% This property is used by the method 'gono_source'
eta;
%end of nv additions
end % class properties
methods
% Class Constructor
function [self] = CT_IBM_2021(N, params, adj_set, VERBOSE, LOW_MEM)
% Creates the object "model". (ALL)
%
%
% This is the most important and the first method to be invoked. The arguments are:
% [self]=CT_IBM_2021( N, params, adj_set, VERBOSE, LOW_MEM)
% where:
% INPUT:
%
% - N: the number of individuals in the model (typically N=10^3, 10^4).
%
% - params: is the structure containing the parameters values.
%
% - adj_set: is a NxN matrix accounting for the sexual partnership. If an empty array is passed as argument
% (i.e. adj_set=[]),the constructor will make a scale-free network.
%
% - VERBOSE: optional logical argument for the VERBOSE regime.
%
% - LOW_MEM: optional logical argument for the LOW_MEM regime.
%
%
%
% OUTPUT:
% -[self]: a member (an instance) of
% the class CT_IBM_2021
%
%------------------------------------------------------------------
%
% PROCESS.
%------------------------------------------------------------------
% When the contructor is invoked, the following procedures
% are followed.
%
% i) The parameter's values are assigned using the
% information contained in params.
%
% ii) The vectors containing several indices are
% initialised with zeros (e.g. symptomps, seek treatments,
% etc)
%
% iii) If no network is provided (i.e. adj_set=[]), the
% contstuctor calls the function:
%
% [adj,rel_list,Nm]= plhet_network(N,ALPHA,ALPHAM,d_maxF,d_maxm)
%
% to generate the a scale-free network
%
% iv) Set the number of infected individuals at day=0, the
% proportion of them with/without symptomps, plus other
% counters.
%
% Once these four steps are completed, the instance is
% created
%---------NV
if nargin == 4
self.VERBOSE = VERBOSE;
elseif nargin == 5
self.VERBOSE = VERBOSE;
self.LOW_MEM = LOW_MEM;
end
% debug console output ON/OFF
self.DEBUG = false;
% set values from inputs
self.N = N;
% for this AMR / non-AMR implementation, fix n_Strains=2
% (dont even attempt changing this value as much of the code now
% relies on this being equal to 2!)
self.n_Strains = 2;
% i)Set parameter values from params structure
if isempty(params)
error('No model parameters have been assigned!');
end
self.ALPHA = params.ALPHA;
self.FULL_MAX_PARTNERS = params.FULL_MAX_PARTNERS;
self.RESTRICT_MAX_PARTNERS = params.RESTRICT_MAX_PARTNERS;
self.RESTRICT_RATE = params.RESTRICT_RATE;
self.R = params.R;
self.MU = params.MU;
self.BETA = params.BETA;
self.GAMMA = params.GAMMA;
self.PSI = params.PSI;
self.HR_PSI = params.HR_PSI;
self.MAX_TRACE = params.MAX_TRACE;
self.LAB_DELAY_MEAN = params.LAB_DELAY_MEAN;
self.LAB_DELAY_STD = params.LAB_DELAY_STD;
self.ONSET_DELAY_MEAN = params.ONSET_DELAY_MEAN;
self.ONSET_DELAY_STD = params.ONSET_DELAY_STD;
self.SEEK_DELAY_MEAN = params.SEEK_DELAY_MEAN;
self.SEEK_DELAY_STD = params.SEEK_DELAY_STD;
self.RECALL_DELAY_MEAN = params.RECALL_DELAY_MEAN;
self.RECALL_DELAY_STD = params.RECALL_DELAY_STD;
self.TRACE_DELAY_MEAN = params.TRACE_DELAY_MEAN;
self.TRACE_DELAY_STD = params.TRACE_DELAY_STD;
self.P_SYMPTOMS = params.P_SYMPTOMS;
self.P_SEEKS_TREATMENT = params.P_SEEKS_TREATMENT;
self.NON_AMR_MAX_DELAY = params.NON_AMR_MAX_DELAY;
self.NON_AMR_MAX_PARTNERS = params.NON_AMR_MAX_PARTNERS;
self.P_BLINDTREAT_AS_AMR = params.P_BLINDTREAT_AS_AMR;
self.ENABLE_nonAMR_RECALL = params.ENABLE_nonAMR_RECALL;
self.ENABLE_nonAMR_TRACE = params.ENABLE_nonAMR_TRACE;
self.ENABLE_POCT = params.ENABLE_POCT;
self.DISCRIM_POCT = params.DISCRIM_POCT;
self.PRESCREEN_TRACED = params.PRESCREEN_TRACED;
self.PRESCREEN_SEEKED = params.PRESCREEN_SEEKED;
self.SCREEN_SEEKED_HIGHRISK = params.SCREEN_SEEKED_HIGHRISK;
self.HR_SCREEN_EFFICACY = params.HR_SCREEN_EFFICACY;
self.Re_Screening_Period = params.Re_Screening_Period;
self.SCREEN_NumContacts_HIGHRISK = params.SCREEN_NumContacts_HIGHRISK;
self.TRACE_PARNTERS_NumContacts_HIGHRISK = params.TRACE_PARNTERS_NumContacts_HIGHRISK;
self.ALLOW_COINFECTION = params.ALLOW_COINFECTION;
self.ALLOW_TREAT = params.ALLOW_TREAT;
%-----------------------------------------------------------------
%NEW PROPERTIES (ADDED BY NV).
self.ALPHAM=params.ALPHAM;
self.FULL_MAX_PARTNERSM=params.FULL_MAX_PARTNERSM;
self.eta=params.eta;
%end of changes
% some warnings / overrides
if self.ENABLE_POCT && ((self.LAB_DELAY_MEAN > 0) || (self.LAB_DELAY_STD > 0))
warning('Point-of-care treatment has been enabled but LAB delay values are non-zero...resetting delays')
self.LAB_DELAY_MEAN = 0;
self.LAB_DELAY_STD = 0;
end
%ii)
% set initial prevalences
self.p0 = params.p0;
% state matrix
% 1: non-AMR state
% 2: AMR state
% 3: date infection acquired (either strain)
% 4: symptomatic (true / false)
self.indiv_state = false(self.N,self.n_Strains,1);
% day on which particular strain passed to (susceptible) individual
% initialise with NaNs
self.infected_since = nan(self.N,self.n_Strains);
% flags indicating whether infections are symptomatic
self.symptoms = false(self.N,1);
% values indicating if/when(day) symptomatic individual will voluntarily seek
% treatment (init with NaNs - value assigned when necessary)
self.seeks_treatment_on = nan(self.N,1);
% screening / recall notification matrix
% (day recall issued, day attending, AMR flag)
self.recall_notify = nan(self.N,3);
% tracing notification matr2000ix
% (day trace issued, day attending, AMR flag)
self.trace_notify = nan(self.N,3);
% treatment counters for each individual
self.counters = struct;
self.counters.N = self.N;
% count number of times each individual has been infected
% (per strain)
self.counters.infection_count = zeros(self.N,self.n_Strains);
% screening matrix
% (day screening)
self.counters.screened = false(self.N,1);
% flags indicating all those that seeked attention and are
% High risk
self.counters.idx_highRisk_population = false(self.N,1);
%Addition of High risk population vector
self.counters.highRisk_population = zeros(self.N,3);
% 2 drugs,e.g. Cipr for non-AMR, Ceft/A for AMR strains
self.counters.drug_count = zeros(self.N,2);
% total CEFT/A prescribed each day
self.counters.cefta = 0;
% of which prescribed to non-infected individuals [0 0]
self.counters.cefta_notinf = 0;
% of which prescribed to nonAMR individuals [1 0]
% (POOR TREATMENT CHOICE / WASTE)
self.counters.cefta_nonAMR = 0;
% of which prescribed to AMR individuals [0 1] or [1 1]
% (CORRECT TREATMENT)
self.counters.cefta_AMR = 0;
% total Cipr prescribed each day
self.counters.cipr = 0;
% of which prescribed to non-infected individuals [0 0]
self.counters.cipr_notinf = 0;
% of which prescribed to AMR infected individuals [0 1] or [1 1 ]
% (MISTREATMENT REQUIRING RECALL)
self.counters.cipr_AMR = 0; % each day
% of which prescribed to AMR infected individuals [1 0]
% (CORRECT TREATMENT)
self.counters.cipr_nonAMR = 0; % each day
% prevalences - number of individuals with each strain
% : nonAMR / AMR
self.counters.prevalence = zeros(1,2);
self.counters.prev_both = 0;
self.counters.prev_either = 0;
self.counters.prev_nonAMRonly = 0;
% incidence - number of new infections of each strain each day
self.counters.incidence = zeros(1,2);
self.counters.incidence_either = 0;
self.counters.incidence_new = 0;
% number of people who attended after voluntarily seeking at each time step
% (2nd/3rd column: number infected with each strain)
self.counters.n_attended_seeked = zeros(1,3);
% number of people who attended after being recalled at each time step
% (2nd/3rd column: number infected with each strain)
self.counters.n_attended_recalled = zeros(1,3);
% number of people who attended after being recalled at each time step
% (2nd/3rd column: number infected with each strain)
self.counters.n_attended_traced = zeros(1,3);
% number of people who attended and were treated at each time step
% (2nd/3rd column: number infected with each strain)
self.counters.n_attended_treated = zeros(1,3);
self.counters.n_treated_infected_symptomatic = zeros(1,2);
% number of people who were screened at each time step
% (2nd/3rd column: number infected with each strain)
% - number of recalled individuals will be rowsum of
% columns 2 and 3
self.counters.n_screened = zeros(1,3);
% number of people traced at each time step
% (2nd/3rd column: number infected with each strain)
self.counters.n_traced = zeros(1,3);
% number of people recalled at each time step
% (2nd/3rd column: number infected with each strain)
self.counters.n_recalled = zeros(1,3);
% data for analysing undertreatment with nonAMR
% therapy using informed treatment scenario
self.counters.informed.undertreated_degree = [];
self.counters.informed.undertreated_infected_duration = [];
self.counters.informed.correct_degree = [];
self.counters.informed.correct_infected_duration = [];
% file info for saving
%self.DIR_NAME = ['_N=',num2str(N),'_nS=',num2str(self.n_Strains),'_days=',num2str(self.today)];
self.DIR_NAME = 'temp';
self.fig_h = [];
self.plot_names = {};
self.param_updates = {};
%iii)
% generate (static) partership network structure
if self.VERBOSE
if isempty(adj_set)
fprintf(['Generating scale-free network structure with ALPHA=(female ; male)) = (',num2str(self.ALPHA),';',num2str(self.ALPHAM),') ....']);
else
fprintf(['Using pre-generated network with ALPHA = ', num2str(adj_set.alpha_out),'....']);
end
end
tic;
if isempty(adj_set)
self.adj_full = [];
%heterosexual network
[self.adj_full,self.rel_list_full,self.Nm]=self.plhet_network(self.N,self.ALPHA,self.ALPHAM,self.FULL_MAX_PARTNERS,self.FULL_MAX_PARTNERSM);
%HOMOSEXUAL NETWORK
% % loop mitigates minor bug producing errors for very small N<10 networks
% while length(self.adj_full) ~= self.N
% %[self.adj_full,~,self.rel_list_full] =
% %self.pl_network(self.N,self.ALPHA,self.FULL_MAX_PARTNERS);%homosexual version
%
%
% end
else
self.adj_full = adj_set.adj;
self.rel_list_full = adj_set.rel_list;
self.ALPHA = adj_set.alpha_out;
self.FULL_MAX_PARTNERS = adj_set.d_max;
self.adj_xmin = adj_set.x_min;
self.adj_L = adj_set.L;
end
network_elapsed = toc;
self.Nf=self.N-self.Nm;
gen=zeros(self.N,1); gen(self.Nm+1:end)=true;
self.GENDER=gen;
% degree sequence of full network generated
% (from row sums of adjacency matrix)
%--NV
%Notice that this is for the full matrix and thereofre is
%the concatenation of the degree sequence for males Nm and
%females.
self.num_partners_full = full(sum(self.adj_full,2));
% mean node degree of network
%-NV
%Notice that this is for the full matrix and therefore is
%not considering the average in each gender.
self.mean_degree_full = mean(self.num_partners_full);
% number, size and members of connected components
[self.n_Comp,self.comp_sizes,self.comp_members] = self.networkComponents(self.adj_full);
%Notice that the output properties of this function are not
%used anywhere apart from the console output (That's why
%this function is not in the flowchart
% set default daily partnership network
self.adj = self.adj_full;
self.num_partners = self.num_partners_full;
%THIS IS THE PRECOMPUTATION FOR THE SUB-NETWORK
%
% restrict daily partnership network by limiting -----
% individuals to a max number of partners per day
partner_check = self.num_partners_full - self.RESTRICT_MAX_PARTNERS;
self.id_casuals = [find(partner_check > 0), partner_check(partner_check>0)];
% pre-calculate fixed and prunable links
self.fixed_rels = self.rel_list_full;
% fixed links (won't include any links to nodes with degree > threshold)
for i = self.id_casuals(:,1)'
id_remove = self.fixed_rels(:,1) == i | self.fixed_rels(:,2) == i;
self.fixed_rels(id_remove,:) = [];
end
% prunable links
self.other_rels = setdiff(self.rel_list_full, self.fixed_rels,'rows');
self.adj_int = sparse(self.N,self.N);
self.mean_degree_current = zeros(1,2);
self.restrict_adj3();
%------------------------------------------------------
% console output
if self.VERBOSE
fprintf(['[DONE - in ',sprintf('%.2f',network_elapsed),' sec]']);
fprintf(['\n\t> mean degree (ave. partners) \t= ',sprintf('%.2f',self.mean_degree_full)]);
fprintf(['\n\t> # connected components \t= ',num2str(self.n_Comp),'\n\n']);
end
% console output
if self.VERBOSE
fprintf(['\n--------------------------------------------------\n',...
'Multi-strain SIS\n',...
'------------------\n']);
fprintf(['Population size (N) \t\t= ',num2str(self.N),...
'\nNumber of Females/Males\t=',num2str(self.Nf),'/',num2str(self.Nm),...
'\nNumber of Strains \t\t= ',num2str(self.n_Strains),...
'\nInfection rate (Beta) \t\t= ',sprintf('%.2s',self.BETA(1)),' (non-AMR), ',sprintf('%.2s',self.BETA(2)),' (AMR)',...
'\nNatural recovery rate (R) \t= ',sprintf('%.2s',self.R),...
'\nBirth/death rate (MU) \t\t= ',sprintf('%.2s',self.MU),...
'\nScreening rate (GAMMA) \t\t= ',sprintf('%.2s',self.GAMMA),...
'\nTracing efficiency (PSI) \t= ',sprintf('%.2f',self.PSI),...
'\n\n']);
end
% iii) beginning of time.
%% Infect population on day zero
% start with non-AMR.. infect p0(1) fraction of population
id_toinfect = randperm(self.N,round(self.p0(1)*self.N));
self.indiv_state(id_toinfect,1,1) = 1;
% for everyone infected with nonAMR gonorrhea at this point,
% switch a fraction p0(2) of those to be AMR infected instead
idx = randperm(size(id_toinfect,2),round(self.p0(2)*size(id_toinfect,2)));
self.indiv_state(id_toinfect(idx),2) = 1;
self.indiv_state(id_toinfect(idx),1) = 0;
% here take a proportion p0(3) of the AMR (only) infections
% and (re)infect with nonAMR giving the prescribed
% coinfection (given AMR) proportion
if self.ALLOW_COINFECTION == false && self.p0(3)~=0
self.p0(3) = 0;
warning('ALLOW_COINFECTION = false, setting p0(3) = 0');
end
id_AMR = find(self.indiv_state(:,2));
idx = randperm(size(id_AMR,1),round(self.p0(3)*size(id_AMR,1)));
self.indiv_state(id_AMR(idx),1) = 1;
% CARE! what is the proportion of individuals who are
% coinfected?? - how much difference does it make?
%----------
% set values for 'infected_since' and 'infection_count'
% for each strain
self.infected_since(self.indiv_state(:,1,1)==1,1) = 0;
self.infected_since(self.indiv_state(:,2,1)==1,2) = 0;
self.counters.infection_count(self.indiv_state(:,1,1)==1,1) = 1;
self.counters.infection_count(self.indiv_state(:,2,1)==1,2) = 1;
% prescribe proportion of symptomatic infections
idx_infected = any(self.indiv_state,2);
self.symptoms(idx_infected,1) = rand(sum(idx_infected),1)<self.P_SYMPTOMS;
% for initial infected, symptomatic individuals who seek
% treatment - randomise treatment seeking day to be within
% first month (30 days)
idx_willseek = false(self.N,1);
idx_willseek(logical(self.symptoms)) = rand(sum(self.symptoms),1)<self.P_SEEKS_TREATMENT;
%self.seeks_treatment_on(idx_willseek) = randi([1,21],sum(idx_willseek),1);
% init. other counters for day zero
self.counters.prevalence(1,:) = sum(self.indiv_state(:,:,1),1);
self.counters.prev_both(1) = sum(all(self.indiv_state(:,:,1),2),1);
self.counters.prev_either(1) = sum(any(self.indiv_state(:,:,1),2),1);
self.counters.prev_nonAMRonly(1) = sum(self.indiv_state(:,1,1) & ~self.indiv_state(:,2,1),1);
%self.counters.n_screened(1,:) = 0;
%self.counters.n_traced(1,:) = 0;
% infected partner ratio (per degree)
[self.ipr,~] = self.infected_partner_ratio(self.indiv_state(:,:,1),self.adj);
% Population data updated for day zero
self.today = 0;
self.burn_in = params.burn_in;
end % class constructor
function [self] = simulate(self,n_Days)
%% Continue SIS simulation from where we left off. (ALL)
%-----NV
% This is the most important method (apart from the
% constructor). It requires two arguments.
%