diff --git a/src/Host.cpp b/src/Host.cpp index 1f49f1f..f44a84f 100644 --- a/src/Host.cpp +++ b/src/Host.cpp @@ -194,7 +194,7 @@ Host::operator hostState() const { // save this object to the host state structure return {WM, WF, totalWorms, totalWormYears, M, biteRisk, age, monthsSinceTreated, - hydroMult, lymphoMult, sex}; + hydroMult, lymphoMult, sex, pTreat}; } void Host::restore(const hostState &state) { @@ -211,4 +211,5 @@ void Host::restore(const hostState &state) { hydroMult = state.hydroMult; lymphoMult = state.lymphoMult; sex = state.sex; + pTreat = state.pTreat; } diff --git a/src/Host.hpp b/src/Host.hpp index 321b555..9966c32 100644 --- a/src/Host.hpp +++ b/src/Host.hpp @@ -27,7 +27,6 @@ typedef struct { double hydroMult; double lymphoMult; int sex; - int neverTreat; double pTreat; // probability of treatment drawn from a beta distribution as // defined in section 1.5.3 of supplement to // https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5340860/ diff --git a/src/Model.cpp b/src/Model.cpp index 523cbe5..6b9670b 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -196,18 +196,11 @@ void Model::evolveAndSave(int y, Population &popln, Vector &vectors, std::string folderName = opDir; std::string MDAType; int t_import_reduction = -1; - int preTASSurveyTime = -1000; - int TASSurveyTime = -1000; int paramIndex = 0; int targetMonth = sc.getMonthToSave(y); // simulate to start of this month double mfprev = 1; // variable to check prevalence of mf for survey // double icprev = 1; //variable to check prevalence of ic for survey int numMDADoSurvey = popln.firstTASNumMDA; - popln.totMDAs = 0; - popln.post2020MDAs = 0; - popln.numPreTASSurveys = 0; - popln.numTASSurveys = 0; - popln.t_TAS_Pass = -1; int sampleSize = popln.getSampleSize(); // set the outputEndgameDate to be relative to year 2000. // This should be updated when we automatically get the baseYear of the @@ -218,11 +211,9 @@ void Model::evolveAndSave(int y, Population &popln, Vector &vectors, double mfprev_aimp_old = popln.getMFPrev(sc, 0, 0, outputEndgameDate, rep, popSize, folderName); double mfprev_aimp_new = 0; - bool preTAS_Pass = 0; int changeSensSpec = 0; int changeNeverTreat = 0; // int maxAge = popln.getMaxAge(); - int TAS_Pass = 0; int neededTASPass = 3; // number of times TAS must be passed to reached WHO target // (https://www.who.int/publications/i/item/9789241501484) @@ -241,19 +232,18 @@ void Model::evolveAndSave(int y, Population &popln, Vector &vectors, } int vec_control = 0; - double prevCov = -1; - double prevRho = -1; + int minAge; int maxAge = popln.returnMaxAge(); int donePreTAS = 0; int doneTAS = 0; // indicator if we should do the MDA when the MDA is called. - // This will be switched to 0 if preTAS is passed, then the MDA function will - // be called, but will not be done We will still get the output of the MDA - // showing that no people were treated this year. This is to keep the output - // of MDA's constant so that we can combine different runs even if they have - // different numbers of MDA's performed. - int DoMDA = 1; + // This will be switched to false if preTAS is passed, then the MDA function + // will be called, but will not be done. We will still get the output of the + // MDA showing that no people were treated this year. This is to keep the + // output of MDA's constant so that we can combine different runs even if they + // have different numbers of MDA's performed. + popln.DoMDA = true; for (int q = 0; q < popln.sensSpecChangeCount; q++) { if (popln.sensSpecChangeName[q] == sc.getName()) { @@ -286,14 +276,15 @@ void Model::evolveAndSave(int y, Population &popln, Vector &vectors, // year we want to do the endgame output for, then don't do this. if ((t % 12 == 0) && (outputEndgame == 1) && (t >= outputEndgameDate)) { sc.writePrevByAge(popln, t, rep, folderName); - sc.writeRoadmapTarget(popln, t, rep, DoMDA, TAS_Pass, neededTASPass, - folderName); + sc.writeRoadmapTarget(popln, t, rep, popln.DoMDA, popln.TAS_Pass, + neededTASPass, folderName); sc.writeNumberByAge(popln, t, rep, folderName, "not survey"); sc.writeSequelaeByAge(popln, t, LymphodemaTotalWorms, LymphodemaShape, HydroceleTotalWorms, HydroceleShape, rep, folderName); popln.getIncidence(sc, t, rep, folderName); - sc.writeSurveyByAge(popln, t, preTAS_Pass, TAS_Pass, rep, folderName); + sc.writeSurveyByAge(popln, t, popln.preTAS_Pass, popln.TAS_Pass, rep, + folderName); } // If we haven't done a survey this year we still want to output this fact @@ -345,50 +336,50 @@ void Model::evolveAndSave(int y, Population &popln, Vector &vectors, outputPrev); // prev measured before mda done to kill mf in hosts // snippet to perform a preTAS survey - if (t == preTASSurveyTime) { + if (t == popln.preTASSurveyTime) { - preTAS_Pass = popln.PreTASSurvey(sc, outputEndgame, t, outputEndgameDate, - rep, folderName); + popln.preTAS_Pass = popln.PreTASSurvey( + sc, outputEndgame, t, outputEndgameDate, rep, folderName); if ((outputEndgame == 1) && (t >= outputEndgameDate)) { sc.writeNumberByAge(popln, t, rep, folderName, "PreTAS survey"); } donePreTAS = 1; - if (preTAS_Pass == 1) { + if (popln.preTAS_Pass == 1) { // if we pass the preTAS survey then we set a time for the TASsurvey // we also stop doing MDA - TASSurveyTime = t; - DoMDA = 0; + popln.TASSurveyTime = t; + popln.DoMDA = false; } else { - preTASSurveyTime = t + popln.interSurveyPeriod; - DoMDA = 1; + popln.preTASSurveyTime = t + popln.interSurveyPeriod; + popln.DoMDA = true; } } // snippet to perform a TAS survey - if (t == TASSurveyTime) { + if (t == popln.TASSurveyTime) { int TAS_Pass_ind = popln.TASSurvey(sc, t, outputEndgameDate, rep, folderName); if ((outputEndgame == 1) && (t >= outputEndgameDate)) { sc.writeNumberByAge(popln, t, rep, folderName, "TAS survey"); } doneTAS = 1; - TAS_Pass += TAS_Pass_ind; + popln.TAS_Pass += TAS_Pass_ind; if (TAS_Pass_ind == 0) { // if failed, then reset TAS_PAss to 0 and set a time to do another // preTAS survey also switch back on MDA's - TAS_Pass = 0; - preTASSurveyTime = t + popln.interSurveyPeriod; - TASSurveyTime = t + popln.interSurveyPeriod; - DoMDA = 1; - } else if (TAS_Pass == neededTASPass) { + popln.TAS_Pass = 0; + popln.preTASSurveyTime = t + popln.interSurveyPeriod; + popln.TASSurveyTime = t + popln.interSurveyPeriod; + popln.DoMDA = true; + } else if (popln.TAS_Pass == neededTASPass) { // if we have passed a sufficient number of times, then make it so we // won't do any more TAS surveys - TASSurveyTime = 99999999; - } else if (TAS_Pass < neededTASPass) { + popln.TASSurveyTime = 99999999; + } else if (popln.TAS_Pass < neededTASPass) { // if we have passed the survey, but need to pass more, then set a time // for the next TAS survey - TASSurveyTime = t + popln.interSurveyPeriod; + popln.TASSurveyTime = t + popln.interSurveyPeriod; if (vec_control == 0) { vec_control = 1; } @@ -403,19 +394,19 @@ void Model::evolveAndSave(int y, Population &popln, Vector &vectors, double rho = applyMDA->getCompliance(); // if we this is the first MDA, then we need to initialise the Probability // of treatment for each person - if (prevCov == -1) { + if (popln.prevCov == -1) { popln.initPTreat(cov, rho); - prevCov = cov; - prevRho = rho; + popln.prevCov = cov; + popln.prevRho = rho; } // if the MDA parameters have changed then we need to update the // probability of treatment for each person - if ((prevCov != applyMDA->getCoverage()) || - (prevRho != applyMDA->getCompliance())) { - popln.checkForZeroPTreat(prevCov, prevRho); + if ((popln.prevCov != applyMDA->getCoverage()) || + (popln.prevRho != applyMDA->getCompliance())) { + popln.checkForZeroPTreat(popln.prevCov, popln.prevRho); popln.editPTreat(cov, rho); - prevCov = cov; - prevRho = rho; + popln.prevCov = cov; + popln.prevRho = rho; } // check for anyone with 0 probability of treatment, as these will be // people who have not had this value initialised @@ -426,13 +417,12 @@ void Model::evolveAndSave(int y, Population &popln, Vector &vectors, // then we will not begin MDA. If the indicator is not 1 then we will do // MDA even with low MF prevalence this uses the sampleSize input as this // would be assessed via a survey - if (popln.totMDAs == 0) { if (popln.getNoMDALowMF() == 1) { mfprev = popln.getMFPrev(sc, 0, t, outputEndgameDate, rep, sampleSize, folderName); if (mfprev <= popln.MFThreshold) { - DoMDA = 0; + popln.DoMDA = false; } } } @@ -446,10 +436,11 @@ void Model::evolveAndSave(int y, Population &popln, Vector &vectors, mfprev_aimp_old = popln.getMFPrev(sc, 0, t, outputEndgameDate, rep, popSize, folderName); - // apply the MDA. If DoMDA = 0, then we call this function, but don't do - // the MDA, we just write to a file showing that no people were treated. + // apply the MDA. If popln.DoMDA = false, then we call this function, but + // don't do the MDA, we just write to a file showing that no people were + // treated. popln.ApplyTreatmentUpdated(applyMDA, worms, sc, t, outputEndgameDate, - rep, DoMDA, outputEndgame, folderName); + rep, popln.DoMDA, outputEndgame, folderName); t_import_reduction = t + 6; popln.totMDAs += 1; @@ -467,8 +458,8 @@ void Model::evolveAndSave(int y, Population &popln, Vector &vectors, // from now. We will set the time for the TAS survey if the pre TAS // survey is passed. int minNumberMonthsBeforeSurvey = 6; - preTASSurveyTime = std::max(popln.getSurveyStartDate(), - t + minNumberMonthsBeforeSurvey); + popln.preTASSurveyTime = std::max(popln.getSurveyStartDate(), + t + minNumberMonthsBeforeSurvey); } } @@ -527,7 +518,6 @@ void Model::evolveAndSave(int y, Population &popln, Vector &vectors, popln.neverTreatToOriginal(); // done currentMonth = targetMonth; - if (y < (sc.getNumMonthsToSave() - 1)) { // not finished this scenario popln.saveCurrentState( currentMonth, sc.getName()); // worms and importation rate. Scenario diff --git a/src/Population.cpp b/src/Population.cpp index b2e4f6e..3475527 100644 --- a/src/Population.cpp +++ b/src/Population.cpp @@ -399,6 +399,18 @@ void Population::initHosts(std::string distType, double k_val, bedNetCov = 0.0; aImp_factor = 1.0; mdaCoverage = 0.0; + numPreTASSurveys = 0; + numTASSurveys = 0; + // when initializing the hosts, also reset everything to do with surveys + totMDAs = 0; + post2020MDAs = 0; + time_TAS_Passes = -1; + preTASSurveyTime = -1000; + TASSurveyTime = -1000; + DoMDA = true; + preTAS_Pass = 0; + TAS_Pass = 0; + prevCov = -1; } void Population::updateKVal(double k_val) { @@ -551,7 +563,7 @@ int Population::TASSurvey(Scenario &sc, int t, int outputEndgameDate, int rep, if ((icprev <= ICThreshold)) { // if the ic prevalence is below the threshold // and mf prev also below threshold TAS_Pass = 1; // set TAS pass indicator to 1 - t_TAS_Pass = t; // store the time of passing TAS + time_TAS_Passes = t; // store the time of passing TAS } return TAS_Pass; } @@ -929,9 +941,7 @@ void Population::saveCurrentState(int month, std::string sname) { savedMonth currentState; currentState.scenario = sname; // debugging only - currentState.data.resize(size, {0, 0, 0, 0.0, 0.0, 0.0, 0, - 0}); // WM, WF,totalWorms, totalWormYears, - // M,biteRisk,age,monthSinceTreated + currentState.data.resize(size); for (int i = 0; i < size; i++) currentState.data[i] = @@ -946,7 +956,17 @@ void Population::saveCurrentState(int month, std::string sname) { currentState.u0bednets = u0CompBednets; currentState.mdaCov = mdaCoverage; currentState.bednetCov = bedNetCov; - + // when saving data, also save everything to do with surveys + currentState.DoMDA = DoMDA; + currentState.totMDAs = totMDAs; + currentState.numPreTASSurveys = numPreTASSurveys; + currentState.numTASSurveys = numTASSurveys; + currentState.preTASSurveyTime = preTASSurveyTime; + currentState.TASSurveyTime = TASSurveyTime; + currentState.preTAS_Pass = preTAS_Pass; + currentState.TAS_Pass = TAS_Pass; + currentState.prevCov = prevCov; + currentState.prevRho = prevRho; savedMonths.push_back(currentState); } @@ -971,7 +991,17 @@ void Population::resetToMonth(int month) { u0CompBednets = lastMonth.u0bednets; mdaCoverage = lastMonth.mdaCov; bedNetCov = lastMonth.bednetCov; - + // when resetting time, also reset everything to do with surveys + DoMDA = lastMonth.DoMDA; + totMDAs = lastMonth.totMDAs; + numPreTASSurveys = lastMonth.numPreTASSurveys; + numTASSurveys = lastMonth.numTASSurveys; + preTASSurveyTime = lastMonth.preTASSurveyTime; + TASSurveyTime = lastMonth.TASSurveyTime; + preTAS_Pass = lastMonth.preTAS_Pass; + TAS_Pass = lastMonth.TAS_Pass; + prevCov = lastMonth.prevCov; + prevRho = lastMonth.prevRho; if (_DEBUG) std::cout << "Reset to month " << month << ", that was saved by " << lastMonth.scenario << std::endl; @@ -1213,7 +1243,7 @@ int Population::returnMaxAge() { return maxAge; } void Population::ApplyTreatmentUpdated(MDAEvent *mda, Worm &worms, Scenario &sc, int t, int outputEndgameDate, int rep, - int DoMDA, int outputEndgame, + bool DoMDA, int outputEndgame, std::string folderName) { int minAge = (mda->getMinAge() >= 0) ? mda->getMinAge() : minAgeMDA; int minAgeMDAinMonths = minAge * 12; @@ -1232,7 +1262,7 @@ void Population::ApplyTreatmentUpdated(MDAEvent *mda, Worm &worms, Scenario &sc, float flooredAge = std::floor(host_pop[i].age / 12); int flooredAgeInt = std::min(static_cast(flooredAge), maxAge - 1); numHostsByAge[flooredAgeInt] += 1; - if (DoMDA == 1) { + if (DoMDA) { if (host_pop[i].age >= minAgeMDAinMonths) { if (stats.uniform_dist() < host_pop[i].pTreat) { if (host_pop[i].neverTreat == 0) { diff --git a/src/Population.hpp b/src/Population.hpp index 2b2561c..713829f 100644 --- a/src/Population.hpp +++ b/src/Population.hpp @@ -99,7 +99,7 @@ class Population { void ApplyTreatment(MDAEvent *mda, Worm &worms, Scenario &sc, int t, int rep, std::string folderName); void ApplyTreatmentUpdated(MDAEvent *mda, Worm &worms, Scenario &sc, int t, - int outputEndgameDate, int rep, int DoMDA, + int outputEndgameDate, int rep, bool DoMDA, int outputEndgame, std::string folderName); void saveCurrentState(int month, std::string sname); void resetToMonth(int month); @@ -123,11 +123,25 @@ class Population { double MFThreshold; int interSurveyPeriod; int firstTASNumMDA; - int numPreTASSurveys = 0; - int numTASSurveys = 0; - int totMDAs = 0; - int post2020MDAs = 0; - int t_TAS_Pass = -1; + // declare the information regarding surveys + int numPreTASSurveys; + int numTASSurveys; + int totMDAs; + int post2020MDAs; + int time_TAS_Passes; + int preTASSurveyTime; + int TASSurveyTime; + int preTAS_Pass; + int TAS_Pass; + double prevCov; + double prevRho; + // indicator if we should do the MDA when the MDA is called. + // This will be switched to 0 if preTAS is passed, then the MDA function will + // be called, but will not be done We will still get the output of the MDA + // showing that no people were treated this year. This is to keep the output + // of MDA's constant so that we can combine different runs even if they have + // different numbers of MDA's performed. + bool DoMDA; double aImp; int sensSpecChangeCount = 0; int neverTreatChangeCount = 0; @@ -230,6 +244,16 @@ class Population { double u0MDA; double bednetCov; double mdaCov; + bool DoMDA; + int totMDAs; + int numPreTASSurveys; + int numTASSurveys; + int preTASSurveyTime; + int TASSurveyTime; + int preTAS_Pass; + int TAS_Pass; + double prevCov; + double prevRho; std::string scenario; // for debugging only. The scenario that saved this month diff --git a/src/Scenario.cpp b/src/Scenario.cpp index 184cebc..cf5aeb8 100644 --- a/src/Scenario.cpp +++ b/src/Scenario.cpp @@ -334,7 +334,7 @@ void Scenario::printResults(int repnum, Output &results, Population &popln) { myFileIC << "\t" << popln.post2020MDAs; myFileIC << "\t" << popln.numPreTASSurveys; myFileIC << "\t" << popln.numTASSurveys; - myFileIC << "\t" << popln.t_TAS_Pass; + myFileIC << "\t" << popln.time_TAS_Passes; myFileIC << std::endl; } @@ -343,7 +343,7 @@ void Scenario::printResults(int repnum, Output &results, Population &popln) { myFileMF << "\t" << popln.post2020MDAs; myFileMF << "\t" << popln.numPreTASSurveys; myFileMF << "\t" << popln.numTASSurveys; - myFileMF << "\t" << popln.t_TAS_Pass; + myFileMF << "\t" << popln.time_TAS_Passes; myFileMF << std::endl; } @@ -352,7 +352,7 @@ void Scenario::printResults(int repnum, Output &results, Population &popln) { myFileWC << "\t" << popln.post2020MDAs; myFileWC << "\t" << popln.numPreTASSurveys; myFileWC << "\t" << popln.numTASSurveys; - myFileWC << "\t" << popln.t_TAS_Pass; + myFileWC << "\t" << popln.time_TAS_Passes; myFileWC << std::endl; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index df6061b..42d2c50 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,4 +17,4 @@ target_link_libraries(tests PRIVATE Catch2::Catch2WithMain model) include(CTest) include(Catch) -catch_discover_tests(tests) +catch_discover_tests(tests) \ No newline at end of file diff --git a/tests/test_host.cpp b/tests/test_host.cpp index 3d55ca6..8cd376e 100644 --- a/tests/test_host.cpp +++ b/tests/test_host.cpp @@ -3,8 +3,65 @@ TEST_CASE("Host", "[classic]") { SECTION("Host::restore") { - Host host; - hostState state; - host.restore(state); + // Initialize a population of hosts + int size = 1; + double TotalBiteRisk = 0.0; + Host host_pop; + + // initialise population and set pTreat value + + host_pop.initialise(1.0, 100, 0.2, &TotalBiteRisk, 0.1, 0.1, 0.0); + host_pop.WM = 1; + host_pop.WF = 2; + host_pop.totalWorms = 3; + host_pop.totalWormYears = 4.1; + host_pop.M = 5.0; + host_pop.biteRisk = 6.0; + host_pop.age = 7.0; + host_pop.monthsSinceTreated = 8; + host_pop.hydroMult = 9.0; + host_pop.lymphoMult = 10.0; + host_pop.sex = 0; + host_pop.pTreat = 3.1415926535; + + // Save the state of each host + // hostState currentState[size]; + hostState currentState; + currentState = host_pop; + + // change the values in some fields, so that we know that the tested code is + // doing something + + host_pop.WM = 0; + host_pop.WF = 0; + host_pop.totalWorms = 0; + host_pop.totalWormYears = 0.0; + host_pop.M = 0.0; + host_pop.biteRisk = 0.0; + host_pop.age = 0.0; + host_pop.monthsSinceTreated = 0; + host_pop.hydroMult = 0.0; + host_pop.lymphoMult = 0.0; + host_pop.sex = 1; + host_pop.pTreat = 0.0; + + // Restore the hosts from the saved state + + host_pop.restore(currentState); + + // check that each host's state matches the saved state + + REQUIRE(host_pop.WM == 1); + REQUIRE(host_pop.WF == 2); + REQUIRE(host_pop.totalWorms == 3); + REQUIRE(host_pop.totalWormYears == 4.1); + REQUIRE(host_pop.M == 5.0); + REQUIRE(host_pop.biteRisk == 6.0); + REQUIRE(host_pop.age == 7.0); + REQUIRE(host_pop.monthsSinceTreated == 8); + REQUIRE(host_pop.hydroMult == 9.0); + REQUIRE(host_pop.lymphoMult == 10.0); + REQUIRE(host_pop.sex == 0); + REQUIRE(host_pop.pTreat == 3.1415926535); } }