diff --git a/inst/cpp/pops-core b/inst/cpp/pops-core index 24bc87bc..e65eb932 160000 --- a/inst/cpp/pops-core +++ b/inst/cpp/pops-core @@ -1 +1 @@ -Subproject commit 24bc87bcb8b42d75b3b38694d0f42121813c67ff +Subproject commit e65eb9323f744fb2a158acaf7d8a574449571f37 diff --git a/inst/include/host_pool.hpp b/inst/include/host_pool.hpp index ec7221d5..77da4d5f 100644 --- a/inst/include/host_pool.hpp +++ b/inst/include/host_pool.hpp @@ -515,6 +515,7 @@ class HostPool : public HostPoolInterface * @brief Completely remove any hosts * * Removes hosts completely (as opposed to moving them to another pool). + * If mortality is not active, the *mortality* parameter is ignored. * * @param row Row index of the cell * @param col Column index of the cell @@ -523,9 +524,6 @@ class HostPool : public HostPoolInterface * @param infected Number of infected hosts to remove. * @param mortality Number of infected hosts in each mortality cohort. * - * @note Counts are doubles, so that handling of floating point values is managed - * here in the same way as in the original treatment code. - * * @note This does not remove resistant just like the original implementation in * treatments. */ @@ -556,6 +554,11 @@ class HostPool : public HostPoolInterface // Possibly reuse in the I->S removal. if (infected <= 0) return; + if (!mortality_tracker_vector_.size()) { + infected_(row, col) -= infected; + reset_total_host(row, col); + return; + } if (mortality_tracker_vector_.size() != mortality.size()) { throw std::invalid_argument( "mortality is not the same size as the internal mortality tracker (" @@ -564,8 +567,8 @@ class HostPool : public HostPoolInterface + std::to_string(row) + ", " + std::to_string(col) + ")"); } - double mortality_total = 0; - for (size_t i = 0; i < mortality.size(); ++i) { + int mortality_total = 0; + for (size_t i = 0; i < mortality_tracker_vector_.size(); ++i) { if (mortality_tracker_vector_[i](row, col) < mortality[i]) { throw std::invalid_argument( "Mortality value [" + std::to_string(i) + "] is too high (" @@ -582,20 +585,20 @@ class HostPool : public HostPoolInterface // and once we don't need to keep the exact same double to int results for // tests. First condition always fails the tests. The second one may potentially // fail. - if (false && infected != mortality_total) { + if (infected != mortality_total) { throw std::invalid_argument( "Total of removed mortality values differs from removed infected " "count (" + std::to_string(mortality_total) + " != " + std::to_string(infected) - + " for cell (" + std::to_string(row) + ", " + std::to_string(col) + + ") for cell (" + std::to_string(row) + ", " + std::to_string(col) + ")"); } - if (false && infected_(row, col) < mortality_total) { + if (infected_(row, col) < mortality_total) { throw std::invalid_argument( "Total of removed mortality values is higher than current number " - "of infected hosts for cell (" - + std::to_string(row) + ", " + std::to_string(col) + ") is too high (" + "of infected hosts (" + std::to_string(mortality_total) + " > " + std::to_string(infected) + + ") for cell (" + std::to_string(row) + ", " + std::to_string(col) + ")"); } infected_(row, col) -= infected; @@ -700,6 +703,8 @@ class HostPool : public HostPoolInterface /** * @brief Make hosts resistant in a given cell * + * If mortality is not active, the *mortality* parameter is ignored. + * * @param row Row index of the cell * @param col Column index of the cell * @param susceptible Number of susceptible hosts to make resistant @@ -746,6 +751,12 @@ class HostPool : public HostPoolInterface total_resistant += exposed[i]; } infected_(row, col) -= infected; + total_resistant += infected; + resistant_(row, col) += total_resistant; + if (!mortality_tracker_vector_.size()) { + reset_total_host(row, col); + return; + } if (mortality_tracker_vector_.size() != mortality.size()) { throw std::invalid_argument( "mortality is not the same size as the internal mortality tracker (" @@ -755,7 +766,7 @@ class HostPool : public HostPoolInterface } int mortality_total = 0; // no simple zip in C++, falling back to indices - for (size_t i = 0; i < mortality.size(); ++i) { + for (size_t i = 0; i < mortality_tracker_vector_.size(); ++i) { mortality_tracker_vector_[i](row, col) -= mortality[i]; mortality_total += mortality[i]; } @@ -771,8 +782,7 @@ class HostPool : public HostPoolInterface + " for cell (" + std::to_string(row) + ", " + std::to_string(col) + "))"); } - total_resistant += infected; - resistant_(row, col) += total_resistant; + reset_total_host(row, col); } /** @@ -975,6 +985,9 @@ class HostPool : public HostPoolInterface /** * @brief Get infected hosts in each mortality cohort at a given cell * + * If mortality is not active, it returns number of all infected individuals + * in the first and only item of the vector. + * * @param row Row index of the cell * @param col Column index of the cell * @@ -983,6 +996,12 @@ class HostPool : public HostPoolInterface std::vector mortality_by_group_at(RasterIndex row, RasterIndex col) const { std::vector all; + + if (!mortality_tracker_vector_.size()) { + all.push_back(infected_at(row, col)); + return all; + } + all.reserve(mortality_tracker_vector_.size()); for (const auto& raster : mortality_tracker_vector_) all.push_back(raster(row, col)); diff --git a/inst/include/treatments.hpp b/inst/include/treatments.hpp index d6f15df3..9494be97 100644 --- a/inst/include/treatments.hpp +++ b/inst/include/treatments.hpp @@ -125,15 +125,15 @@ class BaseTreatment : public AbstractTreatment } // returning double allows identical results with the previous version - double get_treated(int i, int j, int count) + int get_treated(int i, int j, int count) { return get_treated(i, j, count, this->application_); } - double get_treated(int i, int j, int count, TreatmentApplication application) + int get_treated(int i, int j, int count, TreatmentApplication application) { if (application == TreatmentApplication::Ratio) { - return count * this->map_(i, j); + return std::lround(count * this->map_(i, j)); } else if (application == TreatmentApplication::AllInfectedInCell) { return static_cast(this->map_(i, j)) ? count : 0; @@ -173,20 +173,21 @@ class SimpleTreatment : public BaseTreatment for (auto indices : host_pool.suitable_cells()) { int i = indices[0]; int j = indices[1]; - int remove_susceptible = static_cast(std::ceil(this->get_treated( - i, j, host_pool.susceptible_at(i, j), TreatmentApplication::Ratio))); - int remove_infected = static_cast( - std::ceil(this->get_treated(i, j, host_pool.infected_at(i, j)))); + int remove_susceptible = this->get_treated( + i, j, host_pool.susceptible_at(i, j), TreatmentApplication::Ratio); + // Treated infected are computed as a sum of treated in mortality groups. + int remove_infected = 0; std::vector remove_mortality; for (int count : host_pool.mortality_by_group_at(i, j)) { - remove_mortality.push_back( - static_cast(std::ceil(this->get_treated(i, j, count)))); + int remove = this->get_treated(i, j, count); + remove_mortality.push_back(remove); + remove_infected += remove; } + // Will need to use infected directly if not mortality. std::vector remove_exposed; for (int count : host_pool.exposed_by_group_at(i, j)) { - remove_exposed.push_back( - static_cast(std::ceil(this->get_treated(i, j, count)))); + remove_exposed.push_back(this->get_treated(i, j, count)); } host_pool.completely_remove_hosts_at( i, @@ -240,26 +241,19 @@ class PesticideTreatment : public BaseTreatment for (auto indices : host_pool.suitable_cells()) { int i = indices[0]; int j = indices[1]; - // Given how the original code was written (everything was first converted - // to ints and subtractions happened only afterwards), this needs ints, - // not doubles to pass the r.pops.spread test (unlike the other code which - // did substractions before converting to ints), so the conversion to ints - // happened only later. Now get_treated returns double and floor or ceil is - // applied to the result to get the same results as before. - int susceptible_resistant = static_cast(std::floor(this->get_treated( - i, j, host_pool.susceptible_at(i, j), TreatmentApplication::Ratio))); + int susceptible_resistant = this->get_treated( + i, j, host_pool.susceptible_at(i, j), TreatmentApplication::Ratio); std::vector resistant_exposed_list; for (const auto& number : host_pool.exposed_by_group_at(i, j)) { - resistant_exposed_list.push_back( - static_cast(std::floor(this->get_treated(i, j, number)))); + resistant_exposed_list.push_back(this->get_treated(i, j, number)); } + int infected = 0; std::vector resistant_mortality_list; for (const auto& number : host_pool.mortality_by_group_at(i, j)) { - resistant_mortality_list.push_back( - static_cast(std::floor(this->get_treated(i, j, number)))); + int remove = this->get_treated(i, j, number); + resistant_mortality_list.push_back(remove); + infected += remove; } - int infected = static_cast( - std::floor(this->get_treated(i, j, host_pool.infected_at(i, j)))); host_pool.make_resistant_at( i, j,