Skip to content

Commit 0b2f3e6

Browse files
authored
Add option to move percentage of exposed/infected hosts to susceptibles (#175)
Similarly to lethal temperature and mortality. Removes certain percentage of exposed/infected host and makes them susceptible. The scheduling is done in the same way as lethal temperature, so it is scheduled yearly on the first of certain month. Refactors relevant common code from mortality. Closes #173.
1 parent 88c808d commit 0b2f3e6

File tree

9 files changed

+283
-29
lines changed

9 files changed

+283
-29
lines changed

include/pops/config.hpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ class Config
5454
int lethal_temperature_month{0};
5555
bool weather{false};
5656
double reproductive_rate{0};
57+
// survival rate
58+
bool use_survival_rate{false};
59+
int survival_rate_month{0};
60+
int survival_rate_day{0};
5761
// SI/SEI
5862
std::string model_type;
5963
int latency_period_steps;
@@ -110,6 +114,9 @@ class Config
110114
if (use_lethal_temperature)
111115
lethal_schedule_ =
112116
scheduler_.schedule_action_yearly(lethal_temperature_month, 1);
117+
if (use_survival_rate)
118+
survival_rate_schedule_ = scheduler_.schedule_action_yearly(
119+
survival_rate_month, survival_rate_day);
113120
if (use_spreadrates)
114121
spread_rate_schedule_ = schedule_from_string(
115122
scheduler_, spreadrate_frequency, spreadrate_frequency_n);
@@ -154,6 +161,17 @@ class Config
154161
return lethal_schedule_;
155162
}
156163

164+
const std::vector<bool>& survival_rate_schedule() const
165+
{
166+
if (!use_survival_rate)
167+
throw std::logic_error(
168+
"survival_rate_schedule() not available when use_survival_rate is false");
169+
if (!schedules_created_)
170+
throw std::logic_error(
171+
"Schedules were not created before calling survival_rate_schedule()");
172+
return survival_rate_schedule_;
173+
}
174+
157175
const std::vector<bool>& spread_rate_schedule() const
158176
{
159177
if (!use_spreadrates)
@@ -203,6 +221,17 @@ class Config
203221
return get_number_of_scheduled_actions(lethal_schedule_);
204222
}
205223

224+
unsigned num_survival_rate()
225+
{
226+
if (!use_survival_rate)
227+
throw std::logic_error(
228+
"num_survival_rate() not available when use_survival_rate is false");
229+
if (!schedules_created_)
230+
throw std::logic_error(
231+
"Schedules were not created before calling num_survival_rate()");
232+
return get_number_of_scheduled_actions(survival_rate_schedule_);
233+
}
234+
206235
unsigned rate_num_steps()
207236
{
208237
if (!use_spreadrates)
@@ -302,6 +331,7 @@ class Config
302331
std::vector<bool> output_schedule_;
303332
std::vector<bool> mortality_schedule_;
304333
std::vector<bool> lethal_schedule_;
334+
std::vector<bool> survival_rate_schedule_;
305335
std::vector<bool> spread_rate_schedule_;
306336
std::vector<bool> quarantine_schedule_;
307337
};

