diff --git a/cpp/models/abm/infection.cpp b/cpp/models/abm/infection.cpp index c4ec73ea64..dfcdafd039 100644 --- a/cpp/models/abm/infection.cpp +++ b/cpp/models/abm/infection.cpp @@ -180,7 +180,10 @@ void Infection::draw_infection_course_forward(PersonalRandomNumberGenerator& rng case InfectionState::InfectedSevere: // roll out next infection step v = uniform_dist(rng); - if (v < 0.5) { // TODO: subject to change + if (v < 0.25) { // TODO: subject to change + time_period = days(params.get()[{m_virus_variant, age}]); // TODO: subject to change + next_state = InfectionState::Dead; + } else if (v < 0.5) { // TODO: subject to change time_period = days(params.get()[{m_virus_variant, age}]); // TODO: subject to change next_state = InfectionState::InfectedCritical; } @@ -271,8 +274,15 @@ TimePoint Infection::draw_infection_course_backward(PersonalRandomNumberGenerato break; case InfectionState::Dead: - time_period = days(params.get()[{m_virus_variant, age}]); // TODO: subject to change - previous_state = InfectionState::InfectedCritical; + v = uniform_dist(rng); + if (v < 0.5) { + time_period = days(params.get()[{m_virus_variant, age}]); // TODO: subject to change + previous_state = InfectionState::InfectedSevere; + } + else { + time_period = days(params.get()[{m_virus_variant, age}]); // TODO: subject to change + previous_state = InfectionState::InfectedCritical; + } break; default: diff --git a/cpp/models/abm/infection.h b/cpp/models/abm/infection.h index bd054e1fc6..71a027d3db 100644 --- a/cpp/models/abm/infection.h +++ b/cpp/models/abm/infection.h @@ -141,7 +141,7 @@ class Infection Infection() = default; /** - * @brief Determine ViralLoad course and Infection course based on init_state. + * @brief Determine Infection course based on #InfectionState init_state. * Calls draw_infection_course_backward for all #InfectionState%s prior and draw_infection_course_forward for all * subsequent #InfectionState%s. * @param[inout] rng PersonalRandomNumberGenerator of the Person. @@ -149,25 +149,38 @@ class Infection * @param[in] params Parameters of the Model. * @param[in] init_date Date of initializing the Infection. * @param[in] init_state #InfectionState at time of initializing the Infection. + * @param[in] latest_protection Latest protection against Infection, has an influence on transition probabilities. * @return The starting date of the Infection. */ TimePoint draw_infection_course(PersonalRandomNumberGenerator& rng, AgeGroup age, const Parameters& params, TimePoint init_date, InfectionState start_state, ProtectionEvent latest_protection); /** - * @brief Determine ViralLoad course and Infection course prior to the given start_state. + * @brief Determine Infection course subsequent to the given #InfectionState start_state. + * From the start_state, a random path through the #InfectionState tree is chosen, that is + * Susceptible -> InfectedNoSymptoms, + * InfectedNoSymptoms -> InfectedSymptoms or InfectedNoSymptoms -> Recovered, + * InfectedSymptoms -> Infected_Severe or InfectedSymptoms -> Recovered, + * InfectedSevere -> InfectedCritical or InfectedSevere -> Recovered or InfectedSevere -> Dead, + * InfectedCritical -> Recovered or InfectedCritical -> Dead, + * with artifical, hardcoded probabilites, until either Recoverd or Dead is reached. + * This is subject to change when parameter distributions for these transitions are implemented. + * The duration in each #InfectionState is taken from the respective parameter. * @param[inout] rng PersonalRandomNumberGenerator of the Person. * @param[in] age AgeGroup of the Person. * @param[in] params Parameters of the Model. * @param[in] init_date Date of initializing the Infection. * @param[in] init_state #InfectionState at time of initializing the Infection. + * @param[in] latest_protection Latest protection against Infection, has an influence on transition probabilities. */ void draw_infection_course_forward(PersonalRandomNumberGenerator& rng, AgeGroup age, const Parameters& params, - TimePoint init_date, InfectionState start_state, + TimePoint init_date, InfectionState init_state, ProtectionEvent latest_protection); /** - * @brief Determine ViralLoad course and Infection course subsequent to the given start_state. + * @brief Determine Infection course prior to the given #InfectionState start_state. + * From the start_state, a random path through the #InfectionState tree is chosen backwards, until Susceptible is reached. + * For more detailed information, refer to draw_infection_course_forward. * @param[inout] rng PersonalRandomNumberGenerator of the Person. * @param[in] age AgeGroup of the person. * @param[in] params Parameters of the Model. diff --git a/cpp/models/abm/parameters.h b/cpp/models/abm/parameters.h index 1b4a322112..1da8cc46ca 100644 --- a/cpp/models/abm/parameters.h +++ b/cpp/models/abm/parameters.h @@ -133,6 +133,18 @@ struct SevereToRecovered { } }; +struct SevereToDead { + using Type = CustomIndexArray, VirusVariant, AgeGroup>; + static Type get_default(AgeGroup size) + { + return Type({VirusVariant::Count, size}, 1.); + } + static std::string name() + { + return "SevereToDead"; + } +}; + struct CriticalToRecovered { using Type = CustomIndexArray, VirusVariant, AgeGroup>; static Type get_default(AgeGroup size) @@ -551,7 +563,7 @@ struct AgeGroupGotoWork { using ParametersBase = ParameterSetget()[{VirusVariant::Wildtype, age_group}] < 0.0) { + log_error("Constraint check: Parameter SevereToDead of age group {:.0f} smaller than {:d}", + (size_t)age_group, 0); + return true; + } + if (this->get()[{virus_variant, age_group}] < 0.0) { log_error("Constraint check: Parameter CriticalToDead of age group {:.0f} smaller than {:d}", (size_t)age_group, 0); diff --git a/cpp/simulations/abm.cpp b/cpp/simulations/abm.cpp index d9be12a0e6..8bfee8db00 100644 --- a/cpp/simulations/abm.cpp +++ b/cpp/simulations/abm.cpp @@ -475,6 +475,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.186; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.015; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.143; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; @@ -486,6 +487,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.186; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.015; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.143; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.; @@ -499,6 +501,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.003; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.157; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.013; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.126; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; @@ -511,6 +514,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.009; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.113; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.02; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.05; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.; @@ -524,6 +528,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.024; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.083; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.; @@ -536,6 +541,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.033; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.055; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.036; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.035; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.; @@ -550,6 +556,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.186; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.015; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.143; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.0; @@ -562,6 +569,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.186; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.015; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.143; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.0; @@ -575,6 +583,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.157; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.013; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.126; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.0; @@ -588,6 +597,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.003; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.113; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.02; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.05; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.0; @@ -601,6 +611,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.009; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.083; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.0; @@ -613,6 +624,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.012; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.055; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.036; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.035; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.0; diff --git a/cpp/simulations/abm_braunschweig.cpp b/cpp/simulations/abm_braunschweig.cpp index 8f324b34c4..5853c220f0 100644 --- a/cpp/simulations/abm_braunschweig.cpp +++ b/cpp/simulations/abm_braunschweig.cpp @@ -406,6 +406,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.186; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.015; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.143; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; @@ -417,6 +418,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.186; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.015; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.143; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.; @@ -430,6 +432,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.003; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.157; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.013; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.126; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; @@ -442,6 +445,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.009; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.113; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.02; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.05; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.; @@ -455,6 +459,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.024; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.083; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.; @@ -467,6 +472,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.033; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.055; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.036; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.035; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.; @@ -481,6 +487,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.186; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.015; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.143; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.0; @@ -541,6 +548,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.186; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.015; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.143; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.0; @@ -601,6 +609,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.001; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.157; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.013; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.126; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.0; @@ -659,6 +668,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.003; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.113; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.02; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.05; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.0; @@ -717,6 +727,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.009; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.083; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.0; @@ -775,6 +786,7 @@ void set_parameters(mio::abm::Parameters params) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.012; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.055; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.036; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.035; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.0; diff --git a/cpp/tests/test_abm_infection.cpp b/cpp/tests/test_abm_infection.cpp index 2799829e5c..1930bf8108 100644 --- a/cpp/tests/test_abm_infection.cpp +++ b/cpp/tests/test_abm_infection.cpp @@ -140,14 +140,25 @@ TEST_F(TestInfection, drawInfectionCourseForward) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 1; ScopedMockDistribution>>> mock_uniform_dist; EXPECT_CALL(mock_uniform_dist.get_mock(), invoke) - .Times(testing::AtLeast(1)) - .WillRepeatedly(testing::Return(0.8)); // Recovered - auto infection = mio::abm::Infection(prng, mio::abm::VirusVariant::Wildtype, age_group_15_to_34, params, t, + .Times(testing::Exactly(6)) // First five draws for viral load + .WillRepeatedly(testing::Return(0.8)); // Sixth draw: Recovered draw in drawInfectionCourseForward + auto infection1 = mio::abm::Infection(prng, mio::abm::VirusVariant::Wildtype, age_group_15_to_34, params, t, mio::abm::InfectionState::InfectedCritical, {mio::abm::ProtectionType::NoProtection, mio::abm::TimePoint(0)}, true); // Test state transitions from Critical to Recovered - EXPECT_EQ(infection.get_infection_state(t), mio::abm::InfectionState::InfectedCritical); - EXPECT_EQ(infection.get_infection_state(t + mio::abm::days(1)), mio::abm::InfectionState::Recovered); + EXPECT_EQ(infection1.get_infection_state(t), mio::abm::InfectionState::InfectedCritical); + EXPECT_EQ(infection1.get_infection_state(t + mio::abm::days(1)), mio::abm::InfectionState::Recovered); + + // Mock death transition + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 1; + EXPECT_CALL(mock_uniform_dist.get_mock(), invoke) + .Times(testing::Exactly(6)) // First five draws for viral load + .WillRepeatedly(testing::Return(0.2)); // Sixth draw: Dead draw in drawInfectionCourseForward + auto infection2 = mio::abm::Infection(prng, mio::abm::VirusVariant::Wildtype, age_group_15_to_34, params, t, + mio::abm::InfectionState::InfectedSevere, + {mio::abm::ProtectionType::NoProtection, mio::abm::TimePoint(0)}, true); + EXPECT_EQ(infection2.get_infection_state(t), mio::abm::InfectionState::InfectedSevere); + EXPECT_EQ(infection2.get_infection_state(t + mio::abm::days(1)), mio::abm::InfectionState::Dead); } /** diff --git a/cpp/tests/test_abm_model.cpp b/cpp/tests/test_abm_model.cpp index c19bf7e5a0..c1a76b5299 100644 --- a/cpp/tests/test_abm_model.cpp +++ b/cpp/tests/test_abm_model.cpp @@ -311,26 +311,12 @@ TEST_F(TestModel, evolveMobilityTrips) auto work_id = model.add_location(mio::abm::LocationType::Work); auto hospital_id = model.add_location(mio::abm::LocationType::Hospital); - // Mock the random distribution to control random behavior. - ScopedMockDistribution>>> mock_uniform_dist; - EXPECT_CALL(mock_uniform_dist.get_mock(), invoke) - .Times(testing::AtLeast(8)) - .WillOnce(testing::Return(0.8)) // draw random work group - .WillOnce(testing::Return(0.8)) // draw random school group - .WillOnce(testing::Return(0.8)) // draw random work hour - .WillOnce(testing::Return(0.8)) // draw random school hour - .WillOnce(testing::Return(0.8)) // draw random work group - .WillOnce(testing::Return(0.8)) // draw random school group - .WillOnce(testing::Return(0.8)) // draw random work hour - .WillOnce(testing::Return(0.8)) // draw random school hour - .WillRepeatedly(testing::Return(1.0)); // this forces p1 and p3 to recover - // Create persons with various infection states and assign them to multiple locations. - auto pid1 = add_test_person(model, home_id, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms, t); - auto pid2 = add_test_person(model, home_id, age_group_5_to_14, mio::abm::InfectionState::Susceptible, t); - auto pid3 = add_test_person(model, home_id, age_group_5_to_14, mio::abm::InfectionState::InfectedSevere, t); - auto pid4 = add_test_person(model, hospital_id, age_group_5_to_14, mio::abm::InfectionState::Recovered, t); - auto pid5 = add_test_person(model, home_id, age_group_15_to_34, mio::abm::InfectionState::Susceptible, t); + auto pid1 = model.add_person(home_id, age_group_15_to_34); + auto pid2 = model.add_person(home_id, age_group_5_to_14); + auto pid3 = model.add_person(home_id, age_group_5_to_14); + auto pid4 = model.add_person(hospital_id, age_group_5_to_14); + auto pid5 = model.add_person(home_id, age_group_15_to_34); // Assign persons to locations for trips. auto& p1 = model.get_person(pid1); @@ -365,6 +351,43 @@ TEST_F(TestModel, evolveMobilityTrips) // Set trips to use weekday trips on weekends. data.use_weekday_trips_on_weekend(); + // Mock the random distribution to control random behavior. + ScopedMockDistribution>>> mock_uniform_dist; + EXPECT_CALL(mock_uniform_dist.get_mock(), invoke) + .Times(testing::Exactly(18)) + .WillOnce(testing::Return(1.0)) // draw transition to Recovered p1 + .WillOnce(testing::Return(0.8)) // draw random peak p1 + .WillOnce(testing::Return(0.8)) // draw random incline p1 + .WillOnce(testing::Return(0.8)) // draw random decline p1 + .WillOnce(testing::Return(0.8)) // draw random alpha p1 + .WillOnce(testing::Return(0.8)) // draw random beta p1 + .WillOnce(testing::Return(1.0)) // draw transition to Recovered p3 + .WillOnce(testing::Return(0.8)) // draw random peak p3 + .WillOnce(testing::Return(0.8)) // draw random incline p3 + .WillOnce(testing::Return(0.8)) // draw random decline p3 + .WillOnce(testing::Return(0.8)) // draw random alpha p3 + .WillOnce(testing::Return(0.8)) // draw random beta p3 + .WillOnce(testing::Return(1.0)) // draw transition from InfectedCritical p4 + .WillOnce(testing::Return(0.8)) // draw random peak p4 + .WillOnce(testing::Return(0.8)) // draw random incline p4 + .WillOnce(testing::Return(0.8)) // draw random decline p4 + .WillOnce(testing::Return(0.8)) // draw random alpha p4 + .WillOnce(testing::Return(0.8)) // draw random beta p4 + .RetiresOnSaturation(); + + auto rng_p1 = mio::abm::PersonalRandomNumberGenerator(model.get_rng(), p1); + p1.add_new_infection(mio::abm::Infection(rng_p1, static_cast(0), p1.get_age(), + model.parameters, t, mio::abm::InfectionState::InfectedNoSymptoms)); + auto rng_p3 = mio::abm::PersonalRandomNumberGenerator(model.get_rng(), p1); + p3.add_new_infection(mio::abm::Infection(rng_p3, static_cast(0), p3.get_age(), + model.parameters, t, mio::abm::InfectionState::InfectedSevere)); + auto rng_p4 = mio::abm::PersonalRandomNumberGenerator(model.get_rng(), p1); + p4.add_new_infection(mio::abm::Infection(rng_p4, static_cast(0), p4.get_age(), + model.parameters, t, mio::abm::InfectionState::Recovered)); + + // For any other uniform distribution calls in model.evolve + EXPECT_CALL(mock_uniform_dist.get_mock(), invoke).WillRepeatedly(Return(1.)); + // Mock the distribution to prevent infections or state transitions in the test. ScopedMockDistribution>>> mock_exponential_dist; @@ -494,7 +517,7 @@ TEST_F(TestModel, checkMobilityOfDeadPerson) auto dt = mio::abm::days(1); auto model = mio::abm::Model(num_age_groups); - // Time to go from severe to critical infection is 1 day (dt). + // Time to go from severe to critical infection is 1/2 day (0.5 * dt). model.parameters.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.5; // Time to go from critical infection to dead state is 1/2 day (0.5 * dt). model.parameters.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.5; @@ -503,6 +526,12 @@ TEST_F(TestModel, checkMobilityOfDeadPerson) auto work_id = model.add_location(mio::abm::LocationType::Work); auto icu_id = model.add_location(mio::abm::LocationType::ICU); auto hospital_id = model.add_location(mio::abm::LocationType::Hospital); + + // Make sure all persons will be InfectedSevere -> InfectedCritical -> Dead. + // Also mocks other things in the setup and evolve, thus not using times::Exactly here. + ScopedMockDistribution>>> mock_uniform_dist; + EXPECT_CALL(mock_uniform_dist.get_mock(), invoke).WillRepeatedly(testing::Return(1.0)); + // Create a person that is dead at time t add_test_person(model, icu_id, age_group_60_to_79, mio::abm::InfectionState::Dead, t); // Create a person that is severe at hospital and will be dead at time t + dt @@ -624,9 +653,10 @@ TEST_F(TestModel, checkParameterConstraints) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 5.; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 6.; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 7.; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 8.; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 9.; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 10.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 8.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 9.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 10.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 11.; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.3; params.get()[age_group_35_to_59] = mio::abm::hours(4); params.get()[age_group_35_to_59] = mio::abm::hours(8); @@ -657,18 +687,21 @@ TEST_F(TestModel, checkParameterConstraints) params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = -6.; EXPECT_TRUE(params.check_constraints()); params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 6.; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = -7.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = -7.; + EXPECT_TRUE(params.check_constraints()); + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 7.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = -8.; EXPECT_TRUE(params.check_constraints()); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 7.; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = -8.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 8.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = -9.; EXPECT_TRUE(params.check_constraints()); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 8.; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = -9.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 9.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = -10.; EXPECT_TRUE(params.check_constraints()); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 9.; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = -10.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 10.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = -11.; EXPECT_TRUE(params.check_constraints()); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 10.; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 11.; params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 1.1; EXPECT_TRUE(params.check_constraints()); params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.3; @@ -947,3 +980,57 @@ TEST_F(TestModel, mobilityTripWithAppliedNPIs) // The person does not want to isolate when the test is positive EXPECT_FALSE(p_no_isolation.is_in_quarantine(t, model.parameters)); } + +/** + * @brief Tests whether a person can die in a hospital setting, specifically not only in the InfectionState Severe. + */ +TEST_F(TestModel, personCanDieInHospital) +{ + using testing::Return; + + auto t = mio::abm::TimePoint(0); + auto dt = mio::abm::days(1); + auto model = mio::abm::Model(num_age_groups); + model.get_rng() = this->get_rng(); + + // Time to go from infected with symptoms to severe infection is 1 day(dt). + model.parameters.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 1; + // Time to go from severe infection to critical is 1 day(dt). + model.parameters.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 1; + // Time to go from severe infection to dead is 1 day(dt). + model.parameters.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 1; + // Time to go from critical infection to dead is 1 day(dt). + model.parameters.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 1; + + auto home_id = model.add_location(mio::abm::LocationType::Home); + auto work_id = model.add_location(mio::abm::LocationType::Work); + auto icu_id = model.add_location(mio::abm::LocationType::ICU); + auto hospital_id = model.add_location(mio::abm::LocationType::Hospital); + + // Make sure all persons will be InfectedSevere before Dead. + // Also mocks other things in the setup and evolve, thus not using times::Exactly here. + ScopedMockDistribution>>> mock_uniform_dist; + EXPECT_CALL(mock_uniform_dist.get_mock(), invoke).WillRepeatedly(testing::Return(0.3)); + + // Create a person that has InfectedSymptoms at time t - dt. The person is dead at time t + dt + add_test_person(model, home_id, age_group_60_to_79, mio::abm::InfectionState::Dead, t + dt); + + auto& p_severe = model.get_persons()[0]; + p_severe.set_assigned_location(mio::abm::LocationType::Hospital, hospital_id); + p_severe.set_assigned_location(mio::abm::LocationType::ICU, icu_id); + p_severe.set_assigned_location(mio::abm::LocationType::Home, home_id); + p_severe.set_assigned_location(mio::abm::LocationType::Work, work_id); + + // Check the infection course goes from InfectedSymptoms to Severe to Dead and skips Critical + EXPECT_EQ(p_severe.get_infection_state(t - dt), mio::abm::InfectionState::InfectedSymptoms); + EXPECT_EQ(p_severe.get_infection_state(t), mio::abm::InfectionState::InfectedSevere); + EXPECT_EQ(p_severe.get_infection_state(t + dt), mio::abm::InfectionState::Dead); + + // Check the severely infected person go to hospital + EXPECT_EQ(model.get_location(p_severe.get_id()).get_type(), mio::abm::LocationType::Home); + model.evolve(t, dt); + EXPECT_EQ(model.get_location(p_severe.get_id()).get_type(), mio::abm::LocationType::Hospital); + // Check the severely infected person dies and got burried + model.evolve(t + dt, dt); + EXPECT_EQ(model.get_location(p_severe.get_id()).get_type(), mio::abm::LocationType::Cemetery); +}