From b425066b09ff7ab2bd8cd5183dfbfa96219982c3 Mon Sep 17 00:00:00 2001 From: David Vernest Date: Tue, 23 Jun 2020 10:36:41 +0100 Subject: [PATCH 1/2] Refactor DigitalContactTracingSweep --- src/Sweep.cpp | 149 +++++++++++++++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 55 deletions(-) diff --git a/src/Sweep.cpp b/src/Sweep.cpp index 34d8103b6..b0c881693 100644 --- a/src/Sweep.cpp +++ b/src/Sweep.cpp @@ -15,6 +15,10 @@ #include "Sweep.h" #include "Update.h" +void UpdateQueue(int j, int i, int k, int contact, int infector, unsigned short contact_time); +void EndDigital(int contact); +unsigned short GetStartTime(int infector, int contact, unsigned short contact_time); +unsigned short GetEndTime(int infector, unsigned short& dct_start_time, int contact, unsigned short contact_time); void TravelReturnSweep(double t) { @@ -1108,42 +1112,8 @@ void DigitalContactTracingSweep(double t) int contact = StateT[j].dct_queue[i][k].contact; unsigned short int contact_time = StateT[j].dct_queue[i][k].contact_time; - unsigned short int dct_start_time, dct_end_time; - //this condition is only ever met when a symptomatic case is detected in DoDetectedCase and is not already an index case. If they have already - //been made an index case due to testing, then this won't occur again for them. - if (infector==-1) - { - //i.e. this is an index case that has been detected by becoming symptomatic and added to the digital contact tracing queue - dct_start_time = Hosts[contact].dct_trigger_time; //trigger time for these cases is set in DoIncub and already accounts for delay between onset and isolation - dct_end_time = dct_start_time + (unsigned short int)(P.LengthDigitalContactIsolation * P.TimeStepsPerDay); - - } - else //We are looking at actual contact events between infectious hosts and their contacts. - { - //trigger times are either set in DoDetectedCase or in the loop below (for asymptomatic and presymptomatic cases that are picked up via testing - //If the contact's index case has a trigger time that means that they have been detected, and we can calculate start and end isolation times for the contact. - if (Hosts[infector].dct_trigger_time < (USHRT_MAX - 1)) - { - if (contact_time > Hosts[infector].dct_trigger_time) - { - //if the contact time was made after host detected, we should use the later time - dct_start_time = contact_time + (unsigned short int) (P.DigitalContactTracingDelay * P.TimeStepsPerDay); - } - else - { - //if the contact time was made before or at the same time as detection, use the trigger time instead - dct_start_time = Hosts[infector].dct_trigger_time + (unsigned short int) (P.DigitalContactTracingDelay * P.TimeStepsPerDay); - } - dct_end_time = dct_start_time + (unsigned short int)(P.LengthDigitalContactIsolation * P.TimeStepsPerDay); - } - else - { - dct_start_time = USHRT_MAX - 1; //for contacts of asymptomatic or presymptomatic cases - they won't get added as their index case won't know that they are infected (unless explicitly tested) - //but we keep them in the queue in case their index case is detected as the contact of someone else and gets their trigger time set - //set dct_end_time to recovery time of infector, in order to remove from queue if their infector isn't detected before they recover. - dct_end_time = Hosts[infector].recovery_or_death_time; - } - } + unsigned short int dct_start_time = GetStartTime(infector, contact, contact_time); + unsigned short int dct_end_time = GetEndTime(infector, dct_start_time, contact, contact_time); //if we've reached the start time for isolation if (dct_start_time == ts) @@ -1180,9 +1150,7 @@ void DigitalContactTracingSweep(double t) //if false negative, remove from queue by setting the end time to the test time if ((P.SensitivityDCT == 0) || ((P.SensitivityDCT < 1) && (ranf_mt(tn) >= P.SensitivityDCT))) { - Hosts[contact].dct_end_time = Hosts[contact].dct_test_time; - //set index_dct_flag to 2 to indicate that contacts should be removed, if we are removing based on negative test result of index case - if (P.RemoveContactsOfNegativeIndexCase) Hosts[contact].index_case_dct = 2; + EndDigital(contact); } } //if host is non-infectious) @@ -1192,8 +1160,7 @@ void DigitalContactTracingSweep(double t) if ((P.SpecificityDCT == 1) || ((P.SpecificityDCT > 0) && (ranf_mt(tn) < P.SpecificityDCT))) { //again mark them to be removed from list at test time rather than end_time, and change index_case_dct flag - Hosts[contact].dct_end_time = Hosts[contact].dct_test_time; - if (P.RemoveContactsOfNegativeIndexCase) Hosts[contact].index_case_dct = 2; + EndDigital(contact); } } } @@ -1222,9 +1189,7 @@ void DigitalContactTracingSweep(double t) StateT[tn].cumDCT++; //now remove this case from the queues - StateT[j].dct_queue[i][k] = StateT[j].dct_queue[i][StateT[j].ndct_queue[i] - 1]; - StateT[j].dct_queue[i][StateT[j].ndct_queue[i] - 1] = { contact,infector,contact_time }; - StateT[j].ndct_queue[i]--; + UpdateQueue(j, i, k, contact, infector, contact_time); } else { @@ -1251,9 +1216,7 @@ void DigitalContactTracingSweep(double t) //if false negative, remove from if ((P.SensitivityDCT == 0) || ((P.SensitivityDCT < 1) && (ranf_mt(tn) >= P.SensitivityDCT))) { - Hosts[contact].dct_end_time = Hosts[contact].dct_test_time; - //set index_dct_flag to 2 to indicate that contacts should be removed - if (P.RemoveContactsOfNegativeIndexCase) Hosts[contact].index_case_dct = 2; + EndDigital(contact); } } //if host is non-infectious @@ -1263,8 +1226,7 @@ void DigitalContactTracingSweep(double t) if ((P.SpecificityDCT == 1) || ((P.SpecificityDCT > 0) && (ranf_mt(tn) < P.SpecificityDCT))) { //again mark them to be removed from list at test time rather than end_time, and change index_case_dct flag - Hosts[contact].dct_end_time = Hosts[contact].dct_test_time; - if (P.RemoveContactsOfNegativeIndexCase) Hosts[contact].index_case_dct = 2; + EndDigital(contact); } } } @@ -1288,18 +1250,14 @@ void DigitalContactTracingSweep(double t) } //now remove this case from the queue - StateT[j].dct_queue[i][k] = StateT[j].dct_queue[i][StateT[j].ndct_queue[i] - 1]; - StateT[j].dct_queue[i][StateT[j].ndct_queue[i] - 1] = { contact,infector,contact_time }; - StateT[j].ndct_queue[i]--; + UpdateQueue(j, i, k, contact, infector, contact_time); } } //if contact of an asymptomatic host has passed the recovery time of their asymptomatic index, they would no longer be identified by testing of their index case - remove from the queue so they don't stay here forever else if ((dct_start_time == (USHRT_MAX - 1)) && (dct_end_time == ts)) { //now remove this case from the queue - StateT[j].dct_queue[i][k] = StateT[j].dct_queue[i][StateT[j].ndct_queue[i] - 1]; - StateT[j].dct_queue[i][StateT[j].ndct_queue[i] - 1] = { contact,infector,contact_time }; - StateT[j].ndct_queue[i]--; + UpdateQueue(j, i, k, contact, infector, contact_time); } else { @@ -2006,3 +1964,84 @@ int TreatSweep(double t) return (f > 0); } + +unsigned short GetStartTime(int infector, int contact, unsigned short contact_time) +{ + unsigned short dct_start_time; + + //this condition is only ever met when a symptomatic case is detected in DoDetectedCase and is not already an index case. If they have already + //been made an index case due to testing, then this won't occur again for them. + if (infector == -1) + { + //i.e. this is an index case that has been detected by becoming symptomatic and added to the digital contact tracing queue + dct_start_time = Hosts[contact].dct_trigger_time; //trigger time for these cases is set in DoIncub and already accounts for delay between onset and isolation + } + else //We are looking at actual contact events between infectious hosts and their contacts. + { + //trigger times are either set in DoDetectedCase or in the loop below (for asymptomatic and presymptomatic cases that are picked up via testing + //If the contact's index case has a trigger time that means that they have been detected, and we can calculate start and end isolation times for the contact. + if (Hosts[infector].dct_trigger_time < (USHRT_MAX - 1)) + { + if (contact_time > Hosts[infector].dct_trigger_time) + { + //if the contact time was made after host detected, we should use the later time + dct_start_time = contact_time + (unsigned short int) (P.DigitalContactTracingDelay * P.TimeStepsPerDay); + } + else + { + //if the contact time was made before or at the same time as detection, use the trigger time instead + dct_start_time = Hosts[infector].dct_trigger_time + (unsigned short int) (P.DigitalContactTracingDelay * P.TimeStepsPerDay); + } + } + else + { + dct_start_time = USHRT_MAX - 1; //for contacts of asymptomatic or presymptomatic cases - they won't get added as their index case won't know that they are infected (unless explicitly tested) + //but we keep them in the queue in case their index case is detected as the contact of someone else and gets their trigger time set + //set dct_end_time to recovery time of infector, in order to remove from queue if their infector isn't detected before they recover. + } + } + return dct_start_time; +} + +unsigned short GetEndTime(int infector, unsigned short& dct_start_time, int contact, unsigned short contact_time) +{ + unsigned short dct_end_time; + + //this condition is only ever met when a symptomatic case is detected in DoDetectedCase and is not already an index case. If they have already + //been made an index case due to testing, then this won't occur again for them. + if (infector == -1) + { + //i.e. this is an index case that has been detected by becoming symptomatic and added to the digital contact tracing queue + dct_end_time = dct_start_time + (unsigned short int)(P.LengthDigitalContactIsolation * P.TimeStepsPerDay); + + } + else //We are looking at actual contact events between infectious hosts and their contacts. + { + //trigger times are either set in DoDetectedCase or in the loop below (for asymptomatic and presymptomatic cases that are picked up via testing + //If the contact's index case has a trigger time that means that they have been detected, and we can calculate start and end isolation times for the contact. + if (Hosts[infector].dct_trigger_time < (USHRT_MAX - 1)) + { + dct_end_time = dct_start_time + (unsigned short int)(P.LengthDigitalContactIsolation * P.TimeStepsPerDay); + } + else + { + dct_end_time = Hosts[infector].recovery_or_death_time; + } + } + return dct_end_time; +} + + +void UpdateQueue(int j, int i, int k, int contact, int infector, unsigned short contact_time) +{ + StateT[j].dct_queue[i][k] = StateT[j].dct_queue[i][StateT[j].ndct_queue[i] - 1]; + StateT[j].dct_queue[i][StateT[j].ndct_queue[i] - 1] = { contact,infector,contact_time }; + StateT[j].ndct_queue[i]--; +} + +void EndDigital(int contact) +{ + Hosts[contact].dct_end_time = Hosts[contact].dct_test_time; + //set index_dct_flag to 2 to indicate that contacts should be removed, if we are removing based on negative test result of index case + if (P.RemoveContactsOfNegativeIndexCase) Hosts[contact].index_case_dct = 2; +} From 8bd1853c47f8db241ad1de4c4bfd9c87e6853e7a Mon Sep 17 00:00:00 2001 From: David Vernest Date: Tue, 23 Jun 2020 13:22:26 +0100 Subject: [PATCH 2/2] cleanup Dct functions --- src/Sweep.cpp | 74 +++++++++++++++++---------------------------------- 1 file changed, 25 insertions(+), 49 deletions(-) diff --git a/src/Sweep.cpp b/src/Sweep.cpp index b0c881693..81e2c0277 100644 --- a/src/Sweep.cpp +++ b/src/Sweep.cpp @@ -15,10 +15,11 @@ #include "Sweep.h" #include "Update.h" -void UpdateQueue(int j, int i, int k, int contact, int infector, unsigned short contact_time); -void EndDigital(int contact); -unsigned short GetStartTime(int infector, int contact, unsigned short contact_time); -unsigned short GetEndTime(int infector, unsigned short& dct_start_time, int contact, unsigned short contact_time); +// DigitalContractTracing helper functions +static void GetDctStartEndTimes(int infector, int contact, unsigned short contact_time, unsigned short& dct_start_time, + unsigned short& dct_end_time); +static void UpdateDctQueue(int j, int i, int k, int contact, int infector, unsigned short contact_time); +static void StopDct(int contact); void TravelReturnSweep(double t) { @@ -1111,10 +1112,10 @@ void DigitalContactTracingSweep(double t) int infector = StateT[j].dct_queue[i][k].index; int contact = StateT[j].dct_queue[i][k].contact; unsigned short int contact_time = StateT[j].dct_queue[i][k].contact_time; - - unsigned short int dct_start_time = GetStartTime(infector, contact, contact_time); - unsigned short int dct_end_time = GetEndTime(infector, dct_start_time, contact, contact_time); - + unsigned short int dct_start_time; + unsigned short int dct_end_time; + GetDctStartEndTimes(infector, contact, contact_time, dct_start_time, dct_end_time); + //if we've reached the start time for isolation if (dct_start_time == ts) { @@ -1150,7 +1151,7 @@ void DigitalContactTracingSweep(double t) //if false negative, remove from queue by setting the end time to the test time if ((P.SensitivityDCT == 0) || ((P.SensitivityDCT < 1) && (ranf_mt(tn) >= P.SensitivityDCT))) { - EndDigital(contact); + StopDct(contact); } } //if host is non-infectious) @@ -1160,7 +1161,7 @@ void DigitalContactTracingSweep(double t) if ((P.SpecificityDCT == 1) || ((P.SpecificityDCT > 0) && (ranf_mt(tn) < P.SpecificityDCT))) { //again mark them to be removed from list at test time rather than end_time, and change index_case_dct flag - EndDigital(contact); + StopDct(contact); } } } @@ -1189,7 +1190,7 @@ void DigitalContactTracingSweep(double t) StateT[tn].cumDCT++; //now remove this case from the queues - UpdateQueue(j, i, k, contact, infector, contact_time); + UpdateDctQueue(j, i, k, contact, infector, contact_time); } else { @@ -1216,7 +1217,7 @@ void DigitalContactTracingSweep(double t) //if false negative, remove from if ((P.SensitivityDCT == 0) || ((P.SensitivityDCT < 1) && (ranf_mt(tn) >= P.SensitivityDCT))) { - EndDigital(contact); + StopDct(contact); } } //if host is non-infectious @@ -1226,7 +1227,7 @@ void DigitalContactTracingSweep(double t) if ((P.SpecificityDCT == 1) || ((P.SpecificityDCT > 0) && (ranf_mt(tn) < P.SpecificityDCT))) { //again mark them to be removed from list at test time rather than end_time, and change index_case_dct flag - EndDigital(contact); + StopDct(contact); } } } @@ -1250,14 +1251,14 @@ void DigitalContactTracingSweep(double t) } //now remove this case from the queue - UpdateQueue(j, i, k, contact, infector, contact_time); + UpdateDctQueue(j, i, k, contact, infector, contact_time); } } //if contact of an asymptomatic host has passed the recovery time of their asymptomatic index, they would no longer be identified by testing of their index case - remove from the queue so they don't stay here forever else if ((dct_start_time == (USHRT_MAX - 1)) && (dct_end_time == ts)) { //now remove this case from the queue - UpdateQueue(j, i, k, contact, infector, contact_time); + UpdateDctQueue(j, i, k, contact, infector, contact_time); } else { @@ -1965,16 +1966,19 @@ int TreatSweep(double t) return (f > 0); } -unsigned short GetStartTime(int infector, int contact, unsigned short contact_time) +static void GetDctStartEndTimes(int infector, int contact, unsigned short contact_time, unsigned short& dct_start_time, + unsigned short& dct_end_time) { - unsigned short dct_start_time; - //this condition is only ever met when a symptomatic case is detected in DoDetectedCase and is not already an index case. If they have already //been made an index case due to testing, then this won't occur again for them. if (infector == -1) { //i.e. this is an index case that has been detected by becoming symptomatic and added to the digital contact tracing queue dct_start_time = Hosts[contact].dct_trigger_time; //trigger time for these cases is set in DoIncub and already accounts for delay between onset and isolation + + //i.e. this is an index case that has been detected by becoming symptomatic and added to the digital contact tracing queue + dct_end_time = dct_start_time + (unsigned short int)(P.LengthDigitalContactIsolation * P.TimeStepsPerDay); + } else //We are looking at actual contact events between infectious hosts and their contacts. { @@ -1992,54 +1996,26 @@ unsigned short GetStartTime(int infector, int contact, unsigned short contact_ti //if the contact time was made before or at the same time as detection, use the trigger time instead dct_start_time = Hosts[infector].dct_trigger_time + (unsigned short int) (P.DigitalContactTracingDelay * P.TimeStepsPerDay); } + dct_end_time = dct_start_time + (unsigned short int)(P.LengthDigitalContactIsolation * P.TimeStepsPerDay); } else { dct_start_time = USHRT_MAX - 1; //for contacts of asymptomatic or presymptomatic cases - they won't get added as their index case won't know that they are infected (unless explicitly tested) //but we keep them in the queue in case their index case is detected as the contact of someone else and gets their trigger time set //set dct_end_time to recovery time of infector, in order to remove from queue if their infector isn't detected before they recover. - } - } - return dct_start_time; -} - -unsigned short GetEndTime(int infector, unsigned short& dct_start_time, int contact, unsigned short contact_time) -{ - unsigned short dct_end_time; - - //this condition is only ever met when a symptomatic case is detected in DoDetectedCase and is not already an index case. If they have already - //been made an index case due to testing, then this won't occur again for them. - if (infector == -1) - { - //i.e. this is an index case that has been detected by becoming symptomatic and added to the digital contact tracing queue - dct_end_time = dct_start_time + (unsigned short int)(P.LengthDigitalContactIsolation * P.TimeStepsPerDay); - - } - else //We are looking at actual contact events between infectious hosts and their contacts. - { - //trigger times are either set in DoDetectedCase or in the loop below (for asymptomatic and presymptomatic cases that are picked up via testing - //If the contact's index case has a trigger time that means that they have been detected, and we can calculate start and end isolation times for the contact. - if (Hosts[infector].dct_trigger_time < (USHRT_MAX - 1)) - { - dct_end_time = dct_start_time + (unsigned short int)(P.LengthDigitalContactIsolation * P.TimeStepsPerDay); - } - else - { dct_end_time = Hosts[infector].recovery_or_death_time; } } - return dct_end_time; } - -void UpdateQueue(int j, int i, int k, int contact, int infector, unsigned short contact_time) +static void UpdateDctQueue(int j, int i, int k, int contact, int infector, unsigned short contact_time) { StateT[j].dct_queue[i][k] = StateT[j].dct_queue[i][StateT[j].ndct_queue[i] - 1]; StateT[j].dct_queue[i][StateT[j].ndct_queue[i] - 1] = { contact,infector,contact_time }; StateT[j].ndct_queue[i]--; } -void EndDigital(int contact) +static void StopDct(int contact) { Hosts[contact].dct_end_time = Hosts[contact].dct_test_time; //set index_dct_flag to 2 to indicate that contacts should be removed, if we are removing based on negative test result of index case