include/pops/model.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ class Model
189189
std::vector<IntegerRaster>& mortality_tracker,
190190
IntegerRaster& died,
191191
const std::vector<FloatRaster>& temperatures,
192+
const std::vector<FloatRaster>& survival_rates,
192193
const FloatRaster& weather_coefficient,
193194
Treatments<IntegerRaster, FloatRaster>& treatments,
194195
IntegerRaster& resistant,
@@ -212,6 +213,19 @@ class Model
212213
config_.lethal_temperature,
213214
suitable_cells);
214215
}
216+
// removal of percentage of dispersers
217+
if (config_.use_survival_rate && config_.survival_rate_schedule()[step]) {
218+
int survival_step =
219+
simulation_step_to_action_step(config_.survival_rate_schedule(), step);
220+
simulation_.remove_percentage(
221+
infected,
222+
susceptible,
223+
mortality_tracker,
224+
exposed,
225+
total_exposed,
226+
survival_rates[survival_step],
227+
suitable_cells);
228+
}
215229
// actual spread
216230
if (config_.spread_schedule()[step]) {
217231
simulation_.generate(

include/pops/simulation.hpp

Lines changed: 98 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,31 @@ std::vector<int> draw_n_from_v(std::vector<int> v, unsigned n, Generator& genera
5555
return v;
5656
}
5757

58+
/** Draws n elements from a cohort of rasters. Expects n to be equal or less than
59+
* sum of cohorts at cell (i, j).
60+
*/
61+
template<typename Generator, typename IntegerRaster, typename RasterIndex = int>
62+
std::vector<int> draw_n_from_cohorts(
63+
std::vector<IntegerRaster>& cohorts,
64+
int n,
65+
RasterIndex row,
66+
RasterIndex col,
67+
Generator& generator)
68+
{
69+
std::vector<int> categories;
70+
unsigned index = 0;
71+
for (auto& raster : cohorts) {
72+
categories.insert(categories.end(), raster(row, col), index);
73+
index += 1;
74+
}
75+
std::vector<int> draw = draw_n_from_v(categories, n, generator);
76+
std::vector<int> cohort_counts;
77+
for (index = 0; index < cohorts.size(); index++) {
78+
cohort_counts.push_back(std::count(draw.begin(), draw.end(), index));
79+
}
80+
return cohort_counts;
81+
}
82+
5883
/** The type of a epidemiological model (SI or SEI)
5984
*/
6085
enum class ModelType
@@ -207,6 +232,67 @@ class Simulation
207232
}
208233
}
209234

