From 5304a7b32ecbbb54ec105946a18dbf508c688350 Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Thu, 11 Jun 2020 21:52:49 -0400 Subject: [PATCH 01/13] 25% reduction in run time for regressiontest_US_based.py by reworking a comparison between a host's country and a nearby place's country to utilize better CPU caching and removing a redundant computation for each loop in SetupModel.cpp --- src/CovidSim.cpp | 4 +++- src/Model.h | 3 +++ src/SetupModel.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/CovidSim.cpp b/src/CovidSim.cpp index 660e68c69..ddcfc79b7 100644 --- a/src/CovidSim.cpp +++ b/src/CovidSim.cpp @@ -4,9 +4,10 @@ #include #include -#include #include #include +#include +#include #include #include #include @@ -82,6 +83,7 @@ PopVar State, StateT[MAX_NUM_THREADS]; Cell* Cells; // Cells[i] is the i'th cell Cell ** CellLookup; // CellLookup[i] is a pointer to the i'th populated cell Microcell* Mcells, ** McellLookup; +std::vector mcell_country; Place** Places; AdminUnit AdUnits[MAX_ADUNITS]; //// Time Series defs: diff --git a/src/Model.h b/src/Model.h index 617c1f0dd..1270a32c4 100644 --- a/src/Model.h +++ b/src/Model.h @@ -1,7 +1,9 @@ #ifndef COVIDSIM_MODEL_H_INCLUDED_ #define COVIDSIM_MODEL_H_INCLUDED_ +#include #include +#include #include "Country.h" #include "Constants.h" @@ -295,6 +297,7 @@ extern Household* Households; extern PopVar State, StateT[MAX_NUM_THREADS]; extern Cell* Cells, ** CellLookup; extern Microcell* Mcells, ** McellLookup; +extern std::vector mcell_country; extern Place** Places; extern AdminUnit AdUnits[MAX_ADUNITS]; diff --git a/src/SetupModel.cpp b/src/SetupModel.cpp index 7aace0065..c5f3fad5b 100644 --- a/src/SetupModel.cpp +++ b/src/SetupModel.cpp @@ -709,13 +709,13 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den FILE* dat = NULL, *dat2; BinFile rec; double *mcell_dens; - int *mcell_adunits, *mcell_num, *mcell_country; + int *mcell_adunits, *mcell_num; Cells = (Cell*)Memory::xcalloc(P.NC, sizeof(Cell)); Mcells = (Microcell*)Memory::xcalloc(P.NMC, sizeof(Microcell)); mcell_num = (int*)Memory::xcalloc(P.NMC, sizeof(int)); mcell_dens = (double*)Memory::xcalloc(P.NMC, sizeof(double)); - mcell_country = (int*)Memory::xcalloc(P.NMC, sizeof(int)); + mcell_country.reserve(P.NMC); mcell_adunits = (int*)Memory::xcalloc(P.NMC, sizeof(int)); for (j = 0; j < P.NMC; j++) @@ -1018,7 +1018,6 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den Memory::xfree(mcell_dens); Memory::xfree(mcell_num); - Memory::xfree(mcell_country); Memory::xfree(mcell_adunits); t = 0.0; @@ -2120,12 +2119,13 @@ void AssignPeopleToPlaces() Direction m2 = Right; if (Hosts[i].PlaceLinks[tp] < 0) //added this so that if any hosts have already be assigned due to their household membership, they will not be reassigned { + const uint16_t host_country = Mcells[Hosts[i].mcell].country; while (((k < nn) || (l < 4)) && (l < P.get_number_of_micro_cells_wide())) { if (P.is_in_bounds(mc_position)) { ic = P.get_micro_cell_index_from_position(mc_position); - if (Mcells[ic].country == Mcells[Hosts[i].mcell].country) + if (mcell_country[ic] == host_country) { for (cnt = 0; cnt < Mcells[ic].np[tp]; cnt++) { From ccf24ff6e42e0252d399e4d824eda564e710f7cd Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Thu, 11 Jun 2020 22:48:29 -0400 Subject: [PATCH 02/13] 20% reduction in run-time for regressiontest_US_based.py by replacing Param::get_number_of_micro_cells_wide() and Param::get_number_of_micro_cells_high() with Param.total_microcells_wide_ and Param.total_microcells_high_; since the function was performing redudant calculations (the inputs never changed) it makes more sense to compute and store the values instead of spending a function call and loading two memory addresses to achieve the same effect --- src/Bitmap.cpp | 14 +++++++------- src/CovidSim.cpp | 10 +++++----- src/Dist.cpp | 8 ++++---- src/Param.cpp | 22 +++++++--------------- src/Param.h | 3 +-- src/SetupModel.cpp | 36 ++++++++++++++++++++---------------- 6 files changed, 44 insertions(+), 49 deletions(-) diff --git a/src/Bitmap.cpp b/src/Bitmap.cpp index 2eac96d53..2238f0dd9 100644 --- a/src/Bitmap.cpp +++ b/src/Bitmap.cpp @@ -61,16 +61,16 @@ void CaptureBitmap() if (Mcells[i].n > 0) { f = 0; - if ((i < P.NMC - 1) && (i / P.get_number_of_micro_cells_high() == (i + 1) / P.get_number_of_micro_cells_high()) && (Mcells[i + 1].n > 0) && ((Mcells[i].country != Mcells[i + 1].country) + if ((i < P.NMC - 1) && (i / P.total_microcells_high_ == (i + 1) / P.total_microcells_high_) && (Mcells[i + 1].n > 0) && ((Mcells[i].country != Mcells[i + 1].country) || ((P.DoAdunitBoundaryOutput) && ((AdUnits[Mcells[i].adunit].id % P.AdunitLevel1Mask) / P.AdunitBitmapDivisor != (AdUnits[Mcells[i + 1].adunit].id % P.AdunitLevel1Mask) / P.AdunitBitmapDivisor)))) f = 1; - if ((i > 0) && (i / P.get_number_of_micro_cells_high() == (i - 1) / P.get_number_of_micro_cells_high()) && (Mcells[i - 1].n > 0) && (Mcells[i].country != Mcells[i - 1].country)) f = 1; - if ((i < P.NMC - P.get_number_of_micro_cells_high()) && (Mcells[i + P.get_number_of_micro_cells_high()].n > 0) && ((Mcells[i].country != Mcells[i + P.get_number_of_micro_cells_high()].country) - || ((P.DoAdunitBoundaryOutput) && ((AdUnits[Mcells[i].adunit].id % P.AdunitLevel1Mask) / P.AdunitBitmapDivisor != (AdUnits[Mcells[i + P.get_number_of_micro_cells_high()].adunit].id % P.AdunitLevel1Mask) / P.AdunitBitmapDivisor)))) f = 1; - if ((i >= P.get_number_of_micro_cells_high()) && (Mcells[i - P.get_number_of_micro_cells_high()].n > 0) && (Mcells[i].country != Mcells[i - P.get_number_of_micro_cells_high()].country)) f = 1; + if ((i > 0) && (i / P.total_microcells_high_ == (i - 1) / P.total_microcells_high_) && (Mcells[i - 1].n > 0) && (Mcells[i].country != Mcells[i - 1].country)) f = 1; + if ((i < P.NMC - P.total_microcells_high_) && (Mcells[i + P.total_microcells_high_].n > 0) && ((Mcells[i].country != Mcells[i + P.total_microcells_high_].country) + || ((P.DoAdunitBoundaryOutput) && ((AdUnits[Mcells[i].adunit].id % P.AdunitLevel1Mask) / P.AdunitBitmapDivisor != (AdUnits[Mcells[i + P.total_microcells_high_].adunit].id % P.AdunitLevel1Mask) / P.AdunitBitmapDivisor)))) f = 1; + if ((i >= P.total_microcells_high_) && (Mcells[i - P.total_microcells_high_].n > 0) && (Mcells[i].country != Mcells[i - P.total_microcells_high_].country)) f = 1; if (f) { - x = (int)(P.in_microcells_.width * (((double)(i / P.get_number_of_micro_cells_high())) + 0.5) * P.scale.x) - P.bmin.x; - y = (int)(P.in_microcells_.height * (((double)(i % P.get_number_of_micro_cells_high())) + 0.5) * P.scale.y) - P.bmin.y; + x = (int)(P.in_microcells_.width * (((double)(i / P.total_microcells_high_)) + 0.5) * P.scale.x) - P.bmin.x; + y = (int)(P.in_microcells_.height * (((double)(i % P.total_microcells_high_)) + 0.5) * P.scale.y) - P.bmin.y; if ((x >= 0) && (x < P.b.width) && (y >= 0) && (y < P.b.height)) { j = y * bmh->width + x; diff --git a/src/CovidSim.cpp b/src/CovidSim.cpp index ddcfc79b7..5af1c012b 100644 --- a/src/CovidSim.cpp +++ b/src/CovidSim.cpp @@ -2719,7 +2719,7 @@ void SeedInfection(double t, int* NumSeedingInfections_byLocation, int rf, int r { k = (int)(P.LocationInitialInfection[i][0] / P.in_microcells_.width); l = (int)(P.LocationInitialInfection[i][1] / P.in_microcells_.height); - j = k * P.get_number_of_micro_cells_high() + l; + j = k * P.total_microcells_high_ + l; m = 0; for (k = 0; (k < NumSeedingInfections_byLocation[i]) && (m < 10000); k++) { @@ -5332,7 +5332,7 @@ void CalcOriginDestMatrix_adunit() //find index of cell from which flow travels ptrdiff_t cl_from = CellLookup[i] - Cells; - ptrdiff_t cl_from_mcl = (cl_from / P.nch) * P.NMCL * P.get_number_of_micro_cells_high() + (cl_from % P.nch) * P.NMCL; + ptrdiff_t cl_from_mcl = (cl_from / P.nch) * P.NMCL * P.total_microcells_high_ + (cl_from % P.nch) * P.NMCL; //loop over microcells in these cells to find populations in each admin unit and so flows for (int k = 0; k < P.NMCL; k++) @@ -5340,7 +5340,7 @@ void CalcOriginDestMatrix_adunit() for (int l = 0; l < P.NMCL; l++) { //get index of microcell - ptrdiff_t mcl_from = cl_from_mcl + l + k * P.get_number_of_micro_cells_high(); + ptrdiff_t mcl_from = cl_from_mcl + l + k * P.total_microcells_high_; if (Mcells[mcl_from].n > 0) { //get proportion of each population of cell that exists in each admin unit @@ -5356,7 +5356,7 @@ void CalcOriginDestMatrix_adunit() //find index of cell which flow travels to ptrdiff_t cl_to = CellLookup[j] - Cells; - ptrdiff_t cl_to_mcl = (cl_to / P.nch) * P.NMCL * P.get_number_of_micro_cells_high() + (cl_to % P.nch) * P.NMCL; + ptrdiff_t cl_to_mcl = (cl_to / P.nch) * P.NMCL * P.total_microcells_high_ + (cl_to % P.nch) * P.NMCL; //calculate distance and kernel between the cells //total_flow=Cells[cl_from].max_trans[j]*Cells[cl_from].n*Cells[cl_to].n; double total_flow; @@ -5375,7 +5375,7 @@ void CalcOriginDestMatrix_adunit() for (int p = 0; p < P.NMCL; p++) { //get index of microcell - ptrdiff_t mcl_to = cl_to_mcl + p + m * P.get_number_of_micro_cells_high(); + ptrdiff_t mcl_to = cl_to_mcl + p + m * P.total_microcells_high_; if (Mcells[mcl_to].n > 0) { //get proportion of each population of cell that exists in each admin unit diff --git a/src/Dist.cpp b/src/Dist.cpp index 38ef15e93..94bc41c3e 100644 --- a/src/Dist.cpp +++ b/src/Dist.cpp @@ -152,12 +152,12 @@ double dist2_mm(Microcell* a, Microcell* b) l = (int)(a - Mcells); m = (int)(b - Mcells); if (P.DoUTM_coords) - return dist2UTM(P.in_microcells_.width * fabs((double)(l / P.get_number_of_micro_cells_high())), P.in_microcells_.height * fabs((double)(l % P.get_number_of_micro_cells_high())), - P.in_microcells_.width * fabs((double)(m / P.get_number_of_micro_cells_high())), P.in_microcells_.height * fabs((double)(m % P.get_number_of_micro_cells_high()))); + return dist2UTM(P.in_microcells_.width * fabs((double)(l / P.total_microcells_high_)), P.in_microcells_.height * fabs((double)(l % P.total_microcells_high_)), + P.in_microcells_.width * fabs((double)(m / P.total_microcells_high_)), P.in_microcells_.height * fabs((double)(m % P.total_microcells_high_))); else { - x = P.in_microcells_.width * fabs((double)(l / P.get_number_of_micro_cells_high() - m / P.get_number_of_micro_cells_high())); - y = P.in_microcells_.height * fabs((double)(l % P.get_number_of_micro_cells_high() - m % P.get_number_of_micro_cells_high())); + x = P.in_microcells_.width * fabs((double)(l / P.total_microcells_high_ - m / P.total_microcells_high_)); + y = P.in_microcells_.height * fabs((double)(l % P.total_microcells_high_ - m % P.total_microcells_high_)); return periodic_xy(x, y); } } diff --git a/src/Param.cpp b/src/Param.cpp index 4eb8a869e..288230291 100644 --- a/src/Param.cpp +++ b/src/Param.cpp @@ -1,28 +1,20 @@ #include "Param.h" -int Param::get_number_of_micro_cells_wide() const { - return this->ncw * this->NMCL; -} - -int Param::get_number_of_micro_cells_high() const { - return this->nch * this->NMCL; -} - MicroCellPosition Param::get_micro_cell_position_from_cell_index(int cell_index) const { - int x = cell_index / this->get_number_of_micro_cells_high(); - int y = cell_index % this->get_number_of_micro_cells_high(); + int x = cell_index / this->total_microcells_high_; + int y = cell_index % this->total_microcells_high_; return {x, y}; } bool Param::is_in_bounds(MicroCellPosition position) const { return position.x >= 0 && position.y >= 0 - && position.x < this->get_number_of_micro_cells_wide() - && position.y < this->get_number_of_micro_cells_high(); + && position.x < this->total_microcells_wide_ + && position.y < this->total_microcells_high_; } int Param::get_micro_cell_index_from_position(MicroCellPosition position) const { - int x = (position.x + this->get_number_of_micro_cells_wide()) % this->get_number_of_micro_cells_wide(); - int y = (position.y + this->get_number_of_micro_cells_high()) % this->get_number_of_micro_cells_high(); - return x * this->get_number_of_micro_cells_high() + y; + int x = (position.x + this->total_microcells_wide_) % this->total_microcells_wide_; + int y = (position.y + this->total_microcells_high_) % this->total_microcells_high_; + return x * this->total_microcells_high_ + y; } diff --git a/src/Param.h b/src/Param.h index d3bfb2c17..ff7856b77 100644 --- a/src/Param.h +++ b/src/Param.h @@ -45,9 +45,8 @@ struct Param int NMCL; // Number of microcells wide/high a cell is; i.e. NMC = NC * NMCL * NMCL int NCP; /**< Number of populated cells */ int NMCP, ncw, nch, DoUTM_coords, nsp, DoSeasonality, DoCorrectAgeDist, DoPartialImmunity; + int total_microcells_wide_, total_microcells_high_; - int get_number_of_micro_cells_wide() const; - int get_number_of_micro_cells_high() const; MicroCellPosition get_micro_cell_position_from_cell_index(int cell_index) const; int get_micro_cell_index_from_position(MicroCellPosition position) const; bool is_in_bounds(MicroCellPosition position) const; diff --git a/src/SetupModel.cpp b/src/SetupModel.cpp index c5f3fad5b..f27765cca 100644 --- a/src/SetupModel.cpp +++ b/src/SetupModel.cpp @@ -149,7 +149,9 @@ void SetupModel(std::string const& density_file, std::string const& out_density_ P.in_degrees_.width = P.SpatialBoundingBox[2] - P.SpatialBoundingBox[0]; P.in_degrees_.height = P.SpatialBoundingBox[3] - P.SpatialBoundingBox[1]; P.ncw = 4 * ((int)ceil(P.in_degrees_.width / P.in_cells_.width / 4)); + P.total_microcells_wide_ = P.ncw * P.NMCL; P.nch = 4 * ((int)ceil(P.in_degrees_.height / P.in_cells_.height / 4)); + P.total_microcells_high_ = P.nch * P.NMCL; P.in_degrees_.width = ((double)P.ncw) * P.in_cells_.width; P.in_degrees_.height = ((double)P.nch) * P.in_cells_.height; P.SpatialBoundingBox[2] = P.SpatialBoundingBox[0] + P.in_degrees_.width; @@ -170,6 +172,8 @@ void SetupModel(std::string const& density_file, std::string const& out_density_ else { P.ncw = P.nch = (int)sqrt((double)P.NC); + P.total_microcells_wide_ = P.ncw * P.NMCL; + P.total_microcells_high_ = P.nch * P.NMCL; P.NC = P.ncw * P.nch; fprintf(stderr, "Number of cells adjusted to be %i (%i^2)\n", P.NC, P.ncw); s = floor(sqrt((double)P.PopSize)); @@ -781,7 +785,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den { j = (int)floor((x - P.SpatialBoundingBox[0]) / P.in_microcells_.width + 0.1); k = (int)floor((y - P.SpatialBoundingBox[1]) / P.in_microcells_.height + 0.1); - l = j * P.get_number_of_micro_cells_high() + k; + l = j * P.total_microcells_high_ + k; if (l < P.NMC) { mr++; @@ -824,8 +828,8 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den for (l = 0; l < P.NMC; l++) if (mcell_adunits[l] >= 0) { - BF[rn].x = (double)(P.in_microcells_.width * (((double)(l / P.get_number_of_micro_cells_high())) + 0.5)) + P.SpatialBoundingBox[0]; //x - BF[rn].y = (double)(P.in_microcells_.height * (((double)(l % P.get_number_of_micro_cells_high())) + 0.5)) + P.SpatialBoundingBox[1]; //y + BF[rn].x = (double)(P.in_microcells_.width * (((double)(l / P.total_microcells_high_)) + 0.5)) + P.SpatialBoundingBox[0]; //x + BF[rn].y = (double)(P.in_microcells_.height * (((double)(l % P.total_microcells_high_)) + 0.5)) + P.SpatialBoundingBox[1]; //y BF[rn].ad = (P.DoAdUnits) ? (AdUnits[mcell_adunits[l]].id) : 0; BF[rn].pop = mcell_dens[l]; BF[rn].cnt = mcell_country[l]; @@ -1027,12 +1031,12 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den for (int i = i2 = j2 = 0; i < P.NC; i++) { Cells[i].n = 0; - int k = (i / P.nch) * P.NMCL * P.get_number_of_micro_cells_high() + (i % P.nch) * P.NMCL; + int k = (i / P.nch) * P.NMCL * P.total_microcells_high_ + (i % P.nch) * P.NMCL; Cells[i].members = State.CellMemberArray + j2; for (l = 0; l < P.NMCL; l++) for (m = 0; m < P.NMCL; m++) { - j = k + m + l * P.get_number_of_micro_cells_high(); + j = k + m + l * P.total_microcells_high_; if (Mcells[j].n > 0) { Mcells[j].members = State.CellMemberArray + j2; @@ -1087,7 +1091,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den for (j2 = 0; j2 < P.NMCP; j2++) { j = (int)(McellLookup[j2] - Mcells); - l = ((j / P.get_number_of_micro_cells_high()) / P.NMCL) * P.nch + ((j % P.get_number_of_micro_cells_high()) / P.NMCL); + l = ((j / P.total_microcells_high_) / P.NMCL) * P.nch + ((j % P.total_microcells_high_) / P.NMCL); ad = (!reg_demog_file.empty() && (P.DoAdUnits)) ? Mcells[j].adunit : 0; for (int k = 0; k < Mcells[j].n;) { @@ -1125,8 +1129,8 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den for (j2 = tn; j2 < P.NMCP; j2 += P.NumThreads) { j = (int)(McellLookup[j2] - Mcells); - x = (double)(j / P.get_number_of_micro_cells_high()); - y = (double)(j % P.get_number_of_micro_cells_high()); + x = (double)(j / P.total_microcells_high_); + y = (double)(j % P.total_microcells_high_); int i = Mcells[j].members[0]; if (j % 100 == 0) fprintf(stderr_shared, "%i=%i (%i %i) \r", j, Mcells[j].n, Mcells[j].adunit, (AdUnits[Mcells[j].adunit].id % P.AdunitLevel1Mask) / P.AdunitLevel1Divisor); @@ -1251,7 +1255,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den { int k = (int)(P.LocationInitialInfection[0][0] / P.in_microcells_.width); l = (int)(P.LocationInitialInfection[0][1] / P.in_microcells_.height); - j = k * P.get_number_of_micro_cells_high() + l; + j = k * P.total_microcells_high_ + l; double rand_r = 0.0; //added these variables so that if initial infection location is empty we can search the 10km neighbourhood to find a suitable cell double rand_theta = 0.0; @@ -1264,7 +1268,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den rand_r = 0.083 * sqrt(rand_r); rand_theta = 2 * PI * rand_theta; //rand_r is multiplied by 0.083 as this is roughly equal to 10km in decimal degrees k = (int)((P.LocationInitialInfection[0][0] + rand_r * cos(rand_theta)) / P.in_microcells_.width); l = (int)((P.LocationInitialInfection[0][1] + rand_r * sin(rand_theta)) / P.in_microcells_.height); - j = k * P.get_number_of_micro_cells_high() + l; + j = k * P.total_microcells_high_ + l; counter++; } if (counter < 100) @@ -1343,7 +1347,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den Places[j][P.Nplace[j]].n = m; i = (int)(Places[j][P.Nplace[j]].loc.x / P.in_microcells_.width); int k = (int)(Places[j][P.Nplace[j]].loc.y / P.in_microcells_.height); - j2 = i * P.get_number_of_micro_cells_high() + k; + j2 = i * P.total_microcells_high_ + k; Mcells[j2].np[j]++; Places[j][P.Nplace[j]].mcell = j2; P.Nplace[j]++; @@ -1407,8 +1411,8 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den if (Mcells[i].np[j2] > 0) { Mcells[i].places[j2] = (int*)Memory::xcalloc(Mcells[i].np[j2], sizeof(int)); - x = (double)(i / P.get_number_of_micro_cells_high()); - y = (double)(i % P.get_number_of_micro_cells_high()); + x = (double)(i / P.total_microcells_high_); + y = (double)(i % P.total_microcells_high_); for (j = 0; j < Mcells[i].np[j2]; j++) { xh = P.in_microcells_.width * (ranf_mt(tn) + x); @@ -1531,8 +1535,8 @@ void SetupAirports(void) if (Mcells[i].n > 0) { if (i % 10000 == 0) fprintf(stderr_shared, "\n%i ", i); - x = (((double)(i / P.get_number_of_micro_cells_high())) + 0.5) * P.in_microcells_.width; - y = (((double)(i % P.get_number_of_micro_cells_high())) + 0.5) * P.in_microcells_.height; + x = (((double)(i / P.total_microcells_high_)) + 0.5) * P.in_microcells_.width; + y = (((double)(i % P.total_microcells_high_)) + 0.5) * P.in_microcells_.height; k = l = 0; tmin = 1e20; for (int j = 0; j < P.Nairports; j++) @@ -2120,7 +2124,7 @@ void AssignPeopleToPlaces() if (Hosts[i].PlaceLinks[tp] < 0) //added this so that if any hosts have already be assigned due to their household membership, they will not be reassigned { const uint16_t host_country = Mcells[Hosts[i].mcell].country; - while (((k < nn) || (l < 4)) && (l < P.get_number_of_micro_cells_wide())) + while (((k < nn) || (l < 4)) && (l < P.total_microcells_wide_)) { if (P.is_in_bounds(mc_position)) { From 0970aa3af7d56aff6158aa4b6db82d4fe2072952 Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Fri, 12 Jun 2020 09:02:53 -0400 Subject: [PATCH 03/13] deduplicated code --- src/SetupModel.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/SetupModel.cpp b/src/SetupModel.cpp index f27765cca..52fa0ed2c 100644 --- a/src/SetupModel.cpp +++ b/src/SetupModel.cpp @@ -149,9 +149,7 @@ void SetupModel(std::string const& density_file, std::string const& out_density_ P.in_degrees_.width = P.SpatialBoundingBox[2] - P.SpatialBoundingBox[0]; P.in_degrees_.height = P.SpatialBoundingBox[3] - P.SpatialBoundingBox[1]; P.ncw = 4 * ((int)ceil(P.in_degrees_.width / P.in_cells_.width / 4)); - P.total_microcells_wide_ = P.ncw * P.NMCL; P.nch = 4 * ((int)ceil(P.in_degrees_.height / P.in_cells_.height / 4)); - P.total_microcells_high_ = P.nch * P.NMCL; P.in_degrees_.width = ((double)P.ncw) * P.in_cells_.width; P.in_degrees_.height = ((double)P.nch) * P.in_cells_.height; P.SpatialBoundingBox[2] = P.SpatialBoundingBox[0] + P.in_degrees_.width; @@ -172,8 +170,6 @@ void SetupModel(std::string const& density_file, std::string const& out_density_ else { P.ncw = P.nch = (int)sqrt((double)P.NC); - P.total_microcells_wide_ = P.ncw * P.NMCL; - P.total_microcells_high_ = P.nch * P.NMCL; P.NC = P.ncw * P.nch; fprintf(stderr, "Number of cells adjusted to be %i (%i^2)\n", P.NC, P.ncw); s = floor(sqrt((double)P.PopSize)); @@ -186,6 +182,8 @@ void SetupModel(std::string const& density_file, std::string const& out_density_ P.in_cells_.height = P.in_degrees_.height / ((double)P.nch); } P.NMC = P.NMCL * P.NMCL * P.NC; + P.total_microcells_wide_ = P.ncw * P.NMCL; + P.total_microcells_high_ = P.nch * P.NMCL; fprintf(stderr, "Number of microcells = %i\n", P.NMC); P.scale.x = P.BitmapScale; P.scale.y = P.BitmapAspectScale * P.BitmapScale; From 29f86e7304636af6eb16567880b40d5948c21022 Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Fri, 12 Jun 2020 09:46:34 -0400 Subject: [PATCH 04/13] 3% reduction in regressiontest_US_based.py by changing MicroCellPosition code to use a standard compound operator implementation (https://en.cppreference.com/w/cpp/language/operators) and making it an inline call --- covid-sim.vcxproj | 1 - src/CMakeLists.txt | 3 +-- src/MicroCellPosition.cpp | 16 ---------------- src/MicroCellPosition.hpp | 20 +++++++++++++++----- 4 files changed, 16 insertions(+), 24 deletions(-) delete mode 100644 src/MicroCellPosition.cpp diff --git a/covid-sim.vcxproj b/covid-sim.vcxproj index 223c9e06b..d9204b328 100644 --- a/covid-sim.vcxproj +++ b/covid-sim.vcxproj @@ -104,7 +104,6 @@ - diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e149dd91f..181e32474 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,8 +3,7 @@ # Set up the IDE set(MAIN_SRC_FILES CovidSim.cpp BinIO.cpp Rand.cpp Error.cpp Dist.cpp Kernels.cpp Bitmap.cpp SetupModel.cpp CalcInfSusc.cpp Sweep.cpp Update.cpp - Param.cpp MicroCellPosition.cpp Direction.cpp InverseCdf.cpp Memory.cpp - CLI.cpp) + Param.cpp Direction.cpp InverseCdf.cpp Memory.cpp CLI.cpp) set(MAIN_HDR_FILES CovidSim.h BinIO.h Rand.h Constants.h Country.h Error.h Dist.h Kernels.h Bitmap.h Model.h Param.h SetupModel.h ModelMacros.h InfStat.h CalcInfSusc.h Sweep.h Update.h MicroCellPosition.hpp Direction.hpp diff --git a/src/MicroCellPosition.cpp b/src/MicroCellPosition.cpp deleted file mode 100644 index 247bdb27d..000000000 --- a/src/MicroCellPosition.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "MicroCellPosition.hpp" -#include - -MicroCellPosition MicroCellPosition::operator+(Direction direction) const { - switch (direction) { - case Right: return {this->x + 1, this->y}; - case Up: return {this->x, this->y - 1}; - case Left: return {this->x - 1, this->y}; - case Down: return {this->x, this->y + 1}; - } - throw std::out_of_range("direction"); -} - -MicroCellPosition &MicroCellPosition::operator+=(Direction direction) { - return *this = *this + direction; -} diff --git a/src/MicroCellPosition.hpp b/src/MicroCellPosition.hpp index 4f05bee3e..28d1b7230 100644 --- a/src/MicroCellPosition.hpp +++ b/src/MicroCellPosition.hpp @@ -1,13 +1,23 @@ #pragma once +#include + #include "Direction.hpp" -class MicroCellPosition { -public: +struct MicroCellPosition +{ int x; int y; - MicroCellPosition operator+(Direction direction) const; - MicroCellPosition& operator+=(Direction direction); + inline MicroCellPosition& operator+=(Direction direction) + { + switch (direction) { + case Right: this->x += 1; break; + case Up: this->y -= 1; break; + case Left: this->x -= 1; break; + case Down: this->y += 1; break; + default: throw std::out_of_range("direction"); + } + return *this; + } }; - From 5f8e3a5494de8af16bb7e3575061739bd6a75f6b Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Fri, 12 Jun 2020 14:12:53 -0400 Subject: [PATCH 05/13] changed Param::is_in_bounds() and Param::get_micro_cell_index_from_position() to pass by const reference instead of by value --- src/Param.cpp | 4 ++-- src/Param.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Param.cpp b/src/Param.cpp index 288230291..1cc081b57 100644 --- a/src/Param.cpp +++ b/src/Param.cpp @@ -6,14 +6,14 @@ MicroCellPosition Param::get_micro_cell_position_from_cell_index(int cell_index) return {x, y}; } -bool Param::is_in_bounds(MicroCellPosition position) const { +bool Param::is_in_bounds(MicroCellPosition const& position) const { return position.x >= 0 && position.y >= 0 && position.x < this->total_microcells_wide_ && position.y < this->total_microcells_high_; } -int Param::get_micro_cell_index_from_position(MicroCellPosition position) const { +int Param::get_micro_cell_index_from_position(MicroCellPosition const& position) const { int x = (position.x + this->total_microcells_wide_) % this->total_microcells_wide_; int y = (position.y + this->total_microcells_high_) % this->total_microcells_high_; return x * this->total_microcells_high_ + y; diff --git a/src/Param.h b/src/Param.h index ff7856b77..055fa3e3b 100644 --- a/src/Param.h +++ b/src/Param.h @@ -48,8 +48,8 @@ struct Param int total_microcells_wide_, total_microcells_high_; MicroCellPosition get_micro_cell_position_from_cell_index(int cell_index) const; - int get_micro_cell_index_from_position(MicroCellPosition position) const; - bool is_in_bounds(MicroCellPosition position) const; + int get_micro_cell_index_from_position(MicroCellPosition const& position) const; + bool is_in_bounds(MicroCellPosition const& position) const; int DoAdUnits, NumAdunits, DoAdunitBoundaries, AdunitLevel1Divisor, AdunitLevel1Mask, AdunitBitmapDivisor, CountryDivisor; int DoAdunitOutput, DoAdunitBoundaryOutput, DoCorrectAdunitPop, DoSpecifyPop, AdunitLevel1Lookup[ADUNIT_LOOKUP_SIZE]; From 34cbece80a077203308db75e8a78dec7f1a46e9e Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Tue, 16 Jun 2020 11:40:32 -0400 Subject: [PATCH 06/13] replaced mcell_country's vector.reserve() in SetupPopulation() to a copy-by-value initialized vector to ensure that the space not only allocated and initialized but the vector's size is not 0 --- src/SetupModel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SetupModel.cpp b/src/SetupModel.cpp index 52fa0ed2c..35e5de834 100644 --- a/src/SetupModel.cpp +++ b/src/SetupModel.cpp @@ -717,7 +717,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den Mcells = (Microcell*)Memory::xcalloc(P.NMC, sizeof(Microcell)); mcell_num = (int*)Memory::xcalloc(P.NMC, sizeof(int)); mcell_dens = (double*)Memory::xcalloc(P.NMC, sizeof(double)); - mcell_country.reserve(P.NMC); + mcell_country = std::vector(P.NMC, 0); mcell_adunits = (int*)Memory::xcalloc(P.NMC, sizeof(int)); for (j = 0; j < P.NMC; j++) @@ -725,7 +725,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den Mcells[j].n = 0; mcell_adunits[j] = -1; mcell_dens[j] = 0; - mcell_num[j] = mcell_country[j] = 0; + mcell_num[j] = 0; } if (P.DoAdUnits) for (int i = 0; i < MAX_ADUNITS; i++) From bf874547aae2f66fc93d2bedf3ff1a843971fd8d Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Tue, 16 Jun 2020 13:54:53 -0400 Subject: [PATCH 07/13] 4% reduction in run time for regressiontest_US_based.py by specifying const values or const references for data in the main loop of AssignPeopleToPlaces(); because of the size of the loop, calls to other functions, and the lack of specificity that most of the arguments are const, it helps a lot to tell the compiler that many of the data accesses in the loop will not cause a side effect (even though we know they don't); this commit also makes the main loop look more readable --- src/SetupModel.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/SetupModel.cpp b/src/SetupModel.cpp index 35e5de834..93771e4b3 100644 --- a/src/SetupModel.cpp +++ b/src/SetupModel.cpp @@ -2121,7 +2121,7 @@ void AssignPeopleToPlaces() Direction m2 = Right; if (Hosts[i].PlaceLinks[tp] < 0) //added this so that if any hosts have already be assigned due to their household membership, they will not be reassigned { - const uint16_t host_country = Mcells[Hosts[i].mcell].country; + auto const host_country = Mcells[Hosts[i].mcell].country; while (((k < nn) || (l < 4)) && (l < P.total_microcells_wide_)) { if (P.is_in_bounds(mc_position)) @@ -2129,18 +2129,22 @@ void AssignPeopleToPlaces() ic = P.get_micro_cell_index_from_position(mc_position); if (mcell_country[ic] == host_country) { - for (cnt = 0; cnt < Mcells[ic].np[tp]; cnt++) + auto const& cur_cell = Mcells[ic]; + auto const place_type_count = cur_cell.np[tp]; + for (cnt = 0; cnt < place_type_count; cnt++) { - if (Mcells[ic].places[tp][cnt] >= P.Nplace[tp]) fprintf(stderr, "#%i %i %i ", tp, ic, cnt); + auto const place_idx = cur_cell.places[tp][cnt]; + if (place_idx >= P.Nplace[tp]) fprintf(stderr, "#%i %i %i ", tp, ic, cnt); + auto const& cur_place = Places[tp][place_idx]; t = dist2_raw(Households[Hosts[i].hh].loc.x, Households[Hosts[i].hh].loc.y, - Places[tp][Mcells[ic].places[tp][cnt]].loc.x, Places[tp][Mcells[ic].places[tp][cnt]].loc.y); + cur_place.loc.x, cur_place.loc.y); s = P.KernelLookup.num(t); if (tp < P.nsp) { - t = ((double)Places[tp][Mcells[ic].places[tp][cnt]].treat_end_time); + t = ((double)cur_place.treat_end_time); if (HOST_AGE_YEAR(i) < P.PlaceTypeMaxAgeRead[tp]) { - if ((t > 0) && (Places[tp][Mcells[ic].places[tp][cnt]].AvailByAge[HOST_AGE_YEAR(i)] > 0)) + if ((t > 0) && (cur_place.AvailByAge[HOST_AGE_YEAR(i)] > 0)) s *= t; else s = 0; @@ -2155,7 +2159,7 @@ void AssignPeopleToPlaces() { if (k < nn) { - NearestPlaces[tn][k] = Mcells[ic].places[tp][cnt]; + NearestPlaces[tn][k] = place_idx; NearestPlacesProb[tn][k] = s; k++; } @@ -2171,7 +2175,7 @@ void AssignPeopleToPlaces() if (s > t) { NearestPlacesProb[tn][j2] = s; - NearestPlaces[tn][j2] = Mcells[ic].places[tp][cnt]; + NearestPlaces[tn][j2] = place_idx; } } } From 780a65c5e1f765f5ea650f9440faf92b369acff6 Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Tue, 16 Jun 2020 21:06:07 -0400 Subject: [PATCH 08/13] 4% reduction in run time for regressiontest_US_based.py by removing the unsigned short country field in Microcell struct and replacing all references to use the new mcell_country vector; this likely increased SIMD/SIMT performance with Microcells and all increased performance with microcell country comparisons --- src/Bitmap.cpp | 8 ++++---- src/CovidSim.cpp | 2 +- src/Models/Microcell.h | 1 - src/SetupModel.cpp | 9 ++++----- src/Update.cpp | 2 +- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Bitmap.cpp b/src/Bitmap.cpp index 2238f0dd9..3d776a32b 100644 --- a/src/Bitmap.cpp +++ b/src/Bitmap.cpp @@ -61,12 +61,12 @@ void CaptureBitmap() if (Mcells[i].n > 0) { f = 0; - if ((i < P.NMC - 1) && (i / P.total_microcells_high_ == (i + 1) / P.total_microcells_high_) && (Mcells[i + 1].n > 0) && ((Mcells[i].country != Mcells[i + 1].country) + if ((i < P.NMC - 1) && (i / P.total_microcells_high_ == (i + 1) / P.total_microcells_high_) && (Mcells[i + 1].n > 0) && ((mcell_country[i] != mcell_country[i + 1]) || ((P.DoAdunitBoundaryOutput) && ((AdUnits[Mcells[i].adunit].id % P.AdunitLevel1Mask) / P.AdunitBitmapDivisor != (AdUnits[Mcells[i + 1].adunit].id % P.AdunitLevel1Mask) / P.AdunitBitmapDivisor)))) f = 1; - if ((i > 0) && (i / P.total_microcells_high_ == (i - 1) / P.total_microcells_high_) && (Mcells[i - 1].n > 0) && (Mcells[i].country != Mcells[i - 1].country)) f = 1; - if ((i < P.NMC - P.total_microcells_high_) && (Mcells[i + P.total_microcells_high_].n > 0) && ((Mcells[i].country != Mcells[i + P.total_microcells_high_].country) + if ((i > 0) && (i / P.total_microcells_high_ == (i - 1) / P.total_microcells_high_) && (Mcells[i - 1].n > 0) && (mcell_country[i] != mcell_country[i - 1])) f = 1; + if ((i < P.NMC - P.total_microcells_high_) && (Mcells[i + P.total_microcells_high_].n > 0) && ((mcell_country[i] != mcell_country[i + P.total_microcells_high_]) || ((P.DoAdunitBoundaryOutput) && ((AdUnits[Mcells[i].adunit].id % P.AdunitLevel1Mask) / P.AdunitBitmapDivisor != (AdUnits[Mcells[i + P.total_microcells_high_].adunit].id % P.AdunitLevel1Mask) / P.AdunitBitmapDivisor)))) f = 1; - if ((i >= P.total_microcells_high_) && (Mcells[i - P.total_microcells_high_].n > 0) && (Mcells[i].country != Mcells[i - P.total_microcells_high_].country)) f = 1; + if ((i >= P.total_microcells_high_) && (Mcells[i - P.total_microcells_high_].n > 0) && (mcell_country[i] != mcell_country[i - P.total_microcells_high_])) f = 1; if (f) { x = (int)(P.in_microcells_.width * (((double)(i / P.total_microcells_high_)) + 0.5) * P.scale.x) - P.bmin.x; diff --git a/src/CovidSim.cpp b/src/CovidSim.cpp index 5af1c012b..56e299d6c 100644 --- a/src/CovidSim.cpp +++ b/src/CovidSim.cpp @@ -5180,7 +5180,7 @@ void RecordInfTypes(void) { if (Hosts[i].latent_time * P.TimeStep <= P.SampleTime) TimeSeries[(int)(Hosts[i].latent_time * P.TimeStep / P.SampleStep)].Rdenom++; - infcountry[Mcells[Hosts[i].mcell].country]++; + infcountry[mcell_country[Hosts[i].mcell]]++; if (abs(Hosts[i].inf) < InfStat_Recovered) l = -1; else if (l >= 0) diff --git a/src/Models/Microcell.h b/src/Models/Microcell.h index bf0614b80..175f73c4a 100644 --- a/src/Models/Microcell.h +++ b/src/Models/Microcell.h @@ -16,7 +16,6 @@ struct Microcell */ int n /*Number of people in microcell*/, adunit; int* members; - unsigned short int country; int* places[NUM_PLACE_TYPES]; unsigned short int np[NUM_PLACE_TYPES]; diff --git a/src/SetupModel.cpp b/src/SetupModel.cpp index 93771e4b3..4a8715a50 100644 --- a/src/SetupModel.cpp +++ b/src/SetupModel.cpp @@ -854,7 +854,6 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den if (mcell_num[i] > 0) { mcell_dens[i] /= ((double)mcell_num[i]); - Mcells[i].country = (unsigned short)mcell_country[i]; if (P.DoAdUnits) Mcells[i].adunit = mcell_adunits[i]; else @@ -870,8 +869,8 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den for (int i = 0; i < P.NMC; i++) { mcell_dens[i] = 1.0; - Mcells[i].country = 1; } + std::fill_n(&mcell_country[0], P.NMC, 1); maxd = ((double)P.NMC); } if (!P.DoAdUnits) P.NumAdunits = 1; @@ -1384,7 +1383,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den FILE* stderr_shared = stderr; #pragma omp parallel for private(j2,j,t,m,s,x,y,xh,yh) schedule(static,1) default(none) \ - shared(P, Hosts, Places, PropPlaces, Mcells, maxd, last_i, stderr_shared) + shared(P, Hosts, Places, PropPlaces, Mcells, maxd, last_i, mcell_country, stderr_shared) for (int tn = 0; tn < P.NumThreads; tn++) for (j2 = P.nsp + tn; j2 < P.PlaceTypeNum; j2 += P.NumThreads) { @@ -1419,7 +1418,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den Places[j2][k].loc.y = (float)yh; Places[j2][k].n = 0; Places[j2][k].mcell = i; - Places[j2][k].country = Mcells[i].country; + Places[j2][k].country = mcell_country[i]; Mcells[i].places[j2][j] = k; k++; } @@ -2121,7 +2120,7 @@ void AssignPeopleToPlaces() Direction m2 = Right; if (Hosts[i].PlaceLinks[tp] < 0) //added this so that if any hosts have already be assigned due to their household membership, they will not be reassigned { - auto const host_country = Mcells[Hosts[i].mcell].country; + auto const host_country = mcell_country[Hosts[i].mcell]; while (((k < nn) || (l < 4)) && (l < P.total_microcells_wide_)) { if (P.is_in_bounds(mc_position)) diff --git a/src/Update.cpp b/src/Update.cpp index 16c47de51..6e3d85d8a 100644 --- a/src/Update.cpp +++ b/src/Update.cpp @@ -847,7 +847,7 @@ void DoCase(int ai, double t, unsigned short int ts, int tn) //// makes an infec if (HOST_TREATED(ai)) Cells[Hosts[ai].pcell].cumTC++; StateT[tn].cumC++; StateT[tn].cumCa[age]++; - StateT[tn].cumC_country[Mcells[Hosts[ai].mcell].country]++; //add to cumulative count of cases in that country: ggilani - 12/11/14 + StateT[tn].cumC_country[mcell_country[Hosts[ai].mcell]]++; //add to cumulative count of cases in that country: ggilani - 12/11/14 StateT[tn].cumC_keyworker[a->keyworker]++; From 8f79c578073d9df48d46f036482a2464faafb03e Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Wed, 17 Jun 2020 09:31:28 -0400 Subject: [PATCH 09/13] significant runtime improvement in RecordQuarNotInfected() (~10% reduction in regressiontest_US_based.py) by moving the 'quar_comply' and 'quar_start_time' fields out from 'struct Person' into a new 'struct PersonQuarantine'; this change provides much better CPU caching behavior --- src/CovidSim.cpp | 4 ++-- src/Model.h | 1 + src/ModelMacros.h | 4 ++-- src/Models/Person.h | 14 ++++++++++++-- src/SetupModel.cpp | 2 ++ src/Update.cpp | 8 ++++---- 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/CovidSim.cpp b/src/CovidSim.cpp index 56e299d6c..5fa854c77 100644 --- a/src/CovidSim.cpp +++ b/src/CovidSim.cpp @@ -78,6 +78,7 @@ int GetInputParameter3(FILE*, const char*, const char*, void*, int, int, int); Param P; Person* Hosts; +std::vector HostsQuarantine; Household* Households; PopVar State, StateT[MAX_NUM_THREADS]; Cell* Cells; // Cells[i] is the i'th cell @@ -2481,9 +2482,8 @@ void InitModel(int run) // passing run number so we can save run number in the i Hosts[k].absent_start_time = USHRT_MAX - 1; Hosts[k].absent_stop_time = 0; if (P.DoAirports) Hosts[k].PlaceLinks[P.HotelPlaceType] = -1; - Hosts[k].vacc_start_time = Hosts[k].treat_start_time = Hosts[k].quar_start_time = Hosts[k].isolation_start_time = Hosts[k].absent_start_time = Hosts[k].dct_start_time = Hosts[k].dct_trigger_time = USHRT_MAX - 1; + Hosts[k].vacc_start_time = Hosts[k].treat_start_time = Hosts[k].isolation_start_time = Hosts[k].absent_start_time = Hosts[k].dct_start_time = Hosts[k].dct_trigger_time = USHRT_MAX - 1; Hosts[k].treat_stop_time = Hosts[k].absent_stop_time = Hosts[k].dct_end_time = 0; - Hosts[k].quar_comply = 2; Hosts[k].to_die = 0; Hosts[k].Travelling = 0; Hosts[k].detected = 0; //set detected to zero initially: ggilani - 19/02/15 diff --git a/src/Model.h b/src/Model.h index 1270a32c4..9ba3cf4de 100644 --- a/src/Model.h +++ b/src/Model.h @@ -293,6 +293,7 @@ struct AdminUnit #pragma pack(pop) extern Person* Hosts; +extern std::vector HostsQuarantine; extern Household* Households; extern PopVar State, StateT[MAX_NUM_THREADS]; extern Cell* Cells, ** CellLookup; diff --git a/src/ModelMacros.h b/src/ModelMacros.h index 19f446607..58c46b2a1 100644 --- a/src/ModelMacros.h +++ b/src/ModelMacros.h @@ -10,8 +10,8 @@ #define HOST_TO_BE_VACCED(x) (Hosts[x].vacc_start_time < USHRT_MAX - 1) #define HOST_VACCED(x) (Hosts[x].vacc_start_time+P.usVaccTimeToEfficacy<=ts) #define HOST_VACCED_SWITCH(x) (Hosts[x].vacc_start_time >= P.usVaccTimeEfficacySwitch) -#define HOST_QUARANTINED(x) ((Hosts[x].quar_comply == 1) && (Hosts[x].quar_start_time + P.usHQuarantineHouseDuration > ts) && (Hosts[x].quar_start_time <= ts)) -#define HOST_TO_BE_QUARANTINED(x) ((Hosts[x].quar_start_time + P.usHQuarantineHouseDuration > ts) && (Hosts[x].quar_comply < 2)) +#define HOST_QUARANTINED(x) ((HostsQuarantine[x].comply == 1) && (HostsQuarantine[x].start_time + P.usHQuarantineHouseDuration > ts) && (HostsQuarantine[x].start_time <= ts)) +#define HOST_TO_BE_QUARANTINED(x) ((HostsQuarantine[x].start_time + P.usHQuarantineHouseDuration > ts) && (HostsQuarantine[x].comply < 2)) #define HOST_ISOLATED(x) ((Hosts[x].isolation_start_time + P.usCaseIsolationDelay <= ts) && (Hosts[x].isolation_start_time + P.usCaseIsolationDelay + P.usCaseIsolationDuration > ts)) #define HOST_ABSENT(x) ((Hosts[x].absent_start_time <= ts) && (Hosts[x].absent_stop_time > ts)) diff --git a/src/Models/Person.h b/src/Models/Person.h index d7f8f3725..707933377 100644 --- a/src/Models/Person.h +++ b/src/Models/Person.h @@ -1,5 +1,8 @@ #pragma once +#include +#include + #include "../Country.h" #include "../InfStat.h" @@ -21,7 +24,6 @@ struct Person unsigned char Travelling; // Range up to MAX_TRAVEL_TIME unsigned char age; - unsigned char quar_comply; // can be 0, 1, or 2 unsigned char num_treats; // set to 0 and tested < 2. but never modified? Severity Severity_Current, Severity_Final; //// Note we allow Severity_Final to take values: Severity_Mild, Severity_ILI, Severity_SARI, Severity_Critical (not e.g. Severity_Dead or Severity_RecoveringFromCritical) @@ -31,7 +33,7 @@ struct Person unsigned short int detected_time; //added hospitalisation flag: ggilani 28/10/2014, added flag to determined whether this person's infection is detected or not unsigned short int absent_start_time, absent_stop_time; - unsigned short int quar_start_time, isolation_start_time; + unsigned short int isolation_start_time; unsigned short int infection_time, latent_time; // Set in DoInfect function. infection time is time of infection; latent_time is a misnomer - it is the time at which person become infectious (i.e. infection time + latent period for this person). latent_time will also refer to time of onset with ILI or Mild symptomatic disease. unsigned short int recovery_or_death_time; // set in DoIncub function unsigned short int SARI_time, Critical_time, RecoveringFromCritical_time; //// /*mild_time, ILI_time,*/ Time of infectiousness onset same for asymptomatic, Mild, and ILI infection so don't need mild_time etc. @@ -43,3 +45,11 @@ struct Person int ncontacts; //added this in to record total number of contacts each index case records: ggilani 13/04/20 }; + +struct PersonQuarantine +{ + uint8_t comply; // can be 0, 1, 2 + uint16_t start_time; // timestep quarantine is started + + PersonQuarantine() : comply(2), start_time(std::numeric_limits::max()-1) {} +}; \ No newline at end of file diff --git a/src/SetupModel.cpp b/src/SetupModel.cpp index 4a8715a50..9238e9443 100644 --- a/src/SetupModel.cpp +++ b/src/SetupModel.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "BinIO.h" #include "Error.h" @@ -1065,6 +1066,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den i2 = 0; Hosts = (Person*)Memory::xcalloc(P.PopSize, sizeof(Person)); + HostsQuarantine = std::vector(P.PopSize); fprintf(stderr, "sizeof(Person)=%i\n", (int) sizeof(Person)); for (int i = 0; i < P.NCP; i++) { diff --git a/src/Update.cpp b/src/Update.cpp index 6e3d85d8a..de9a3830a 100644 --- a/src/Update.cpp +++ b/src/Update.cpp @@ -604,16 +604,16 @@ void DoDetectedCase(int ai, double t, unsigned short int ts, int tn) j1 = Households[Hosts[ai].hh].FirstPerson; j2 = j1 + Households[Hosts[ai].hh].nh; if ((!HOST_TO_BE_QUARANTINED(j1)) || (P.DoHQretrigger)) { - Hosts[j1].quar_start_time = ts + ((unsigned short int) (P.TimeStepsPerDay * P.HQuarantineDelay)); + HostsQuarantine[j1].start_time = ts + ((unsigned short int) (P.TimeStepsPerDay * P.HQuarantineDelay)); k = (ranf_mt(tn) < P.HQuarantinePropHouseCompliant) ? 1 : 0; //// Is household compliant? True or false if (k) StateT[tn].cumHQ++; //// if compliant, increment cumulative numbers of households under quarantine. //// if household not compliant then neither is first person. Otheswise ask whether first person is compliant? ///// cycle through remaining household members and repeat the above steps for (j = j1; j < j2; j++) { - if(j>j1) Hosts[j].quar_start_time = Hosts[j1].quar_start_time; - Hosts[j].quar_comply = ((k == 0) ? 0 : ((ranf_mt(tn) < P.HQuarantinePropIndivCompliant) ? 1 : 0)); - if ((Hosts[j].quar_comply) && (!HOST_ABSENT(j))) + if(j>j1) HostsQuarantine[j].start_time = HostsQuarantine[j1].start_time; + HostsQuarantine[j].comply = ((k == 0) ? 0 : ((ranf_mt(tn) < P.HQuarantinePropIndivCompliant) ? 1 : 0)); + if ((HostsQuarantine[j].comply) && (!HOST_ABSENT(j))) { if (HOST_AGE_YEAR(j) >= P.CaseAbsentChildAgeCutoff) { From 1e8faba8acc6edbf6105a7cd8f22eba945f82014 Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Wed, 17 Jun 2020 11:09:47 -0400 Subject: [PATCH 10/13] moved mcell_country initialization value to the vector constructor call to not duplicate twice --- src/SetupModel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/SetupModel.cpp b/src/SetupModel.cpp index 9238e9443..e5f94ab65 100644 --- a/src/SetupModel.cpp +++ b/src/SetupModel.cpp @@ -718,7 +718,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den Mcells = (Microcell*)Memory::xcalloc(P.NMC, sizeof(Microcell)); mcell_num = (int*)Memory::xcalloc(P.NMC, sizeof(int)); mcell_dens = (double*)Memory::xcalloc(P.NMC, sizeof(double)); - mcell_country = std::vector(P.NMC, 0); + mcell_country = std::vector(P.NMC, 1); mcell_adunits = (int*)Memory::xcalloc(P.NMC, sizeof(int)); for (j = 0; j < P.NMC; j++) @@ -871,7 +871,6 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den { mcell_dens[i] = 1.0; } - std::fill_n(&mcell_country[0], P.NMC, 1); maxd = ((double)P.NMC); } if (!P.DoAdUnits) P.NumAdunits = 1; From 0658858df8a6fd238fbd5f29382a75707313aaa3 Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Thu, 18 Jun 2020 11:32:04 -0400 Subject: [PATCH 11/13] fixed MSVC build error --- src/Models/Person.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Models/Person.h b/src/Models/Person.h index 707933377..ccc964f50 100644 --- a/src/Models/Person.h +++ b/src/Models/Person.h @@ -51,5 +51,7 @@ struct PersonQuarantine uint8_t comply; // can be 0, 1, 2 uint16_t start_time; // timestep quarantine is started - PersonQuarantine() : comply(2), start_time(std::numeric_limits::max()-1) {} -}; \ No newline at end of file + // don't remove the extra parentheses around std::numeric_limits::max + // because it conflicts with the max() preprocessor macro in MSVC builds + PersonQuarantine() : comply(2), start_time((std::numeric_limits::max)()-1) {} +}; From 7124e8cd79c87d532500c7a60c6164e6d9cd8cec Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Thu, 18 Jun 2020 13:57:54 -0400 Subject: [PATCH 12/13] replaced exception throw with ERR_CRITICAL in MicroCellPosition.hpp --- src/MicroCellPosition.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/MicroCellPosition.hpp b/src/MicroCellPosition.hpp index 28d1b7230..775262015 100644 --- a/src/MicroCellPosition.hpp +++ b/src/MicroCellPosition.hpp @@ -1,8 +1,7 @@ #pragma once -#include - #include "Direction.hpp" +#include "Error.h" struct MicroCellPosition { @@ -16,7 +15,7 @@ struct MicroCellPosition case Up: this->y -= 1; break; case Left: this->x -= 1; break; case Down: this->y += 1; break; - default: throw std::out_of_range("direction"); + default: ERR_CRITICAL("Unknown direction"); } return *this; } From e8f7864ad150f4002279cff6cf8673208b5cd387 Mon Sep 17 00:00:00 2001 From: Ozmorph Date: Thu, 18 Jun 2020 13:58:45 -0400 Subject: [PATCH 13/13] added re-initialization of HostsQuarantine back into InitModel() which fixes regression tests --- src/CovidSim.cpp | 2 +- src/SetupModel.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CovidSim.cpp b/src/CovidSim.cpp index 5fa854c77..f97122997 100644 --- a/src/CovidSim.cpp +++ b/src/CovidSim.cpp @@ -2473,7 +2473,7 @@ void InitModel(int run) // passing run number so we can save run number in the i StateT[Thread].cumInf_age_adunit [AgeGroup][Adunit] = 0; } - + std::fill(HostsQuarantine.begin(), HostsQuarantine.end(), PersonQuarantine()); #pragma omp parallel for schedule(static,1) default(none) \ shared(P, Hosts) for (int tn = 0; tn < P.NumThreads; tn++) diff --git a/src/SetupModel.cpp b/src/SetupModel.cpp index e5f94ab65..269d3ef35 100644 --- a/src/SetupModel.cpp +++ b/src/SetupModel.cpp @@ -1065,7 +1065,7 @@ void SetupPopulation(std::string const& density_file, std::string const& out_den i2 = 0; Hosts = (Person*)Memory::xcalloc(P.PopSize, sizeof(Person)); - HostsQuarantine = std::vector(P.PopSize); + HostsQuarantine = std::vector(P.PopSize, PersonQuarantine()); fprintf(stderr, "sizeof(Person)=%i\n", (int) sizeof(Person)); for (int i = 0; i < P.NCP; i++) {