-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathHIVTestingUpdater.cpp
More file actions
732 lines (652 loc) · 33.5 KB
/
Copy pathHIVTestingUpdater.cpp
File metadata and controls
732 lines (652 loc) · 33.5 KB
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
#include "include.h"
/** \brief Constructor takes in the patient as a pointer */
HIVTestingUpdater::HIVTestingUpdater(Patient *patient) : StateUpdater(patient) {
}
/** \brief Destructor is empty, no cleanup required */
HIVTestingUpdater::~HIVTestingUpdater(void) {
}
/** \brief performInitialUpdates perform all of the state and statistics updates upon patient creation */
void HIVTestingUpdater::performInitialUpdates() {
/** First calls the parent function to perform general updates and initialization */
StateUpdater::performInitialUpdates();
//initialize variables
resetNumMissedVisitsEID();
setFalsePositiveStatus(false, false);
setCanReceiveEID(true);
setMostRecentPositiveEIDTest(false, -1, SimContext::EID_TEST_TYPE_BASE);
setMostRecentNegativeEIDTest(false);
setMissedEIDTest(false, -1);
bool useHIVTesting = false;
bool useEID = false;
//Use either the HIVTest inputs or the EID inputs for initial states, depending on whether the Peds Module is enabled
if(simContext->getHIVTestInputs()->enableHIVTesting)
useHIVTesting = true;
if(simContext->getPedsInputs()->enablePediatricsModel && simContext->getEIDInputs()->enableHIVTestingEID){
useHIVTesting = true;
useEID = true;
}
/** If not using the testing module, set all HIV positive patients to detected and return */
if (!useHIVTesting) {
//Pediatric patients can be HIV negative if EID is not enabled; adult patients are all initailly chronic HIV+ and in care if HIVTest is not enabled
if (patient->getDiseaseState()->infectedHIVState == SimContext::HIV_INF_NEG){
setDetectedHIVState(false);
setLinkedState(false);
}
else{
setDetectedHIVState(true, SimContext::HIV_DET_INITIAL);
setLinkedState(true, SimContext::HIV_DET_INITIAL);
}
return;
}
/** Start with adult HIV test inputs */
if(!useEID){
/** If using the adult testing module for initial states, determine if patient should enter the model detected */
if (patient->getDiseaseState()->infectedHIVState != SimContext::HIV_INF_NEG){
SimContext::HIV_POS hivPosState = patient->getDiseaseState()->infectedHIVPosState;
double randNum = CepacUtil::getRandomDouble(100010, patient);
if(randNum < simContext->getHIVTestInputs()->probHIVDetectionInitial[hivPosState]) {
setDetectedHIVState(true, SimContext::HIV_DET_INITIAL);
setLinkedState(true, SimContext::HIV_DET_INITIAL);
}
else{
setDetectedHIVState(false);
setLinkedState(false);
}
}
else {
setDetectedHIVState(false);
setLinkedState(false);
}
/** If adult patient is not detected as positive and linked, initialize the HIV testing freq and acceptance probability */
if (!patient->getMonitoringState()->isLinked) {
if(simContext->getHIVTestInputs()->HIVTestAvailable && patient->getGeneralState()->ageMonths >= simContext->getHIVTestInputs()->HIVRegularTestingStartAge){
initRegularScreening();
}
else{
scheduleHIVTest(false, SimContext::NOT_APPL);
}
} // end if patient is not yet linked to HIV care
}
// If Peds and EID modules are enabled, patients enter the model undetected
else{
setDetectedHIVState(false);
setLinkedState(false);
// patients may transition to the adult HIV Testing module at the starting age for user-defined tests
if(simContext->getHIVTestInputs()->enableHIVTesting){
if(simContext->getHIVTestInputs()->HIVTestAvailable && patient->getGeneralState()->ageMonths >= simContext->getHIVTestInputs()->HIVRegularTestingStartAge){
initRegularScreening();
}
else{
scheduleHIVTest(false, SimContext::NOT_APPL);
}
}
}
} /* end performInitialUpdates */
/** \brief setSimContext changes the inputs the updater uses to determine disease progression -- to be used primarily by the transmission model
* changes the testing frequency and acceptance probability based on the testing strategy of the new simContext
*
* \param newSimContext a pointer to a SimContext object that patient should switch calling inputs from
**/
void HIVTestingUpdater::setSimContext(SimContext *newSimContext){
/** First calls the parent function to switch the simContext */
StateUpdater::setSimContext(newSimContext);
/** Only update the testing strategy if there is a strategy to update and the patient is undetected. Since this function is no longer being called it has not been updated to check for a starting age or call initRegularScreening - would need to add that in if it ever were revived */
if (this->simContext->getHIVTestInputs()->enableHIVTesting && !patient->getMonitoringState()->isDetectedHIVPositive){
// Default HIV testing parameters to NOT_APPL
int intervalTestIndex = 0;
int acceptanceProbIndex = 0;
bool hasNextTest = patient->getMonitoringState()->hasScheduledHIVTest;
int monthNextTest = patient->getMonitoringState()->monthOfScheduledHIVTest;
if (simContext->getHIVTestInputs()->HIVTestAvailable) {
/** Set the HIV testing interval and time for next test */
double randNum = CepacUtil::getRandomDouble(100020, patient);
for (int i = 0; i < SimContext::HIV_TEST_FREQ_NUM; i++) {
if ((randNum < simContext->getHIVTestInputs()->HIVTestingProbability[i]) &&
(simContext->getHIVTestInputs()->HIVTestingProbability[i] > 0)) {
if (simContext->getHIVTestInputs()->HIVTestingInterval[i] > 0) {
hasNextTest = true;
intervalTestIndex = i;
/** If we're turning testing on for this patient, set monthNextTest to be randomly determined between current month and currMonth+testingInterval
//0.5 is added because casting as int just takes the floor... adding 0.5 causes correct rounding */
monthNextTest = patient->getGeneralState()->monthNum + ((int) (CepacUtil::getRandomDouble(100025, patient) * simContext->getHIVTestInputs()->HIVTestingInterval[i] + 0.5));
}
break;
}
randNum -= simContext->getHIVTestInputs()->HIVTestingProbability[i];
}
/** Set the HIV testing acceptance probability */
randNum = CepacUtil::getRandomDouble(100030, patient);
SimContext::HIV_EXT_INF extInfectedState;
if ((patient->getDiseaseState()->infectedHIVState == SimContext::HIV_INF_NEG) && !patient->getMonitoringState()->isHighRiskForHIV) {
extInfectedState = SimContext::HIV_EXT_INF_NEG_LO;
}
else {
extInfectedState = (SimContext::HIV_EXT_INF) patient->getDiseaseState()->infectedHIVState;
}
for (int i = 0; i < SimContext::TEST_ACCEPT_NUM; i++) {
if ((randNum < simContext->getHIVTestInputs()->HIVTestAcceptDistribution[extInfectedState][i]) &&
(simContext->getHIVTestInputs()->HIVTestAcceptDistribution[extInfectedState][i] > 0)) {
acceptanceProbIndex = i;
break;
}
randNum -= simContext->getHIVTestInputs()->HIVTestAcceptDistribution[extInfectedState][i];
}
}
setHIVTestingParams(intervalTestIndex, acceptanceProbIndex);
scheduleHIVTest(hasNextTest, monthNextTest);
}
}
/** \brief performMonthlyUpdates perform all of the state and statistics updates for a simulated month */
void HIVTestingUpdater::performMonthlyUpdates() {
if (patient->getMonitoringState()->isLinked)
return;
if (patient->getPedsState()->isFalsePositiveLinked)
return;
bool useHIVTesting = false;
bool useEID = false;
//Use either the HIVTest inputs or the EID inputs, depending on whether the Peds Module is enabled
if(simContext->getHIVTestInputs()->enableHIVTesting)
useHIVTesting = true;
if (simContext->getPedsInputs()->enablePediatricsModel){
if(simContext->getEIDInputs()->enableHIVTestingEID){
useHIVTesting = true;
if(!simContext->getHIVTestInputs()->enableHIVTesting || patient->getGeneralState()->ageMonths < simContext->getHIVTestInputs()->HIVRegularTestingStartAge)
useEID = true;
}
}
if (!useHIVTesting)
return;
if(patient->getGeneralState()->ageMonths == simContext->getHIVTestInputs()->HIVRegularTestingStartAge && !patient->getMonitoringState()->isLinked &&simContext->getHIVTestInputs()->HIVTestAvailable){
// Regular screening should be initiated immediately before offering the first test to avoid giving user-defined tests to people who are underage
initRegularScreening(false);
}
if (useEID){
//This ordering of tests reduces the likelihood of people getting a base test when they need a confirmatory test due to a previous positive result
performEIDResultReturnUpdates();
performEIDFirstConfirmatoryTests();
performEIDResultReturnUpdates();
performEIDSecondConfirmatoryTests();
performEIDResultReturnUpdates();
performEIDScreeningUpdates();
performEIDResultReturnUpdates();
performEIDFirstConfirmatoryTests();
performEIDResultReturnUpdates();
performEIDSecondConfirmatoryTests();
performEIDResultReturnUpdates();
}
else{
/** perform the regular and background HIV screenings if patient is not already linked to care by calling HIVTestingUpdater::performRegularScreeningUpdates() and then if they are still not linked, call HIVTestingUpdater::performBackgroundScreeningUpdates() */
performRegularScreeningUpdates();
if (!patient->getMonitoringState()->isLinked) {
performBackgroundScreeningUpdates();
}
}
} /* end performMonthlyUpdates */
/** \brief initRegularScreening sets an unlinked patient's user-defined testing interval and acceptance probability for the run if tests are available
* \param atInit a bool defaulting to true indicating whether this is called at initiation or later in the run when the patient reaches the starting age for user-defined tests
*/
void HIVTestingUpdater::initRegularScreening(bool atInit){
// Default HIV testing month to NOT_APPL
bool hasNextTest = false;
int monthNextTest = SimContext::NOT_APPL;
int intervalTestIndex = 0;
int acceptanceProbIndex = 0;
/** Set the HIV testing interval and time for next test */
double randNum = CepacUtil::getRandomDouble(100020, patient);
for (int i = 0; i < SimContext::HIV_TEST_FREQ_NUM; i++) {
if ((randNum < simContext->getHIVTestInputs()->HIVTestingProbability[i]) &&
(simContext->getHIVTestInputs()->HIVTestingProbability[i] > 0)) {
if (simContext->getHIVTestInputs()->HIVTestingInterval[i] > 0) {
hasNextTest = true;
intervalTestIndex = i;
if(atInit){
monthNextTest = 0;
}
else{
monthNextTest = patient->getGeneralState()->monthNum;
}
break;
}
}
randNum -= simContext->getHIVTestInputs()->HIVTestingProbability[i];
}
/** Determine their HIV testing acceptance probability for the run now */
randNum = CepacUtil::getRandomDouble(100030, patient);
SimContext::HIV_EXT_INF extInfectedState;
if ((patient->getDiseaseState()->infectedHIVState == SimContext::HIV_INF_NEG) && !patient->getMonitoringState()->isHighRiskForHIV) {
extInfectedState = SimContext::HIV_EXT_INF_NEG_LO;
}
else {
extInfectedState = (SimContext::HIV_EXT_INF) patient->getDiseaseState()->infectedHIVState;
}
for (int i = 0; i < SimContext::TEST_ACCEPT_NUM; i++) {
if ((randNum < simContext->getHIVTestInputs()->HIVTestAcceptDistribution[extInfectedState][i]) &&
(simContext->getHIVTestInputs()->HIVTestAcceptDistribution[extInfectedState][i] > 0)) {
acceptanceProbIndex = i;
break;
}
randNum -= simContext->getHIVTestInputs()->HIVTestAcceptDistribution[extInfectedState][i];
}
setHIVTestingParams(intervalTestIndex, acceptanceProbIndex);
scheduleHIVTest(hasNextTest, monthNextTest);
}
/** \brief performRegularScreeningUpdates determines if a screening occurs, if its accepted, if
they are detected, and updates the associated state and statistics */
void HIVTestingUpdater::performRegularScreeningUpdates() {
/** Check if patient is too old to get regular testing */
if(patient->getMonitoringState()->hasScheduledHIVTest && simContext->getHIVTestInputs()->HIVRegularTestingStopAge >= 0){
if (patient->getGeneralState()->ageMonths >= simContext->getHIVTestInputs()->HIVRegularTestingStopAge){
scheduleHIVTest(false, SimContext::NOT_APPL);
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d HIV SCREENING STOP, NOT AGE ELGIBLE;\n",
patient->getGeneralState()->monthNum);
}
}
if (patient->getGeneralState()->ageMonths == simContext->getHIVTestInputs()->HIVRegularTestingStopAge){
if (patient->getMonitoringState()->hasPrEP){
setPrEP(false, false, true);
if (patient->getGeneralState()->tracingEnabled){
tracer->printTrace(1, "**%d STOP PrEP;\n", patient->getGeneralState()->monthNum);
}
}
}
}
/** Return if this is not the month of the next test */
if (!patient->getMonitoringState()->hasScheduledHIVTest ||
(patient->getGeneralState()->monthNum < patient->getMonitoringState()->monthOfScheduledHIVTest)){
return;
}
SimContext::HIV_INF infectedState = patient->getDiseaseState()->infectedHIVState;
SimContext::HIV_EXT_INF extInfectedState;
if ((infectedState == SimContext::HIV_INF_NEG) && !patient->getMonitoringState()->isHighRiskForHIV) {
extInfectedState = SimContext::HIV_EXT_INF_NEG_LO;
}
else {
extInfectedState = (SimContext::HIV_EXT_INF) patient->getDiseaseState()->infectedHIVState;
}
/** Accrue the initial startup cost for all patients, regardless of test acceptance */
if ((patient->getGeneralState()->monthNum == patient->getGeneralState()->initialMonthNum) || (patient->getGeneralState()->ageMonths == simContext->getHIVTestInputs()->HIVRegularTestingStartAge)) {
double cost = simContext->getHIVTestInputs()->HIVTestInitialCost[extInfectedState];
incrementCostsHIVTest(cost);
// Output tracing if enabled
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d HIV SCREENING STARTUP, $ %1.0lf\n",
patient->getGeneralState()->monthNum, patient->getGeneralState()->costsDiscounted);
}
}
/** Check if scheduled testing is accepted by patient */
double randNum = CepacUtil::getRandomDouble(100040, patient);
double probAccept;
if (patient->getMonitoringState()->hasPrEP){
SimContext::HIV_BEHAV risk = patient->getMonitoringState()->isHighRiskForHIV?SimContext::HIV_BEHAV_HI:SimContext::HIV_BEHAV_LO;
probAccept = simContext->getHIVTestInputs()->PrEPHIVTestAcceptProb[risk];
}
else
probAccept = patient->getMonitoringState()->acceptanceProbHIVTest;
if (randNum < probAccept) {
/** If test is accepted, accrue the cost of performing the test */
double cost = simContext->getHIVTestInputs()->HIVTestCost[extInfectedState];
incrementCostsHIVTest(cost);
incrementNumHIVTests();
/** Check if patient returns for test result; if so, roll for that result */
randNum = CepacUtil::getRandomDouble(100050, patient);
if (randNum < simContext->getHIVTestInputs()->HIVTestReturnProb[infectedState]) {
/** Determine the test result */
randNum = CepacUtil::getRandomDouble(100060, patient);
if (randNum < simContext->getHIVTestInputs()->HIVTestPositiveProb[infectedState]) {
/** Increment cost, set QOL, and update identified state for a positive test result */
cost = simContext->getHIVTestInputs()->HIVTestPositiveCost[infectedState];
incrementCostsHIVMisc(cost);
accumulateQOLModifier(simContext->getHIVTestInputs()->HIVTestPositiveQOLModifier[infectedState]);
/** Update statistics for the accepted and positive HIV test result */
updateHIVTestingStats(true, true, true);
// Output tracing if enabled
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d HIV TEST ACCEPT, RETURN, %s POSITIVE, $ %1.0lf\n",
patient->getGeneralState()->monthNum,
(infectedState != SimContext::HIV_INF_NEG) ? "TRUE" : "FALSE",
patient->getGeneralState()->costsDiscounted);
}
if (infectedState != SimContext::HIV_INF_NEG) {
cost = simContext->getHIVTestInputs()->HIVTestDetectionCost[patient->getDiseaseState()->infectedHIVPosState];
incrementCostsHIVMisc(cost);
bool wasPrevDetected= patient->getMonitoringState()->isDetectedHIVPositive;
if (wasPrevDetected)
setDetectedHIVState(true, SimContext::HIV_DET_SCREENING_PREV_DET);
else
setDetectedHIVState(true, SimContext::HIV_DET_SCREENING);
if (simContext->getHIVTestInputs()->CD4TestAvailable)
performLabStagingUpdates(wasPrevDetected);
else{
if (wasPrevDetected)
setLinkedState(true,SimContext::HIV_DET_SCREENING_PREV_DET);
else
setLinkedState(true, SimContext::HIV_DET_SCREENING);
scheduleInitialClinicVisit();
}
return;
}
}
else {
/** Increment cost and set QOL for a negative test result */
cost = simContext->getHIVTestInputs()->HIVTestNegativeCost[infectedState];
incrementCostsHIVMisc(cost);
accumulateQOLModifier(simContext->getHIVTestInputs()->HIVTestNegativeQOLModifier[infectedState]);
/** Update statistics for the accepted and negative HIV test result */
updateHIVTestingStats(true, true, false);
// Output tracing if enabled
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d HIV TEST ACCEPT, RETURN, %s NEGATIVE, $ %1.0lf\n",
patient->getGeneralState()->monthNum,
(infectedState == SimContext::HIV_INF_NEG) ? "TRUE" : "FALSE",
patient->getGeneralState()->costsDiscounted);
}
}
} // end if patient returns for the test result
else {
/** Increment cost for patient not returning for test results */
cost = simContext->getHIVTestInputs()->HIVTestNonReturnCost[extInfectedState];
incrementCostsHIVMisc(cost);
/** Update statistics for the accepted HIV test with no return for results */
updateHIVTestingStats(true, false, false);
// Output tracing if enabled
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d HIV TEST ACCEPT, NON-RETURN, $ %1.0lf\n",
patient->getGeneralState()->monthNum, patient->getGeneralState()->costsDiscounted);
}
}
}
else {
/** Update statistics for the refused HIV test */
updateHIVTestingStats(false, false, false);
// Output tracing if enabled
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d HIV TEST NOT ACCEPTED, $ %1.0lf\n",
patient->getGeneralState()->monthNum, patient->getGeneralState()->costsDiscounted);
}
}
/** Schedule the next HIV test */
scheduleHIVTest(true, patient->getGeneralState()->monthNum + patient->getMonitoringState()->intervalHIVTest);
} /* end performRegularScreeningUpdates */
/** \brief performBackgroundScreeningUpdates handles whether patient is detected by background
screening and updates the associated state and statistics */
void HIVTestingUpdater::performBackgroundScreeningUpdates() {
/** Return if patient is not old enough for background testing */
if (patient->getGeneralState()->ageMonths < simContext->getHIVTestInputs()->HIVBackgroundStartAge)
return;
SimContext::HIV_INF infectedState = patient->getDiseaseState()->infectedHIVState;
SimContext::HIV_EXT_INF extInfectedState;
if ((infectedState == SimContext::HIV_INF_NEG) && !patient->getMonitoringState()->isHighRiskForHIV) {
extInfectedState = SimContext::HIV_EXT_INF_NEG_LO;
}
else {
extInfectedState = (SimContext::HIV_EXT_INF) patient->getDiseaseState()->infectedHIVState;
}
/** Check if background testing is accepted by patient */
double randNum = CepacUtil::getRandomDouble(100040, patient);
if (randNum < simContext->getHIVTestInputs()->HIVBackgroundAcceptProb[extInfectedState]) {
/** If test is accepted, accrue the cost of performing the test */
double cost = simContext->getHIVTestInputs()->HIVBackgroundTestCost[extInfectedState];
incrementCostsHIVMisc(cost);
/** Check if patient returns for test result */
randNum = CepacUtil::getRandomDouble(100050, patient);
if (randNum < simContext->getHIVTestInputs()->HIVBackgroundReturnProb[extInfectedState]) {
/** Determine the test result */
randNum = CepacUtil::getRandomDouble(100060, patient);
if (randNum < simContext->getHIVTestInputs()->HIVBackgroundPositiveProb[extInfectedState]) {
/** Increment cost, , and update identified state for a positive test result */
cost = simContext->getHIVTestInputs()->HIVBackgroundPositiveCost[extInfectedState];
incrementCostsHIVMisc(cost);
// Output tracing if enabled
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d HIV BACKGROUND TEST ACCEPT, RETURN, %s POSITIVE, $ %1.0lf\n",
patient->getGeneralState()->monthNum,
(infectedState != SimContext::HIV_INF_NEG) ? "TRUE" : "FALSE",
patient->getGeneralState()->costsDiscounted);
}
if (infectedState != SimContext::HIV_INF_NEG) {
cost = simContext->getHIVTestInputs()->HIVTestDetectionCost[patient->getDiseaseState()->infectedHIVPosState];
incrementCostsHIVMisc(cost);
bool wasPrevDetected= patient->getMonitoringState()->isDetectedHIVPositive;
if (wasPrevDetected)
setDetectedHIVState(true, SimContext::HIV_DET_BACKGROUND_PREV_DET);
else
setDetectedHIVState(true, SimContext::HIV_DET_BACKGROUND);
//Roll for linkage
randNum = CepacUtil::getRandomDouble(100065, patient);
if (randNum < simContext->getHIVTestInputs()->HIVBackgroundProbLinkage) {
if (wasPrevDetected)
setLinkedState(true,SimContext::HIV_DET_BACKGROUND_PREV_DET);
else
setLinkedState(true, SimContext::HIV_DET_BACKGROUND);
scheduleInitialClinicVisit();
}
return;
}
}
else {
/** Increment cost for a negative test result */
cost = simContext->getHIVTestInputs()->HIVBackgroundNegativeCost[extInfectedState];
incrementCostsHIVMisc(cost);
// Output tracing if enabled
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d HIV BACKGROUND TEST ACCEPT, RETURN, %s NEGATIVE, $ %1.0lf\n",
patient->getGeneralState()->monthNum,
(infectedState == SimContext::HIV_INF_NEG) ? "TRUE" : "FALSE",
patient->getGeneralState()->costsDiscounted);
}
}
}
else {
// Output tracing if enabled
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d HIV BACKGROUND TEST ACCEPT, NON-RETURN, $ %1.0lf\n",
patient->getGeneralState()->monthNum, patient->getGeneralState()->costsDiscounted);
}
}
}
} /* end performBackgroundScreeningUpdates */
/** \brief performLabStagingUpdates handles whether a patient is given a cd4 test, if they accept and updates the associated state and statistics*/
void HIVTestingUpdater::performLabStagingUpdates(bool wasPrevDetected){
// return if they are HIV negative or too young to be eligible - absolute CD4 counts only
if (patient->getDiseaseState()->infectedHIVState == SimContext::HIV_INF_NEG || patient->getPedsState()->ageCategoryPediatrics < SimContext::PEDS_AGE_LATE)
return;
SimContext::HIV_POS hivPosState = patient->getDiseaseState()->infectedHIVPosState;
/** Accrue the initial startup cost for all patients, regardless of test acceptance */
if ((patient->getGeneralState()->monthNum == patient->getGeneralState()->initialMonthNum) || (patient->getGeneralState()->ageMonths == simContext->getHIVTestInputs()->HIVRegularTestingStartAge)) {
double cost = simContext->getHIVTestInputs()->CD4TestInitialCost[hivPosState];
incrementCostsLabStagingTest(cost);
// Output tracing if enabled
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d LAB STAGING STARTUP, $ %1.0lf\n",
patient->getGeneralState()->monthNum, patient->getGeneralState()->costsDiscounted);
}
}
/** Check if scheduled testing is accepted by patient */
double randNum = CepacUtil::getRandomDouble(100080, patient);
if (randNum < simContext->getHIVTestInputs()->CD4TestAcceptProb[hivPosState]) {
/** If test is accepted, accrue the cost of performing the test */
double cost = simContext->getHIVTestInputs()->CD4TestCost[hivPosState];
incrementCostsLabStagingTest(cost);
incrementNumLabStagingTests();
/** Check if patient returns for test result */
randNum = CepacUtil::getRandomDouble(100090, patient);
if (randNum < simContext->getHIVTestInputs()->CD4TestReturnProb[hivPosState]) {
/** If performing a test, calculate the observed CD4 level using the standard deviation of testing error */
double stdDevPerc = CepacUtil::getRandomGaussian(0, simContext->getHIVTestInputs()->CD4TestStdDevPercentage, 50010, patient);
double biasStdDevPerc = CepacUtil::getRandomGaussian(0 , simContext->getHIVTestInputs()->CD4TestBiasStdDevPercentage, 50013, patient);
double cd4Value = patient->getDiseaseState()->currTrueCD4*(1+stdDevPerc+simContext->getHIVTestInputs()->CD4TestBiasMean)*(1+biasStdDevPerc);
setObservedCD4(true, cd4Value, true);
/**Increment cost for return for result**/
double cost = simContext->getHIVTestInputs()->CD4TestReturnCost[hivPosState];
incrementCostsLabStagingMisc(cost);
/** Determine Linkage to Care */
randNum = CepacUtil::getRandomDouble(100110, patient);
if (randNum < simContext->getHIVTestInputs()->CD4TestLinkageProb[patient->getMonitoringState()->currObservedCD4Strata]){
//patient linked to care
updateLabStagingStats(true,true,true);
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d LAB STAGING ACCEPT, RETURN, LINK: obsv CD4 %1.0lf, $ %1.0lf\n",
patient->getGeneralState()->monthNum, patient->getMonitoringState()->currObservedCD4, patient->getGeneralState()->costsDiscounted);
}
if (wasPrevDetected)
setLinkedState(true, SimContext::HIV_DET_SCREENING_PREV_DET);
else
setLinkedState(true, SimContext::HIV_DET_SCREENING);
scheduleInitialClinicVisit();
return;
}
else{
updateLabStagingStats(true,true,false);
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d LAB STAGING ACCEPT, RETURN, NON-LINK: obsv CD4 %1.0lf, $ %1.0lf\n",
patient->getGeneralState()->monthNum, patient->getMonitoringState()->currObservedCD4, patient->getGeneralState()->costsDiscounted);
}
}
}
else {
/** Increment cost for patient not returning for test results */
double cost = simContext->getHIVTestInputs()->CD4TestNonReturnCost[hivPosState];
incrementCostsLabStagingMisc(cost);
updateLabStagingStats(true,false,false);
// Output tracing if enabled
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d LAB STAGING ACCEPT, NON-RETURN, $ %1.0lf\n",
patient->getGeneralState()->monthNum, patient->getGeneralState()->costsDiscounted);
}
}
}
else {
updateLabStagingStats(false,false,false);
// Output tracing if enabled
if (patient->getGeneralState()->tracingEnabled) {
tracer->printTrace(1, "**%d LAB STAGING NOT ACCEPTED, $ %1.0lf\n",
patient->getGeneralState()->monthNum, patient->getGeneralState()->costsDiscounted);
}
}
/** Schedule the next HIV test */
scheduleHIVTest(true, patient->getGeneralState()->monthNum + patient->getMonitoringState()->intervalHIVTest);
}
/** \brief performEIDScreeningUpdates determines if a EID screening occurs, if its accepted, if
they are detected, and updates the associated state and statistics */
void HIVTestingUpdater::performEIDScreeningUpdates() {
if (patient->getMonitoringState()->isLinked)
return;
if (patient->getPedsState()->isFalsePositiveLinked)
return;
//determine if mother is known positive or not known to be positive
SimContext::PEDS_MATERNAL_KNOWLEDGE maternalKnowledge;
if (patient->getPedsState()->maternalStatus != SimContext::PEDS_MATERNAL_STATUS_NEG && patient->getPedsState()->maternalStatusKnown)
maternalKnowledge = SimContext::PEDS_MATERNAL_KNOWLEDGE_KNOWN_POSITIVE;
else
maternalKnowledge = SimContext::PEDS_MATERNAL_KNOWLEDGE_NOT_KNOWN_POSITIVE;
int patientAge = patient->getGeneralState()->ageMonths;
bool hasVisit = false;
int assayNum;
double probPresent;
double probNonMaternal;
bool isEIDVisit;
bool reofferTest;
//check if it is time for a EID test visit
for (int i = 0; i < SimContext::EID_NUM_ASSAYS; i++){
if (patientAge == simContext->getEIDInputs()->testingAdminAge[maternalKnowledge][i]){
hasVisit = true;
assayNum = simContext->getEIDInputs()->testingAdminAssay[maternalKnowledge][i];
probPresent = simContext->getEIDInputs()->testingAdminProbPresent[maternalKnowledge][i];
if (patient->getPedsState()->isMotherAlive)
probNonMaternal = simContext->getEIDInputs()->testingAdminProbNonMaternalCaregiver[maternalKnowledge][i];
else
probNonMaternal = 1.0;
isEIDVisit = simContext->getEIDInputs()->testingAdminIsEIDVisit[maternalKnowledge][i];
reofferTest = simContext->getEIDInputs()->testingAdminReofferTestIfMissed[maternalKnowledge][i];
if (patient->getGeneralState()->tracingEnabled)
tracer->printTrace(1, "**%d %s visit scheduled\n", patient->getGeneralState()->monthNum, isEIDVisit?"EID":"Well Child");
break;
}
}
if (!hasVisit)
return;
//If this is an EID visit don't let people in who have exited EID system
if (isEIDVisit && !patient->getPedsState()->canReceiveEID){
if (assayNum != SimContext::NOT_APPL)
setMissedEIDTest(true, assayNum);
return;
}
/**patient has scheduled visit*/
//Check if patient presents to visit
//multiply prob of presenting by number of previous missed visits
probPresent = probPresent * pow(simContext->getEIDInputs()->probMultMissedVisit,patient->getPedsState()->numMissedVistsEID);
double randNum = CepacUtil::getRandomDouble(100120, patient);
if (randNum >= probPresent){
//patient does not present
incrementNumMissedVisitsEID();
if (patient->getGeneralState()->tracingEnabled)
tracer->printTrace(1, "**%d EID failed to present to visit\n", patient->getGeneralState()->monthNum);
if (assayNum != SimContext::NOT_APPL)
setMissedEIDTest(true, assayNum);
return;
}
/** patient presented to visit */
//Add cost of visit
if(patientAge < SimContext::EID_COST_VISIT_NUM)
incrementCostsEIDVisit(simContext->getEIDInputs()->costVisit[patientAge]);
//Roll for non maternal caregiver
bool isNonMaternal = false;
randNum = CepacUtil::getRandomDouble(100123, patient);
if (randNum < probNonMaternal)
isNonMaternal = true;
if (patient->getGeneralState()->tracingEnabled)
tracer->printTrace(1, "**%d EID presented to visit, %s care giver\n", patient->getGeneralState()->monthNum, isNonMaternal?"non-maternal":"maternal");
//if no test scheduled this visit, check if can make up previous visit tests
if ( assayNum == SimContext::NOT_APPL){
if (patient->getPedsState()->hasMissedEIDTest && reofferTest)
performEIDTest(patient->getPedsState()->missedEIDTestBaseAssay, patient->getPedsState()->missedEIDTestBaseAssay, SimContext::EID_TEST_TYPE_BASE, SimContext::OI_NONE, isNonMaternal);
return;
}
//If provider has knowledge of previous positive result continue the cascade from where they left off
randNum = CepacUtil::getRandomDouble(100125, patient);
if (randNum < simContext->getEIDInputs()->probKnowedgePriorResult && patient->getPedsState()->hasMostRecentPositiveEIDTest){
int mostRecentAssay = patient->getPedsState()->mostRecentPositiveEIDTestBaseAssay;
SimContext::EID_TEST_TYPE mostRecentType = patient->getPedsState()->mostRecentPositiveEIDTestType;
SimContext::EIDInputs::EIDTest mostRecentTest = simContext->getEIDInputs()->EIDTests[mostRecentAssay];
if (patient->getGeneralState()->tracingEnabled)
tracer->printTrace(1, "**%d EID provider used knowledge of previous test %d\n", patient->getGeneralState()->monthNum, mostRecentAssay);
bool testScheduled = false;
if (mostRecentType == SimContext::EID_TEST_TYPE_BASE && mostRecentTest.EIDFirstConfirmatoryTestAssay != SimContext::NOT_APPL){
if(patient->getPedsState()->eidScheduledConfirmatoryTests.size() > 0) {
for (vector<SimContext::EIDTestState>::const_iterator i = patient->getPedsState()->eidScheduledConfirmatoryTests.begin(); i != patient->getPedsState()->eidScheduledConfirmatoryTests.end(); i++){
if(i->baseAssay == mostRecentAssay && i->testType == SimContext::EID_TEST_TYPE_FIRST_CONF){
testScheduled = true;
if (patient->getGeneralState()->tracingEnabled)
tracer->printTrace(1, "**%d Patient has a first confirmatory test scheduled for month %d\n", patient->getGeneralState()->monthNum, i->monthToReturn);
break;
}
}
}
if(!testScheduled)
performEIDTest(mostRecentAssay, mostRecentTest.EIDFirstConfirmatoryTestAssay, SimContext::EID_TEST_TYPE_FIRST_CONF, SimContext::OI_NONE, isNonMaternal);
}
else if (mostRecentType == SimContext::EID_TEST_TYPE_FIRST_CONF && mostRecentTest.EIDSecondConfirmatoryTestAssay != SimContext::NOT_APPL){
if(patient->getPedsState()->eidScheduledConfirmatoryTests.size() > 0) {
for (vector<SimContext::EIDTestState>::const_iterator i = patient->getPedsState()->eidScheduledConfirmatoryTests.begin(); i != patient->getPedsState()->eidScheduledConfirmatoryTests.end(); i++){
if(i->baseAssay == mostRecentAssay && i->testType == SimContext::EID_TEST_TYPE_SECOND_CONF){
testScheduled = true;
if (patient->getGeneralState()->tracingEnabled)
tracer->printTrace(1, "**%d Patient has a second confirmatory test scheduled for month %d\n", patient->getGeneralState()->monthNum, i->monthToReturn);
break;
}
}
}
if(!testScheduled)
performEIDTest(mostRecentAssay, mostRecentTest.EIDSecondConfirmatoryTestAssay, SimContext::EID_TEST_TYPE_SECOND_CONF, SimContext::OI_NONE, isNonMaternal);
}
else{
//roll for linkage
rollForEIDLinkage(mostRecentAssay, SimContext::OI_NONE);
}
}
else{
//do regular scheduled test
performEIDTest(assayNum, assayNum, SimContext::EID_TEST_TYPE_BASE, SimContext::OI_NONE, isNonMaternal);
}
}