235+
/** Removes percentage of exposed and infected
236+
*
237+
* @param infected Currently infected hosts
238+
* @param susceptible Currently susceptible hosts
239+
* @param mortality_tracker_vector Hosts that are infected at a specific time step
240+
* @param exposed Exposed hosts per cohort
241+
* @param total_exposed Total exposed in all exposed cohorts
242+
* @param survival_rate Raster between 0 and 1 representing pest survival rate
243+
* @param suitable_cells used to run model only where host are known to occur
244+
*/
245+
void remove_percentage(
246+
IntegerRaster& infected,
247+
IntegerRaster& susceptible,
248+
std::vector<IntegerRaster>& mortality_tracker_vector,
249+
std::vector<IntegerRaster>& exposed,
250+
IntegerRaster& total_exposed,
251+
const FloatRaster& survival_rate,
252+
const std::vector<std::vector<int>>& suitable_cells)
253+
{
254+
for (auto indices : suitable_cells) {
255+
int i = indices[0];
256+
int j = indices[1];
257+
if (survival_rate(i, j) < 1) {
258+
int removed = 0;
259+
// remove percentage of infestation/infection in the infected class
260+
int removed_infected =
261+
infected(i, j) - std::lround(infected(i, j) * survival_rate(i, j));
262+
infected(i, j) -= removed_infected;
263+
removed += removed_infected;
264+
// remove the removed infected from mortality cohorts
265+
if (removed_infected > 0) {
266+
std::vector<int> mortality_draw = draw_n_from_cohorts(
267+
mortality_tracker_vector, removed_infected, i, j, generator_);
268+
int index = 0;
269+
for (auto& raster : mortality_tracker_vector) {
270+
raster(i, j) -= mortality_draw[index];
271+
index += 1;
272+
}
273+
}
274+
// remove the same percentage for total exposed and remove randomly from
275+
// each cohort
276+
int total_removed_exposed =
277+
total_exposed(i, j)
278+
- std::lround(total_exposed(i, j) * survival_rate(i, j));
279+
total_exposed(i, j) -= total_removed_exposed;
280+
removed += total_removed_exposed;
281+
if (total_removed_exposed > 0) {
282+
std::vector<int> exposed_draw = draw_n_from_cohorts(
283+
exposed, total_removed_exposed, i, j, generator_);
284+
int index = 0;
285+
for (auto& raster : exposed) {
286+
raster(i, j) -= exposed_draw[index];
287+
index += 1;
288+
}
289+
}
290+
// move infested/infected host back to susceptible pool
291+
susceptible(i, j) += removed;
292+
}
293+
}
294+
}
295+
210296
/** kills infected hosts based on mortality rate and timing. In the last year
211297
* of mortality tracking the first index all remaining tracked infected hosts
212298
* are removed. In indexes that are in the mortality_time_lag no mortality occurs.
@@ -347,43 +433,26 @@ class Simulation
347433
resistant_moved = std::count(draw.begin(), draw.end(), 4);
348434

349435
if (exposed_moved > 0) {
436+
std::vector<int> exposed_draw = draw_n_from_cohorts(
437+
exposed, exposed_moved, row_from, col_from, generator_);
350438
int index = 0;
351439
for (auto& raster : exposed) {
352-
auto exposed_count = raster(row_from, col_from);
353-
exposed_categories.insert(
354-
exposed_categories.end(), exposed_count, index);
355-
356-
index += 1;
357-
}
358-
std::vector<int> exposed_draw =
359-
draw_n_from_v(exposed_categories, exposed_moved, generator_);
360-
index = 0;
361-
for (auto& raster : exposed) {
362-
auto exposed_moved_in_cohort =
363-
std::count(exposed_draw.begin(), exposed_draw.end(), index);
364-
raster(row_from, col_from) -= exposed_moved_in_cohort;
365-
raster(row_to, col_to) += exposed_moved_in_cohort;
440+
raster(row_from, col_from) -= exposed_draw[index];
441+
raster(row_to, col_to) += exposed_draw[index];
366442
index += 1;
367443
}
368444
}
369-
370445
if (infected_moved > 0) {
371-
std::vector<int> mortality_categories;
446+
std::vector<int> mortality_draw = draw_n_from_cohorts(
447+
mortality_tracker_vector,
448+
infected_moved,
449+
row_from,
450+
col_from,
451+
generator_);
372452
int index = 0;
373453
for (auto& raster : mortality_tracker_vector) {
374-
auto mortality_count = raster(row_from, col_from);
375-
mortality_categories.insert(
376-
mortality_categories.end(), mortality_count, index);
377-
index += 1;
378-
}
379-
std::vector<int> mortality_draw =
380-
draw_n_from_v(mortality_categories, infected_moved, generator_);
381-
index = 0;
382-
for (auto& raster : mortality_tracker_vector) {
383-
auto mortality_moved_in_cohort =
384-
std::count(mortality_draw.begin(), mortality_draw.end(), index);
385-
raster(row_from, col_from) -= mortality_moved_in_cohort;
386-
raster(row_to, col_to) += mortality_moved_in_cohort;
454+
raster(row_from, col_from) -= mortality_draw[index];
455+
raster(row_to, col_to) += mortality_draw[index];
387456
index += 1;
388457
}
389458
}

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ add_pops_test(test_deterministic)
2323
add_pops_test(test_model)
2424
add_pops_test(test_mortality)
2525
add_pops_test(test_movements)
26+
add_pops_test(test_survival_rate)
2627
add_pops_test(test_raster)
2728
add_pops_test(test_scheduling)
2829
add_pops_test(test_simulation)

tests/test_model.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ int test_with_reduced_stochasticity()
5959
config.model_type = "SI";
6060
config.latency_period_steps = 0;
6161
config.use_lethal_temperature = false;
62+
config.use_survival_rate = false;
6263
config.use_quarantine = true;
6364
config.quarantine_frequency = "year";
6465
config.quarantine_frequency_n = 1;
@@ -125,6 +126,7 @@ int test_with_reduced_stochasticity()
125126
mortality_tracker,
126127
died,
127128
empty_float,
129+
empty_float,
128130
empty_float[0],
129131
treatments,
130132
zeros,
@@ -212,6 +214,7 @@ int test_deterministic()
212214
config.model_type = "SI";
213215
config.latency_period_steps = 0;
214216
config.use_lethal_temperature = false;
217+
config.use_survival_rate = false;
215218
config.use_quarantine = false;
216219
config.use_spreadrates = true;
217220
config.spreadrate_frequency = "year";
@@ -265,6 +268,7 @@ int test_deterministic()
265268
mortality_tracker,
266269
died,
267270
empty_float,
271+
empty_float,
268272
empty_float[0],
269273
treatments,
270274
zeros,
@@ -351,6 +355,7 @@ int test_deterministic_exponential()
351355
config.model_type = "SI";
352356
config.latency_period_steps = 0;
353357
config.use_lethal_temperature = false;
358+
config.use_survival_rate = false;
354359
config.use_quarantine = false;
355360
config.use_spreadrates = true;
356361
config.spreadrate_frequency = "year";
@@ -405,6 +410,7 @@ int test_deterministic_exponential()
405410
mortality_tracker,
406411
died,
407412
empty_float,
413+
empty_float,
408414
empty_float[0],
409415
treatments,
410416
zeros,
@@ -487,6 +493,7 @@ int test_model_sei_deterministic()
487493
config.model_type = "SEI";
488494
config.latency_period_steps = 11;
489495
config.use_lethal_temperature = false;
496+
config.use_survival_rate = false;
490497
config.use_quarantine = false;
491498
config.use_spreadrates = true;
492499
config.spreadrate_frequency = "year";
@@ -550,6 +557,7 @@ int test_model_sei_deterministic()
550557
mortality_tracker,
551558
died,
552559
empty_float,
560+
empty_float,
553561
empty_float[0],
554562
treatments,
555563
zeros,
@@ -627,6 +635,7 @@ int test_model_sei_deterministic_with_treatments()
627635
config.model_type = "SEI";
628636
config.latency_period_steps = 11;
629637
config.use_lethal_temperature = false;
638+
config.use_survival_rate = false;
630639
config.use_quarantine = false;
631640
config.use_spreadrates = true;
632641
config.spreadrate_frequency = "year";
@@ -708,6 +717,7 @@ int test_model_sei_deterministic_with_treatments()
708717
mortality_tracker,
709718
died,
710719
empty_float,
720+
empty_float,
711721
empty_float[0],
712722
treatments,
713723
zeros,

tests/test_network_kernel.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ int test_model_with_network()
128128
empty_ints,
129129
zeros,
130130
empty_floats,
131+
empty_floats,
131132
empty_floats[0],
132133
treatments,
133134
zeros,

tests/test_overpopulation_movements.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ int test_model()
148148
empty_ints,
149149
zeros,
150150
empty_floats,
151+
empty_floats,
151152
empty_floats[0],
152153
treatments,
153154
zeros,

tests/test_simulation_kernels.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ int test_simulation_with_kernels_generic(
248248
config.model_type = "SI";
249249
config.latency_period_steps = 3;
250250
config.use_lethal_temperature = false;
251+
config.use_survival_rate = false;
251252
config.use_quarantine = false;
252253
config.use_spreadrates = true;
253254
config.spreadrate_frequency = "year";
@@ -355,6 +356,7 @@ int test_model_with_kernels_generic(
355356
config.model_type = "SI";
356357
config.latency_period_steps = 3;
357358
config.use_lethal_temperature = false;
359+
config.use_survival_rate = false;
358360
config.use_quarantine = false;
359361
config.use_spreadrates = true;
360362
config.spreadrate_frequency = "year";
@@ -432,6 +434,7 @@ int test_model_with_kernels_generic(
432434
mortality_tracker,
433435
died,
434436
empty_float,
437+
empty_float,
435438
empty_float[0],
436439
treatments,
437440
zeros,

0 commit comments

Comments
 (0)