19 #ifndef POPS_SIMULATION_HPP
20 #define POPS_SIMULATION_HPP
39 template<
typename Container>
42 std::rotate(container.begin(), container.begin() + 1, container.end());
47 template<
typename Generator>
48 std::vector<int>
draw_n_from_v(std::vector<int> v,
unsigned n, Generator& generator)
53 std::shuffle(v.begin(), v.end(), generator);
54 v.erase(v.begin() + n, v.end());
73 if (text ==
"SI" || text ==
"SusceptibleInfected" || text ==
"susceptible-infected"
74 || text ==
"susceptible_infected")
77 text ==
"SEI" || text ==
"SusceptibleExposedInfected"
78 || text ==
"susceptible-exposed-infected"
79 || text ==
"susceptible_exposed_infected")
82 throw std::invalid_argument(
83 "model_type_from_string: Invalid"
85 + text +
"' provided");
125 template<
typename IntegerRaster,
typename FloatRaster,
typename RasterIndex =
int>
131 bool dispersers_stochasticity_;
132 bool establishment_stochasticity_;
133 bool movement_stochasticity_;
135 unsigned latency_period_;
136 std::default_random_engine generator_;
158 unsigned random_seed,
162 unsigned latency_period = 0,
163 bool dispersers_stochasticity =
true,
164 bool establishment_stochasticity =
true,
165 bool movement_stochasticity =
true)
168 dispersers_stochasticity_(dispersers_stochasticity),
169 establishment_stochasticity_(establishment_stochasticity),
170 movement_stochasticity_(movement_stochasticity),
171 model_type_(model_type),
172 latency_period_(latency_period)
174 generator_.seed(random_seed);
188 IntegerRaster& infected,
189 IntegerRaster& susceptible,
190 const FloatRaster& temperature,
191 double lethal_temperature,
192 const std::vector<std::vector<int>>& suitable_cells)
194 for (
auto indices : suitable_cells) {
197 if (temperature(i, j) < lethal_temperature) {
199 susceptible(i, j) += infected(i, j);
224 IntegerRaster& infected,
225 IntegerRaster& total_hosts,
226 double mortality_rate,
227 int mortality_time_lag,
229 std::vector<IntegerRaster>& mortality_tracker_vector,
230 const std::vector<std::vector<int>>& suitable_cells)
233 int max_index = mortality_tracker_vector.size() - mortality_time_lag - 1;
235 for (
auto indices : suitable_cells) {
238 for (
int index = 0; index <= max_index; index++) {
239 int mortality_in_index = 0;
240 if (mortality_tracker_vector[index](i, j) > 0) {
244 mortality_in_index = mortality_tracker_vector[index](i, j);
248 mortality_rate * mortality_tracker_vector[index](i, j);
250 mortality_tracker_vector[index](i, j) -= mortality_in_index;
251 died(i, j) += mortality_in_index;
252 if (infected(i, j) > 0) {
253 infected(i, j) -= mortality_in_index;
255 if (total_hosts(i, j) > 0) {
256 total_hosts(i, j) -= mortality_in_index;
287 IntegerRaster& infected,
288 IntegerRaster& susceptible,
289 std::vector<IntegerRaster>& mortality_tracker_vector,
290 std::vector<IntegerRaster>& exposed,
291 IntegerRaster& resistant,
292 IntegerRaster& total_hosts,
293 IntegerRaster& total_exposed,
296 const std::vector<std::vector<int>>& movements,
297 std::vector<unsigned> movement_schedule,
298 std::vector<std::vector<int>>& suitable_cells)
300 for (
unsigned i = last_index; i < movements.size(); i++) {
301 auto moved = movements[i];
302 unsigned move_schedule = movement_schedule[i];
303 if (move_schedule != step) {
306 int infected_moved = 0;
307 int exposed_moved = 0;
308 int susceptible_moved = 0;
309 int resistant_moved = 0;
310 int total_hosts_moved = 0;
311 int row_from = moved[0];
312 int col_from = moved[1];
313 int row_to = moved[2];
314 int col_to = moved[3];
315 int hosts = moved[4];
316 std::vector<int> exposed_categories;
317 std::vector<int> mortality_categories;
318 if (hosts > total_hosts(row_from, col_from)) {
319 total_hosts_moved = total_hosts(row_from, col_from);
322 total_hosts_moved = hosts;
324 auto total_infecteds = infected(row_from, col_from);
325 auto suscepts = susceptible(row_from, col_from);
326 auto expose = total_exposed(row_from, col_from);
327 auto resist = resistant(row_from, col_from);
330 std::vector<int> categories(total_infecteds, 1);
331 categories.insert(categories.end(), suscepts, 2);
332 categories.insert(categories.end(), expose, 3);
333 categories.insert(categories.end(), resist, 4);
335 std::vector<int> draw =
337 infected_moved = std::count(draw.begin(), draw.end(), 1);
338 susceptible_moved = std::count(draw.begin(), draw.end(), 2);
339 exposed_moved = std::count(draw.begin(), draw.end(), 3);
340 resistant_moved = std::count(draw.begin(), draw.end(), 4);
342 if (exposed_moved > 0) {
344 for (
auto& raster : exposed) {
345 auto exposed_count = raster(row_from, col_from);
346 exposed_categories.insert(
347 exposed_categories.end(), exposed_count, index);
351 std::vector<int> exposed_draw =
352 draw_n_from_v(exposed_categories, exposed_moved, generator_);
354 for (
auto& raster : exposed) {
355 auto exposed_moved_in_cohort =
356 std::count(exposed_draw.begin(), exposed_draw.end(), index);
357 raster(row_from, col_from) -= exposed_moved_in_cohort;
358 raster(row_to, col_to) += exposed_moved_in_cohort;
363 if (infected_moved > 0) {
364 std::vector<int> mortality_categories;
366 for (
auto& raster : mortality_tracker_vector) {
367 auto mortality_count = raster(row_from, col_from);
368 mortality_categories.insert(
369 mortality_categories.end(), mortality_count, index);
372 std::vector<int> mortality_draw =
373 draw_n_from_v(mortality_categories, infected_moved, generator_);
375 for (
auto& raster : mortality_tracker_vector) {
376 auto mortality_moved_in_cohort =
377 std::count(mortality_draw.begin(), mortality_draw.end(), index);
378 raster(row_from, col_from) -= mortality_moved_in_cohort;
379 raster(row_to, col_to) += mortality_moved_in_cohort;
386 if (total_hosts(row_to, col_to) == 0) {
387 for (
auto indices : suitable_cells) {
390 if ((i == row_to) && (j == col_to)) {
391 std::vector<int> added_index = {row_to, col_to};
392 suitable_cells.push_back(added_index);
398 infected(row_from, col_from) -= infected_moved;
399 susceptible(row_from, col_from) -= susceptible_moved;
400 total_hosts(row_from, col_from) -= total_hosts_moved;
401 total_exposed(row_from, col_from) -= exposed_moved;
402 resistant(row_from, col_from) -= resistant_moved;
403 infected(row_to, col_to) += infected_moved;
404 susceptible(row_to, col_to) += susceptible_moved;
405 total_hosts(row_to, col_to) += total_hosts_moved;
406 total_exposed(row_to, col_to) += exposed_moved;
407 resistant(row_to, col_to) += resistant_moved;
409 return movements.size();
422 IntegerRaster& dispersers,
423 const IntegerRaster& infected,
425 const FloatRaster& weather_coefficient,
426 double reproductive_rate,
427 const std::vector<std::vector<int>>& suitable_cells)
429 double lambda = reproductive_rate;
430 for (
auto indices : suitable_cells) {
433 if (infected(i, j) > 0) {
435 lambda = reproductive_rate * weather_coefficient(i, j);
436 int dispersers_from_cell = 0;
437 if (dispersers_stochasticity_) {
438 std::poisson_distribution<int> distribution(lambda);
439 for (
int k = 0; k < infected(i, j); k++) {
440 dispersers_from_cell += distribution(generator_);
444 dispersers_from_cell = lambda * infected(i, j);
446 dispersers(i, j) = dispersers_from_cell;
449 dispersers(i, j) = 0;
498 template<
typename DispersalKernel>
500 const IntegerRaster& dispersers,
501 IntegerRaster& susceptible,
502 IntegerRaster& exposed_or_infected,
503 IntegerRaster& mortality_tracker,
504 const IntegerRaster& total_populations,
505 IntegerRaster& total_exposed,
506 std::vector<std::tuple<int, int>>& outside_dispersers,
508 const FloatRaster& weather_coefficient,
510 const std::vector<std::vector<int>>& suitable_cells,
511 double establishment_probability = 0.5)
513 std::uniform_real_distribution<double> distribution_uniform(0.0, 1.0);
517 for (
auto indices : suitable_cells) {
520 if (dispersers(i, j) > 0) {
521 for (
int k = 0; k < dispersers(i, j); k++) {
522 std::tie(row, col) = dispersal_kernel(generator_, i, j);
523 if (row < 0 || row >= rows_ || col < 0 || col >= cols_) {
525 outside_dispersers.emplace_back(std::make_tuple(row, col));
528 if (susceptible(row, col) > 0) {
529 double probability_of_establishment =
530 (double)(susceptible(row, col))
531 / total_populations(row, col);
532 double establishment_tester = 1 - establishment_probability;
533 if (establishment_stochasticity_)
534 establishment_tester = distribution_uniform(generator_);
537 probability_of_establishment *= weather_coefficient(i, j);
538 if (establishment_tester < probability_of_establishment) {
539 exposed_or_infected(row, col) += 1;
540 susceptible(row, col) -= 1;
542 mortality_tracker(row, col) += 1;
546 total_exposed(row, col) += 1;
549 throw std::runtime_error(
550 "Unknown ModelType value in "
551 "Simulation::disperse()");
590 template<
typename DispersalKernel>
592 IntegerRaster& susceptible,
593 IntegerRaster& infected,
594 const IntegerRaster& total_hosts,
595 std::vector<std::tuple<int, int>>& outside_dispersers,
597 const std::vector<std::vector<int>>& suitable_cells,
598 double overpopulation_percentage,
599 double leaving_percentage)
607 std::vector<Move> moves;
610 for (
auto indices : suitable_cells) {
613 int original_count = infected(i, j);
615 if (original_count <= 1)
619 double ratio = original_count / double(total_hosts(i, j));
620 if (ratio >= overpopulation_percentage) {
623 std::tie(row, col) = dispersal_kernel(generator_, i, j);
627 int leaving = original_count * leaving_percentage;
628 susceptible(i, j) += leaving;
629 infected(i, j) -= leaving;
630 if (row < 0 || row >= rows_ || col < 0 || col >= cols_) {
632 outside_dispersers.reserve(outside_dispersers.size() + leaving);
633 for (
int pest = 0; pest < leaving; ++pest)
634 outside_dispersers.emplace_back(row, col);
642 moves.push_back(Move({row, col, leaving}));
646 for (
const auto& move : moves) {
647 RasterIndex row = move.row;
648 RasterIndex col = move.col;
649 int leaving = move.count;
651 if (susceptible(row, col) >= leaving) {
652 susceptible(row, col) -= leaving;
653 infected(row, col) += leaving;
661 leaving = susceptible(row, col);
662 susceptible(row, col) -= leaving;
663 infected(row, col) += leaving;
712 std::vector<IntegerRaster>& exposed,
713 IntegerRaster& infected,
714 IntegerRaster& mortality_tracker,
715 IntegerRaster& total_exposed)
718 if (step >= latency_period_) {
720 auto& oldest = exposed.front();
723 mortality_tracker += oldest;
724 total_exposed -= oldest;
739 throw std::runtime_error(
740 "Unknown ModelType value in Simulation::infect_exposed()");
770 template<
typename DispersalKernel>
773 const IntegerRaster& dispersers,
774 IntegerRaster& susceptible,
775 std::vector<IntegerRaster>& exposed,
776 IntegerRaster& infected,
777 IntegerRaster& mortality_tracker,
778 const IntegerRaster& total_populations,
779 IntegerRaster& total_exposed,
780 std::vector<std::tuple<int, int>>& outside_dispersers,
782 const FloatRaster& weather_coefficient,
784 const std::vector<std::vector<int>>& suitable_cells,
785 double establishment_probability = 0.5)
787 auto* infected_or_exposed = &infected;
791 infected_or_exposed = &exposed.back();
796 *infected_or_exposed,
805 establishment_probability);
808 step, exposed, infected, mortality_tracker, total_exposed);
815 #endif // POPS_SIMULATION_HPP