From d5cc1b68815fc4979ff41f6d23ff985e8a0aa5a9 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Mon, 28 Apr 2025 13:50:23 +0200 Subject: [PATCH 01/22] Implemented an ide secir birth and death model --- cpp/CMakeLists.txt | 1 + cpp/examples/CMakeLists.txt | 4 + cpp/examples/ide_endemic_secir.cpp | 91 ++++ cpp/models/ide_endemic_secir/CMakeLists.txt | 14 + .../ide_endemic_secir/infection_state.h | 49 ++ cpp/models/ide_endemic_secir/model.cpp | 491 ++++++++++++++++++ cpp/models/ide_endemic_secir/model.h | 253 +++++++++ cpp/models/ide_endemic_secir/parameters.h | 314 +++++++++++ cpp/models/ide_endemic_secir/simulation.cpp | 61 +++ cpp/models/ide_endemic_secir/simulation.h | 103 ++++ cpp/models/ide_secir/model.h | 2 +- cpp/models/ide_secir/simulation.h | 1 + 12 files changed, 1383 insertions(+), 1 deletion(-) create mode 100644 cpp/examples/ide_endemic_secir.cpp create mode 100644 cpp/models/ide_endemic_secir/CMakeLists.txt create mode 100644 cpp/models/ide_endemic_secir/infection_state.h create mode 100644 cpp/models/ide_endemic_secir/model.cpp create mode 100644 cpp/models/ide_endemic_secir/model.h create mode 100644 cpp/models/ide_endemic_secir/parameters.h create mode 100644 cpp/models/ide_endemic_secir/simulation.cpp create mode 100644 cpp/models/ide_endemic_secir/simulation.h diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 45a3d67773..22ea6f48cc 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -156,6 +156,7 @@ if(MEMILIO_BUILD_MODELS) add_subdirectory(models/ode_secirvvs) add_subdirectory(models/lct_secir) add_subdirectory(models/glct_secir) + add_subdirectory(models/ide_endemic_secir) add_subdirectory(models/ide_secir) add_subdirectory(models/ide_seir) add_subdirectory(models/ode_seir) diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index e7c5cb99f4..96e0d02ecb 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -104,6 +104,10 @@ add_executable(twitter_mobility_example twitter_mobility.cpp) target_link_libraries(twitter_mobility_example PRIVATE memilio ode_secir) target_compile_options(twitter_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ide_endemic_secir_example ide_endemic_secir.cpp) +target_link_libraries(ide_endemic_secir_example PRIVATE memilio ide_endemic_secir) +target_compile_options(ide_endemic_secir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(ide_seir_example ide_seir.cpp) target_link_libraries(ide_seir_example PRIVATE memilio ide_seir) target_compile_options(ide_seir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp new file mode 100644 index 0000000000..ddd4619ff0 --- /dev/null +++ b/cpp/examples/ide_endemic_secir.cpp @@ -0,0 +1,91 @@ +#include "ide_endemic_secir/model.h" +#include "ide_endemic_secir/infection_state.h" +#include "ide_endemic_secir/parameters.h" +#include "ide_endemic_secir/simulation.h" +#include "ide_endemic_secir/infection_state.h" +#include "memilio/config.h" +#include "memilio/epidemiology/age_group.h" +#include "memilio/math/eigen.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/utils/time_series.h" +#include "memilio/epidemiology/uncertain_matrix.h" +#include "memilio/epidemiology/state_age_function.h" +#include "memilio/data/analyze_result.h" +#include +#include + +int main() +{ + using Vec = mio::TimeSeries::Vector; + + ScalarType tmax = 10; + ScalarType dt = 1; + + int num_states = static_cast(mio::endisecir::InfectionState::Count); + int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); + + // Create TimeSeries with num_states elements where states needed for simulation will be stored. + mio::TimeSeries init(num_states); + + Vec vec_init(num_states); + + vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = 15000.; + vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = 50.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = 100.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = 200.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSevere)] = 90.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedCritical)] = 50.; + vec_init[static_cast(mio::endisecir::InfectionState::Recovered)] = 300.; + vec_init[static_cast(mio::endisecir::InfectionState::Dead)] = 5.; + + init.add_time_point(0, vec_init); + + mio::endisecir::Model model(std::move(init)); + + //Set working parameters + + mio::ExponentialSurvivalFunction exp(7.0); + mio::StateAgeFunctionWrapper delaydistribution(exp); + std::vector vec_delaydistribution(num_transitions, delaydistribution); + + // mio::SmootherCosine smoothcos(4.0); + // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + // std::vector vec_delaydistribution(num_transitions, delaydistribution); + + model.parameters.get() = vec_delaydistribution; + + std::vector vec_prob(num_transitions, 0.5); + // The following probabilities must be 1, as there is no other way to go. + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::SusceptibleToExposed)] = 1; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms)] = 1; + model.parameters.get() = vec_prob; + + mio::ContactMatrixGroup contact_matrix = mio::ContactMatrixGroup(1, 1); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 15.)); + model.parameters.get() = mio::UncertainContactMatrix(contact_matrix); + + mio::ConstantFunction constant(0.3); + mio::StateAgeFunctionWrapper constant_prob(constant); + + model.parameters.get() = constant_prob; + + mio::ExponentialSurvivalFunction exponential(0.5); + mio::StateAgeFunctionWrapper exponential_prob(exponential); + + model.parameters.get() = exponential_prob; + model.parameters.get() = exponential_prob; + + model.parameters.set(9e-5); + model.parameters.set(3e-5); + + // start the simulation. + mio::endisecir::Simulation sim(model, dt); + sim.advance(tmax); + + auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); + interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); + + sim.get_transitions().print_table( + {"S->E 1", "E->C 1", "C->I 1", "C->R 1", "I->H 1", "I->R 1", "H->U 1", "H->R 1", "U->D 1", "U->R 1"}, 16, 8); + std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; +} \ No newline at end of file diff --git a/cpp/models/ide_endemic_secir/CMakeLists.txt b/cpp/models/ide_endemic_secir/CMakeLists.txt new file mode 100644 index 0000000000..9417a51f42 --- /dev/null +++ b/cpp/models/ide_endemic_secir/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(ide_endemic_secir + infection_state.h + model.h + model.cpp + simulation.h + simulation.cpp + parameters.h +) +target_link_libraries(ide_endemic_secir PUBLIC memilio) +target_include_directories(ide_endemic_secir PUBLIC + $ + $ +) +target_compile_options(ide_endemic_secir PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ide_endemic_secir/infection_state.h b/cpp/models/ide_endemic_secir/infection_state.h new file mode 100644 index 0000000000..e2e7563d40 --- /dev/null +++ b/cpp/models/ide_endemic_secir/infection_state.h @@ -0,0 +1,49 @@ +#ifndef IDE_END_SECIR_INFECTIONSTATE_H +#define IDE_END_SECIR_INFECTIONSTATE_H + +namespace mio +{ + +namespace endisecir +{ + +/** + * @brief The #InfectionState enum describes the possible + * categories for the infectious state of persons + */ +enum class InfectionState +{ + Susceptible = 0, + Exposed = 1, + InfectedNoSymptoms = 2, + InfectedSymptoms = 3, + InfectedSevere = 4, + InfectedCritical = 5, + Recovered = 6, + Dead = 7, + Count = 8 +}; + +/** + * @brief The #InfectionTransition enum describes the possible + * transitions of the infectious state of persons. + */ +enum class InfectionTransition +{ + SusceptibleToExposed = 0, + ExposedToInfectedNoSymptoms = 1, + InfectedNoSymptomsToInfectedSymptoms = 2, + InfectedNoSymptomsToRecovered = 3, + InfectedSymptomsToInfectedSevere = 4, + InfectedSymptomsToRecovered = 5, + InfectedSevereToInfectedCritical = 6, + InfectedSevereToRecovered = 7, + InfectedCriticalToDead = 8, + InfectedCriticalToRecovered = 9, + Count = 10 +}; + +} // namespace endisecir +} // namespace mio + +#endif //IDE_END_SECIR_INFECTIONSTATE_H diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp new file mode 100644 index 0000000000..30d7936ca0 --- /dev/null +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -0,0 +1,491 @@ +#include "ide_endemic_secir/model.h" +#include "ide_endemic_secir/parameters.h" +#include "ide_endemic_secir/infection_state.h" +#include "memilio/config.h" +#include "memilio/utils/logging.h" + +#include "memilio/utils/time_series.h" +#include "ode_secir/parameters.h" +#include "vector" +#include +#include +#include +#include + +namespace mio +{ +namespace endisecir +{ +Model::Model(TimeSeries&& states_init) + : parameters{Parameters()} + , transitions{TimeSeries(Eigen::Index(InfectionTransition::Count))} + , populations{std::move(states_init)} +{ + // Set flows at start time t0. + // As we assume that all individuals have infectio age 0 at time t0, the flows at t0 are set to 0. + transitions.add_time_point( + 0, TimeSeries::Vector::Constant(static_cast(InfectionTransition::Count), 0.)); + + // Set population size at start timt t0. + ScalarType init_populationsize = std::accumulate(populations[0].begin(), populations[0].end(), 0); + m_totalpopulation.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); + // Set the force of infection at start time t0. + m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); +} + +bool Model::check_constraints() const +{ + if (!(static_cast(populations.get_num_elements()) == static_cast(InfectionState::Count))) { + log_error(" A variable given for model construction is not valid. Number of elements in vector of populations " + "does not match the required number."); + return true; + } + + for (int i = 0; i < static_cast(InfectionState::Count); i++) { + if (populations[0][i] < 0) { + log_error("Initialization failed. Initial values for populations are less than zero."); + return true; + } + } + return parameters.check_constraints(); +} + +// ----Functionality for the iterations of a simulation. ---- +void Model::compute_susceptibles(ScalarType dt) +{ + Eigen::Index num_time_points = populations.get_num_time_points(); + populations.get_last_value()[static_cast(InfectionState::Susceptible)] = + (populations[num_time_points - 2][static_cast(InfectionState::Susceptible)] * + (1 - parameters.get()) + + m_totalpopulation[num_time_points - 2][0] * parameters.get()) / + (1 + dt * m_forceofinfection[num_time_points - 2][0]); +} + +void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, Eigen::Index current_time_index, ScalarType dt) +{ + ScalarType sum = 0; + + for (Eigen::Index i = 0; i < current_time_index; i++) { + sum += transitions[i + 1][idx_IncomingFlow] * + std::exp((-parameters.get()) * (current_time_index - i)) * + m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; + } + transitions.get_value(current_time_index)[idx_InfectionTransitions] = + (-dt) * parameters.get()[idx_InfectionTransitions] * sum - + std::exp((-parameters.get()) * (current_time_index)) * + populations[0][idx_CurrentCompartment] * + parameters.get()[idx_InfectionTransitions] * + m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; +} + +void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, ScalarType dt) +{ + Eigen::Index current_time_index = transitions.get_num_time_points() - 1; + compute_flow(idx_InfectionTransitions, idx_IncomingFlow, idx_CurrentCompartment, current_time_index, dt); +} + +void Model::flows_currents_timestep(ScalarType dt) +{ + Eigen::Index current_time_index = populations.get_num_time_points() - 1; + // Calculate the transition SusceptibleToExposed with force of infection from previous time step and Susceptibles from + // current time step. + transitions.get_last_value()[static_cast(InfectionTransition::SusceptibleToExposed)] = + dt * m_forceofinfection[current_time_index - 1][0] * + populations.get_last_value()[static_cast(InfectionState::Susceptible)]; + + // Calculate the other Transitions with compute_flow. + // Exposed to InfectedNoSymptoms + compute_flow(Eigen::Index(InfectionTransition::ExposedToInfectedNoSymptoms), + Eigen::Index(InfectionTransition::SusceptibleToExposed), Eigen::Index(InfectionState::Exposed), dt); + // InfectedNoSymptoms to InfectedSymptoms + compute_flow(Eigen::Index(InfectionTransition::InfectedNoSymptomsToInfectedSymptoms), + Eigen::Index(InfectionTransition::ExposedToInfectedNoSymptoms), + Eigen::Index(InfectionState::InfectedNoSymptoms), dt); + // InfectedNoSymptoms to Recovered + compute_flow(Eigen::Index(InfectionTransition::InfectedNoSymptomsToRecovered), + Eigen::Index(InfectionTransition::ExposedToInfectedNoSymptoms), + Eigen::Index(InfectionState::InfectedNoSymptoms), dt); + // InfectedSymptoms to InfectedSevere + compute_flow(Eigen::Index(InfectionTransition::InfectedSymptomsToInfectedSevere), + Eigen::Index(InfectionTransition::InfectedNoSymptomsToInfectedSymptoms), + Eigen::Index(InfectionState::InfectedSymptoms), dt); + // InfectedSymptoms to Recovered + compute_flow(Eigen::Index(InfectionTransition::InfectedSymptomsToRecovered), + Eigen::Index(InfectionTransition::InfectedNoSymptomsToInfectedSymptoms), + Eigen::Index(InfectionState::InfectedSymptoms), dt); + // InfectedSevere to InfectedCritical + compute_flow(Eigen::Index(InfectionTransition::InfectedSevereToInfectedCritical), + Eigen::Index(InfectionTransition::InfectedSymptomsToInfectedSevere), + Eigen::Index(InfectionState::InfectedSevere), dt); + // InfectedCritical to Recovered + compute_flow(Eigen::Index(InfectionTransition::InfectedSevereToRecovered), + Eigen::Index(InfectionTransition::InfectedSymptomsToInfectedSevere), + Eigen::Index(InfectionState::InfectedSevere), dt); + // InfectedCritical to Dead + compute_flow(Eigen::Index(InfectionTransition::InfectedCriticalToDead), + Eigen::Index(InfectionTransition::InfectedSevereToInfectedCritical), + Eigen::Index(InfectionState::InfectedCritical), dt); + // InfectedCritical to Recovered + compute_flow(Eigen::Index(InfectionTransition::InfectedCriticalToRecovered), + Eigen::Index(InfectionTransition::InfectedSevereToInfectedCritical), + Eigen::Index(InfectionState::InfectedCritical), dt); +} + +void Model::update_compartment_from_flow(InfectionState infectionState, + std::vector const& IncomingFlows, + std::vector const& OutgoingFlows, + bool NaturalDeathispossible, ScalarType dt) +{ + Eigen::Index num_time_points = populations.get_num_time_points(); + + ScalarType updated_compartment = 0; + if (NaturalDeathispossible) { + updated_compartment = populations[num_time_points - 2][static_cast(infectionState)] * + (1 - parameters.get()); + } + else { + updated_compartment = populations[num_time_points - 2][static_cast(infectionState)]; + } + for (const InfectionTransition& inflow : IncomingFlows) { + updated_compartment += dt * transitions.get_last_value()[(int)inflow]; + } + for (const InfectionTransition& outflow : OutgoingFlows) { + updated_compartment -= dt * transitions.get_last_value()[(int)outflow]; + } + populations.get_last_value()[(int)infectionState] = updated_compartment; +} + +void Model::update_compartments(ScalarType dt) +{ + // Exposed + update_compartment_from_flow(InfectionState::Exposed, {InfectionTransition::SusceptibleToExposed}, + {InfectionTransition::ExposedToInfectedNoSymptoms}, true, dt); + + // InfectedNoSymptoms + update_compartment_from_flow( + InfectionState::InfectedNoSymptoms, {InfectionTransition::ExposedToInfectedNoSymptoms}, + {InfectionTransition::InfectedNoSymptomsToInfectedSymptoms, InfectionTransition::InfectedNoSymptomsToRecovered}, + true, dt); + + // InfectedSymptoms + update_compartment_from_flow( + InfectionState::InfectedSymptoms, {InfectionTransition::InfectedNoSymptomsToInfectedSymptoms}, + {InfectionTransition::InfectedSymptomsToInfectedSevere, InfectionTransition::InfectedSymptomsToRecovered}, true, + dt); + + // InfectedSevere + update_compartment_from_flow( + InfectionState::InfectedSevere, {InfectionTransition::InfectedSymptomsToInfectedSevere}, + {InfectionTransition::InfectedSevereToInfectedCritical, InfectionTransition::InfectedSevereToRecovered}, true, + dt); + + // InfectedCritical + update_compartment_from_flow( + InfectionState::InfectedCritical, {InfectionTransition::InfectedSevereToInfectedCritical}, + {InfectionTransition::InfectedCriticalToDead, InfectionTransition::InfectedCriticalToRecovered}, true, dt); + + // Recovered + update_compartment_from_flow(InfectionState::Recovered, + { + InfectionTransition::InfectedNoSymptomsToRecovered, + InfectionTransition::InfectedSymptomsToRecovered, + InfectionTransition::InfectedSevereToRecovered, + InfectionTransition::InfectedCriticalToRecovered, + }, + std::vector(), true, dt); + + // Dead + update_compartment_from_flow(InfectionState::Dead, {InfectionTransition::InfectedCriticalToDead}, + std::vector(), false, dt); +} + +void Model::compute_populationsize() +{ + m_totalpopulation.get_last_value()[0] = + std::accumulate(populations.get_last_value().begin(), populations.get_last_value().end(), 0); +} + +void Model::compute_forceofinfection(ScalarType dt) +{ + + Eigen::Index num_time_points = populations.get_num_time_points(); + ScalarType current_time = populations.get_last_time(); + + Eigen::Index calc_time_index = (Eigen::Index)std::ceil(m_calctime / dt) - 1; + ScalarType sum = 0; + + //Computation of phi_0 + ScalarType phi_0 = 0; + if (num_time_points <= calc_time_index) { + phi_0 = m_meaninfectivity[num_time_points] * + (populations[0][static_cast(InfectionState::InfectedNoSymptoms)] * + m_transitiondistributions_in_forceofinfection[0][num_time_points] + + populations[0][static_cast(InfectionState::InfectedSymptoms)] * + m_transitiondistributions_in_forceofinfection[1][num_time_points]) / + m_totalpopulation[num_time_points - 1][0]; + } + //Computation of f + ScalarType f = 0.; + ScalarType f_1 = 0.; + ScalarType f_2 = 0.; + ScalarType f_3 = 0.; + for (int i = 1; i <= calc_time_index; i++) { + ScalarType state_age_i = static_cast(i - 1) * dt; + //Compute sum for f_1: + f_1 += m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] + [current_time + 1 - i] * + parameters.get().eval(state_age_i) * + m_transitiondistributions_in_forceofinfection[0][i - 1]; + + //Compute sum for f_2: + f_2 += m_transitiondistributions_derivative[static_cast( + InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][num_time_points + 1 - i] * + parameters.get().eval(state_age_i) * + m_transitiondistributions_in_forceofinfection[1][i - 1]; + + //Compute sum for f_3: + sum = 0.; + for (int j = 1; j <= i; j++) { + ScalarType state_age_j = static_cast(j - 1) * dt; + sum += parameters.get()[static_cast( + InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] * + m_transitiondistributions_derivative[static_cast( + InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][num_time_points + 1 - j] * + parameters.get().eval(state_age_j) * + m_transitiondistributions_in_forceofinfection[1][j - 1]; + } + f_3 += m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] + [num_time_points + 1 - i] * + sum; + } + f = std::pow(dt, 2) * populations[0][static_cast(InfectionState::Exposed)] * + std::exp(-parameters.get() * current_time) * f_3 - + dt * populations[0][static_cast(InfectionState::InfectedNoSymptoms)] * + std::exp(-parameters.get() * current_time) * f_2 - + dt * populations[0][static_cast(InfectionState::Exposed)] * + std::exp(-parameters.get() * current_time) * f_1; + + // Computation of the rest + + //ERKLÄRUNG!!! + Eigen::Index starting_point = std::max(0, (int)num_time_points - (int)calc_time_index - 1); + + sum = 0.; + for (Eigen::Index i = starting_point; i < num_time_points - 1; i++) { + std::cout << " mean infectivitity at time " << num_time_points - 1 - i << " is " + << m_meaninfectivity[num_time_points - 1 - i] << "\n"; + sum += m_meaninfectivity[num_time_points - 1 - i] * populations[i + 1][(int)InfectionState::Susceptible] * + m_forceofinfection[i][0]; + } + + m_forceofinfection.get_last_value()[0] = + phi_0 + (dt * sum + f) * + (parameters.get().eval(current_time) * + parameters.get().get_cont_freq_mat().get_matrix_at(num_time_points)(0, 0)) / + m_totalpopulation[num_time_points - 1][0]; +} + +// ---- Functionality to set vectors with necessary information regarding TransitionDistributions. ---- +void Model::set_transitiondistributions_support_max(ScalarType dt) +{ + // The transition Susceptible to Exposed is not needed in the computations. + for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { + m_transitiondistributions_support_max[transition] = + parameters.get()[transition].get_support_max(dt, m_tol); + } +} + +void Model::set_calctime() +{ + // Transitions needed in the force of infection term. + std::vector> relevant_transitions = { + {(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms, + (int)InfectionTransition::InfectedNoSymptomsToRecovered}, + {(int)InfectionTransition::InfectedSymptomsToInfectedSevere, + (int)InfectionTransition::InfectedSymptomsToRecovered}}; + + m_calctime = std::max({m_transitiondistributions_support_max[relevant_transitions[0][0]], + m_transitiondistributions_support_max[relevant_transitions[0][1]], + m_transitiondistributions_support_max[relevant_transitions[1][0]], + m_transitiondistributions_support_max[relevant_transitions[1][1]]}); +} + +void Model::set_transitiondistributions(ScalarType dt) +{ + + // Transitions needed in the force of infection term. + std::vector> relevant_transitions = { + {(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms, + (int)InfectionTransition::InfectedNoSymptomsToRecovered}, + {(int)InfectionTransition::InfectedSymptomsToInfectedSevere, + (int)InfectionTransition::InfectedSymptomsToRecovered}}; + + // Determine the corresponding time index to m_calctime. + // Subtract 1 because in the last summand all TransitionDistributions evaluate to 0 (by definition of support_max). + Eigen::Index calc_time_index = (Eigen::Index)std::ceil(m_calctime / dt) - 1; + + // Compute the distributions from survival functions and transition probabilities starting in InfectedNoSymptoms and + // InfectedSymptims ont the force of infection term. + for (int contribution = 0; contribution < 2; contribution++) { + std::vector vec_contribution_to_foi(calc_time_index + 1, 0.); + for (Eigen::Index i = 0; i <= calc_time_index; i++) { + //Compute the state_age. + ScalarType state_age = i * dt; + vec_contribution_to_foi[i] = + parameters.get()[relevant_transitions[contribution][0]] * + parameters.get()[relevant_transitions[contribution][0]].eval(state_age) + + parameters.get()[relevant_transitions[contribution][1]] * + parameters.get()[relevant_transitions[contribution][1]].eval(state_age); + } + m_transitiondistributions_in_forceofinfection[contribution] = vec_contribution_to_foi; + } +} +void Model::set_transitiondistributions_derivative(ScalarType dt) +{ + // The transition SusceptibleToExposed is not needed in the computations. + for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { + Eigen::Index support_max_index = + (Eigen::Index)std::ceil(m_transitiondistributions_support_max[transition] / dt); + + // Create vec_derivative that stores the value of the approximated derivative for all necessary time points. + std::vector vec_derivative(support_max_index + 1, 0.); + + for (Eigen::Index i = 0; i <= support_max_index; i++) { + // Compute state_age. + ScalarType state_age = (ScalarType)i * dt; + //Compute the apprximate derivative by a backwards difference scheme. + vec_derivative[i] = (parameters.get()[transition].eval(state_age) - + parameters.get()[transition].eval(state_age - dt)) / + dt; + } + m_transitiondistributions_derivative[transition] = vec_derivative; + } +} + +void Model::set_meaninfectivity(ScalarType dt) +{ + + // Determine the corresponding time index. + Eigen::Index calc_time_index = (Eigen::Index)std::ceil(m_calctime / dt) - 1; + + m_meaninfectivity = std::vector(calc_time_index, 0.); + + // The mean infectivity is computed as exp(-NaturalDeathRate t) * (a_2(t)-a_1(t)). + for (int time_point_index = 1; time_point_index <= calc_time_index; time_point_index++) { + ScalarType a_1 = 0; + ScalarType a_2 = 0; + + ScalarType time_point_age = (ScalarType)time_point_index * dt; + //We compute a_1 and a_2 at time_point. + for (int i = 1; i <= time_point_index; i++) { + ScalarType state_age_i = static_cast(i) * dt; + //Computation of a_1. + a_1 += parameters.get().eval(state_age_i) * + m_transitiondistributions_in_forceofinfection[0][i] * + m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] + [time_point_index - i]; + //Computation of a_2. + ScalarType sum = 0; + for (int j = 1; j <= i; j++) { + ScalarType state_age_j = static_cast(j) * dt; + sum += + parameters.get().eval(state_age_j) * + m_transitiondistributions_in_forceofinfection[1][j] * + parameters.get()[( + int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] * + m_transitiondistributions_derivative[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] + [time_point_index - j]; + } + a_2 += m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] + [time_point_index - i] * + sum; + } + m_meaninfectivity[time_point_index] = + std::exp(-parameters.get() * time_point_age) * (std::pow(dt, 2) * a_2 - dt * a_1); + } +} +// void Model::set_initalvaluesforceofinfection(ScalarType dt) +// { +// // Determine the relevant calculation area. +// ScalarType calc_time = +// std::max({m_transitiondistributions_support_max[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms], +// m_transitiondistributions_support_max[(int)InfectionTransition::InfectedNoSymptomsToRecovered], +// m_transitiondistributions_support_max[(int)InfectionTransition::InfectedSymptomsToInfectedSevere], +// m_transitiondistributions_support_max[(int)InfectionTransition::InfectedSymptomsToRecovered]}); + +// Eigen::Index calc_time_index = (Eigen::Index)std::ceil(calc_time / dt) - 1; +// m_initalvaluesforceofinfection = std::vector(calc_time_index, 0.); + +// for (int time_point_index = 1; time_point_index < calc_time_index; time_point_index++) { +// ScalarType time_point_age = time_point_index / dt; +// // Evtl wieder hier einfügen wenn ich weiß wie ! +// //We start by adding the phi_0 term. +// // m_initalvaluesforceofinfection[time_point_index] = +// // m_meaninfectivity[time_point_index] * +// // (populations[static_cast(InfectionState::InfectedNoSymptoms)][0] * +// // m_transitiondistributions_in_forceofinfection[0][time_point_index] + +// // populations[static_cast(InfectionState::InfectedSymptoms)][0] * +// // m_transitiondistributions_in_forceofinfection[1][time_point_index]); + +// // Now we compute the f term, that is f=f_3-f_2-f_1. +// ScalarType f_1 = 0.; +// ScalarType f_2 = 0.; +// ScalarType f_3 = 0.; +// for (int i = 1; i <= time_point_index; i++) { +// ScalarType state_age_i = static_cast(i - 1) * dt; +// //Compute sum for f_1: +// f_1 += +// m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] +// [time_point_index + 1 - i] * +// parameters.get().eval(state_age_i) * +// m_transitiondistributions_in_forceofinfection[0][i - 1]; + +// //Compute sum for f_2: +// f_2 += m_transitiondistributions_derivative[static_cast( +// InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][time_point_index + 1 - i] * +// parameters.get().eval(state_age_i) * +// m_transitiondistributions_in_forceofinfection[1][i - 1]; + +// //Compute sum for f_3: +// ScalarType sum = 0.; +// for (int j = 1; j <= i; j++) { +// ScalarType state_age_j = static_cast(j - 1) * dt; +// sum += parameters.get()[static_cast( +// InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] * +// m_transitiondistributions_derivative[static_cast( +// InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][time_point_index + 1 - j] * +// parameters.get().eval(state_age_j) * +// m_transitiondistributions_in_forceofinfection[1][j - 1]; +// } +// f_3 += +// m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] +// [time_point_index + 1 - i] * +// sum; +// } +// m_initalvaluesforceofinfection[time_point_index] += +// std::pow(dt, 2) * populations[static_cast(InfectionState::Exposed)][0] * +// std::exp(-parameters.get() * time_point_age) * f_3 - +// dt * populations[static_cast(InfectionState::InfectedNoSymptoms)][0] * +// std::exp(-parameters.get() * time_point_age) * f_2 - +// dt * populations[static_cast(InfectionState::Exposed)][0] * +// std::exp(-parameters.get() * time_point_age) * f_1; +// } +// } + +// ---- Computation of the Reproduction number. ---- + +void Model::set_reproductionnumber_c(ScalarType dt) +{ + ScalarType sum = 0; + for (ScalarType mean_infectivity_i : m_meaninfectivity) { + sum += mean_infectivity_i; + } + m_reproductionnumber_c = parameters.get().eval(0) * + parameters.get().get_cont_freq_mat().get_matrix_at(0)(0, 0) * dt * sum; +} + +}; // namespace endisecir + +} // namespace mio diff --git a/cpp/models/ide_endemic_secir/model.h b/cpp/models/ide_endemic_secir/model.h new file mode 100644 index 0000000000..9ec9fbaa6a --- /dev/null +++ b/cpp/models/ide_endemic_secir/model.h @@ -0,0 +1,253 @@ +#ifndef IDE_END_SECIR_MODEL_H +#define IDE_END_SECIR_MODEL_H + +#include "ide_endemic_secir/infection_state.h" +#include "ide_endemic_secir/parameters.h" +#include "memilio/config.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/utils/time_series.h" + +#include "vector" +#include + +namespace mio +{ +namespace endisecir +{ +// Forward declaration of friend classes/functions of Model. +class Model; +class Simulation; + +class Model +{ + using ParameterSet = Parameters; + +public: + /** + * @brief Constructor to create an endemic IDE_SECIR model. + * + * @param[in] states_init A vector, containing the number of individuals in each compartment at time 0. + */ + + Model(TimeSeries&& states_init); + + /** + * @brief Checks constraints on model parameters and initial data. + * @return Returns true if one (or more) constraint(s) are not satisfied, otherwise false. + */ + bool check_constraints() const; + + /** + * @brief Setter for the tolerance used to calculate the maximum support of the TransitionDistributions. + * + * @param[in] new_tol New tolerance. + */ + void set_tol_for_support_max(ScalarType new_tol) + { + m_tol = new_tol; + } + + // ---- Public parameters. ---- + ParameterSet parameters; ///< ParameterSet of Model Parameters. + TimeSeries + transitions; ///< TimesSeries containing points of time and the corresponding number of individuals transitioning + // from one #InfectionState to another as defined in #Infection%s. + TimeSeries populations; ///< TimeSeries containing points of time and the corresponding number of people + // in defined #InfectionState%s. + +private: + // ---- Functionality for the iterations of a simulation. + + /** + * @brief Computes number of Susceptibles for the current last time in populations. + * + * Number is computed by using the previous number of Susceptibles, total population of the last time point and + * the force of infection (also from the last time point). + * Number is stored at the matching index in populations. + * + * @param[in] dt Time discretization step size. + */ + void compute_susceptibles(ScalarType dt); + + /** + * @brief Computes sizeof a flow + * + * Computes size of one Transition from #InfectionTransition, specified in idx_InfectionTransitions, for the time index + * current_time_index. + * + * @param[in] idx_InfectionTransitions Specifies the considered transition from #InfectionTransition + * @param[in] idx_IncomingFlow Index of the transition in #InfectionTransition, which goes to the considered starting + * compartment of the transition specified in idx_InfectionTransitions. Size of considered flow is calculated via + * the value of this incoming flow. + * @param[in] idx_CurrentCompartment Index of the Compartment we flow out. + * @param[in] current_time_index The time index the transition should be computed for. + * @param[in] dt Time discretization step size. + */ + void compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, Eigen::Index current_time_index, ScalarType dt); + + /** + * @brief Computes size of a flow + * + * Computes size of one Transition from #InfectionTransition, specified in idx_InfectionTransitions, for the current + * last time value in transitions. + * + * @param[in] idx_InfectionTransitions Specifies the considered transition from #InfectionTransition + * @param[in] idx_IncomingFlow Index of the transition in #InfectionTransition, which goes to the considered starting + * compartment of the transition specified in idx_InfectionTransitions. Size of considered flow is calculated via + * the value of this incoming flow. + * @param[in] idx_CurrentCompartment Index of the Compartment we flow out. + * @param[in] dt Time discretization step size. + */ + void compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, ScalarType dt); + + /** + * @brief Sets all required transitions for the current last timestep in transitions. + * + * New values are stored in transitions. Most values are computed via the function compute_flow() + * + * @param[in] dt time discretization step size. + */ + void flows_currents_timestep(ScalarType dt); + + /** + * @brief Updates the values of one compartment, specified in infectionState, using the transitions. + * + * New value is stored in populations. The values are calculated using the compartment size in the previous + * time step and the related flows of the current time step. + * Therefore the flows of the current time step should be calculated before using this function. + * @param[in] infectionState Specifies the #InfectionState we want to update. + * @param[in] IncomingFlows + * @param[in] OutgoingFlows + * @param[in] NaturalDeathispossible Boolian that determines if there is the possibility of Natural Death in infectionState. + */ + void update_compartment_from_flow(InfectionState infectionState, + std::vector const& IncomingFlows, + std::vector const& OutgoingFlowsm, + bool NaturalDeathispossible, ScalarType dt); + + /** + * @brief Updates the values of all compartments except Susceptible + * + * New value is stored in populations. Values are computed via the function update_compartment_from_flow + */ + void update_compartments(ScalarType dt); + + /** + * @brief Compute the population size for the current last time in populations. + * + * The population size is computed as the sum of all compartments. + * The population size is stored in the vector m_populationsize. + */ + void compute_populationsize(); + + /** + * @brief Computes the force of infection for the current last time in transitions. + * + * Computed value is stored in m_forceofinfection. + * + * @param[in] dt Time discretization step size. + */ + void compute_forceofinfection(ScalarType dt); + + // ---- Functionality to set vectors with necessary information regarding TransitionDistributions. ---- + /** + * @brief Setter for the vector m_transitiondistributions_support_max that contains the support_max for all + * TransitionDistributions. + * + * This determines how many summands are required when calculating flows, the force of infection or compartments. + * + * @param[in] dt Time step size. + */ + void set_transitiondistributions_support_max(ScalarType dt); + + /** + * @brief Setter for the vector m_transitiondistributions. + * + * In the computation of the force of infection in the initialization function of the force of infection term, + * we evaluate the survival functions of the TransitionDistributions InfectedNoSymptomsToInfectedSymptoms, + * InfectedNoSymptomsToRecovered, InfectedSymptomsToInfectedSevere and InfectedSymptomsToRecovered, weighted by + * the corresponding TransitionProbabilities, at the same time points. + * Here, we compute these contributions to the force of infection term, an store the vector + * m_transitiondistributions_in_forceofinfection so that we can access this vector for all following computations. + * + * @param[in] dt Time step size. + */ + void set_transitiondistributions(ScalarType dt); + + void set_calctime(); + + /** + * @brief Setter for the vector m_transitiondistributions_derivative that contains the approximated derivative for + * all TransitionDistributions for all necessary time points. + * + * The derivative is approximated using a backwards difference scheme. + * The number of necessary time points for each TransitionDistribution is determined using + * m_transitiondistributions_support_max. + * + * @param[in] dt Time step size. + */ + void set_transitiondistributions_derivative(ScalarType dt); + + /** + *@brief Setter for the vector m_meaninfectivity that contains the approximated value of the mean infectivity for all + * for all necessary time points. + * + * @param[in] dt Time step size. + */ + void set_meaninfectivity(ScalarType dt); + + // /** + // *@brief Setter for the vector m_initalvaluesforceofinfection that contains the approximated value of the part of the + // * force of infection term that is influenced by the initial values. + // * + // * @param[in] dt Time step size. + // */ + // void set_initalvaluesforceofinfection(ScalarType dt); + + /** + * @brief Setter for the Reproduction number R_c. + * + */ + void set_reproductionnumber_c(ScalarType dt); + + // ---- Private parameters. ---- + + TimeSeries m_forceofinfection{ + TimeSeries(1)}; ///< Vector containing the Force of infection term for every time point, + // needed for the numerical scheme. + TimeSeries m_totalpopulation{TimeSeries( + 1)}; ///< Vector containing the total population size of the considered region for each time point. + ScalarType m_reproductionnumber_c; ///< The control Reproduction number + + ScalarType m_tol{1e-10}; ///< Tolerance used to calculate the maximum support of the TransitionDistributions. + ScalarType m_calctime{ + 0}; ///< A ScalarType wit he calc time determined by the support max of the transition distributions. + std::vector m_transitiondistributions_support_max{ + std::vector((int)InfectionTransition::Count, 0.)}; ///< A vector containing the support_max + // for all TransitionDistributions. + std::vector> m_transitiondistributions_in_forceofinfection{ + std::vector>( + 2, std::vector(1, 0.))}; ///> A vectpr containing the weighted TransitionDistributions + // needed in the compuation of the initial functions for the compartments and the mean infectivity at all necessary + // time points. + std::vector> m_transitiondistributions_derivative{std::vector>( + (int)InfectionTransition::Count, std::vector(1, 0.))}; ///> A Vector containing + // the approximated derivative for all TransitionDistributions for all necessary time points. + std::vector + m_meaninfectivity; ///> a vector containing the approximated mean infectivity for all time points. + + std::vector m_initalvaluesforceofinfection; ///> a vector containing the parts of the force of infection + // that are influenced by the inital values of our model, i.e phi_0 and f. + + // ---- Friend classes/functions. ---- + // In the Simulation class, the actual simulation is performed which is why it needs access to the here + // defined (and private) functions to solve the model equations. + friend class Simulation; +}; + +} // namespace endisecir +} // namespace mio + +#endif //IDE_END_SECIR_MODEL_H \ No newline at end of file diff --git a/cpp/models/ide_endemic_secir/parameters.h b/cpp/models/ide_endemic_secir/parameters.h new file mode 100644 index 0000000000..e09cf6e8f9 --- /dev/null +++ b/cpp/models/ide_endemic_secir/parameters.h @@ -0,0 +1,314 @@ +#ifndef IDE_END_SECIR_PARAMS_H +#define IDE_END_SECIR_PARAMS_H + +#include "memilio/config.h" +#include "memilio/epidemiology/contact_matrix.h" +#include "memilio/math/floating_point.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/utils/parameter_set.h" +#include "ide_endemic_secir/infection_state.h" +#include "memilio/epidemiology/state_age_function.h" +#include "memilio/epidemiology/uncertain_matrix.h" + +#include +#include +#include + +namespace mio +{ +namespace endisecir +{ + +/************************************************** +* Define Parameters of the IDE-END-SECIHURD model * +**************************************************/ + +/** + * @brief Transitions distribution for each transition in #Infection Transition. + * + * we use as a default SmootherCosine functions for all transitions with m_paramter=2. + */ + +struct TransitionDistributions { + using Type = std::vector; + static Type get_default() + { + SmootherCosine smoothcos(2.0); + StateAgeFunctionWrapper delaydistribution(smoothcos); + return Type((int)InfectionTransition::Count, delaydistribution); + } + + static std::string mame() + { + return "TransitionDistributions"; + } +}; + +/** + * @brief Defines the probability for each possible transitions to take this transition- + */ + +struct TransitionProbabilities { + /*For consistency, also define TransitionProbabilities for each transition in #InfectionTransition. + Transition Probabilities should be set to 1 if there is no possible other flow from starting compartment.*/ + using Type = std::vector; + static Type get_default() + { + std::vector probs((int)InfectionTransition::Count, 0.5); + // Set the following probablities to 1 as there is no other option to go anywhere else. + probs[Eigen::Index(InfectionTransition::SusceptibleToExposed)] = 1; + probs[Eigen::Index(InfectionTransition::ExposedToInfectedNoSymptoms)] = 1; + return Type(probs); + } + static std::string name() + { + return "TransitionsProbabilities"; + } +}; + +/** + * @brief The contact patterns within the society are modelled using an UncertainContactMatrix. + */ +struct ContactPatterns { + using Type = UncertainContactMatrix; + static Type get_default() + { + ContactMatrixGroup contact_matrix = ContactMatrixGroup(1, 1); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); + return Type(contact_matrix); + } + static std::string name() + { + return "ContactPatterns"; + } +}; + +/** +* @brief Probability of getting infected from a contact. +*/ +struct TransmissionProbabilityOnContact { + using Type = StateAgeFunctionWrapper; + static Type get_default() + { + ConstantFunction constfunc(1.0); + return Type(constfunc); + } + static std::string name() + { + return "TransmissionProbabilityOnContact"; + } +}; + +/** +* @brief The relative InfectedNoSymptoms infectability. +*/ +struct RelativeTransmissionNoSymptoms { + using Type = StateAgeFunctionWrapper; + static Type get_default() + { + ConstantFunction constfunc(1.0); + return Type(constfunc); + } + static std::string name() + { + return "RelativeTrabsnissionNoSymptoms"; + } +}; + +/** +* @brief The risk of infection from symptomatic cases in the SECIR model. +*/ +struct RiskOfInfectionFromSymptomatic { + using Type = StateAgeFunctionWrapper; + static Type get_default() + { + ConstantFunction constfunc(1.0); + return Type(constfunc); + } + static std::string name() + { + return "RiskOfInfectionFromSymptomatic"; + } +}; + +/** + * @brief The natural birth rate. + */ +struct NaturalBirthRate { + using Type = ScalarType; + static Type get_default() + { + return Type(5e-5); + } + static std::string name() + { + return "NaturalBirthRate"; + } +}; + +/** + * @brief The natural death rate. + */ +struct NaturalDeathRate { + using Type = ScalarType; + static Type get_default() + { + return Type(3e-5); + } + static std::string name() + { + return "NaturalDeathRate"; + } +}; + +// Define Parameterset for IDE-END-SECIR model. +using ParametersBase = + ParameterSet; + +/** + * @brief Parameters of an endemic SECIR/SECIHURD model. + */ + +class Parameters : public ParametersBase +{ +public: + /** + * @brief Checks whether all Parameters satisfy their corresponding constraints and logs an error. + */ + bool check_constraints() const + { + // For paramerers potentially depending on the infectious age, the values are checked equidistantly on a + // realistic maximum window. + size_t infectious_window_check = 50; // parameter defining minmal window on x-axis. + + //Check if all the probabilitys are between 0 and 1. + for (size_t i = 0; i < infectious_window_check; i++) { + if (this->get().eval((static_cast(i))) < 0.0 || + this->get().eval(static_cast(i)) > 1.0) { + log_error( + "Constraint check: TransmissionProbabilityOnContact smaller {:d} or larger {:d} at some time {:d}", + 0, 1, i); + return true; + } + } + + for (size_t i = 0; i < infectious_window_check; i++) { + if (this->get().eval((static_cast(i))) < 0.0 || + this->get().eval(static_cast(i)) > 1.0) { + log_error( + "Constraint check: RelativeTransmissionNoSymptoms smaller {:d} or larger {:d} at some time {:d}", 0, + 1, i); + return true; + } + } + + for (size_t i = 0; i < infectious_window_check; i++) { + if (this->get().eval((static_cast(i))) < 0.0 || + this->get().eval(static_cast(i)) > 1.0) { + log_error( + "Constraint check: RiskOfInfectionFromSymptomatic smaller {:d} or larger {:d} at some time {:d}", 0, + 1, i); + return true; + } + } + + for (size_t i = 0; i < static_cast(InfectionTransition::Count); i++) { + if (this->get()[i] < 0.0 || this->get()[i] > 1.0) { + log_error("Constraint check: One parameter in TransitionProbabilities smaller {:d} or larger {:d}", 0, + 1); + return true; + } + } + + // The TransitionProbabilities SusceptibleToExposed and ExposedToInfectedNoSymptoms should be 1. + if (!floating_point_equal( + this->get()[static_cast(InfectionTransition::SusceptibleToExposed)], 1.0, + 1e-14)) { + log_error("Constraint check: Parameter transition probability for SusceptibleToExposed unequal to {:d}", 1); + return true; + } + + if (!floating_point_equal(this->get()[static_cast( + InfectionTransition::ExposedToInfectedNoSymptoms)], + 1.0, 1e-14)) { + log_error("Constraint check: Parameter transition probability for ExposedToInfectedNoSymptoms unequal " + "to {:d}", + 1); + return true; + } + + // All TransitionProbabilities where the Transition starts in the same compartment should sum up to 1. + + if (!floating_point_equal(this->get()[static_cast( + InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] + + this->get()[static_cast( + InfectionTransition::InfectedNoSymptomsToRecovered)], + 1.0, 1e-14)) { + log_error("Constraint check: Sum of transition probability for InfectedNoSymptomsToInfectedSymptoms and " + "InfectedNoSymptomsToRecovered not equal to {:d}", + 1); + return true; + } + + if (!floating_point_equal(this->get()[static_cast( + InfectionTransition::InfectedSymptomsToInfectedSevere)] + + this->get()[static_cast( + InfectionTransition::InfectedSymptomsToRecovered)], + 1.0, 1e-14)) { + log_error("Constraint check: Sum of transition probability for InfectedSymptomsToInfectedSevere and " + "InfectedSymptomsToRecovered not equal to {:d}", + 1); + return true; + } + + if (!floating_point_equal(this->get()[static_cast( + InfectionTransition::InfectedSevereToInfectedCritical)] + + this->get()[static_cast( + InfectionTransition::InfectedSevereToRecovered)], + 1.0, 1e-14)) { + log_error("Constraint check: Sum of transition probability for InfectedSevereToInfectedCritical and " + "InfectedSevereToRecovered not equal to {:d}", + 1); + return true; + } + + if (!floating_point_equal( + this->get()[static_cast(InfectionTransition::InfectedCriticalToDead)] + + this->get()[static_cast( + InfectionTransition::InfectedCriticalToRecovered)], + 1.0, 1e-14)) { + log_error("Constraint check: Sum of transition probability for InfectedCriticalToDead and " + "InfectedCriticalToRecovered not equal to {:d}", + 1); + return true; + } + + /* The first entry of TransitionDistributions is not checked because the distribution S->E is never used + (and it makes no sense to use the distribution). The support does not need to be valid.*/ + for (size_t i = 1; i < static_cast(InfectionTransition::Count); i++) { + if (floating_point_less(this->get()[i].get_support_max(10), 0.0, 1e-14)) { + log_error("Constraint check: One function in TransitionDistributions has invalid support."); + return true; + } + } + + if (this->get() < 0.0) { + log_warning("Constraint check: Parameter NaturalBirthRate should be greater than {:d}", 0); + return true; + } + + if (this->get() < 0.0) { + log_warning("Constraint check: Parameter NaturalDeathRate should be greater than {:d}", 0); + return true; + } + + return false; + } +}; + +} // namespace endisecir + +} // namespace mio + +#endif //IDE_END_SECIR_PARAMS_H \ No newline at end of file diff --git a/cpp/models/ide_endemic_secir/simulation.cpp b/cpp/models/ide_endemic_secir/simulation.cpp new file mode 100644 index 0000000000..6d61c1ac66 --- /dev/null +++ b/cpp/models/ide_endemic_secir/simulation.cpp @@ -0,0 +1,61 @@ + +#include "ide_endemic_secir/simulation.h" +#include "ide_endemic_secir/model.h" +#include "memilio/config.h" +#include "memilio/utils/time_series.h" +#include + +namespace mio +{ +namespace endisecir +{ + +void Simulation::advance(ScalarType tmax) +{ + mio::log_info("Simulating IDE-END-SECIR from t0 = {} until tmax = {} with dt = {}.", + m_model->transitions.get_last_time(), tmax, m_dt); + + m_model->set_transitiondistributions_support_max(m_dt); + m_model->set_calctime(); + m_model->set_transitiondistributions(m_dt); + m_model->set_transitiondistributions_derivative(m_dt); + m_model->set_meaninfectivity(m_dt); + // m_model->set_initalvaluesforceofinfection(m_dt); + m_model->set_reproductionnumber_c(m_dt); + + // For every time step: + while (m_model->transitions.get_last_time() < tmax - m_dt / 2) { + + m_model->transitions.add_time_point(m_model->transitions.get_last_time() + m_dt); + m_model->populations.add_time_point(m_model->populations.get_last_time() + m_dt); + m_model->m_forceofinfection.add_time_point(m_model->m_forceofinfection.get_last_time() + m_dt); + m_model->m_totalpopulation.add_time_point(m_model->m_totalpopulation.get_last_time() + m_dt); + + // Compute susceptibles: + m_model->compute_susceptibles(m_dt); + + // Compute flows: + m_model->flows_currents_timestep(m_dt); + + // Compute remaining compartments: + m_model->update_compartments(m_dt); + + // Compute m_populationsize: + m_model->compute_populationsize(); + + // Compute m_forceofinfection; + m_model->compute_forceofinfection(m_dt); + } +} + +TimeSeries simulate(ScalarType tmax, ScalarType dt, Model const& m_model) +{ + m_model.check_constraints(); + Simulation sim(m_model, dt); + sim.advance(tmax); + return sim.get_compartments(); +} + +} // namespace endisecir + +} // namespace mio diff --git a/cpp/models/ide_endemic_secir/simulation.h b/cpp/models/ide_endemic_secir/simulation.h new file mode 100644 index 0000000000..9859a9ed57 --- /dev/null +++ b/cpp/models/ide_endemic_secir/simulation.h @@ -0,0 +1,103 @@ +#ifndef IDE_END_SECIR_SIMULATION_H +#define IDE_END_SECIR_SIMULATION_H + +#include "ide_endemic_secir/model.h" +#include "memilio/config.h" +#include "memilio/utils/time_series.h" +#include + +namespace mio +{ +namespace endisecir +{ + +class Simulation +{ +public: + Simulation(Model const& model, ScalarType dt = 0.1) + : m_model(std::make_unique(model)) + , m_dt(dt) + { + } + + /** + * @brief Run the simulation until time tmax. + */ + void advance(ScalarType tmax); + + /** + * @brief Get the result of the simulation for the compartments + * Return the number of persons in all #InfectionState%s + */ + TimeSeries get_compartments() + { + return m_model->populations; + } + + /** + * @brief Get the result of the simulation for the compartments + * Return the number of persons in all #InfectionState%s + */ + TimeSeries& get_compartments() const + { + return m_model->populations; + } + + /** + * @brief Get the transitions between the different #InfectionState%s. + */ + TimeSeries const& get_transitions() + { + return m_model->transitions; + } + + TimeSeries const& get_forceofinfections() + { + return m_model->m_forceofinfection; + } + + TimeSeries const& get_totalpopulations() + { + return m_model->m_totalpopulation; + } + + ScalarType const& get_reproductionnumber_c() + { + return m_model->m_reproductionnumber_c; + } + + /** + * @brief returns the simulation model used in simulation. + */ + const Model& get_model() const + { + return *m_model; + } + + /** + * @brief returns the simulation model used in simulation. + */ + Model& get_model() + { + return *m_model; + } + + /** + * @brief get the size of the time step of the simulation. + */ + ScalarType get_stepsize() + { + return m_dt; + } + +private: + std::unique_ptr m_model; ///< Unique pointer to the simulated Model. + ScalarType m_dt; ///< Time step used for numerical computations in simulation. +}; + +TimeSeries simulate(ScalarType tmax, ScalarType dt, Model const& model); + +} // namespace endisecir +} // namespace mio + +#endif //IDE_END_SECIR_SIMULATION_H \ No newline at end of file diff --git a/cpp/models/ide_secir/model.h b/cpp/models/ide_secir/model.h index 98cff9ea7b..bb96e033e0 100644 --- a/cpp/models/ide_secir/model.h +++ b/cpp/models/ide_secir/model.h @@ -68,7 +68,7 @@ class Model CustomIndexArray total_confirmed_cases_init = CustomIndexArray()); // ---- Additional functionality such as constraint checking, setters and getters, etc. ---- - /** + /**c * @brief Checks constraints on model parameters and initial data. * @return Returns true if one (or more) constraint(s) are not satisfied, otherwise false. */ diff --git a/cpp/models/ide_secir/simulation.h b/cpp/models/ide_secir/simulation.h index ce5cce5f28..688347fce8 100644 --- a/cpp/models/ide_secir/simulation.h +++ b/cpp/models/ide_secir/simulation.h @@ -1,3 +1,4 @@ + /* * Copyright (C) 2020-2025 MEmilio * From 33b3da2a3930b93c2728eebca43b7347de04f540 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Thu, 8 May 2025 13:07:26 +0200 Subject: [PATCH 02/22] Implemented funcionality to study the long term behavior of the model --- cpp/examples/ide_endemic_secir.cpp | 62 ++++--- cpp/models/ide_endemic_secir/model.cpp | 179 ++++++++++++++++++-- cpp/models/ide_endemic_secir/model.h | 61 +++++-- cpp/models/ide_endemic_secir/simulation.cpp | 7 + cpp/models/ide_endemic_secir/simulation.h | 21 +++ 5 files changed, 288 insertions(+), 42 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index ddd4619ff0..d0e7d34f7e 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -4,13 +4,13 @@ #include "ide_endemic_secir/simulation.h" #include "ide_endemic_secir/infection_state.h" #include "memilio/config.h" -#include "memilio/epidemiology/age_group.h" #include "memilio/math/eigen.h" #include "memilio/utils/custom_index_array.h" #include "memilio/utils/time_series.h" #include "memilio/epidemiology/uncertain_matrix.h" #include "memilio/epidemiology/state_age_function.h" #include "memilio/data/analyze_result.h" +#include #include #include @@ -18,7 +18,7 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 10; + ScalarType tmax = 300; ScalarType dt = 1; int num_states = static_cast(mio::endisecir::InfectionState::Count); @@ -30,13 +30,13 @@ int main() Vec vec_init(num_states); vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = 15000.; - vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = 50.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = 100.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = 200.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedSevere)] = 90.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedCritical)] = 50.; - vec_init[static_cast(mio::endisecir::InfectionState::Recovered)] = 300.; - vec_init[static_cast(mio::endisecir::InfectionState::Dead)] = 5.; + vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = 40.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSevere)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedCritical)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::Recovered)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::Dead)] = 0.; init.add_time_point(0, vec_init); @@ -44,14 +44,14 @@ int main() //Set working parameters - mio::ExponentialSurvivalFunction exp(7.0); - mio::StateAgeFunctionWrapper delaydistribution(exp); - std::vector vec_delaydistribution(num_transitions, delaydistribution); - - // mio::SmootherCosine smoothcos(4.0); - // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + // mio::ExponentialSurvivalFunction exp(7.0); + // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); + mio::SmootherCosine smoothcos(8.0); + mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + std::vector vec_delaydistribution(num_transitions, delaydistribution); + model.parameters.get() = vec_delaydistribution; std::vector vec_prob(num_transitions, 0.5); @@ -75,17 +75,41 @@ int main() model.parameters.get() = exponential_prob; model.parameters.get() = exponential_prob; - model.parameters.set(9e-5); - model.parameters.set(3e-5); + model.parameters.set(5e-3); + model.parameters.set(2e-3); // start the simulation. mio::endisecir::Simulation sim(model, dt); sim.advance(tmax); auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); + interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); - sim.get_transitions().print_table( - {"S->E 1", "E->C 1", "C->I 1", "C->R 1", "I->H 1", "I->R 1", "H->U 1", "H->R 1", "U->D 1", "U->R 1"}, 16, 8); + // Uncomment to print the reproduction number std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; + + // Uncomment to print the transitions. + // sim.get_transitions().print_table( + // {"S->E 1", "E->C 1", "C->I 1", "C->R 1", "I->H 1", "I->R 1", "H->U 1", "H->R 1", "U->D 1", "U->R 1"}, 16, 8); + + // Uncomment to print the normalized compartments. + sim.get_normalizedcompartments().print_table({"s", "e", "c", "i", "h", "u", "r", "d "}, 16, 8); + + // Uncomment to print the total population size. + sim.get_totalpopulations().print_table({"N"}, 16, 9); + + // Uncomment to print the force of infection. + sim.get_forceofinfections().print_table({"FoI"}, 16, 8); + + std::vector equi = sim.get_equilibriumcompartments(); + std::cout << "Equilibrium normalized compartments: \n"; + std::cout << "foi* " << sim.get_equilibrium_forceofinfection() << "\n"; + std::cout << "s* " << equi[(int)mio::endisecir::InfectionState::Susceptible] << "\n"; + std::cout << "e* " << equi[(int)mio::endisecir::InfectionState::Exposed] << "\n"; + std::cout << "c* " << equi[(int)mio::endisecir::InfectionState::InfectedNoSymptoms] << "\n"; + std::cout << "i* " << equi[(int)mio::endisecir::InfectionState::InfectedSymptoms] << "\n"; + std::cout << "h* " << equi[(int)mio::endisecir::InfectionState::InfectedSevere] << "\n"; + std::cout << "u* " << equi[(int)mio::endisecir::InfectionState::InfectedCritical] << "\n"; + std::cout << "r* " << equi[(int)mio::endisecir::InfectionState::Recovered] << "\n"; } \ No newline at end of file diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index 30d7936ca0..3136130376 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -9,6 +9,7 @@ #include "vector" #include #include +#include #include #include @@ -27,10 +28,19 @@ Model::Model(TimeSeries&& states_init) 0, TimeSeries::Vector::Constant(static_cast(InfectionTransition::Count), 0.)); // Set population size at start timt t0. - ScalarType init_populationsize = std::accumulate(populations[0].begin(), populations[0].end(), 0); + ScalarType init_populationsize = + std::accumulate(populations[0].begin(), populations[0].end(), 0) - populations[0][(int)InfectionState::Dead]; m_totalpopulation.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); // Set the force of infection at start time t0. m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); + + //Set normalized_populations at start time t0. + TimeSeries::Vector vec_normalizedpopulations = + TimeSeries::Vector(Eigen::Index(InfectionState::Count) - 1); + for (int infection_state = 0; infection_state < Eigen::Index(InfectionState::Count) - 1; infection_state++) { + vec_normalizedpopulations[infection_state] = populations[0][infection_state] / m_totalpopulation[0][0]; + } + m_normalizedpopulations.add_time_point(0, vec_normalizedpopulations); } bool Model::check_constraints() const @@ -64,19 +74,30 @@ void Model::compute_susceptibles(ScalarType dt) void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, Eigen::Index idx_CurrentCompartment, Eigen::Index current_time_index, ScalarType dt) { + Eigen::Index calc_time_index = + (Eigen::Index)std::ceil(m_transitiondistributions_support_max[idx_InfectionTransitions] / dt); + ScalarType sum = 0; - for (Eigen::Index i = 0; i < current_time_index; i++) { + //Determine the starting point of the for loop. + Eigen::Index starting_point = std::max(0, (int)current_time_index - (int)calc_time_index); + for (Eigen::Index i = starting_point; i < current_time_index; i++) { sum += transitions[i + 1][idx_IncomingFlow] * std::exp((-parameters.get()) * (current_time_index - i)) * m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; } - transitions.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions] * sum - - std::exp((-parameters.get()) * (current_time_index)) * - populations[0][idx_CurrentCompartment] * - parameters.get()[idx_InfectionTransitions] * - m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; + if (current_time_index <= calc_time_index) { + transitions.get_value(current_time_index)[idx_InfectionTransitions] = + (-dt) * parameters.get()[idx_InfectionTransitions] * sum - + std::exp((-parameters.get()) * (current_time_index)) * + populations[0][idx_CurrentCompartment] * + parameters.get()[idx_InfectionTransitions] * + m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; + } + else { + transitions.get_value(current_time_index)[idx_InfectionTransitions] = + (-dt) * parameters.get()[idx_InfectionTransitions] * sum; + } } void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, @@ -204,7 +225,16 @@ void Model::update_compartments(ScalarType dt) void Model::compute_populationsize() { m_totalpopulation.get_last_value()[0] = - std::accumulate(populations.get_last_value().begin(), populations.get_last_value().end(), 0); + std::accumulate(populations.get_last_value().begin(), populations.get_last_value().end(), 0) - + populations.get_last_value()[(int)InfectionState::Dead]; +} + +void Model::compute_normalizedcompartments() +{ + for (int infection_state = 0; infection_state < Eigen::Index(InfectionState::Count) - 1; infection_state++) { + m_normalizedpopulations.get_last_value()[infection_state] = + populations.get_last_value()[infection_state] / m_totalpopulation.get_last_value()[0]; + } } void Model::compute_forceofinfection(ScalarType dt) @@ -269,13 +299,11 @@ void Model::compute_forceofinfection(ScalarType dt) // Computation of the rest - //ERKLÄRUNG!!! + // Determine the starting point of the for loop. Eigen::Index starting_point = std::max(0, (int)num_time_points - (int)calc_time_index - 1); sum = 0.; for (Eigen::Index i = starting_point; i < num_time_points - 1; i++) { - std::cout << " mean infectivitity at time " << num_time_points - 1 - i << " is " - << m_meaninfectivity[num_time_points - 1 - i] << "\n"; sum += m_meaninfectivity[num_time_points - 1 - i] * populations[i + 1][(int)InfectionState::Susceptible] * m_forceofinfection[i][0]; } @@ -474,7 +502,7 @@ void Model::set_meaninfectivity(ScalarType dt) // } // } -// ---- Computation of the Reproduction number. ---- +// ---- Functionality for the model analysis. ---- void Model::set_reproductionnumber_c(ScalarType dt) { @@ -486,6 +514,131 @@ void Model::set_reproductionnumber_c(ScalarType dt) parameters.get().get_cont_freq_mat().get_matrix_at(0)(0, 0) * dt * sum; } +void Model::set_probability_of_transition(ScalarType dt) +{ + + for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { + Eigen::Index support_max_index = + (Eigen::Index)std::ceil(m_transitiondistributions_support_max[transition] / dt); + ScalarType sum = 0.; + for (int i = 0; i <= support_max_index; i++) { + ScalarType state_age_i = static_cast(i) * dt; + sum -= std::exp(-parameters.get() * state_age_i) * + parameters.get()[transition] * + m_transitiondistributions_derivative[transition][i]; + } + m_probabilityoftransition[transition] = dt * sum; + } +} + +//TODO schönere implementierung überlegen, die evtl m_transitiondistributions_in_forceofinfection verwendet!!!! +void Model::set_meansojourntime(ScalarType dt) +{ + ScalarType sum = 0; + //Exposed State: + Eigen::Index support_max_index = (Eigen::Index)std::ceil( + m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms] / dt); + for (int i = 0; i <= support_max_index; i++) { + ScalarType state_age_i = static_cast(i) * dt; + sum += parameters.get()[(int)InfectionTransition::ExposedToInfectedNoSymptoms].eval( + state_age_i) * + std::exp(-parameters.get() * state_age_i); + } + m_meaninfectivity[(int)InfectionState::Exposed] = dt * sum; + + // Other Infected States: + // Transitions needed to compute the mean sojourn time of the other states. + std::vector> relevant_transitions_with_state = { + {(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms, + (int)InfectionTransition::InfectedNoSymptomsToRecovered, (int)InfectionState::InfectedNoSymptoms}, + {(int)InfectionTransition::InfectedSymptomsToInfectedSevere, + (int)InfectionTransition::InfectedSymptomsToRecovered, (int)InfectionState::InfectedSymptoms}, + {(int)InfectionTransition::InfectedSymptomsToInfectedSevere, + (int)InfectionTransition::InfectedSymptomsToRecovered, (int)InfectionState::InfectedSevere}, + {(int)InfectionTransition::InfectedSevereToInfectedCritical, + (int)InfectionTransition::InfectedSevereToRecovered, (int)InfectionState::InfectedCritical}}; + + for (int contribution = 0; contribution < 4; contribution++) { + support_max_index = (Eigen::Index)std::ceil( + std::max(m_transitiondistributions_support_max[relevant_transitions_with_state[contribution][0]], + m_transitiondistributions_support_max[relevant_transitions_with_state[contribution][1]]) / + dt); + sum = 0; + for (int i = 0; i <= support_max_index; i++) { + ScalarType state_age_i = static_cast(i) * dt; + sum += + (parameters.get()[relevant_transitions_with_state[contribution][0]] * + parameters.get()[relevant_transitions_with_state[contribution][0]].eval( + state_age_i) + + parameters.get()[relevant_transitions_with_state[contribution][1]] * + parameters.get()[relevant_transitions_with_state[contribution][1]].eval( + state_age_i)) * + std::exp(-parameters.get() * state_age_i); + } + m_meansojourntime[relevant_transitions_with_state[contribution][2]] = dt * sum; + } +} + +void Model::set_equilibrium() +{ + // Case of the disease free equilibrium. + if (m_reproductionnumber_c < 1) { + m_equilibriumforceofinfection = 0; + m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] = 1; + m_equilibriumnormalizedcompartments[(int)InfectionState::Exposed] = 0; + m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedNoSymptoms] = 0; + m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedSymptoms] = 0; + m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedSevere] = 0; + m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedCritical] = 0; + m_equilibriumnormalizedcompartments[(int)InfectionState::Recovered] = 0; + } + // Case of the endemic equilibrium. + + if (m_reproductionnumber_c > 1) { + + //Set probabilities that we transition to a specific compartment during the disease. + ScalarType transition_to_INS = m_probabilityoftransition[(int)InfectionTransition::ExposedToInfectedNoSymptoms]; + ScalarType transition_to_ISy = + transition_to_INS * + m_probabilityoftransition[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms]; + ScalarType transition_to_ISe = + transition_to_ISy * m_probabilityoftransition[(int)InfectionTransition::InfectedSymptomsToInfectedSevere]; + ScalarType transition_to_IC = + transition_to_ISe * m_probabilityoftransition[(int)InfectionTransition::InfectedSevereToInfectedCritical]; + ScalarType transition_to_D = + transition_to_IC * m_probabilityoftransition[(int)InfectionTransition::InfectedCriticalToDead]; + ScalarType transition_to_R = + m_probabilityoftransition[(int)InfectionTransition::InfectedNoSymptomsToRecovered] * transition_to_INS + + m_probabilityoftransition[(int)InfectionTransition::InfectedSymptomsToRecovered] * transition_to_ISy + + m_probabilityoftransition[(int)InfectionTransition::InfectedSevereToRecovered] * transition_to_ISe + + m_probabilityoftransition[(int)InfectionTransition::InfectedCriticalToRecovered] * transition_to_IC; + + m_equilibriumforceofinfection = + parameters.get() * (m_reproductionnumber_c - 1) + + (parameters.get() * transition_to_D * (m_reproductionnumber_c - 1)) / + (1 - transition_to_D); + m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] = 1 / m_reproductionnumber_c; + m_equilibriumnormalizedcompartments[(int)InfectionState::Exposed] = + m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * + m_meansojourntime[(int)InfectionState::Exposed]; + m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedNoSymptoms] = + m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * + transition_to_INS * m_meansojourntime[(int)InfectionState::InfectedNoSymptoms]; + m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedSymptoms] = + m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * + transition_to_ISy * m_meansojourntime[(int)InfectionState::InfectedSymptoms]; + m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedSevere] = + m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * + transition_to_ISe * m_meansojourntime[(int)InfectionState::InfectedSevere]; + m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedCritical] = + m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * + transition_to_IC * m_meansojourntime[(int)InfectionState::InfectedCritical]; + m_equilibriumnormalizedcompartments[(int)InfectionState::Recovered] = + m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * + transition_to_R / parameters.get(); + } +} + }; // namespace endisecir } // namespace mio diff --git a/cpp/models/ide_endemic_secir/model.h b/cpp/models/ide_endemic_secir/model.h index 9ec9fbaa6a..cabec09f3d 100644 --- a/cpp/models/ide_endemic_secir/model.h +++ b/cpp/models/ide_endemic_secir/model.h @@ -8,6 +8,7 @@ #include "memilio/utils/time_series.h" #include "vector" +#include #include namespace mio @@ -142,6 +143,13 @@ class Model */ void compute_populationsize(); + /** + * @brief Compute the normalized compartments for the current last time in normalized_populations. + * + * The normalized compartments are computed as populations / m_populationsize. + */ + void compute_normalizedcompartments(); + /** * @brief Computes the force of infection for the current last time in transitions. * @@ -198,27 +206,49 @@ class Model */ void set_meaninfectivity(ScalarType dt); - // /** - // *@brief Setter for the vector m_initalvaluesforceofinfection that contains the approximated value of the part of the - // * force of infection term that is influenced by the initial values. - // * - // * @param[in] dt Time step size. - // */ + // // /** + // // *@brief Setter for the vector m_initalvaluesforceofinfection that contains the approximated value of the part of the + // // * force of infection term that is influenced by the initial values. + // // * + // // * @param[in] dt Time step size. + // // */ // void set_initalvaluesforceofinfection(ScalarType dt); + // ---- Functionality for the model analysis. ---- + /** * @brief Setter for the Reproduction number R_c. * */ void set_reproductionnumber_c(ScalarType dt); + //TODO Beschreibung + void set_probability_of_transition(ScalarType dt); + + //TODO Beschreibung + void set_meansojourntime(ScalarType dt); + + /** + * @brief Setter for the equilibrium of the normalized model + * + * If the m_reproductionnumber_c < 1 we use the disease free equilibrium and if m_reproductionnumber_c > 1 we compute + * the endemic equilibrium. + * + */ + void set_equilibrium(); + // ---- Private parameters. ---- TimeSeries m_forceofinfection{ - TimeSeries(1)}; ///< Vector containing the Force of infection term for every time point, + TimeSeries(1)}; ///< TimeSeries containing the Force of infection term for every time point, // needed for the numerical scheme. TimeSeries m_totalpopulation{TimeSeries( - 1)}; ///< Vector containing the total population size of the considered region for each time point. + 1)}; ///< TimeSeries containing the total population size of the considered region for each time point. + TimeSeries m_normalizedpopulations{ + TimeSeries(Eigen::Index(InfectionState::Count) - + 1)}; ///< TimeSeries containing points of time and the corresponding portion + // of people in defined #IndectionState%s. + ScalarType m_reproductionnumber_c; ///< The control Reproduction number ScalarType m_tol{1e-10}; ///< Tolerance used to calculate the maximum support of the TransitionDistributions. @@ -238,8 +268,19 @@ class Model std::vector m_meaninfectivity; ///> a vector containing the approximated mean infectivity for all time points. - std::vector m_initalvaluesforceofinfection; ///> a vector containing the parts of the force of infection - // that are influenced by the inital values of our model, i.e phi_0 and f. + std::vector m_equilibriumnormalizedcompartments{ + std::vector(int(InfectionState::Count), 0.)}; ///< Vector containing + // the equilibrium for the normalized compartments. + + ScalarType m_equilibriumforceofinfection{0.}; ///< The equilibrium of the force of infection. + + std::vector m_probabilityoftransition{ + std::vector((int)InfectionTransition::Count, 0.)}; /// m_meansojourntime{std::vector((int)InfectionState::Count - 2, 0.)}; /// m_initalvaluesforceofinfection; ///> a vector containing the parts of the force of infection + // // that are influenced by the inital values of our model, i.e phi_0 and f. // ---- Friend classes/functions. ---- // In the Simulation class, the actual simulation is performed which is why it needs access to the here diff --git a/cpp/models/ide_endemic_secir/simulation.cpp b/cpp/models/ide_endemic_secir/simulation.cpp index 6d61c1ac66..38cb64bd5b 100644 --- a/cpp/models/ide_endemic_secir/simulation.cpp +++ b/cpp/models/ide_endemic_secir/simulation.cpp @@ -22,6 +22,9 @@ void Simulation::advance(ScalarType tmax) m_model->set_meaninfectivity(m_dt); // m_model->set_initalvaluesforceofinfection(m_dt); m_model->set_reproductionnumber_c(m_dt); + m_model->set_probability_of_transition(m_dt); + m_model->set_meansojourntime(m_dt); + m_model->set_equilibrium(); // For every time step: while (m_model->transitions.get_last_time() < tmax - m_dt / 2) { @@ -30,6 +33,7 @@ void Simulation::advance(ScalarType tmax) m_model->populations.add_time_point(m_model->populations.get_last_time() + m_dt); m_model->m_forceofinfection.add_time_point(m_model->m_forceofinfection.get_last_time() + m_dt); m_model->m_totalpopulation.add_time_point(m_model->m_totalpopulation.get_last_time() + m_dt); + m_model->m_normalizedpopulations.add_time_point(m_model->m_normalizedpopulations.get_last_time() + m_dt); // Compute susceptibles: m_model->compute_susceptibles(m_dt); @@ -43,6 +47,9 @@ void Simulation::advance(ScalarType tmax) // Compute m_populationsize: m_model->compute_populationsize(); + // Compute normalized compartments: + m_model->compute_normalizedcompartments(); + // Compute m_forceofinfection; m_model->compute_forceofinfection(m_dt); } diff --git a/cpp/models/ide_endemic_secir/simulation.h b/cpp/models/ide_endemic_secir/simulation.h index 9859a9ed57..ff242146ea 100644 --- a/cpp/models/ide_endemic_secir/simulation.h +++ b/cpp/models/ide_endemic_secir/simulation.h @@ -5,6 +5,7 @@ #include "memilio/config.h" #include "memilio/utils/time_series.h" #include +#include namespace mio { @@ -34,6 +35,11 @@ class Simulation return m_model->populations; } + TimeSeries get_normalizedcompartments() + { + return m_model->m_normalizedpopulations; + } + /** * @brief Get the result of the simulation for the compartments * Return the number of persons in all #InfectionState%s @@ -43,6 +49,11 @@ class Simulation return m_model->populations; } + TimeSeries& get_normalizedcompartments() const + { + return m_model->m_normalizedpopulations; + } + /** * @brief Get the transitions between the different #InfectionState%s. */ @@ -66,6 +77,16 @@ class Simulation return m_model->m_reproductionnumber_c; } + std::vector const& get_equilibriumcompartments() + { + return m_model->m_equilibriumnormalizedcompartments; + } + + ScalarType const& get_equilibrium_forceofinfection() + { + return m_model->m_equilibriumforceofinfection; + } + /** * @brief returns the simulation model used in simulation. */ From bc73193623d60ea36c3279dac8bc381d9a9c08fd Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Thu, 15 May 2025 09:53:54 +0200 Subject: [PATCH 03/22] small changes --- cpp/examples/ide_endemic_secir.cpp | 36 +++--- cpp/models/ide_endemic_secir/model.cpp | 155 ++++++++++++++----------- cpp/models/ide_endemic_secir/model.h | 8 +- 3 files changed, 108 insertions(+), 91 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index d0e7d34f7e..4cc2e02465 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -18,8 +18,8 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 300; - ScalarType dt = 1; + ScalarType tmax = 100; + ScalarType dt = 1.; int num_states = static_cast(mio::endisecir::InfectionState::Count); int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); @@ -29,13 +29,13 @@ int main() Vec vec_init(num_states); - vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = 15000.; - vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = 0.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = 0.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = 40.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedSevere)] = 0.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedCritical)] = 0.; - vec_init[static_cast(mio::endisecir::InfectionState::Recovered)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = 9950.; + vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = 25.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = 15.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = 8.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSevere)] = 1.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedCritical)] = 1.; + vec_init[static_cast(mio::endisecir::InfectionState::Recovered)] = 5.; vec_init[static_cast(mio::endisecir::InfectionState::Dead)] = 0.; init.add_time_point(0, vec_init); @@ -44,14 +44,14 @@ int main() //Set working parameters - // mio::ExponentialSurvivalFunction exp(7.0); - // mio::StateAgeFunctionWrapper delaydistribution(exp); - // std::vector vec_delaydistribution(num_transitions, delaydistribution); - - mio::SmootherCosine smoothcos(8.0); - mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + mio::ExponentialSurvivalFunction exp(3.0); + mio::StateAgeFunctionWrapper delaydistribution(exp); std::vector vec_delaydistribution(num_transitions, delaydistribution); + // mio::SmootherCosine smoothcos(9.0); + // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + // std::vector vec_delaydistribution(num_transitions, delaydistribution); + model.parameters.get() = vec_delaydistribution; std::vector vec_prob(num_transitions, 0.5); @@ -61,10 +61,10 @@ int main() model.parameters.get() = vec_prob; mio::ContactMatrixGroup contact_matrix = mio::ContactMatrixGroup(1, 1); - contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 15.)); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); model.parameters.get() = mio::UncertainContactMatrix(contact_matrix); - mio::ConstantFunction constant(0.3); + mio::ConstantFunction constant(0.1); mio::StateAgeFunctionWrapper constant_prob(constant); model.parameters.get() = constant_prob; @@ -76,7 +76,7 @@ int main() model.parameters.get() = exponential_prob; model.parameters.set(5e-3); - model.parameters.set(2e-3); + model.parameters.set(3e-3); // start the simulation. mio::endisecir::Simulation sim(model, dt); diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index 3136130376..761a9d371f 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace mio @@ -66,8 +67,8 @@ void Model::compute_susceptibles(ScalarType dt) Eigen::Index num_time_points = populations.get_num_time_points(); populations.get_last_value()[static_cast(InfectionState::Susceptible)] = (populations[num_time_points - 2][static_cast(InfectionState::Susceptible)] * - (1 - parameters.get()) + - m_totalpopulation[num_time_points - 2][0] * parameters.get()) / + (1 - dt * parameters.get()) + + dt * m_totalpopulation[num_time_points - 2][0] * parameters.get()) / (1 + dt * m_forceofinfection[num_time_points - 2][0]); } @@ -76,20 +77,22 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx { Eigen::Index calc_time_index = (Eigen::Index)std::ceil(m_transitiondistributions_support_max[idx_InfectionTransitions] / dt); + ScalarType current_time_age = static_cast(current_time_index) * dt; ScalarType sum = 0; //Determine the starting point of the for loop. Eigen::Index starting_point = std::max(0, (int)current_time_index - (int)calc_time_index); for (Eigen::Index i = starting_point; i < current_time_index; i++) { + ScalarType state_age_i = static_cast(i) * dt; sum += transitions[i + 1][idx_IncomingFlow] * - std::exp((-parameters.get()) * (current_time_index - i)) * + std::exp(-parameters.get() * (current_time_age - state_age_i)) * m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; } if (current_time_index <= calc_time_index) { transitions.get_value(current_time_index)[idx_InfectionTransitions] = (-dt) * parameters.get()[idx_InfectionTransitions] * sum - - std::exp((-parameters.get()) * (current_time_index)) * + std::exp((-parameters.get()) * (current_time_age)) * populations[0][idx_CurrentCompartment] * parameters.get()[idx_InfectionTransitions] * m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; @@ -113,7 +116,7 @@ void Model::flows_currents_timestep(ScalarType dt) // Calculate the transition SusceptibleToExposed with force of infection from previous time step and Susceptibles from // current time step. transitions.get_last_value()[static_cast(InfectionTransition::SusceptibleToExposed)] = - dt * m_forceofinfection[current_time_index - 1][0] * + m_forceofinfection[current_time_index - 1][0] * populations.get_last_value()[static_cast(InfectionState::Susceptible)]; // Calculate the other Transitions with compute_flow. @@ -164,7 +167,7 @@ void Model::update_compartment_from_flow(InfectionState infectionState, ScalarType updated_compartment = 0; if (NaturalDeathispossible) { updated_compartment = populations[num_time_points - 2][static_cast(infectionState)] * - (1 - parameters.get()); + (1 - dt * parameters.get()); } else { updated_compartment = populations[num_time_points - 2][static_cast(infectionState)]; @@ -180,10 +183,10 @@ void Model::update_compartment_from_flow(InfectionState infectionState, void Model::update_compartments(ScalarType dt) { + // Exposed update_compartment_from_flow(InfectionState::Exposed, {InfectionTransition::SusceptibleToExposed}, {InfectionTransition::ExposedToInfectedNoSymptoms}, true, dt); - // InfectedNoSymptoms update_compartment_from_flow( InfectionState::InfectedNoSymptoms, {InfectionTransition::ExposedToInfectedNoSymptoms}, @@ -244,75 +247,83 @@ void Model::compute_forceofinfection(ScalarType dt) ScalarType current_time = populations.get_last_time(); Eigen::Index calc_time_index = (Eigen::Index)std::ceil(m_calctime / dt) - 1; - ScalarType sum = 0; - //Computation of phi_0 - ScalarType phi_0 = 0; - if (num_time_points <= calc_time_index) { - phi_0 = m_meaninfectivity[num_time_points] * + ScalarType phi_0 = 0.; + ScalarType f = 0.; + + //Otherwise the initial values do not have an influence anymore. + if (num_time_points - 1 <= calc_time_index) { + + //Computation of phi_0: + phi_0 = m_meaninfectivity[num_time_points - 1] * (populations[0][static_cast(InfectionState::InfectedNoSymptoms)] * - m_transitiondistributions_in_forceofinfection[0][num_time_points] + + m_transitiondistributions_in_forceofinfection[0][num_time_points - 1] + populations[0][static_cast(InfectionState::InfectedSymptoms)] * - m_transitiondistributions_in_forceofinfection[1][num_time_points]) / + m_transitiondistributions_in_forceofinfection[1][num_time_points - 1]) / m_totalpopulation[num_time_points - 1][0]; - } - //Computation of f - ScalarType f = 0.; - ScalarType f_1 = 0.; - ScalarType f_2 = 0.; - ScalarType f_3 = 0.; - for (int i = 1; i <= calc_time_index; i++) { - ScalarType state_age_i = static_cast(i - 1) * dt; - //Compute sum for f_1: - f_1 += m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] - [current_time + 1 - i] * - parameters.get().eval(state_age_i) * - m_transitiondistributions_in_forceofinfection[0][i - 1]; - - //Compute sum for f_2: - f_2 += m_transitiondistributions_derivative[static_cast( - InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][num_time_points + 1 - i] * - parameters.get().eval(state_age_i) * - m_transitiondistributions_in_forceofinfection[1][i - 1]; - - //Compute sum for f_3: - sum = 0.; - for (int j = 1; j <= i; j++) { - ScalarType state_age_j = static_cast(j - 1) * dt; - sum += parameters.get()[static_cast( - InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] * - m_transitiondistributions_derivative[static_cast( - InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][num_time_points + 1 - j] * - parameters.get().eval(state_age_j) * - m_transitiondistributions_in_forceofinfection[1][j - 1]; + + //Computation of f: + ScalarType f_1 = 0.; + ScalarType f_2 = 0.; + ScalarType f_3 = 0.; + + for (int i = 1; i < num_time_points; i++) { + ScalarType state_age_i = static_cast(i - 1) * dt; + //Compute sum for f_1: + f_1 += + m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] + [num_time_points - 1 - i] * + parameters.get().eval(state_age_i) * + m_transitiondistributions_in_forceofinfection[0][i - 1]; + + //Compute sum for f_2: + f_2 += m_transitiondistributions_derivative[static_cast( + InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][num_time_points - 1 - i] * + parameters.get().eval(state_age_i) * + m_transitiondistributions_in_forceofinfection[1][i - 1]; + + //Compute sum for f_3: + ScalarType sum_f = 0.; + for (int j = 1; j <= i; j++) { + ScalarType state_age_j = static_cast(j - 1) * dt; + sum_f += parameters.get()[static_cast( + InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] * + m_transitiondistributions_derivative[static_cast( + InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][num_time_points - 1 - j] * + parameters.get().eval(state_age_j) * + m_transitiondistributions_in_forceofinfection[1][j - 1]; + } + f_3 += + m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] + [num_time_points - 1 - i] * + sum_f; } - f_3 += m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] - [num_time_points + 1 - i] * - sum; + f = (dt * dt * populations[0][static_cast(InfectionState::Exposed)] * + std::exp(-parameters.get() * current_time) * f_3 - + dt * populations[0][static_cast(InfectionState::InfectedNoSymptoms)] * + std::exp(-parameters.get() * current_time) * f_2 - + dt * populations[0][static_cast(InfectionState::Exposed)] * + std::exp(-parameters.get() * current_time) * f_1) / + m_totalpopulation[num_time_points - 1][0]; } - f = std::pow(dt, 2) * populations[0][static_cast(InfectionState::Exposed)] * - std::exp(-parameters.get() * current_time) * f_3 - - dt * populations[0][static_cast(InfectionState::InfectedNoSymptoms)] * - std::exp(-parameters.get() * current_time) * f_2 - - dt * populations[0][static_cast(InfectionState::Exposed)] * - std::exp(-parameters.get() * current_time) * f_1; // Computation of the rest // Determine the starting point of the for loop. - Eigen::Index starting_point = std::max(0, (int)num_time_points - (int)calc_time_index - 1); + Eigen::Index starting_point = std::max(0, (int)num_time_points - 1 - (int)calc_time_index); - sum = 0.; + ScalarType sum = 0.; for (Eigen::Index i = starting_point; i < num_time_points - 1; i++) { sum += m_meaninfectivity[num_time_points - 1 - i] * populations[i + 1][(int)InfectionState::Susceptible] * m_forceofinfection[i][0]; } m_forceofinfection.get_last_value()[0] = - phi_0 + (dt * sum + f) * - (parameters.get().eval(current_time) * - parameters.get().get_cont_freq_mat().get_matrix_at(num_time_points)(0, 0)) / - m_totalpopulation[num_time_points - 1][0]; + phi_0 + f + + (dt * sum) * + (parameters.get().eval(current_time) * + parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)) / + m_totalpopulation[num_time_points - 1][0]; } // ---- Functionality to set vectors with necessary information regarding TransitionDistributions. ---- @@ -360,7 +371,7 @@ void Model::set_transitiondistributions(ScalarType dt) std::vector vec_contribution_to_foi(calc_time_index + 1, 0.); for (Eigen::Index i = 0; i <= calc_time_index; i++) { //Compute the state_age. - ScalarType state_age = i * dt; + ScalarType state_age = (ScalarType)i * dt; vec_contribution_to_foi[i] = parameters.get()[relevant_transitions[contribution][0]] * parameters.get()[relevant_transitions[contribution][0]].eval(state_age) + @@ -396,9 +407,11 @@ void Model::set_meaninfectivity(ScalarType dt) { // Determine the corresponding time index. - Eigen::Index calc_time_index = (Eigen::Index)std::ceil(m_calctime / dt) - 1; + Eigen::Index calc_time = std::min( + m_calctime, m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms]); + Eigen::Index calc_time_index = (Eigen::Index)std::ceil(calc_time / dt) - 1; - m_meaninfectivity = std::vector(calc_time_index, 0.); + m_meaninfectivity = std::vector(calc_time_index + 1, 0.); // The mean infectivity is computed as exp(-NaturalDeathRate t) * (a_2(t)-a_1(t)). for (int time_point_index = 1; time_point_index <= calc_time_index; time_point_index++) { @@ -407,7 +420,7 @@ void Model::set_meaninfectivity(ScalarType dt) ScalarType time_point_age = (ScalarType)time_point_index * dt; //We compute a_1 and a_2 at time_point. - for (int i = 1; i <= time_point_index; i++) { + for (int i = 0; i <= time_point_index - 1; i++) { ScalarType state_age_i = static_cast(i) * dt; //Computation of a_1. a_1 += parameters.get().eval(state_age_i) * @@ -416,7 +429,7 @@ void Model::set_meaninfectivity(ScalarType dt) [time_point_index - i]; //Computation of a_2. ScalarType sum = 0; - for (int j = 1; j <= i; j++) { + for (int j = 0; j <= i - 1; j++) { ScalarType state_age_j = static_cast(j) * dt; sum += parameters.get().eval(state_age_j) * @@ -431,7 +444,7 @@ void Model::set_meaninfectivity(ScalarType dt) sum; } m_meaninfectivity[time_point_index] = - std::exp(-parameters.get() * time_point_age) * (std::pow(dt, 2) * a_2 - dt * a_1); + std::exp(-parameters.get() * time_point_age) * (dt * dt * a_2 - dt * a_1); } } // void Model::set_initalvaluesforceofinfection(ScalarType dt) @@ -506,9 +519,13 @@ void Model::set_meaninfectivity(ScalarType dt) void Model::set_reproductionnumber_c(ScalarType dt) { - ScalarType sum = 0; - for (ScalarType mean_infectivity_i : m_meaninfectivity) { - sum += mean_infectivity_i; + // Determine the corresponding time index. + Eigen::Index calc_time = std::min( + m_calctime, m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms]); + Eigen::Index calc_time_index = (Eigen::Index)std::ceil(calc_time / dt) - 1; + ScalarType sum = 0; + for (int i = 0; i <= calc_time_index; i++) { + sum += m_meaninfectivity[i]; } m_reproductionnumber_c = parameters.get().eval(0) * parameters.get().get_cont_freq_mat().get_matrix_at(0)(0, 0) * dt * sum; @@ -544,7 +561,7 @@ void Model::set_meansojourntime(ScalarType dt) state_age_i) * std::exp(-parameters.get() * state_age_i); } - m_meaninfectivity[(int)InfectionState::Exposed] = dt * sum; + m_meansojourntime[(int)InfectionState::Exposed] = dt * sum; // Other Infected States: // Transitions needed to compute the mean sojourn time of the other states. diff --git a/cpp/models/ide_endemic_secir/model.h b/cpp/models/ide_endemic_secir/model.h index cabec09f3d..8961097313 100644 --- a/cpp/models/ide_endemic_secir/model.h +++ b/cpp/models/ide_endemic_secir/model.h @@ -249,8 +249,6 @@ class Model 1)}; ///< TimeSeries containing points of time and the corresponding portion // of people in defined #IndectionState%s. - ScalarType m_reproductionnumber_c; ///< The control Reproduction number - ScalarType m_tol{1e-10}; ///< Tolerance used to calculate the maximum support of the TransitionDistributions. ScalarType m_calctime{ 0}; ///< A ScalarType wit he calc time determined by the support max of the transition distributions. @@ -265,8 +263,10 @@ class Model std::vector> m_transitiondistributions_derivative{std::vector>( (int)InfectionTransition::Count, std::vector(1, 0.))}; ///> A Vector containing // the approximated derivative for all TransitionDistributions for all necessary time points. - std::vector - m_meaninfectivity; ///> a vector containing the approximated mean infectivity for all time points. + std::vector m_meaninfectivity{ + std::vector(1, 0.)}; ///> a vector containing the approximated mean infectivity for all time points. + + ScalarType m_reproductionnumber_c; ///< The control Reproduction number std::vector m_equilibriumnormalizedcompartments{ std::vector(int(InfectionState::Count), 0.)}; ///< Vector containing From 06f08fe2fd4af5478941830502d16606d2ec8983 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Tue, 20 May 2025 10:45:29 +0200 Subject: [PATCH 04/22] Added another version of computing the compartments --- cpp/examples/ide_endemic_secir.cpp | 38 ++-- cpp/models/ide_endemic_secir/model.cpp | 248 +++++++++++++++++-------- cpp/models/ide_endemic_secir/model.h | 35 +++- 3 files changed, 216 insertions(+), 105 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index 4cc2e02465..74e6e50f96 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -18,8 +18,8 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 100; - ScalarType dt = 1.; + ScalarType tmax = 10; + ScalarType dt = 0.1; int num_states = static_cast(mio::endisecir::InfectionState::Count); int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); @@ -44,14 +44,14 @@ int main() //Set working parameters - mio::ExponentialSurvivalFunction exp(3.0); - mio::StateAgeFunctionWrapper delaydistribution(exp); - std::vector vec_delaydistribution(num_transitions, delaydistribution); - - // mio::SmootherCosine smoothcos(9.0); - // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + // mio::ExponentialSurvivalFunction exp(2.0); + // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); + mio::SmootherCosine smoothcos(4.0); + mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + std::vector vec_delaydistribution(num_transitions, delaydistribution); + model.parameters.get() = vec_delaydistribution; std::vector vec_prob(num_transitions, 0.5); @@ -94,7 +94,7 @@ int main() // {"S->E 1", "E->C 1", "C->I 1", "C->R 1", "I->H 1", "I->R 1", "H->U 1", "H->R 1", "U->D 1", "U->R 1"}, 16, 8); // Uncomment to print the normalized compartments. - sim.get_normalizedcompartments().print_table({"s", "e", "c", "i", "h", "u", "r", "d "}, 16, 8); + // sim.get_normalizedcompartments().print_table({"s", "e", "c", "i", "h", "u", "r", "d "}, 16, 8); // Uncomment to print the total population size. sim.get_totalpopulations().print_table({"N"}, 16, 9); @@ -102,14 +102,14 @@ int main() // Uncomment to print the force of infection. sim.get_forceofinfections().print_table({"FoI"}, 16, 8); - std::vector equi = sim.get_equilibriumcompartments(); - std::cout << "Equilibrium normalized compartments: \n"; - std::cout << "foi* " << sim.get_equilibrium_forceofinfection() << "\n"; - std::cout << "s* " << equi[(int)mio::endisecir::InfectionState::Susceptible] << "\n"; - std::cout << "e* " << equi[(int)mio::endisecir::InfectionState::Exposed] << "\n"; - std::cout << "c* " << equi[(int)mio::endisecir::InfectionState::InfectedNoSymptoms] << "\n"; - std::cout << "i* " << equi[(int)mio::endisecir::InfectionState::InfectedSymptoms] << "\n"; - std::cout << "h* " << equi[(int)mio::endisecir::InfectionState::InfectedSevere] << "\n"; - std::cout << "u* " << equi[(int)mio::endisecir::InfectionState::InfectedCritical] << "\n"; - std::cout << "r* " << equi[(int)mio::endisecir::InfectionState::Recovered] << "\n"; + // std::vector equi = sim.get_equilibriumcompartments(); + // std::cout << "Equilibrium normalized compartments: \n"; + // std::cout << "foi* " << sim.get_equilibrium_forceofinfection() << "\n"; + // std::cout << "s* " << equi[(int)mio::endisecir::InfectionState::Susceptible] << "\n"; + // std::cout << "e* " << equi[(int)mio::endisecir::InfectionState::Exposed] << "\n"; + // std::cout << "c* " << equi[(int)mio::endisecir::InfectionState::InfectedNoSymptoms] << "\n"; + // std::cout << "i* " << equi[(int)mio::endisecir::InfectionState::InfectedSymptoms] << "\n"; + // std::cout << "h* " << equi[(int)mio::endisecir::InfectionState::InfectedSevere] << "\n"; + // std::cout << "u* " << equi[(int)mio::endisecir::InfectionState::InfectedCritical] << "\n"; + // std::cout << "r* " << equi[(int)mio::endisecir::InfectionState::Recovered] << "\n"; } \ No newline at end of file diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index 761a9d371f..bb59379dbf 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -21,19 +21,25 @@ namespace endisecir Model::Model(TimeSeries&& states_init) : parameters{Parameters()} , transitions{TimeSeries(Eigen::Index(InfectionTransition::Count))} + , transitions_update{TimeSeries(Eigen::Index(InfectionTransition::Count))} , populations{std::move(states_init)} + , populations_update{std::move(states_init)} { // Set flows at start time t0. // As we assume that all individuals have infectio age 0 at time t0, the flows at t0 are set to 0. transitions.add_time_point( 0, TimeSeries::Vector::Constant(static_cast(InfectionTransition::Count), 0.)); + transitions_update.add_time_point( + 0, TimeSeries::Vector::Constant(static_cast(InfectionTransition::Count), 0.)); // Set population size at start timt t0. ScalarType init_populationsize = std::accumulate(populations[0].begin(), populations[0].end(), 0) - populations[0][(int)InfectionState::Dead]; m_totalpopulation.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); + m_totalpopulationupdate.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); // Set the force of infection at start time t0. m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); + m_forceofinfectionupdate.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); //Set normalized_populations at start time t0. TimeSeries::Vector vec_normalizedpopulations = @@ -70,6 +76,14 @@ void Model::compute_susceptibles(ScalarType dt) (1 - dt * parameters.get()) + dt * m_totalpopulation[num_time_points - 2][0] * parameters.get()) / (1 + dt * m_forceofinfection[num_time_points - 2][0]); + + //Computation of susceptibles using the update formula for the other compartments. + //Formula for Susceptibles stays the same, but we use m_totalpopulationupdate and m_forceofinfectionupdate + populations_update.get_last_value()[static_cast(InfectionState::Susceptible)] = + (populations_update[num_time_points - 2][static_cast(InfectionState::Susceptible)] * + (1 - dt * parameters.get()) + + dt * m_totalpopulationupdate[num_time_points - 2][0] * parameters.get()) / + (1 + dt * m_forceofinfectionupdate[num_time_points - 2][0]); } void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, @@ -88,6 +102,10 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx sum += transitions[i + 1][idx_IncomingFlow] * std::exp(-parameters.get() * (current_time_age - state_age_i)) * m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; + //For the update formula version of the model: + sum += transitions_update[i + 1][idx_IncomingFlow] * + std::exp(-parameters.get() * (current_time_age - state_age_i)) * + m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; } if (current_time_index <= calc_time_index) { transitions.get_value(current_time_index)[idx_InfectionTransitions] = @@ -96,10 +114,22 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx populations[0][idx_CurrentCompartment] * parameters.get()[idx_InfectionTransitions] * m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; + + //For the update formula version of the model: + transitions_update.get_value(current_time_index)[idx_InfectionTransitions] = + (-dt) * parameters.get()[idx_InfectionTransitions] * sum - + std::exp((-parameters.get()) * (current_time_age)) * + populations_update[0][idx_CurrentCompartment] * + parameters.get()[idx_InfectionTransitions] * + m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; } else { transitions.get_value(current_time_index)[idx_InfectionTransitions] = (-dt) * parameters.get()[idx_InfectionTransitions] * sum; + + //For the update formula version of the model: + transitions_update.get_value(current_time_index)[idx_InfectionTransitions] = + (-dt) * parameters.get()[idx_InfectionTransitions] * sum; } } @@ -119,6 +149,11 @@ void Model::flows_currents_timestep(ScalarType dt) m_forceofinfection[current_time_index - 1][0] * populations.get_last_value()[static_cast(InfectionState::Susceptible)]; + ///For the update formula version of the model: + transitions_update.get_last_value()[static_cast(InfectionTransition::SusceptibleToExposed)] = + m_forceofinfectionupdate[current_time_index - 1][0] * + populations_update.get_last_value()[static_cast(InfectionState::Susceptible)]; + // Calculate the other Transitions with compute_flow. // Exposed to InfectedNoSymptoms compute_flow(Eigen::Index(InfectionTransition::ExposedToInfectedNoSymptoms), @@ -157,6 +192,40 @@ void Model::flows_currents_timestep(ScalarType dt) Eigen::Index(InfectionState::InfectedCritical), dt); } +void Model::update_compartment_with_sum(InfectionState infectionState, + std::vector const& IncomingFlows, + bool NaturalDeathispossible, ScalarType dt) +{ + Eigen::Index current_time_index = populations.get_num_time_points() - 1; + ScalarType current_time_age = (ScalarType)current_time_index * dt; + ScalarType sum = 0; + + for (int i = 0; i < current_time_index; i++) { + ScalarType state_age_i = (ScalarType)i * dt; + ScalarType sum_inflows = 0; + for (const InfectionTransition& inflow : IncomingFlows) { + sum_inflows += transitions[i + 1][(int)inflow]; + } + if (NaturalDeathispossible) { + sum += m_transitiondistributions[(int)infectionState][current_time_index - i] * sum_inflows * + std::exp(-parameters.get() * (current_time_age - state_age_i)); + } + else { + sum += m_transitiondistributions[(int)infectionState][current_time_index - i] * sum_inflows; + } + } + if (NaturalDeathispossible) { + populations.get_last_value()[(int)infectionState] = + dt * sum + m_transitiondistributions[(int)infectionState][current_time_index] * + populations[0][(int)infectionState] * + std::exp(-parameters.get() * (current_time_age)); + } + else { + populations.get_last_value()[(int)infectionState] = + dt * sum + + m_transitiondistributions[(int)infectionState][current_time_index] * populations[0][(int)infectionState]; + } +} void Model::update_compartment_from_flow(InfectionState infectionState, std::vector const& IncomingFlows, std::vector const& OutgoingFlows, @@ -166,19 +235,19 @@ void Model::update_compartment_from_flow(InfectionState infectionState, ScalarType updated_compartment = 0; if (NaturalDeathispossible) { - updated_compartment = populations[num_time_points - 2][static_cast(infectionState)] * + updated_compartment = populations_update[num_time_points - 2][static_cast(infectionState)] * (1 - dt * parameters.get()); } else { - updated_compartment = populations[num_time_points - 2][static_cast(infectionState)]; + updated_compartment = populations_update[num_time_points - 2][static_cast(infectionState)]; } for (const InfectionTransition& inflow : IncomingFlows) { - updated_compartment += dt * transitions.get_last_value()[(int)inflow]; + updated_compartment += dt * transitions_update.get_last_value()[(int)inflow]; } for (const InfectionTransition& outflow : OutgoingFlows) { - updated_compartment -= dt * transitions.get_last_value()[(int)outflow]; + updated_compartment -= dt * transitions_update.get_last_value()[(int)outflow]; } - populations.get_last_value()[(int)infectionState] = updated_compartment; + populations_update.get_last_value()[(int)infectionState] = updated_compartment; } void Model::update_compartments(ScalarType dt) @@ -187,29 +256,37 @@ void Model::update_compartments(ScalarType dt) // Exposed update_compartment_from_flow(InfectionState::Exposed, {InfectionTransition::SusceptibleToExposed}, {InfectionTransition::ExposedToInfectedNoSymptoms}, true, dt); + update_compartment_with_sum(InfectionState::Exposed, {InfectionTransition::SusceptibleToExposed}, true, dt); // InfectedNoSymptoms update_compartment_from_flow( InfectionState::InfectedNoSymptoms, {InfectionTransition::ExposedToInfectedNoSymptoms}, {InfectionTransition::InfectedNoSymptomsToInfectedSymptoms, InfectionTransition::InfectedNoSymptomsToRecovered}, true, dt); + update_compartment_with_sum(InfectionState::InfectedNoSymptoms, {InfectionTransition::ExposedToInfectedNoSymptoms}, + true, dt); // InfectedSymptoms update_compartment_from_flow( InfectionState::InfectedSymptoms, {InfectionTransition::InfectedNoSymptomsToInfectedSymptoms}, {InfectionTransition::InfectedSymptomsToInfectedSevere, InfectionTransition::InfectedSymptomsToRecovered}, true, dt); + update_compartment_with_sum(InfectionState::InfectedSymptoms, + {InfectionTransition::InfectedNoSymptomsToInfectedSymptoms}, true, dt); // InfectedSevere update_compartment_from_flow( InfectionState::InfectedSevere, {InfectionTransition::InfectedSymptomsToInfectedSevere}, {InfectionTransition::InfectedSevereToInfectedCritical, InfectionTransition::InfectedSevereToRecovered}, true, dt); + update_compartment_with_sum(InfectionState::InfectedSevere, {InfectionTransition::InfectedSymptomsToInfectedSevere}, + true, dt); // InfectedCritical update_compartment_from_flow( InfectionState::InfectedCritical, {InfectionTransition::InfectedSevereToInfectedCritical}, {InfectionTransition::InfectedCriticalToDead, InfectionTransition::InfectedCriticalToRecovered}, true, dt); - + update_compartment_with_sum(InfectionState::InfectedCritical, + {InfectionTransition::InfectedSevereToInfectedCritical}, true, dt); // Recovered update_compartment_from_flow(InfectionState::Recovered, { @@ -219,10 +296,19 @@ void Model::update_compartments(ScalarType dt) InfectionTransition::InfectedCriticalToRecovered, }, std::vector(), true, dt); + update_compartment_with_sum(InfectionState::Recovered, + { + InfectionTransition::InfectedNoSymptomsToRecovered, + InfectionTransition::InfectedSymptomsToRecovered, + InfectionTransition::InfectedSevereToRecovered, + InfectionTransition::InfectedCriticalToRecovered, + }, + true, dt); // Dead update_compartment_from_flow(InfectionState::Dead, {InfectionTransition::InfectedCriticalToDead}, std::vector(), false, dt); + update_compartment_with_sum(InfectionState::Dead, {InfectionTransition::InfectedCriticalToDead}, false, dt); } void Model::compute_populationsize() @@ -230,6 +316,9 @@ void Model::compute_populationsize() m_totalpopulation.get_last_value()[0] = std::accumulate(populations.get_last_value().begin(), populations.get_last_value().end(), 0) - populations.get_last_value()[(int)InfectionState::Dead]; + m_totalpopulationupdate.get_last_value()[0] = + std::accumulate(populations_update.get_last_value().begin(), populations_update.get_last_value().end(), 0) - + populations_update.get_last_value()[(int)InfectionState::Dead]; } void Model::compute_normalizedcompartments() @@ -248,19 +337,19 @@ void Model::compute_forceofinfection(ScalarType dt) Eigen::Index calc_time_index = (Eigen::Index)std::ceil(m_calctime / dt) - 1; - ScalarType phi_0 = 0.; + ScalarType foi_0 = 0.; ScalarType f = 0.; //Otherwise the initial values do not have an influence anymore. if (num_time_points - 1 <= calc_time_index) { //Computation of phi_0: - phi_0 = m_meaninfectivity[num_time_points - 1] * - (populations[0][static_cast(InfectionState::InfectedNoSymptoms)] * - m_transitiondistributions_in_forceofinfection[0][num_time_points - 1] + - populations[0][static_cast(InfectionState::InfectedSymptoms)] * - m_transitiondistributions_in_forceofinfection[1][num_time_points - 1]) / - m_totalpopulation[num_time_points - 1][0]; + foi_0 = + m_meaninfectivity[num_time_points - 1] * + (populations[0][static_cast(InfectionState::InfectedNoSymptoms)] * + m_transitiondistributions[static_cast(InfectionState::InfectedNoSymptoms)][num_time_points - 1] + + populations[0][static_cast(InfectionState::InfectedSymptoms)] * + m_transitiondistributions[static_cast(InfectionState::InfectedSymptoms)][num_time_points - 1]); //Computation of f: ScalarType f_1 = 0.; @@ -274,13 +363,13 @@ void Model::compute_forceofinfection(ScalarType dt) m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] [num_time_points - 1 - i] * parameters.get().eval(state_age_i) * - m_transitiondistributions_in_forceofinfection[0][i - 1]; + m_transitiondistributions[static_cast(InfectionState::InfectedNoSymptoms)][i - 1]; //Compute sum for f_2: f_2 += m_transitiondistributions_derivative[static_cast( InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][num_time_points - 1 - i] * parameters.get().eval(state_age_i) * - m_transitiondistributions_in_forceofinfection[1][i - 1]; + m_transitiondistributions[static_cast(InfectionState::InfectedSymptoms)][i - 1]; //Compute sum for f_3: ScalarType sum_f = 0.; @@ -291,7 +380,7 @@ void Model::compute_forceofinfection(ScalarType dt) m_transitiondistributions_derivative[static_cast( InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][num_time_points - 1 - j] * parameters.get().eval(state_age_j) * - m_transitiondistributions_in_forceofinfection[1][j - 1]; + m_transitiondistributions[static_cast(InfectionState::InfectedSymptoms)][j - 1]; } f_3 += m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] @@ -303,8 +392,7 @@ void Model::compute_forceofinfection(ScalarType dt) dt * populations[0][static_cast(InfectionState::InfectedNoSymptoms)] * std::exp(-parameters.get() * current_time) * f_2 - dt * populations[0][static_cast(InfectionState::Exposed)] * - std::exp(-parameters.get() * current_time) * f_1) / - m_totalpopulation[num_time_points - 1][0]; + std::exp(-parameters.get() * current_time) * f_1); } // Computation of the rest @@ -319,11 +407,25 @@ void Model::compute_forceofinfection(ScalarType dt) } m_forceofinfection.get_last_value()[0] = - phi_0 + f + + foi_0 / m_totalpopulation[num_time_points - 1][0] + f / m_totalpopulation[num_time_points - 1][0] + (dt * sum) * (parameters.get().eval(current_time) * parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)) / m_totalpopulation[num_time_points - 1][0]; + + //For the update formula version of the model: + sum = 0.; + for (Eigen::Index i = starting_point; i < num_time_points - 1; i++) { + sum += m_meaninfectivity[num_time_points - 1 - i] * + populations_update[i + 1][(int)InfectionState::Susceptible] * m_forceofinfectionupdate[i][0]; + } + + m_forceofinfection.get_last_value()[0] = + foi_0 / m_totalpopulationupdate[num_time_points - 1][0] + f / m_totalpopulationupdate[num_time_points - 1][0] + + (dt * sum) * + (parameters.get().eval(current_time) * + parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)) / + m_totalpopulationupdate[num_time_points - 1][0]; } // ---- Functionality to set vectors with necessary information regarding TransitionDistributions. ---- @@ -353,34 +455,52 @@ void Model::set_calctime() void Model::set_transitiondistributions(ScalarType dt) { + //Exposed state: + Eigen::Index support_max_index = (Eigen::Index)std::ceil( + m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms] / dt); - // Transitions needed in the force of infection term. - std::vector> relevant_transitions = { + std::vector vec_contribution_to_foi_1(support_max_index + 1, 0.); + for (Eigen::Index i = 0; i <= support_max_index; i++) { + ///Compute the state_age. + ScalarType state_age = (ScalarType)i * dt; + vec_contribution_to_foi_1[i] = + parameters.get()[(int)InfectionTransition::ExposedToInfectedNoSymptoms].eval( + state_age); + } + m_transitiondistributions[(int)InfectionState::Exposed] = vec_contribution_to_foi_1; + + // Other states: + // Vector containing the transitions for the states with two outgoing flows. + std::vector> vector_transitions = { {(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms, (int)InfectionTransition::InfectedNoSymptomsToRecovered}, {(int)InfectionTransition::InfectedSymptomsToInfectedSevere, - (int)InfectionTransition::InfectedSymptomsToRecovered}}; + (int)InfectionTransition::InfectedSymptomsToRecovered}, + {(int)InfectionTransition::InfectedSevereToInfectedCritical, + (int)InfectionTransition::InfectedSevereToRecovered}, + {(int)InfectionTransition::InfectedCriticalToDead, (int)InfectionTransition::InfectedCriticalToRecovered}}; - // Determine the corresponding time index to m_calctime. - // Subtract 1 because in the last summand all TransitionDistributions evaluate to 0 (by definition of support_max). - Eigen::Index calc_time_index = (Eigen::Index)std::ceil(m_calctime / dt) - 1; + for (int state = 2; state < (int)InfectionState::Count - 2; state++) { + Eigen::Index calc_time_index = + (Eigen::Index)std::ceil(std::max(m_transitiondistributions_support_max[transitions[state - 2][0]], + m_transitiondistributions_support_max[transitions[state - 2][1]]) / + dt); - // Compute the distributions from survival functions and transition probabilities starting in InfectedNoSymptoms and - // InfectedSymptims ont the force of infection term. - for (int contribution = 0; contribution < 2; contribution++) { - std::vector vec_contribution_to_foi(calc_time_index + 1, 0.); + // Create vec_derivative that stores the value of the approximated derivative for all necessary time points. + std::vector vec_contribution_to_foi_2(calc_time_index + 1, 0.); for (Eigen::Index i = 0; i <= calc_time_index; i++) { - //Compute the state_age. + ///Compute the state_age. ScalarType state_age = (ScalarType)i * dt; - vec_contribution_to_foi[i] = - parameters.get()[relevant_transitions[contribution][0]] * - parameters.get()[relevant_transitions[contribution][0]].eval(state_age) + - parameters.get()[relevant_transitions[contribution][1]] * - parameters.get()[relevant_transitions[contribution][1]].eval(state_age); + vec_contribution_to_foi_2[i] = + parameters.get()[vector_transitions[state - 2][0]] * + parameters.get()[vector_transitions[state - 2][0]].eval(state_age) + + parameters.get()[vector_transitions[state - 2][1]] * + parameters.get()[vector_transitions[state - 2][1]].eval(state_age); } - m_transitiondistributions_in_forceofinfection[contribution] = vec_contribution_to_foi; + m_transitiondistributions[state] = vec_contribution_to_foi_2; } } + void Model::set_transitiondistributions_derivative(ScalarType dt) { // The transition SusceptibleToExposed is not needed in the computations. @@ -424,7 +544,7 @@ void Model::set_meaninfectivity(ScalarType dt) ScalarType state_age_i = static_cast(i) * dt; //Computation of a_1. a_1 += parameters.get().eval(state_age_i) * - m_transitiondistributions_in_forceofinfection[0][i] * + m_transitiondistributions[static_cast(InfectionState::InfectedNoSymptoms)][i] * m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] [time_point_index - i]; //Computation of a_2. @@ -433,7 +553,7 @@ void Model::set_meaninfectivity(ScalarType dt) ScalarType state_age_j = static_cast(j) * dt; sum += parameters.get().eval(state_age_j) * - m_transitiondistributions_in_forceofinfection[1][j] * + m_transitiondistributions[static_cast(InfectionState::InfectedSymptoms)][j] * parameters.get()[( int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] * m_transitiondistributions_derivative[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] @@ -551,48 +671,20 @@ void Model::set_probability_of_transition(ScalarType dt) //TODO schönere implementierung überlegen, die evtl m_transitiondistributions_in_forceofinfection verwendet!!!! void Model::set_meansojourntime(ScalarType dt) { - ScalarType sum = 0; - //Exposed State: - Eigen::Index support_max_index = (Eigen::Index)std::ceil( - m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms] / dt); - for (int i = 0; i <= support_max_index; i++) { - ScalarType state_age_i = static_cast(i) * dt; - sum += parameters.get()[(int)InfectionTransition::ExposedToInfectedNoSymptoms].eval( - state_age_i) * - std::exp(-parameters.get() * state_age_i); - } - m_meansojourntime[(int)InfectionState::Exposed] = dt * sum; + std::vector relevant_states = {(int)InfectionState::Exposed, (int)InfectionState::InfectedNoSymptoms, + (int)InfectionState::InfectedSymptoms, (int)InfectionState::InfectedSevere, + (int)InfectionState::InfectedCritical}; - // Other Infected States: - // Transitions needed to compute the mean sojourn time of the other states. - std::vector> relevant_transitions_with_state = { - {(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms, - (int)InfectionTransition::InfectedNoSymptomsToRecovered, (int)InfectionState::InfectedNoSymptoms}, - {(int)InfectionTransition::InfectedSymptomsToInfectedSevere, - (int)InfectionTransition::InfectedSymptomsToRecovered, (int)InfectionState::InfectedSymptoms}, - {(int)InfectionTransition::InfectedSymptomsToInfectedSevere, - (int)InfectionTransition::InfectedSymptomsToRecovered, (int)InfectionState::InfectedSevere}, - {(int)InfectionTransition::InfectedSevereToInfectedCritical, - (int)InfectionTransition::InfectedSevereToRecovered, (int)InfectionState::InfectedCritical}}; - - for (int contribution = 0; contribution < 4; contribution++) { - support_max_index = (Eigen::Index)std::ceil( - std::max(m_transitiondistributions_support_max[relevant_transitions_with_state[contribution][0]], - m_transitiondistributions_support_max[relevant_transitions_with_state[contribution][1]]) / - dt); - sum = 0; - for (int i = 0; i <= support_max_index; i++) { - ScalarType state_age_i = static_cast(i) * dt; - sum += - (parameters.get()[relevant_transitions_with_state[contribution][0]] * - parameters.get()[relevant_transitions_with_state[contribution][0]].eval( - state_age_i) + - parameters.get()[relevant_transitions_with_state[contribution][1]] * - parameters.get()[relevant_transitions_with_state[contribution][1]].eval( - state_age_i)) * - std::exp(-parameters.get() * state_age_i); + ScalarType sum = 0; + for (int contribution = 0; contribution < 5; contribution++) { + int calc_time_index = m_transitiondistributions[relevant_states[contribution]].size(); + for (int i = 0; i < calc_time_index; i++) { + ScalarType state_age_i = (ScalarType)i * dt; + sum += m_transitiondistributions[relevant_states[contribution]][i] * + std::exp(-parameters.get() * state_age_i); } - m_meansojourntime[relevant_transitions_with_state[contribution][2]] = dt * sum; + + m_meansojourntime[relevant_states[contribution]] = dt * sum; } } diff --git a/cpp/models/ide_endemic_secir/model.h b/cpp/models/ide_endemic_secir/model.h index 8961097313..11692d18a6 100644 --- a/cpp/models/ide_endemic_secir/model.h +++ b/cpp/models/ide_endemic_secir/model.h @@ -53,8 +53,14 @@ class Model TimeSeries transitions; ///< TimesSeries containing points of time and the corresponding number of individuals transitioning // from one #InfectionState to another as defined in #Infection%s. + TimeSeries + transitions_update; ///< TimesSeries containing points of time and the corresponding number of individuals transitioning + // from one #InfectionState to another as defined in #Infection%s. In this case we use the update formula version. TimeSeries populations; ///< TimeSeries containing points of time and the corresponding number of people - // in defined #InfectionState%s. + // in defined #InfectionState%s. In this case we compute them by a sum. + TimeSeries + populations_update; ///< TimeSeries containing points of time and the corresponding number of people + // in defined #InfectionState%s. We compute them by an update formula. private: // ---- Functionality for the iterations of a simulation. @@ -112,6 +118,9 @@ class Model */ void flows_currents_timestep(ScalarType dt); + void update_compartment_with_sum(InfectionState infectionState, + std::vector const& IncomingFlows, bool NaturalDeathispossible, + ScalarType dt); /** * @brief Updates the values of one compartment, specified in infectionState, using the transitions. * @@ -144,7 +153,7 @@ class Model void compute_populationsize(); /** - * @brief Compute the normalized compartments for the current last time in normalized_populations. + * @brief Compute the normalized compartments for the current last time in m_normalizedpopulations. * * The normalized compartments are computed as populations / m_populationsize. */ @@ -184,6 +193,12 @@ class Model */ void set_transitiondistributions(ScalarType dt); + /** + * @brief Setter for m_calctime + * + * The calculation is the maximum of the support max of the InfectionTransitionDistributions needed to compute the + * mean infectivity. + */ void set_calctime(); /** @@ -242,8 +257,14 @@ class Model TimeSeries m_forceofinfection{ TimeSeries(1)}; ///< TimeSeries containing the Force of infection term for every time point, // needed for the numerical scheme. + TimeSeries m_forceofinfectionupdate{ + TimeSeries(1)}; ///< TimeSeries containing the Force of infection term for every time point, + // needed for the numerical scheme. For the numerical scheme using the update formula for the compartments. TimeSeries m_totalpopulation{TimeSeries( 1)}; ///< TimeSeries containing the total population size of the considered region for each time point. + TimeSeries m_totalpopulationupdate{TimeSeries( + 1)}; ///< TimeSeries containing the total population size of the considered region for each time point. + //In this case we use the compartments from populations_update. TimeSeries m_normalizedpopulations{ TimeSeries(Eigen::Index(InfectionState::Count) - 1)}; ///< TimeSeries containing points of time and the corresponding portion @@ -255,13 +276,11 @@ class Model std::vector m_transitiondistributions_support_max{ std::vector((int)InfectionTransition::Count, 0.)}; ///< A vector containing the support_max // for all TransitionDistributions. - std::vector> m_transitiondistributions_in_forceofinfection{ - std::vector>( - 2, std::vector(1, 0.))}; ///> A vectpr containing the weighted TransitionDistributions - // needed in the compuation of the initial functions for the compartments and the mean infectivity at all necessary - // time points. + std::vector> m_transitiondistributions{std::vector>( + (int)InfectionTransition::Count, + std::vector(1, 0.))}; ///> A vector containing the weighted TransitionDistributions. std::vector> m_transitiondistributions_derivative{std::vector>( - (int)InfectionTransition::Count, std::vector(1, 0.))}; ///> A Vector containing + (int)InfectionState::Count, std::vector(1, 0.))}; ///> A Vector containing // the approximated derivative for all TransitionDistributions for all necessary time points. std::vector m_meaninfectivity{ std::vector(1, 0.)}; ///> a vector containing the approximated mean infectivity for all time points. From 36f7854f556a9116961259a9ba9ee21569efbd90 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Mon, 2 Jun 2025 10:33:59 +0200 Subject: [PATCH 05/22] Small changes --- cpp/examples/ide_endemic_secir.cpp | 14 ++-- cpp/models/ide_endemic_secir/model.cpp | 75 +++++++++++++-------- cpp/models/ide_endemic_secir/model.h | 12 +++- cpp/models/ide_endemic_secir/simulation.cpp | 7 ++ cpp/models/ide_endemic_secir/simulation.h | 35 ++++++++++ 5 files changed, 109 insertions(+), 34 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index 74e6e50f96..7bd3c4fa27 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -19,7 +19,7 @@ int main() using Vec = mio::TimeSeries::Vector; ScalarType tmax = 10; - ScalarType dt = 0.1; + ScalarType dt = 1.; int num_states = static_cast(mio::endisecir::InfectionState::Count); int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); @@ -75,8 +75,10 @@ int main() model.parameters.get() = exponential_prob; model.parameters.get() = exponential_prob; - model.parameters.set(5e-3); - model.parameters.set(3e-3); + model.parameters.set(0.); + model.parameters.set(0.); + + //model.set_tol_for_support_max(1e-6); // start the simulation. mio::endisecir::Simulation sim(model, dt); @@ -86,6 +88,9 @@ int main() interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); + auto interpolated_results_update = mio::interpolate_simulation_result(sim.get_compartments_update(), dt / 2.); + + // interpolated_results_update.print_table({"US", "UE", "UC", "UI", "UH", "UU", "UR", "UD"}, 16, 8); // Uncomment to print the reproduction number std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; @@ -100,7 +105,8 @@ int main() sim.get_totalpopulations().print_table({"N"}, 16, 9); // Uncomment to print the force of infection. - sim.get_forceofinfections().print_table({"FoI"}, 16, 8); + //sim.get_forceofinfections().print_table({"FoI"}, 16, 8); + //sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); // std::vector equi = sim.get_equilibriumcompartments(); // std::cout << "Equilibrium normalized compartments: \n"; diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index bb59379dbf..ded427da96 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace mio @@ -23,8 +24,9 @@ Model::Model(TimeSeries&& states_init) , transitions{TimeSeries(Eigen::Index(InfectionTransition::Count))} , transitions_update{TimeSeries(Eigen::Index(InfectionTransition::Count))} , populations{std::move(states_init)} - , populations_update{std::move(states_init)} + , populations_update{TimeSeries(Eigen::Index(InfectionState::Count))} { + populations_update.add_time_point(0, populations[0]); // Set flows at start time t0. // As we assume that all individuals have infectio age 0 at time t0, the flows at t0 are set to 0. transitions.add_time_point( @@ -37,6 +39,12 @@ Model::Model(TimeSeries&& states_init) std::accumulate(populations[0].begin(), populations[0].end(), 0) - populations[0][(int)InfectionState::Dead]; m_totalpopulation.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); m_totalpopulationupdate.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); + // m_totalpopulationincludingD.add_time_point( + // 0, + // TimeSeries::Vector::Constant(1, init_populationsize + populations[0][(int)InfectionState::Dead])); + // m_totalpopulationupdateincludingD.add_time_point( + // 0, + // TimeSeries::Vector::Constant(1, init_populationsize + populations[0][(int)InfectionState::Dead])); // Set the force of infection at start time t0. m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); m_forceofinfectionupdate.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); @@ -93,23 +101,24 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx (Eigen::Index)std::ceil(m_transitiondistributions_support_max[idx_InfectionTransitions] / dt); ScalarType current_time_age = static_cast(current_time_index) * dt; - ScalarType sum = 0; - + ScalarType sum1 = 0; + ScalarType sum2 = 0; //Determine the starting point of the for loop. Eigen::Index starting_point = std::max(0, (int)current_time_index - (int)calc_time_index); + for (Eigen::Index i = starting_point; i < current_time_index; i++) { ScalarType state_age_i = static_cast(i) * dt; - sum += transitions[i + 1][idx_IncomingFlow] * - std::exp(-parameters.get() * (current_time_age - state_age_i)) * - m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; + sum1 += transitions[i + 1][idx_IncomingFlow] * + std::exp(-parameters.get() * (current_time_age - state_age_i)) * + m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; //For the update formula version of the model: - sum += transitions_update[i + 1][idx_IncomingFlow] * - std::exp(-parameters.get() * (current_time_age - state_age_i)) * - m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; + sum2 += transitions_update[i + 1][idx_IncomingFlow] * + std::exp(-parameters.get() * (current_time_age - state_age_i)) * + m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; } if (current_time_index <= calc_time_index) { transitions.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions] * sum - + (-dt) * parameters.get()[idx_InfectionTransitions] * sum1 - std::exp((-parameters.get()) * (current_time_age)) * populations[0][idx_CurrentCompartment] * parameters.get()[idx_InfectionTransitions] * @@ -117,7 +126,7 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx //For the update formula version of the model: transitions_update.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions] * sum - + (-dt) * parameters.get()[idx_InfectionTransitions] * sum2 - std::exp((-parameters.get()) * (current_time_age)) * populations_update[0][idx_CurrentCompartment] * parameters.get()[idx_InfectionTransitions] * @@ -125,11 +134,11 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx } else { transitions.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions] * sum; + (-dt) * parameters.get()[idx_InfectionTransitions] * sum1; //For the update formula version of the model: transitions_update.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions] * sum; + (-dt) * parameters.get()[idx_InfectionTransitions] * sum2; } } @@ -194,7 +203,7 @@ void Model::flows_currents_timestep(ScalarType dt) void Model::update_compartment_with_sum(InfectionState infectionState, std::vector const& IncomingFlows, - bool NaturalDeathispossible, ScalarType dt) + bool NaturalDeathispossible, bool Transitionispossible, ScalarType dt) { Eigen::Index current_time_index = populations.get_num_time_points() - 1; ScalarType current_time_age = (ScalarType)current_time_index * dt; @@ -206,20 +215,28 @@ void Model::update_compartment_with_sum(InfectionState infectionState, for (const InfectionTransition& inflow : IncomingFlows) { sum_inflows += transitions[i + 1][(int)inflow]; } - if (NaturalDeathispossible) { + if (NaturalDeathispossible && Transitionispossible) { sum += m_transitiondistributions[(int)infectionState][current_time_index - i] * sum_inflows * std::exp(-parameters.get() * (current_time_age - state_age_i)); } + else if (NaturalDeathispossible && !Transitionispossible) { + sum += sum_inflows * std::exp(-parameters.get() * (current_time_age - state_age_i)); + } else { - sum += m_transitiondistributions[(int)infectionState][current_time_index - i] * sum_inflows; + sum += sum_inflows; } } - if (NaturalDeathispossible) { + if (NaturalDeathispossible && Transitionispossible) { populations.get_last_value()[(int)infectionState] = dt * sum + m_transitiondistributions[(int)infectionState][current_time_index] * populations[0][(int)infectionState] * std::exp(-parameters.get() * (current_time_age)); } + else if (NaturalDeathispossible && !Transitionispossible) { + populations.get_last_value()[(int)infectionState] = + dt * sum + + populations[0][(int)infectionState] * std::exp(-parameters.get() * (current_time_age)); + } else { populations.get_last_value()[(int)infectionState] = dt * sum + @@ -256,14 +273,14 @@ void Model::update_compartments(ScalarType dt) // Exposed update_compartment_from_flow(InfectionState::Exposed, {InfectionTransition::SusceptibleToExposed}, {InfectionTransition::ExposedToInfectedNoSymptoms}, true, dt); - update_compartment_with_sum(InfectionState::Exposed, {InfectionTransition::SusceptibleToExposed}, true, dt); + update_compartment_with_sum(InfectionState::Exposed, {InfectionTransition::SusceptibleToExposed}, true, true, dt); // InfectedNoSymptoms update_compartment_from_flow( InfectionState::InfectedNoSymptoms, {InfectionTransition::ExposedToInfectedNoSymptoms}, {InfectionTransition::InfectedNoSymptomsToInfectedSymptoms, InfectionTransition::InfectedNoSymptomsToRecovered}, true, dt); update_compartment_with_sum(InfectionState::InfectedNoSymptoms, {InfectionTransition::ExposedToInfectedNoSymptoms}, - true, dt); + true, true, dt); // InfectedSymptoms update_compartment_from_flow( @@ -271,7 +288,7 @@ void Model::update_compartments(ScalarType dt) {InfectionTransition::InfectedSymptomsToInfectedSevere, InfectionTransition::InfectedSymptomsToRecovered}, true, dt); update_compartment_with_sum(InfectionState::InfectedSymptoms, - {InfectionTransition::InfectedNoSymptomsToInfectedSymptoms}, true, dt); + {InfectionTransition::InfectedNoSymptomsToInfectedSymptoms}, true, true, dt); // InfectedSevere update_compartment_from_flow( @@ -279,14 +296,14 @@ void Model::update_compartments(ScalarType dt) {InfectionTransition::InfectedSevereToInfectedCritical, InfectionTransition::InfectedSevereToRecovered}, true, dt); update_compartment_with_sum(InfectionState::InfectedSevere, {InfectionTransition::InfectedSymptomsToInfectedSevere}, - true, dt); + true, true, dt); // InfectedCritical update_compartment_from_flow( InfectionState::InfectedCritical, {InfectionTransition::InfectedSevereToInfectedCritical}, {InfectionTransition::InfectedCriticalToDead, InfectionTransition::InfectedCriticalToRecovered}, true, dt); update_compartment_with_sum(InfectionState::InfectedCritical, - {InfectionTransition::InfectedSevereToInfectedCritical}, true, dt); + {InfectionTransition::InfectedSevereToInfectedCritical}, true, true, dt); // Recovered update_compartment_from_flow(InfectionState::Recovered, { @@ -303,12 +320,12 @@ void Model::update_compartments(ScalarType dt) InfectionTransition::InfectedSevereToRecovered, InfectionTransition::InfectedCriticalToRecovered, }, - true, dt); + true, false, dt); // Dead update_compartment_from_flow(InfectionState::Dead, {InfectionTransition::InfectedCriticalToDead}, std::vector(), false, dt); - update_compartment_with_sum(InfectionState::Dead, {InfectionTransition::InfectedCriticalToDead}, false, dt); + update_compartment_with_sum(InfectionState::Dead, {InfectionTransition::InfectedCriticalToDead}, false, false, dt); } void Model::compute_populationsize() @@ -319,6 +336,10 @@ void Model::compute_populationsize() m_totalpopulationupdate.get_last_value()[0] = std::accumulate(populations_update.get_last_value().begin(), populations_update.get_last_value().end(), 0) - populations_update.get_last_value()[(int)InfectionState::Dead]; + // m_totalpopulationincludingD.get_last_value()[0] = + // std::accumulate(populations.get_last_value().begin(), populations.get_last_value().end(), 0); + // m_totalpopulationupdateincludingD.get_last_value()[0] = + // std::accumulate(populations_update.get_last_value().begin(), populations_update.get_last_value().end(), 0); } void Model::compute_normalizedcompartments() @@ -420,7 +441,7 @@ void Model::compute_forceofinfection(ScalarType dt) populations_update[i + 1][(int)InfectionState::Susceptible] * m_forceofinfectionupdate[i][0]; } - m_forceofinfection.get_last_value()[0] = + m_forceofinfectionupdate.get_last_value()[0] = foi_0 / m_totalpopulationupdate[num_time_points - 1][0] + f / m_totalpopulationupdate[num_time_points - 1][0] + (dt * sum) * (parameters.get().eval(current_time) * @@ -482,8 +503,8 @@ void Model::set_transitiondistributions(ScalarType dt) for (int state = 2; state < (int)InfectionState::Count - 2; state++) { Eigen::Index calc_time_index = - (Eigen::Index)std::ceil(std::max(m_transitiondistributions_support_max[transitions[state - 2][0]], - m_transitiondistributions_support_max[transitions[state - 2][1]]) / + (Eigen::Index)std::ceil(std::max(m_transitiondistributions_support_max[vector_transitions[state - 2][0]], + m_transitiondistributions_support_max[vector_transitions[state - 2][1]]) / dt); // Create vec_derivative that stores the value of the approximated derivative for all necessary time points. diff --git a/cpp/models/ide_endemic_secir/model.h b/cpp/models/ide_endemic_secir/model.h index 11692d18a6..478a49f7da 100644 --- a/cpp/models/ide_endemic_secir/model.h +++ b/cpp/models/ide_endemic_secir/model.h @@ -120,7 +120,7 @@ class Model void update_compartment_with_sum(InfectionState infectionState, std::vector const& IncomingFlows, bool NaturalDeathispossible, - ScalarType dt); + bool Transitionispossible, ScalarType dt); /** * @brief Updates the values of one compartment, specified in infectionState, using the transitions. * @@ -265,6 +265,12 @@ class Model TimeSeries m_totalpopulationupdate{TimeSeries( 1)}; ///< TimeSeries containing the total population size of the considered region for each time point. //In this case we use the compartments from populations_update. + // TimeSeries m_totalpopulationincludingD{TimeSeries( + // 1)}; ///< TimeSeries containing the total population size + the all persons who died of the disease + // // of the considered region for each time point. + // TimeSeries m_totalpopulationupdateincludingD{TimeSeries( + // 1)}; ///< TimeSeries containing the total population size + the all persons who died of the disease + // // of the considered region for each time point. In this case we use the compartments from populations_update. TimeSeries m_normalizedpopulations{ TimeSeries(Eigen::Index(InfectionState::Count) - 1)}; ///< TimeSeries containing points of time and the corresponding portion @@ -277,10 +283,10 @@ class Model std::vector((int)InfectionTransition::Count, 0.)}; ///< A vector containing the support_max // for all TransitionDistributions. std::vector> m_transitiondistributions{std::vector>( - (int)InfectionTransition::Count, + (int)InfectionState::Count, std::vector(1, 0.))}; ///> A vector containing the weighted TransitionDistributions. std::vector> m_transitiondistributions_derivative{std::vector>( - (int)InfectionState::Count, std::vector(1, 0.))}; ///> A Vector containing + (int)InfectionTransition::Count, std::vector(1, 0.))}; ///> A Vector containing // the approximated derivative for all TransitionDistributions for all necessary time points. std::vector m_meaninfectivity{ std::vector(1, 0.)}; ///> a vector containing the approximated mean infectivity for all time points. diff --git a/cpp/models/ide_endemic_secir/simulation.cpp b/cpp/models/ide_endemic_secir/simulation.cpp index 38cb64bd5b..d5de927642 100644 --- a/cpp/models/ide_endemic_secir/simulation.cpp +++ b/cpp/models/ide_endemic_secir/simulation.cpp @@ -30,9 +30,16 @@ void Simulation::advance(ScalarType tmax) while (m_model->transitions.get_last_time() < tmax - m_dt / 2) { m_model->transitions.add_time_point(m_model->transitions.get_last_time() + m_dt); + m_model->transitions_update.add_time_point(m_model->transitions_update.get_last_time() + m_dt); m_model->populations.add_time_point(m_model->populations.get_last_time() + m_dt); + m_model->populations_update.add_time_point(m_model->populations_update.get_last_time() + m_dt); m_model->m_forceofinfection.add_time_point(m_model->m_forceofinfection.get_last_time() + m_dt); + m_model->m_forceofinfectionupdate.add_time_point(m_model->m_forceofinfectionupdate.get_last_time() + m_dt); m_model->m_totalpopulation.add_time_point(m_model->m_totalpopulation.get_last_time() + m_dt); + m_model->m_totalpopulationupdate.add_time_point(m_model->m_totalpopulationupdate.get_last_time() + m_dt); + // m_model->m_totalpopulationincludingD.add_time_point(m_model->m_totalpopulationupdate.get_last_time() + m_dt); + // m_model->m_totalpopulationupdateincludingD.add_time_point(m_model->m_totalpopulationupdate.get_last_time() + + // m_dt); m_model->m_normalizedpopulations.add_time_point(m_model->m_normalizedpopulations.get_last_time() + m_dt); // Compute susceptibles: diff --git a/cpp/models/ide_endemic_secir/simulation.h b/cpp/models/ide_endemic_secir/simulation.h index ff242146ea..a3926d102c 100644 --- a/cpp/models/ide_endemic_secir/simulation.h +++ b/cpp/models/ide_endemic_secir/simulation.h @@ -35,6 +35,11 @@ class Simulation return m_model->populations; } + TimeSeries get_compartments_update() + { + return m_model->populations_update; + } + TimeSeries get_normalizedcompartments() { return m_model->m_normalizedpopulations; @@ -49,6 +54,11 @@ class Simulation return m_model->populations; } + TimeSeries& get_compartments_update() const + { + return m_model->populations_update; + } + TimeSeries& get_normalizedcompartments() const { return m_model->m_normalizedpopulations; @@ -62,16 +72,41 @@ class Simulation return m_model->transitions; } + TimeSeries const& get_transitions_update() + { + return m_model->transitions_update; + } + TimeSeries const& get_forceofinfections() { return m_model->m_forceofinfection; } + TimeSeries const& get_forceofinfections_update() + { + return m_model->m_forceofinfectionupdate; + } + TimeSeries const& get_totalpopulations() { return m_model->m_totalpopulation; } + TimeSeries const& get_totalpopulations_update() + { + return m_model->m_totalpopulationupdate; + } + + // TimeSeries const& get_totalpopulations_includingD() + // { + // return m_model->m_totalpopulationincludingD; + // } + + // TimeSeries const& get_totalpopulations_update_includingD() + // { + // return m_model->m_totalpopulationupdateincludingD; + // } + ScalarType const& get_reproductionnumber_c() { return m_model->m_reproductionnumber_c; From bbd75075ecd735f2b7f34cf14db00c1e294aafc0 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Thu, 12 Jun 2025 14:41:19 +0200 Subject: [PATCH 06/22] Small changes --- cpp/examples/ide_endemic_secir.cpp | 66 ++++++++++++++------------ cpp/models/ide_endemic_secir/model.cpp | 36 ++++++++------ 2 files changed, 57 insertions(+), 45 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index 7bd3c4fa27..9586e6a046 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -18,7 +18,7 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 10; + ScalarType tmax = 100; ScalarType dt = 1.; int num_states = static_cast(mio::endisecir::InfectionState::Count); @@ -29,13 +29,13 @@ int main() Vec vec_init(num_states); - vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = 9950.; - vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = 25.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = 15.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = 8.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedSevere)] = 1.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedCritical)] = 1.; - vec_init[static_cast(mio::endisecir::InfectionState::Recovered)] = 5.; + vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = 10000.; + vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = 10.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = 10.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSevere)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedCritical)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::Recovered)] = 0.; vec_init[static_cast(mio::endisecir::InfectionState::Dead)] = 0.; init.add_time_point(0, vec_init); @@ -44,11 +44,11 @@ int main() //Set working parameters - // mio::ExponentialSurvivalFunction exp(2.0); + // mio::ExponentialSurvivalFunction exp(3.0); // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - mio::SmootherCosine smoothcos(4.0); + mio::SmootherCosine smoothcos(2.0); mio::StateAgeFunctionWrapper delaydistribution(smoothcos); std::vector vec_delaydistribution(num_transitions, delaydistribution); @@ -75,8 +75,8 @@ int main() model.parameters.get() = exponential_prob; model.parameters.get() = exponential_prob; - model.parameters.set(0.); - model.parameters.set(0.); + model.parameters.set(4e-4); + model.parameters.set(3e-4); //model.set_tol_for_support_max(1e-6); @@ -88,34 +88,38 @@ int main() interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); - auto interpolated_results_update = mio::interpolate_simulation_result(sim.get_compartments_update(), dt / 2.); - + // Uncomment to print the compartments computed with the update scheme. + // auto interpolated_results_update = mio::interpolate_simulation_result(sim.get_compartments_update(), dt / 2.); // interpolated_results_update.print_table({"US", "UE", "UC", "UI", "UH", "UU", "UR", "UD"}, 16, 8); + // Uncomment to print the reproduction number std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; // Uncomment to print the transitions. - // sim.get_transitions().print_table( - // {"S->E 1", "E->C 1", "C->I 1", "C->R 1", "I->H 1", "I->R 1", "H->U 1", "H->R 1", "U->D 1", "U->R 1"}, 16, 8); + sim.get_transitions().print_table( + {"S->E 1", "E->C 1", "C->I 1", "C->R 1", "I->H 1", "I->R 1", "H->U 1", "H->R 1", "U->D 1", "U->R 1"}, 16, 8); + // sim.get_transitions_update().print_table( + // {"US->E 1", "UE->C 1", "UC->I 1", "UC->R 1", "UI->H 1", "UI->R 1", "UH->U 1", "uH->R 1", "UU->D 1", "UU->R 1"}, + // 16, 8); // Uncomment to print the normalized compartments. - // sim.get_normalizedcompartments().print_table({"s", "e", "c", "i", "h", "u", "r", "d "}, 16, 8); + sim.get_normalizedcompartments().print_table({"s", "e", "c", "i", "h", "u", "r", "d "}, 16, 8); // Uncomment to print the total population size. - sim.get_totalpopulations().print_table({"N"}, 16, 9); + // sim.get_totalpopulations().print_table({"N"}, 16, 9); // Uncomment to print the force of infection. - //sim.get_forceofinfections().print_table({"FoI"}, 16, 8); - //sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); - - // std::vector equi = sim.get_equilibriumcompartments(); - // std::cout << "Equilibrium normalized compartments: \n"; - // std::cout << "foi* " << sim.get_equilibrium_forceofinfection() << "\n"; - // std::cout << "s* " << equi[(int)mio::endisecir::InfectionState::Susceptible] << "\n"; - // std::cout << "e* " << equi[(int)mio::endisecir::InfectionState::Exposed] << "\n"; - // std::cout << "c* " << equi[(int)mio::endisecir::InfectionState::InfectedNoSymptoms] << "\n"; - // std::cout << "i* " << equi[(int)mio::endisecir::InfectionState::InfectedSymptoms] << "\n"; - // std::cout << "h* " << equi[(int)mio::endisecir::InfectionState::InfectedSevere] << "\n"; - // std::cout << "u* " << equi[(int)mio::endisecir::InfectionState::InfectedCritical] << "\n"; - // std::cout << "r* " << equi[(int)mio::endisecir::InfectionState::Recovered] << "\n"; + sim.get_forceofinfections().print_table({"FoI"}, 16, 8); + // sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); + + std::vector equi = sim.get_equilibriumcompartments(); + std::cout << "Equilibrium normalized compartments: \n"; + std::cout << "foi* " << sim.get_equilibrium_forceofinfection() << "\n"; + std::cout << "s* " << equi[(int)mio::endisecir::InfectionState::Susceptible] << "\n"; + std::cout << "e* " << equi[(int)mio::endisecir::InfectionState::Exposed] << "\n"; + std::cout << "c* " << equi[(int)mio::endisecir::InfectionState::InfectedNoSymptoms] << "\n"; + std::cout << "i* " << equi[(int)mio::endisecir::InfectionState::InfectedSymptoms] << "\n"; + std::cout << "h* " << equi[(int)mio::endisecir::InfectionState::InfectedSevere] << "\n"; + std::cout << "u* " << equi[(int)mio::endisecir::InfectionState::InfectedCritical] << "\n"; + std::cout << "r* " << equi[(int)mio::endisecir::InfectionState::Recovered] << "\n"; } \ No newline at end of file diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index ded427da96..fb8aba3016 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -207,9 +207,15 @@ void Model::update_compartment_with_sum(InfectionState infectionState, { Eigen::Index current_time_index = populations.get_num_time_points() - 1; ScalarType current_time_age = (ScalarType)current_time_index * dt; - ScalarType sum = 0; + Eigen::Index calc_time_index = current_time_index; + if (Transitionispossible) { + calc_time_index = m_transitiondistributions[(int)infectionState].size() - 1; + } + + ScalarType sum = 0; - for (int i = 0; i < current_time_index; i++) { + Eigen::Index starting_point = std::max(0, (int)current_time_index - (int)calc_time_index); + for (int i = starting_point; i < current_time_index; i++) { ScalarType state_age_i = (ScalarType)i * dt; ScalarType sum_inflows = 0; for (const InfectionTransition& inflow : IncomingFlows) { @@ -227,10 +233,15 @@ void Model::update_compartment_with_sum(InfectionState infectionState, } } if (NaturalDeathispossible && Transitionispossible) { - populations.get_last_value()[(int)infectionState] = - dt * sum + m_transitiondistributions[(int)infectionState][current_time_index] * - populations[0][(int)infectionState] * - std::exp(-parameters.get() * (current_time_age)); + if (current_time_index <= calc_time_index) { + populations.get_last_value()[(int)infectionState] = + dt * sum + m_transitiondistributions[(int)infectionState][current_time_index] * + populations[0][(int)infectionState] * + std::exp(-parameters.get() * (current_time_age)); + } + else { + populations.get_last_value()[(int)infectionState] = dt * sum; + } } else if (NaturalDeathispossible && !Transitionispossible) { populations.get_last_value()[(int)infectionState] = @@ -250,20 +261,17 @@ void Model::update_compartment_from_flow(InfectionState infectionState, { Eigen::Index num_time_points = populations.get_num_time_points(); - ScalarType updated_compartment = 0; - if (NaturalDeathispossible) { - updated_compartment = populations_update[num_time_points - 2][static_cast(infectionState)] * - (1 - dt * parameters.get()); - } - else { - updated_compartment = populations_update[num_time_points - 2][static_cast(infectionState)]; - } + ScalarType updated_compartment = populations_update[num_time_points - 2][static_cast(infectionState)]; + for (const InfectionTransition& inflow : IncomingFlows) { updated_compartment += dt * transitions_update.get_last_value()[(int)inflow]; } for (const InfectionTransition& outflow : OutgoingFlows) { updated_compartment -= dt * transitions_update.get_last_value()[(int)outflow]; } + if (NaturalDeathispossible) { + updated_compartment = updated_compartment / (1 + dt * parameters.get()); + } populations_update.get_last_value()[(int)infectionState] = updated_compartment; } From 7619990e6fe49af5713a1d70449fe261cb3aee3c Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Thu, 26 Jun 2025 11:16:56 +0200 Subject: [PATCH 07/22] Added an example to save results in order to produce plots. --- cpp/examples/CMakeLists.txt | 7 + cpp/examples/ide_endemic_secir.cpp | 19 +- .../ide_endemic_secir_save_results.cpp | 235 ++++++++++++++++++ 3 files changed, 251 insertions(+), 10 deletions(-) create mode 100644 cpp/examples/ide_endemic_secir_save_results.cpp diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 96e0d02ecb..bc607a6eeb 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -179,8 +179,15 @@ if(MEMILIO_HAS_HDF5) target_compile_options(ode_secir_save_results_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) endif() + if(MEMILIO_HAS_JSONCPP) add_executable(ide_initialization_example ide_initialization.cpp) target_link_libraries(ide_initialization_example PRIVATE memilio ide_secir) target_compile_options(ide_initialization_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) endif() + +if(MEMILIO_HAS_HDF5) + add_executable(ide_endemic_secir_save_results_example ide_endemic_secir_save_results.cpp) + target_link_libraries(ide_endemic_secir_save_results_example PRIVATE memilio ide_endemic_secir) + target_compile_options(ide_endemic_secir_save_results_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +endif() \ No newline at end of file diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index 9586e6a046..7a2a3963f9 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -2,7 +2,6 @@ #include "ide_endemic_secir/infection_state.h" #include "ide_endemic_secir/parameters.h" #include "ide_endemic_secir/simulation.h" -#include "ide_endemic_secir/infection_state.h" #include "memilio/config.h" #include "memilio/math/eigen.h" #include "memilio/utils/custom_index_array.h" @@ -18,8 +17,8 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 100; - ScalarType dt = 1.; + ScalarType tmax = 30; + ScalarType dt = 0.1; int num_states = static_cast(mio::endisecir::InfectionState::Count); int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); @@ -29,7 +28,7 @@ int main() Vec vec_init(num_states); - vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = 10000.; + vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = 100000.; vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = 10.; vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = 0.; vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = 10.; @@ -64,7 +63,7 @@ int main() contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); model.parameters.get() = mio::UncertainContactMatrix(contact_matrix); - mio::ConstantFunction constant(0.1); + mio::ConstantFunction constant(0.5); mio::StateAgeFunctionWrapper constant_prob(constant); model.parameters.get() = constant_prob; @@ -96,20 +95,20 @@ int main() std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; // Uncomment to print the transitions. - sim.get_transitions().print_table( - {"S->E 1", "E->C 1", "C->I 1", "C->R 1", "I->H 1", "I->R 1", "H->U 1", "H->R 1", "U->D 1", "U->R 1"}, 16, 8); + //sim.get_transitions().print_table( + // {"S->E 1", "E->C 1", "C->I 1", "C->R 1", "I->H 1", "I->R 1", "H->U 1", "H->R 1", "U->D 1", "U->R 1"}, 16, 8); // sim.get_transitions_update().print_table( // {"US->E 1", "UE->C 1", "UC->I 1", "UC->R 1", "UI->H 1", "UI->R 1", "UH->U 1", "uH->R 1", "UU->D 1", "UU->R 1"}, // 16, 8); // Uncomment to print the normalized compartments. - sim.get_normalizedcompartments().print_table({"s", "e", "c", "i", "h", "u", "r", "d "}, 16, 8); + //sim.get_normalizedcompartments().print_table({"s", "e", "c", "i", "h", "u", "r", "d "}, 16, 8); // Uncomment to print the total population size. - // sim.get_totalpopulations().print_table({"N"}, 16, 9); + sim.get_totalpopulations().print_table({"N"}, 16, 9); // Uncomment to print the force of infection. - sim.get_forceofinfections().print_table({"FoI"}, 16, 8); + //sim.get_forceofinfections().print_table({"FoI"}, 16, 8); // sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); std::vector equi = sim.get_equilibriumcompartments(); diff --git a/cpp/examples/ide_endemic_secir_save_results.cpp b/cpp/examples/ide_endemic_secir_save_results.cpp new file mode 100644 index 0000000000..5c3b6e79ad --- /dev/null +++ b/cpp/examples/ide_endemic_secir_save_results.cpp @@ -0,0 +1,235 @@ +#include "memilio/io/result_io.h" +#include "memilio/utils/time_series.h" +#include "memilio/config.h" +#include "memilio/epidemiology/state_age_function.h" +#include "memilio/epidemiology/uncertain_matrix.h" +#include "memilio/math/floating_point.h" + +#include "ide_endemic_secir/infection_state.h" +#include "ide_endemic_secir/model.h" +#include "ide_endemic_secir/simulation.h" +#include "ide_endemic_secir/parameters.h" + +#include "boost/filesystem.hpp" +#include +#include +#include + +std::map simulation_parameter = {{"dt", 0.1}, + {"t0", 0.}, + {"Susceptibles", 10000.}, + {"Exposed", 0}, + {"InfectedNoSymptoms", 10.}, + {"InfectedSymptoms", 20}, + {"InfectedSevere", 0.}, + {"InfectedCritical", 0.}, + {"Recovered", 0.}, + {"Dead", 0.}, + {"TransmissionProbabilityOnContact", 0.4}, + {"RelativeTransmissionNoSymptoms", 0.5}, + {"RiskOfInfectionFromSymptomatic", 0.5}, + {"InfectedSymptomsPerInfectedNoSymptoms", 0.5}, + {"SeverePerInfectedSymptoms", 0.2}, + {"CriticalPerSevere", 0.5}, + {"DeathsPerCritical", 0.2}, + {"BirthRate1", 4e-5}, + {"DeathRate1", 3e-5}, + {"BirthRate2", 3e-5}, + {"DeathRate2", 3e-5}, + {"BirthRate3", 3e-5}, + {"DeathRate3", 4e-5}, + {"Contacts", 10.}}; + +mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = "") +{ + int num_states = static_cast(mio::endisecir::InfectionState::Count); + int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); + + mio::TimeSeries init(num_states); + + mio::TimeSeries::Vector vec_init(num_states); + + vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = simulation_parameter["Susceptibles"]; + vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = simulation_parameter["Exposed"]; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = + simulation_parameter["InfectedNoSymptoms"]; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = + simulation_parameter["InfectedSymptoms"]; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSevere)] = simulation_parameter["InfectedSevere"]; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedCritical)] = + simulation_parameter["InfectedCritical"]; + vec_init[static_cast(mio::endisecir::InfectionState::Recovered)] = simulation_parameter["Recovered"]; + vec_init[static_cast(mio::endisecir::InfectionState::Dead)] = simulation_parameter["Dead"]; + + init.add_time_point(0, vec_init); + + // Model 1, with BirthRate > DeathRate: + mio::TimeSeries init_copy1(init); + mio::endisecir::Model model_endide1(std::move(init_copy1)); + + mio::SmootherCosine smoothcos(2.0); + mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + std::vector vec_delaydistribution(num_transitions, delaydistribution); + + model_endide1.parameters.get() = vec_delaydistribution; + + // Set other parameters. + std::vector vec_prob((int)mio::endisecir::InfectionTransition::Count, 1.); + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] = + simulation_parameter["InfectedSymptomsPerInfectedNoSymptoms"]; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered)] = + 1 - simulation_parameter["InfectedSymptomsPerInfectedNoSymptoms"]; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere)] = + simulation_parameter["SeverePerInfectedSymptoms"]; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered)] = + 1 - simulation_parameter["SeverePerInfectedSymptoms"]; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical)] = + simulation_parameter["CriticalPerSevere"]; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToRecovered)] = + 1 - simulation_parameter["CriticalPerSevere"]; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToDead)] = + simulation_parameter["DeathsPerCritical"]; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToRecovered)] = + 1 - simulation_parameter["DeathsPerCritical"]; + + model_endide1.parameters.set(vec_prob); + + mio::ContactMatrixGroup contact_matrix = mio::ContactMatrixGroup(1, 1); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, simulation_parameter["Contacts"])); + model_endide1.parameters.get() = mio::UncertainContactMatrix(contact_matrix); + + mio::ConstantFunction constfunc(simulation_parameter["TransmissionProbabilityOnContact"]); + mio::StateAgeFunctionWrapper StateAgeFunctionWrapperide(constfunc); + model_endide1.parameters.set(StateAgeFunctionWrapperide); + StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RelativeTransmissionNoSymptoms"]); + model_endide1.parameters.set(StateAgeFunctionWrapperide); + StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); + model_endide1.parameters.set(StateAgeFunctionWrapperide); + + model_endide1.parameters.set(simulation_parameter["BirthRate1"]); + model_endide1.parameters.set(simulation_parameter["DeathRate1"]); + + model_endide1.set_tol_for_support_max(1e-6); + model_endide1.check_constraints(); + + // Model 2, with BirthRate = DeathRate: + mio::TimeSeries init_copy2(init); + mio::endisecir::Model model_endide2(std::move(init_copy2)); + + model_endide2.parameters.get() = vec_delaydistribution; + + // Set other parameters. + model_endide2.parameters.set(vec_prob); + + model_endide2.parameters.get() = mio::UncertainContactMatrix(contact_matrix); + + mio::ConstantFunction constfunc2(simulation_parameter["TransmissionProbabilityOnContact"]); + mio::StateAgeFunctionWrapper StateAgeFunctionWrapperide2(constfunc); + model_endide2.parameters.set(StateAgeFunctionWrapperide2); + StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RelativeTransmissionNoSymptoms"]); + model_endide2.parameters.set(StateAgeFunctionWrapperide2); + StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); + model_endide2.parameters.set(StateAgeFunctionWrapperide2); + + model_endide2.parameters.set(simulation_parameter["BirthRate2"]); + model_endide2.parameters.set(simulation_parameter["DeathRate2"]); + + model_endide2.set_tol_for_support_max(1e-6); + model_endide2.check_constraints(); + + // Model 3, with BirthRate < DeathRate: + mio::TimeSeries init_copy3(init); + mio::endisecir::Model model_endide3(std::move(init_copy3)); + + model_endide2.parameters.get() = vec_delaydistribution; + + // Set other parameters. + model_endide2.parameters.set(vec_prob); + + model_endide2.parameters.get() = mio::UncertainContactMatrix(contact_matrix); + + mio::ConstantFunction constfunc3(simulation_parameter["TransmissionProbabilityOnContact"]); + mio::StateAgeFunctionWrapper StateAgeFunctionWrapperide3(constfunc); + model_endide3.parameters.set(StateAgeFunctionWrapperide3); + StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RelativeTransmissionNoSymptoms"]); + model_endide3.parameters.set(StateAgeFunctionWrapperide3); + StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); + model_endide3.parameters.set(StateAgeFunctionWrapperide3); + + model_endide3.parameters.set(simulation_parameter["BirthRate3"]); + model_endide3.parameters.set(simulation_parameter["DeathRate3"]); + + model_endide3.set_tol_for_support_max(1e-6); + model_endide3.check_constraints(); + + // Simulate. + mio::endisecir::Simulation sim1(model_endide1, simulation_parameter["dt"]); + sim1.advance(tmax); + mio::endisecir::Simulation sim2(model_endide2, simulation_parameter["dt"]); + sim2.advance(tmax); + mio::endisecir::Simulation sim3(model_endide3, simulation_parameter["dt"]); + sim3.advance(tmax); + + if (!save_dir.empty()) { + std::string tmax_string = std::to_string(tmax); + std::string dt_string = std::to_string(simulation_parameter["dt"]); + + std::string filename_ide = save_dir + "analysis_endide_" + tmax_string.substr(0, tmax_string.find(".")) + "_" + + dt_string.substr(0, dt_string.find(".") + 5); + + //Save total population for different birth and death rates + std::string filename_ide_totalpopulation1 = filename_ide + "_totalpopulation1.h5"; + mio::IOResult save_result_status_tp1 = + mio::save_result({sim1.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation1); + + std::string filename_ide_totalpopulation2 = filename_ide + "_totalpopulation2.h5"; + mio::IOResult save_result_status_tp2 = + mio::save_result({sim2.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation2); + + std::string filename_ide_totalpopulation3 = filename_ide + "_totalpopulation3.h5"; + mio::IOResult save_result_status_tp3 = + mio::save_result({sim3.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation3); + + //Save compartments for different birth and death rates + std::string filename_ide_compartments1 = filename_ide + "_compartments1.h5"; + mio::IOResult save_result_status_c1 = + mio::save_result({sim1.get_compartments()}, {0}, 1, filename_ide_compartments1); + + std::string filename_ide_compartments2 = filename_ide + "_compartments2.h5"; + mio::IOResult save_result_status_c2 = + mio::save_result({sim2.get_compartments()}, {0}, 1, filename_ide_compartments2); + + std::string filename_ide_compartments3 = filename_ide + "_compartments3.h5"; + mio::IOResult save_result_status_c3 = + mio::save_result({sim3.get_compartments()}, {0}, 1, filename_ide_compartments3); + + if (!save_result_status_tp1 || !save_result_status_tp2 || !save_result_status_tp3 || !save_result_status_c1 || + !save_result_status_c2 || !save_result_status_c3) { + return mio::failure(mio::StatusCode::UnknownError, "Error while saving results."); + } + } + + // Return results (i.e. total populations) of the simulation. + return mio::success(); +} + +int main(int argc, char** argv) +{ + std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDE/simulation_results/"; + + // Set result_dir via command line. + if (argc == 2) { + result_dir = argv[1]; + } + + // Define tmax for both scenarios. + ScalarType tmax = 500; + + auto result_ide = simulate_endidemodel(tmax, result_dir); + if (!result_ide) { + printf("%s\n", result_ide.error().formatted_message().c_str()); + return -1; + } + + return 0; +} \ No newline at end of file From 9ff899dab2241d35c6f71503dc5a60b62cd99988 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Thu, 26 Jun 2025 14:06:13 +0200 Subject: [PATCH 08/22] Fixed some small errors in the code --- cpp/examples/ide_endemic_secir.cpp | 37 ++++++++++--------- .../ide_endemic_secir_save_results.cpp | 23 +++++------- cpp/models/ide_endemic_secir/model.cpp | 10 ++--- 3 files changed, 31 insertions(+), 39 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index 7a2a3963f9..b6343e8b35 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -17,7 +17,7 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 30; + ScalarType tmax = 100; ScalarType dt = 0.1; int num_states = static_cast(mio::endisecir::InfectionState::Count); @@ -29,9 +29,9 @@ int main() Vec vec_init(num_states); vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = 100000.; - vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = 10.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = 0.; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = 10.; + vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = 10.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = 20.; vec_init[static_cast(mio::endisecir::InfectionState::InfectedSevere)] = 0.; vec_init[static_cast(mio::endisecir::InfectionState::InfectedCritical)] = 0.; vec_init[static_cast(mio::endisecir::InfectionState::Recovered)] = 0.; @@ -57,13 +57,14 @@ int main() // The following probabilities must be 1, as there is no other way to go. vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::SusceptibleToExposed)] = 1; vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms)] = 1; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToDead)] = 0.1; model.parameters.get() = vec_prob; mio::ContactMatrixGroup contact_matrix = mio::ContactMatrixGroup(1, 1); contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); model.parameters.get() = mio::UncertainContactMatrix(contact_matrix); - mio::ConstantFunction constant(0.5); + mio::ConstantFunction constant(0.1); mio::StateAgeFunctionWrapper constant_prob(constant); model.parameters.get() = constant_prob; @@ -74,8 +75,8 @@ int main() model.parameters.get() = exponential_prob; model.parameters.get() = exponential_prob; - model.parameters.set(4e-4); - model.parameters.set(3e-4); + model.parameters.set(3e-4); + model.parameters.set(4e-4); //model.set_tol_for_support_max(1e-6); @@ -105,20 +106,20 @@ int main() //sim.get_normalizedcompartments().print_table({"s", "e", "c", "i", "h", "u", "r", "d "}, 16, 8); // Uncomment to print the total population size. - sim.get_totalpopulations().print_table({"N"}, 16, 9); + // sim.get_totalpopulations().print_table({"N"}, 16, 9); // Uncomment to print the force of infection. //sim.get_forceofinfections().print_table({"FoI"}, 16, 8); // sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); - std::vector equi = sim.get_equilibriumcompartments(); - std::cout << "Equilibrium normalized compartments: \n"; - std::cout << "foi* " << sim.get_equilibrium_forceofinfection() << "\n"; - std::cout << "s* " << equi[(int)mio::endisecir::InfectionState::Susceptible] << "\n"; - std::cout << "e* " << equi[(int)mio::endisecir::InfectionState::Exposed] << "\n"; - std::cout << "c* " << equi[(int)mio::endisecir::InfectionState::InfectedNoSymptoms] << "\n"; - std::cout << "i* " << equi[(int)mio::endisecir::InfectionState::InfectedSymptoms] << "\n"; - std::cout << "h* " << equi[(int)mio::endisecir::InfectionState::InfectedSevere] << "\n"; - std::cout << "u* " << equi[(int)mio::endisecir::InfectionState::InfectedCritical] << "\n"; - std::cout << "r* " << equi[(int)mio::endisecir::InfectionState::Recovered] << "\n"; + // std::vector equi = sim.get_equilibriumcompartments(); + // std::cout << "Equilibrium normalized compartments: \n"; + // std::cout << "foi* " << sim.get_equilibrium_forceofinfection() << "\n"; + // std::cout << "s* " << equi[(int)mio::endisecir::InfectionState::Susceptible] << "\n"; + // std::cout << "e* " << equi[(int)mio::endisecir::InfectionState::Exposed] << "\n"; + // std::cout << "c* " << equi[(int)mio::endisecir::InfectionState::InfectedNoSymptoms] << "\n"; + // std::cout << "i* " << equi[(int)mio::endisecir::InfectionState::InfectedSymptoms] << "\n"; + // std::cout << "h* " << equi[(int)mio::endisecir::InfectionState::InfectedSevere] << "\n"; + // std::cout << "u* " << equi[(int)mio::endisecir::InfectionState::InfectedCritical] << "\n"; + // std::cout << "r* " << equi[(int)mio::endisecir::InfectionState::Recovered] << "\n"; } \ No newline at end of file diff --git a/cpp/examples/ide_endemic_secir_save_results.cpp b/cpp/examples/ide_endemic_secir_save_results.cpp index 5c3b6e79ad..42797dd2e1 100644 --- a/cpp/examples/ide_endemic_secir_save_results.cpp +++ b/cpp/examples/ide_endemic_secir_save_results.cpp @@ -19,19 +19,19 @@ std::map simulation_parameter = {{"dt", 0.1}, {"t0", 0.}, {"Susceptibles", 10000.}, {"Exposed", 0}, - {"InfectedNoSymptoms", 10.}, - {"InfectedSymptoms", 20}, + {"InfectedNoSymptoms", 0.}, + {"InfectedSymptoms", 0.}, {"InfectedSevere", 0.}, {"InfectedCritical", 0.}, {"Recovered", 0.}, {"Dead", 0.}, - {"TransmissionProbabilityOnContact", 0.4}, + {"TransmissionProbabilityOnContact", 0.5}, {"RelativeTransmissionNoSymptoms", 0.5}, {"RiskOfInfectionFromSymptomatic", 0.5}, {"InfectedSymptomsPerInfectedNoSymptoms", 0.5}, - {"SeverePerInfectedSymptoms", 0.2}, + {"SeverePerInfectedSymptoms", 0.5}, {"CriticalPerSevere", 0.5}, - {"DeathsPerCritical", 0.2}, + {"DeathsPerCritical", 0.1}, {"BirthRate1", 4e-5}, {"DeathRate1", 3e-5}, {"BirthRate2", 3e-5}, @@ -141,12 +141,12 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = mio::TimeSeries init_copy3(init); mio::endisecir::Model model_endide3(std::move(init_copy3)); - model_endide2.parameters.get() = vec_delaydistribution; + model_endide3.parameters.get() = vec_delaydistribution; // Set other parameters. - model_endide2.parameters.set(vec_prob); + model_endide3.parameters.set(vec_prob); - model_endide2.parameters.get() = mio::UncertainContactMatrix(contact_matrix); + model_endide3.parameters.get() = mio::UncertainContactMatrix(contact_matrix); mio::ConstantFunction constfunc3(simulation_parameter["TransmissionProbabilityOnContact"]); mio::StateAgeFunctionWrapper StateAgeFunctionWrapperide3(constfunc); @@ -213,15 +213,10 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = return mio::success(); } -int main(int argc, char** argv) +int main() { std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDE/simulation_results/"; - // Set result_dir via command line. - if (argc == 2) { - result_dir = argv[1]; - } - // Define tmax for both scenarios. ScalarType tmax = 500; diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index fb8aba3016..2a24f5b45f 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -39,13 +39,7 @@ Model::Model(TimeSeries&& states_init) std::accumulate(populations[0].begin(), populations[0].end(), 0) - populations[0][(int)InfectionState::Dead]; m_totalpopulation.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); m_totalpopulationupdate.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); - // m_totalpopulationincludingD.add_time_point( - // 0, - // TimeSeries::Vector::Constant(1, init_populationsize + populations[0][(int)InfectionState::Dead])); - // m_totalpopulationupdateincludingD.add_time_point( - // 0, - // TimeSeries::Vector::Constant(1, init_populationsize + populations[0][(int)InfectionState::Dead])); - // Set the force of infection at start time t0. + m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); m_forceofinfectionupdate.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); @@ -110,10 +104,12 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx ScalarType state_age_i = static_cast(i) * dt; sum1 += transitions[i + 1][idx_IncomingFlow] * std::exp(-parameters.get() * (current_time_age - state_age_i)) * + parameters.get()[idx_InfectionTransitions] * m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; //For the update formula version of the model: sum2 += transitions_update[i + 1][idx_IncomingFlow] * std::exp(-parameters.get() * (current_time_age - state_age_i)) * + parameters.get()[idx_InfectionTransitions] * m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; } if (current_time_index <= calc_time_index) { From c740a961d0376fa61c90d6d9b84f2f85436005ae Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:16:40 +0200 Subject: [PATCH 09/22] small changes in the examples --- cpp/examples/ide_endemic_secir.cpp | 31 +-- .../ide_endemic_secir_save_results.cpp | 210 ++++++++++++------ cpp/models/ide_endemic_secir/model.cpp | 18 +- 3 files changed, 172 insertions(+), 87 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index b6343e8b35..4eae0757e1 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -17,8 +17,8 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 100; - ScalarType dt = 0.1; + ScalarType tmax = 1000; + ScalarType dt = 1.0; int num_states = static_cast(mio::endisecir::InfectionState::Count); int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); @@ -47,18 +47,23 @@ int main() // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - mio::SmootherCosine smoothcos(2.0); + mio::SmootherCosine smoothcos(8.0); mio::StateAgeFunctionWrapper delaydistribution(smoothcos); std::vector vec_delaydistribution(num_transitions, delaydistribution); model.parameters.get() = vec_delaydistribution; - std::vector vec_prob(num_transitions, 0.5); - // The following probabilities must be 1, as there is no other way to go. - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::SusceptibleToExposed)] = 1; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms)] = 1; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToDead)] = 0.1; - model.parameters.get() = vec_prob; + std::vector vec_prob((int)mio::endisecir::InfectionTransition::Count, 1.); + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] = 0.5; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered)] = 1 - 0.5; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere)] = 0.1; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered)] = 1 - 0.1; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical)] = 0.3; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToRecovered)] = 1 - 0.3; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToDead)] = 0.2; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToRecovered)] = 1 - 0.2; + + model.parameters.set(vec_prob); mio::ContactMatrixGroup contact_matrix = mio::ContactMatrixGroup(1, 1); contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); @@ -75,8 +80,8 @@ int main() model.parameters.get() = exponential_prob; model.parameters.get() = exponential_prob; - model.parameters.set(3e-4); - model.parameters.set(4e-4); + model.parameters.set(4e-3); + model.parameters.set(3e-3); //model.set_tol_for_support_max(1e-6); @@ -86,7 +91,7 @@ int main() auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); - interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); + // interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); // Uncomment to print the compartments computed with the update scheme. // auto interpolated_results_update = mio::interpolate_simulation_result(sim.get_compartments_update(), dt / 2.); @@ -109,7 +114,7 @@ int main() // sim.get_totalpopulations().print_table({"N"}, 16, 9); // Uncomment to print the force of infection. - //sim.get_forceofinfections().print_table({"FoI"}, 16, 8); + sim.get_forceofinfections().print_table({"FoI"}, 16, 8); // sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); // std::vector equi = sim.get_equilibriumcompartments(); diff --git a/cpp/examples/ide_endemic_secir_save_results.cpp b/cpp/examples/ide_endemic_secir_save_results.cpp index 42797dd2e1..9058c2a9ae 100644 --- a/cpp/examples/ide_endemic_secir_save_results.cpp +++ b/cpp/examples/ide_endemic_secir_save_results.cpp @@ -15,29 +15,29 @@ #include #include -std::map simulation_parameter = {{"dt", 0.1}, +std::map simulation_parameter = {{"dt", 1.}, {"t0", 0.}, - {"Susceptibles", 10000.}, + {"Susceptibles", 100000.}, {"Exposed", 0}, - {"InfectedNoSymptoms", 0.}, - {"InfectedSymptoms", 0.}, + {"InfectedNoSymptoms", 10.}, + {"InfectedSymptoms", 20.}, {"InfectedSevere", 0.}, {"InfectedCritical", 0.}, {"Recovered", 0.}, {"Dead", 0.}, - {"TransmissionProbabilityOnContact", 0.5}, + {"TransmissionProbabilityOnContact", 0.1}, {"RelativeTransmissionNoSymptoms", 0.5}, {"RiskOfInfectionFromSymptomatic", 0.5}, {"InfectedSymptomsPerInfectedNoSymptoms", 0.5}, - {"SeverePerInfectedSymptoms", 0.5}, - {"CriticalPerSevere", 0.5}, - {"DeathsPerCritical", 0.1}, - {"BirthRate1", 4e-5}, - {"DeathRate1", 3e-5}, - {"BirthRate2", 3e-5}, - {"DeathRate2", 3e-5}, - {"BirthRate3", 3e-5}, - {"DeathRate3", 4e-5}, + {"SeverePerInfectedSymptoms", 0.1}, + {"CriticalPerSevere", 0.3}, + {"DeathsPerCritical", 0.2}, + {"BirthRate1", 4e-3}, + {"DeathRate1", 3e-3}, + {"BirthRate2", 3e-4}, + {"DeathRate2", 3e-4}, + {"BirthRate3", 3e-4}, + {"DeathRate3", 4e-4}, {"Contacts", 10.}}; mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = "") @@ -45,8 +45,8 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = int num_states = static_cast(mio::endisecir::InfectionState::Count); int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); + //Set the inital values for the compartments. mio::TimeSeries init(num_states); - mio::TimeSeries::Vector vec_init(num_states); vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = simulation_parameter["Susceptibles"]; @@ -63,15 +63,63 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = init.add_time_point(0, vec_init); + // We are going to simulate thre times with three different Birth and Death Rates, + // but all other parameters stay the same. + // Model 1, with BirthRate > DeathRate: mio::TimeSeries init_copy1(init); mio::endisecir::Model model_endide1(std::move(init_copy1)); - mio::SmootherCosine smoothcos(2.0); + // Set distributions. + // Set TransitionDistributions. + + mio::SmootherCosine smoothcos(8.0); mio::StateAgeFunctionWrapper delaydistribution(smoothcos); std::vector vec_delaydistribution(num_transitions, delaydistribution); - model_endide1.parameters.get() = vec_delaydistribution; + // Uncomment for Lognorm. + // mio::ConstantFunction initialfunc(0); + // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); + // std::vector vec_delaydistribution((int)mio::endisecir::InfectionTransition::Count, + // delaydistributioninit); + // // ExposedToInfectedNoSymptoms + // mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.3, 0, 4.2); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms].set_state_age_function( + // survivalExposedToInfectedNoSymptoms); + // // InfectedNoSymptomsToInfectedSymptoms + // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.7, 0, 0.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] + // .set_state_age_function(survivalInfectedNoSymptomsToInfectedSymptoms); + // // InfectedNoSymptomsToRecovered + // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToRecovered(0.2, 0, 7.7); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered] + // .set_state_age_function(survivalInfectedNoSymptomsToRecovered); + // // InfectedSymptomsToInfectedSevere + // mio::LognormSurvivalFunction survivalInfectedSymptomsToInfectedSevere(0.7, 0, 5.3); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere] + // .set_state_age_function(survivalInfectedSymptomsToInfectedSevere); + // // InfectedSymptomsToRecovered + // mio::LognormSurvivalFunction survivalInfectedSymptomsToRecovered(0.2, 0, 7.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered].set_state_age_function( + // survivalInfectedSymptomsToRecovered); + // // InfectedSevereToInfectedCritical + // mio::LognormSurvivalFunction survivalInfectedSevereToInfectedCritical(1.0, 0, 0.9); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical] + // .set_state_age_function(survivalInfectedSevereToInfectedCritical); + // // InfectedSevereToRecovered + // mio::LognormSurvivalFunction survivalInfectedSevereToRecovered(0.3, 0, 17.1); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToRecovered].set_state_age_function( + // survivalInfectedSevereToRecovered); + // // InfectedCriticalToDead + // mio::LognormSurvivalFunction survivalInfectedCriticalToDead(0.4, 0, 9.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToDead].set_state_age_function( + // survivalInfectedCriticalToDead); + // // InfectedCriticalToRecovered + // mio::LognormSurvivalFunction survivalInfectedCriticalToRecovered(0.3, 0, 17.1); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToRecovered].set_state_age_function( + // survivalInfectedCriticalToRecovered); + + model_endide1.parameters.set(vec_delaydistribution); // Set other parameters. std::vector vec_prob((int)mio::endisecir::InfectionTransition::Count, 1.); @@ -98,13 +146,17 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, simulation_parameter["Contacts"])); model_endide1.parameters.get() = mio::UncertainContactMatrix(contact_matrix); - mio::ConstantFunction constfunc(simulation_parameter["TransmissionProbabilityOnContact"]); - mio::StateAgeFunctionWrapper StateAgeFunctionWrapperide(constfunc); - model_endide1.parameters.set(StateAgeFunctionWrapperide); - StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RelativeTransmissionNoSymptoms"]); - model_endide1.parameters.set(StateAgeFunctionWrapperide); - StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); - model_endide1.parameters.set(StateAgeFunctionWrapperide); + mio::ConstantFunction constant(simulation_parameter["TransmissionProbabilityOnContact"]); + mio::StateAgeFunctionWrapper constant_prob(constant); + + model_endide1.parameters.get() = constant_prob; + + mio::ExponentialSurvivalFunction exponential(simulation_parameter["RelativeTransmissionNoSymptoms"]); + mio::StateAgeFunctionWrapper exponential_prob(exponential); + + model_endide1.parameters.set(exponential_prob); + exponential_prob.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); + model_endide1.parameters.set(exponential_prob); model_endide1.parameters.set(simulation_parameter["BirthRate1"]); model_endide1.parameters.set(simulation_parameter["DeathRate1"]); @@ -123,13 +175,12 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = model_endide2.parameters.get() = mio::UncertainContactMatrix(contact_matrix); - mio::ConstantFunction constfunc2(simulation_parameter["TransmissionProbabilityOnContact"]); - mio::StateAgeFunctionWrapper StateAgeFunctionWrapperide2(constfunc); - model_endide2.parameters.set(StateAgeFunctionWrapperide2); - StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RelativeTransmissionNoSymptoms"]); - model_endide2.parameters.set(StateAgeFunctionWrapperide2); - StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); - model_endide2.parameters.set(StateAgeFunctionWrapperide2); + model_endide2.parameters.get() = constant_prob; + + exponential_prob.set_distribution_parameter(simulation_parameter["RelativeTransmissionNoSymptoms"]); + model_endide2.parameters.set(exponential_prob); + exponential_prob.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); + model_endide2.parameters.set(exponential_prob); model_endide2.parameters.set(simulation_parameter["BirthRate2"]); model_endide2.parameters.set(simulation_parameter["DeathRate2"]); @@ -148,13 +199,12 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = model_endide3.parameters.get() = mio::UncertainContactMatrix(contact_matrix); - mio::ConstantFunction constfunc3(simulation_parameter["TransmissionProbabilityOnContact"]); - mio::StateAgeFunctionWrapper StateAgeFunctionWrapperide3(constfunc); - model_endide3.parameters.set(StateAgeFunctionWrapperide3); - StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RelativeTransmissionNoSymptoms"]); - model_endide3.parameters.set(StateAgeFunctionWrapperide3); - StateAgeFunctionWrapperide.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); - model_endide3.parameters.set(StateAgeFunctionWrapperide3); + model_endide3.parameters.get() = constant_prob; + + exponential_prob.set_distribution_parameter(simulation_parameter["RelativeTransmissionNoSymptoms"]); + model_endide3.parameters.set(exponential_prob); + exponential_prob.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); + model_endide3.parameters.set(exponential_prob); model_endide3.parameters.set(simulation_parameter["BirthRate3"]); model_endide3.parameters.set(simulation_parameter["DeathRate3"]); @@ -165,10 +215,11 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = // Simulate. mio::endisecir::Simulation sim1(model_endide1, simulation_parameter["dt"]); sim1.advance(tmax); - mio::endisecir::Simulation sim2(model_endide2, simulation_parameter["dt"]); - sim2.advance(tmax); - mio::endisecir::Simulation sim3(model_endide3, simulation_parameter["dt"]); - sim3.advance(tmax); + // mio::endisecir::Simulation sim2(model_endide2, simulation_parameter["dt"]); + // sim2.advance(tmax); + // mio::endisecir::Simulation sim3(model_endide3, simulation_parameter["dt"]); + // sim3.advance(tmax); + sim1.get_forceofinfections().print_table({"FoI"}, 16, 8); if (!save_dir.empty()) { std::string tmax_string = std::to_string(tmax); @@ -177,39 +228,70 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = std::string filename_ide = save_dir + "analysis_endide_" + tmax_string.substr(0, tmax_string.find(".")) + "_" + dt_string.substr(0, dt_string.find(".") + 5); - //Save total population for different birth and death rates + //Save total population for different birth and death rates. std::string filename_ide_totalpopulation1 = filename_ide + "_totalpopulation1.h5"; mio::IOResult save_result_status_tp1 = mio::save_result({sim1.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation1); - std::string filename_ide_totalpopulation2 = filename_ide + "_totalpopulation2.h5"; - mio::IOResult save_result_status_tp2 = - mio::save_result({sim2.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation2); + // std::string filename_ide_totalpopulation2 = filename_ide + "_totalpopulation2.h5"; + // mio::IOResult save_result_status_tp2 = + // mio::save_result({sim2.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation2); - std::string filename_ide_totalpopulation3 = filename_ide + "_totalpopulation3.h5"; - mio::IOResult save_result_status_tp3 = - mio::save_result({sim3.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation3); + // std::string filename_ide_totalpopulation3 = filename_ide + "_totalpopulation3.h5"; + // mio::IOResult save_result_status_tp3 = + // mio::save_result({sim3.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation3); - //Save compartments for different birth and death rates + //Save compartments for different birth and death rates. std::string filename_ide_compartments1 = filename_ide + "_compartments1.h5"; mio::IOResult save_result_status_c1 = mio::save_result({sim1.get_compartments()}, {0}, 1, filename_ide_compartments1); - std::string filename_ide_compartments2 = filename_ide + "_compartments2.h5"; - mio::IOResult save_result_status_c2 = - mio::save_result({sim2.get_compartments()}, {0}, 1, filename_ide_compartments2); - - std::string filename_ide_compartments3 = filename_ide + "_compartments3.h5"; - mio::IOResult save_result_status_c3 = - mio::save_result({sim3.get_compartments()}, {0}, 1, filename_ide_compartments3); - - if (!save_result_status_tp1 || !save_result_status_tp2 || !save_result_status_tp3 || !save_result_status_c1 || - !save_result_status_c2 || !save_result_status_c3) { + // std::string filename_ide_compartments2 = filename_ide + "_compartments2.h5"; + // mio::IOResult save_result_status_c2 = + // mio::save_result({sim2.get_compartments()}, {0}, 1, filename_ide_compartments2); + + // std::string filename_ide_compartments3 = filename_ide + "_compartments3.h5"; + // mio::IOResult save_result_status_c3 = + // mio::save_result({sim3.get_compartments()}, {0}, 1, filename_ide_compartments3); + + //Save normalized compartments for only one birth and death rate. + std::string filename_ide_normcompartments = filename_ide + "_normcompartments.h5"; + mio::IOResult save_result_status_nc = + mio::save_result({sim1.get_normalizedcompartments()}, {0}, 1, filename_ide_normcompartments); + + //Save the equilibrium of the normalized compartments. + // std::string filename_ide_normcompartmentsequi = filename_ide + "_equinormcompartments.h5"; + // mio::IOResult save_result_status_nce = + // mio::save_result({sim1.get_equilibriumcompartments()}, {0}, 1, filename_ide_normcompartmentsequi); + + //Save the force of infection for only one birth and death rate. + std::string filename_ide_forceofinfection = filename_ide + "_forceofinfection.h5"; + mio::IOResult save_result_status_foi = + mio::save_result({sim1.get_forceofinfections()}, {0}, 1, filename_ide_forceofinfection); + + //Save the equilibrium of the force of infection. + // std::string filename_ide_forceofinfectionequi = filename_ide + "_equiforceofinfection.h5"; + // mio::IOResult save_result_status_foie = + // mio::save_result({sim1.get_equilibrium_forceofinfection()}, {0}, 1, filename_ide_forceofinfectionequi); + + // if (!save_result_status_tp1 || !save_result_status_tp2 || !save_result_status_tp3 || !save_result_status_c1 || + // !save_result_status_c2 || !save_result_status_c3 || !save_result_status_nc || !save_result_status_foi || + // !save_result_status_nce || !save_result_status_foie) { + // return mio::failure(mio::StatusCode::UnknownError, "Error while saving results."); + // } + if (!save_result_status_tp1 || !save_result_status_c1 || !save_result_status_nc || !save_result_status_foi) { return mio::failure(mio::StatusCode::UnknownError, "Error while saving results."); } } - - // Return results (i.e. total populations) of the simulation. + // Print the reproduction numbers for different birth and death rates. + std::cout << "The reproduction number Rc for Birth rate > Death rate is " << sim1.get_reproductionnumber_c() + << "\n"; + // std::cout << "The reproduction number Rc for Birth rate = Death rate is " << sim2.get_reproductionnumber_c() + // << "\n"; + // std::cout << "The reproduction number Rc for Birth rate < Death rate is " << sim3.get_reproductionnumber_c() + // << "\n"; + + // Return results of the simulation. return mio::success(); } @@ -217,8 +299,8 @@ int main() { std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDE/simulation_results/"; - // Define tmax for both scenarios. - ScalarType tmax = 500; + // Define tmax. + ScalarType tmax = 100; auto result_ide = simulate_endidemodel(tmax, result_dir); if (!result_ide) { diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index 2a24f5b45f..cd36c70a39 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -334,16 +334,14 @@ void Model::update_compartments(ScalarType dt) void Model::compute_populationsize() { - m_totalpopulation.get_last_value()[0] = - std::accumulate(populations.get_last_value().begin(), populations.get_last_value().end(), 0) - - populations.get_last_value()[(int)InfectionState::Dead]; - m_totalpopulationupdate.get_last_value()[0] = - std::accumulate(populations_update.get_last_value().begin(), populations_update.get_last_value().end(), 0) - - populations_update.get_last_value()[(int)InfectionState::Dead]; - // m_totalpopulationincludingD.get_last_value()[0] = - // std::accumulate(populations.get_last_value().begin(), populations.get_last_value().end(), 0); - // m_totalpopulationupdateincludingD.get_last_value()[0] = - // std::accumulate(populations_update.get_last_value().begin(), populations_update.get_last_value().end(), 0); + ScalarType sum1 = 0; + ScalarType sum2 = 0; + for (int state = 0; state < Eigen::Index(InfectionState::Count) - 1; state++) { + sum1 += populations.get_last_value()[state]; + sum2 += populations_update.get_last_value()[state]; + } + m_totalpopulation.get_last_value()[0] = sum1; + m_totalpopulationupdate.get_last_value()[0] = sum2; } void Model::compute_normalizedcompartments() From 6a1b1f1365fd9c016b86619360ec581b362cb916 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Mon, 11 Aug 2025 10:17:37 +0200 Subject: [PATCH 10/22] Changed the structure of the Implementation. Added computed_parameters.h where we compute all the parameters we can compute in advance of the simulation. Also added normalized_model.h/.cpp where we compute the normalized version of the model, implementation is similar to model.cpp --- cpp/models/ide_endemic_secir/CMakeLists.txt | 3 + .../ide_endemic_secir/computed_parameters.h | 366 +++++++++++++ cpp/models/ide_endemic_secir/model.cpp | 487 +++--------------- cpp/models/ide_endemic_secir/model.h | 150 +----- .../ide_endemic_secir/normalized_model.cpp | 281 ++++++++++ .../ide_endemic_secir/normalized_model.h | 157 ++++++ cpp/models/ide_endemic_secir/simulation.cpp | 20 +- cpp/models/ide_endemic_secir/simulation.h | 23 +- 8 files changed, 898 insertions(+), 589 deletions(-) create mode 100644 cpp/models/ide_endemic_secir/computed_parameters.h create mode 100644 cpp/models/ide_endemic_secir/normalized_model.cpp create mode 100644 cpp/models/ide_endemic_secir/normalized_model.h diff --git a/cpp/models/ide_endemic_secir/CMakeLists.txt b/cpp/models/ide_endemic_secir/CMakeLists.txt index 9417a51f42..b335f4c23c 100644 --- a/cpp/models/ide_endemic_secir/CMakeLists.txt +++ b/cpp/models/ide_endemic_secir/CMakeLists.txt @@ -2,9 +2,12 @@ add_library(ide_endemic_secir infection_state.h model.h model.cpp + normalized_model.h + normalized_model.cpp simulation.h simulation.cpp parameters.h + computed_parameters.h ) target_link_libraries(ide_endemic_secir PUBLIC memilio) target_include_directories(ide_endemic_secir PUBLIC diff --git a/cpp/models/ide_endemic_secir/computed_parameters.h b/cpp/models/ide_endemic_secir/computed_parameters.h new file mode 100644 index 0000000000..fcd2752c9b --- /dev/null +++ b/cpp/models/ide_endemic_secir/computed_parameters.h @@ -0,0 +1,366 @@ +#ifndef IDE_END_SECIR_COMPPARAMS_H +#define IDE_END_SECIR_COMPPARAMS_H + +#include "ide_endemic_secir/infection_state.h" +#include "ide_endemic_secir/parameters.h" +#include "memilio/config.h" +#include "memilio/utils/time_series.h" + +#include "vector" +#include +#include +#include +#include + +namespace mio +{ +namespace endisecir +{ +class CompParameters; +class Model; +class Simulation; + +class CompParameters +{ + using ParameterSet = Parameters; + +public: + CompParameters(TimeSeries&& states_init) + : parameters{Parameters()} + , m_statesinit{std::move(states_init)} + { + m_totalpopulationinit = std::accumulate(m_statesinit[0].begin(), m_statesinit[0].end(), 0) - + m_statesinit[0][(int)InfectionState::Dead]; + } + + bool check_constraints() const + { + if (!(static_cast(m_statesinit.get_num_elements()) == static_cast(InfectionState::Count))) { + log_error( + " A variable given for model construction is not valid. Number of elements in vector of populations " + "does not match the required number."); + return true; + } + for (int i = 0; i < static_cast(InfectionState::Count); i++) { + if (m_statesinit[0][i] < 0) { + log_error("Initialization failed. Initial values for populations are less than zero."); + return true; + } + } + return parameters.check_constraints(); + } + + /** + * @brief Setter for the tolerance used to calculate the maximum support of the TransitionDistributions. + * + * @param[in] new_tol New tolerance. + */ + void set_tol_for_support_max(ScalarType new_tol) + { + m_tol = new_tol; + } + + // ---- Public parameters. ---- + ParameterSet parameters; ///< ParameterSet of Model Parameters. + +private: + // ---- Functionality to set vectors with necessary information regarding TransitionDistributions. ---- + /** + * @brief Setter for the vector m_transitiondistributions_support_max that contains the support_max for all + * TransitionDistributions. + * + * This determines how many summands are required when calculating flows, the force of infection or compartments. + * + * @param[in] dt Time step size. + */ + void set_transitiondistributions_support_max(ScalarType dt) + { + // The transition Susceptible to Exposed is not needed in the computations. + for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { + m_transitiondistributions_support_max[transition] = + parameters.get()[transition].get_support_max(dt, m_tol); + } + } + + /** + * @brief Setter for the vector m_transitiondistributions. + * + * In the computation of the force of infection in the initialization function of the force of infection term, + * we evaluate the survival functions of the TransitionDistributions InfectedNoSymptomsToInfectedSymptoms, + * InfectedNoSymptomsToRecovered, InfectedSymptomsToInfectedSevere and InfectedSymptomsToRecovered, weighted by + * the corresponding TransitionProbabilities, at the same time points. + * Here, we compute these contributions to the force of infection term, an store the vector + * m_transitiondistributions_in_forceofinfection so that we can access this vector for all following computations. + * + * @param[in] dt Time step size. + */ + void set_transitiondistributions(ScalarType dt) + { + //Exposed state: + Eigen::Index support_max_index = (Eigen::Index)std::ceil( + m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms] / dt); + + std::vector vec_contribution_to_foi_1(support_max_index + 1, 0.); + for (Eigen::Index i = 0; i <= support_max_index; i++) { + ///Compute the state_age. + ScalarType state_age = (ScalarType)i * dt; + vec_contribution_to_foi_1[i] = + parameters.get()[(int)InfectionTransition::ExposedToInfectedNoSymptoms].eval( + state_age); + } + m_transitiondistributions[(int)InfectionState::Exposed] = vec_contribution_to_foi_1; + + // Vector containing the transitions for the states with two outgoing flows. + // We will compute the Transition Distribution for InfectedNoSymptoms and InfectedSymptoms until m_caltime, as we need + // that many values to compute the mean_infectivity. + + std::vector> vector_transitions = { + {(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms, + (int)InfectionTransition::InfectedNoSymptomsToRecovered}, + {(int)InfectionTransition::InfectedSymptomsToInfectedSevere, + (int)InfectionTransition::InfectedSymptomsToRecovered}, + {(int)InfectionTransition::InfectedSevereToInfectedCritical, + (int)InfectionTransition::InfectedSevereToRecovered}, + {(int)InfectionTransition::InfectedCriticalToDead, (int)InfectionTransition::InfectedCriticalToRecovered}}; + + for (int state = 2; state < (int)InfectionState::Count - 2; state++) { + Eigen::Index calc_time_index = std::max((Eigen::Index)std::ceil(vector_transitions[state - 2][0]), + (Eigen::Index)std::ceil(vector_transitions[state - 2][1])) / + dt; + + // Create vec_derivative that stores the value of the approximated derivative for all necessary time points. + std::vector vec_contribution_to_foi_2(calc_time_index + 1, 0.); + for (Eigen::Index i = 0; i <= calc_time_index; i++) { + ///Compute the state_age. + ScalarType state_age = (ScalarType)i * dt; + vec_contribution_to_foi_2[i] = + parameters.get()[vector_transitions[state - 2][0]] * + parameters.get()[vector_transitions[state - 2][0]].eval(state_age) + + parameters.get()[vector_transitions[state - 2][1]] * + parameters.get()[vector_transitions[state - 2][1]].eval(state_age); + } + m_transitiondistributions[state] = vec_contribution_to_foi_2; + } + } + + /** + * @brief Setter for the vector m_transitiondistributions_derivative that contains the approximated derivative for + * all TransitionDistributions for all necessary time points. + * + * The derivative is approximated using a backwards difference scheme. + * The number of necessary time points for each TransitionDistribution is determined using + * m_transitiondistributions_support_max. + * + * @param[in] dt Time step size. + */ + void set_transitiondistributions_derivative(ScalarType dt) + { + // The transition SusceptibleToExposed is not needed in the computations. + for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { + Eigen::Index support_max_index = + (Eigen::Index)std::ceil(m_transitiondistributions_support_max[transition] / dt); + + // Create vec_derivative that stores the value of the approximated derivative for all necessary time points. + std::vector vec_derivative(support_max_index + 1, 0.); + + for (Eigen::Index i = 0; i <= support_max_index; i++) { + // Compute state_age. + ScalarType state_age = (ScalarType)i * dt; + //Compute the apprximate derivative by a backwards difference scheme. + vec_derivative[i] = (parameters.get()[transition].eval(state_age) - + parameters.get()[transition].eval(state_age - dt)) / + dt; + } + m_transitiondistributions_derivative[transition] = vec_derivative; + } + } + + /** + *@brief Setter for the vector m_B that contains the approximated value of B for all for all necessary time points. + * + * @param[in] dt Time step size. + */ + void set_B(ScalarType dt) + { + // Determine the calc_time_index that is the maximum of the support max of the TransitionDistributions that are + // used in this computation. + ScalarType calc_time = + std::max(m_transitiondistributions_support_max[(int)InfectionTransition::InfectedSymptomsToInfectedSevere], + m_transitiondistributions_support_max[(int)InfectionTransition::InfectedSymptomsToRecovered]); + Eigen::Index calc_time_index = (Eigen::Index)std::ceil(calc_time / dt) - 1; + + m_B = std::vector(calc_time_index + 1, 0.); + + for (Eigen::Index time_point_index = 1; time_point_index < calc_time_index; time_point_index++) { + + ScalarType sum = 0; + + Eigen::Index starting_point = + std::max(0, (int)time_point_index - 1 - + (int)m_transitiondistributions_support_max[( + int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms]); + + for (int i = starting_point; i <= time_point_index - 1; i++) { + ScalarType state_age_i = static_cast(i) * dt; + + sum += + parameters.get().eval(state_age_i) * + m_transitiondistributions[static_cast(InfectionState::InfectedSymptoms)][i] * + m_transitiondistributions_derivative[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] + [time_point_index - i]; + } + m_B[time_point_index] = dt * sum; + } + } + + /** + *@brief Setter for the vector m_meaninfectivity that contains the approximated value of the mean infectivity for all + * for all necessary time points. + * + * @param[in] dt Time step size. + */ + void set_infectivity(ScalarType dt) + { + // Compute the calc_time_indedx corresponding to a_1: + ScalarType calc_time_1 = std::max( + m_transitiondistributions_support_max[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms], + m_transitiondistributions_support_max[(int)InfectionTransition::InfectedNoSymptomsToRecovered]); + Eigen::Index calc_time_index_1 = (Eigen::Index)std::ceil(calc_time_1 / dt) - 1; + + // Compute the calc_time_indedx corresponding to a_2: + Eigen::Index calc_time_index_2 = m_B.size() - 1; + + // All in all calc_time_index for the infectivity: + Eigen::Index calc_time_index = std::max(calc_time_index_1 + 1, calc_time_index_2 + 1); + + m_infectivity = std::vector(calc_time_index, 0.); + + for (Eigen::Index time_point_index = 1; time_point_index < calc_time_index; time_point_index++) { + ScalarType a_1 = 0; + ScalarType a_2 = 0; + + ScalarType time_point_age = (ScalarType)time_point_index * dt; + //We compute a_1 and a_2 at time_point. + Eigen::Index starting_point_1 = std::max( + 0, + (int)time_point_index - 1 - + (int)m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms]); + Eigen::Index starting_point_2 = + std::max(0, (int)time_point_index - 1 - + (int)m_transitiondistributions_support_max[( + int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms]); + + //compute a_1: + for (int i = starting_point_1; i < std::min(calc_time_index_1, calc_time_index); i++) { + + ScalarType state_age_i = static_cast(i) * dt; + a_1 += parameters.get().eval(state_age_i) * + m_transitiondistributions[static_cast(InfectionState::InfectedNoSymptoms)][i] * + m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] + [time_point_index - i]; + } + //compute a_2: + for (int i = starting_point_2; i < std::min(calc_time_index_2, calc_time_index); i++) { + + a_2 += m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] + [time_point_index - i] * + m_B[i]; + } + m_infectivity[time_point_index] = + dt * std::exp(-parameters.get() * time_point_age) * (a_2 - a_1); + } + } + /** + * @brief Setter for the Reproduction number R_c. + * + */ + void set_reproductionnumber_c(ScalarType dt) + { + // Determine the corresponding time index. + + Eigen::Index calc_time_index = m_infectivity.size() - 1; + ScalarType sum = 0; + for (int i = 0; i <= calc_time_index; i++) { + sum += m_infectivity[i]; + } + m_reproductionnumber_c = parameters.get().eval(0) * + parameters.get().get_cont_freq_mat().get_matrix_at(0)(0, 0) * dt * + sum; + } + + //TODO Erklärung + void set_FoI_0() + { + Eigen::Index calc_time_index = m_infectivity.size() - 1; + m_FoI_0 = std::vector(calc_time_index, 0.); + m_NormFoI_0 = std::vector(calc_time_index, 0.); + + for (Eigen::Index time_point_index = 0; time_point_index <= calc_time_index; time_point_index++) { + m_FoI_0[time_point_index] = + m_infectivity[time_point_index] * (m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] + + m_statesinit[0][(int)InfectionState::InfectedNoSymptoms]); + m_NormFoI_0[time_point_index] = + m_infectivity[time_point_index] * ((m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] + + m_statesinit[0][(int)InfectionState::InfectedNoSymptoms]) / + m_totalpopulationinit); + } + } + + void set_InitFoI(ScalarType dt) + { + Eigen::Index calc_time_index = std::max(m_infectivity.size(), m_B.size()) - 1; + m_InitFoI = std::vector(calc_time_index, 0.); + m_NormInitFoI = std::vector(calc_time_index, 0.); + for (Eigen::Index time_point_index = 0; time_point_index <= calc_time_index; time_point_index++) { + ScalarType time_point_age = (ScalarType)time_point_index * dt; + if (time_point_index <= (int)m_B.size()) { + m_InitFoI[time_point_index] += m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] * + std::exp(-parameters.get() * time_point_age) * + m_B[time_point_index]; + m_NormInitFoI[time_point_index] += + m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] / m_totalpopulationinit * + std::exp(-parameters.get() * time_point_age) * m_B[time_point_index]; + } + if (time_point_index <= (int)m_infectivity.size()) { + m_InitFoI[time_point_index] += + m_statesinit[0][(int)InfectionState::Exposed] * m_infectivity[time_point_index]; + m_NormInitFoI[time_point_index] += m_statesinit[0][(int)InfectionState::Exposed] / + m_totalpopulationinit * m_infectivity[time_point_index]; + } + } + } + + // ---- Private parameters. ---- + TimeSeries m_statesinit; ///< TimeSeries containing the initial values for the compartments. + ScalarType m_totalpopulationinit; + ScalarType m_tol{1e-10}; ///< Tolerance used to calculate the maximum support of the TransitionDistributions. + std::vector m_transitiondistributions_support_max{ + std::vector((int)InfectionTransition::Count, 0.)}; ///< A vector containing the support_max + // for all TransitionDistributions. + std::vector> m_transitiondistributions{std::vector>( + (int)InfectionState::Count, + std::vector(1, 0.))}; ///< A vector containing the weighted TransitionDistributions. + std::vector> m_transitiondistributions_derivative{std::vector>( + (int)InfectionTransition::Count, std::vector(1, 0.))}; ///< A Vector containing + // the approximated derivative for all TransitionDistributions for all necessary time points. + std::vector m_B{std::vector(1, 0.)}; ///< A Vector contaiing the appriximated + // values for B. + std::vector m_infectivity{ + std::vector(1, 0.)}; ///> a vector containing the approximated mean infectivity for all time points. + ScalarType m_reproductionnumber_c; ///< The control Reproduction number + std::vector m_FoI_0{std::vector(1, 0.)}; ///< TODO + std::vector m_NormFoI_0{std::vector(1, 0.)}; ///< TODO + std::vector m_InitFoI{std::vector(1, 0.)}; ///< TODO + std::vector m_NormInitFoI{std::vector(1, 0.)}; ///< TODO + + // ---- Friend classes/functions. ---- + friend class Model; + friend class NormModel; + friend class Simulation; +}; + +} // namespace endisecir + +} // namespace mio + +#endif //IDE_END_SECIR_COMPPARAMS_H \ No newline at end of file diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index cd36c70a39..5904d005cc 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -1,32 +1,36 @@ #include "ide_endemic_secir/model.h" +#include "ide_endemic_secir/computed_parameters.h" #include "ide_endemic_secir/parameters.h" #include "ide_endemic_secir/infection_state.h" #include "memilio/config.h" #include "memilio/utils/logging.h" #include "memilio/utils/time_series.h" -#include "ode_secir/parameters.h" #include "vector" #include #include #include #include -#include -#include +#include #include namespace mio { namespace endisecir { -Model::Model(TimeSeries&& states_init) +Model::Model(CompParameters const& compparams) : parameters{Parameters()} + , compparameters{std::make_shared(compparams)} , transitions{TimeSeries(Eigen::Index(InfectionTransition::Count))} , transitions_update{TimeSeries(Eigen::Index(InfectionTransition::Count))} - , populations{std::move(states_init)} + , populations{TimeSeries(Eigen::Index(InfectionState::Count))} , populations_update{TimeSeries(Eigen::Index(InfectionState::Count))} + { - populations_update.add_time_point(0, populations[0]); + // Set States at start time t_0. + populations.add_time_point(0, compparameters->m_statesinit)[0]; + populations_update.add_time_point(0, compparameters->m_statesinit[0]); + // Set flows at start time t0. // As we assume that all individuals have infectio age 0 at time t0, the flows at t0 are set to 0. transitions.add_time_point( @@ -74,25 +78,23 @@ void Model::compute_susceptibles(ScalarType dt) { Eigen::Index num_time_points = populations.get_num_time_points(); populations.get_last_value()[static_cast(InfectionState::Susceptible)] = - (populations[num_time_points - 2][static_cast(InfectionState::Susceptible)] * - (1 - dt * parameters.get()) + - dt * m_totalpopulation[num_time_points - 2][0] * parameters.get()) / - (1 + dt * m_forceofinfection[num_time_points - 2][0]); + (populations[num_time_points - 2][static_cast(InfectionState::Susceptible)] + + dt * (m_totalpopulation[num_time_points - 2][0] * parameters.get())) / + (1 + dt * (m_forceofinfection[num_time_points - 2][0] + parameters.get())); //Computation of susceptibles using the update formula for the other compartments. //Formula for Susceptibles stays the same, but we use m_totalpopulationupdate and m_forceofinfectionupdate populations_update.get_last_value()[static_cast(InfectionState::Susceptible)] = - (populations_update[num_time_points - 2][static_cast(InfectionState::Susceptible)] * - (1 - dt * parameters.get()) + - dt * m_totalpopulationupdate[num_time_points - 2][0] * parameters.get()) / - (1 + dt * m_forceofinfectionupdate[num_time_points - 2][0]); + (populations_update[num_time_points - 2][static_cast(InfectionState::Susceptible)] + + dt * (m_totalpopulationupdate[num_time_points - 2][0] * parameters.get())) / + (1 + dt * (m_forceofinfectionupdate[num_time_points - 2][0] + parameters.get())); } void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, Eigen::Index idx_CurrentCompartment, Eigen::Index current_time_index, ScalarType dt) { Eigen::Index calc_time_index = - (Eigen::Index)std::ceil(m_transitiondistributions_support_max[idx_InfectionTransitions] / dt); + (Eigen::Index)std::ceil(compparameters->m_transitiondistributions_support_max[idx_InfectionTransitions] / dt); ScalarType current_time_age = static_cast(current_time_index) * dt; ScalarType sum1 = 0; @@ -105,12 +107,12 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx sum1 += transitions[i + 1][idx_IncomingFlow] * std::exp(-parameters.get() * (current_time_age - state_age_i)) * parameters.get()[idx_InfectionTransitions] * - m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; + compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; //For the update formula version of the model: sum2 += transitions_update[i + 1][idx_IncomingFlow] * std::exp(-parameters.get() * (current_time_age - state_age_i)) * parameters.get()[idx_InfectionTransitions] * - m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; + compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; } if (current_time_index <= calc_time_index) { transitions.get_value(current_time_index)[idx_InfectionTransitions] = @@ -118,7 +120,7 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx std::exp((-parameters.get()) * (current_time_age)) * populations[0][idx_CurrentCompartment] * parameters.get()[idx_InfectionTransitions] * - m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; + compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; //For the update formula version of the model: transitions_update.get_value(current_time_index)[idx_InfectionTransitions] = @@ -126,7 +128,7 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx std::exp((-parameters.get()) * (current_time_age)) * populations_update[0][idx_CurrentCompartment] * parameters.get()[idx_InfectionTransitions] * - m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; + compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; } else { transitions.get_value(current_time_index)[idx_InfectionTransitions] = @@ -205,7 +207,7 @@ void Model::update_compartment_with_sum(InfectionState infectionState, ScalarType current_time_age = (ScalarType)current_time_index * dt; Eigen::Index calc_time_index = current_time_index; if (Transitionispossible) { - calc_time_index = m_transitiondistributions[(int)infectionState].size() - 1; + calc_time_index = compparameters->m_transitiondistributions[(int)infectionState].size() - 1; } ScalarType sum = 0; @@ -218,8 +220,8 @@ void Model::update_compartment_with_sum(InfectionState infectionState, sum_inflows += transitions[i + 1][(int)inflow]; } if (NaturalDeathispossible && Transitionispossible) { - sum += m_transitiondistributions[(int)infectionState][current_time_index - i] * sum_inflows * - std::exp(-parameters.get() * (current_time_age - state_age_i)); + sum += compparameters->m_transitiondistributions[(int)infectionState][current_time_index - i] * + sum_inflows * std::exp(-parameters.get() * (current_time_age - state_age_i)); } else if (NaturalDeathispossible && !Transitionispossible) { sum += sum_inflows * std::exp(-parameters.get() * (current_time_age - state_age_i)); @@ -231,7 +233,7 @@ void Model::update_compartment_with_sum(InfectionState infectionState, if (NaturalDeathispossible && Transitionispossible) { if (current_time_index <= calc_time_index) { populations.get_last_value()[(int)infectionState] = - dt * sum + m_transitiondistributions[(int)infectionState][current_time_index] * + dt * sum + compparameters->m_transitiondistributions[(int)infectionState][current_time_index] * populations[0][(int)infectionState] * std::exp(-parameters.get() * (current_time_age)); } @@ -246,8 +248,8 @@ void Model::update_compartment_with_sum(InfectionState infectionState, } else { populations.get_last_value()[(int)infectionState] = - dt * sum + - m_transitiondistributions[(int)infectionState][current_time_index] * populations[0][(int)infectionState]; + dt * sum + compparameters->m_transitiondistributions[(int)infectionState][current_time_index] * + populations[0][(int)infectionState]; } } void Model::update_compartment_from_flow(InfectionState infectionState, @@ -358,419 +360,52 @@ void Model::compute_forceofinfection(ScalarType dt) Eigen::Index num_time_points = populations.get_num_time_points(); ScalarType current_time = populations.get_last_time(); - Eigen::Index calc_time_index = (Eigen::Index)std::ceil(m_calctime / dt) - 1; - - ScalarType foi_0 = 0.; - ScalarType f = 0.; - - //Otherwise the initial values do not have an influence anymore. - if (num_time_points - 1 <= calc_time_index) { - - //Computation of phi_0: - foi_0 = - m_meaninfectivity[num_time_points - 1] * - (populations[0][static_cast(InfectionState::InfectedNoSymptoms)] * - m_transitiondistributions[static_cast(InfectionState::InfectedNoSymptoms)][num_time_points - 1] + - populations[0][static_cast(InfectionState::InfectedSymptoms)] * - m_transitiondistributions[static_cast(InfectionState::InfectedSymptoms)][num_time_points - 1]); - - //Computation of f: - ScalarType f_1 = 0.; - ScalarType f_2 = 0.; - ScalarType f_3 = 0.; - - for (int i = 1; i < num_time_points; i++) { - ScalarType state_age_i = static_cast(i - 1) * dt; - //Compute sum for f_1: - f_1 += - m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] - [num_time_points - 1 - i] * - parameters.get().eval(state_age_i) * - m_transitiondistributions[static_cast(InfectionState::InfectedNoSymptoms)][i - 1]; - - //Compute sum for f_2: - f_2 += m_transitiondistributions_derivative[static_cast( - InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][num_time_points - 1 - i] * - parameters.get().eval(state_age_i) * - m_transitiondistributions[static_cast(InfectionState::InfectedSymptoms)][i - 1]; - - //Compute sum for f_3: - ScalarType sum_f = 0.; - for (int j = 1; j <= i; j++) { - ScalarType state_age_j = static_cast(j - 1) * dt; - sum_f += parameters.get()[static_cast( - InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] * - m_transitiondistributions_derivative[static_cast( - InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][num_time_points - 1 - j] * - parameters.get().eval(state_age_j) * - m_transitiondistributions[static_cast(InfectionState::InfectedSymptoms)][j - 1]; - } - f_3 += - m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] - [num_time_points - 1 - i] * - sum_f; - } - f = (dt * dt * populations[0][static_cast(InfectionState::Exposed)] * - std::exp(-parameters.get() * current_time) * f_3 - - dt * populations[0][static_cast(InfectionState::InfectedNoSymptoms)] * - std::exp(-parameters.get() * current_time) * f_2 - - dt * populations[0][static_cast(InfectionState::Exposed)] * - std::exp(-parameters.get() * current_time) * f_1); - } - - // Computation of the rest - // Determine the starting point of the for loop. - Eigen::Index starting_point = std::max(0, (int)num_time_points - 1 - (int)calc_time_index); + Eigen::Index starting_point = std::max(0, (int)num_time_points - 1 - (int)compparameters->m_FoI_0.size()); - ScalarType sum = 0.; + ScalarType sum = 0.; + ScalarType sum_update = 0.; + // Compute the sum in the force of infection term. for (Eigen::Index i = starting_point; i < num_time_points - 1; i++) { - sum += m_meaninfectivity[num_time_points - 1 - i] * populations[i + 1][(int)InfectionState::Susceptible] * - m_forceofinfection[i][0]; + sum += compparameters->m_infectivity[num_time_points - 1 - i] * + populations[i + 1][(int)InfectionState::Susceptible] * m_forceofinfection[i][0]; + sum_update += compparameters->m_infectivity[num_time_points - 1 - i] * + populations_update[i + 1][(int)InfectionState::Susceptible] * m_forceofinfectionupdate[i][0]; } m_forceofinfection.get_last_value()[0] = - foi_0 / m_totalpopulation[num_time_points - 1][0] + f / m_totalpopulation[num_time_points - 1][0] + (dt * sum) * - (parameters.get().eval(current_time) * - parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)) / - m_totalpopulation[num_time_points - 1][0]; - - //For the update formula version of the model: - sum = 0.; - for (Eigen::Index i = starting_point; i < num_time_points - 1; i++) { - sum += m_meaninfectivity[num_time_points - 1 - i] * - populations_update[i + 1][(int)InfectionState::Susceptible] * m_forceofinfectionupdate[i][0]; - } + (parameters.get().eval(current_time) * + parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)) / + m_totalpopulation[num_time_points - 1][0]; m_forceofinfectionupdate.get_last_value()[0] = - foi_0 / m_totalpopulationupdate[num_time_points - 1][0] + f / m_totalpopulationupdate[num_time_points - 1][0] + - (dt * sum) * - (parameters.get().eval(current_time) * - parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)) / - m_totalpopulationupdate[num_time_points - 1][0]; -} - -// ---- Functionality to set vectors with necessary information regarding TransitionDistributions. ---- -void Model::set_transitiondistributions_support_max(ScalarType dt) -{ - // The transition Susceptible to Exposed is not needed in the computations. - for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { - m_transitiondistributions_support_max[transition] = - parameters.get()[transition].get_support_max(dt, m_tol); - } -} - -void Model::set_calctime() -{ - // Transitions needed in the force of infection term. - std::vector> relevant_transitions = { - {(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms, - (int)InfectionTransition::InfectedNoSymptomsToRecovered}, - {(int)InfectionTransition::InfectedSymptomsToInfectedSevere, - (int)InfectionTransition::InfectedSymptomsToRecovered}}; - - m_calctime = std::max({m_transitiondistributions_support_max[relevant_transitions[0][0]], - m_transitiondistributions_support_max[relevant_transitions[0][1]], - m_transitiondistributions_support_max[relevant_transitions[1][0]], - m_transitiondistributions_support_max[relevant_transitions[1][1]]}); -} - -void Model::set_transitiondistributions(ScalarType dt) -{ - //Exposed state: - Eigen::Index support_max_index = (Eigen::Index)std::ceil( - m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms] / dt); - - std::vector vec_contribution_to_foi_1(support_max_index + 1, 0.); - for (Eigen::Index i = 0; i <= support_max_index; i++) { - ///Compute the state_age. - ScalarType state_age = (ScalarType)i * dt; - vec_contribution_to_foi_1[i] = - parameters.get()[(int)InfectionTransition::ExposedToInfectedNoSymptoms].eval( - state_age); - } - m_transitiondistributions[(int)InfectionState::Exposed] = vec_contribution_to_foi_1; - - // Other states: - // Vector containing the transitions for the states with two outgoing flows. - std::vector> vector_transitions = { - {(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms, - (int)InfectionTransition::InfectedNoSymptomsToRecovered}, - {(int)InfectionTransition::InfectedSymptomsToInfectedSevere, - (int)InfectionTransition::InfectedSymptomsToRecovered}, - {(int)InfectionTransition::InfectedSevereToInfectedCritical, - (int)InfectionTransition::InfectedSevereToRecovered}, - {(int)InfectionTransition::InfectedCriticalToDead, (int)InfectionTransition::InfectedCriticalToRecovered}}; - - for (int state = 2; state < (int)InfectionState::Count - 2; state++) { - Eigen::Index calc_time_index = - (Eigen::Index)std::ceil(std::max(m_transitiondistributions_support_max[vector_transitions[state - 2][0]], - m_transitiondistributions_support_max[vector_transitions[state - 2][1]]) / - dt); - - // Create vec_derivative that stores the value of the approximated derivative for all necessary time points. - std::vector vec_contribution_to_foi_2(calc_time_index + 1, 0.); - for (Eigen::Index i = 0; i <= calc_time_index; i++) { - ///Compute the state_age. - ScalarType state_age = (ScalarType)i * dt; - vec_contribution_to_foi_2[i] = - parameters.get()[vector_transitions[state - 2][0]] * - parameters.get()[vector_transitions[state - 2][0]].eval(state_age) + - parameters.get()[vector_transitions[state - 2][1]] * - parameters.get()[vector_transitions[state - 2][1]].eval(state_age); - } - m_transitiondistributions[state] = vec_contribution_to_foi_2; - } -} - -void Model::set_transitiondistributions_derivative(ScalarType dt) -{ - // The transition SusceptibleToExposed is not needed in the computations. - for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { - Eigen::Index support_max_index = - (Eigen::Index)std::ceil(m_transitiondistributions_support_max[transition] / dt); - - // Create vec_derivative that stores the value of the approximated derivative for all necessary time points. - std::vector vec_derivative(support_max_index + 1, 0.); - - for (Eigen::Index i = 0; i <= support_max_index; i++) { - // Compute state_age. - ScalarType state_age = (ScalarType)i * dt; - //Compute the apprximate derivative by a backwards difference scheme. - vec_derivative[i] = (parameters.get()[transition].eval(state_age) - - parameters.get()[transition].eval(state_age - dt)) / - dt; - } - m_transitiondistributions_derivative[transition] = vec_derivative; + (dt * sum_update) * + (parameters.get().eval(current_time) * + parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)) / + m_totalpopulationupdate[num_time_points - 1][0]; + + // Add inital functions for the force of infection in case they still have an influence. + if ((int)compparameters->m_FoI_0.size() <= num_time_points) { + m_forceofinfection.get_last_value()[0] += + compparameters->m_FoI_0[num_time_points - 1] / m_totalpopulation[num_time_points - 1][0]; + m_forceofinfectionupdate.get_last_value()[0] += + compparameters->m_FoI_0[num_time_points - 1] / m_totalpopulationupdate[num_time_points - 1][0]; } -} - -void Model::set_meaninfectivity(ScalarType dt) -{ - - // Determine the corresponding time index. - Eigen::Index calc_time = std::min( - m_calctime, m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms]); - Eigen::Index calc_time_index = (Eigen::Index)std::ceil(calc_time / dt) - 1; - - m_meaninfectivity = std::vector(calc_time_index + 1, 0.); - - // The mean infectivity is computed as exp(-NaturalDeathRate t) * (a_2(t)-a_1(t)). - for (int time_point_index = 1; time_point_index <= calc_time_index; time_point_index++) { - ScalarType a_1 = 0; - ScalarType a_2 = 0; - - ScalarType time_point_age = (ScalarType)time_point_index * dt; - //We compute a_1 and a_2 at time_point. - for (int i = 0; i <= time_point_index - 1; i++) { - ScalarType state_age_i = static_cast(i) * dt; - //Computation of a_1. - a_1 += parameters.get().eval(state_age_i) * - m_transitiondistributions[static_cast(InfectionState::InfectedNoSymptoms)][i] * - m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] - [time_point_index - i]; - //Computation of a_2. - ScalarType sum = 0; - for (int j = 0; j <= i - 1; j++) { - ScalarType state_age_j = static_cast(j) * dt; - sum += - parameters.get().eval(state_age_j) * - m_transitiondistributions[static_cast(InfectionState::InfectedSymptoms)][j] * - parameters.get()[( - int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] * - m_transitiondistributions_derivative[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] - [time_point_index - j]; - } - a_2 += m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] - [time_point_index - i] * - sum; - } - m_meaninfectivity[time_point_index] = - std::exp(-parameters.get() * time_point_age) * (dt * dt * a_2 - dt * a_1); - } -} -// void Model::set_initalvaluesforceofinfection(ScalarType dt) -// { -// // Determine the relevant calculation area. -// ScalarType calc_time = -// std::max({m_transitiondistributions_support_max[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms], -// m_transitiondistributions_support_max[(int)InfectionTransition::InfectedNoSymptomsToRecovered], -// m_transitiondistributions_support_max[(int)InfectionTransition::InfectedSymptomsToInfectedSevere], -// m_transitiondistributions_support_max[(int)InfectionTransition::InfectedSymptomsToRecovered]}); - -// Eigen::Index calc_time_index = (Eigen::Index)std::ceil(calc_time / dt) - 1; -// m_initalvaluesforceofinfection = std::vector(calc_time_index, 0.); - -// for (int time_point_index = 1; time_point_index < calc_time_index; time_point_index++) { -// ScalarType time_point_age = time_point_index / dt; -// // Evtl wieder hier einfügen wenn ich weiß wie ! -// //We start by adding the phi_0 term. -// // m_initalvaluesforceofinfection[time_point_index] = -// // m_meaninfectivity[time_point_index] * -// // (populations[static_cast(InfectionState::InfectedNoSymptoms)][0] * -// // m_transitiondistributions_in_forceofinfection[0][time_point_index] + -// // populations[static_cast(InfectionState::InfectedSymptoms)][0] * -// // m_transitiondistributions_in_forceofinfection[1][time_point_index]); - -// // Now we compute the f term, that is f=f_3-f_2-f_1. -// ScalarType f_1 = 0.; -// ScalarType f_2 = 0.; -// ScalarType f_3 = 0.; -// for (int i = 1; i <= time_point_index; i++) { -// ScalarType state_age_i = static_cast(i - 1) * dt; -// //Compute sum for f_1: -// f_1 += -// m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] -// [time_point_index + 1 - i] * -// parameters.get().eval(state_age_i) * -// m_transitiondistributions_in_forceofinfection[0][i - 1]; - -// //Compute sum for f_2: -// f_2 += m_transitiondistributions_derivative[static_cast( -// InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][time_point_index + 1 - i] * -// parameters.get().eval(state_age_i) * -// m_transitiondistributions_in_forceofinfection[1][i - 1]; - -// //Compute sum for f_3: -// ScalarType sum = 0.; -// for (int j = 1; j <= i; j++) { -// ScalarType state_age_j = static_cast(j - 1) * dt; -// sum += parameters.get()[static_cast( -// InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] * -// m_transitiondistributions_derivative[static_cast( -// InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)][time_point_index + 1 - j] * -// parameters.get().eval(state_age_j) * -// m_transitiondistributions_in_forceofinfection[1][j - 1]; -// } -// f_3 += -// m_transitiondistributions_derivative[static_cast(InfectionTransition::ExposedToInfectedNoSymptoms)] -// [time_point_index + 1 - i] * -// sum; -// } -// m_initalvaluesforceofinfection[time_point_index] += -// std::pow(dt, 2) * populations[static_cast(InfectionState::Exposed)][0] * -// std::exp(-parameters.get() * time_point_age) * f_3 - -// dt * populations[static_cast(InfectionState::InfectedNoSymptoms)][0] * -// std::exp(-parameters.get() * time_point_age) * f_2 - -// dt * populations[static_cast(InfectionState::Exposed)][0] * -// std::exp(-parameters.get() * time_point_age) * f_1; -// } -// } - -// ---- Functionality for the model analysis. ---- - -void Model::set_reproductionnumber_c(ScalarType dt) -{ - // Determine the corresponding time index. - Eigen::Index calc_time = std::min( - m_calctime, m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms]); - Eigen::Index calc_time_index = (Eigen::Index)std::ceil(calc_time / dt) - 1; - ScalarType sum = 0; - for (int i = 0; i <= calc_time_index; i++) { - sum += m_meaninfectivity[i]; - } - m_reproductionnumber_c = parameters.get().eval(0) * - parameters.get().get_cont_freq_mat().get_matrix_at(0)(0, 0) * dt * sum; -} - -void Model::set_probability_of_transition(ScalarType dt) -{ - - for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { - Eigen::Index support_max_index = - (Eigen::Index)std::ceil(m_transitiondistributions_support_max[transition] / dt); - ScalarType sum = 0.; - for (int i = 0; i <= support_max_index; i++) { - ScalarType state_age_i = static_cast(i) * dt; - sum -= std::exp(-parameters.get() * state_age_i) * - parameters.get()[transition] * - m_transitiondistributions_derivative[transition][i]; - } - m_probabilityoftransition[transition] = dt * sum; - } -} - -//TODO schönere implementierung überlegen, die evtl m_transitiondistributions_in_forceofinfection verwendet!!!! -void Model::set_meansojourntime(ScalarType dt) -{ - std::vector relevant_states = {(int)InfectionState::Exposed, (int)InfectionState::InfectedNoSymptoms, - (int)InfectionState::InfectedSymptoms, (int)InfectionState::InfectedSevere, - (int)InfectionState::InfectedCritical}; - - ScalarType sum = 0; - for (int contribution = 0; contribution < 5; contribution++) { - int calc_time_index = m_transitiondistributions[relevant_states[contribution]].size(); - for (int i = 0; i < calc_time_index; i++) { - ScalarType state_age_i = (ScalarType)i * dt; - sum += m_transitiondistributions[relevant_states[contribution]][i] * - std::exp(-parameters.get() * state_age_i); - } - - m_meansojourntime[relevant_states[contribution]] = dt * sum; - } -} - -void Model::set_equilibrium() -{ - // Case of the disease free equilibrium. - if (m_reproductionnumber_c < 1) { - m_equilibriumforceofinfection = 0; - m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] = 1; - m_equilibriumnormalizedcompartments[(int)InfectionState::Exposed] = 0; - m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedNoSymptoms] = 0; - m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedSymptoms] = 0; - m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedSevere] = 0; - m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedCritical] = 0; - m_equilibriumnormalizedcompartments[(int)InfectionState::Recovered] = 0; - } - // Case of the endemic equilibrium. - - if (m_reproductionnumber_c > 1) { - - //Set probabilities that we transition to a specific compartment during the disease. - ScalarType transition_to_INS = m_probabilityoftransition[(int)InfectionTransition::ExposedToInfectedNoSymptoms]; - ScalarType transition_to_ISy = - transition_to_INS * - m_probabilityoftransition[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms]; - ScalarType transition_to_ISe = - transition_to_ISy * m_probabilityoftransition[(int)InfectionTransition::InfectedSymptomsToInfectedSevere]; - ScalarType transition_to_IC = - transition_to_ISe * m_probabilityoftransition[(int)InfectionTransition::InfectedSevereToInfectedCritical]; - ScalarType transition_to_D = - transition_to_IC * m_probabilityoftransition[(int)InfectionTransition::InfectedCriticalToDead]; - ScalarType transition_to_R = - m_probabilityoftransition[(int)InfectionTransition::InfectedNoSymptomsToRecovered] * transition_to_INS + - m_probabilityoftransition[(int)InfectionTransition::InfectedSymptomsToRecovered] * transition_to_ISy + - m_probabilityoftransition[(int)InfectionTransition::InfectedSevereToRecovered] * transition_to_ISe + - m_probabilityoftransition[(int)InfectionTransition::InfectedCriticalToRecovered] * transition_to_IC; - - m_equilibriumforceofinfection = - parameters.get() * (m_reproductionnumber_c - 1) + - (parameters.get() * transition_to_D * (m_reproductionnumber_c - 1)) / - (1 - transition_to_D); - m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] = 1 / m_reproductionnumber_c; - m_equilibriumnormalizedcompartments[(int)InfectionState::Exposed] = - m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * - m_meansojourntime[(int)InfectionState::Exposed]; - m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedNoSymptoms] = - m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * - transition_to_INS * m_meansojourntime[(int)InfectionState::InfectedNoSymptoms]; - m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedSymptoms] = - m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * - transition_to_ISy * m_meansojourntime[(int)InfectionState::InfectedSymptoms]; - m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedSevere] = - m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * - transition_to_ISe * m_meansojourntime[(int)InfectionState::InfectedSevere]; - m_equilibriumnormalizedcompartments[(int)InfectionState::InfectedCritical] = - m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * - transition_to_IC * m_meansojourntime[(int)InfectionState::InfectedCritical]; - m_equilibriumnormalizedcompartments[(int)InfectionState::Recovered] = - m_equilibriumforceofinfection * m_equilibriumnormalizedcompartments[(int)InfectionState::Susceptible] * - transition_to_R / parameters.get(); + if ((int)compparameters->m_InitFoI.size() <= num_time_points) { + m_forceofinfection.get_last_value()[0] += + compparameters->m_InitFoI[num_time_points - 1] * + parameters.get().eval(current_time) * + parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0) / + m_totalpopulation[num_time_points - 1][0]; + m_forceofinfectionupdate.get_last_value()[0] += + compparameters->m_InitFoI[num_time_points - 1] * + parameters.get().eval(current_time) * + parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0) / + m_totalpopulationupdate[num_time_points - 1][0]; } } -}; // namespace endisecir +} // namespace endisecir } // namespace mio diff --git a/cpp/models/ide_endemic_secir/model.h b/cpp/models/ide_endemic_secir/model.h index 478a49f7da..fc4d2ab73d 100644 --- a/cpp/models/ide_endemic_secir/model.h +++ b/cpp/models/ide_endemic_secir/model.h @@ -3,12 +3,14 @@ #include "ide_endemic_secir/infection_state.h" #include "ide_endemic_secir/parameters.h" +#include "ide_endemic_secir/computed_parameters.h" #include "memilio/config.h" #include "memilio/utils/custom_index_array.h" #include "memilio/utils/time_series.h" #include "vector" #include +#include #include namespace mio @@ -27,10 +29,10 @@ class Model /** * @brief Constructor to create an endemic IDE_SECIR model. * - * @param[in] states_init A vector, containing the number of individuals in each compartment at time 0. + * @param[in] TODO!!!!!! */ - Model(TimeSeries&& states_init); + Model(CompParameters const& compparams); /** * @brief Checks constraints on model parameters and initial data. @@ -43,13 +45,10 @@ class Model * * @param[in] new_tol New tolerance. */ - void set_tol_for_support_max(ScalarType new_tol) - { - m_tol = new_tol; - } // ---- Public parameters. ---- ParameterSet parameters; ///< ParameterSet of Model Parameters. + std::shared_ptr compparameters; TimeSeries transitions; ///< TimesSeries containing points of time and the corresponding number of individuals transitioning // from one #InfectionState to another as defined in #Infection%s. @@ -70,7 +69,7 @@ class Model * * Number is computed by using the previous number of Susceptibles, total population of the last time point and * the force of infection (also from the last time point). - * Number is stored at the matching index in populations. + * Number is stored at the matching index in populations and populations_update. * * @param[in] dt Time discretization step size. */ @@ -118,13 +117,26 @@ class Model */ void flows_currents_timestep(ScalarType dt); + /** + * @brief Updates the values of one compartment, specified in infectionState, using all past transitions. + * + * New value is stored in populations. The values are calculated using all past values for the incoming flows + * including the current time step. + * Therefore the flows of the current time step should be calculated before using this function. + * @param[in] infectionState Specifies the #InfectionState we want to update. + * @param[in] IncomingFlows + * @param[in] NaturalDeathispossible Boolian that determines if there is the possibility of Natural Death in infectionState. + * @param[in] Transitionispossible Boolian that determines if it is possible to transition from the current InfectionState + * into another + * @param[in] dt + */ void update_compartment_with_sum(InfectionState infectionState, std::vector const& IncomingFlows, bool NaturalDeathispossible, bool Transitionispossible, ScalarType dt); /** * @brief Updates the values of one compartment, specified in infectionState, using the transitions. * - * New value is stored in populations. The values are calculated using the compartment size in the previous + * New value is stored in populations_update. The values are calculated using the compartment size in the previous * time step and the related flows of the current time step. * Therefore the flows of the current time step should be calculated before using this function. * @param[in] infectionState Specifies the #InfectionState we want to update. @@ -168,90 +180,6 @@ class Model */ void compute_forceofinfection(ScalarType dt); - // ---- Functionality to set vectors with necessary information regarding TransitionDistributions. ---- - /** - * @brief Setter for the vector m_transitiondistributions_support_max that contains the support_max for all - * TransitionDistributions. - * - * This determines how many summands are required when calculating flows, the force of infection or compartments. - * - * @param[in] dt Time step size. - */ - void set_transitiondistributions_support_max(ScalarType dt); - - /** - * @brief Setter for the vector m_transitiondistributions. - * - * In the computation of the force of infection in the initialization function of the force of infection term, - * we evaluate the survival functions of the TransitionDistributions InfectedNoSymptomsToInfectedSymptoms, - * InfectedNoSymptomsToRecovered, InfectedSymptomsToInfectedSevere and InfectedSymptomsToRecovered, weighted by - * the corresponding TransitionProbabilities, at the same time points. - * Here, we compute these contributions to the force of infection term, an store the vector - * m_transitiondistributions_in_forceofinfection so that we can access this vector for all following computations. - * - * @param[in] dt Time step size. - */ - void set_transitiondistributions(ScalarType dt); - - /** - * @brief Setter for m_calctime - * - * The calculation is the maximum of the support max of the InfectionTransitionDistributions needed to compute the - * mean infectivity. - */ - void set_calctime(); - - /** - * @brief Setter for the vector m_transitiondistributions_derivative that contains the approximated derivative for - * all TransitionDistributions for all necessary time points. - * - * The derivative is approximated using a backwards difference scheme. - * The number of necessary time points for each TransitionDistribution is determined using - * m_transitiondistributions_support_max. - * - * @param[in] dt Time step size. - */ - void set_transitiondistributions_derivative(ScalarType dt); - - /** - *@brief Setter for the vector m_meaninfectivity that contains the approximated value of the mean infectivity for all - * for all necessary time points. - * - * @param[in] dt Time step size. - */ - void set_meaninfectivity(ScalarType dt); - - // // /** - // // *@brief Setter for the vector m_initalvaluesforceofinfection that contains the approximated value of the part of the - // // * force of infection term that is influenced by the initial values. - // // * - // // * @param[in] dt Time step size. - // // */ - // void set_initalvaluesforceofinfection(ScalarType dt); - - // ---- Functionality for the model analysis. ---- - - /** - * @brief Setter for the Reproduction number R_c. - * - */ - void set_reproductionnumber_c(ScalarType dt); - - //TODO Beschreibung - void set_probability_of_transition(ScalarType dt); - - //TODO Beschreibung - void set_meansojourntime(ScalarType dt); - - /** - * @brief Setter for the equilibrium of the normalized model - * - * If the m_reproductionnumber_c < 1 we use the disease free equilibrium and if m_reproductionnumber_c > 1 we compute - * the endemic equilibrium. - * - */ - void set_equilibrium(); - // ---- Private parameters. ---- TimeSeries m_forceofinfection{ @@ -265,48 +193,12 @@ class Model TimeSeries m_totalpopulationupdate{TimeSeries( 1)}; ///< TimeSeries containing the total population size of the considered region for each time point. //In this case we use the compartments from populations_update. - // TimeSeries m_totalpopulationincludingD{TimeSeries( - // 1)}; ///< TimeSeries containing the total population size + the all persons who died of the disease - // // of the considered region for each time point. - // TimeSeries m_totalpopulationupdateincludingD{TimeSeries( - // 1)}; ///< TimeSeries containing the total population size + the all persons who died of the disease - // // of the considered region for each time point. In this case we use the compartments from populations_update. + TimeSeries m_normalizedpopulations{ TimeSeries(Eigen::Index(InfectionState::Count) - 1)}; ///< TimeSeries containing points of time and the corresponding portion // of people in defined #IndectionState%s. - ScalarType m_tol{1e-10}; ///< Tolerance used to calculate the maximum support of the TransitionDistributions. - ScalarType m_calctime{ - 0}; ///< A ScalarType wit he calc time determined by the support max of the transition distributions. - std::vector m_transitiondistributions_support_max{ - std::vector((int)InfectionTransition::Count, 0.)}; ///< A vector containing the support_max - // for all TransitionDistributions. - std::vector> m_transitiondistributions{std::vector>( - (int)InfectionState::Count, - std::vector(1, 0.))}; ///> A vector containing the weighted TransitionDistributions. - std::vector> m_transitiondistributions_derivative{std::vector>( - (int)InfectionTransition::Count, std::vector(1, 0.))}; ///> A Vector containing - // the approximated derivative for all TransitionDistributions for all necessary time points. - std::vector m_meaninfectivity{ - std::vector(1, 0.)}; ///> a vector containing the approximated mean infectivity for all time points. - - ScalarType m_reproductionnumber_c; ///< The control Reproduction number - - std::vector m_equilibriumnormalizedcompartments{ - std::vector(int(InfectionState::Count), 0.)}; ///< Vector containing - // the equilibrium for the normalized compartments. - - ScalarType m_equilibriumforceofinfection{0.}; ///< The equilibrium of the force of infection. - - std::vector m_probabilityoftransition{ - std::vector((int)InfectionTransition::Count, 0.)}; /// m_meansojourntime{std::vector((int)InfectionState::Count - 2, 0.)}; /// m_initalvaluesforceofinfection; ///> a vector containing the parts of the force of infection - // // that are influenced by the inital values of our model, i.e phi_0 and f. - // ---- Friend classes/functions. ---- // In the Simulation class, the actual simulation is performed which is why it needs access to the here // defined (and private) functions to solve the model equations. diff --git a/cpp/models/ide_endemic_secir/normalized_model.cpp b/cpp/models/ide_endemic_secir/normalized_model.cpp new file mode 100644 index 0000000000..2b9413a827 --- /dev/null +++ b/cpp/models/ide_endemic_secir/normalized_model.cpp @@ -0,0 +1,281 @@ +#include "ide_endemic_secir/model.h" +#include "ide_endemic_secir/normalized_model.h" +#include "ide_endemic_secir/computed_parameters.h" +#include "ide_endemic_secir/parameters.h" +#include "ide_endemic_secir/infection_state.h" +#include "memilio/config.h" +#include "memilio/utils/logging.h" + +#include "memilio/utils/time_series.h" +#include "vector" +#include +#include +#include +#include +#include +#include + +namespace mio +{ +namespace endisecir +{ + +NormModel::NormModel(CompParameters const& compparams) + : parameters{Parameters()} + , compparameters{std::make_shared(compparams)} + , transitions{TimeSeries(Eigen::Index(InfectionTransition::Count))} + , populations{TimeSeries(Eigen::Index(InfectionState::Count) - 1)} +{ + //Set populations at start time t0. + TimeSeries::Vector vec_initnormalizedpopulations = + TimeSeries::Vector(Eigen::Index(InfectionState::Count) - 1); + for (int infection_state = 0; infection_state < Eigen::Index(InfectionState::Count) - 1; infection_state++) { + vec_initnormalizedpopulations[infection_state] = + compparameters->m_statesinit[0][infection_state] / compparameters->m_totalpopulationinit[0][0]; + } + populations.add_time_point(0, vec_initnormalizedpopulations); + + // Set flows at start time t0. + // As we assume that all individuals have infectio age 0 at time t0, the flows at t0 are set to 0. + transitions.add_time_point( + 0, TimeSeries::Vector::Constant(static_cast(InfectionTransition::Count), 0.)); +} + +bool NormModel::check_constraints() const +{ + if (!(static_cast(populations.get_num_elements()) == static_cast(InfectionState::Count) - 1)) { + log_error(" A variable given for model construction is not valid. Number of elements in vector of populations " + "does not match the required number."); + return true; + } + + for (int i = 0; i < static_cast(InfectionState::Count) - 1; i++) { + if (populations[0][i] < 0) { + log_error("Initialization failed. Initial values for populations are less than zero."); + return true; + } + } + return parameters.check_constraints(); +} + +// ----Functionality for the iterations of a simulation. ---- +void NormModel::compute_susceptibles(ScalarType dt) +{ + Eigen::Index num_time_points = populations.get_num_time_points(); + populations.get_last_value()[static_cast(InfectionState::Susceptible)] = + (populations[num_time_points - 2][static_cast(InfectionState::Susceptible)] + + dt * parameters.get()) / + (1 + dt * (m_forceofinfection[num_time_points - 2][0] + parameters.get()) - + transitions[num_time_points - 2][(Eigen::Index)InfectionTransition::InfectedCriticalToDead]); +} + +void NormModel::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, Eigen::Index current_time_index, ScalarType dt) +{ + Eigen::Index calc_time_index = + (Eigen::Index)std::ceil(compparameters->m_transitiondistributions_support_max[idx_InfectionTransitions] / dt); + ScalarType current_time_age = static_cast(current_time_index) * dt; + ScalarType sum = 0; + //Determine the starting point of the for loop. + Eigen::Index starting_point = std::max(0, (int)current_time_index - (int)calc_time_index); + + for (Eigen::Index i = starting_point; i < current_time_index; i++) { + ScalarType state_age_i = static_cast(i) * dt; + + sum += (transitions[i + 1][idx_IncomingFlow] + + (parameters.get() + + transitions[i][(Eigen::Index)InfectionTransition::InfectedCriticalToDead] - + parameters.get()) * + populations[i][idx_CurrentCompartment]) * + std::exp(-parameters.get() * (current_time_age - state_age_i)) * + parameters.get()[idx_InfectionTransitions] * + compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; + } + if (current_time_index <= calc_time_index) { + transitions.get_value(current_time_index)[idx_InfectionTransitions] = + (-dt) * parameters.get()[idx_InfectionTransitions] * sum - + std::exp((-parameters.get()) * (current_time_age)) * + populations[0][idx_CurrentCompartment] * + parameters.get()[idx_InfectionTransitions] * + compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; + } + else { + transitions.get_value(current_time_index)[idx_InfectionTransitions] = + (-dt) * parameters.get()[idx_InfectionTransitions]*; + } +} + +void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, ScalarType dt) +{ + Eigen::Index current_time_index = transitions.get_num_time_points() - 1; + compute_flow(idx_InfectionTransitions, idx_IncomingFlow, idx_CurrentCompartment, current_time_index, dt); +} + +void Model::flows_currents_timestep(ScalarType dt) +{ + Eigen::Index current_time_index = populations.get_num_time_points() - 1; + // Calculate the transition SusceptibleToExposed with force of infection from previous time step and Susceptibles from + // current time step. + transitions.get_last_value()[static_cast(InfectionTransition::SusceptibleToExposed)] = + m_forceofinfection[current_time_index - 1][0] * + populations.get_last_value()[static_cast(InfectionState::Susceptible)]; + + // Calculate the other Transitions with compute_flow. + // Exposed to InfectedNoSymptoms + compute_flow(Eigen::Index(InfectionTransition::ExposedToInfectedNoSymptoms), + Eigen::Index(InfectionTransition::SusceptibleToExposed), Eigen::Index(InfectionState::Exposed), dt); + // InfectedNoSymptoms to InfectedSymptoms + compute_flow(Eigen::Index(InfectionTransition::InfectedNoSymptomsToInfectedSymptoms), + Eigen::Index(InfectionTransition::ExposedToInfectedNoSymptoms), + Eigen::Index(InfectionState::InfectedNoSymptoms), dt); + // InfectedNoSymptoms to Recovered + compute_flow(Eigen::Index(InfectionTransition::InfectedNoSymptomsToRecovered), + Eigen::Index(InfectionTransition::ExposedToInfectedNoSymptoms), + Eigen::Index(InfectionState::InfectedNoSymptoms), dt); + // InfectedSymptoms to InfectedSevere + compute_flow(Eigen::Index(InfectionTransition::InfectedSymptomsToInfectedSevere), + Eigen::Index(InfectionTransition::InfectedNoSymptomsToInfectedSymptoms), + Eigen::Index(InfectionState::InfectedSymptoms), dt); + // InfectedSymptoms to Recovered + compute_flow(Eigen::Index(InfectionTransition::InfectedSymptomsToRecovered), + Eigen::Index(InfectionTransition::InfectedNoSymptomsToInfectedSymptoms), + Eigen::Index(InfectionState::InfectedSymptoms), dt); + // InfectedSevere to InfectedCritical + compute_flow(Eigen::Index(InfectionTransition::InfectedSevereToInfectedCritical), + Eigen::Index(InfectionTransition::InfectedSymptomsToInfectedSevere), + Eigen::Index(InfectionState::InfectedSevere), dt); + // InfectedCritical to Recovered + compute_flow(Eigen::Index(InfectionTransition::InfectedSevereToRecovered), + Eigen::Index(InfectionTransition::InfectedSymptomsToInfectedSevere), + Eigen::Index(InfectionState::InfectedSevere), dt); + // InfectedCritical to Dead + compute_flow(Eigen::Index(InfectionTransition::InfectedCriticalToDead), + Eigen::Index(InfectionTransition::InfectedSevereToInfectedCritical), + Eigen::Index(InfectionState::InfectedCritical), dt); + // InfectedCritical to Recovered + compute_flow(Eigen::Index(InfectionTransition::InfectedCriticalToRecovered), + Eigen::Index(InfectionTransition::InfectedSevereToInfectedCritical), + Eigen::Index(InfectionState::InfectedCritical), dt); +} + +void NormModel::update_compartment_with_sum(InfectionState infectionState, + std::vector const& IncomingFlows, + bool Transitionispossible, ScalarType dt) +{ + Eigen::Index current_time_index = populations.get_num_time_points() - 1; + ScalarType current_time_age = (ScalarType)current_time_index * dt; + Eigen::Index calc_time_index = current_time_index; + if (Transitionispossible) { + calc_time_index = compparameters->m_transitiondistributions[(int)infectionState].size() - 1; + } + + ScalarType sum = 0; + + Eigen::Index starting_point = std::max(0, (int)current_time_index - (int)calc_time_index); + for (int i = starting_point; i < current_time_index; i++) { + ScalarType state_age_i = (ScalarType)i * dt; + ScalarType sum_inflows = 0; + for (const InfectionTransition& inflow : IncomingFlows) { + sum_inflows += transitions[i + 1][(int)inflow]; + } + if (Transitionispossible) { + sum += compparameters->m_transitiondistributions[(int)infectionState][current_time_index - i] * + (sum_inflows + (parameters.get() + + transitions[i][(Eigen::Index)InfectionTransition::InfectedCriticalToDead] - + parameters.get()) * + populations[i][(int)infectionState]) * + std::exp(-parameters.get() * (current_time_age - state_age_i)); + } + else { + sum += (sum_inflows + (parameters.get() + + transitions[i][(Eigen::Index)InfectionTransition::InfectedCriticalToDead] - + parameters.get()) * + populations[i][(int)infectionState]) * + std::exp(-parameters.get() * (current_time_age - state_age_i)); + } + } + if (Transitionispossible) { + if (current_time_index <= calc_time_index) { + populations.get_last_value()[(int)infectionState] = + dt * sum + compparameters->m_transitiondistributions[(int)infectionState][current_time_index] * + populations[0][(int)infectionState] * + std::exp(-parameters.get() * (current_time_age)); + } + else { + populations.get_last_value()[(int)infectionState] = dt * sum; + } + } + else { + populations.get_last_value()[(int)infectionState] = + dt * sum + + populations[0][(int)infectionState] * std::exp(-parameters.get() * (current_time_age)); + } +} + +void NormModel::update_compartments(ScalarType dt) +{ + + // Exposed + update_compartment_with_sum(InfectionState::Exposed, {InfectionTransition::SusceptibleToExposed}, true, dt); + // InfectedNoSymptoms + update_compartment_with_sum(InfectionState::InfectedNoSymptoms, {InfectionTransition::ExposedToInfectedNoSymptoms}, + true, dt); + + // InfectedSymptoms + update_compartment_with_sum(InfectionState::InfectedSymptoms, + {InfectionTransition::InfectedNoSymptomsToInfectedSymptoms}, true, dt); + + // InfectedSevere + update_compartment_with_sum(InfectionState::InfectedSevere, {InfectionTransition::InfectedSymptomsToInfectedSevere}, + true, dt); + + // InfectedCritical + update_compartment_with_sum(InfectionState::InfectedCritical, + {InfectionTransition::InfectedSevereToInfectedCritical}, true, dt); + // Recovered + update_compartment_with_sum(InfectionState::Recovered, + { + InfectionTransition::InfectedNoSymptomsToRecovered, + InfectionTransition::InfectedSymptomsToRecovered, + InfectionTransition::InfectedSevereToRecovered, + InfectionTransition::InfectedCriticalToRecovered, + }, + false, dt); +} + +void NormModel::compute_forceofinfection(ScalarType dt) +{ + + Eigen::Index num_time_points = populations.get_num_time_points(); + ScalarType current_time = populations.get_last_time(); + + // Determine the starting point of the for loop. + Eigen::Index starting_point = std::max(0, (int)num_time_points - 1 - (int)compparameters->m_FoI_0.size()); + + ScalarType sum = 0.; + // Compute the sum in the force of infection term. + for (Eigen::Index i = starting_point; i < num_time_points - 1; i++) { + sum += compparameters->m_infectivity[num_time_points - 1 - i] * + populations[i + 1][(int)InfectionState::Susceptible] * m_forceofinfection[i][0]; + } + + m_forceofinfection.get_last_value()[0] = + (dt * sum) * (parameters.get().eval(current_time) * + parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)); + + // Add inital functions for the force of infection in case they still have an influence. + if ((int)compparameters->m_FoI_0.size() <= num_time_points) { + m_forceofinfection.get_last_value()[0] += compparameters->m_FoI_0[num_time_points - 1]; + } + if ((int)compparameters->m_InitFoI.size() <= num_time_points) { + m_forceofinfection.get_last_value()[0] += + compparameters->m_InitFoI[num_time_points - 1] * + parameters.get().eval(current_time) * + parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0); + } +} + +} // namespace endisecir + +} // namespace mio \ No newline at end of file diff --git a/cpp/models/ide_endemic_secir/normalized_model.h b/cpp/models/ide_endemic_secir/normalized_model.h new file mode 100644 index 0000000000..660c61591a --- /dev/null +++ b/cpp/models/ide_endemic_secir/normalized_model.h @@ -0,0 +1,157 @@ +#ifndef IDE_END_SECIR_NORMMODEL_H +#define IDE_END_SECIR_NORMMODEL_H + +#include "ide_endemic_secir/infection_state.h" +#include "ide_endemic_secir/parameters.h" +#include "ide_endemic_secir/computed_parameters.h" +#include "memilio/config.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/utils/time_series.h" + +#include "vector" +#include +#include +#include + +namespace mio +{ +namespace endisecir +{ + +// Forward declaration of friend classes/functions of Model. +class NormModel; +class Simulation; + +class NormModel +{ + using ParameterSet = Parameters; + +public: + /** + * @brief Constructor to create an endemic IDE_SECIR model. + * + * @param[in] TODO!!!!!! + */ + + NormModel(CompParameters const& compparams); + + /** + * @brief Checks constraints on model parameters and initial data. + * @return Returns true if one (or more) constraint(s) are not satisfied, otherwise false. + */ + bool check_constraints() const; + + // ---- Public parameters. ---- + ParameterSet parameters; ///< ParameterSet of Model Parameters. + std::shared_ptr compparameters; + TimeSeries + transitions; ///< TimesSeries containing points of time and the corresponding number of individuals transitioning + // from one #InfectionState to another as defined in #Infection%s. + TimeSeries populations; ///< TimeSeries containing points of time and the corresponding number of people + // in defined #InfectionState%s. + +private: + // ---- Functionality for the iterations of a simulation. + + /** + * @brief Computes number of Susceptibles for the current last time in populations. + * + * Number is computed by using the previous number of Susceptibles, total population of the last time point and + * the force of infection (also from the last time point). + * Number is stored at the matching index in populations. + * + * @param[in] dt Time discretization step size. + */ + void compute_susceptibles(ScalarType dt); + + /** + * @brief Computes sizeof a flow + * + * Computes size of one Transition from #InfectionTransition, specified in idx_InfectionTransitions, for the time index + * current_time_index. + * + * @param[in] idx_InfectionTransitions Specifies the considered transition from #InfectionTransition + * @param[in] idx_IncomingFlow Index of the transition in #InfectionTransition, which goes to the considered starting + * compartment of the transition specified in idx_InfectionTransitions. Size of considered flow is calculated via + * the value of this incoming flow. + * @param[in] idx_CurrentCompartment Index of the Compartment we flow out. + * @param[in] current_time_index The time index the transition should be computed for. + * @param[in] dt Time discretization step size. + */ + void compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, Eigen::Index current_time_index, ScalarType dt); + + /** + * @brief Computes size of a flow + * + * Computes size of one Transition from #InfectionTransition, specified in idx_InfectionTransitions, for the current + * last time value in transitions. + * + * @param[in] idx_InfectionTransitions Specifies the considered transition from #InfectionTransition + * @param[in] idx_IncomingFlow Index of the transition in #InfectionTransition, which goes to the considered starting + * compartment of the transition specified in idx_InfectionTransitions. Size of considered flow is calculated via + * the value of this incoming flow. + * @param[in] idx_CurrentCompartment Index of the Compartment we flow out. + * @param[in] dt Time discretization step size. + */ + void compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, ScalarType dt); + + /** + * @brief Sets all required transitions for the current last timestep in transitions. + * + * New values are stored in transitions. Most values are computed via the function compute_flow() + * + * @param[in] dt time discretization step size. + */ + void flows_currents_timestep(ScalarType dt); + + /** + * @brief Updates the values of one compartment, specified in infectionState, using all past transitions. + * + * New value is stored in populations. The values are calculated using all past values for the incoming flows + * including the current time step. + * Therefore the flows of the current time step should be calculated before using this function. + * @param[in] infectionState Specifies the #InfectionState we want to update. + * @param[in] IncomingFlows + * @param[in] NaturalDeathispossible Boolian that determines if there is the possibility of Natural Death in infectionState. + * @param[in] Transitionispossible Boolian that determines if it is possible to transition from the current InfectionState + * into another + * @param[in] dt + */ + void update_compartment_with_sum(InfectionState infectionState, + std::vector const& IncomingFlows, bool Transitionispossible, + ScalarType dt); + + /** + * @brief Updates the values of all compartments except Susceptible + * + * New value is stored in populations. Values are computed via the function update_compartment_from_flow + */ + void update_compartments(ScalarType dt); + + /** + * @brief Computes the force of infection for the current last time in transitions. + * + * Computed value is stored in m_forceofinfection. + * + * @param[in] dt Time discretization step size. + */ + void compute_forceofinfection(ScalarType dt); + + // ---- Private parameters. ---- + + TimeSeries m_forceofinfection{ + TimeSeries(1)}; ///< TimeSeries containing the Force of infection term for every time point, + // needed for the numerical scheme. + + // ---- Friend classes/functions. ---- + // In the Simulation class, the actual simulation is performed which is why it needs access to the here + // defined (and private) functions to solve the model equations. + friend class Simulation; +}; + +} // namespace endisecir +} // namespace mio + +#endif // IDE_END_SECIR_NORMMODEL_H \ No newline at end of file diff --git a/cpp/models/ide_endemic_secir/simulation.cpp b/cpp/models/ide_endemic_secir/simulation.cpp index d5de927642..095274183c 100644 --- a/cpp/models/ide_endemic_secir/simulation.cpp +++ b/cpp/models/ide_endemic_secir/simulation.cpp @@ -15,16 +15,13 @@ void Simulation::advance(ScalarType tmax) mio::log_info("Simulating IDE-END-SECIR from t0 = {} until tmax = {} with dt = {}.", m_model->transitions.get_last_time(), tmax, m_dt); - m_model->set_transitiondistributions_support_max(m_dt); - m_model->set_calctime(); - m_model->set_transitiondistributions(m_dt); - m_model->set_transitiondistributions_derivative(m_dt); - m_model->set_meaninfectivity(m_dt); - // m_model->set_initalvaluesforceofinfection(m_dt); - m_model->set_reproductionnumber_c(m_dt); - m_model->set_probability_of_transition(m_dt); - m_model->set_meansojourntime(m_dt); - m_model->set_equilibrium(); + m_model->compparameters->set_transitiondistributions_support_max(m_dt); + m_model->compparameters->set_transitiondistributions(m_dt); + m_model->compparameters->set_transitiondistributions_derivative(m_dt); + m_model->compparameters->set_infectivity(m_dt); + m_model->compparameters->set_reproductionnumber_c(m_dt); + m_model->compparameters->set_FoI_0(); + m_model->compparameters->set_InitFoI(m_dt); // For every time step: while (m_model->transitions.get_last_time() < tmax - m_dt / 2) { @@ -37,9 +34,6 @@ void Simulation::advance(ScalarType tmax) m_model->m_forceofinfectionupdate.add_time_point(m_model->m_forceofinfectionupdate.get_last_time() + m_dt); m_model->m_totalpopulation.add_time_point(m_model->m_totalpopulation.get_last_time() + m_dt); m_model->m_totalpopulationupdate.add_time_point(m_model->m_totalpopulationupdate.get_last_time() + m_dt); - // m_model->m_totalpopulationincludingD.add_time_point(m_model->m_totalpopulationupdate.get_last_time() + m_dt); - // m_model->m_totalpopulationupdateincludingD.add_time_point(m_model->m_totalpopulationupdate.get_last_time() + - // m_dt); m_model->m_normalizedpopulations.add_time_point(m_model->m_normalizedpopulations.get_last_time() + m_dt); // Compute susceptibles: diff --git a/cpp/models/ide_endemic_secir/simulation.h b/cpp/models/ide_endemic_secir/simulation.h index a3926d102c..ce383990e9 100644 --- a/cpp/models/ide_endemic_secir/simulation.h +++ b/cpp/models/ide_endemic_secir/simulation.h @@ -1,6 +1,7 @@ #ifndef IDE_END_SECIR_SIMULATION_H #define IDE_END_SECIR_SIMULATION_H +#include "ide_endemic_secir/computed_parameters.h" #include "ide_endemic_secir/model.h" #include "memilio/config.h" #include "memilio/utils/time_series.h" @@ -97,29 +98,9 @@ class Simulation return m_model->m_totalpopulationupdate; } - // TimeSeries const& get_totalpopulations_includingD() - // { - // return m_model->m_totalpopulationincludingD; - // } - - // TimeSeries const& get_totalpopulations_update_includingD() - // { - // return m_model->m_totalpopulationupdateincludingD; - // } - ScalarType const& get_reproductionnumber_c() { - return m_model->m_reproductionnumber_c; - } - - std::vector const& get_equilibriumcompartments() - { - return m_model->m_equilibriumnormalizedcompartments; - } - - ScalarType const& get_equilibrium_forceofinfection() - { - return m_model->m_equilibriumforceofinfection; + return m_model->compparameters->m_reproductionnumber_c; } /** From 265774af50696c7c49080e5b523a6860d71073fe Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Mon, 18 Aug 2025 13:05:09 +0200 Subject: [PATCH 11/22] small changes --- cpp/examples/ide_endemic_secir.cpp | 139 ++++++++++---- .../ide_endemic_secir/computed_parameters.h | 171 ++++++++++++------ cpp/models/ide_endemic_secir/model.cpp | 13 +- .../ide_endemic_secir/normalized_model.cpp | 88 +++++++-- .../ide_endemic_secir/normalized_model.h | 1 - cpp/models/ide_endemic_secir/simulation.cpp | 41 ++++- cpp/models/ide_endemic_secir/simulation.h | 76 +++++++- 7 files changed, 406 insertions(+), 123 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index 4eae0757e1..c5e0936211 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -1,5 +1,7 @@ +#include "ide_endemic_secir/computed_parameters.h" #include "ide_endemic_secir/model.h" #include "ide_endemic_secir/infection_state.h" +#include "ide_endemic_secir/normalized_model.h" #include "ide_endemic_secir/parameters.h" #include "ide_endemic_secir/simulation.h" #include "memilio/config.h" @@ -17,7 +19,7 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 1000; + ScalarType tmax = 10; ScalarType dt = 1.0; int num_states = static_cast(mio::endisecir::InfectionState::Count); @@ -39,7 +41,7 @@ int main() init.add_time_point(0, vec_init); - mio::endisecir::Model model(std::move(init)); + mio::endisecir::CompParameters computed_parameters(std::move(init)); //Set working parameters @@ -47,11 +49,52 @@ int main() // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - mio::SmootherCosine smoothcos(8.0); + mio::SmootherCosine smoothcos(6.0); mio::StateAgeFunctionWrapper delaydistribution(smoothcos); std::vector vec_delaydistribution(num_transitions, delaydistribution); - model.parameters.get() = vec_delaydistribution; + // Uncomment for Lognorm. + // mio::ConstantFunction initialfunc(0); + // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); + // std::vector vec_delaydistribution(num_transitions, delaydistributioninit); + // // ExposedToInfectedNoSymptoms + // mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.3, 0, 4.2); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms].set_state_age_function( + // survivalExposedToInfectedNoSymptoms); + // // InfectedNoSymptomsToInfectedSymptoms + // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.7, 0, 0.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] + // .set_state_age_function(survivalInfectedNoSymptomsToInfectedSymptoms); + // // InfectedNoSymptomsToRecovered + // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToRecovered(0.2, 0, 7.7); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered] + // .set_state_age_function(survivalInfectedNoSymptomsToRecovered); + // // InfectedSymptomsToInfectedSevere + // mio::LognormSurvivalFunction survivalInfectedSymptomsToInfectedSevere(0.7, 0, 5.3); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere] + // .set_state_age_function(survivalInfectedSymptomsToInfectedSevere); + // // InfectedSymptomsToRecovered + // mio::LognormSurvivalFunction survivalInfectedSymptomsToRecovered(0.2, 0, 7.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered].set_state_age_function( + // survivalInfectedSymptomsToRecovered); + // // InfectedSevereToInfectedCritical + // mio::LognormSurvivalFunction survivalInfectedSevereToInfectedCritical(1.0, 0, 0.9); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical] + // .set_state_age_function(survivalInfectedSevereToInfectedCritical); + // // InfectedSevereToRecovered + // mio::LognormSurvivalFunction survivalInfectedSevereToRecovered(0.3, 0, 17.1); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToRecovered].set_state_age_function( + // survivalInfectedSevereToRecovered); + // // InfectedCriticalToDead + // mio::LognormSurvivalFunction survivalInfectedCriticalToDead(0.4, 0, 9.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToDead].set_state_age_function( + // survivalInfectedCriticalToDead); + // // InfectedCriticalToRecovered + // mio::LognormSurvivalFunction survivalInfectedCriticalToRecovered(0.3, 0, 17.1); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToRecovered].set_state_age_function( + // survivalInfectedCriticalToRecovered); + + computed_parameters.parameters.get() = vec_delaydistribution; std::vector vec_prob((int)mio::endisecir::InfectionTransition::Count, 1.); vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] = 0.5; @@ -63,68 +106,92 @@ int main() vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToDead)] = 0.2; vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToRecovered)] = 1 - 0.2; - model.parameters.set(vec_prob); + computed_parameters.parameters.set(vec_prob); - mio::ContactMatrixGroup contact_matrix = mio::ContactMatrixGroup(1, 1); - contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); - model.parameters.get() = mio::UncertainContactMatrix(contact_matrix); + mio::ContactMatrixGroup contact_matrix = mio::ContactMatrixGroup(1, 1); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); + computed_parameters.parameters.get() = mio::UncertainContactMatrix(contact_matrix); mio::ConstantFunction constant(0.1); mio::StateAgeFunctionWrapper constant_prob(constant); - model.parameters.get() = constant_prob; + computed_parameters.parameters.get() = constant_prob; mio::ExponentialSurvivalFunction exponential(0.5); mio::StateAgeFunctionWrapper exponential_prob(exponential); - model.parameters.get() = exponential_prob; - model.parameters.get() = exponential_prob; + computed_parameters.parameters.get() = exponential_prob; + computed_parameters.parameters.get() = exponential_prob; - model.parameters.set(4e-3); - model.parameters.set(3e-3); + computed_parameters.parameters.set(4e-3); + computed_parameters.parameters.set(3e-3); - //model.set_tol_for_support_max(1e-6); + //computed_parameters.set_tol_for_support_max(1e-6); + + mio::endisecir::Model model(computed_parameters); + + mio::endisecir::NormModel normmodel(computed_parameters); // start the simulation. - mio::endisecir::Simulation sim(model, dt); + mio::endisecir::Simulation sim(computed_parameters, model, normmodel, dt); sim.advance(tmax); + //Get the compartments of model and print them. auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); - - // interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); - + interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); // Uncomment to print the compartments computed with the update scheme. // auto interpolated_results_update = mio::interpolate_simulation_result(sim.get_compartments_update(), dt / 2.); // interpolated_results_update.print_table({"US", "UE", "UC", "UI", "UH", "UU", "UR", "UD"}, 16, 8); + //Get the commpartments of normmodel and print them. + auto interpolated_normresults = mio::interpolate_simulation_result(sim.get_normmodel_compartments(), dt / 2.); + interpolated_normresults.print_table({"s", "e", "c", "i", "h", "u", "r"}, 16, 8); + + // Uncomment to print the normalized compartments of model. + sim.get_normalizedcompartments().print_table({"S/N", "E/N", "C/N", "I/N", "H/N", "U/N", "R/N"}, 16, 8); + + // Uncomment to print the transitions of model. + // sim.get_transitions().print_table( + // {"S->E", "E->C", "C->I", "C->R", "I->H", "I->R", "H->U", "H->R", "U->D", "U->R"}, 16, 8); + // sim.get_transitions_update().print_table( + // {"US->UE", "UE->UC", "UC->UI", "UC->UR", "UI->UH", "UI->UR", "UH->UU", "UH->UR", "UU->UD", "UU->UR"}, + // 16, 8); + + // Uncomment to print the transitions of normmodel. + // sim.get_normmodel_transitions().print_table( + // {"s->e", "e->c", "c->i", "c->r", "i->h", "i->r , "h->u", "h->r", "u->d", "u->r"}, 16, 8); + + // Uncomment to print the force of infection of model. + sim.get_forceofinfections().print_table({"FoI"}, 16, 8); + // sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); + + // Uncomment to print the force of infection of normmodel. + sim.get_normmodel_forceofinfections().print_table({"norm FoI"}, 16, 8); + // Uncomment to print the reproduction number std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; + // Uncomment to print the the values T_z1^z2 + // for (int i = 0; i < (int)sim.get_T().size(); i++) { + // std::cout << "T_" << i << " = " << sim.get_T()[i] << "\n"; + // } + + // Uncomment to print the values W_z + // for (int i = 0; i < (int)sim.get_W().size(); i++) { + // std::cout << "W_" << i << " = " << sim.get_W()[i] << "\n"; + // } + // Uncomment to print the transitions. - //sim.get_transitions().print_table( - // {"S->E 1", "E->C 1", "C->I 1", "C->R 1", "I->H 1", "I->R 1", "H->U 1", "H->R 1", "U->D 1", "U->R 1"}, 16, 8); + // sim.get_transitions().print_table( + // {"S->E 1", "E->C 1", "C->I 1", "C->R 1", "I->H 1", "I->R 1", "H->U 1", "H->R 1", "U->D 1", "U->R 1"}, 16, 8); // sim.get_transitions_update().print_table( // {"US->E 1", "UE->C 1", "UC->I 1", "UC->R 1", "UI->H 1", "UI->R 1", "UH->U 1", "uH->R 1", "UU->D 1", "UU->R 1"}, // 16, 8); - // Uncomment to print the normalized compartments. - //sim.get_normalizedcompartments().print_table({"s", "e", "c", "i", "h", "u", "r", "d "}, 16, 8); - // Uncomment to print the total population size. - // sim.get_totalpopulations().print_table({"N"}, 16, 9); + //sim.get_totalpopulations().print_table({"N"}, 16, 9); // Uncomment to print the force of infection. - sim.get_forceofinfections().print_table({"FoI"}, 16, 8); + // sim.get_forceofinfections().print_table({"FoI"}, 16, 8); // sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); - - // std::vector equi = sim.get_equilibriumcompartments(); - // std::cout << "Equilibrium normalized compartments: \n"; - // std::cout << "foi* " << sim.get_equilibrium_forceofinfection() << "\n"; - // std::cout << "s* " << equi[(int)mio::endisecir::InfectionState::Susceptible] << "\n"; - // std::cout << "e* " << equi[(int)mio::endisecir::InfectionState::Exposed] << "\n"; - // std::cout << "c* " << equi[(int)mio::endisecir::InfectionState::InfectedNoSymptoms] << "\n"; - // std::cout << "i* " << equi[(int)mio::endisecir::InfectionState::InfectedSymptoms] << "\n"; - // std::cout << "h* " << equi[(int)mio::endisecir::InfectionState::InfectedSevere] << "\n"; - // std::cout << "u* " << equi[(int)mio::endisecir::InfectionState::InfectedCritical] << "\n"; - // std::cout << "r* " << equi[(int)mio::endisecir::InfectionState::Recovered] << "\n"; } \ No newline at end of file diff --git a/cpp/models/ide_endemic_secir/computed_parameters.h b/cpp/models/ide_endemic_secir/computed_parameters.h index fcd2752c9b..79925d1d7b 100644 --- a/cpp/models/ide_endemic_secir/computed_parameters.h +++ b/cpp/models/ide_endemic_secir/computed_parameters.h @@ -124,20 +124,31 @@ class CompParameters {(int)InfectionTransition::InfectedCriticalToDead, (int)InfectionTransition::InfectedCriticalToRecovered}}; for (int state = 2; state < (int)InfectionState::Count - 2; state++) { - Eigen::Index calc_time_index = std::max((Eigen::Index)std::ceil(vector_transitions[state - 2][0]), - (Eigen::Index)std::ceil(vector_transitions[state - 2][1])) / - dt; + Eigen::Index calc_time_index = + std::max( + m_transitiondistributions_support_max[(Eigen::Index)std::ceil(vector_transitions[state - 2][0])], + m_transitiondistributions_support_max[(Eigen::Index)std::ceil(vector_transitions[state - 2][1])]) / + dt; // Create vec_derivative that stores the value of the approximated derivative for all necessary time points. std::vector vec_contribution_to_foi_2(calc_time_index + 1, 0.); for (Eigen::Index i = 0; i <= calc_time_index; i++) { ///Compute the state_age. ScalarType state_age = (ScalarType)i * dt; - vec_contribution_to_foi_2[i] = - parameters.get()[vector_transitions[state - 2][0]] * - parameters.get()[vector_transitions[state - 2][0]].eval(state_age) + - parameters.get()[vector_transitions[state - 2][1]] * + if (m_transitiondistributions_support_max[(Eigen::Index)std::ceil(vector_transitions[state - 2][0])] / + dt <= + calc_time_index) { + vec_contribution_to_foi_2[i] += + parameters.get()[vector_transitions[state - 2][0]] * + parameters.get()[vector_transitions[state - 2][0]].eval(state_age); + } + if (m_transitiondistributions_support_max[(Eigen::Index)std::ceil(vector_transitions[state - 2][1])] / + dt <= + calc_time_index) { + vec_contribution_to_foi_2[i] += + parameters.get()[vector_transitions[state - 2][1]] * parameters.get()[vector_transitions[state - 2][1]].eval(state_age); + } } m_transitiondistributions[state] = vec_contribution_to_foi_2; } @@ -196,15 +207,14 @@ class CompParameters ScalarType sum = 0; Eigen::Index starting_point = - std::max(0, (int)time_point_index - 1 - - (int)m_transitiondistributions_support_max[( - int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms]); + std::max(0, (int)time_point_index - (int)m_transitiondistributions_support_max[( + int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms]); for (int i = starting_point; i <= time_point_index - 1; i++) { ScalarType state_age_i = static_cast(i) * dt; sum += - parameters.get().eval(state_age_i) * + parameters.get().eval(state_age_i) * m_transitiondistributions[static_cast(InfectionState::InfectedSymptoms)][i] * m_transitiondistributions_derivative[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] [time_point_index - i]; @@ -241,61 +251,47 @@ class CompParameters ScalarType time_point_age = (ScalarType)time_point_index * dt; //We compute a_1 and a_2 at time_point. - Eigen::Index starting_point_1 = std::max( + Eigen::Index starting_point = std::max( 0, - (int)time_point_index - 1 - + (int)time_point_index - (int)m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms]); - Eigen::Index starting_point_2 = - std::max(0, (int)time_point_index - 1 - - (int)m_transitiondistributions_support_max[( - int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms]); //compute a_1: - for (int i = starting_point_1; i < std::min(calc_time_index_1, calc_time_index); i++) { + if (time_point_index <= calc_time_index_1) { - ScalarType state_age_i = static_cast(i) * dt; - a_1 += parameters.get().eval(state_age_i) * - m_transitiondistributions[static_cast(InfectionState::InfectedNoSymptoms)][i] * - m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] - [time_point_index - i]; + for (int i = starting_point; i < time_point_index; i++) { + + ScalarType state_age_i = static_cast(i) * dt; + a_1 += parameters.get().eval(state_age_i) * + m_transitiondistributions[static_cast(InfectionState::InfectedNoSymptoms)][i] * + m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] + [time_point_index - i]; + } } //compute a_2: - for (int i = starting_point_2; i < std::min(calc_time_index_2, calc_time_index); i++) { + if (time_point_index <= calc_time_index_2) { + + for (int i = starting_point; i < time_point_index; i++) { - a_2 += m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] - [time_point_index - i] * - m_B[i]; + a_2 += m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] + [time_point_index - i] * + m_B[i]; + } } m_infectivity[time_point_index] = dt * std::exp(-parameters.get() * time_point_age) * (a_2 - a_1); } } - /** - * @brief Setter for the Reproduction number R_c. - * - */ - void set_reproductionnumber_c(ScalarType dt) - { - // Determine the corresponding time index. - - Eigen::Index calc_time_index = m_infectivity.size() - 1; - ScalarType sum = 0; - for (int i = 0; i <= calc_time_index; i++) { - sum += m_infectivity[i]; - } - m_reproductionnumber_c = parameters.get().eval(0) * - parameters.get().get_cont_freq_mat().get_matrix_at(0)(0, 0) * dt * - sum; - } //TODO Erklärung void set_FoI_0() { - Eigen::Index calc_time_index = m_infectivity.size() - 1; + Eigen::Index calc_time_index = m_infectivity.size(); m_FoI_0 = std::vector(calc_time_index, 0.); m_NormFoI_0 = std::vector(calc_time_index, 0.); - - for (Eigen::Index time_point_index = 0; time_point_index <= calc_time_index; time_point_index++) { + // m_InitFoI.resize(calc_time_index, 0.); + // m_NormInitFoI.resize(calc_time_index, 0.); + for (Eigen::Index time_point_index = 0; time_point_index < calc_time_index; time_point_index++) { m_FoI_0[time_point_index] = m_infectivity[time_point_index] * (m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] + m_statesinit[0][(int)InfectionState::InfectedNoSymptoms]); @@ -308,16 +304,16 @@ class CompParameters void set_InitFoI(ScalarType dt) { - Eigen::Index calc_time_index = std::max(m_infectivity.size(), m_B.size()) - 1; - m_InitFoI = std::vector(calc_time_index, 0.); - m_NormInitFoI = std::vector(calc_time_index, 0.); - for (Eigen::Index time_point_index = 0; time_point_index <= calc_time_index; time_point_index++) { + Eigen::Index calc_time_index = std::max(m_infectivity.size(), m_B.size()); + m_InitFoI.resize(calc_time_index, 0.); + m_NormInitFoI.resize(calc_time_index, 0.); + for (Eigen::Index time_point_index = 0; time_point_index < calc_time_index; time_point_index++) { ScalarType time_point_age = (ScalarType)time_point_index * dt; if (time_point_index <= (int)m_B.size()) { - m_InitFoI[time_point_index] += m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] * + m_InitFoI[time_point_index] -= m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] * std::exp(-parameters.get() * time_point_age) * m_B[time_point_index]; - m_NormInitFoI[time_point_index] += + m_NormInitFoI[time_point_index] -= m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] / m_totalpopulationinit * std::exp(-parameters.get() * time_point_age) * m_B[time_point_index]; } @@ -330,6 +326,68 @@ class CompParameters } } + // ---- Parameters needed for the analysis of the model ---- + /** + * @brief Setter for the Reproduction number R_c. + * + */ + void set_reproductionnumber_c(ScalarType dt) + { + // Determine the corresponding time index. + + Eigen::Index calc_time_index = m_infectivity.size() - 1; + ScalarType sum = 0; + for (int i = 0; i <= calc_time_index; i++) { + sum += m_infectivity[i]; + } + m_reproductionnumber_c = parameters.get().eval(0) * + parameters.get().get_cont_freq_mat().get_matrix_at(0)(0, 0) * dt * + sum; + } + + /** + * @brief TODO + * + */ + void set_T(ScalarType dt) + { + // The transition SusceptibleToExposed is not needed in the computations. + for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { + Eigen::Index support_max_index = + (Eigen::Index)std::ceil(m_transitiondistributions_support_max[transition] / dt); + ScalarType sum = 0; + + for (Eigen::Index i = 0; i <= support_max_index; i++) { + // Compute state_age. + ScalarType state_age = (ScalarType)i * dt; + //Compute the apprximate derivative by a backwards difference scheme. + sum -= std::exp(-parameters.get() * state_age) * + m_transitiondistributions_derivative[transition][i]; + } + m_T[transition] = parameters.get()[transition] * sum; + } + } + + /** + * @brief TODO + * + */ + void set_W(ScalarType dt) + { + for (int state = 1; state < (int)InfectionState::Count - 2; state++) { + Eigen::Index calc_time_index = m_transitiondistributions[state].size(); + ScalarType sum = 0; + + for (Eigen::Index i = 0; i <= calc_time_index; i++) { + // Compute state_age. + ScalarType state_age = (ScalarType)i * dt; + //Compute the apprximate derivative by a backwards difference scheme. + sum += std::exp(-parameters.get() * state_age) * m_transitiondistributions[state][i]; + } + m_W[state] = sum; + } + } + // ---- Private parameters. ---- TimeSeries m_statesinit; ///< TimeSeries containing the initial values for the compartments. ScalarType m_totalpopulationinit; @@ -346,13 +404,14 @@ class CompParameters std::vector m_B{std::vector(1, 0.)}; ///< A Vector contaiing the appriximated // values for B. std::vector m_infectivity{ - std::vector(1, 0.)}; ///> a vector containing the approximated mean infectivity for all time points. + std::vector(1, 0.)}; ///< A vector containing the approximated mean infectivity for all time points. ScalarType m_reproductionnumber_c; ///< The control Reproduction number std::vector m_FoI_0{std::vector(1, 0.)}; ///< TODO std::vector m_NormFoI_0{std::vector(1, 0.)}; ///< TODO - std::vector m_InitFoI{std::vector(1, 0.)}; ///< TODO + std::vector m_InitFoI = std::vector(1, 0.); ///< TODO std::vector m_NormInitFoI{std::vector(1, 0.)}; ///< TODO - + std::vector m_T{std::vector((int)InfectionTransition::Count, 0.)}; ///< TODO + std::vector m_W{std::vector((int)InfectionState::Count, 0.)}; ///(compparams)} , transitions{TimeSeries(Eigen::Index(InfectionTransition::Count))} , transitions_update{TimeSeries(Eigen::Index(InfectionTransition::Count))} - , populations{TimeSeries(Eigen::Index(InfectionState::Count))} - , populations_update{TimeSeries(Eigen::Index(InfectionState::Count))} + , populations{compparameters->m_statesinit} + , populations_update{compparameters->m_statesinit} { - // Set States at start time t_0. - populations.add_time_point(0, compparameters->m_statesinit)[0]; - populations_update.add_time_point(0, compparameters->m_statesinit[0]); // Set flows at start time t0. // As we assume that all individuals have infectio age 0 at time t0, the flows at t0 are set to 0. @@ -386,13 +383,13 @@ void Model::compute_forceofinfection(ScalarType dt) m_totalpopulationupdate[num_time_points - 1][0]; // Add inital functions for the force of infection in case they still have an influence. - if ((int)compparameters->m_FoI_0.size() <= num_time_points) { + if (num_time_points <= (int)compparameters->m_FoI_0.size()) { m_forceofinfection.get_last_value()[0] += compparameters->m_FoI_0[num_time_points - 1] / m_totalpopulation[num_time_points - 1][0]; m_forceofinfectionupdate.get_last_value()[0] += compparameters->m_FoI_0[num_time_points - 1] / m_totalpopulationupdate[num_time_points - 1][0]; } - if ((int)compparameters->m_InitFoI.size() <= num_time_points) { + if (num_time_points <= (int)compparameters->m_InitFoI.size()) { m_forceofinfection.get_last_value()[0] += compparameters->m_InitFoI[num_time_points - 1] * parameters.get().eval(current_time) * @@ -406,6 +403,6 @@ void Model::compute_forceofinfection(ScalarType dt) } } -} // namespace endisecir +}; // namespace endisecir } // namespace mio diff --git a/cpp/models/ide_endemic_secir/normalized_model.cpp b/cpp/models/ide_endemic_secir/normalized_model.cpp index 2b9413a827..dd5bc10c79 100644 --- a/cpp/models/ide_endemic_secir/normalized_model.cpp +++ b/cpp/models/ide_endemic_secir/normalized_model.cpp @@ -31,7 +31,7 @@ NormModel::NormModel(CompParameters const& compparams) TimeSeries::Vector(Eigen::Index(InfectionState::Count) - 1); for (int infection_state = 0; infection_state < Eigen::Index(InfectionState::Count) - 1; infection_state++) { vec_initnormalizedpopulations[infection_state] = - compparameters->m_statesinit[0][infection_state] / compparameters->m_totalpopulationinit[0][0]; + compparameters->m_statesinit[0][infection_state] / compparameters->m_totalpopulationinit; } populations.add_time_point(0, vec_initnormalizedpopulations); @@ -39,6 +39,8 @@ NormModel::NormModel(CompParameters const& compparams) // As we assume that all individuals have infectio age 0 at time t0, the flows at t0 are set to 0. transitions.add_time_point( 0, TimeSeries::Vector::Constant(static_cast(InfectionTransition::Count), 0.)); + + m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); } bool NormModel::check_constraints() const @@ -88,7 +90,6 @@ void NormModel::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index parameters.get()) * populations[i][idx_CurrentCompartment]) * std::exp(-parameters.get() * (current_time_age - state_age_i)) * - parameters.get()[idx_InfectionTransitions] * compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; } if (current_time_index <= calc_time_index) { @@ -101,18 +102,18 @@ void NormModel::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index } else { transitions.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions]*; + (-dt) * parameters.get()[idx_InfectionTransitions] * sum; } } -void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, - Eigen::Index idx_CurrentCompartment, ScalarType dt) +void NormModel::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, ScalarType dt) { Eigen::Index current_time_index = transitions.get_num_time_points() - 1; compute_flow(idx_InfectionTransitions, idx_IncomingFlow, idx_CurrentCompartment, current_time_index, dt); } -void Model::flows_currents_timestep(ScalarType dt) +void NormModel::flows_currents_timestep(ScalarType dt) { Eigen::Index current_time_index = populations.get_num_time_points() - 1; // Calculate the transition SusceptibleToExposed with force of infection from previous time step and Susceptibles from @@ -251,26 +252,81 @@ void NormModel::compute_forceofinfection(ScalarType dt) ScalarType current_time = populations.get_last_time(); // Determine the starting point of the for loop. - Eigen::Index starting_point = std::max(0, (int)num_time_points - 1 - (int)compparameters->m_FoI_0.size()); + Eigen::Index starting_point1 = std::max(0, (int)num_time_points - 1 - (int)compparameters->m_infectivity.size()); + + ScalarType sum1 = 0.; + // Compute the first sum in the force of infection term. + for (Eigen::Index i = starting_point1; i < num_time_points - 1; i++) { + sum1 += compparameters->m_infectivity[num_time_points - 1 - i] * + (populations[i + 1][(int)InfectionState::Susceptible] * m_forceofinfection[i][0] + + (parameters.get() + + transitions[i + 1][(int)InfectionTransition::InfectedCriticalToDead] - + parameters.get()) * + populations[i + 1][(int)InfectionState::Exposed]); + } + + // Determine the starting point of the for loop. + Eigen::Index starting_point2 = std::max(0, (int)num_time_points - 1 - (int)compparameters->m_B.size()); + + ScalarType sum2 = 0.; + // Compute the second sum in the force of infection term. + for (Eigen::Index i = starting_point2; i < num_time_points - 1; i++) { + ScalarType state_age = static_cast(i) * dt; + sum2 += + (parameters.get() + transitions[i + 1][(int)InfectionTransition::InfectedCriticalToDead] - + parameters.get()) * + std::exp(-parameters.get() * (current_time - state_age)) * + populations[i + 1][(int)InfectionState::InfectedNoSymptoms] * compparameters->m_B[num_time_points - 1 - i]; + } + + // Determine the starting point of the for loop. + Eigen::Index starting_point3 = + std::max(0, (int)num_time_points - 1 - + (int)compparameters->m_transitiondistributions[(int)InfectionState::InfectedNoSymptoms].size()); + + ScalarType sum3 = 0.; + // Compute the third sum in the force of infection term. + for (Eigen::Index i = starting_point3; i < num_time_points - 1; i++) { + ScalarType state_age = static_cast(i) * dt; + sum3 += + (parameters.get() + transitions[i + 1][(int)InfectionTransition::InfectedCriticalToDead] - + parameters.get()) * + std::exp(-parameters.get() * (current_time - state_age)) * + populations[i + 1][(int)InfectionState::InfectedNoSymptoms] * + parameters.get().eval(current_time - state_age) * + compparameters->m_transitiondistributions[(int)InfectionState::InfectedNoSymptoms][num_time_points - 1 - i]; + } + + // Determine the starting point of the for loop. + Eigen::Index starting_point4 = + std::max(0, (int)num_time_points - 1 - + (int)compparameters->m_transitiondistributions[(int)InfectionState::InfectedSymptoms].size()); - ScalarType sum = 0.; - // Compute the sum in the force of infection term. - for (Eigen::Index i = starting_point; i < num_time_points - 1; i++) { - sum += compparameters->m_infectivity[num_time_points - 1 - i] * - populations[i + 1][(int)InfectionState::Susceptible] * m_forceofinfection[i][0]; + ScalarType sum4 = 0.; + // Compute the third sum in the force of infection term. + for (Eigen::Index i = starting_point4; i < num_time_points - 1; i++) { + ScalarType state_age = static_cast(i) * dt; + sum4 += + (parameters.get() + transitions[i + 1][(int)InfectionTransition::InfectedCriticalToDead] - + parameters.get()) * + std::exp(-parameters.get() * (current_time - state_age)) * + populations[i + 1][(int)InfectionState::InfectedSymptoms] * + parameters.get().eval(current_time - state_age) * + compparameters->m_transitiondistributions[(int)InfectionState::InfectedSymptoms][num_time_points - 1 - i]; } + ScalarType sum = sum1 + sum2 + sum3 + sum4; m_forceofinfection.get_last_value()[0] = (dt * sum) * (parameters.get().eval(current_time) * parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)); // Add inital functions for the force of infection in case they still have an influence. - if ((int)compparameters->m_FoI_0.size() <= num_time_points) { - m_forceofinfection.get_last_value()[0] += compparameters->m_FoI_0[num_time_points - 1]; + if (num_time_points <= (int)compparameters->m_NormFoI_0.size()) { + m_forceofinfection.get_last_value()[0] += compparameters->m_NormFoI_0[num_time_points - 1]; } - if ((int)compparameters->m_InitFoI.size() <= num_time_points) { + if (num_time_points <= (int)compparameters->m_NormInitFoI.size()) { m_forceofinfection.get_last_value()[0] += - compparameters->m_InitFoI[num_time_points - 1] * + compparameters->m_NormInitFoI[num_time_points - 1] * parameters.get().eval(current_time) * parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0); } diff --git a/cpp/models/ide_endemic_secir/normalized_model.h b/cpp/models/ide_endemic_secir/normalized_model.h index 660c61591a..ca2a117fdb 100644 --- a/cpp/models/ide_endemic_secir/normalized_model.h +++ b/cpp/models/ide_endemic_secir/normalized_model.h @@ -5,7 +5,6 @@ #include "ide_endemic_secir/parameters.h" #include "ide_endemic_secir/computed_parameters.h" #include "memilio/config.h" -#include "memilio/utils/custom_index_array.h" #include "memilio/utils/time_series.h" #include "vector" diff --git a/cpp/models/ide_endemic_secir/simulation.cpp b/cpp/models/ide_endemic_secir/simulation.cpp index 095274183c..78f8c8e13e 100644 --- a/cpp/models/ide_endemic_secir/simulation.cpp +++ b/cpp/models/ide_endemic_secir/simulation.cpp @@ -1,6 +1,8 @@ #include "ide_endemic_secir/simulation.h" +#include "ide_endemic_secir/computed_parameters.h" #include "ide_endemic_secir/model.h" +#include "ide_endemic_secir/normalized_model.h" #include "memilio/config.h" #include "memilio/utils/time_series.h" #include @@ -18,14 +20,29 @@ void Simulation::advance(ScalarType tmax) m_model->compparameters->set_transitiondistributions_support_max(m_dt); m_model->compparameters->set_transitiondistributions(m_dt); m_model->compparameters->set_transitiondistributions_derivative(m_dt); + m_model->compparameters->set_B(m_dt); m_model->compparameters->set_infectivity(m_dt); - m_model->compparameters->set_reproductionnumber_c(m_dt); m_model->compparameters->set_FoI_0(); m_model->compparameters->set_InitFoI(m_dt); + m_model->compparameters->set_reproductionnumber_c(m_dt); + m_model->compparameters->set_T(m_dt); + m_model->compparameters->set_W(m_dt); + + m_normmodel->compparameters->set_transitiondistributions_support_max(m_dt); + m_normmodel->compparameters->set_transitiondistributions(m_dt); + m_normmodel->compparameters->set_transitiondistributions_derivative(m_dt); + m_normmodel->compparameters->set_B(m_dt); + m_normmodel->compparameters->set_infectivity(m_dt); + m_normmodel->compparameters->set_FoI_0(); + m_normmodel->compparameters->set_InitFoI(m_dt); + m_normmodel->compparameters->set_reproductionnumber_c(m_dt); + m_normmodel->compparameters->set_T(m_dt); + m_normmodel->compparameters->set_W(m_dt); // For every time step: while (m_model->transitions.get_last_time() < tmax - m_dt / 2) { + //standard model: m_model->transitions.add_time_point(m_model->transitions.get_last_time() + m_dt); m_model->transitions_update.add_time_point(m_model->transitions_update.get_last_time() + m_dt); m_model->populations.add_time_point(m_model->populations.get_last_time() + m_dt); @@ -53,13 +70,31 @@ void Simulation::advance(ScalarType tmax) // Compute m_forceofinfection; m_model->compute_forceofinfection(m_dt); + + // normalized model: + m_normmodel->transitions.add_time_point(m_normmodel->transitions.get_last_time() + m_dt); + m_normmodel->populations.add_time_point(m_normmodel->populations.get_last_time() + m_dt); + m_normmodel->m_forceofinfection.add_time_point(m_normmodel->m_forceofinfection.get_last_time() + m_dt); + + // Compute susceptibles: + m_normmodel->compute_susceptibles(m_dt); + + // Compute flows: + m_normmodel->flows_currents_timestep(m_dt); + + // Compute remaining compartments: + m_normmodel->update_compartments(m_dt); + + // Compute m_forceofinfection; + m_normmodel->compute_forceofinfection(m_dt); } } -TimeSeries simulate(ScalarType tmax, ScalarType dt, Model const& m_model) +TimeSeries simulate(ScalarType tmax, ScalarType dt, CompParameters const& m_compparams, + Model const& m_model, NormModel const& m_normmodel) { m_model.check_constraints(); - Simulation sim(m_model, dt); + Simulation sim(m_compparams, m_model, m_normmodel, dt); sim.advance(tmax); return sim.get_compartments(); } diff --git a/cpp/models/ide_endemic_secir/simulation.h b/cpp/models/ide_endemic_secir/simulation.h index ce383990e9..d23373778d 100644 --- a/cpp/models/ide_endemic_secir/simulation.h +++ b/cpp/models/ide_endemic_secir/simulation.h @@ -3,7 +3,9 @@ #include "ide_endemic_secir/computed_parameters.h" #include "ide_endemic_secir/model.h" +#include "ide_endemic_secir/normalized_model.h" #include "memilio/config.h" +#include "memilio/utils/miompi.h" #include "memilio/utils/time_series.h" #include #include @@ -16,8 +18,10 @@ namespace endisecir class Simulation { public: - Simulation(Model const& model, ScalarType dt = 0.1) - : m_model(std::make_unique(model)) + Simulation(CompParameters const& compparams, Model const& model, NormModel const& normmodel, ScalarType dt = 0.1) + : m_compparams(std::make_unique(compparams)) + , m_model(std::make_unique(model)) + , m_normmodel(std::make_unique(normmodel)) , m_dt(dt) { } @@ -41,13 +45,25 @@ class Simulation return m_model->populations_update; } + /** + * @brief Get the result of the simulation for the normalized compartments, where we use m_model. + * Return the number of persons in all #InfectionState%s + */ TimeSeries get_normalizedcompartments() { return m_model->m_normalizedpopulations; } + /** + * @brief Get the result of the simulation for the compartments of the normalized model. + * Return the number of persons in all #InfectionState%s + */ + TimeSeries get_normmodel_compartments() + { + return m_normmodel->populations; + } /** - * @brief Get the result of the simulation for the compartments + * @brief Get the result of the simulation for the compartments. * Return the number of persons in all #InfectionState%s */ TimeSeries& get_compartments() const @@ -60,11 +76,24 @@ class Simulation return m_model->populations_update; } + /** + * @brief Get the result of the simulation for the normalized compartments, where we use m_model. + * Return the number of persons in all #InfectionState%s + */ TimeSeries& get_normalizedcompartments() const { return m_model->m_normalizedpopulations; } + /** + * @brief Get the result of the simulation for the compartments of the normalized model. + * Return the number of persons in all #InfectionState%s + */ + TimeSeries& get_normmodel_compartments() const + { + return m_normmodel->populations; + } + /** * @brief Get the transitions between the different #InfectionState%s. */ @@ -78,6 +107,14 @@ class Simulation return m_model->transitions_update; } + /** + * @brief Get the transitions between the different #InfectionState%s of the normalized Model. + */ + TimeSeries const& get_normmodel_transitions() + { + return m_normmodel->transitions; + } + TimeSeries const& get_forceofinfections() { return m_model->m_forceofinfection; @@ -88,6 +125,11 @@ class Simulation return m_model->m_forceofinfectionupdate; } + TimeSeries const& get_normmodel_forceofinfections() + { + return m_normmodel->m_forceofinfection; + } + TimeSeries const& get_totalpopulations() { return m_model->m_totalpopulation; @@ -103,6 +145,16 @@ class Simulation return m_model->compparameters->m_reproductionnumber_c; } + std::vector const& get_T() + { + return m_model->compparameters->m_T; + } + + std::vector const& get_W() + { + return m_model->compparameters->m_W; + } + /** * @brief returns the simulation model used in simulation. */ @@ -119,6 +171,22 @@ class Simulation return *m_model; } + /** + * @brief returns the simulation normmodel used in simulation. + */ + const NormModel& get_normmodel() const + { + return *m_normmodel; + } + + /** + * @brief returns the simulation normmodel used in simulation. + */ + NormModel& get_normmodel() + { + return *m_normmodel; + } + /** * @brief get the size of the time step of the simulation. */ @@ -128,7 +196,9 @@ class Simulation } private: + std::unique_ptr m_compparams; ///< Unique pointer to the computed Parameters. std::unique_ptr m_model; ///< Unique pointer to the simulated Model. + std::unique_ptr m_normmodel; ///< Unique pointer to the simulated normalized Model. ScalarType m_dt; ///< Time step used for numerical computations in simulation. }; From 1545eccaccaebb76204ef0f5db0b31315d6d96dc Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Mon, 18 Aug 2025 13:31:55 +0200 Subject: [PATCH 12/22] added some comments --- .../ide_endemic_secir/computed_parameters.h | 56 +++++++++++++------ cpp/models/ide_endemic_secir/simulation.h | 46 +++++++++++++-- 2 files changed, 79 insertions(+), 23 deletions(-) diff --git a/cpp/models/ide_endemic_secir/computed_parameters.h b/cpp/models/ide_endemic_secir/computed_parameters.h index 79925d1d7b..310577fdf1 100644 --- a/cpp/models/ide_endemic_secir/computed_parameters.h +++ b/cpp/models/ide_endemic_secir/computed_parameters.h @@ -85,12 +85,8 @@ class CompParameters /** * @brief Setter for the vector m_transitiondistributions. * - * In the computation of the force of infection in the initialization function of the force of infection term, - * we evaluate the survival functions of the TransitionDistributions InfectedNoSymptomsToInfectedSymptoms, - * InfectedNoSymptomsToRecovered, InfectedSymptomsToInfectedSevere and InfectedSymptomsToRecovered, weighted by - * the corresponding TransitionProbabilities, at the same time points. - * Here, we compute these contributions to the force of infection term, an store the vector - * m_transitiondistributions_in_forceofinfection so that we can access this vector for all following computations. + * Here we compute the weighted transition distributions for every compartment. Meaning for every compartment we weight + * the distributions of the outgoing transitions with their probability and compute the sum of the two weighed distributions. * * @param[in] dt Time step size. */ @@ -189,6 +185,9 @@ class CompParameters /** *@brief Setter for the vector m_B that contains the approximated value of B for all for all necessary time points. * + * The value m_B is needed for the compuation of the force of infection term and also for the compuation of + * m_infectivity. + * * @param[in] dt Time step size. */ void set_B(ScalarType dt) @@ -227,6 +226,8 @@ class CompParameters *@brief Setter for the vector m_meaninfectivity that contains the approximated value of the mean infectivity for all * for all necessary time points. * + * This values is needed the compute the reproduction numer and the force of infection term. + * * @param[in] dt Time step size. */ void set_infectivity(ScalarType dt) @@ -283,7 +284,10 @@ class CompParameters } } - //TODO Erklärung + /** + *@brief Setter for the vectors m_FoI_0 and m_NormFoI_0 that contain the approximated values of the function FoI_0, + * that is a part of the force of infection term for all necessary time points. + */ void set_FoI_0() { Eigen::Index calc_time_index = m_infectivity.size(); @@ -302,6 +306,13 @@ class CompParameters } } + /** + * @brief Setter for the vectors m_InitFoI and m_NormInitFoI that contain the approximated values of the functions + * f(standard model) and g(normalized model) that is a part of the force of infection term for all necessary time + * points. + * + * @param[in] dt Time step size. + */ void set_InitFoI(ScalarType dt) { Eigen::Index calc_time_index = std::max(m_infectivity.size(), m_B.size()); @@ -328,7 +339,7 @@ class CompParameters // ---- Parameters needed for the analysis of the model ---- /** - * @brief Setter for the Reproduction number R_c. + * @brief Setter for the Reproduction number m_reproductionnumber_c. * */ void set_reproductionnumber_c(ScalarType dt) @@ -346,12 +357,13 @@ class CompParameters } /** - * @brief TODO + * @brief Setter for m_T. * + * @param[in] dt step size. */ void set_T(ScalarType dt) { - // The transition SusceptibleToExposed is not needed in the computations. + // The value T_z1^z2 is not defined for the transition SusceptiblesToExposed. for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { Eigen::Index support_max_index = (Eigen::Index)std::ceil(m_transitiondistributions_support_max[transition] / dt); @@ -369,8 +381,12 @@ class CompParameters } /** - * @brief TODO + * @brief Setter for m_W. * + * m_W contains the values W_z for compartments z. As W_z is only defined for the compartments Exposed, InfectedNoSymptoms, + * InfectedSymptoms, InfectedSevere and InfectedCrititcal we will set W_z for the other compartments to zero. + * + * @param[in] dt step size. */ void set_W(ScalarType dt) { @@ -406,12 +422,18 @@ class CompParameters std::vector m_infectivity{ std::vector(1, 0.)}; ///< A vector containing the approximated mean infectivity for all time points. ScalarType m_reproductionnumber_c; ///< The control Reproduction number - std::vector m_FoI_0{std::vector(1, 0.)}; ///< TODO - std::vector m_NormFoI_0{std::vector(1, 0.)}; ///< TODO - std::vector m_InitFoI = std::vector(1, 0.); ///< TODO - std::vector m_NormInitFoI{std::vector(1, 0.)}; ///< TODO - std::vector m_T{std::vector((int)InfectionTransition::Count, 0.)}; ///< TODO - std::vector m_W{std::vector((int)InfectionState::Count, 0.)}; /// m_FoI_0{std::vector(1, 0.)}; ///< A vector containing the approcimated + // value of the function FoI_0 used for the computation of the force of infection in the standard model + std::vector m_NormFoI_0{std::vector(1, 0.)}; ///< A vector containing the approcimated + // value of the function FoI_0 used for the computation of the force of infection in the normalized model + std::vector m_InitFoI = std::vector(1, 0.); ///< A vector containing the approcimated + // value of the function FoI_0 used for the computation of the force of infection in the standard model + std::vector m_NormInitFoI{std::vector(1, 0.)}; ///< A vector containing the approcimated + // value of the function FoI_0 used for the computation of the force of infection in the normalized model + std::vector m_T{std::vector((int)InfectionTransition::Count, 0.)}; ///< A vector + // containing the approximated value for T_z1^z2 for every Flow z1 to z2. + std::vector m_W{std::vector((int)InfectionState::Count, 0.)}; ///< A vector containing+ + // the approximated value for W_z for every compartment z. // ---- Friend classes/functions. ---- friend class Model; friend class NormModel; diff --git a/cpp/models/ide_endemic_secir/simulation.h b/cpp/models/ide_endemic_secir/simulation.h index d23373778d..63acf76a1c 100644 --- a/cpp/models/ide_endemic_secir/simulation.h +++ b/cpp/models/ide_endemic_secir/simulation.h @@ -32,21 +32,25 @@ class Simulation void advance(ScalarType tmax); /** - * @brief Get the result of the simulation for the compartments + * @brief Get the result of the simulation for the compartments of m_model * Return the number of persons in all #InfectionState%s */ TimeSeries get_compartments() { return m_model->populations; } - + /** + * @brief Get the result of the simulation for the compartments of m_model, where we use the update scheme. + * Return the number of persons in all #InfectionState%s + */ TimeSeries get_compartments_update() { return m_model->populations_update; } /** - * @brief Get the result of the simulation for the normalized compartments, where we use m_model. + * @brief Get the result of the simulation for the normalized compartments, where we use m_model and the compartments + * computed using the sum scheme. * Return the number of persons in all #InfectionState%s */ TimeSeries get_normalizedcompartments() @@ -71,6 +75,10 @@ class Simulation return m_model->populations; } + /** + * @brief Get the result of the simulation for the compartments of m_model, where we use the update scheme. + * Return the number of persons in all #InfectionState%s + */ TimeSeries& get_compartments_update() const { return m_model->populations_update; @@ -95,61 +103,87 @@ class Simulation } /** - * @brief Get the transitions between the different #InfectionState%s. + * @brief Get the transitions between the different #InfectionState%s for m_model. */ TimeSeries const& get_transitions() { return m_model->transitions; } - + /** + * @brief Get the transitions between the different #InfectionState%s for m_model using the update scheme. + */ TimeSeries const& get_transitions_update() { return m_model->transitions_update; } /** - * @brief Get the transitions between the different #InfectionState%s of the normalized Model. + * @brief Get the transitions between the different #InfectionState%s of m_normmodel. */ TimeSeries const& get_normmodel_transitions() { return m_normmodel->transitions; } + /** + * @brief Get the force of infection term of m_model. + */ TimeSeries const& get_forceofinfections() { return m_model->m_forceofinfection; } + /** + * @brief Get the force of infection term of m_model using the update scheme. + */ TimeSeries const& get_forceofinfections_update() { return m_model->m_forceofinfectionupdate; } + /** + * @brief Get the force of infection term of m_normmodel. + */ TimeSeries const& get_normmodel_forceofinfections() { return m_normmodel->m_forceofinfection; } + /** + * @brief Get the total population of m_model. + */ TimeSeries const& get_totalpopulations() { return m_model->m_totalpopulation; } + /** + * @brief Get the total population of m_model using the update scheme. + */ TimeSeries const& get_totalpopulations_update() { return m_model->m_totalpopulationupdate; } + /** + * @brief Get the reproduction numer. + */ ScalarType const& get_reproductionnumber_c() { return m_model->compparameters->m_reproductionnumber_c; } + /** + * @brief Get T. + */ std::vector const& get_T() { return m_model->compparameters->m_T; } + /** + * @brief Get W. + */ std::vector const& get_W() { return m_model->compparameters->m_W; From 6679d08447d9eaea2971f9ebc9c018dd429a0b87 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Mon, 25 Aug 2025 13:18:05 +0200 Subject: [PATCH 13/22] fixed some mistakes --- cpp/examples/ide_endemic_secir.cpp | 24 ++-- .../ide_endemic_secir/computed_parameters.h | 88 +++++++++------ cpp/models/ide_endemic_secir/model.cpp | 106 +++++++++--------- cpp/models/ide_endemic_secir/model.h | 9 +- .../ide_endemic_secir/normalized_model.cpp | 91 ++++++++------- .../ide_endemic_secir/normalized_model.h | 8 +- cpp/models/ide_endemic_secir/simulation.cpp | 6 +- 7 files changed, 188 insertions(+), 144 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index c5e0936211..134b204752 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -19,7 +19,7 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 10; + ScalarType tmax = 20; ScalarType dt = 1.0; int num_states = static_cast(mio::endisecir::InfectionState::Count); @@ -97,14 +97,14 @@ int main() computed_parameters.parameters.get() = vec_delaydistribution; std::vector vec_prob((int)mio::endisecir::InfectionTransition::Count, 1.); - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] = 0.5; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered)] = 1 - 0.5; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] = 0.8; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered)] = 1 - 0.8; vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere)] = 0.1; vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered)] = 1 - 0.1; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical)] = 0.3; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToRecovered)] = 1 - 0.3; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToDead)] = 0.2; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToRecovered)] = 1 - 0.2; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical)] = 0.2; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToRecovered)] = 1 - 0.2; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToDead)] = 0.4; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToRecovered)] = 1 - 0.4; computed_parameters.parameters.set(vec_prob); @@ -123,8 +123,8 @@ int main() computed_parameters.parameters.get() = exponential_prob; computed_parameters.parameters.get() = exponential_prob; - computed_parameters.parameters.set(4e-3); - computed_parameters.parameters.set(3e-3); + computed_parameters.parameters.set(4e-5); + computed_parameters.parameters.set(2e-5); //computed_parameters.set_tol_for_support_max(1e-6); @@ -148,11 +148,11 @@ int main() interpolated_normresults.print_table({"s", "e", "c", "i", "h", "u", "r"}, 16, 8); // Uncomment to print the normalized compartments of model. - sim.get_normalizedcompartments().print_table({"S/N", "E/N", "C/N", "I/N", "H/N", "U/N", "R/N"}, 16, 8); + // sim.get_normalizedcompartments().print_table({"S/N", "E/N", "C/N", "I/N", "H/N", "U/N", "R/N"}, 16, 8); // Uncomment to print the transitions of model. - // sim.get_transitions().print_table( - // {"S->E", "E->C", "C->I", "C->R", "I->H", "I->R", "H->U", "H->R", "U->D", "U->R"}, 16, 8); + sim.get_transitions().print_table({"S->E", "E->C", "C->I", "C->R", "I->H", "I->R", "H->U", "H->R", "U->D", "U->R"}, + 16, 8); // sim.get_transitions_update().print_table( // {"US->UE", "UE->UC", "UC->UI", "UC->UR", "UI->UH", "UI->UR", "UH->UU", "UH->UR", "UU->UD", "UU->UR"}, // 16, 8); diff --git a/cpp/models/ide_endemic_secir/computed_parameters.h b/cpp/models/ide_endemic_secir/computed_parameters.h index 310577fdf1..8b1fcfab98 100644 --- a/cpp/models/ide_endemic_secir/computed_parameters.h +++ b/cpp/models/ide_endemic_secir/computed_parameters.h @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace mio @@ -218,7 +219,10 @@ class CompParameters m_transitiondistributions_derivative[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] [time_point_index - i]; } - m_B[time_point_index] = dt * sum; + m_B[time_point_index] = + parameters + .get()[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] * + dt * sum; } } @@ -258,29 +262,25 @@ class CompParameters (int)m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms]); //compute a_1: - if (time_point_index <= calc_time_index_1) { - for (int i = starting_point; i < time_point_index; i++) { + for (int i = starting_point; i < std::min(calc_time_index_1, time_point_index); i++) { - ScalarType state_age_i = static_cast(i) * dt; - a_1 += parameters.get().eval(state_age_i) * - m_transitiondistributions[static_cast(InfectionState::InfectedNoSymptoms)][i] * - m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] - [time_point_index - i]; - } + ScalarType state_age_i = static_cast(i) * dt; + a_1 += parameters.get().eval(state_age_i) * + m_transitiondistributions[static_cast(InfectionState::InfectedNoSymptoms)][i] * + m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] + [time_point_index - i]; } //compute a_2: - if (time_point_index <= calc_time_index_2) { - for (int i = starting_point; i < time_point_index; i++) { + for (int i = starting_point; i < std::min(calc_time_index_1, time_point_index); i++) { - a_2 += m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] - [time_point_index - i] * - m_B[i]; - } + a_2 += m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] + [time_point_index - i] * + m_B[i]; } m_infectivity[time_point_index] = - dt * std::exp(-parameters.get() * time_point_age) * (a_2 - a_1); + dt * std::exp(-parameters.get() * time_point_age) * (a_2 - a_1); } } @@ -288,21 +288,36 @@ class CompParameters *@brief Setter for the vectors m_FoI_0 and m_NormFoI_0 that contain the approximated values of the function FoI_0, * that is a part of the force of infection term for all necessary time points. */ - void set_FoI_0() + void set_FoI_0(ScalarType dt) { Eigen::Index calc_time_index = m_infectivity.size(); m_FoI_0 = std::vector(calc_time_index, 0.); m_NormFoI_0 = std::vector(calc_time_index, 0.); - // m_InitFoI.resize(calc_time_index, 0.); - // m_NormInitFoI.resize(calc_time_index, 0.); for (Eigen::Index time_point_index = 0; time_point_index < calc_time_index; time_point_index++) { + ScalarType time_point_age = (ScalarType)time_point_index * dt; m_FoI_0[time_point_index] = - m_infectivity[time_point_index] * (m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] + - m_statesinit[0][(int)InfectionState::InfectedNoSymptoms]); + (parameters.get().eval(time_point_age) * + parameters.get().get_cont_freq_mat().get_matrix_at(time_point_age)(0, 0)) * + (m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] * + m_transitiondistributions[(int)InfectionState::InfectedNoSymptoms][time_point_index] * + std::exp(-parameters.get() * time_point_age) * + parameters.get().eval(time_point_age) + + m_statesinit[0][(int)InfectionState::InfectedSymptoms] * + m_transitiondistributions[(int)InfectionState::InfectedSymptoms][time_point_index] * + std::exp(-parameters.get() * time_point_age) * + parameters.get().eval(time_point_age)); m_NormFoI_0[time_point_index] = - m_infectivity[time_point_index] * ((m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] + - m_statesinit[0][(int)InfectionState::InfectedNoSymptoms]) / - m_totalpopulationinit); + (parameters.get().eval(time_point_age) * + parameters.get().get_cont_freq_mat().get_matrix_at(time_point_age)(0, 0)) * + ((m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] * + m_transitiondistributions[(int)InfectionState::InfectedNoSymptoms][time_point_index] * + std::exp(-parameters.get() * time_point_age) * + parameters.get().eval(time_point_age) + + m_statesinit[0][(int)InfectionState::InfectedSymptoms] * + m_transitiondistributions[(int)InfectionState::InfectedSymptoms][time_point_index] * + std::exp(-parameters.get() * time_point_age) * + parameters.get().eval(time_point_age)) / + m_totalpopulationinit); } } @@ -319,21 +334,26 @@ class CompParameters m_InitFoI.resize(calc_time_index, 0.); m_NormInitFoI.resize(calc_time_index, 0.); for (Eigen::Index time_point_index = 0; time_point_index < calc_time_index; time_point_index++) { + ScalarType sum = 0; + ScalarType sum_norm = 0; ScalarType time_point_age = (ScalarType)time_point_index * dt; if (time_point_index <= (int)m_B.size()) { - m_InitFoI[time_point_index] -= m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] * - std::exp(-parameters.get() * time_point_age) * - m_B[time_point_index]; - m_NormInitFoI[time_point_index] -= - m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] / m_totalpopulationinit * - std::exp(-parameters.get() * time_point_age) * m_B[time_point_index]; + sum -= m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] * + std::exp(-parameters.get() * time_point_age) * m_B[time_point_index]; + sum_norm -= m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] / m_totalpopulationinit * + std::exp(-parameters.get() * time_point_age) * m_B[time_point_index]; } if (time_point_index <= (int)m_infectivity.size()) { - m_InitFoI[time_point_index] += - m_statesinit[0][(int)InfectionState::Exposed] * m_infectivity[time_point_index]; - m_NormInitFoI[time_point_index] += m_statesinit[0][(int)InfectionState::Exposed] / - m_totalpopulationinit * m_infectivity[time_point_index]; + sum += m_statesinit[0][(int)InfectionState::Exposed] * m_infectivity[time_point_index]; + sum_norm += m_statesinit[0][(int)InfectionState::Exposed] / m_totalpopulationinit * + m_infectivity[time_point_index]; } + m_InitFoI[time_point_index] = + parameters.get().eval(time_point_age) * + parameters.get().get_cont_freq_mat().get_matrix_at(time_point_age)(0, 0) * sum; + m_NormInitFoI[time_point_index] = + parameters.get().eval(time_point_age) * + parameters.get().get_cont_freq_mat().get_matrix_at(time_point_age)(0, 0) * sum_norm; } } diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index 46f74f3a50..7289541092 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -19,8 +20,7 @@ namespace mio namespace endisecir { Model::Model(CompParameters const& compparams) - : parameters{Parameters()} - , compparameters{std::make_shared(compparams)} + : compparameters{std::make_shared(compparams)} , transitions{TimeSeries(Eigen::Index(InfectionTransition::Count))} , transitions_update{TimeSeries(Eigen::Index(InfectionTransition::Count))} , populations{compparameters->m_statesinit} @@ -67,24 +67,30 @@ bool Model::check_constraints() const return true; } } - return parameters.check_constraints(); + return compparameters->check_constraints(); +} +// ----Functionality for Initialization. ---- +void Model::initialization_compute_forceofinfection() +{ + m_forceofinfection[0][0] = compparameters->m_FoI_0[0] / m_totalpopulation[0][0]; + m_forceofinfectionupdate[0][0] = compparameters->m_FoI_0[0] / m_totalpopulationupdate[0][0]; } - // ----Functionality for the iterations of a simulation. ---- void Model::compute_susceptibles(ScalarType dt) { Eigen::Index num_time_points = populations.get_num_time_points(); populations.get_last_value()[static_cast(InfectionState::Susceptible)] = (populations[num_time_points - 2][static_cast(InfectionState::Susceptible)] + - dt * (m_totalpopulation[num_time_points - 2][0] * parameters.get())) / - (1 + dt * (m_forceofinfection[num_time_points - 2][0] + parameters.get())); + dt * m_totalpopulation[num_time_points - 2][0] * compparameters->parameters.get()) / + (1 + dt * (m_forceofinfection[num_time_points - 2][0] + compparameters->parameters.get())); //Computation of susceptibles using the update formula for the other compartments. //Formula for Susceptibles stays the same, but we use m_totalpopulationupdate and m_forceofinfectionupdate populations_update.get_last_value()[static_cast(InfectionState::Susceptible)] = (populations_update[num_time_points - 2][static_cast(InfectionState::Susceptible)] + - dt * (m_totalpopulationupdate[num_time_points - 2][0] * parameters.get())) / - (1 + dt * (m_forceofinfectionupdate[num_time_points - 2][0] + parameters.get())); + dt * (m_totalpopulationupdate[num_time_points - 2][0] * compparameters->parameters.get())) / + (1 + + dt * (m_forceofinfectionupdate[num_time_points - 2][0] + compparameters->parameters.get())); } void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, @@ -102,38 +108,38 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx for (Eigen::Index i = starting_point; i < current_time_index; i++) { ScalarType state_age_i = static_cast(i) * dt; sum1 += transitions[i + 1][idx_IncomingFlow] * - std::exp(-parameters.get() * (current_time_age - state_age_i)) * - parameters.get()[idx_InfectionTransitions] * + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)) * + compparameters->parameters.get()[idx_InfectionTransitions] * compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; //For the update formula version of the model: sum2 += transitions_update[i + 1][idx_IncomingFlow] * - std::exp(-parameters.get() * (current_time_age - state_age_i)) * - parameters.get()[idx_InfectionTransitions] * + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)) * + compparameters->parameters.get()[idx_InfectionTransitions] * compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; } if (current_time_index <= calc_time_index) { transitions.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions] * sum1 - - std::exp((-parameters.get()) * (current_time_age)) * + (-dt) * compparameters->parameters.get()[idx_InfectionTransitions] * sum1 - + std::exp((-compparameters->parameters.get()) * (current_time_age)) * populations[0][idx_CurrentCompartment] * - parameters.get()[idx_InfectionTransitions] * + compparameters->parameters.get()[idx_InfectionTransitions] * compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; //For the update formula version of the model: transitions_update.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions] * sum2 - - std::exp((-parameters.get()) * (current_time_age)) * + (-dt) * compparameters->parameters.get()[idx_InfectionTransitions] * sum2 - + std::exp((-compparameters->parameters.get()) * (current_time_age)) * populations_update[0][idx_CurrentCompartment] * - parameters.get()[idx_InfectionTransitions] * + compparameters->parameters.get()[idx_InfectionTransitions] * compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; } else { transitions.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions] * sum1; + (-dt) * compparameters->parameters.get()[idx_InfectionTransitions] * sum1; //For the update formula version of the model: transitions_update.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions] * sum2; + (-dt) * compparameters->parameters.get()[idx_InfectionTransitions] * sum2; } } @@ -218,10 +224,12 @@ void Model::update_compartment_with_sum(InfectionState infectionState, } if (NaturalDeathispossible && Transitionispossible) { sum += compparameters->m_transitiondistributions[(int)infectionState][current_time_index - i] * - sum_inflows * std::exp(-parameters.get() * (current_time_age - state_age_i)); + sum_inflows * + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)); } else if (NaturalDeathispossible && !Transitionispossible) { - sum += sum_inflows * std::exp(-parameters.get() * (current_time_age - state_age_i)); + sum += sum_inflows * + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)); } else { sum += sum_inflows; @@ -232,7 +240,7 @@ void Model::update_compartment_with_sum(InfectionState infectionState, populations.get_last_value()[(int)infectionState] = dt * sum + compparameters->m_transitiondistributions[(int)infectionState][current_time_index] * populations[0][(int)infectionState] * - std::exp(-parameters.get() * (current_time_age)); + std::exp(-compparameters->parameters.get() * (current_time_age)); } else { populations.get_last_value()[(int)infectionState] = dt * sum; @@ -240,8 +248,8 @@ void Model::update_compartment_with_sum(InfectionState infectionState, } else if (NaturalDeathispossible && !Transitionispossible) { populations.get_last_value()[(int)infectionState] = - dt * sum + - populations[0][(int)infectionState] * std::exp(-parameters.get() * (current_time_age)); + dt * sum + populations[0][(int)infectionState] * + std::exp(-compparameters->parameters.get() * (current_time_age)); } else { populations.get_last_value()[(int)infectionState] = @@ -265,7 +273,7 @@ void Model::update_compartment_from_flow(InfectionState infectionState, updated_compartment -= dt * transitions_update.get_last_value()[(int)outflow]; } if (NaturalDeathispossible) { - updated_compartment = updated_compartment / (1 + dt * parameters.get()); + updated_compartment = updated_compartment / (1 + dt * compparameters->parameters.get()); } populations_update.get_last_value()[(int)infectionState] = updated_compartment; } @@ -358,7 +366,7 @@ void Model::compute_forceofinfection(ScalarType dt) ScalarType current_time = populations.get_last_time(); // Determine the starting point of the for loop. - Eigen::Index starting_point = std::max(0, (int)num_time_points - 1 - (int)compparameters->m_FoI_0.size()); + Eigen::Index starting_point = std::max(0, (int)num_time_points - 1 - (int)compparameters->m_infectivity.size()); ScalarType sum = 0.; ScalarType sum_update = 0.; @@ -370,37 +378,31 @@ void Model::compute_forceofinfection(ScalarType dt) populations_update[i + 1][(int)InfectionState::Susceptible] * m_forceofinfectionupdate[i][0]; } - m_forceofinfection.get_last_value()[0] = - (dt * sum) * - (parameters.get().eval(current_time) * - parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)) / - m_totalpopulation[num_time_points - 1][0]; - - m_forceofinfectionupdate.get_last_value()[0] = - (dt * sum_update) * - (parameters.get().eval(current_time) * - parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)) / - m_totalpopulationupdate[num_time_points - 1][0]; + ScalarType Foi_0 = 0; + ScalarType Foi_0_update = 0; + ScalarType f = 0; + ScalarType f_update = 0; // Add inital functions for the force of infection in case they still have an influence. if (num_time_points <= (int)compparameters->m_FoI_0.size()) { - m_forceofinfection.get_last_value()[0] += - compparameters->m_FoI_0[num_time_points - 1] / m_totalpopulation[num_time_points - 1][0]; - m_forceofinfectionupdate.get_last_value()[0] += - compparameters->m_FoI_0[num_time_points - 1] / m_totalpopulationupdate[num_time_points - 1][0]; + Foi_0 = compparameters->m_FoI_0[num_time_points - 1] / m_totalpopulation[num_time_points - 1][0]; + Foi_0_update = compparameters->m_FoI_0[num_time_points - 1] / m_totalpopulationupdate[num_time_points - 1][0]; } if (num_time_points <= (int)compparameters->m_InitFoI.size()) { - m_forceofinfection.get_last_value()[0] += - compparameters->m_InitFoI[num_time_points - 1] * - parameters.get().eval(current_time) * - parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0) / - m_totalpopulation[num_time_points - 1][0]; - m_forceofinfectionupdate.get_last_value()[0] += - compparameters->m_InitFoI[num_time_points - 1] * - parameters.get().eval(current_time) * - parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0) / - m_totalpopulationupdate[num_time_points - 1][0]; + f = compparameters->m_InitFoI[num_time_points - 1] / m_totalpopulation[num_time_points - 1][0]; + f_update = compparameters->m_InitFoI[num_time_points - 1] / m_totalpopulationupdate[num_time_points - 1][0]; } + m_forceofinfection.get_last_value()[0] = + (dt * sum * compparameters->parameters.get().eval(current_time) * + compparameters->parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)) / + m_totalpopulation[num_time_points - 1][0] + + Foi_0 + f; + m_forceofinfectionupdate.get_last_value()[0] = + (dt * sum_update * + (compparameters->parameters.get().eval(current_time) * + compparameters->parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0))) / + m_totalpopulationupdate[num_time_points - 1][0] + + Foi_0_update + f_update; } }; // namespace endisecir diff --git a/cpp/models/ide_endemic_secir/model.h b/cpp/models/ide_endemic_secir/model.h index fc4d2ab73d..e8b83a58df 100644 --- a/cpp/models/ide_endemic_secir/model.h +++ b/cpp/models/ide_endemic_secir/model.h @@ -47,7 +47,6 @@ class Model */ // ---- Public parameters. ---- - ParameterSet parameters; ///< ParameterSet of Model Parameters. std::shared_ptr compparameters; TimeSeries transitions; ///< TimesSeries containing points of time and the corresponding number of individuals transitioning @@ -62,6 +61,14 @@ class Model // in defined #InfectionState%s. We compute them by an update formula. private: + // ----Functionality for Initialization. ---- + + /** + *@brief Comoutes the value of the force of infection term at startim time. + * + * */ + void initialization_compute_forceofinfection(); + // ---- Functionality for the iterations of a simulation. /** diff --git a/cpp/models/ide_endemic_secir/normalized_model.cpp b/cpp/models/ide_endemic_secir/normalized_model.cpp index dd5bc10c79..5cfc6061a2 100644 --- a/cpp/models/ide_endemic_secir/normalized_model.cpp +++ b/cpp/models/ide_endemic_secir/normalized_model.cpp @@ -1,4 +1,3 @@ -#include "ide_endemic_secir/model.h" #include "ide_endemic_secir/normalized_model.h" #include "ide_endemic_secir/computed_parameters.h" #include "ide_endemic_secir/parameters.h" @@ -21,8 +20,7 @@ namespace endisecir { NormModel::NormModel(CompParameters const& compparams) - : parameters{Parameters()} - , compparameters{std::make_shared(compparams)} + : compparameters{std::make_shared(compparams)} , transitions{TimeSeries(Eigen::Index(InfectionTransition::Count))} , populations{TimeSeries(Eigen::Index(InfectionState::Count) - 1)} { @@ -40,7 +38,7 @@ NormModel::NormModel(CompParameters const& compparams) transitions.add_time_point( 0, TimeSeries::Vector::Constant(static_cast(InfectionTransition::Count), 0.)); - m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); + m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, compparameters->m_NormFoI_0[0])); } bool NormModel::check_constraints() const @@ -57,7 +55,12 @@ bool NormModel::check_constraints() const return true; } } - return parameters.check_constraints(); + return compparameters->check_constraints(); +} +// ----Functionality for Initialization. ---- +void NormModel::initialization_compute_forceofinfection() +{ + m_forceofinfection[0][0] = compparameters->m_NormFoI_0[0]; } // ----Functionality for the iterations of a simulation. ---- @@ -66,8 +69,8 @@ void NormModel::compute_susceptibles(ScalarType dt) Eigen::Index num_time_points = populations.get_num_time_points(); populations.get_last_value()[static_cast(InfectionState::Susceptible)] = (populations[num_time_points - 2][static_cast(InfectionState::Susceptible)] + - dt * parameters.get()) / - (1 + dt * (m_forceofinfection[num_time_points - 2][0] + parameters.get()) - + dt * compparameters->parameters.get()) / + (1 + dt * (m_forceofinfection[num_time_points - 2][0] + compparameters->parameters.get()) - transitions[num_time_points - 2][(Eigen::Index)InfectionTransition::InfectedCriticalToDead]); } @@ -85,24 +88,24 @@ void NormModel::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index ScalarType state_age_i = static_cast(i) * dt; sum += (transitions[i + 1][idx_IncomingFlow] + - (parameters.get() + + (compparameters->parameters.get() + transitions[i][(Eigen::Index)InfectionTransition::InfectedCriticalToDead] - - parameters.get()) * + compparameters->parameters.get()) * populations[i][idx_CurrentCompartment]) * - std::exp(-parameters.get() * (current_time_age - state_age_i)) * + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)) * compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; } if (current_time_index <= calc_time_index) { transitions.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions] * sum - - std::exp((-parameters.get()) * (current_time_age)) * + (-dt) * compparameters->parameters.get()[idx_InfectionTransitions] * sum - + std::exp((-compparameters->parameters.get()) * (current_time_age)) * populations[0][idx_CurrentCompartment] * - parameters.get()[idx_InfectionTransitions] * + compparameters->parameters.get()[idx_InfectionTransitions] * compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; } else { transitions.get_value(current_time_index)[idx_InfectionTransitions] = - (-dt) * parameters.get()[idx_InfectionTransitions] * sum; + (-dt) * compparameters->parameters.get()[idx_InfectionTransitions] * sum; } } @@ -182,18 +185,18 @@ void NormModel::update_compartment_with_sum(InfectionState infectionState, } if (Transitionispossible) { sum += compparameters->m_transitiondistributions[(int)infectionState][current_time_index - i] * - (sum_inflows + (parameters.get() + + (sum_inflows + (compparameters->parameters.get() + transitions[i][(Eigen::Index)InfectionTransition::InfectedCriticalToDead] - - parameters.get()) * + compparameters->parameters.get()) * populations[i][(int)infectionState]) * - std::exp(-parameters.get() * (current_time_age - state_age_i)); + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)); } else { - sum += (sum_inflows + (parameters.get() + + sum += (sum_inflows + (compparameters->parameters.get() + transitions[i][(Eigen::Index)InfectionTransition::InfectedCriticalToDead] - - parameters.get()) * + compparameters->parameters.get()) * populations[i][(int)infectionState]) * - std::exp(-parameters.get() * (current_time_age - state_age_i)); + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)); } } if (Transitionispossible) { @@ -201,7 +204,7 @@ void NormModel::update_compartment_with_sum(InfectionState infectionState, populations.get_last_value()[(int)infectionState] = dt * sum + compparameters->m_transitiondistributions[(int)infectionState][current_time_index] * populations[0][(int)infectionState] * - std::exp(-parameters.get() * (current_time_age)); + std::exp(-compparameters->parameters.get() * (current_time_age)); } else { populations.get_last_value()[(int)infectionState] = dt * sum; @@ -209,8 +212,8 @@ void NormModel::update_compartment_with_sum(InfectionState infectionState, } else { populations.get_last_value()[(int)infectionState] = - dt * sum + - populations[0][(int)infectionState] * std::exp(-parameters.get() * (current_time_age)); + dt * sum + populations[0][(int)infectionState] * + std::exp(-compparameters->parameters.get() * (current_time_age)); } } @@ -259,9 +262,9 @@ void NormModel::compute_forceofinfection(ScalarType dt) for (Eigen::Index i = starting_point1; i < num_time_points - 1; i++) { sum1 += compparameters->m_infectivity[num_time_points - 1 - i] * (populations[i + 1][(int)InfectionState::Susceptible] * m_forceofinfection[i][0] + - (parameters.get() + + (compparameters->parameters.get() + transitions[i + 1][(int)InfectionTransition::InfectedCriticalToDead] - - parameters.get()) * + compparameters->parameters.get()) * populations[i + 1][(int)InfectionState::Exposed]); } @@ -272,11 +275,12 @@ void NormModel::compute_forceofinfection(ScalarType dt) // Compute the second sum in the force of infection term. for (Eigen::Index i = starting_point2; i < num_time_points - 1; i++) { ScalarType state_age = static_cast(i) * dt; - sum2 += - (parameters.get() + transitions[i + 1][(int)InfectionTransition::InfectedCriticalToDead] - - parameters.get()) * - std::exp(-parameters.get() * (current_time - state_age)) * - populations[i + 1][(int)InfectionState::InfectedNoSymptoms] * compparameters->m_B[num_time_points - 1 - i]; + sum2 -= (compparameters->parameters.get() + + transitions[i + 1][(int)InfectionTransition::InfectedCriticalToDead] - + compparameters->parameters.get()) * + std::exp(-compparameters->parameters.get() * (current_time - state_age)) * + populations[i + 1][(int)InfectionState::InfectedNoSymptoms] * + compparameters->m_B[num_time_points - 1 - i]; } // Determine the starting point of the for loop. @@ -289,11 +293,12 @@ void NormModel::compute_forceofinfection(ScalarType dt) for (Eigen::Index i = starting_point3; i < num_time_points - 1; i++) { ScalarType state_age = static_cast(i) * dt; sum3 += - (parameters.get() + transitions[i + 1][(int)InfectionTransition::InfectedCriticalToDead] - - parameters.get()) * - std::exp(-parameters.get() * (current_time - state_age)) * + (compparameters->parameters.get() + + transitions[i + 1][(int)InfectionTransition::InfectedCriticalToDead] - + compparameters->parameters.get()) * + std::exp(-compparameters->parameters.get() * (current_time - state_age)) * populations[i + 1][(int)InfectionState::InfectedNoSymptoms] * - parameters.get().eval(current_time - state_age) * + compparameters->parameters.get().eval(current_time - state_age) * compparameters->m_transitiondistributions[(int)InfectionState::InfectedNoSymptoms][num_time_points - 1 - i]; } @@ -307,18 +312,20 @@ void NormModel::compute_forceofinfection(ScalarType dt) for (Eigen::Index i = starting_point4; i < num_time_points - 1; i++) { ScalarType state_age = static_cast(i) * dt; sum4 += - (parameters.get() + transitions[i + 1][(int)InfectionTransition::InfectedCriticalToDead] - - parameters.get()) * - std::exp(-parameters.get() * (current_time - state_age)) * + (compparameters->parameters.get() + + transitions[i + 1][(int)InfectionTransition::InfectedCriticalToDead] - + compparameters->parameters.get()) * + std::exp(-compparameters->parameters.get() * (current_time - state_age)) * populations[i + 1][(int)InfectionState::InfectedSymptoms] * - parameters.get().eval(current_time - state_age) * + compparameters->parameters.get().eval(current_time - state_age) * compparameters->m_transitiondistributions[(int)InfectionState::InfectedSymptoms][num_time_points - 1 - i]; } ScalarType sum = sum1 + sum2 + sum3 + sum4; m_forceofinfection.get_last_value()[0] = - (dt * sum) * (parameters.get().eval(current_time) * - parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)); + dt * sum * + (compparameters->parameters.get().eval(current_time) * + compparameters->parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)); // Add inital functions for the force of infection in case they still have an influence. if (num_time_points <= (int)compparameters->m_NormFoI_0.size()) { @@ -327,8 +334,8 @@ void NormModel::compute_forceofinfection(ScalarType dt) if (num_time_points <= (int)compparameters->m_NormInitFoI.size()) { m_forceofinfection.get_last_value()[0] += compparameters->m_NormInitFoI[num_time_points - 1] * - parameters.get().eval(current_time) * - parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0); + compparameters->parameters.get().eval(current_time) * + compparameters->parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0); } } diff --git a/cpp/models/ide_endemic_secir/normalized_model.h b/cpp/models/ide_endemic_secir/normalized_model.h index ca2a117fdb..8d39a28c5b 100644 --- a/cpp/models/ide_endemic_secir/normalized_model.h +++ b/cpp/models/ide_endemic_secir/normalized_model.h @@ -41,7 +41,6 @@ class NormModel bool check_constraints() const; // ---- Public parameters. ---- - ParameterSet parameters; ///< ParameterSet of Model Parameters. std::shared_ptr compparameters; TimeSeries transitions; ///< TimesSeries containing points of time and the corresponding number of individuals transitioning @@ -50,6 +49,13 @@ class NormModel // in defined #InfectionState%s. private: + // ----Functionality for Initialization. ---- + + /** + *@brief Comoutes the value of the force of infection term at startim time. + * + * */ + void initialization_compute_forceofinfection(); // ---- Functionality for the iterations of a simulation. /** diff --git a/cpp/models/ide_endemic_secir/simulation.cpp b/cpp/models/ide_endemic_secir/simulation.cpp index 78f8c8e13e..ead9cb87cb 100644 --- a/cpp/models/ide_endemic_secir/simulation.cpp +++ b/cpp/models/ide_endemic_secir/simulation.cpp @@ -22,22 +22,24 @@ void Simulation::advance(ScalarType tmax) m_model->compparameters->set_transitiondistributions_derivative(m_dt); m_model->compparameters->set_B(m_dt); m_model->compparameters->set_infectivity(m_dt); - m_model->compparameters->set_FoI_0(); + m_model->compparameters->set_FoI_0(m_dt); m_model->compparameters->set_InitFoI(m_dt); m_model->compparameters->set_reproductionnumber_c(m_dt); m_model->compparameters->set_T(m_dt); m_model->compparameters->set_W(m_dt); + m_model->initialization_compute_forceofinfection(); m_normmodel->compparameters->set_transitiondistributions_support_max(m_dt); m_normmodel->compparameters->set_transitiondistributions(m_dt); m_normmodel->compparameters->set_transitiondistributions_derivative(m_dt); m_normmodel->compparameters->set_B(m_dt); m_normmodel->compparameters->set_infectivity(m_dt); - m_normmodel->compparameters->set_FoI_0(); + m_normmodel->compparameters->set_FoI_0(m_dt); m_normmodel->compparameters->set_InitFoI(m_dt); m_normmodel->compparameters->set_reproductionnumber_c(m_dt); m_normmodel->compparameters->set_T(m_dt); m_normmodel->compparameters->set_W(m_dt); + m_normmodel->initialization_compute_forceofinfection(); // For every time step: while (m_model->transitions.get_last_time() < tmax - m_dt / 2) { From 47371d01edfc96d9008a554b00fecb4e0aef610e Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Wed, 27 Aug 2025 09:39:41 +0200 Subject: [PATCH 14/22] fixed a small mistake --- cpp/models/ide_endemic_secir/model.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index 7289541092..e5760f67a7 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -109,12 +109,10 @@ void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx ScalarType state_age_i = static_cast(i) * dt; sum1 += transitions[i + 1][idx_IncomingFlow] * std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)) * - compparameters->parameters.get()[idx_InfectionTransitions] * compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; //For the update formula version of the model: sum2 += transitions_update[i + 1][idx_IncomingFlow] * std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)) * - compparameters->parameters.get()[idx_InfectionTransitions] * compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; } if (current_time_index <= calc_time_index) { @@ -252,9 +250,7 @@ void Model::update_compartment_with_sum(InfectionState infectionState, std::exp(-compparameters->parameters.get() * (current_time_age)); } else { - populations.get_last_value()[(int)infectionState] = - dt * sum + compparameters->m_transitiondistributions[(int)infectionState][current_time_index] * - populations[0][(int)infectionState]; + populations.get_last_value()[(int)infectionState] = dt * sum + populations[0][(int)infectionState]; } } void Model::update_compartment_from_flow(InfectionState infectionState, @@ -272,6 +268,7 @@ void Model::update_compartment_from_flow(InfectionState infectionState, for (const InfectionTransition& outflow : OutgoingFlows) { updated_compartment -= dt * transitions_update.get_last_value()[(int)outflow]; } + if (NaturalDeathispossible) { updated_compartment = updated_compartment / (1 + dt * compparameters->parameters.get()); } From 560c55e89b093d34199419021d4532246e28e306 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Wed, 27 Aug 2025 11:54:13 +0200 Subject: [PATCH 15/22] small changes --- cpp/examples/ide_endemic_secir.cpp | 119 +++--- .../ide_endemic_secir_save_results.cpp | 349 ++++++------------ .../ide_endemic_secir/computed_parameters.h | 2 +- 3 files changed, 178 insertions(+), 292 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index 134b204752..fd53a8d750 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -19,7 +19,7 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 20; + ScalarType tmax = 500; ScalarType dt = 1.0; int num_states = static_cast(mio::endisecir::InfectionState::Count); @@ -49,50 +49,50 @@ int main() // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - mio::SmootherCosine smoothcos(6.0); - mio::StateAgeFunctionWrapper delaydistribution(smoothcos); - std::vector vec_delaydistribution(num_transitions, delaydistribution); + // mio::SmootherCosine smoothcos(8.0); + // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + // std::vector vec_delaydistribution(num_transitions, delaydistribution); // Uncomment for Lognorm. - // mio::ConstantFunction initialfunc(0); - // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); - // std::vector vec_delaydistribution(num_transitions, delaydistributioninit); - // // ExposedToInfectedNoSymptoms - // mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.3, 0, 4.2); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms].set_state_age_function( - // survivalExposedToInfectedNoSymptoms); - // // InfectedNoSymptomsToInfectedSymptoms - // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.7, 0, 0.8); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] - // .set_state_age_function(survivalInfectedNoSymptomsToInfectedSymptoms); - // // InfectedNoSymptomsToRecovered - // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToRecovered(0.2, 0, 7.7); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered] - // .set_state_age_function(survivalInfectedNoSymptomsToRecovered); - // // InfectedSymptomsToInfectedSevere - // mio::LognormSurvivalFunction survivalInfectedSymptomsToInfectedSevere(0.7, 0, 5.3); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere] - // .set_state_age_function(survivalInfectedSymptomsToInfectedSevere); - // // InfectedSymptomsToRecovered - // mio::LognormSurvivalFunction survivalInfectedSymptomsToRecovered(0.2, 0, 7.8); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered].set_state_age_function( - // survivalInfectedSymptomsToRecovered); - // // InfectedSevereToInfectedCritical - // mio::LognormSurvivalFunction survivalInfectedSevereToInfectedCritical(1.0, 0, 0.9); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical] - // .set_state_age_function(survivalInfectedSevereToInfectedCritical); - // // InfectedSevereToRecovered - // mio::LognormSurvivalFunction survivalInfectedSevereToRecovered(0.3, 0, 17.1); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToRecovered].set_state_age_function( - // survivalInfectedSevereToRecovered); - // // InfectedCriticalToDead - // mio::LognormSurvivalFunction survivalInfectedCriticalToDead(0.4, 0, 9.8); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToDead].set_state_age_function( - // survivalInfectedCriticalToDead); - // // InfectedCriticalToRecovered - // mio::LognormSurvivalFunction survivalInfectedCriticalToRecovered(0.3, 0, 17.1); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToRecovered].set_state_age_function( - // survivalInfectedCriticalToRecovered); + mio::ConstantFunction initialfunc(0); + mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); + std::vector vec_delaydistribution(num_transitions, delaydistributioninit); + // ExposedToInfectedNoSymptoms + mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.3, 0, 4.2); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms].set_state_age_function( + survivalExposedToInfectedNoSymptoms); + // InfectedNoSymptomsToInfectedSymptoms + mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.7, 0, 0.8); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] + .set_state_age_function(survivalInfectedNoSymptomsToInfectedSymptoms); + // InfectedNoSymptomsToRecovered + mio::LognormSurvivalFunction survivalInfectedNoSymptomsToRecovered(0.2, 0, 7.7); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered] + .set_state_age_function(survivalInfectedNoSymptomsToRecovered); + // InfectedSymptomsToInfectedSevere + mio::LognormSurvivalFunction survivalInfectedSymptomsToInfectedSevere(0.7, 0, 5.3); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere] + .set_state_age_function(survivalInfectedSymptomsToInfectedSevere); + // InfectedSymptomsToRecovered + mio::LognormSurvivalFunction survivalInfectedSymptomsToRecovered(0.2, 0, 7.8); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered].set_state_age_function( + survivalInfectedSymptomsToRecovered); + // InfectedSevereToInfectedCritical + mio::LognormSurvivalFunction survivalInfectedSevereToInfectedCritical(1.0, 0, 0.9); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical] + .set_state_age_function(survivalInfectedSevereToInfectedCritical); + // InfectedSevereToRecovered + mio::LognormSurvivalFunction survivalInfectedSevereToRecovered(0.3, 0, 17.1); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToRecovered].set_state_age_function( + survivalInfectedSevereToRecovered); + // InfectedCriticalToDead + mio::LognormSurvivalFunction survivalInfectedCriticalToDead(0.4, 0, 9.8); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToDead].set_state_age_function( + survivalInfectedCriticalToDead); + // InfectedCriticalToRecovered + mio::LognormSurvivalFunction survivalInfectedCriticalToRecovered(0.3, 0, 17.1); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToRecovered].set_state_age_function( + survivalInfectedCriticalToRecovered); computed_parameters.parameters.get() = vec_delaydistribution; @@ -123,8 +123,8 @@ int main() computed_parameters.parameters.get() = exponential_prob; computed_parameters.parameters.get() = exponential_prob; - computed_parameters.parameters.set(4e-5); - computed_parameters.parameters.set(2e-5); + computed_parameters.parameters.set(4e-3); + computed_parameters.parameters.set(3e-3); //computed_parameters.set_tol_for_support_max(1e-6); @@ -137,39 +137,38 @@ int main() sim.advance(tmax); //Get the compartments of model and print them. - auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); - interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); + // auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); + // interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); // Uncomment to print the compartments computed with the update scheme. // auto interpolated_results_update = mio::interpolate_simulation_result(sim.get_compartments_update(), dt / 2.); // interpolated_results_update.print_table({"US", "UE", "UC", "UI", "UH", "UU", "UR", "UD"}, 16, 8); //Get the commpartments of normmodel and print them. - auto interpolated_normresults = mio::interpolate_simulation_result(sim.get_normmodel_compartments(), dt / 2.); - interpolated_normresults.print_table({"s", "e", "c", "i", "h", "u", "r"}, 16, 8); + // auto interpolated_normresults = mio::interpolate_simulation_result(sim.get_normmodel_compartments(), dt / 2.); + // interpolated_normresults.print_table({"s", "e", "c", "i", "h", "u", "r"}, 16, 8); // Uncomment to print the normalized compartments of model. // sim.get_normalizedcompartments().print_table({"S/N", "E/N", "C/N", "I/N", "H/N", "U/N", "R/N"}, 16, 8); // Uncomment to print the transitions of model. - sim.get_transitions().print_table({"S->E", "E->C", "C->I", "C->R", "I->H", "I->R", "H->U", "H->R", "U->D", "U->R"}, - 16, 8); + // sim.get_transitions().print_table({"S->E", "E->C", "C->I", "C->R", "I->H", "I->R", "H->U", "H->R", "U->D", "U->R"}, + // 16, 8); // sim.get_transitions_update().print_table( - // {"US->UE", "UE->UC", "UC->UI", "UC->UR", "UI->UH", "UI->UR", "UH->UU", "UH->UR", "UU->UD", "UU->UR"}, - // 16, 8); + // {"US->UE", "UE->UC", "UC->UI", "UC->UR", "UI->UH", "UI->UR", "UH->UU", "UH->UR", "UU->UD", "UU->UR"}, 16, 8); // Uncomment to print the transitions of normmodel. // sim.get_normmodel_transitions().print_table( // {"s->e", "e->c", "c->i", "c->r", "i->h", "i->r , "h->u", "h->r", "u->d", "u->r"}, 16, 8); // Uncomment to print the force of infection of model. - sim.get_forceofinfections().print_table({"FoI"}, 16, 8); + // sim.get_forceofinfections().print_table({"FoI"}, 16, 8); // sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); // Uncomment to print the force of infection of normmodel. sim.get_normmodel_forceofinfections().print_table({"norm FoI"}, 16, 8); // Uncomment to print the reproduction number - std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; + // std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; // Uncomment to print the the values T_z1^z2 // for (int i = 0; i < (int)sim.get_T().size(); i++) { @@ -181,15 +180,9 @@ int main() // std::cout << "W_" << i << " = " << sim.get_W()[i] << "\n"; // } - // Uncomment to print the transitions. - // sim.get_transitions().print_table( - // {"S->E 1", "E->C 1", "C->I 1", "C->R 1", "I->H 1", "I->R 1", "H->U 1", "H->R 1", "U->D 1", "U->R 1"}, 16, 8); - // sim.get_transitions_update().print_table( - // {"US->E 1", "UE->C 1", "UC->I 1", "UC->R 1", "UI->H 1", "UI->R 1", "UH->U 1", "uH->R 1", "UU->D 1", "UU->R 1"}, - // 16, 8); - // Uncomment to print the total population size. - //sim.get_totalpopulations().print_table({"N"}, 16, 9); + // sim.get_totalpopulations().print_table({"N"}, 16, 9); + // sim.get_totalpopulations_update().print_table({"UN"}, 16, 9); // Uncomment to print the force of infection. // sim.get_forceofinfections().print_table({"FoI"}, 16, 8); diff --git a/cpp/examples/ide_endemic_secir_save_results.cpp b/cpp/examples/ide_endemic_secir_save_results.cpp index 9058c2a9ae..a7d3605031 100644 --- a/cpp/examples/ide_endemic_secir_save_results.cpp +++ b/cpp/examples/ide_endemic_secir_save_results.cpp @@ -15,283 +15,176 @@ #include #include -std::map simulation_parameter = {{"dt", 1.}, - {"t0", 0.}, - {"Susceptibles", 100000.}, - {"Exposed", 0}, - {"InfectedNoSymptoms", 10.}, - {"InfectedSymptoms", 20.}, - {"InfectedSevere", 0.}, - {"InfectedCritical", 0.}, - {"Recovered", 0.}, - {"Dead", 0.}, - {"TransmissionProbabilityOnContact", 0.1}, - {"RelativeTransmissionNoSymptoms", 0.5}, - {"RiskOfInfectionFromSymptomatic", 0.5}, - {"InfectedSymptomsPerInfectedNoSymptoms", 0.5}, - {"SeverePerInfectedSymptoms", 0.1}, - {"CriticalPerSevere", 0.3}, - {"DeathsPerCritical", 0.2}, - {"BirthRate1", 4e-3}, - {"DeathRate1", 3e-3}, - {"BirthRate2", 3e-4}, - {"DeathRate2", 3e-4}, - {"BirthRate3", 3e-4}, - {"DeathRate3", 4e-4}, - {"Contacts", 10.}}; - mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = "") { + using Vec = mio::TimeSeries::Vector; + + ScalarType dt = 1.0; + int num_states = static_cast(mio::endisecir::InfectionState::Count); int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); - //Set the inital values for the compartments. + // Create TimeSeries with num_states elements where states needed for simulation will be stored. mio::TimeSeries init(num_states); - mio::TimeSeries::Vector vec_init(num_states); - - vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = simulation_parameter["Susceptibles"]; - vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = simulation_parameter["Exposed"]; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = - simulation_parameter["InfectedNoSymptoms"]; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = - simulation_parameter["InfectedSymptoms"]; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedSevere)] = simulation_parameter["InfectedSevere"]; - vec_init[static_cast(mio::endisecir::InfectionState::InfectedCritical)] = - simulation_parameter["InfectedCritical"]; - vec_init[static_cast(mio::endisecir::InfectionState::Recovered)] = simulation_parameter["Recovered"]; - vec_init[static_cast(mio::endisecir::InfectionState::Dead)] = simulation_parameter["Dead"]; + + Vec vec_init(num_states); + + vec_init[static_cast(mio::endisecir::InfectionState::Susceptible)] = 100000.; + vec_init[static_cast(mio::endisecir::InfectionState::Exposed)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedNoSymptoms)] = 10.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSymptoms)] = 20.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedSevere)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::InfectedCritical)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::Recovered)] = 0.; + vec_init[static_cast(mio::endisecir::InfectionState::Dead)] = 0.; init.add_time_point(0, vec_init); - // We are going to simulate thre times with three different Birth and Death Rates, - // but all other parameters stay the same. + mio::endisecir::CompParameters computed_parameters(std::move(init)); - // Model 1, with BirthRate > DeathRate: - mio::TimeSeries init_copy1(init); - mio::endisecir::Model model_endide1(std::move(init_copy1)); + //Set working parameters - // Set distributions. - // Set TransitionDistributions. + // mio::ExponentialSurvivalFunction exp(3.0); + // mio::StateAgeFunctionWrapper delaydistribution(exp); + // std::vector vec_delaydistribution(num_transitions, delaydistribution); - mio::SmootherCosine smoothcos(8.0); - mio::StateAgeFunctionWrapper delaydistribution(smoothcos); - std::vector vec_delaydistribution(num_transitions, delaydistribution); + // mio::SmootherCosine smoothcos(8.0); + // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + // std::vector vec_delaydistribution(num_transitions, delaydistribution); // Uncomment for Lognorm. - // mio::ConstantFunction initialfunc(0); - // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); - // std::vector vec_delaydistribution((int)mio::endisecir::InfectionTransition::Count, - // delaydistributioninit); - // // ExposedToInfectedNoSymptoms - // mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.3, 0, 4.2); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms].set_state_age_function( - // survivalExposedToInfectedNoSymptoms); - // // InfectedNoSymptomsToInfectedSymptoms - // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.7, 0, 0.8); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] - // .set_state_age_function(survivalInfectedNoSymptomsToInfectedSymptoms); - // // InfectedNoSymptomsToRecovered - // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToRecovered(0.2, 0, 7.7); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered] - // .set_state_age_function(survivalInfectedNoSymptomsToRecovered); - // // InfectedSymptomsToInfectedSevere - // mio::LognormSurvivalFunction survivalInfectedSymptomsToInfectedSevere(0.7, 0, 5.3); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere] - // .set_state_age_function(survivalInfectedSymptomsToInfectedSevere); - // // InfectedSymptomsToRecovered - // mio::LognormSurvivalFunction survivalInfectedSymptomsToRecovered(0.2, 0, 7.8); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered].set_state_age_function( - // survivalInfectedSymptomsToRecovered); - // // InfectedSevereToInfectedCritical - // mio::LognormSurvivalFunction survivalInfectedSevereToInfectedCritical(1.0, 0, 0.9); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical] - // .set_state_age_function(survivalInfectedSevereToInfectedCritical); - // // InfectedSevereToRecovered - // mio::LognormSurvivalFunction survivalInfectedSevereToRecovered(0.3, 0, 17.1); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToRecovered].set_state_age_function( - // survivalInfectedSevereToRecovered); - // // InfectedCriticalToDead - // mio::LognormSurvivalFunction survivalInfectedCriticalToDead(0.4, 0, 9.8); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToDead].set_state_age_function( - // survivalInfectedCriticalToDead); - // // InfectedCriticalToRecovered - // mio::LognormSurvivalFunction survivalInfectedCriticalToRecovered(0.3, 0, 17.1); - // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToRecovered].set_state_age_function( - // survivalInfectedCriticalToRecovered); - - model_endide1.parameters.set(vec_delaydistribution); - - // Set other parameters. + mio::ConstantFunction initialfunc(0); + mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); + std::vector vec_delaydistribution(num_transitions, delaydistributioninit); + // ExposedToInfectedNoSymptoms + mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.3, 0, 4.2); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms].set_state_age_function( + survivalExposedToInfectedNoSymptoms); + // InfectedNoSymptomsToInfectedSymptoms + mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.7, 0, 0.8); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] + .set_state_age_function(survivalInfectedNoSymptomsToInfectedSymptoms); + // InfectedNoSymptomsToRecovered + mio::LognormSurvivalFunction survivalInfectedNoSymptomsToRecovered(0.2, 0, 7.7); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered] + .set_state_age_function(survivalInfectedNoSymptomsToRecovered); + // InfectedSymptomsToInfectedSevere + mio::LognormSurvivalFunction survivalInfectedSymptomsToInfectedSevere(0.7, 0, 5.3); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere] + .set_state_age_function(survivalInfectedSymptomsToInfectedSevere); + // InfectedSymptomsToRecovered + mio::LognormSurvivalFunction survivalInfectedSymptomsToRecovered(0.2, 0, 7.8); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered].set_state_age_function( + survivalInfectedSymptomsToRecovered); + // InfectedSevereToInfectedCritical + mio::LognormSurvivalFunction survivalInfectedSevereToInfectedCritical(1.0, 0, 0.9); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical] + .set_state_age_function(survivalInfectedSevereToInfectedCritical); + // InfectedSevereToRecovered + mio::LognormSurvivalFunction survivalInfectedSevereToRecovered(0.3, 0, 17.1); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToRecovered].set_state_age_function( + survivalInfectedSevereToRecovered); + // InfectedCriticalToDead + mio::LognormSurvivalFunction survivalInfectedCriticalToDead(0.4, 0, 9.8); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToDead].set_state_age_function( + survivalInfectedCriticalToDead); + // InfectedCriticalToRecovered + mio::LognormSurvivalFunction survivalInfectedCriticalToRecovered(0.3, 0, 17.1); + vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToRecovered].set_state_age_function( + survivalInfectedCriticalToRecovered); + + computed_parameters.parameters.get() = vec_delaydistribution; + std::vector vec_prob((int)mio::endisecir::InfectionTransition::Count, 1.); - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] = - simulation_parameter["InfectedSymptomsPerInfectedNoSymptoms"]; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered)] = - 1 - simulation_parameter["InfectedSymptomsPerInfectedNoSymptoms"]; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere)] = - simulation_parameter["SeverePerInfectedSymptoms"]; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered)] = - 1 - simulation_parameter["SeverePerInfectedSymptoms"]; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical)] = - simulation_parameter["CriticalPerSevere"]; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToRecovered)] = - 1 - simulation_parameter["CriticalPerSevere"]; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToDead)] = - simulation_parameter["DeathsPerCritical"]; - vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToRecovered)] = - 1 - simulation_parameter["DeathsPerCritical"]; - - model_endide1.parameters.set(vec_prob); + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] = 0.8; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered)] = 1 - 0.8; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere)] = 0.1; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered)] = 1 - 0.1; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical)] = 0.2; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToRecovered)] = 1 - 0.2; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToDead)] = 0.4; + vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToRecovered)] = 1 - 0.4; + + computed_parameters.parameters.set(vec_prob); mio::ContactMatrixGroup contact_matrix = mio::ContactMatrixGroup(1, 1); - contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, simulation_parameter["Contacts"])); - model_endide1.parameters.get() = mio::UncertainContactMatrix(contact_matrix); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); + computed_parameters.parameters.get() = mio::UncertainContactMatrix(contact_matrix); - mio::ConstantFunction constant(simulation_parameter["TransmissionProbabilityOnContact"]); + mio::ConstantFunction constant(0.1); mio::StateAgeFunctionWrapper constant_prob(constant); - model_endide1.parameters.get() = constant_prob; + computed_parameters.parameters.get() = constant_prob; - mio::ExponentialSurvivalFunction exponential(simulation_parameter["RelativeTransmissionNoSymptoms"]); + mio::ExponentialSurvivalFunction exponential(0.5); mio::StateAgeFunctionWrapper exponential_prob(exponential); - model_endide1.parameters.set(exponential_prob); - exponential_prob.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); - model_endide1.parameters.set(exponential_prob); - - model_endide1.parameters.set(simulation_parameter["BirthRate1"]); - model_endide1.parameters.set(simulation_parameter["DeathRate1"]); - - model_endide1.set_tol_for_support_max(1e-6); - model_endide1.check_constraints(); - - // Model 2, with BirthRate = DeathRate: - mio::TimeSeries init_copy2(init); - mio::endisecir::Model model_endide2(std::move(init_copy2)); - - model_endide2.parameters.get() = vec_delaydistribution; - - // Set other parameters. - model_endide2.parameters.set(vec_prob); - - model_endide2.parameters.get() = mio::UncertainContactMatrix(contact_matrix); - - model_endide2.parameters.get() = constant_prob; + computed_parameters.parameters.get() = exponential_prob; + computed_parameters.parameters.get() = exponential_prob; - exponential_prob.set_distribution_parameter(simulation_parameter["RelativeTransmissionNoSymptoms"]); - model_endide2.parameters.set(exponential_prob); - exponential_prob.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); - model_endide2.parameters.set(exponential_prob); + computed_parameters.parameters.set(4e-3); + computed_parameters.parameters.set(3e-3); - model_endide2.parameters.set(simulation_parameter["BirthRate2"]); - model_endide2.parameters.set(simulation_parameter["DeathRate2"]); + //computed_parameters.set_tol_for_support_max(1e-6); - model_endide2.set_tol_for_support_max(1e-6); - model_endide2.check_constraints(); + mio::endisecir::Model model(computed_parameters); - // Model 3, with BirthRate < DeathRate: - mio::TimeSeries init_copy3(init); - mio::endisecir::Model model_endide3(std::move(init_copy3)); + mio::endisecir::NormModel normmodel(computed_parameters); - model_endide3.parameters.get() = vec_delaydistribution; - - // Set other parameters. - model_endide3.parameters.set(vec_prob); - - model_endide3.parameters.get() = mio::UncertainContactMatrix(contact_matrix); - - model_endide3.parameters.get() = constant_prob; - - exponential_prob.set_distribution_parameter(simulation_parameter["RelativeTransmissionNoSymptoms"]); - model_endide3.parameters.set(exponential_prob); - exponential_prob.set_distribution_parameter(simulation_parameter["RiskOfInfectionFromSymptomatic"]); - model_endide3.parameters.set(exponential_prob); - - model_endide3.parameters.set(simulation_parameter["BirthRate3"]); - model_endide3.parameters.set(simulation_parameter["DeathRate3"]); - - model_endide3.set_tol_for_support_max(1e-6); - model_endide3.check_constraints(); - - // Simulate. - mio::endisecir::Simulation sim1(model_endide1, simulation_parameter["dt"]); - sim1.advance(tmax); - // mio::endisecir::Simulation sim2(model_endide2, simulation_parameter["dt"]); - // sim2.advance(tmax); - // mio::endisecir::Simulation sim3(model_endide3, simulation_parameter["dt"]); - // sim3.advance(tmax); - sim1.get_forceofinfections().print_table({"FoI"}, 16, 8); + // start the simulation. + mio::endisecir::Simulation sim(computed_parameters, model, normmodel, dt); + sim.advance(tmax); if (!save_dir.empty()) { std::string tmax_string = std::to_string(tmax); - std::string dt_string = std::to_string(simulation_parameter["dt"]); + std::string dt_string = std::to_string(dt); std::string filename_ide = save_dir + "analysis_endide_" + tmax_string.substr(0, tmax_string.find(".")) + "_" + dt_string.substr(0, dt_string.find(".") + 5); - //Save total population for different birth and death rates. + //Save files of Model. + //Save total population. std::string filename_ide_totalpopulation1 = filename_ide + "_totalpopulation1.h5"; mio::IOResult save_result_status_tp1 = - mio::save_result({sim1.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation1); + mio::save_result({sim.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation1); - // std::string filename_ide_totalpopulation2 = filename_ide + "_totalpopulation2.h5"; - // mio::IOResult save_result_status_tp2 = - // mio::save_result({sim2.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation2); - - // std::string filename_ide_totalpopulation3 = filename_ide + "_totalpopulation3.h5"; - // mio::IOResult save_result_status_tp3 = - // mio::save_result({sim3.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation3); - - //Save compartments for different birth and death rates. + //Save compartments. std::string filename_ide_compartments1 = filename_ide + "_compartments1.h5"; mio::IOResult save_result_status_c1 = - mio::save_result({sim1.get_compartments()}, {0}, 1, filename_ide_compartments1); + mio::save_result({sim.get_compartments()}, {0}, 1, filename_ide_compartments1); - // std::string filename_ide_compartments2 = filename_ide + "_compartments2.h5"; - // mio::IOResult save_result_status_c2 = - // mio::save_result({sim2.get_compartments()}, {0}, 1, filename_ide_compartments2); + //Save normalized compartments. + std::string filename_ide_normcompartments = filename_ide + "_normcompartments1.h5"; + mio::IOResult save_result_status_nc = + mio::save_result({sim.get_normalizedcompartments()}, {0}, 1, filename_ide_normcompartments); - // std::string filename_ide_compartments3 = filename_ide + "_compartments3.h5"; - // mio::IOResult save_result_status_c3 = - // mio::save_result({sim3.get_compartments()}, {0}, 1, filename_ide_compartments3); + //Save the force of infection. + std::string filename_ide_forceofinfection = filename_ide + "_forceofinfection1.h5"; + mio::IOResult save_result_status_foi = + mio::save_result({sim.get_forceofinfections()}, {0}, 1, filename_ide_forceofinfection); - //Save normalized compartments for only one birth and death rate. - std::string filename_ide_normcompartments = filename_ide + "_normcompartments.h5"; - mio::IOResult save_result_status_nc = - mio::save_result({sim1.get_normalizedcompartments()}, {0}, 1, filename_ide_normcompartments); + //Save files of NormModel. + //Save compartments. + std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments1.h5"; + mio::IOResult save_result_status_nmc1 = + mio::save_result({sim.get_normmodel_compartments()}, {0}, 1, filename_ide_normmod_compartments); - //Save the equilibrium of the normalized compartments. - // std::string filename_ide_normcompartmentsequi = filename_ide + "_equinormcompartments.h5"; - // mio::IOResult save_result_status_nce = - // mio::save_result({sim1.get_equilibriumcompartments()}, {0}, 1, filename_ide_normcompartmentsequi); + //Save the force of infection. + std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection1.h5"; + mio::IOResult save_result_status_nmfoi = + mio::save_result({sim.get_normmodel_forceofinfections()}, {0}, 1, filename_ide_normmod_forceofinfection); - //Save the force of infection for only one birth and death rate. - std::string filename_ide_forceofinfection = filename_ide + "_forceofinfection.h5"; - mio::IOResult save_result_status_foi = - mio::save_result({sim1.get_forceofinfections()}, {0}, 1, filename_ide_forceofinfection); - - //Save the equilibrium of the force of infection. - // std::string filename_ide_forceofinfectionequi = filename_ide + "_equiforceofinfection.h5"; - // mio::IOResult save_result_status_foie = - // mio::save_result({sim1.get_equilibrium_forceofinfection()}, {0}, 1, filename_ide_forceofinfectionequi); - - // if (!save_result_status_tp1 || !save_result_status_tp2 || !save_result_status_tp3 || !save_result_status_c1 || - // !save_result_status_c2 || !save_result_status_c3 || !save_result_status_nc || !save_result_status_foi || - // !save_result_status_nce || !save_result_status_foie) { - // return mio::failure(mio::StatusCode::UnknownError, "Error while saving results."); - // } - if (!save_result_status_tp1 || !save_result_status_c1 || !save_result_status_nc || !save_result_status_foi) { + if (!save_result_status_tp1 || !save_result_status_c1 || !save_result_status_nc || !save_result_status_foi || + !save_result_status_nmc1 || !save_result_status_nmfoi) { return mio::failure(mio::StatusCode::UnknownError, "Error while saving results."); } } - // Print the reproduction numbers for different birth and death rates. - std::cout << "The reproduction number Rc for Birth rate > Death rate is " << sim1.get_reproductionnumber_c() + // Print the reproduction number. + std::cout << "The reproduction number Rc for Birth rate > Death rate is " << sim.get_reproductionnumber_c() << "\n"; - // std::cout << "The reproduction number Rc for Birth rate = Death rate is " << sim2.get_reproductionnumber_c() - // << "\n"; - // std::cout << "The reproduction number Rc for Birth rate < Death rate is " << sim3.get_reproductionnumber_c() - // << "\n"; - // Return results of the simulation. + sim.get_forceofinfections().print_table({"FoI"}, 16, 8); + return mio::success(); } @@ -300,7 +193,7 @@ int main() std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDE/simulation_results/"; // Define tmax. - ScalarType tmax = 100; + ScalarType tmax = 500; auto result_ide = simulate_endidemodel(tmax, result_dir); if (!result_ide) { diff --git a/cpp/models/ide_endemic_secir/computed_parameters.h b/cpp/models/ide_endemic_secir/computed_parameters.h index 8b1fcfab98..4ede4d886d 100644 --- a/cpp/models/ide_endemic_secir/computed_parameters.h +++ b/cpp/models/ide_endemic_secir/computed_parameters.h @@ -273,7 +273,7 @@ class CompParameters } //compute a_2: - for (int i = starting_point; i < std::min(calc_time_index_1, time_point_index); i++) { + for (int i = starting_point; i < std::min(calc_time_index_2, time_point_index); i++) { a_2 += m_transitiondistributions_derivative[(int)InfectionTransition::ExposedToInfectedNoSymptoms] [time_point_index - i] * From 4d48704efdeebbf76d29727b2ae159e397a292db Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:04:31 +0200 Subject: [PATCH 16/22] small changes --- .../ide_endemic_secir/computed_parameters.h | 58 ++++++++----------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/cpp/models/ide_endemic_secir/computed_parameters.h b/cpp/models/ide_endemic_secir/computed_parameters.h index 4ede4d886d..e0d0b9b12f 100644 --- a/cpp/models/ide_endemic_secir/computed_parameters.h +++ b/cpp/models/ide_endemic_secir/computed_parameters.h @@ -121,31 +121,21 @@ class CompParameters {(int)InfectionTransition::InfectedCriticalToDead, (int)InfectionTransition::InfectedCriticalToRecovered}}; for (int state = 2; state < (int)InfectionState::Count - 2; state++) { - Eigen::Index calc_time_index = - std::max( - m_transitiondistributions_support_max[(Eigen::Index)std::ceil(vector_transitions[state - 2][0])], - m_transitiondistributions_support_max[(Eigen::Index)std::ceil(vector_transitions[state - 2][1])]) / - dt; + Eigen::Index calc_time_index = std::ceil( + std::max(m_transitiondistributions_support_max[(Eigen::Index)vector_transitions[state - 2][0]], + m_transitiondistributions_support_max[(Eigen::Index)vector_transitions[state - 2][1]]) / + dt); - // Create vec_derivative that stores the value of the approximated derivative for all necessary time points. std::vector vec_contribution_to_foi_2(calc_time_index + 1, 0.); for (Eigen::Index i = 0; i <= calc_time_index; i++) { ///Compute the state_age. ScalarType state_age = (ScalarType)i * dt; - if (m_transitiondistributions_support_max[(Eigen::Index)std::ceil(vector_transitions[state - 2][0])] / - dt <= - calc_time_index) { - vec_contribution_to_foi_2[i] += - parameters.get()[vector_transitions[state - 2][0]] * - parameters.get()[vector_transitions[state - 2][0]].eval(state_age); - } - if (m_transitiondistributions_support_max[(Eigen::Index)std::ceil(vector_transitions[state - 2][1])] / - dt <= - calc_time_index) { - vec_contribution_to_foi_2[i] += - parameters.get()[vector_transitions[state - 2][1]] * + + vec_contribution_to_foi_2[i] += + parameters.get()[vector_transitions[state - 2][0]] * + parameters.get()[vector_transitions[state - 2][0]].eval(state_age) + + parameters.get()[vector_transitions[state - 2][1]] * parameters.get()[vector_transitions[state - 2][1]].eval(state_age); - } } m_transitiondistributions[state] = vec_contribution_to_foi_2; } @@ -202,13 +192,16 @@ class CompParameters m_B = std::vector(calc_time_index + 1, 0.); - for (Eigen::Index time_point_index = 1; time_point_index < calc_time_index; time_point_index++) { - - ScalarType sum = 0; + // We start the for loop for time_point_index = 1, as the next for loop where we compute the sum, goes up to + // time_point_index-1. Therefore, for time_point_index = 0, the for loop would start at 0 and go up to -1, which + // is not possible. The value m_B(0) is just set 0 zero. + for (Eigen::Index time_point_index = 1; time_point_index <= calc_time_index; time_point_index++) { - Eigen::Index starting_point = - std::max(0, (int)time_point_index - (int)m_transitiondistributions_support_max[( - int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms]); + ScalarType sum = 0; + Eigen::Index max_support_index = std::ceil( + m_transitiondistributions_support_max[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] / + dt); + Eigen::Index starting_point = std::max(0, (int)time_point_index - (int)max_support_index); for (int i = starting_point; i <= time_point_index - 1; i++) { ScalarType state_age_i = static_cast(i) * dt; @@ -256,10 +249,9 @@ class CompParameters ScalarType time_point_age = (ScalarType)time_point_index * dt; //We compute a_1 and a_2 at time_point. - Eigen::Index starting_point = std::max( - 0, - (int)time_point_index - - (int)m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms]); + Eigen::Index max_support_index = std::ceil( + m_transitiondistributions_support_max[(int)InfectionTransition::ExposedToInfectedNoSymptoms] / dt); + Eigen::Index starting_point = std::max(0, (int)time_point_index - (int)max_support_index); //compute a_1: @@ -290,7 +282,7 @@ class CompParameters */ void set_FoI_0(ScalarType dt) { - Eigen::Index calc_time_index = m_infectivity.size(); + Eigen::Index calc_time_index = m_transitiondistributions[(int)InfectionState::InfectedNoSymptoms].size(); m_FoI_0 = std::vector(calc_time_index, 0.); m_NormFoI_0 = std::vector(calc_time_index, 0.); for (Eigen::Index time_point_index = 0; time_point_index < calc_time_index; time_point_index++) { @@ -337,13 +329,13 @@ class CompParameters ScalarType sum = 0; ScalarType sum_norm = 0; ScalarType time_point_age = (ScalarType)time_point_index * dt; - if (time_point_index <= (int)m_B.size()) { + if (time_point_index < (int)m_B.size()) { sum -= m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] * std::exp(-parameters.get() * time_point_age) * m_B[time_point_index]; sum_norm -= m_statesinit[0][(int)InfectionState::InfectedNoSymptoms] / m_totalpopulationinit * std::exp(-parameters.get() * time_point_age) * m_B[time_point_index]; } - if (time_point_index <= (int)m_infectivity.size()) { + if (time_point_index < (int)m_infectivity.size()) { sum += m_statesinit[0][(int)InfectionState::Exposed] * m_infectivity[time_point_index]; sum_norm += m_statesinit[0][(int)InfectionState::Exposed] / m_totalpopulationinit * m_infectivity[time_point_index]; @@ -414,7 +406,7 @@ class CompParameters Eigen::Index calc_time_index = m_transitiondistributions[state].size(); ScalarType sum = 0; - for (Eigen::Index i = 0; i <= calc_time_index; i++) { + for (Eigen::Index i = 0; i < calc_time_index; i++) { // Compute state_age. ScalarType state_age = (ScalarType)i * dt; //Compute the apprximate derivative by a backwards difference scheme. From cfaa3ffb5353f1f23e363b7449d749fe8c028569 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Wed, 27 Aug 2025 14:59:27 +0200 Subject: [PATCH 17/22] small changes --- cpp/models/ide_endemic_secir/model.cpp | 14 ++++++-------- cpp/models/ide_endemic_secir/model.h | 8 -------- .../ide_endemic_secir/normalized_model.cpp | 11 +++-------- cpp/models/ide_endemic_secir/normalized_model.h | 9 +-------- cpp/models/ide_endemic_secir/simulation.cpp | 7 +++++++ cpp/models/ide_endemic_secir/simulation.h | 17 +++++++++++++++++ 6 files changed, 34 insertions(+), 32 deletions(-) diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index e5760f67a7..1bc559149f 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -41,8 +41,9 @@ Model::Model(CompParameters const& compparams) m_totalpopulation.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); m_totalpopulationupdate.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); - m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); - m_forceofinfectionupdate.add_time_point(0, TimeSeries::Vector::Constant(1, 0)); + m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, compparameters->m_FoI_0[0])); + m_forceofinfectionupdate.add_time_point( + 0, TimeSeries::Vector::Constant(1, compparameters->m_NormFoI_0[0])); //Set normalized_populations at start time t0. TimeSeries::Vector vec_normalizedpopulations = @@ -69,12 +70,7 @@ bool Model::check_constraints() const } return compparameters->check_constraints(); } -// ----Functionality for Initialization. ---- -void Model::initialization_compute_forceofinfection() -{ - m_forceofinfection[0][0] = compparameters->m_FoI_0[0] / m_totalpopulation[0][0]; - m_forceofinfectionupdate[0][0] = compparameters->m_FoI_0[0] / m_totalpopulationupdate[0][0]; -} + // ----Functionality for the iterations of a simulation. ---- void Model::compute_susceptibles(ScalarType dt) { @@ -229,6 +225,8 @@ void Model::update_compartment_with_sum(InfectionState infectionState, sum += sum_inflows * std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)); } + // The case !NaturalDeathispossible && Transitionispossible is not possible, as if NaturalDeath is not possible + // this means you are in the Death compartment and then Transition is also not possible. else { sum += sum_inflows; } diff --git a/cpp/models/ide_endemic_secir/model.h b/cpp/models/ide_endemic_secir/model.h index e8b83a58df..caeee6f4e6 100644 --- a/cpp/models/ide_endemic_secir/model.h +++ b/cpp/models/ide_endemic_secir/model.h @@ -61,14 +61,6 @@ class Model // in defined #InfectionState%s. We compute them by an update formula. private: - // ----Functionality for Initialization. ---- - - /** - *@brief Comoutes the value of the force of infection term at startim time. - * - * */ - void initialization_compute_forceofinfection(); - // ---- Functionality for the iterations of a simulation. /** diff --git a/cpp/models/ide_endemic_secir/normalized_model.cpp b/cpp/models/ide_endemic_secir/normalized_model.cpp index 5cfc6061a2..f570aff0c7 100644 --- a/cpp/models/ide_endemic_secir/normalized_model.cpp +++ b/cpp/models/ide_endemic_secir/normalized_model.cpp @@ -1,5 +1,6 @@ #include "ide_endemic_secir/normalized_model.h" #include "ide_endemic_secir/computed_parameters.h" +#include "ide_endemic_secir/model.h" #include "ide_endemic_secir/parameters.h" #include "ide_endemic_secir/infection_state.h" #include "memilio/config.h" @@ -11,6 +12,7 @@ #include #include #include +#include #include #include @@ -58,10 +60,6 @@ bool NormModel::check_constraints() const return compparameters->check_constraints(); } // ----Functionality for Initialization. ---- -void NormModel::initialization_compute_forceofinfection() -{ - m_forceofinfection[0][0] = compparameters->m_NormFoI_0[0]; -} // ----Functionality for the iterations of a simulation. ---- void NormModel::compute_susceptibles(ScalarType dt) @@ -332,10 +330,7 @@ void NormModel::compute_forceofinfection(ScalarType dt) m_forceofinfection.get_last_value()[0] += compparameters->m_NormFoI_0[num_time_points - 1]; } if (num_time_points <= (int)compparameters->m_NormInitFoI.size()) { - m_forceofinfection.get_last_value()[0] += - compparameters->m_NormInitFoI[num_time_points - 1] * - compparameters->parameters.get().eval(current_time) * - compparameters->parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0); + m_forceofinfection.get_last_value()[0] += compparameters->m_NormInitFoI[num_time_points - 1]; } } diff --git a/cpp/models/ide_endemic_secir/normalized_model.h b/cpp/models/ide_endemic_secir/normalized_model.h index 8d39a28c5b..a2809f12e2 100644 --- a/cpp/models/ide_endemic_secir/normalized_model.h +++ b/cpp/models/ide_endemic_secir/normalized_model.h @@ -4,6 +4,7 @@ #include "ide_endemic_secir/infection_state.h" #include "ide_endemic_secir/parameters.h" #include "ide_endemic_secir/computed_parameters.h" +#include "ide_endemic_secir/model.h" #include "memilio/config.h" #include "memilio/utils/time_series.h" @@ -49,13 +50,6 @@ class NormModel // in defined #InfectionState%s. private: - // ----Functionality for Initialization. ---- - - /** - *@brief Comoutes the value of the force of infection term at startim time. - * - * */ - void initialization_compute_forceofinfection(); // ---- Functionality for the iterations of a simulation. /** @@ -148,7 +142,6 @@ class NormModel TimeSeries m_forceofinfection{ TimeSeries(1)}; ///< TimeSeries containing the Force of infection term for every time point, - // needed for the numerical scheme. // ---- Friend classes/functions. ---- // In the Simulation class, the actual simulation is performed which is why it needs access to the here diff --git a/cpp/models/ide_endemic_secir/simulation.cpp b/cpp/models/ide_endemic_secir/simulation.cpp index ead9cb87cb..ac8800f68c 100644 --- a/cpp/models/ide_endemic_secir/simulation.cpp +++ b/cpp/models/ide_endemic_secir/simulation.cpp @@ -41,9 +41,13 @@ void Simulation::advance(ScalarType tmax) m_normmodel->compparameters->set_W(m_dt); m_normmodel->initialization_compute_forceofinfection(); + m_difference_normalizedcompartments.add_time_point(0); + compute_difference_normalizedcompartments(); + // For every time step: while (m_model->transitions.get_last_time() < tmax - m_dt / 2) { + m_difference_normalizedcompartments.add_time_point(m_difference_normalizedcompartments.get_last_time() + m_dt); //standard model: m_model->transitions.add_time_point(m_model->transitions.get_last_time() + m_dt); m_model->transitions_update.add_time_point(m_model->transitions_update.get_last_time() + m_dt); @@ -89,6 +93,9 @@ void Simulation::advance(ScalarType tmax) // Compute m_forceofinfection; m_normmodel->compute_forceofinfection(m_dt); + + //Compute the difference of the two normalized compartments. + compute_difference_normalizedcompartments(); } } diff --git a/cpp/models/ide_endemic_secir/simulation.h b/cpp/models/ide_endemic_secir/simulation.h index 63acf76a1c..342773fed8 100644 --- a/cpp/models/ide_endemic_secir/simulation.h +++ b/cpp/models/ide_endemic_secir/simulation.h @@ -229,11 +229,28 @@ class Simulation return m_dt; } + void compute_difference_normalizedcompartments() + { + for (int state = 0; state < (int)InfectionState::Count - 1; state++) { + m_difference_normalizedcompartments.get_last_value()[state] = std::abs( + m_normmodel->populations.get_last_value()[state] - m_model->populations.get_last_value()[state]); + } + } + + TimeSeries const& get_difference_normalizedcompartments() + { + return m_difference_normalizedcompartments; + } + private: std::unique_ptr m_compparams; ///< Unique pointer to the computed Parameters. std::unique_ptr m_model; ///< Unique pointer to the simulated Model. std::unique_ptr m_normmodel; ///< Unique pointer to the simulated normalized Model. ScalarType m_dt; ///< Time step used for numerical computations in simulation. + TimeSeries m_difference_normalizedcompartments{TimeSeries( + (int)InfectionState::Count - 1)}; ///< TimeSeries containing the difference of the compartments + // computed by NormModel and the normalized compartments comouted in Model. + // needed for the numerical scheme. }; TimeSeries simulate(ScalarType tmax, ScalarType dt, Model const& model); From 12082ebfe69711973660c194275193f2b6b3c428 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:48:57 +0200 Subject: [PATCH 18/22] Added the value m_V and the derivative of the total population --- cpp/examples/ide_endemic_secir.cpp | 31 ++--- .../ide_endemic_secir_save_results.cpp | 126 +++++++++++------- .../ide_endemic_secir/computed_parameters.h | 36 ++++- cpp/models/ide_endemic_secir/model.cpp | 8 ++ cpp/models/ide_endemic_secir/model.h | 4 +- cpp/models/ide_endemic_secir/simulation.cpp | 12 +- cpp/models/ide_endemic_secir/simulation.h | 38 +++++- 7 files changed, 177 insertions(+), 78 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index fd53a8d750..5438d1e9e3 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -19,7 +19,7 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 500; + ScalarType tmax = 1; ScalarType dt = 1.0; int num_states = static_cast(mio::endisecir::InfectionState::Count); @@ -49,7 +49,7 @@ int main() // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - // mio::SmootherCosine smoothcos(8.0); + // mio::SmootherCosine smoothcos(6.0); // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); // std::vector vec_delaydistribution(num_transitions, delaydistribution); @@ -165,26 +165,27 @@ int main() // sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); // Uncomment to print the force of infection of normmodel. - sim.get_normmodel_forceofinfections().print_table({"norm FoI"}, 16, 8); + // sim.get_normmodel_forceofinfections().print_table({"norm FoI"}, 16, 8); - // Uncomment to print the reproduction number - // std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; + //Uncomment to print the reproduction number + std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; // Uncomment to print the the values T_z1^z2 - // for (int i = 0; i < (int)sim.get_T().size(); i++) { - // std::cout << "T_" << i << " = " << sim.get_T()[i] << "\n"; - // } + for (int i = 0; i < (int)sim.get_T().size(); i++) { + std::cout << "T_" << i << " = " << sim.get_T()[i] << "\n"; + } + + // Uncomment to print the the values V^z + for (int i = 0; i < (int)sim.get_V().size(); i++) { + std::cout << "V_" << i << " = " << sim.get_V()[i] << "\n"; + } // Uncomment to print the values W_z - // for (int i = 0; i < (int)sim.get_W().size(); i++) { - // std::cout << "W_" << i << " = " << sim.get_W()[i] << "\n"; - // } + for (int i = 0; i < (int)sim.get_W().size(); i++) { + std::cout << "W_" << i << " = " << sim.get_W()[i] << "\n"; + } // Uncomment to print the total population size. // sim.get_totalpopulations().print_table({"N"}, 16, 9); // sim.get_totalpopulations_update().print_table({"UN"}, 16, 9); - - // Uncomment to print the force of infection. - // sim.get_forceofinfections().print_table({"FoI"}, 16, 8); - // sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); } \ No newline at end of file diff --git a/cpp/examples/ide_endemic_secir_save_results.cpp b/cpp/examples/ide_endemic_secir_save_results.cpp index a7d3605031..9178095443 100644 --- a/cpp/examples/ide_endemic_secir_save_results.cpp +++ b/cpp/examples/ide_endemic_secir_save_results.cpp @@ -48,50 +48,50 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - // mio::SmootherCosine smoothcos(8.0); - // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); - // std::vector vec_delaydistribution(num_transitions, delaydistribution); - - // Uncomment for Lognorm. - mio::ConstantFunction initialfunc(0); - mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); - std::vector vec_delaydistribution(num_transitions, delaydistributioninit); - // ExposedToInfectedNoSymptoms - mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.3, 0, 4.2); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms].set_state_age_function( - survivalExposedToInfectedNoSymptoms); - // InfectedNoSymptomsToInfectedSymptoms - mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.7, 0, 0.8); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] - .set_state_age_function(survivalInfectedNoSymptomsToInfectedSymptoms); - // InfectedNoSymptomsToRecovered - mio::LognormSurvivalFunction survivalInfectedNoSymptomsToRecovered(0.2, 0, 7.7); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered] - .set_state_age_function(survivalInfectedNoSymptomsToRecovered); - // InfectedSymptomsToInfectedSevere - mio::LognormSurvivalFunction survivalInfectedSymptomsToInfectedSevere(0.7, 0, 5.3); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere] - .set_state_age_function(survivalInfectedSymptomsToInfectedSevere); - // InfectedSymptomsToRecovered - mio::LognormSurvivalFunction survivalInfectedSymptomsToRecovered(0.2, 0, 7.8); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered].set_state_age_function( - survivalInfectedSymptomsToRecovered); - // InfectedSevereToInfectedCritical - mio::LognormSurvivalFunction survivalInfectedSevereToInfectedCritical(1.0, 0, 0.9); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical] - .set_state_age_function(survivalInfectedSevereToInfectedCritical); - // InfectedSevereToRecovered - mio::LognormSurvivalFunction survivalInfectedSevereToRecovered(0.3, 0, 17.1); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToRecovered].set_state_age_function( - survivalInfectedSevereToRecovered); - // InfectedCriticalToDead - mio::LognormSurvivalFunction survivalInfectedCriticalToDead(0.4, 0, 9.8); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToDead].set_state_age_function( - survivalInfectedCriticalToDead); - // InfectedCriticalToRecovered - mio::LognormSurvivalFunction survivalInfectedCriticalToRecovered(0.3, 0, 17.1); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToRecovered].set_state_age_function( - survivalInfectedCriticalToRecovered); + mio::SmootherCosine smoothcos(2.0); + mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + std::vector vec_delaydistribution(num_transitions, delaydistribution); + + //Uncomment for Lognorm. + // mio::ConstantFunction initialfunc(0); + // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); + // std::vector vec_delaydistribution(num_transitions, delaydistributioninit); + // // ExposedToInfectedNoSymptoms + // mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.3, 0, 4.2); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms].set_state_age_function( + // survivalExposedToInfectedNoSymptoms); + // // InfectedNoSymptomsToInfectedSymptoms + // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.7, 0, 0.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] + // .set_state_age_function(survivalInfectedNoSymptomsToInfectedSymptoms); + // // InfectedNoSymptomsToRecovered + // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToRecovered(0.2, 0, 7.7); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered] + // .set_state_age_function(survivalInfectedNoSymptomsToRecovered); + // // InfectedSymptomsToInfectedSevere + // mio::LognormSurvivalFunction survivalInfectedSymptomsToInfectedSevere(0.7, 0, 5.3); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere] + // .set_state_age_function(survivalInfectedSymptomsToInfectedSevere); + // // InfectedSymptomsToRecovered + // mio::LognormSurvivalFunction survivalInfectedSymptomsToRecovered(0.2, 0, 7.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered].set_state_age_function( + // survivalInfectedSymptomsToRecovered); + // // InfectedSevereToInfectedCritical + // mio::LognormSurvivalFunction survivalInfectedSevereToInfectedCritical(1.0, 0, 0.9); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical] + // .set_state_age_function(survivalInfectedSevereToInfectedCritical); + // // InfectedSevereToRecovered + // mio::LognormSurvivalFunction survivalInfectedSevereToRecovered(0.3, 0, 17.1); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToRecovered].set_state_age_function( + // survivalInfectedSevereToRecovered); + // // InfectedCriticalToDead + // mio::LognormSurvivalFunction survivalInfectedCriticalToDead(0.4, 0, 9.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToDead].set_state_age_function( + // survivalInfectedCriticalToDead); + // // InfectedCriticalToRecovered + // mio::LognormSurvivalFunction survivalInfectedCriticalToRecovered(0.3, 0, 17.1); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToRecovered].set_state_age_function( + // survivalInfectedCriticalToRecovered); computed_parameters.parameters.get() = vec_delaydistribution; @@ -105,6 +105,17 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToDead)] = 0.4; vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToRecovered)] = 1 - 0.4; + //Different values: + // std::vector vec_prob((int)mio::endisecir::InfectionTransition::Count, 1.); + // vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)] = 0.5; + // vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered)] = 1 - 0.5; + // vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere)] = 0.5; + // vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered)] = 1 - 0.5; + // vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical)] = 0.5; + // vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedSevereToRecovered)] = 1 - 0.5; + // vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToDead)] = 0.8; + // vec_prob[Eigen::Index(mio::endisecir::InfectionTransition::InfectedCriticalToRecovered)] = 1 - 0.8; + computed_parameters.parameters.set(vec_prob); mio::ContactMatrixGroup contact_matrix = mio::ContactMatrixGroup(1, 1); @@ -147,9 +158,13 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = std::string filename_ide_totalpopulation1 = filename_ide + "_totalpopulation1.h5"; mio::IOResult save_result_status_tp1 = mio::save_result({sim.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation1); + //Save derivative of total population. + std::string filename_ide_dertotalpopulation1 = filename_ide + "_dertotalpopulation1.h5"; + mio::IOResult save_result_status_dtp1 = + mio::save_result({sim.get_totalpopulations_derivative()}, {0}, 1, filename_ide_dertotalpopulation1); //Save compartments. - std::string filename_ide_compartments1 = filename_ide + "_compartments1.h5"; + std::string filename_ide_compartments1 = filename_ide + "_compartments.h5"; mio::IOResult save_result_status_c1 = mio::save_result({sim.get_compartments()}, {0}, 1, filename_ide_compartments1); @@ -165,17 +180,28 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = //Save files of NormModel. //Save compartments. - std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments1.h5"; + std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments.h5"; mio::IOResult save_result_status_nmc1 = mio::save_result({sim.get_normmodel_compartments()}, {0}, 1, filename_ide_normmod_compartments); //Save the force of infection. - std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection1.h5"; + std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection.h5"; mio::IOResult save_result_status_nmfoi = mio::save_result({sim.get_normmodel_forceofinfections()}, {0}, 1, filename_ide_normmod_forceofinfection); + //Safe difference between normalized compartments. + std::string filename_ide_difference_normcomp = filename_ide + "_difference_normcomp.h5"; + mio::IOResult save_result_status_dnm = + mio::save_result({sim.get_difference_normalizationcomp()}, {0}, 1, filename_ide_difference_normcomp); + + //Safe difference between Force of Infections. + std::string filename_ide_difference_normFoI = filename_ide + "_difference_normfoi.h5"; + mio::IOResult save_result_status_dnf = + mio::save_result({sim.get_difference_normalizationFoi()}, {0}, 1, filename_ide_difference_normFoI); + if (!save_result_status_tp1 || !save_result_status_c1 || !save_result_status_nc || !save_result_status_foi || - !save_result_status_nmc1 || !save_result_status_nmfoi) { + !save_result_status_nmc1 || !save_result_status_nmfoi || !save_result_status_dnm || + !save_result_status_dnf || !save_result_status_dtp1) { return mio::failure(mio::StatusCode::UnknownError, "Error while saving results."); } } @@ -183,8 +209,6 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = std::cout << "The reproduction number Rc for Birth rate > Death rate is " << sim.get_reproductionnumber_c() << "\n"; - sim.get_forceofinfections().print_table({"FoI"}, 16, 8); - return mio::success(); } @@ -193,7 +217,7 @@ int main() std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDE/simulation_results/"; // Define tmax. - ScalarType tmax = 500; + ScalarType tmax = 100; auto result_ide = simulate_endidemodel(tmax, result_dir); if (!result_ide) { diff --git a/cpp/models/ide_endemic_secir/computed_parameters.h b/cpp/models/ide_endemic_secir/computed_parameters.h index e0d0b9b12f..a2bc681ec0 100644 --- a/cpp/models/ide_endemic_secir/computed_parameters.h +++ b/cpp/models/ide_endemic_secir/computed_parameters.h @@ -392,6 +392,38 @@ class CompParameters } } + /** + * @brief Setter for m_V. + * + * @param[in] dt step size. + */ + void set_V() + { + // The value V^z is not defined for the compartments Susceptibles and Exposed + // InfectedNoSymptoms: + m_V[(int)InfectionState::InfectedNoSymptoms] = m_T[(int)InfectionTransition::ExposedToInfectedNoSymptoms]; + // InfectedSymptoms: + m_V[(int)InfectionState::InfectedSymptoms] = + m_T[(int)InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] * + m_V[(int)InfectionState::InfectedNoSymptoms]; + // InfectedSevere: + m_V[(int)InfectionState::InfectedSevere] = m_T[(int)InfectionTransition::InfectedSymptomsToInfectedSevere] * + m_V[(int)InfectionState::InfectedSymptoms]; + // InfectedCritical: + m_V[(int)InfectionState::InfectedCritical] = + m_T[(int)InfectionTransition::InfectedSevereToInfectedCritical] * m_V[(int)InfectionState::InfectedSevere]; + // Dead: + m_V[(int)InfectionState::Dead] = + m_T[(int)InfectionTransition::InfectedCriticalToDead] * m_V[(int)InfectionState::InfectedCritical]; + // Recovered: + m_V[(int)InfectionState::Recovered] = + m_T[(int)InfectionTransition::InfectedNoSymptomsToRecovered] * + m_V[(int)InfectionState::InfectedNoSymptoms] + + m_T[(int)InfectionTransition::InfectedSymptomsToRecovered] * m_V[(int)InfectionState::InfectedSymptoms] + + m_T[(int)InfectionTransition::InfectedSevereToRecovered] * m_V[(int)InfectionState::InfectedSevere] + + m_T[(int)InfectionTransition::InfectedCriticalToRecovered] * m_V[(int)InfectionState::InfectedCritical]; + } + /** * @brief Setter for m_W. * @@ -444,13 +476,15 @@ class CompParameters // value of the function FoI_0 used for the computation of the force of infection in the normalized model std::vector m_T{std::vector((int)InfectionTransition::Count, 0.)}; ///< A vector // containing the approximated value for T_z1^z2 for every Flow z1 to z2. + std::vector m_V{std::vector((int)InfectionTransition::Count, 0.)}; ///< A vector + // containing the approximated value for V^z for every compartment z. std::vector m_W{std::vector((int)InfectionState::Count, 0.)}; ///< A vector containing+ // the approximated value for W_z for every compartment z. // ---- Friend classes/functions. ---- friend class Model; friend class NormModel; friend class Simulation; -}; +}; // namespace endisecir } // namespace endisecir diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index 1bc559149f..5f17f72a0b 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -40,7 +40,9 @@ Model::Model(CompParameters const& compparams) std::accumulate(populations[0].begin(), populations[0].end(), 0) - populations[0][(int)InfectionState::Dead]; m_totalpopulation.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); m_totalpopulationupdate.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); + m_totalpopulation_derivative.add_time_point(0, TimeSeries::Vector::Constant(1, 0.)); + // Set the force of infection term at time t0. m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, compparameters->m_FoI_0[0])); m_forceofinfectionupdate.add_time_point( 0, TimeSeries::Vector::Constant(1, compparameters->m_NormFoI_0[0])); @@ -344,6 +346,12 @@ void Model::compute_populationsize() } m_totalpopulation.get_last_value()[0] = sum1; m_totalpopulationupdate.get_last_value()[0] = sum2; + // Here we comoute the derivative of the total population that is given by + // BirthRate * N(t) - DeathRate * N(t) - Transition[InfectedCritical>ToDeath](t). + m_totalpopulation_derivative.get_last_value()[0] = + (compparameters->parameters.get() - compparameters->parameters.get()) * + m_totalpopulation.get_last_value()[0] - + transitions.get_last_value()[(int)InfectionTransition::InfectedCriticalToDead]; } void Model::compute_normalizedcompartments() diff --git a/cpp/models/ide_endemic_secir/model.h b/cpp/models/ide_endemic_secir/model.h index caeee6f4e6..82e4e61043 100644 --- a/cpp/models/ide_endemic_secir/model.h +++ b/cpp/models/ide_endemic_secir/model.h @@ -192,7 +192,9 @@ class Model TimeSeries m_totalpopulationupdate{TimeSeries( 1)}; ///< TimeSeries containing the total population size of the considered region for each time point. //In this case we use the compartments from populations_update. - + TimeSeries m_totalpopulation_derivative{TimeSeries( + 1)}; ///< TimeSeries containing the derivative of the total population size of the considered + // region for each time point. TimeSeries m_normalizedpopulations{ TimeSeries(Eigen::Index(InfectionState::Count) - 1)}; ///< TimeSeries containing points of time and the corresponding portion diff --git a/cpp/models/ide_endemic_secir/simulation.cpp b/cpp/models/ide_endemic_secir/simulation.cpp index ac8800f68c..1c41aad2d9 100644 --- a/cpp/models/ide_endemic_secir/simulation.cpp +++ b/cpp/models/ide_endemic_secir/simulation.cpp @@ -26,8 +26,8 @@ void Simulation::advance(ScalarType tmax) m_model->compparameters->set_InitFoI(m_dt); m_model->compparameters->set_reproductionnumber_c(m_dt); m_model->compparameters->set_T(m_dt); + m_model->compparameters->set_V(); m_model->compparameters->set_W(m_dt); - m_model->initialization_compute_forceofinfection(); m_normmodel->compparameters->set_transitiondistributions_support_max(m_dt); m_normmodel->compparameters->set_transitiondistributions(m_dt); @@ -38,16 +38,18 @@ void Simulation::advance(ScalarType tmax) m_normmodel->compparameters->set_InitFoI(m_dt); m_normmodel->compparameters->set_reproductionnumber_c(m_dt); m_normmodel->compparameters->set_T(m_dt); + m_normmodel->compparameters->set_V(); m_normmodel->compparameters->set_W(m_dt); - m_normmodel->initialization_compute_forceofinfection(); m_difference_normalizedcompartments.add_time_point(0); - compute_difference_normalizedcompartments(); + m_difference_normalizedFoI.add_time_point(0); + compute_difference_normalizations(); // For every time step: while (m_model->transitions.get_last_time() < tmax - m_dt / 2) { m_difference_normalizedcompartments.add_time_point(m_difference_normalizedcompartments.get_last_time() + m_dt); + m_difference_normalizedFoI.add_time_point(m_difference_normalizedFoI.get_last_time() + m_dt); //standard model: m_model->transitions.add_time_point(m_model->transitions.get_last_time() + m_dt); m_model->transitions_update.add_time_point(m_model->transitions_update.get_last_time() + m_dt); @@ -57,6 +59,8 @@ void Simulation::advance(ScalarType tmax) m_model->m_forceofinfectionupdate.add_time_point(m_model->m_forceofinfectionupdate.get_last_time() + m_dt); m_model->m_totalpopulation.add_time_point(m_model->m_totalpopulation.get_last_time() + m_dt); m_model->m_totalpopulationupdate.add_time_point(m_model->m_totalpopulationupdate.get_last_time() + m_dt); + m_model->m_totalpopulation_derivative.add_time_point(m_model->m_totalpopulation_derivative.get_last_time() + + m_dt); m_model->m_normalizedpopulations.add_time_point(m_model->m_normalizedpopulations.get_last_time() + m_dt); // Compute susceptibles: @@ -95,7 +99,7 @@ void Simulation::advance(ScalarType tmax) m_normmodel->compute_forceofinfection(m_dt); //Compute the difference of the two normalized compartments. - compute_difference_normalizedcompartments(); + compute_difference_normalizations(); } } diff --git a/cpp/models/ide_endemic_secir/simulation.h b/cpp/models/ide_endemic_secir/simulation.h index 342773fed8..e1bb5640ed 100644 --- a/cpp/models/ide_endemic_secir/simulation.h +++ b/cpp/models/ide_endemic_secir/simulation.h @@ -165,6 +165,14 @@ class Simulation return m_model->m_totalpopulationupdate; } + /** + * @brief Get the derivative of the total population of m_model. + */ + TimeSeries const& get_totalpopulations_derivative() + { + return m_model->m_totalpopulation_derivative; + } + /** * @brief Get the reproduction numer. */ @@ -181,6 +189,14 @@ class Simulation return m_model->compparameters->m_T; } + /** + * @brief Get V. + */ + std::vector const& get_V() + { + return m_model->compparameters->m_V; + } + /** * @brief Get W. */ @@ -229,19 +245,27 @@ class Simulation return m_dt; } - void compute_difference_normalizedcompartments() + void compute_difference_normalizations() { for (int state = 0; state < (int)InfectionState::Count - 1; state++) { - m_difference_normalizedcompartments.get_last_value()[state] = std::abs( - m_normmodel->populations.get_last_value()[state] - m_model->populations.get_last_value()[state]); + m_difference_normalizedcompartments.get_last_value()[state] = + std::abs(m_normmodel->populations.get_last_value()[state] - + m_model->m_normalizedpopulations.get_last_value()[state]); } + m_difference_normalizedFoI.get_last_value()[0] = std::abs(m_normmodel->m_forceofinfection.get_last_value()[0] - + m_model->m_forceofinfection.get_last_value()[0]); } - TimeSeries const& get_difference_normalizedcompartments() + TimeSeries const& get_difference_normalizationcomp() { return m_difference_normalizedcompartments; } + TimeSeries const& get_difference_normalizationFoi() + { + return m_difference_normalizedFoI; + } + private: std::unique_ptr m_compparams; ///< Unique pointer to the computed Parameters. std::unique_ptr m_model; ///< Unique pointer to the simulated Model. @@ -249,8 +273,10 @@ class Simulation ScalarType m_dt; ///< Time step used for numerical computations in simulation. TimeSeries m_difference_normalizedcompartments{TimeSeries( (int)InfectionState::Count - 1)}; ///< TimeSeries containing the difference of the compartments - // computed by NormModel and the normalized compartments comouted in Model. - // needed for the numerical scheme. + // computed by NormModel and the normalized compartments computed in Model. + TimeSeries m_difference_normalizedFoI{ + TimeSeries(1)}; ///< TimeSeries containing the difference of the force of infection terms + // computed by NormModel and Model. }; TimeSeries simulate(ScalarType tmax, ScalarType dt, Model const& model); From 6d21d3369eea0f78d28633892a1a1bdb965c4f56 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Wed, 3 Sep 2025 10:05:27 +0200 Subject: [PATCH 19/22] Added an endemic SIRD model --- cpp/CMakeLists.txt | 1 + cpp/examples/ide_endemic_secir.cpp | 115 +++---- .../ide_endemic_secir_save_results.cpp | 18 +- cpp/models/ide_endemic_secir/model.cpp | 3 +- cpp/models/ide_endemic_secir/simulation.cpp | 62 ++-- cpp/models/ide_endemic_sird/CMakeLists.txt | 17 + .../ide_endemic_sird/computed_parameters.h | 297 ++++++++++++++++++ cpp/models/ide_endemic_sird/infection_state.h | 38 +++ cpp/models/ide_endemic_sird/model.cpp | 259 +++++++++++++++ cpp/models/ide_endemic_sird/model.h | 185 +++++++++++ .../ide_endemic_sird/normalized_model.cpp | 235 ++++++++++++++ .../ide_endemic_sird/normalized_model.h | 155 +++++++++ cpp/models/ide_endemic_sird/parameters.h | 244 ++++++++++++++ cpp/models/ide_endemic_sird/simulation.cpp | 107 +++++++ cpp/models/ide_endemic_sird/simulation.h | 237 ++++++++++++++ 15 files changed, 1874 insertions(+), 99 deletions(-) create mode 100644 cpp/models/ide_endemic_sird/CMakeLists.txt create mode 100644 cpp/models/ide_endemic_sird/computed_parameters.h create mode 100644 cpp/models/ide_endemic_sird/infection_state.h create mode 100644 cpp/models/ide_endemic_sird/model.cpp create mode 100644 cpp/models/ide_endemic_sird/model.h create mode 100644 cpp/models/ide_endemic_sird/normalized_model.cpp create mode 100644 cpp/models/ide_endemic_sird/normalized_model.h create mode 100644 cpp/models/ide_endemic_sird/parameters.h create mode 100644 cpp/models/ide_endemic_sird/simulation.cpp create mode 100644 cpp/models/ide_endemic_sird/simulation.h diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 22ea6f48cc..4855a17a68 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -157,6 +157,7 @@ if(MEMILIO_BUILD_MODELS) add_subdirectory(models/lct_secir) add_subdirectory(models/glct_secir) add_subdirectory(models/ide_endemic_secir) + add_subdirectory(models/ide_endemic_sird) add_subdirectory(models/ide_secir) add_subdirectory(models/ide_seir) add_subdirectory(models/ode_seir) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index 5438d1e9e3..9d2f580349 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -20,7 +20,7 @@ int main() using Vec = mio::TimeSeries::Vector; ScalarType tmax = 1; - ScalarType dt = 1.0; + ScalarType dt = 0.00001; int num_states = static_cast(mio::endisecir::InfectionState::Count); int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); @@ -45,54 +45,54 @@ int main() //Set working parameters - // mio::ExponentialSurvivalFunction exp(3.0); - // mio::StateAgeFunctionWrapper delaydistribution(exp); - // std::vector vec_delaydistribution(num_transitions, delaydistribution); + mio::ExponentialSurvivalFunction exp(3.0); + mio::StateAgeFunctionWrapper delaydistribution(exp); + std::vector vec_delaydistribution(num_transitions, delaydistribution); - // mio::SmootherCosine smoothcos(6.0); + // mio::SmootherCosine smoothcos(2.0); // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); // std::vector vec_delaydistribution(num_transitions, delaydistribution); // Uncomment for Lognorm. - mio::ConstantFunction initialfunc(0); - mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); - std::vector vec_delaydistribution(num_transitions, delaydistributioninit); - // ExposedToInfectedNoSymptoms - mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.3, 0, 4.2); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms].set_state_age_function( - survivalExposedToInfectedNoSymptoms); - // InfectedNoSymptomsToInfectedSymptoms - mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.7, 0, 0.8); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] - .set_state_age_function(survivalInfectedNoSymptomsToInfectedSymptoms); - // InfectedNoSymptomsToRecovered - mio::LognormSurvivalFunction survivalInfectedNoSymptomsToRecovered(0.2, 0, 7.7); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered] - .set_state_age_function(survivalInfectedNoSymptomsToRecovered); - // InfectedSymptomsToInfectedSevere - mio::LognormSurvivalFunction survivalInfectedSymptomsToInfectedSevere(0.7, 0, 5.3); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere] - .set_state_age_function(survivalInfectedSymptomsToInfectedSevere); - // InfectedSymptomsToRecovered - mio::LognormSurvivalFunction survivalInfectedSymptomsToRecovered(0.2, 0, 7.8); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered].set_state_age_function( - survivalInfectedSymptomsToRecovered); - // InfectedSevereToInfectedCritical - mio::LognormSurvivalFunction survivalInfectedSevereToInfectedCritical(1.0, 0, 0.9); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical] - .set_state_age_function(survivalInfectedSevereToInfectedCritical); - // InfectedSevereToRecovered - mio::LognormSurvivalFunction survivalInfectedSevereToRecovered(0.3, 0, 17.1); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToRecovered].set_state_age_function( - survivalInfectedSevereToRecovered); - // InfectedCriticalToDead - mio::LognormSurvivalFunction survivalInfectedCriticalToDead(0.4, 0, 9.8); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToDead].set_state_age_function( - survivalInfectedCriticalToDead); - // InfectedCriticalToRecovered - mio::LognormSurvivalFunction survivalInfectedCriticalToRecovered(0.3, 0, 17.1); - vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToRecovered].set_state_age_function( - survivalInfectedCriticalToRecovered); + // mio::ConstantFunction initialfunc(0); + // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); + // std::vector vec_delaydistribution(num_transitions, delaydistributioninit); + // // ExposedToInfectedNoSymptoms + // mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.3, 0, 4.2); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::ExposedToInfectedNoSymptoms].set_state_age_function( + // survivalExposedToInfectedNoSymptoms); + // // InfectedNoSymptomsToInfectedSymptoms + // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.7, 0, 0.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToInfectedSymptoms] + // .set_state_age_function(survivalInfectedNoSymptomsToInfectedSymptoms); + // // InfectedNoSymptomsToRecovered + // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToRecovered(0.2, 0, 7.7); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedNoSymptomsToRecovered] + // .set_state_age_function(survivalInfectedNoSymptomsToRecovered); + // // InfectedSymptomsToInfectedSevere + // mio::LognormSurvivalFunction survivalInfectedSymptomsToInfectedSevere(0.7, 0, 5.3); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToInfectedSevere] + // .set_state_age_function(survivalInfectedSymptomsToInfectedSevere); + // // InfectedSymptomsToRecovered + // mio::LognormSurvivalFunction survivalInfectedSymptomsToRecovered(0.2, 0, 7.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSymptomsToRecovered].set_state_age_function( + // survivalInfectedSymptomsToRecovered); + // // InfectedSevereToInfectedCritical + // mio::LognormSurvivalFunction survivalInfectedSevereToInfectedCritical(1.0, 0, 0.9); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToInfectedCritical] + // .set_state_age_function(survivalInfectedSevereToInfectedCritical); + // // InfectedSevereToRecovered + // mio::LognormSurvivalFunction survivalInfectedSevereToRecovered(0.3, 0, 17.1); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedSevereToRecovered].set_state_age_function( + // survivalInfectedSevereToRecovered); + // // InfectedCriticalToDead + // mio::LognormSurvivalFunction survivalInfectedCriticalToDead(0.4, 0, 9.8); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToDead].set_state_age_function( + // survivalInfectedCriticalToDead); + // // InfectedCriticalToRecovered + // mio::LognormSurvivalFunction survivalInfectedCriticalToRecovered(0.3, 0, 17.1); + // vec_delaydistribution[(int)mio::endisecir::InfectionTransition::InfectedCriticalToRecovered].set_state_age_function( + // survivalInfectedCriticalToRecovered); computed_parameters.parameters.get() = vec_delaydistribution; @@ -126,7 +126,7 @@ int main() computed_parameters.parameters.set(4e-3); computed_parameters.parameters.set(3e-3); - //computed_parameters.set_tol_for_support_max(1e-6); + computed_parameters.set_tol_for_support_max(1e-6); mio::endisecir::Model model(computed_parameters); @@ -137,8 +137,8 @@ int main() sim.advance(tmax); //Get the compartments of model and print them. - // auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); - // interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); + auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); + interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); // Uncomment to print the compartments computed with the update scheme. // auto interpolated_results_update = mio::interpolate_simulation_result(sim.get_compartments_update(), dt / 2.); // interpolated_results_update.print_table({"US", "UE", "UC", "UI", "UH", "UU", "UR", "UD"}, 16, 8); @@ -161,7 +161,8 @@ int main() // {"s->e", "e->c", "c->i", "c->r", "i->h", "i->r , "h->u", "h->r", "u->d", "u->r"}, 16, 8); // Uncomment to print the force of infection of model. - // sim.get_forceofinfections().print_table({"FoI"}, 16, 8); + auto interpolated_FoI = mio::interpolate_simulation_result(sim.get_forceofinfections(), dt / 2.); + interpolated_FoI.print_table({"FoI"}, 16, 8); // sim.get_forceofinfections_update().print_table({"FoIUpdate"}, 16, 8); // Uncomment to print the force of infection of normmodel. @@ -171,19 +172,19 @@ int main() std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; // Uncomment to print the the values T_z1^z2 - for (int i = 0; i < (int)sim.get_T().size(); i++) { - std::cout << "T_" << i << " = " << sim.get_T()[i] << "\n"; - } + //for (int i = 0; i < (int)sim.get_T().size(); i++) { + // std::cout << "T_" << i << " = " << sim.get_T()[i] << "\n"; + //} // Uncomment to print the the values V^z - for (int i = 0; i < (int)sim.get_V().size(); i++) { - std::cout << "V_" << i << " = " << sim.get_V()[i] << "\n"; - } + //for (int i = 0; i < (int)sim.get_V().size(); i++) { + // std::cout << "V_" << i << " = " << sim.get_V()[i] << "\n"; + //} // Uncomment to print the values W_z - for (int i = 0; i < (int)sim.get_W().size(); i++) { - std::cout << "W_" << i << " = " << sim.get_W()[i] << "\n"; - } + //for (int i = 0; i < (int)sim.get_W().size(); i++) { + // std::cout << "W_" << i << " = " << sim.get_W()[i] << "\n"; + //} // Uncomment to print the total population size. // sim.get_totalpopulations().print_table({"N"}, 16, 9); diff --git a/cpp/examples/ide_endemic_secir_save_results.cpp b/cpp/examples/ide_endemic_secir_save_results.cpp index 9178095443..ba163c9e33 100644 --- a/cpp/examples/ide_endemic_secir_save_results.cpp +++ b/cpp/examples/ide_endemic_secir_save_results.cpp @@ -48,7 +48,7 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - mio::SmootherCosine smoothcos(2.0); + mio::SmootherCosine smoothcos(6.0); mio::StateAgeFunctionWrapper delaydistribution(smoothcos); std::vector vec_delaydistribution(num_transitions, delaydistribution); @@ -133,8 +133,8 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = computed_parameters.parameters.get() = exponential_prob; computed_parameters.parameters.get() = exponential_prob; - computed_parameters.parameters.set(4e-3); - computed_parameters.parameters.set(3e-3); + computed_parameters.parameters.set(4e-4); + computed_parameters.parameters.set(3e-4); //computed_parameters.set_tol_for_support_max(1e-6); @@ -164,28 +164,28 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = mio::save_result({sim.get_totalpopulations_derivative()}, {0}, 1, filename_ide_dertotalpopulation1); //Save compartments. - std::string filename_ide_compartments1 = filename_ide + "_compartments.h5"; + std::string filename_ide_compartments1 = filename_ide + "_compartments2.h5"; mio::IOResult save_result_status_c1 = mio::save_result({sim.get_compartments()}, {0}, 1, filename_ide_compartments1); //Save normalized compartments. - std::string filename_ide_normcompartments = filename_ide + "_normcompartments1.h5"; + std::string filename_ide_normcompartments = filename_ide + "_normcompartments.h5"; mio::IOResult save_result_status_nc = mio::save_result({sim.get_normalizedcompartments()}, {0}, 1, filename_ide_normcompartments); //Save the force of infection. - std::string filename_ide_forceofinfection = filename_ide + "_forceofinfection1.h5"; + std::string filename_ide_forceofinfection = filename_ide + "_forceofinfection2.h5"; mio::IOResult save_result_status_foi = mio::save_result({sim.get_forceofinfections()}, {0}, 1, filename_ide_forceofinfection); //Save files of NormModel. //Save compartments. - std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments.h5"; + std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments2.h5"; mio::IOResult save_result_status_nmc1 = mio::save_result({sim.get_normmodel_compartments()}, {0}, 1, filename_ide_normmod_compartments); //Save the force of infection. - std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection.h5"; + std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection2.h5"; mio::IOResult save_result_status_nmfoi = mio::save_result({sim.get_normmodel_forceofinfections()}, {0}, 1, filename_ide_normmod_forceofinfection); @@ -217,7 +217,7 @@ int main() std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDE/simulation_results/"; // Define tmax. - ScalarType tmax = 100; + ScalarType tmax = 2000; auto result_ide = simulate_endidemodel(tmax, result_dir); if (!result_ide) { diff --git a/cpp/models/ide_endemic_secir/model.cpp b/cpp/models/ide_endemic_secir/model.cpp index 5f17f72a0b..b5031ae015 100644 --- a/cpp/models/ide_endemic_secir/model.cpp +++ b/cpp/models/ide_endemic_secir/model.cpp @@ -44,8 +44,7 @@ Model::Model(CompParameters const& compparams) // Set the force of infection term at time t0. m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, compparameters->m_FoI_0[0])); - m_forceofinfectionupdate.add_time_point( - 0, TimeSeries::Vector::Constant(1, compparameters->m_NormFoI_0[0])); + m_forceofinfectionupdate.add_time_point(0, TimeSeries::Vector::Constant(1, compparameters->m_FoI_0[0])); //Set normalized_populations at start time t0. TimeSeries::Vector vec_normalizedpopulations = diff --git a/cpp/models/ide_endemic_secir/simulation.cpp b/cpp/models/ide_endemic_secir/simulation.cpp index 1c41aad2d9..ee5b9a5384 100644 --- a/cpp/models/ide_endemic_secir/simulation.cpp +++ b/cpp/models/ide_endemic_secir/simulation.cpp @@ -29,27 +29,27 @@ void Simulation::advance(ScalarType tmax) m_model->compparameters->set_V(); m_model->compparameters->set_W(m_dt); - m_normmodel->compparameters->set_transitiondistributions_support_max(m_dt); - m_normmodel->compparameters->set_transitiondistributions(m_dt); - m_normmodel->compparameters->set_transitiondistributions_derivative(m_dt); - m_normmodel->compparameters->set_B(m_dt); - m_normmodel->compparameters->set_infectivity(m_dt); - m_normmodel->compparameters->set_FoI_0(m_dt); - m_normmodel->compparameters->set_InitFoI(m_dt); - m_normmodel->compparameters->set_reproductionnumber_c(m_dt); - m_normmodel->compparameters->set_T(m_dt); - m_normmodel->compparameters->set_V(); - m_normmodel->compparameters->set_W(m_dt); - - m_difference_normalizedcompartments.add_time_point(0); - m_difference_normalizedFoI.add_time_point(0); - compute_difference_normalizations(); + //m_normmodel->compparameters->set_transitiondistributions_support_max(m_dt); + //m_normmodel->compparameters->set_transitiondistributions(m_dt); + //m_normmodel->compparameters->set_transitiondistributions_derivative(m_dt); + //m_normmodel->compparameters->set_B(m_dt); + //m_normmodel->compparameters->set_infectivity(m_dt); + //m_normmodel->compparameters->set_FoI_0(m_dt); + //m_normmodel->compparameters->set_InitFoI(m_dt); + //m_normmodel->compparameters->set_reproductionnumber_c(m_dt); + //m_normmodel->compparameters->set_T(m_dt); + //m_normmodel->compparameters->set_V(); + //m_normmodel->compparameters->set_W(m_dt); + + //m_difference_normalizedcompartments.add_time_point(0); + //m_difference_normalizedFoI.add_time_point(0); + //compute_difference_normalizations(); // For every time step: while (m_model->transitions.get_last_time() < tmax - m_dt / 2) { - m_difference_normalizedcompartments.add_time_point(m_difference_normalizedcompartments.get_last_time() + m_dt); - m_difference_normalizedFoI.add_time_point(m_difference_normalizedFoI.get_last_time() + m_dt); + //m_difference_normalizedcompartments.add_time_point(m_difference_normalizedcompartments.get_last_time() + m_dt); + //m_difference_normalizedFoI.add_time_point(m_difference_normalizedFoI.get_last_time() + m_dt); //standard model: m_model->transitions.add_time_point(m_model->transitions.get_last_time() + m_dt); m_model->transitions_update.add_time_point(m_model->transitions_update.get_last_time() + m_dt); @@ -81,25 +81,25 @@ void Simulation::advance(ScalarType tmax) // Compute m_forceofinfection; m_model->compute_forceofinfection(m_dt); - // normalized model: - m_normmodel->transitions.add_time_point(m_normmodel->transitions.get_last_time() + m_dt); - m_normmodel->populations.add_time_point(m_normmodel->populations.get_last_time() + m_dt); - m_normmodel->m_forceofinfection.add_time_point(m_normmodel->m_forceofinfection.get_last_time() + m_dt); + // // normalized model: + // m_normmodel->transitions.add_time_point(m_normmodel->transitions.get_last_time() + m_dt); + // m_normmodel->populations.add_time_point(m_normmodel->populations.get_last_time() + m_dt); + // m_normmodel->m_forceofinfection.add_time_point(m_normmodel->m_forceofinfection.get_last_time() + m_dt); - // Compute susceptibles: - m_normmodel->compute_susceptibles(m_dt); + // // Compute susceptibles: + // m_normmodel->compute_susceptibles(m_dt); - // Compute flows: - m_normmodel->flows_currents_timestep(m_dt); + // // Compute flows: + // m_normmodel->flows_currents_timestep(m_dt); - // Compute remaining compartments: - m_normmodel->update_compartments(m_dt); + // // Compute remaining compartments: + // m_normmodel->update_compartments(m_dt); - // Compute m_forceofinfection; - m_normmodel->compute_forceofinfection(m_dt); + // // Compute m_forceofinfection; + // m_normmodel->compute_forceofinfection(m_dt); - //Compute the difference of the two normalized compartments. - compute_difference_normalizations(); + // //Compute the difference of the two normalized compartments. + // compute_difference_normalizations(); } } diff --git a/cpp/models/ide_endemic_sird/CMakeLists.txt b/cpp/models/ide_endemic_sird/CMakeLists.txt new file mode 100644 index 0000000000..62d95776f5 --- /dev/null +++ b/cpp/models/ide_endemic_sird/CMakeLists.txt @@ -0,0 +1,17 @@ +add_library(ide_endemic_sird + infection_state.h + model.h + model.cpp + normalized_model.h + normalized_model.cpp + simulation.h + simulation.cpp + parameters.h + computed_parameters.h +) +target_link_libraries(ide_endemic_sird PUBLIC memilio) +target_include_directories(ide_endemic_sird PUBLIC + $ + $ +) +target_compile_options(ide_endemic_secir PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ide_endemic_sird/computed_parameters.h b/cpp/models/ide_endemic_sird/computed_parameters.h new file mode 100644 index 0000000000..92d88fc34a --- /dev/null +++ b/cpp/models/ide_endemic_sird/computed_parameters.h @@ -0,0 +1,297 @@ +#ifndef IDE_END_SIRD_COMPPARAMS_H +#define IDE_END_SIRD_COMPPARAMS_H + +#include "ide_endemic_sird/infection_state.h" +#include "ide_endemic_sird/parameters.h" +#include "memilio/config.h" +#include "memilio/utils/time_series.h" + +#include "vector" +#include +#include +#include +#include +#include + +namespace mio +{ +namespace endisird +{ +class CompParameters; +class Model; +class Simulation; + +class CompParameters +{ + using ParameterSet = Parameters; + +public: + CompParameters(TimeSeries&& states_init) + : parameters{Parameters()} + , m_statesinit{std::move(states_init)} + { + m_totalpopulationinit = std::accumulate(m_statesinit[0].begin(), m_statesinit[0].end(), 0) - + m_statesinit[0][(int)InfectionState::Dead]; + } + + bool check_constraints() const + { + if (!(static_cast(m_statesinit.get_num_elements()) == static_cast(InfectionState::Count))) { + log_error( + " A variable given for model construction is not valid. Number of elements in vector of populations " + "does not match the required number."); + return true; + } + for (int i = 0; i < static_cast(InfectionState::Count); i++) { + if (m_statesinit[0][i] < 0) { + log_error("Initialization failed. Initial values for populations are less than zero."); + return true; + } + } + return parameters.check_constraints(); + } + + /** + * @brief Setter for the tolerance used to calculate the maximum support of the TransitionDistributions. + * + * @param[in] new_tol New tolerance. + */ + void set_tol_for_support_max(ScalarType new_tol) + { + m_tol = new_tol; + } + + // ---- Public parameters. ---- + ParameterSet parameters; ///< ParameterSet of Model Parameters. + +private: + // ---- Functionality to set vectors with necessary information regarding TransitionDistributions. ---- + /** + * @brief Setter for the vector m_transitiondistributions_support_max that contains the support_max for all + * TransitionDistributions. + * + * This determines how many summands are required when calculating flows, the force of infection or compartments. + * + * @param[in] dt Time step size. + */ + void set_transitiondistributions_support_max(ScalarType dt) + { + // The transition Susceptible to Exposed is not needed in the computations. + for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { + m_transitiondistributions_support_max[transition] = + parameters.get()[transition].get_support_max(dt, m_tol); + } + } + + /** + * @brief Setter for the vector m_transitiondistributions. + * + * Here we compute the weighted transition distributions for every compartment. Meaning for every compartment we weight + * the distributions of the outgoing transitions with their probability and compute the sum of the two weighed distributions. + * + * @param[in] dt Time step size. + */ + void set_transitiondistributions(ScalarType dt) + { + + // Vector containing the outgoing transitions for the Infected state. + + std::vector vector_transitions = {(int)InfectionTransition::InfectedToDead, + (int)InfectionTransition::InfectedToRecovered}; + + Eigen::Index calc_time_index = + std::ceil(std::max(m_transitiondistributions_support_max[(Eigen::Index)vector_transitions[0]], + m_transitiondistributions_support_max[(Eigen::Index)vector_transitions[1]]) / + dt); + + std::vector vec_contribution_to_foi_2(calc_time_index + 1, 0.); + for (Eigen::Index i = 0; i <= calc_time_index; i++) { + ///Compute the state_age. + ScalarType state_age = (ScalarType)i * dt; + + vec_contribution_to_foi_2[i] += + parameters.get()[vector_transitions[0]] * + parameters.get()[vector_transitions[0]].eval(state_age) + + parameters.get()[vector_transitions[1]] * + parameters.get()[vector_transitions[1]].eval(state_age); + m_transitiondistributions = vec_contribution_to_foi_2; + } + } + + /** + * @brief Setter for the vector m_transitiondistributions_derivative that contains the approximated derivative for + * all TransitionDistributions for all necessary time points. + * + * The derivative is approximated using a backwards difference scheme. + * The number of necessary time points for each TransitionDistribution is determined using + * m_transitiondistributions_support_max. + * + * @param[in] dt Time step size. + */ + void set_transitiondistributions_derivative(ScalarType dt) + { + // The transition SusceptibleToExposed is not needed in the computations. + for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { + Eigen::Index support_max_index = + (Eigen::Index)std::ceil(m_transitiondistributions_support_max[transition] / dt); + + // Create vec_derivative that stores the value of the approximated derivative for all necessary time points. + std::vector vec_derivative(support_max_index + 1, 0.); + + for (Eigen::Index i = 0; i <= support_max_index; i++) { + // Compute state_age. + ScalarType state_age = (ScalarType)i * dt; + //Compute the apprximate derivative by a backwards difference scheme. + vec_derivative[i] = (parameters.get()[transition].eval(state_age) - + parameters.get()[transition].eval(state_age - dt)) / + dt; + } + m_transitiondistributions_derivative[transition] = vec_derivative; + } + } + + /** + *@brief Setter for the vector m_meaninfectivity that contains the approximated value of the mean infectivity for all + * for all necessary time points. + * + * This values is needed the compute the reproduction numer and the force of infection term. + * + * @param[in] dt Time step size. + */ + void set_infectivity(ScalarType dt) + { + // Compute the calc_time_indedx corresponding to a_1: + ScalarType calc_time_index = m_transitiondistributions.size() - 1; + + m_infectivity = std::vector(calc_time_index, 0.); + + for (Eigen::Index time_point_index = 1; time_point_index < calc_time_index; time_point_index++) { + ScalarType time_point_age = (ScalarType)time_point_index * dt; + m_infectivity[time_point_index] = parameters.get().eval(time_point_age) * + m_transitiondistributions[time_point_index] * + std::exp(-parameters.get() * time_point_age); + } + } + + /** + *@brief Setter for the vectors m_FoI_0 and m_NormFoI_0 that contain the approximated values of the function FoI_0, + * that is a part of the force of infection term for all necessary time points. + */ + void set_FoI_0(ScalarType dt) + { + Eigen::Index calc_time_index = m_transitiondistributions.size(); + m_FoI_0 = std::vector(calc_time_index, 0.); + m_NormFoI_0 = std::vector(calc_time_index, 0.); + for (Eigen::Index time_point_index = 0; time_point_index < calc_time_index; time_point_index++) { + ScalarType time_point_age = (ScalarType)time_point_index * dt; + m_FoI_0[time_point_index] = + (parameters.get().eval(time_point_age) * + parameters.get().get_cont_freq_mat().get_matrix_at(time_point_age)(0, 0)) * + m_statesinit[0][(int)InfectionState::Infected] * m_infectivity[time_point_index]; + m_NormFoI_0[time_point_index] = + (parameters.get().eval(time_point_age) * + parameters.get().get_cont_freq_mat().get_matrix_at(time_point_age)(0, 0)) * + (m_statesinit[0][(int)InfectionState::Infected] / m_totalpopulationinit) * + m_infectivity[time_point_index]; + } + } + + // ---- Parameters needed for the analysis of the model ---- + /** + * @brief Setter for the Reproduction number m_reproductionnumber_c. + * + */ + void set_reproductionnumber_c(ScalarType dt) + { + // Determine the corresponding time index. + + Eigen::Index calc_time_index = m_infectivity.size() - 1; + ScalarType sum = 0; + for (int i = 0; i <= calc_time_index; i++) { + sum += m_infectivity[i]; + } + m_reproductionnumber_c = parameters.get().eval(0) * + parameters.get().get_cont_freq_mat().get_matrix_at(0)(0, 0) * dt * + sum; + } + + /** + * @brief Setter for m_T. + * + * @param[in] dt step size. + */ + void set_T(ScalarType dt) + { + // The value T_z1^z2 is not defined for the transition SusceptiblesToInfected. + for (int transition = 1; transition < (int)InfectionTransition::Count; transition++) { + Eigen::Index support_max_index = + (Eigen::Index)std::ceil(m_transitiondistributions_support_max[transition] / dt); + ScalarType sum = 0; + + for (Eigen::Index i = 0; i <= support_max_index; i++) { + // Compute state_age. + ScalarType state_age = (ScalarType)i * dt; + //Compute the apprximate derivative by a backwards difference scheme. + sum -= std::exp(-parameters.get() * state_age) * + m_transitiondistributions_derivative[transition][i]; + } + m_T[transition] = parameters.get()[transition] * sum; + } + } + + /** + * @brief Setter for m_W. + * + * m_W contains the values W_i + * + * @param[in] dt step size. + */ + void set_W(ScalarType dt) + { + + Eigen::Index calc_time_index = m_transitiondistributions.size(); + ScalarType sum = 0; + + for (Eigen::Index i = 0; i < calc_time_index; i++) { + // Compute state_age. + ScalarType state_age = (ScalarType)i * dt; + //Compute the apprximate derivative by a backwards difference scheme. + sum += std::exp(-parameters.get() * state_age) * m_transitiondistributions[i]; + } + m_W = sum; + } + + // ---- Private parameters. ---- + TimeSeries m_statesinit; ///< TimeSeries containing the initial values for the compartments. + ScalarType m_totalpopulationinit; + ScalarType m_tol{1e-10}; ///< Tolerance used to calculate the maximum support of the TransitionDistributions. + std::vector m_transitiondistributions_support_max{ + std::vector((int)InfectionTransition::Count, 0.)}; ///< A vector containing the support_max + // for all TransitionDistributions. + std::vector m_transitiondistributions{ + std::vector(1, 0.)}; ///< A vector containing the weighted TransitionDistributions + // for the Infected state. + std::vector> m_transitiondistributions_derivative{std::vector>( + (int)InfectionTransition::Count, std::vector(1, 0.))}; ///< A Vector containing + // the approximated derivative for all TransitionDistributions for all necessary time points. + std::vector m_infectivity{ + std::vector(1, 0.)}; ///< A vector containing the approximated mean infectivity for all time points. + ScalarType m_reproductionnumber_c; ///< The control Reproduction number + std::vector m_FoI_0{std::vector(1, 0.)}; ///< A vector containing the approcimated + // value of the function FoI_0 used for the computation of the force of infection in the standard model + std::vector m_NormFoI_0{std::vector(1, 0.)}; ///< A vector containing the approcimated + // value of the function FoI_0 used for the computation of the force of infection in the normalized model + std::vector m_T{std::vector((int)InfectionTransition::Count, 0.)}; ///< A vector + // containing the approximated value for T_z1^z2 for every Flow z1 to z2. + ScalarType m_W{0}; ///< ScalarType of the value W_i. + // ---- Friend classes/functions. ---- + friend class Model; + friend class NormModel; + friend class Simulation; +}; + +} // namespace endisird + +} // namespace mio + +#endif //IDE_END_SIRD_COMPPARAMS_H \ No newline at end of file diff --git a/cpp/models/ide_endemic_sird/infection_state.h b/cpp/models/ide_endemic_sird/infection_state.h new file mode 100644 index 0000000000..03b46edcc1 --- /dev/null +++ b/cpp/models/ide_endemic_sird/infection_state.h @@ -0,0 +1,38 @@ +#ifndef IDE_END_SIRD_INFECTIONSTATE_H +#define IDE_END_SIRD_INFECTIONSTATE_H + +namespace mio +{ + +namespace endisird +{ + +/** + * @brief The #InfectionState enum describes the possible + * categories for the infectious state of persons + */ +enum class InfectionState +{ + Susceptible = 0, + Infected = 1, + Recovered = 2, + Dead = 3, + Count = 4 +}; + +/** + * @brief The #InfectionTransition enum describes the possible + * transitions of the infectious state of persons. + */ +enum class InfectionTransition +{ + SusceptibleToInfected = 0, + InfectedToDead = 1, + InfectedToRecovered = 2, + Count = 3, +}; + +} // namespace endisird +} // namespace mio + +#endif //IDE_END_SIRD_INFECTIONSTATE_H diff --git a/cpp/models/ide_endemic_sird/model.cpp b/cpp/models/ide_endemic_sird/model.cpp new file mode 100644 index 0000000000..15b6456682 --- /dev/null +++ b/cpp/models/ide_endemic_sird/model.cpp @@ -0,0 +1,259 @@ +#include "ide_endemic_sird/model.h" +#include "ide_endemic_sird/computed_parameters.h" +#include "ide_endemic_sird/parameters.h" +#include "ide_endemic_sird/infection_state.h" +#include "memilio/config.h" +#include "memilio/utils/logging.h" + +#include "memilio/utils/time_series.h" +#include "vector" +#include +#include +#include +#include +#include +#include +#include + +namespace mio +{ +namespace endisird +{ +Model::Model(CompParameters const& compparams) + : compparameters{std::make_shared(compparams)} + , transitions{TimeSeries(Eigen::Index(InfectionTransition::Count))} + , populations{compparameters->m_statesinit} + +{ + + // Set flows at start time t0. + // As we assume that all individuals have infectio age 0 at time t0, the flows at t0 are set to 0. + transitions.add_time_point( + 0, TimeSeries::Vector::Constant(static_cast(InfectionTransition::Count), 0.)); + // Set population size at start timt t0. + ScalarType init_populationsize = + std::accumulate(populations[0].begin(), populations[0].end(), 0) - populations[0][(int)InfectionState::Dead]; + m_totalpopulation.add_time_point(0, TimeSeries::Vector::Constant(1, init_populationsize)); + m_totalpopulation_derivative.add_time_point(0, TimeSeries::Vector::Constant(1, 0.)); + + // Set the force of infection term at time t0. + m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, compparameters->m_FoI_0[0])); + + //Set normalized_populations at start time t0. + TimeSeries::Vector vec_normalizedpopulations = + TimeSeries::Vector(Eigen::Index(InfectionState::Count) - 1); + for (int infection_state = 0; infection_state < Eigen::Index(InfectionState::Count) - 1; infection_state++) { + vec_normalizedpopulations[infection_state] = populations[0][infection_state] / m_totalpopulation[0][0]; + } + m_normalizedpopulations.add_time_point(0, vec_normalizedpopulations); +} + +bool Model::check_constraints() const +{ + if (!(static_cast(populations.get_num_elements()) == static_cast(InfectionState::Count))) { + log_error(" A variable given for model construction is not valid. Number of elements in vector of populations " + "does not match the required number."); + return true; + } + + for (int i = 0; i < static_cast(InfectionState::Count); i++) { + if (populations[0][i] < 0) { + log_error("Initialization failed. Initial values for populations are less than zero."); + return true; + } + } + return compparameters->check_constraints(); +} + +// ----Functionality for the iterations of a simulation. ---- +void Model::compute_susceptibles(ScalarType dt) +{ + Eigen::Index num_time_points = populations.get_num_time_points(); + populations.get_last_value()[static_cast(InfectionState::Susceptible)] = + (populations[num_time_points - 2][static_cast(InfectionState::Susceptible)] + + dt * m_totalpopulation[num_time_points - 2][0] * compparameters->parameters.get()) / + (1 + dt * (m_forceofinfection[num_time_points - 2][0] + compparameters->parameters.get())); +} + +void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, Eigen::Index current_time_index, ScalarType dt) +{ + Eigen::Index calc_time_index = + (Eigen::Index)std::ceil(compparameters->m_transitiondistributions_support_max[idx_InfectionTransitions] / dt); + ScalarType current_time_age = static_cast(current_time_index) * dt; + + ScalarType sum = 0; + //Determine the starting point of the for loop. + Eigen::Index starting_point = std::max(0, (int)current_time_index - (int)calc_time_index); + + for (Eigen::Index i = starting_point; i < current_time_index; i++) { + ScalarType state_age_i = static_cast(i) * dt; + sum += transitions[i + 1][idx_IncomingFlow] * + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)) * + compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; + } + if (current_time_index <= calc_time_index) { + transitions.get_value(current_time_index)[idx_InfectionTransitions] = + (-dt) * compparameters->parameters.get()[idx_InfectionTransitions] * sum - + std::exp((-compparameters->parameters.get()) * (current_time_age)) * + populations[0][idx_CurrentCompartment] * + compparameters->parameters.get()[idx_InfectionTransitions] * + compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; + } + else { + transitions.get_value(current_time_index)[idx_InfectionTransitions] = + (-dt) * compparameters->parameters.get()[idx_InfectionTransitions] * sum; + } +} + +void Model::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, ScalarType dt) +{ + Eigen::Index current_time_index = transitions.get_num_time_points() - 1; + compute_flow(idx_InfectionTransitions, idx_IncomingFlow, idx_CurrentCompartment, current_time_index, dt); +} + +void Model::flows_currents_timestep(ScalarType dt) +{ + Eigen::Index current_time_index = populations.get_num_time_points() - 1; + // Calculate the transition SusceptibleToExposed with force of infection from previous time step and Susceptibles from + // current time step. + transitions.get_last_value()[static_cast(InfectionTransition::SusceptibleToInfected)] = + m_forceofinfection[current_time_index - 1][0] * + populations.get_last_value()[static_cast(InfectionState::Susceptible)]; + + // Calculate the other Transitions with compute_flow. + // Infected To Dead: + compute_flow(Eigen::Index(InfectionTransition::InfectedToDead), + Eigen::Index(InfectionTransition::SusceptibleToInfected), Eigen::Index(InfectionState::Infected), dt); + // Infected To Recovered: + compute_flow(Eigen::Index(InfectionTransition::InfectedToRecovered), + Eigen::Index(InfectionTransition::SusceptibleToInfected), Eigen::Index(InfectionState::Infected), dt); +} + +void Model::update_compartment_with_sum(InfectionState infectionState, + std::vector const& IncomingFlows, + bool NaturalDeathispossible, bool Transitionispossible, ScalarType dt) +{ + Eigen::Index current_time_index = populations.get_num_time_points() - 1; + ScalarType current_time_age = (ScalarType)current_time_index * dt; + Eigen::Index calc_time_index = current_time_index; + if (Transitionispossible) { + calc_time_index = compparameters->m_transitiondistributions.size() - 1; + } + + ScalarType sum = 0; + + Eigen::Index starting_point = std::max(0, (int)current_time_index - (int)calc_time_index); + for (int i = starting_point; i < current_time_index; i++) { + ScalarType state_age_i = (ScalarType)i * dt; + ScalarType sum_inflows = 0; + for (const InfectionTransition& inflow : IncomingFlows) { + sum_inflows += transitions[i + 1][(int)inflow]; + } + if (NaturalDeathispossible && Transitionispossible) { + sum += compparameters->m_transitiondistributions[current_time_index - i] * sum_inflows * + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)); + } + else if (NaturalDeathispossible && !Transitionispossible) { + sum += sum_inflows * + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)); + } + // The case !NaturalDeathispossible && Transitionispossible is not possible, as if NaturalDeath is not possible + // this means you are in the Death compartment and then Transition is also not possible. + else { + sum += sum_inflows; + } + } + if (NaturalDeathispossible && Transitionispossible) { + if (current_time_index <= calc_time_index) { + populations.get_last_value()[(int)infectionState] = + dt * sum + compparameters->m_transitiondistributions[current_time_index] * + populations[0][(int)infectionState] * + std::exp(-compparameters->parameters.get() * (current_time_age)); + } + else { + populations.get_last_value()[(int)infectionState] = dt * sum; + } + } + else if (NaturalDeathispossible && !Transitionispossible) { + populations.get_last_value()[(int)infectionState] = + dt * sum + populations[0][(int)infectionState] * + std::exp(-compparameters->parameters.get() * (current_time_age)); + } + else { + populations.get_last_value()[(int)infectionState] = dt * sum + populations[0][(int)infectionState]; + } +} + +void Model::update_compartments(ScalarType dt) +{ + + // Infected + update_compartment_with_sum(InfectionState::Infected, {InfectionTransition::SusceptibleToInfected}, true, true, dt); + // Recovered + update_compartment_with_sum(InfectionState::Recovered, + { + InfectionTransition::InfectedToRecovered, + }, + true, false, dt); + + // Dead + update_compartment_with_sum(InfectionState::Dead, {InfectionTransition::InfectedToDead}, false, false, dt); +} + +void Model::compute_populationsize() +{ + ScalarType sum = 0; + for (int state = 0; state < Eigen::Index(InfectionState::Count) - 1; state++) { + sum += populations.get_last_value()[state]; + } + m_totalpopulation.get_last_value()[0] = sum; + // Here we comoute the derivative of the total population that is given by + // BirthRate * N(t) - DeathRate * N(t) - Transition[InfectedCritical>ToDeath](t). + m_totalpopulation_derivative.get_last_value()[0] = + (compparameters->parameters.get() - compparameters->parameters.get()) * + m_totalpopulation.get_last_value()[0] - + transitions.get_last_value()[(int)InfectionTransition::InfectedToDead]; +} + +void Model::compute_normalizedcompartments() +{ + for (int infection_state = 0; infection_state < Eigen::Index(InfectionState::Count) - 1; infection_state++) { + m_normalizedpopulations.get_last_value()[infection_state] = + populations.get_last_value()[infection_state] / m_totalpopulation.get_last_value()[0]; + } +} + +void Model::compute_forceofinfection(ScalarType dt) +{ + + Eigen::Index num_time_points = populations.get_num_time_points(); + ScalarType current_time = populations.get_last_time(); + + // Determine the starting point of the for loop. + Eigen::Index starting_point = std::max(0, (int)num_time_points - 1 - (int)compparameters->m_infectivity.size()); + + ScalarType sum = 0.; + // Compute the sum in the force of infection term. + for (Eigen::Index i = starting_point; i < num_time_points - 1; i++) { + sum += compparameters->m_infectivity[num_time_points - 1 - i] * + populations[i + 1][(int)InfectionState::Susceptible] * m_forceofinfection[i][0]; + } + + ScalarType Foi_0 = 0; + + // Add inital functions for the force of infection in case they still have an influence. + if (num_time_points <= (int)compparameters->m_FoI_0.size()) { + Foi_0 = compparameters->m_FoI_0[num_time_points - 1] / m_totalpopulation[num_time_points - 1][0]; + } + m_forceofinfection.get_last_value()[0] = + (dt * sum * compparameters->parameters.get().eval(current_time) * + compparameters->parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)) / + m_totalpopulation[num_time_points - 1][0] + + Foi_0; +} + +}; // namespace endisird + +} // namespace mio diff --git a/cpp/models/ide_endemic_sird/model.h b/cpp/models/ide_endemic_sird/model.h new file mode 100644 index 0000000000..017e98527e --- /dev/null +++ b/cpp/models/ide_endemic_sird/model.h @@ -0,0 +1,185 @@ +#ifndef IDE_END_SIRD_MODEL_H +#define IDE_END_SIRD_MODEL_H + +#include "ide_endemic_sird/infection_state.h" +#include "ide_endemic_sird/parameters.h" +#include "ide_endemic_sird/computed_parameters.h" +#include "memilio/config.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/utils/time_series.h" + +#include "vector" +#include +#include +#include + +namespace mio +{ +namespace endisird +{ +// Forward declaration of friend classes/functions of Model. +class Model; +class Simulation; + +class Model +{ + using ParameterSet = Parameters; + +public: + /** + * @brief Constructor to create an endemic IDE_SIRD model. + * + * @param[in] TODO!!!!!! + */ + + Model(CompParameters const& compparams); + + /** + * @brief Checks constraints on model parameters and initial data. + * @return Returns true if one (or more) constraint(s) are not satisfied, otherwise false. + */ + bool check_constraints() const; + + /** + * @brief Setter for the tolerance used to calculate the maximum support of the TransitionDistributions. + * + * @param[in] new_tol New tolerance. + */ + + // ---- Public parameters. ---- + std::shared_ptr compparameters; + TimeSeries + transitions; ///< TimesSeries containing points of time and the corresponding number of individuals transitioning + // from one #InfectionState to another as defined in #Infection%s. + TimeSeries populations; ///< TimeSeries containing points of time and the corresponding number of people + // in defined #InfectionState%s. In this case we compute them by a sum. + +private: + // ---- Functionality for the iterations of a simulation. + + /** + * @brief Computes number of Susceptibles for the current last time in populations. + * + * Number is computed by using the previous number of Susceptibles, total population of the last time point and + * the force of infection (also from the last time point). + * Number is stored at the matching index in populations and populations_update. + * + * @param[in] dt Time discretization step size. + */ + void compute_susceptibles(ScalarType dt); + + /** + * @brief Computes sizeof a flow + * + * Computes size of one Transition from #InfectionTransition, specified in idx_InfectionTransitions, for the time index + * current_time_index. + * + * @param[in] idx_InfectionTransitions Specifies the considered transition from #InfectionTransition + * @param[in] idx_IncomingFlow Index of the transition in #InfectionTransition, which goes to the considered starting + * compartment of the transition specified in idx_InfectionTransitions. Size of considered flow is calculated via + * the value of this incoming flow. + * @param[in] idx_CurrentCompartment Index of the Compartment we flow out. + * @param[in] current_time_index The time index the transition should be computed for. + * @param[in] dt Time discretization step size. + */ + void compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, Eigen::Index current_time_index, ScalarType dt); + + /** + * @brief Computes size of a flow + * + * Computes size of one Transition from #InfectionTransition, specified in idx_InfectionTransitions, for the current + * last time value in transitions. + * + * @param[in] idx_InfectionTransitions Specifies the considered transition from #InfectionTransition + * @param[in] idx_IncomingFlow Index of the transition in #InfectionTransition, which goes to the considered starting + * compartment of the transition specified in idx_InfectionTransitions. Size of considered flow is calculated via + * the value of this incoming flow. + * @param[in] idx_CurrentCompartment Index of the Compartment we flow out. + * @param[in] dt Time discretization step size. + */ + void compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, ScalarType dt); + + /** + * @brief Sets all required transitions for the current last timestep in transitions. + * + * New values are stored in transitions. Most values are computed via the function compute_flow() + * + * @param[in] dt time discretization step size. + */ + void flows_currents_timestep(ScalarType dt); + + /** + * @brief Updates the values of one compartment, specified in infectionState, using all past transitions. + * + * New value is stored in populations. The values are calculated using all past values for the incoming flows + * including the current time step. + * Therefore the flows of the current time step should be calculated before using this function. + * @param[in] infectionState Specifies the #InfectionState we want to update. + * @param[in] IncomingFlows + * @param[in] NaturalDeathispossible Boolian that determines if there is the possibility of Natural Death in infectionState. + * @param[in] Transitionispossible Boolian that determines if it is possible to transition from the current InfectionState + * into another + * @param[in] dt + */ + void update_compartment_with_sum(InfectionState infectionState, + std::vector const& IncomingFlows, bool NaturalDeathispossible, + bool Transitionispossible, ScalarType dt); + + /** + * @brief Updates the values of all compartments except Susceptible + * + * New value is stored in populations. Values are computed via the function update_compartment_from_flow + */ + void update_compartments(ScalarType dt); + + /** + * @brief Compute the population size for the current last time in populations. + * + * The population size is computed as the sum of all compartments. + * The population size is stored in the vector m_populationsize. + */ + void compute_populationsize(); + + /** + * @brief Compute the normalized compartments for the current last time in m_normalizedpopulations. + * + * The normalized compartments are computed as populations / m_populationsize. + */ + void compute_normalizedcompartments(); + + /** + * @brief Computes the force of infection for the current last time in transitions. + * + * Computed value is stored in m_forceofinfection. + * + * @param[in] dt Time discretization step size. + */ + void compute_forceofinfection(ScalarType dt); + + // ---- Private parameters. ---- + + TimeSeries m_forceofinfection{ + TimeSeries(1)}; ///< TimeSeries containing the Force of infection term for every time point, + // needed for the numerical scheme. + TimeSeries m_totalpopulation{TimeSeries( + 1)}; ///< TimeSeries containing the total population size of the considered region for each time point. + TimeSeries m_totalpopulation_derivative{TimeSeries( + 1)}; ///< TimeSeries containing the derivative of the total population size of the considered + // region for each time point. + TimeSeries m_normalizedpopulations{ + TimeSeries(Eigen::Index(InfectionState::Count) - + 1)}; ///< TimeSeries containing points of time and the corresponding portion + // of people in defined #IndectionState%s. + + // ---- Friend classes/functions. ---- + // In the Simulation class, the actual simulation is performed which is why it needs access to the here + // defined (and private) functions to solve the model equations. + friend class Simulation; +}; + +} // namespace endisird +} // namespace mio + +#endif //IDE_END_SIRD_MODEL_H \ No newline at end of file diff --git a/cpp/models/ide_endemic_sird/normalized_model.cpp b/cpp/models/ide_endemic_sird/normalized_model.cpp new file mode 100644 index 0000000000..4708ec2770 --- /dev/null +++ b/cpp/models/ide_endemic_sird/normalized_model.cpp @@ -0,0 +1,235 @@ +#include "ide_endemic_sird/normalized_model.h" +#include "ide_endemic_sird/computed_parameters.h" +#include "ide_endemic_sird/model.h" +#include "ide_endemic_sird/parameters.h" +#include "ide_endemic_sird/infection_state.h" +#include "memilio/config.h" +#include "memilio/utils/logging.h" + +#include "memilio/utils/time_series.h" +#include "vector" +#include +#include +#include +#include +#include +#include +#include + +namespace mio +{ +namespace endisird +{ + +NormModel::NormModel(CompParameters const& compparams) + : compparameters{std::make_shared(compparams)} + , transitions{TimeSeries(Eigen::Index(InfectionTransition::Count))} + , populations{TimeSeries(Eigen::Index(InfectionState::Count) - 1)} +{ + //Set populations at start time t0. + TimeSeries::Vector vec_initnormalizedpopulations = + TimeSeries::Vector(Eigen::Index(InfectionState::Count) - 1); + for (int infection_state = 0; infection_state < Eigen::Index(InfectionState::Count) - 1; infection_state++) { + vec_initnormalizedpopulations[infection_state] = + compparameters->m_statesinit[0][infection_state] / compparameters->m_totalpopulationinit; + } + populations.add_time_point(0, vec_initnormalizedpopulations); + + // Set flows at start time t0. + // As we assume that all individuals have infectio age 0 at time t0, the flows at t0 are set to 0. + transitions.add_time_point( + 0, TimeSeries::Vector::Constant(static_cast(InfectionTransition::Count), 0.)); + + m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, compparameters->m_NormFoI_0[0])); +} + +bool NormModel::check_constraints() const +{ + if (!(static_cast(populations.get_num_elements()) == static_cast(InfectionState::Count) - 1)) { + log_error(" A variable given for model construction is not valid. Number of elements in vector of populations " + "does not match the required number."); + return true; + } + + for (int i = 0; i < static_cast(InfectionState::Count) - 1; i++) { + if (populations[0][i] < 0) { + log_error("Initialization failed. Initial values for populations are less than zero."); + return true; + } + } + return compparameters->check_constraints(); +} + +// ----Functionality for the iterations of a simulation. ---- +void NormModel::compute_susceptibles(ScalarType dt) +{ + Eigen::Index num_time_points = populations.get_num_time_points(); + populations.get_last_value()[static_cast(InfectionState::Susceptible)] = + (populations[num_time_points - 2][static_cast(InfectionState::Susceptible)] + + dt * compparameters->parameters.get()) / + (1 + dt * (m_forceofinfection[num_time_points - 2][0] + compparameters->parameters.get()) - + transitions[num_time_points - 2][(Eigen::Index)InfectionTransition::InfectedToDead]); +} + +void NormModel::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, Eigen::Index current_time_index, ScalarType dt) +{ + Eigen::Index calc_time_index = + (Eigen::Index)std::ceil(compparameters->m_transitiondistributions_support_max[idx_InfectionTransitions] / dt); + ScalarType current_time_age = static_cast(current_time_index) * dt; + ScalarType sum = 0; + //Determine the starting point of the for loop. + Eigen::Index starting_point = std::max(0, (int)current_time_index - (int)calc_time_index); + + for (Eigen::Index i = starting_point; i < current_time_index; i++) { + ScalarType state_age_i = static_cast(i) * dt; + + sum += + (transitions[i + 1][idx_IncomingFlow] + (compparameters->parameters.get() + + transitions[i][(Eigen::Index)InfectionTransition::InfectedToDead] - + compparameters->parameters.get()) * + populations[i][idx_CurrentCompartment]) * + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)) * + compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index - i]; + } + if (current_time_index <= calc_time_index) { + transitions.get_value(current_time_index)[idx_InfectionTransitions] = + (-dt) * compparameters->parameters.get()[idx_InfectionTransitions] * sum - + std::exp((-compparameters->parameters.get()) * (current_time_age)) * + populations[0][idx_CurrentCompartment] * + compparameters->parameters.get()[idx_InfectionTransitions] * + compparameters->m_transitiondistributions_derivative[idx_InfectionTransitions][current_time_index]; + } + else { + transitions.get_value(current_time_index)[idx_InfectionTransitions] = + (-dt) * compparameters->parameters.get()[idx_InfectionTransitions] * sum; + } +} + +void NormModel::compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, ScalarType dt) +{ + Eigen::Index current_time_index = transitions.get_num_time_points() - 1; + compute_flow(idx_InfectionTransitions, idx_IncomingFlow, idx_CurrentCompartment, current_time_index, dt); +} + +void NormModel::flows_currents_timestep(ScalarType dt) +{ + Eigen::Index current_time_index = populations.get_num_time_points() - 1; + // Calculate the transition SusceptibleToExposed with force of infection from previous time step and Susceptibles from + // current time step. + transitions.get_last_value()[static_cast(InfectionTransition::SusceptibleToInfected)] = + m_forceofinfection[current_time_index - 1][0] * + populations.get_last_value()[static_cast(InfectionState::Susceptible)]; + + // Calculate the other Transitions with compute_flow. + // Calculate the other Transitions with compute_flow. + // Infected To Dead: + compute_flow(Eigen::Index(InfectionTransition::InfectedToDead), + Eigen::Index(InfectionTransition::SusceptibleToInfected), Eigen::Index(InfectionState::Infected), dt); + // Infected To Recovered: + compute_flow(Eigen::Index(InfectionTransition::InfectedToRecovered), + Eigen::Index(InfectionTransition::SusceptibleToInfected), Eigen::Index(InfectionState::Infected), dt); +} + +void NormModel::update_compartment_with_sum(InfectionState infectionState, + std::vector const& IncomingFlows, + bool Transitionispossible, ScalarType dt) +{ + Eigen::Index current_time_index = populations.get_num_time_points() - 1; + ScalarType current_time_age = (ScalarType)current_time_index * dt; + Eigen::Index calc_time_index = current_time_index; + if (Transitionispossible) { + calc_time_index = compparameters->m_transitiondistributions.size() - 1; + } + + ScalarType sum = 0; + + Eigen::Index starting_point = std::max(0, (int)current_time_index - (int)calc_time_index); + for (int i = starting_point; i < current_time_index; i++) { + ScalarType state_age_i = (ScalarType)i * dt; + ScalarType sum_inflows = 0; + for (const InfectionTransition& inflow : IncomingFlows) { + sum_inflows += transitions[i + 1][(int)inflow]; + } + if (Transitionispossible) { + sum += compparameters->m_transitiondistributions[current_time_index - i] * + (sum_inflows + (compparameters->parameters.get() + + transitions[i][(Eigen::Index)InfectionTransition::InfectedToDead] - + compparameters->parameters.get()) * + populations[i][(int)infectionState]) * + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)); + } + else { + sum += (sum_inflows + (compparameters->parameters.get() + + transitions[i][(Eigen::Index)InfectionTransition::InfectedToDead] - + compparameters->parameters.get()) * + populations[i][(int)infectionState]) * + std::exp(-compparameters->parameters.get() * (current_time_age - state_age_i)); + } + } + if (Transitionispossible) { + if (current_time_index <= calc_time_index) { + populations.get_last_value()[(int)infectionState] = + dt * sum + compparameters->m_transitiondistributions[current_time_index] * + populations[0][(int)infectionState] * + std::exp(-compparameters->parameters.get() * (current_time_age)); + } + else { + populations.get_last_value()[(int)infectionState] = dt * sum; + } + } + else { + populations.get_last_value()[(int)infectionState] = + dt * sum + populations[0][(int)infectionState] * + std::exp(-compparameters->parameters.get() * (current_time_age)); + } +} + +void NormModel::update_compartments(ScalarType dt) +{ + + // Infected + update_compartment_with_sum(InfectionState::Infected, {InfectionTransition::SusceptibleToInfected}, true, dt); + // Recovered + update_compartment_with_sum(InfectionState::Recovered, + { + InfectionTransition::InfectedToRecovered, + }, + true, dt); +} + +void NormModel::compute_forceofinfection(ScalarType dt) +{ + + Eigen::Index num_time_points = populations.get_num_time_points(); + ScalarType current_time = populations.get_last_time(); + + // Determine the starting point of the for loop. + Eigen::Index starting_point1 = std::max(0, (int)num_time_points - 1 - (int)compparameters->m_infectivity.size()); + + ScalarType sum = 0.; + // Compute the first sum in the force of infection term. + for (Eigen::Index i = starting_point1; i < num_time_points - 1; i++) { + sum += compparameters->m_infectivity[num_time_points - 1 - i] * + (populations[i + 1][(int)InfectionState::Susceptible] * m_forceofinfection[i][0] + + (compparameters->parameters.get() + + transitions[i + 1][(int)InfectionTransition::InfectedToDead] - + compparameters->parameters.get()) * + populations[i + 1][(int)InfectionState::Infected]); + } + + m_forceofinfection.get_last_value()[0] = + dt * sum * + (compparameters->parameters.get().eval(current_time) * + compparameters->parameters.get().get_cont_freq_mat().get_matrix_at(current_time)(0, 0)); + + // Add inital functions for the force of infection in case they still have an influence. + if (num_time_points <= (int)compparameters->m_NormFoI_0.size()) { + m_forceofinfection.get_last_value()[0] += compparameters->m_NormFoI_0[num_time_points - 1]; + } +} + +} // namespace endisird + +} // namespace mio \ No newline at end of file diff --git a/cpp/models/ide_endemic_sird/normalized_model.h b/cpp/models/ide_endemic_sird/normalized_model.h new file mode 100644 index 0000000000..97e877c749 --- /dev/null +++ b/cpp/models/ide_endemic_sird/normalized_model.h @@ -0,0 +1,155 @@ +#ifndef IDE_END_SIRD_NORMMODEL_H +#define IDE_END_SIRD_NORMMODEL_H + +#include "ide_endemic_sird/infection_state.h" +#include "ide_endemic_sird/parameters.h" +#include "ide_endemic_sird/computed_parameters.h" +#include "ide_endemic_sird/model.h" +#include "memilio/config.h" +#include "memilio/utils/time_series.h" + +#include "vector" +#include +#include +#include + +namespace mio +{ +namespace endisird +{ + +// Forward declaration of friend classes/functions of Model. +class NormModel; +class Simulation; + +class NormModel +{ + using ParameterSet = Parameters; + +public: + /** + * @brief Constructor to create an endemic IDE_SECIR model. + * + * @param[in] TODO!!!!!! + */ + + NormModel(CompParameters const& compparams); + + /** + * @brief Checks constraints on model parameters and initial data. + * @return Returns true if one (or more) constraint(s) are not satisfied, otherwise false. + */ + bool check_constraints() const; + + // ---- Public parameters. ---- + std::shared_ptr compparameters; + TimeSeries + transitions; ///< TimesSeries containing points of time and the corresponding number of individuals transitioning + // from one #InfectionState to another as defined in #Infection%s. + TimeSeries populations; ///< TimeSeries containing points of time and the corresponding number of people + // in defined #InfectionState%s. + +private: + // ---- Functionality for the iterations of a simulation. + + /** + * @brief Computes number of Susceptibles for the current last time in populations. + * + * Number is computed by using the previous number of Susceptibles, total population of the last time point and + * the force of infection (also from the last time point). + * Number is stored at the matching index in populations. + * + * @param[in] dt Time discretization step size. + */ + void compute_susceptibles(ScalarType dt); + + /** + * @brief Computes sizeof a flow + * + * Computes size of one Transition from #InfectionTransition, specified in idx_InfectionTransitions, for the time index + * current_time_index. + * + * @param[in] idx_InfectionTransitions Specifies the considered transition from #InfectionTransition + * @param[in] idx_IncomingFlow Index of the transition in #InfectionTransition, which goes to the considered starting + * compartment of the transition specified in idx_InfectionTransitions. Size of considered flow is calculated via + * the value of this incoming flow. + * @param[in] idx_CurrentCompartment Index of the Compartment we flow out. + * @param[in] current_time_index The time index the transition should be computed for. + * @param[in] dt Time discretization step size. + */ + void compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, Eigen::Index current_time_index, ScalarType dt); + + /** + * @brief Computes size of a flow + * + * Computes size of one Transition from #InfectionTransition, specified in idx_InfectionTransitions, for the current + * last time value in transitions. + * + * @param[in] idx_InfectionTransitions Specifies the considered transition from #InfectionTransition + * @param[in] idx_IncomingFlow Index of the transition in #InfectionTransition, which goes to the considered starting + * compartment of the transition specified in idx_InfectionTransitions. Size of considered flow is calculated via + * the value of this incoming flow. + * @param[in] idx_CurrentCompartment Index of the Compartment we flow out. + * @param[in] dt Time discretization step size. + */ + void compute_flow(Eigen::Index idx_InfectionTransitions, Eigen::Index idx_IncomingFlow, + Eigen::Index idx_CurrentCompartment, ScalarType dt); + + /** + * @brief Sets all required transitions for the current last timestep in transitions. + * + * New values are stored in transitions. Most values are computed via the function compute_flow() + * + * @param[in] dt time discretization step size. + */ + void flows_currents_timestep(ScalarType dt); + + /** + * @brief Updates the values of one compartment, specified in infectionState, using all past transitions. + * + * New value is stored in populations. The values are calculated using all past values for the incoming flows + * including the current time step. + * Therefore the flows of the current time step should be calculated before using this function. + * @param[in] infectionState Specifies the #InfectionState we want to update. + * @param[in] IncomingFlows + * @param[in] NaturalDeathispossible Boolian that determines if there is the possibility of Natural Death in infectionState. + * @param[in] Transitionispossible Boolian that determines if it is possible to transition from the current InfectionState + * into another + * @param[in] dt + */ + void update_compartment_with_sum(InfectionState infectionState, + std::vector const& IncomingFlows, bool Transitionispossible, + ScalarType dt); + + /** + * @brief Updates the values of all compartments except Susceptible + * + * New value is stored in populations. Values are computed via the function update_compartment_from_flow + */ + void update_compartments(ScalarType dt); + + /** + * @brief Computes the force of infection for the current last time in transitions. + * + * Computed value is stored in m_forceofinfection. + * + * @param[in] dt Time discretization step size. + */ + void compute_forceofinfection(ScalarType dt); + + // ---- Private parameters. ---- + + TimeSeries m_forceofinfection{ + TimeSeries(1)}; ///< TimeSeries containing the Force of infection term for every time point, + + // ---- Friend classes/functions. ---- + // In the Simulation class, the actual simulation is performed which is why it needs access to the here + // defined (and private) functions to solve the model equations. + friend class Simulation; +}; + +} // namespace endisird +} // namespace mio + +#endif // IDE_END_SIRD_NORMMODEL_H \ No newline at end of file diff --git a/cpp/models/ide_endemic_sird/parameters.h b/cpp/models/ide_endemic_sird/parameters.h new file mode 100644 index 0000000000..e9b64fc3a3 --- /dev/null +++ b/cpp/models/ide_endemic_sird/parameters.h @@ -0,0 +1,244 @@ +#ifndef IDE_END_SIRD_PARAMS_H +#define IDE_END_SIRD_PARAMS_H + +#include "memilio/config.h" +#include "memilio/epidemiology/contact_matrix.h" +#include "memilio/math/floating_point.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/utils/parameter_set.h" +#include "ide_endemic_sird/infection_state.h" +#include "memilio/epidemiology/state_age_function.h" +#include "memilio/epidemiology/uncertain_matrix.h" + +#include +#include +#include + +namespace mio +{ +namespace endisird +{ + +/************************************************** +* Define Parameters of the IDE-END-SIRD model * +**************************************************/ + +/** + * @brief Transitions distribution for each transition in #Infection Transition. + * + * we use as a default SmootherCosine functions for all transitions with m_paramter=2. + */ + +struct TransitionDistributions { + using Type = std::vector; + static Type get_default() + { + SmootherCosine smoothcos(2.0); + StateAgeFunctionWrapper delaydistribution(smoothcos); + return Type((int)InfectionTransition::Count, delaydistribution); + } + + static std::string mame() + { + return "TransitionDistributions"; + } +}; + +/** + * @brief Defines the probability for each possible transitions to take this transition- + */ + +struct TransitionProbabilities { + /*For consistency, also define TransitionProbabilities for each transition in #InfectionTransition. + Transition Probabilities should be set to 1 if there is no possible other flow from starting compartment.*/ + using Type = std::vector; + static Type get_default() + { + std::vector probs((int)InfectionTransition::Count, 0.5); + // Set the following probablities to 1 as there is no other option to go anywhere else. + probs[Eigen::Index(InfectionTransition::SusceptibleToInfected)] = 1; + return Type(probs); + } + static std::string name() + { + return "TransitionsProbabilities"; + } +}; + +/** + * @brief The contact patterns within the society are modelled using an UncertainContactMatrix. + */ +struct ContactPatterns { + using Type = UncertainContactMatrix; + static Type get_default() + { + ContactMatrixGroup contact_matrix = ContactMatrixGroup(1, 1); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); + return Type(contact_matrix); + } + static std::string name() + { + return "ContactPatterns"; + } +}; + +/** +* @brief Probability of getting infected from a contact. +*/ +struct TransmissionProbabilityOnContact { + using Type = StateAgeFunctionWrapper; + static Type get_default() + { + ConstantFunction constfunc(1.0); + return Type(constfunc); + } + static std::string name() + { + return "TransmissionProbabilityOnContact"; + } +}; + +/** +* @brief The risk of infection from symptomatic cases in the SECIR model. +*/ +struct RiskOfInfectionFromSymptomatic { + using Type = StateAgeFunctionWrapper; + static Type get_default() + { + ConstantFunction constfunc(1.0); + return Type(constfunc); + } + static std::string name() + { + return "RiskOfInfectionFromSymptomatic"; + } +}; + +/** + * @brief The natural birth rate. + */ +struct NaturalBirthRate { + using Type = ScalarType; + static Type get_default() + { + return Type(5e-5); + } + static std::string name() + { + return "NaturalBirthRate"; + } +}; + +/** + * @brief The natural death rate. + */ +struct NaturalDeathRate { + using Type = ScalarType; + static Type get_default() + { + return Type(3e-5); + } + static std::string name() + { + return "NaturalDeathRate"; + } +}; + +// Define Parameterset for IDE-END-SECIR model. +using ParametersBase = + ParameterSet; + +/** + * @brief Parameters of an endemic SECIR/SECIHURD model. + */ + +class Parameters : public ParametersBase +{ +public: + /** + * @brief Checks whether all Parameters satisfy their corresponding constraints and logs an error. + */ + bool check_constraints() const + { + // For paramerers potentially depending on the infectious age, the values are checked equidistantly on a + // realistic maximum window. + size_t infectious_window_check = 50; // parameter defining minmal window on x-axis. + + //Check if all the probabilitys are between 0 and 1. + for (size_t i = 0; i < infectious_window_check; i++) { + if (this->get().eval((static_cast(i))) < 0.0 || + this->get().eval(static_cast(i)) > 1.0) { + log_error( + "Constraint check: TransmissionProbabilityOnContact smaller {:d} or larger {:d} at some time {:d}", + 0, 1, i); + return true; + } + } + + for (size_t i = 0; i < infectious_window_check; i++) { + if (this->get().eval((static_cast(i))) < 0.0 || + this->get().eval(static_cast(i)) > 1.0) { + log_error( + "Constraint check: RiskOfInfectionFromSymptomatic smaller {:d} or larger {:d} at some time {:d}", 0, + 1, i); + return true; + } + } + + for (size_t i = 0; i < static_cast(InfectionTransition::Count); i++) { + if (this->get()[i] < 0.0 || this->get()[i] > 1.0) { + log_error("Constraint check: One parameter in TransitionProbabilities smaller {:d} or larger {:d}", 0, + 1); + return true; + } + } + + // The TransitionProbabilitie SusceptibleToInfected should be 1. + if (!floating_point_equal( + this->get()[static_cast(InfectionTransition::SusceptibleToInfected)], 1.0, + 1e-14)) { + log_error("Constraint check: Parameter transition probability for SusceptibleToExposed unequal to {:d}", 1); + return true; + } + + // All TransitionProbabilities where the Transition starts in the same compartment should sum up to 1. + + if (!floating_point_equal( + this->get()[static_cast(InfectionTransition::InfectedToDead)] + + this->get()[static_cast(InfectionTransition::InfectedToRecovered)], + 1.0, 1e-14)) { + log_error("Constraint check: Sum of transition probability for InfectedToDead and " + "InfectedToRecovered not equal to {:d}", + 1); + return true; + } + + /* The first entry of TransitionDistributions is not checked because the distribution S->E is never used + (and it makes no sense to use the distribution). The support does not need to be valid.*/ + for (size_t i = 1; i < static_cast(InfectionTransition::Count); i++) { + if (floating_point_less(this->get()[i].get_support_max(10), 0.0, 1e-14)) { + log_error("Constraint check: One function in TransitionDistributions has invalid support."); + return true; + } + } + + if (this->get() < 0.0) { + log_warning("Constraint check: Parameter NaturalBirthRate should be greater than {:d}", 0); + return true; + } + + if (this->get() < 0.0) { + log_warning("Constraint check: Parameter NaturalDeathRate should be greater than {:d}", 0); + return true; + } + + return false; + } +}; + +} // namespace endisird + +} // namespace mio + +#endif //IDE_END_SIRD_PARAMS_H \ No newline at end of file diff --git a/cpp/models/ide_endemic_sird/simulation.cpp b/cpp/models/ide_endemic_sird/simulation.cpp new file mode 100644 index 0000000000..07b96edccf --- /dev/null +++ b/cpp/models/ide_endemic_sird/simulation.cpp @@ -0,0 +1,107 @@ + +#include "ide_endemic_sird/simulation.h" +#include "ide_endemic_sird/computed_parameters.h" +#include "ide_endemic_sird/model.h" +#include "ide_endemic_sird/normalized_model.h" +#include "memilio/config.h" +#include "memilio/utils/time_series.h" +#include + +namespace mio +{ +namespace endisird +{ + +void Simulation::advance(ScalarType tmax) +{ + mio::log_info("Simulating IDE-END-SECIR from t0 = {} until tmax = {} with dt = {}.", + m_model->transitions.get_last_time(), tmax, m_dt); + + m_model->compparameters->set_transitiondistributions_support_max(m_dt); + m_model->compparameters->set_transitiondistributions(m_dt); + m_model->compparameters->set_transitiondistributions_derivative(m_dt); + m_model->compparameters->set_infectivity(m_dt); + m_model->compparameters->set_FoI_0(m_dt); + m_model->compparameters->set_reproductionnumber_c(m_dt); + m_model->compparameters->set_T(m_dt); + m_model->compparameters->set_W(m_dt); + + m_normmodel->compparameters->set_transitiondistributions_support_max(m_dt); + m_normmodel->compparameters->set_transitiondistributions(m_dt); + m_normmodel->compparameters->set_transitiondistributions_derivative(m_dt); + m_normmodel->compparameters->set_infectivity(m_dt); + m_normmodel->compparameters->set_FoI_0(m_dt); + m_normmodel->compparameters->set_reproductionnumber_c(m_dt); + m_normmodel->compparameters->set_T(m_dt); + m_normmodel->compparameters->set_W(m_dt); + + m_difference_normalizedcompartments.add_time_point(0); + m_difference_normalizedFoI.add_time_point(0); + compute_difference_normalizations(); + + // For every time step: + while (m_model->transitions.get_last_time() < tmax - m_dt / 2) { + + m_difference_normalizedcompartments.add_time_point(m_difference_normalizedcompartments.get_last_time() + m_dt); + m_difference_normalizedFoI.add_time_point(m_difference_normalizedFoI.get_last_time() + m_dt); + //standard model : + m_model->transitions.add_time_point(m_model->transitions.get_last_time() + m_dt); + m_model->populations.add_time_point(m_model->populations.get_last_time() + m_dt); + m_model->m_forceofinfection.add_time_point(m_model->m_forceofinfection.get_last_time() + m_dt); + m_model->m_totalpopulation.add_time_point(m_model->m_totalpopulation.get_last_time() + m_dt); + m_model->m_totalpopulation_derivative.add_time_point(m_model->m_totalpopulation_derivative.get_last_time() + + m_dt); + m_model->m_normalizedpopulations.add_time_point(m_model->m_normalizedpopulations.get_last_time() + m_dt); + + // Compute susceptibles: + m_model->compute_susceptibles(m_dt); + + // Compute flows: + m_model->flows_currents_timestep(m_dt); + + // Compute remaining compartments: + m_model->update_compartments(m_dt); + + // Compute m_populationsize: + m_model->compute_populationsize(); + + // Compute normalized compartments: + m_model->compute_normalizedcompartments(); + + // Compute m_forceofinfection; + m_model->compute_forceofinfection(m_dt); + + // normalized model: + m_normmodel->transitions.add_time_point(m_normmodel->transitions.get_last_time() + m_dt); + m_normmodel->populations.add_time_point(m_normmodel->populations.get_last_time() + m_dt); + m_normmodel->m_forceofinfection.add_time_point(m_normmodel->m_forceofinfection.get_last_time() + m_dt); + + // Compute susceptibles: + m_normmodel->compute_susceptibles(m_dt); + + // Compute flows: + m_normmodel->flows_currents_timestep(m_dt); + + // Compute remaining compartments: + m_normmodel->update_compartments(m_dt); + + // Compute m_forceofinfection; + m_normmodel->compute_forceofinfection(m_dt); + + //Compute the difference of the two normalized compartments. + compute_difference_normalizations(); + } +} + +TimeSeries simulate(ScalarType tmax, ScalarType dt, CompParameters const& m_compparams, + Model const& m_model, NormModel const& m_normmodel) +{ + m_model.check_constraints(); + Simulation sim(m_compparams, m_model, m_normmodel, dt); + sim.advance(tmax); + return sim.get_compartments(); +} + +} // namespace endisird + +} // namespace mio diff --git a/cpp/models/ide_endemic_sird/simulation.h b/cpp/models/ide_endemic_sird/simulation.h new file mode 100644 index 0000000000..8606db574c --- /dev/null +++ b/cpp/models/ide_endemic_sird/simulation.h @@ -0,0 +1,237 @@ +#ifndef IDE_END_SIRD_SIMULATION_H +#define IDE_END_SIRD_SIMULATION_H + +#include "ide_endemic_sird/computed_parameters.h" +#include "ide_endemic_sird/model.h" +#include "ide_endemic_sird/normalized_model.h" +#include "memilio/config.h" +#include "memilio/utils/miompi.h" +#include "memilio/utils/time_series.h" +#include +#include + +namespace mio +{ +namespace endisird +{ +class Simulation +{ +public: + Simulation(CompParameters const& compparams, Model const& model, NormModel const& normmodel, ScalarType dt = 0.1) + : m_compparams(std::make_unique(compparams)) + , m_model(std::make_unique(model)) + , m_normmodel(std::make_unique(normmodel)) + , m_dt(dt) + { + } + + /** + * @brief Run the simulation until time tmax. + */ + void advance(ScalarType tmax); + + /** + * @brief Get the result of the simulation for the compartments of m_model + * Return the number of persons in all #InfectionState%s + */ + TimeSeries get_compartments() + { + return m_model->populations; + } + + /** + * @brief Get the result of the simulation for the normalized compartments, where we use m_model and the compartments + * computed using the sum scheme. + * Return the number of persons in all #InfectionState%s + */ + TimeSeries get_normalizedcompartments() + { + return m_model->m_normalizedpopulations; + } + /** + * @brief Get the result of the simulation for the compartments of the normalized model. + * Return the number of persons in all #InfectionState%s + */ + TimeSeries get_normmodel_compartments() + { + return m_normmodel->populations; + } + + /** + * @brief Get the result of the simulation for the compartments. + * Return the number of persons in all #InfectionState%s + */ + TimeSeries& get_compartments() const + { + return m_model->populations; + } + + /** + * @brief Get the result of the simulation for the normalized compartments, where we use m_model. + * Return the number of persons in all #InfectionState%s + */ + TimeSeries& get_normalizedcompartments() const + { + return m_model->m_normalizedpopulations; + } + + /** + * @brief Get the result of the simulation for the compartments of the normalized model. + * Return the number of persons in all #InfectionState%s + */ + TimeSeries& get_normmodel_compartments() const + { + return m_normmodel->populations; + } + + /** + * @brief Get the transitions between the different #InfectionState%s for m_model. + */ + TimeSeries const& get_transitions() + { + return m_model->transitions; + } + /** + * @brief Get the transitions between the different #InfectionState%s of m_normmodel. + */ + TimeSeries const& get_normmodel_transitions() + { + return m_normmodel->transitions; + } + + /** + * @brief Get the force of infection term of m_model. + */ + TimeSeries const& get_forceofinfections() + { + return m_model->m_forceofinfection; + } + + /** + * @brief Get the force of infection term of m_normmodel. + */ + TimeSeries const& get_normmodel_forceofinfections() + { + return m_normmodel->m_forceofinfection; + } + + /** + * @brief Get the total population of m_model. + */ + TimeSeries const& get_totalpopulations() + { + return m_model->m_totalpopulation; + } + + /** + * @brief Get the derivative of the total population of m_model. + */ + TimeSeries const& get_totalpopulations_derivative() + { + return m_model->m_totalpopulation_derivative; + } + + /** + * @brief Get the reproduction numer. + */ + ScalarType const& get_reproductionnumber_c() + { + return m_model->compparameters->m_reproductionnumber_c; + } + + /** + * @brief Get T. + */ + std::vector const& get_T() + { + return m_model->compparameters->m_T; + } + + /** + * @brief Get W. + */ + ScalarType const& get_W() + { + return m_model->compparameters->m_W; + } + + /** + * @brief returns the simulation model used in simulation. + */ + const Model& get_model() const + { + return *m_model; + } + + /** + * @brief returns the simulation model used in simulation. + */ + Model& get_model() + { + return *m_model; + } + + /** + * @brief returns the simulation normmodel used in simulation. + */ + const NormModel& get_normmodel() const + { + return *m_normmodel; + } + + /** + * @brief returns the simulation normmodel used in simulation. + */ + NormModel& get_normmodel() + { + return *m_normmodel; + } + + /** + * @brief get the size of the time step of the simulation. + */ + ScalarType get_stepsize() + { + return m_dt; + } + + void compute_difference_normalizations() + { + for (int state = 0; state < (int)InfectionState::Count - 1; state++) { + m_difference_normalizedcompartments.get_last_value()[state] = + std::abs(m_normmodel->populations.get_last_value()[state] - + m_model->m_normalizedpopulations.get_last_value()[state]); + } + m_difference_normalizedFoI.get_last_value()[0] = std::abs(m_normmodel->m_forceofinfection.get_last_value()[0] - + m_model->m_forceofinfection.get_last_value()[0]); + } + + TimeSeries const& get_difference_normalizationcomp() + { + return m_difference_normalizedcompartments; + } + + TimeSeries const& get_difference_normalizationFoi() + { + return m_difference_normalizedFoI; + } + +private: + std::unique_ptr m_compparams; ///< Unique pointer to the computed Parameters. + std::unique_ptr m_model; ///< Unique pointer to the simulated Model. + std::unique_ptr m_normmodel; ///< Unique pointer to the simulated normalized Model. + ScalarType m_dt; ///< Time step used for numerical computations in simulation. + TimeSeries m_difference_normalizedcompartments{TimeSeries( + (int)InfectionState::Count - 1)}; ///< TimeSeries containing the difference of the compartments + // computed by NormModel and the normalized compartments computed in Model. + TimeSeries m_difference_normalizedFoI{ + TimeSeries(1)}; ///< TimeSeries containing the difference of the force of infection terms + // computed by NormModel and Model. +}; + +TimeSeries simulate(ScalarType tmax, ScalarType dt, Model const& model); + +} // namespace endisird +} // namespace mio + +#endif //IDE_END_SIRD_SIMULATION_H \ No newline at end of file From ac971719d48c89bddbb0c66e16098e2917dc6939 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Wed, 3 Sep 2025 13:11:30 +0200 Subject: [PATCH 20/22] added examples for sird model --- cpp/examples/CMakeLists.txt | 8 + cpp/examples/ide_endemic_secir.cpp | 24 +-- .../ide_endemic_secir_save_results.cpp | 14 +- cpp/examples/ide_endemic_sird.cpp | 152 ++++++++++++++ .../ide_endemic_sird_save_results.cpp | 190 ++++++++++++++++++ cpp/models/ide_endemic_secir/simulation.cpp | 62 +++--- .../ide_endemic_sird/computed_parameters.h | 2 +- 7 files changed, 401 insertions(+), 51 deletions(-) create mode 100644 cpp/examples/ide_endemic_sird.cpp create mode 100644 cpp/examples/ide_endemic_sird_save_results.cpp diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index bc607a6eeb..a255394e3a 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -108,6 +108,10 @@ add_executable(ide_endemic_secir_example ide_endemic_secir.cpp) target_link_libraries(ide_endemic_secir_example PRIVATE memilio ide_endemic_secir) target_compile_options(ide_endemic_secir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ide_endemic_sird_example ide_endemic_sird.cpp) +target_link_libraries(ide_endemic_sird_example PRIVATE memilio ide_endemic_sird) +target_compile_options(ide_endemic_sird_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(ide_seir_example ide_seir.cpp) target_link_libraries(ide_seir_example PRIVATE memilio ide_seir) target_compile_options(ide_seir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) @@ -190,4 +194,8 @@ if(MEMILIO_HAS_HDF5) add_executable(ide_endemic_secir_save_results_example ide_endemic_secir_save_results.cpp) target_link_libraries(ide_endemic_secir_save_results_example PRIVATE memilio ide_endemic_secir) target_compile_options(ide_endemic_secir_save_results_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + + add_executable(ide_endemic_sird_save_results_example ide_endemic_sird_save_results.cpp) + target_link_libraries(ide_endemic_sird_save_results_example PRIVATE memilio ide_endemic_sird) + target_compile_options(ide_endemic_sird_save_results_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) endif() \ No newline at end of file diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index 9d2f580349..905cc5f153 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -19,8 +19,8 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 1; - ScalarType dt = 0.00001; + ScalarType tmax = 1000; + ScalarType dt = 1.0; int num_states = static_cast(mio::endisecir::InfectionState::Count); int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); @@ -45,14 +45,14 @@ int main() //Set working parameters - mio::ExponentialSurvivalFunction exp(3.0); - mio::StateAgeFunctionWrapper delaydistribution(exp); - std::vector vec_delaydistribution(num_transitions, delaydistribution); - - // mio::SmootherCosine smoothcos(2.0); - // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + // mio::ExponentialSurvivalFunction exp(3.0); + // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); + mio::SmootherCosine smoothcos(6.0); + mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + std::vector vec_delaydistribution(num_transitions, delaydistribution); + // Uncomment for Lognorm. // mio::ConstantFunction initialfunc(0); // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); @@ -123,8 +123,8 @@ int main() computed_parameters.parameters.get() = exponential_prob; computed_parameters.parameters.get() = exponential_prob; - computed_parameters.parameters.set(4e-3); - computed_parameters.parameters.set(3e-3); + computed_parameters.parameters.set(4e-1); + computed_parameters.parameters.set(3e-1); computed_parameters.set_tol_for_support_max(1e-6); @@ -137,8 +137,8 @@ int main() sim.advance(tmax); //Get the compartments of model and print them. - auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); - interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); + auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); + interpolated_results.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 16, 8); // Uncomment to print the compartments computed with the update scheme. // auto interpolated_results_update = mio::interpolate_simulation_result(sim.get_compartments_update(), dt / 2.); // interpolated_results_update.print_table({"US", "UE", "UC", "UI", "UH", "UU", "UR", "UD"}, 16, 8); diff --git a/cpp/examples/ide_endemic_secir_save_results.cpp b/cpp/examples/ide_endemic_secir_save_results.cpp index ba163c9e33..87063cf009 100644 --- a/cpp/examples/ide_endemic_secir_save_results.cpp +++ b/cpp/examples/ide_endemic_secir_save_results.cpp @@ -133,8 +133,8 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = computed_parameters.parameters.get() = exponential_prob; computed_parameters.parameters.get() = exponential_prob; - computed_parameters.parameters.set(4e-4); - computed_parameters.parameters.set(3e-4); + computed_parameters.parameters.set(4e-3); + computed_parameters.parameters.set(3e-3); //computed_parameters.set_tol_for_support_max(1e-6); @@ -164,7 +164,7 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = mio::save_result({sim.get_totalpopulations_derivative()}, {0}, 1, filename_ide_dertotalpopulation1); //Save compartments. - std::string filename_ide_compartments1 = filename_ide + "_compartments2.h5"; + std::string filename_ide_compartments1 = filename_ide + "_compartments1.h5"; mio::IOResult save_result_status_c1 = mio::save_result({sim.get_compartments()}, {0}, 1, filename_ide_compartments1); @@ -174,18 +174,18 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = mio::save_result({sim.get_normalizedcompartments()}, {0}, 1, filename_ide_normcompartments); //Save the force of infection. - std::string filename_ide_forceofinfection = filename_ide + "_forceofinfection2.h5"; + std::string filename_ide_forceofinfection = filename_ide + "_forceofinfection.h5"; mio::IOResult save_result_status_foi = mio::save_result({sim.get_forceofinfections()}, {0}, 1, filename_ide_forceofinfection); //Save files of NormModel. //Save compartments. - std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments2.h5"; + std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments.h5"; mio::IOResult save_result_status_nmc1 = mio::save_result({sim.get_normmodel_compartments()}, {0}, 1, filename_ide_normmod_compartments); //Save the force of infection. - std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection2.h5"; + std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection.h5"; mio::IOResult save_result_status_nmfoi = mio::save_result({sim.get_normmodel_forceofinfections()}, {0}, 1, filename_ide_normmod_forceofinfection); @@ -214,7 +214,7 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = int main() { - std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDE/simulation_results/"; + std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDESECIR/simulation_results/"; // Define tmax. ScalarType tmax = 2000; diff --git a/cpp/examples/ide_endemic_sird.cpp b/cpp/examples/ide_endemic_sird.cpp new file mode 100644 index 0000000000..4a21b61ad5 --- /dev/null +++ b/cpp/examples/ide_endemic_sird.cpp @@ -0,0 +1,152 @@ +#include "ide_endemic_sird/computed_parameters.h" +#include "ide_endemic_sird/model.h" +#include "ide_endemic_sird/infection_state.h" +#include "ide_endemic_sird/normalized_model.h" +#include "ide_endemic_sird/parameters.h" +#include "ide_endemic_sird/simulation.h" +#include "memilio/config.h" +#include "memilio/math/eigen.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/utils/time_series.h" +#include "memilio/epidemiology/uncertain_matrix.h" +#include "memilio/epidemiology/state_age_function.h" +#include "memilio/data/analyze_result.h" +#include +#include +#include + +int main() +{ + using Vec = mio::TimeSeries::Vector; + + ScalarType tmax = 50; + ScalarType dt = 1.0; + + int num_states = static_cast(mio::endisird::InfectionState::Count); + int num_transitions = static_cast(mio::endisird::InfectionTransition::Count); + + // Create TimeSeries with num_states elements where states needed for simulation will be stored. + mio::TimeSeries init(num_states); + + Vec vec_init(num_states); + + vec_init[static_cast(mio::endisird::InfectionState::Susceptible)] = 100000.; + vec_init[static_cast(mio::endisird::InfectionState::Infected)] = 40.; + vec_init[static_cast(mio::endisird::InfectionState::Recovered)] = 0.; + vec_init[static_cast(mio::endisird::InfectionState::Dead)] = 0.; + + init.add_time_point(0, vec_init); + + mio::endisird::CompParameters computed_parameters(std::move(init)); + + //Set working parameters + + // mio::ExponentialSurvivalFunction exp(3.0); + // mio::StateAgeFunctionWrapper delaydistribution(exp); + // std::vector vec_delaydistribution(num_transitions, delaydistribution); + + // mio::SmootherCosine smoothcos(2.0); + // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + // std::vector vec_delaydistribution(num_transitions, delaydistribution); + + mio::ConstantFunction initialfunc(0); + mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); + std::vector vec_delaydistribution(num_transitions, delaydistributioninit); + // InfectedToDead + mio::SmootherCosine survivalExposedToInfectedNoSymptoms(6.0); + vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToDead].set_state_age_function( + survivalExposedToInfectedNoSymptoms); + // InfectedToRecovered + mio::SmootherCosine survivalInfectedNoSymptomsToInfectedSymptoms(8.0); + vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToRecovered].set_state_age_function( + survivalInfectedNoSymptomsToInfectedSymptoms); + + // mio::ConstantFunction initialfunc(0); + // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); + // std::vector vec_delaydistribution(num_transitions, delaydistributioninit); + // // InfectedToDead + // mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.8, 0, 4.2); + // vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToDead].set_state_age_function( + // survivalExposedToInfectedNoSymptoms); + // // InfectedToRecovered + // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.2, 0, 0.8); + // vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToRecovered].set_state_age_function( + // survivalInfectedNoSymptomsToInfectedSymptoms); + + computed_parameters.parameters.get() = vec_delaydistribution; + + std::vector vec_prob((int)mio::endisird::InfectionTransition::Count, 1.); + vec_prob[Eigen::Index(mio::endisird::InfectionTransition::InfectedToDead)] = 0.1; + vec_prob[Eigen::Index(mio::endisird::InfectionTransition::InfectedToRecovered)] = 1 - 0.1; + + computed_parameters.parameters.set(vec_prob); + + mio::ContactMatrixGroup contact_matrix = mio::ContactMatrixGroup(1, 1); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); + computed_parameters.parameters.get() = mio::UncertainContactMatrix(contact_matrix); + + mio::ConstantFunction constant(0.1); + mio::StateAgeFunctionWrapper constant_prob(constant); + + computed_parameters.parameters.get() = constant_prob; + + mio::ExponentialSurvivalFunction exponential(0.5); + mio::StateAgeFunctionWrapper exponential_prob(exponential); + + computed_parameters.parameters.get() = exponential_prob; + + computed_parameters.parameters.set(4e-3); + computed_parameters.parameters.set(3e-3); + + computed_parameters.set_tol_for_support_max(1e-6); + + mio::endisird::Model model(computed_parameters); + + mio::endisird::NormModel normmodel(computed_parameters); + + // start the simulation. + mio::endisird::Simulation sim(computed_parameters, model, normmodel, dt); + sim.advance(tmax); + + //Get the compartments of model and print them. + auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); + interpolated_results.print_table({"S", "I", "R", "D "}, 16, 8); + + //Get the commpartments of normmodel and print them. + // auto interpolated_normresults = mio::interpolate_simulation_result(sim.get_normmodel_compartments(), dt / 2.); + // interpolated_normresults.print_table({"s", "i", "r"}, 16, 8); + + // Uncomment to print the normalized compartments of model. + // sim.get_normalizedcompartments().print_table({"S/N", "I/N", "R/N"}, 16, 8); + + // Uncomment to print the transitions of model. + // sim.get_transitions().print_table({"S->I", "I->D", "I->R"}, + // 16, 8); + + // Uncomment to print the transitions of normmodel. + // sim.get_normmodel_transitions().print_table( + // {"s->i", "i->d", "i->r }, 16, 8); + + // Uncomment to print the force of infection of model. + auto interpolated_FoI = mio::interpolate_simulation_result(sim.get_forceofinfections(), dt / 2.); + interpolated_FoI.print_table({"FoI"}, 16, 8); + + // Uncomment to print the force of infection of normmodel. + // sim.get_normmodel_forceofinfections().print_table({"norm FoI"}, 16, 8); + + //Uncomment to print the reproduction number + std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; + + // Uncomment to print the the values T_z1^z2 + //for (int i = 0; i < (int)sim.get_T().size(); i++) { + // std::cout << "T_" << i << " = " << sim.get_T()[i] << "\n"; + //} + + // Uncomment to print the values W_z + //for (int i = 0; i < (int)sim.get_W().size(); i++) { + // std::cout << "W_" << i << " = " << sim.get_W()[i] << "\n"; + //} + + // Uncomment to print the total population size. + // sim.get_totalpopulations().print_table({"N"}, 16, 9); +} \ No newline at end of file diff --git a/cpp/examples/ide_endemic_sird_save_results.cpp b/cpp/examples/ide_endemic_sird_save_results.cpp new file mode 100644 index 0000000000..5b308edbe7 --- /dev/null +++ b/cpp/examples/ide_endemic_sird_save_results.cpp @@ -0,0 +1,190 @@ +#include "memilio/io/result_io.h" +#include "memilio/utils/time_series.h" +#include "memilio/config.h" +#include "memilio/epidemiology/state_age_function.h" +#include "memilio/epidemiology/uncertain_matrix.h" +#include "memilio/math/floating_point.h" + +#include "ide_endemic_sird/infection_state.h" +#include "ide_endemic_sird/model.h" +#include "ide_endemic_sird/simulation.h" +#include "ide_endemic_sird/parameters.h" + +#include "boost/filesystem.hpp" +#include +#include +#include + +mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = "") +{ + using Vec = mio::TimeSeries::Vector; + + ScalarType dt = 1.0; + + int num_states = static_cast(mio::endisird::InfectionState::Count); + int num_transitions = static_cast(mio::endisird::InfectionTransition::Count); + + // Create TimeSeries with num_states elements where states needed for simulation will be stored. + mio::TimeSeries init(num_states); + + Vec vec_init(num_states); + + vec_init[static_cast(mio::endisird::InfectionState::Susceptible)] = 100000.; + vec_init[static_cast(mio::endisird::InfectionState::Infected)] = 40.; + vec_init[static_cast(mio::endisird::InfectionState::Recovered)] = 0.; + vec_init[static_cast(mio::endisird::InfectionState::Dead)] = 0.; + + init.add_time_point(0, vec_init); + + mio::endisird::CompParameters computed_parameters(std::move(init)); + + //Set working parameters + + // mio::ExponentialSurvivalFunction exp(3.0); + // mio::StateAgeFunctionWrapper delaydistribution(exp); + // std::vector vec_delaydistribution(num_transitions, delaydistribution); + + // mio::SmootherCosine smoothcos(2.0); + // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + // std::vector vec_delaydistribution(num_transitions, delaydistribution); + + mio::ConstantFunction initialfunc(0); + mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); + std::vector vec_delaydistribution(num_transitions, delaydistributioninit); + // InfectedToDead + mio::SmootherCosine survivalExposedToInfectedNoSymptoms(6.0); + vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToDead].set_state_age_function( + survivalExposedToInfectedNoSymptoms); + // InfectedToRecovered + mio::SmootherCosine survivalInfectedNoSymptomsToInfectedSymptoms(8.0); + vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToRecovered].set_state_age_function( + survivalInfectedNoSymptomsToInfectedSymptoms); + + // mio::ConstantFunction initialfunc(0); + // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); + // std::vector vec_delaydistribution(num_transitions, delaydistributioninit); + // // InfectedToDead + // mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.8, 0, 4.2); + // vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToDead].set_state_age_function( + // survivalExposedToInfectedNoSymptoms); + // // InfectedToRecovered + // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.2, 0, 0.8); + // vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToRecovered].set_state_age_function( + // survivalInfectedNoSymptomsToInfectedSymptoms); + + computed_parameters.parameters.get() = vec_delaydistribution; + + std::vector vec_prob((int)mio::endisird::InfectionTransition::Count, 1.); + vec_prob[Eigen::Index(mio::endisird::InfectionTransition::InfectedToDead)] = 0.1; + vec_prob[Eigen::Index(mio::endisird::InfectionTransition::InfectedToRecovered)] = 1 - 0.1; + + computed_parameters.parameters.set(vec_prob); + + mio::ContactMatrixGroup contact_matrix = mio::ContactMatrixGroup(1, 1); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10.)); + computed_parameters.parameters.get() = mio::UncertainContactMatrix(contact_matrix); + + mio::ConstantFunction constant(0.1); + mio::StateAgeFunctionWrapper constant_prob(constant); + + computed_parameters.parameters.get() = constant_prob; + + mio::ExponentialSurvivalFunction exponential(0.5); + mio::StateAgeFunctionWrapper exponential_prob(exponential); + + computed_parameters.parameters.get() = exponential_prob; + + computed_parameters.parameters.set(4e-3); + computed_parameters.parameters.set(3e-3); + + //computed_parameters.set_tol_for_support_max(1e-6); + + mio::endisird::Model model(computed_parameters); + + mio::endisird::NormModel normmodel(computed_parameters); + + // start the simulation. + mio::endisird::Simulation sim(computed_parameters, model, normmodel, dt); + sim.advance(tmax); + + if (!save_dir.empty()) { + std::string tmax_string = std::to_string(tmax); + std::string dt_string = std::to_string(dt); + + std::string filename_ide = save_dir + "analysis_endide_SIRD" + tmax_string.substr(0, tmax_string.find(".")) + + "_" + dt_string.substr(0, dt_string.find(".") + 5); + + //Save files of Model. + //Save total population. + std::string filename_ide_totalpopulation1 = filename_ide + "_totalpopulation1.h5"; + mio::IOResult save_result_status_tp1 = + mio::save_result({sim.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation1); + //Save derivative of total population. + std::string filename_ide_dertotalpopulation1 = filename_ide + "_dertotalpopulation1.h5"; + mio::IOResult save_result_status_dtp1 = + mio::save_result({sim.get_totalpopulations_derivative()}, {0}, 1, filename_ide_dertotalpopulation1); + + //Save compartments. + std::string filename_ide_compartments1 = filename_ide + "_compartments2.h5"; + mio::IOResult save_result_status_c1 = + mio::save_result({sim.get_compartments()}, {0}, 1, filename_ide_compartments1); + + //Save normalized compartments. + std::string filename_ide_normcompartments = filename_ide + "_normcompartments.h5"; + mio::IOResult save_result_status_nc = + mio::save_result({sim.get_normalizedcompartments()}, {0}, 1, filename_ide_normcompartments); + + //Save the force of infection. + std::string filename_ide_forceofinfection = filename_ide + "_forceofinfection2.h5"; + mio::IOResult save_result_status_foi = + mio::save_result({sim.get_forceofinfections()}, {0}, 1, filename_ide_forceofinfection); + + //Save files of NormModel. + //Save compartments. + std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments2.h5"; + mio::IOResult save_result_status_nmc1 = + mio::save_result({sim.get_normmodel_compartments()}, {0}, 1, filename_ide_normmod_compartments); + + //Save the force of infection. + std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection2.h5"; + mio::IOResult save_result_status_nmfoi = + mio::save_result({sim.get_normmodel_forceofinfections()}, {0}, 1, filename_ide_normmod_forceofinfection); + + //Safe difference between normalized compartments. + std::string filename_ide_difference_normcomp = filename_ide + "_difference_normcomp.h5"; + mio::IOResult save_result_status_dnm = + mio::save_result({sim.get_difference_normalizationcomp()}, {0}, 1, filename_ide_difference_normcomp); + + //Safe difference between Force of Infections. + std::string filename_ide_difference_normFoI = filename_ide + "_difference_normfoi.h5"; + mio::IOResult save_result_status_dnf = + mio::save_result({sim.get_difference_normalizationFoi()}, {0}, 1, filename_ide_difference_normFoI); + + if (!save_result_status_tp1 || !save_result_status_c1 || !save_result_status_nc || !save_result_status_foi || + !save_result_status_nmc1 || !save_result_status_nmfoi || !save_result_status_dnm || + !save_result_status_dnf || !save_result_status_dtp1) { + return mio::failure(mio::StatusCode::UnknownError, "Error while saving results."); + } + } + // Print the reproduction number. + std::cout << "The reproduction number Rc for Birth rate > Death rate is " << sim.get_reproductionnumber_c() + << "\n"; + + return mio::success(); +} + +int main() +{ + std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDESIRD/simulation_results/"; + + // Define tmax. + ScalarType tmax = 2000; + + auto result_ide = simulate_endidemodel(tmax, result_dir); + if (!result_ide) { + printf("%s\n", result_ide.error().formatted_message().c_str()); + return -1; + } + + return 0; +} \ No newline at end of file diff --git a/cpp/models/ide_endemic_secir/simulation.cpp b/cpp/models/ide_endemic_secir/simulation.cpp index ee5b9a5384..1c41aad2d9 100644 --- a/cpp/models/ide_endemic_secir/simulation.cpp +++ b/cpp/models/ide_endemic_secir/simulation.cpp @@ -29,27 +29,27 @@ void Simulation::advance(ScalarType tmax) m_model->compparameters->set_V(); m_model->compparameters->set_W(m_dt); - //m_normmodel->compparameters->set_transitiondistributions_support_max(m_dt); - //m_normmodel->compparameters->set_transitiondistributions(m_dt); - //m_normmodel->compparameters->set_transitiondistributions_derivative(m_dt); - //m_normmodel->compparameters->set_B(m_dt); - //m_normmodel->compparameters->set_infectivity(m_dt); - //m_normmodel->compparameters->set_FoI_0(m_dt); - //m_normmodel->compparameters->set_InitFoI(m_dt); - //m_normmodel->compparameters->set_reproductionnumber_c(m_dt); - //m_normmodel->compparameters->set_T(m_dt); - //m_normmodel->compparameters->set_V(); - //m_normmodel->compparameters->set_W(m_dt); - - //m_difference_normalizedcompartments.add_time_point(0); - //m_difference_normalizedFoI.add_time_point(0); - //compute_difference_normalizations(); + m_normmodel->compparameters->set_transitiondistributions_support_max(m_dt); + m_normmodel->compparameters->set_transitiondistributions(m_dt); + m_normmodel->compparameters->set_transitiondistributions_derivative(m_dt); + m_normmodel->compparameters->set_B(m_dt); + m_normmodel->compparameters->set_infectivity(m_dt); + m_normmodel->compparameters->set_FoI_0(m_dt); + m_normmodel->compparameters->set_InitFoI(m_dt); + m_normmodel->compparameters->set_reproductionnumber_c(m_dt); + m_normmodel->compparameters->set_T(m_dt); + m_normmodel->compparameters->set_V(); + m_normmodel->compparameters->set_W(m_dt); + + m_difference_normalizedcompartments.add_time_point(0); + m_difference_normalizedFoI.add_time_point(0); + compute_difference_normalizations(); // For every time step: while (m_model->transitions.get_last_time() < tmax - m_dt / 2) { - //m_difference_normalizedcompartments.add_time_point(m_difference_normalizedcompartments.get_last_time() + m_dt); - //m_difference_normalizedFoI.add_time_point(m_difference_normalizedFoI.get_last_time() + m_dt); + m_difference_normalizedcompartments.add_time_point(m_difference_normalizedcompartments.get_last_time() + m_dt); + m_difference_normalizedFoI.add_time_point(m_difference_normalizedFoI.get_last_time() + m_dt); //standard model: m_model->transitions.add_time_point(m_model->transitions.get_last_time() + m_dt); m_model->transitions_update.add_time_point(m_model->transitions_update.get_last_time() + m_dt); @@ -81,25 +81,25 @@ void Simulation::advance(ScalarType tmax) // Compute m_forceofinfection; m_model->compute_forceofinfection(m_dt); - // // normalized model: - // m_normmodel->transitions.add_time_point(m_normmodel->transitions.get_last_time() + m_dt); - // m_normmodel->populations.add_time_point(m_normmodel->populations.get_last_time() + m_dt); - // m_normmodel->m_forceofinfection.add_time_point(m_normmodel->m_forceofinfection.get_last_time() + m_dt); + // normalized model: + m_normmodel->transitions.add_time_point(m_normmodel->transitions.get_last_time() + m_dt); + m_normmodel->populations.add_time_point(m_normmodel->populations.get_last_time() + m_dt); + m_normmodel->m_forceofinfection.add_time_point(m_normmodel->m_forceofinfection.get_last_time() + m_dt); - // // Compute susceptibles: - // m_normmodel->compute_susceptibles(m_dt); + // Compute susceptibles: + m_normmodel->compute_susceptibles(m_dt); - // // Compute flows: - // m_normmodel->flows_currents_timestep(m_dt); + // Compute flows: + m_normmodel->flows_currents_timestep(m_dt); - // // Compute remaining compartments: - // m_normmodel->update_compartments(m_dt); + // Compute remaining compartments: + m_normmodel->update_compartments(m_dt); - // // Compute m_forceofinfection; - // m_normmodel->compute_forceofinfection(m_dt); + // Compute m_forceofinfection; + m_normmodel->compute_forceofinfection(m_dt); - // //Compute the difference of the two normalized compartments. - // compute_difference_normalizations(); + //Compute the difference of the two normalized compartments. + compute_difference_normalizations(); } } diff --git a/cpp/models/ide_endemic_sird/computed_parameters.h b/cpp/models/ide_endemic_sird/computed_parameters.h index 92d88fc34a..49869088be 100644 --- a/cpp/models/ide_endemic_sird/computed_parameters.h +++ b/cpp/models/ide_endemic_sird/computed_parameters.h @@ -161,7 +161,7 @@ class CompParameters void set_infectivity(ScalarType dt) { // Compute the calc_time_indedx corresponding to a_1: - ScalarType calc_time_index = m_transitiondistributions.size() - 1; + ScalarType calc_time_index = m_transitiondistributions.size(); m_infectivity = std::vector(calc_time_index, 0.); From 7dfc4889cacde6e6bc159c3908fe2c1df1ab5744 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Tue, 9 Sep 2025 12:13:39 +0200 Subject: [PATCH 21/22] small changes --- cpp/examples/ide_endemic_secir.cpp | 6 +- .../ide_endemic_secir_save_results.cpp | 14 ++-- cpp/examples/ide_endemic_sird.cpp | 75 ++++++++++++------ .../ide_endemic_sird_save_results.cpp | 79 ++++++++++++------- .../ide_endemic_sird/computed_parameters.h | 73 +++++++++++++++++ cpp/models/ide_endemic_sird/simulation.cpp | 1 + cpp/models/ide_endemic_sird/simulation.h | 15 ++++ 7 files changed, 200 insertions(+), 63 deletions(-) diff --git a/cpp/examples/ide_endemic_secir.cpp b/cpp/examples/ide_endemic_secir.cpp index 905cc5f153..13113dc3cc 100644 --- a/cpp/examples/ide_endemic_secir.cpp +++ b/cpp/examples/ide_endemic_secir.cpp @@ -19,8 +19,8 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 1000; - ScalarType dt = 1.0; + ScalarType tmax = 1; + ScalarType dt = 0.00001; int num_states = static_cast(mio::endisecir::InfectionState::Count); int num_transitions = static_cast(mio::endisecir::InfectionTransition::Count); @@ -49,7 +49,7 @@ int main() // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - mio::SmootherCosine smoothcos(6.0); + mio::SmootherCosine smoothcos(2.0); mio::StateAgeFunctionWrapper delaydistribution(smoothcos); std::vector vec_delaydistribution(num_transitions, delaydistribution); diff --git a/cpp/examples/ide_endemic_secir_save_results.cpp b/cpp/examples/ide_endemic_secir_save_results.cpp index 87063cf009..9ccc42d053 100644 --- a/cpp/examples/ide_endemic_secir_save_results.cpp +++ b/cpp/examples/ide_endemic_secir_save_results.cpp @@ -133,8 +133,8 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = computed_parameters.parameters.get() = exponential_prob; computed_parameters.parameters.get() = exponential_prob; - computed_parameters.parameters.set(4e-3); - computed_parameters.parameters.set(3e-3); + computed_parameters.parameters.set(9e-2); + computed_parameters.parameters.set(7e-3); //computed_parameters.set_tol_for_support_max(1e-6); @@ -150,8 +150,8 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = std::string tmax_string = std::to_string(tmax); std::string dt_string = std::to_string(dt); - std::string filename_ide = save_dir + "analysis_endide_" + tmax_string.substr(0, tmax_string.find(".")) + "_" + - dt_string.substr(0, dt_string.find(".") + 5); + std::string filename_ide = save_dir + "analysis_endide_SECIR_" + tmax_string.substr(0, tmax_string.find(".")) + + "_" + dt_string.substr(0, dt_string.find(".") + 5); //Save files of Model. //Save total population. @@ -180,12 +180,12 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = //Save files of NormModel. //Save compartments. - std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments.h5"; + std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments1.h5"; mio::IOResult save_result_status_nmc1 = mio::save_result({sim.get_normmodel_compartments()}, {0}, 1, filename_ide_normmod_compartments); //Save the force of infection. - std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection.h5"; + std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection1.h5"; mio::IOResult save_result_status_nmfoi = mio::save_result({sim.get_normmodel_forceofinfections()}, {0}, 1, filename_ide_normmod_forceofinfection); @@ -217,7 +217,7 @@ int main() std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDESECIR/simulation_results/"; // Define tmax. - ScalarType tmax = 2000; + ScalarType tmax = 500; auto result_ide = simulate_endidemodel(tmax, result_dir); if (!result_ide) { diff --git a/cpp/examples/ide_endemic_sird.cpp b/cpp/examples/ide_endemic_sird.cpp index 4a21b61ad5..7592e011fe 100644 --- a/cpp/examples/ide_endemic_sird.cpp +++ b/cpp/examples/ide_endemic_sird.cpp @@ -19,7 +19,7 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 50; + ScalarType tmax = 10; ScalarType dt = 1.0; int num_states = static_cast(mio::endisird::InfectionState::Count); @@ -45,21 +45,21 @@ int main() // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - // mio::SmootherCosine smoothcos(2.0); - // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); - // std::vector vec_delaydistribution(num_transitions, delaydistribution); + mio::SmootherCosine smoothcos(2.0); + mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + std::vector vec_delaydistribution(num_transitions, delaydistribution); - mio::ConstantFunction initialfunc(0); - mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); - std::vector vec_delaydistribution(num_transitions, delaydistributioninit); - // InfectedToDead - mio::SmootherCosine survivalExposedToInfectedNoSymptoms(6.0); - vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToDead].set_state_age_function( - survivalExposedToInfectedNoSymptoms); - // InfectedToRecovered - mio::SmootherCosine survivalInfectedNoSymptomsToInfectedSymptoms(8.0); - vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToRecovered].set_state_age_function( - survivalInfectedNoSymptomsToInfectedSymptoms); + // mio::ConstantFunction initialfunc(0); + // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); + // std::vector vec_delaydistribution(num_transitions, delaydistributioninit); + // // InfectedToDead + // mio::SmootherCosine survivalExposedToInfectedNoSymptoms(6.0); + // vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToDead].set_state_age_function( + // survivalExposedToInfectedNoSymptoms); + // // InfectedToRecovered + // mio::SmootherCosine survivalInfectedNoSymptomsToInfectedSymptoms(8.0); + // vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToRecovered].set_state_age_function( + // survivalInfectedNoSymptomsToInfectedSymptoms); // mio::ConstantFunction initialfunc(0); // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); @@ -128,8 +128,8 @@ int main() // {"s->i", "i->d", "i->r }, 16, 8); // Uncomment to print the force of infection of model. - auto interpolated_FoI = mio::interpolate_simulation_result(sim.get_forceofinfections(), dt / 2.); - interpolated_FoI.print_table({"FoI"}, 16, 8); + // auto interpolated_FoI = mio::interpolate_simulation_result(sim.get_forceofinfections(), dt / 2.); + // interpolated_FoI.print_table({"FoI"}, 16, 8); // Uncomment to print the force of infection of normmodel. // sim.get_normmodel_forceofinfections().print_table({"norm FoI"}, 16, 8); @@ -138,14 +138,39 @@ int main() std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; // Uncomment to print the the values T_z1^z2 - //for (int i = 0; i < (int)sim.get_T().size(); i++) { - // std::cout << "T_" << i << " = " << sim.get_T()[i] << "\n"; - //} - - // Uncomment to print the values W_z - //for (int i = 0; i < (int)sim.get_W().size(); i++) { - // std::cout << "W_" << i << " = " << sim.get_W()[i] << "\n"; - //} + for (int i = 0; i < (int)sim.get_T().size(); i++) { + std::cout << "T_" << i << " = " << sim.get_T()[i] << "\n"; + } + + // Uncomment to print W_i + + std::cout << "W_i = " << sim.get_W() << "\n"; + + // Uncomment to print the equilibria + std::cout << "l_1 = " << sim.get_Equilibirum_FoI()[0] << "\n"; + std::cout << "l_2 = " << sim.get_Equilibirum_FoI()[1] << "\n"; + std::cout << "s_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Susceptible] + << "\n"; + std::cout << "s_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Susceptible] + << "\n"; + std::cout << "i_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Infected] + << "\n"; + std::cout << "i_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Infected] + << "\n"; + std::cout << "r_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Recovered] + << "\n"; + std::cout << "r_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Recovered] + << "\n"; + std::cout << "sigmaid_1 = " + << sim.get_Equilibirum_transitions()[0][(int)mio::endisird::InfectionTransition::InfectedToDead] << "\n"; + std::cout << "sigmaid_2 = " + << sim.get_Equilibirum_transitions()[1][(int)mio::endisird::InfectionTransition::InfectedToDead] << "\n"; + std::cout << "sigmair_1 = " + << sim.get_Equilibirum_transitions()[0][(int)mio::endisird::InfectionTransition::InfectedToRecovered] + << "\n"; + std::cout << "sigmair_2 = " + << sim.get_Equilibirum_transitions()[1][(int)mio::endisird::InfectionTransition::InfectedToRecovered] + << "\n"; // Uncomment to print the total population size. // sim.get_totalpopulations().print_table({"N"}, 16, 9); diff --git a/cpp/examples/ide_endemic_sird_save_results.cpp b/cpp/examples/ide_endemic_sird_save_results.cpp index 5b308edbe7..bf51c309a2 100644 --- a/cpp/examples/ide_endemic_sird_save_results.cpp +++ b/cpp/examples/ide_endemic_sird_save_results.cpp @@ -30,7 +30,7 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = Vec vec_init(num_states); vec_init[static_cast(mio::endisird::InfectionState::Susceptible)] = 100000.; - vec_init[static_cast(mio::endisird::InfectionState::Infected)] = 40.; + vec_init[static_cast(mio::endisird::InfectionState::Infected)] = 30.; vec_init[static_cast(mio::endisird::InfectionState::Recovered)] = 0.; vec_init[static_cast(mio::endisird::InfectionState::Dead)] = 0.; @@ -44,31 +44,19 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - // mio::SmootherCosine smoothcos(2.0); - // mio::StateAgeFunctionWrapper delaydistribution(smoothcos); - // std::vector vec_delaydistribution(num_transitions, delaydistribution); - - mio::ConstantFunction initialfunc(0); - mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); - std::vector vec_delaydistribution(num_transitions, delaydistributioninit); - // InfectedToDead - mio::SmootherCosine survivalExposedToInfectedNoSymptoms(6.0); - vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToDead].set_state_age_function( - survivalExposedToInfectedNoSymptoms); - // InfectedToRecovered - mio::SmootherCosine survivalInfectedNoSymptomsToInfectedSymptoms(8.0); - vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToRecovered].set_state_age_function( - survivalInfectedNoSymptomsToInfectedSymptoms); + mio::SmootherCosine smoothcos(12.0); + mio::StateAgeFunctionWrapper delaydistribution(smoothcos); + std::vector vec_delaydistribution(num_transitions, delaydistribution); // mio::ConstantFunction initialfunc(0); // mio::StateAgeFunctionWrapper delaydistributioninit(initialfunc); // std::vector vec_delaydistribution(num_transitions, delaydistributioninit); // // InfectedToDead - // mio::LognormSurvivalFunction survivalExposedToInfectedNoSymptoms(0.8, 0, 4.2); + // mio::SmootherCosine survivalExposedToInfectedNoSymptoms(14.0); // vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToDead].set_state_age_function( // survivalExposedToInfectedNoSymptoms); // // InfectedToRecovered - // mio::LognormSurvivalFunction survivalInfectedNoSymptomsToInfectedSymptoms(0.2, 0, 0.8); + // mio::SmootherCosine survivalInfectedNoSymptomsToInfectedSymptoms(8.0); // vec_delaydistribution[(int)mio::endisird::InfectionTransition::InfectedToRecovered].set_state_age_function( // survivalInfectedNoSymptomsToInfectedSymptoms); @@ -94,8 +82,8 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = computed_parameters.parameters.get() = exponential_prob; - computed_parameters.parameters.set(4e-3); - computed_parameters.parameters.set(3e-3); + computed_parameters.parameters.set(1e-1); + computed_parameters.parameters.set(2e-2); //computed_parameters.set_tol_for_support_max(1e-6); @@ -111,21 +99,21 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = std::string tmax_string = std::to_string(tmax); std::string dt_string = std::to_string(dt); - std::string filename_ide = save_dir + "analysis_endide_SIRD" + tmax_string.substr(0, tmax_string.find(".")) + + std::string filename_ide = save_dir + "analysis_endide_SIRD_" + tmax_string.substr(0, tmax_string.find(".")) + "_" + dt_string.substr(0, dt_string.find(".") + 5); //Save files of Model. //Save total population. - std::string filename_ide_totalpopulation1 = filename_ide + "_totalpopulation1.h5"; + std::string filename_ide_totalpopulation1 = filename_ide + "_totalpopulation.h5"; mio::IOResult save_result_status_tp1 = mio::save_result({sim.get_totalpopulations()}, {0}, 1, filename_ide_totalpopulation1); //Save derivative of total population. - std::string filename_ide_dertotalpopulation1 = filename_ide + "_dertotalpopulation1.h5"; + std::string filename_ide_dertotalpopulation1 = filename_ide + "_dertotalpopulation.h5"; mio::IOResult save_result_status_dtp1 = mio::save_result({sim.get_totalpopulations_derivative()}, {0}, 1, filename_ide_dertotalpopulation1); //Save compartments. - std::string filename_ide_compartments1 = filename_ide + "_compartments2.h5"; + std::string filename_ide_compartments1 = filename_ide + "_compartments.h5"; mio::IOResult save_result_status_c1 = mio::save_result({sim.get_compartments()}, {0}, 1, filename_ide_compartments1); @@ -141,12 +129,12 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = //Save files of NormModel. //Save compartments. - std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments2.h5"; + std::string filename_ide_normmod_compartments = filename_ide + "_normmod_compartments.h5"; mio::IOResult save_result_status_nmc1 = mio::save_result({sim.get_normmodel_compartments()}, {0}, 1, filename_ide_normmod_compartments); //Save the force of infection. - std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection2.h5"; + std::string filename_ide_normmod_forceofinfection = filename_ide + "_normmod_forceofinfection.h5"; mio::IOResult save_result_status_nmfoi = mio::save_result({sim.get_normmodel_forceofinfections()}, {0}, 1, filename_ide_normmod_forceofinfection); @@ -167,7 +155,42 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = } } // Print the reproduction number. - std::cout << "The reproduction number Rc for Birth rate > Death rate is " << sim.get_reproductionnumber_c() + //Uncomment to print the reproduction number + std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; + + // Uncomment to print the the values T_z1^z2 + for (int i = 0; i < (int)sim.get_T().size(); i++) { + std::cout << "T_" << i << " = " << sim.get_T()[i] << "\n"; + } + + // Uncomment to print W_i + + std::cout << "W_i = " << sim.get_W() << "\n"; + + // Uncomment to print the equilibria + std::cout << "l_1 = " << sim.get_Equilibirum_FoI()[0] << "\n"; + std::cout << "l_2 = " << sim.get_Equilibirum_FoI()[1] << "\n"; + std::cout << "s_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Susceptible] + << "\n"; + std::cout << "s_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Susceptible] + << "\n"; + std::cout << "i_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Infected] + << "\n"; + std::cout << "i_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Infected] + << "\n"; + std::cout << "r_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Recovered] + << "\n"; + std::cout << "r_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Recovered] + << "\n"; + std::cout << "sigmaid_1 = " + << sim.get_Equilibirum_transitions()[0][(int)mio::endisird::InfectionTransition::InfectedToDead] << "\n"; + std::cout << "sigmaid_2 = " + << sim.get_Equilibirum_transitions()[1][(int)mio::endisird::InfectionTransition::InfectedToDead] << "\n"; + std::cout << "sigmair_1 = " + << sim.get_Equilibirum_transitions()[0][(int)mio::endisird::InfectionTransition::InfectedToRecovered] + << "\n"; + std::cout << "sigmair_2 = " + << sim.get_Equilibirum_transitions()[1][(int)mio::endisird::InfectionTransition::InfectedToRecovered] << "\n"; return mio::success(); @@ -178,7 +201,7 @@ int main() std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDESIRD/simulation_results/"; // Define tmax. - ScalarType tmax = 2000; + ScalarType tmax = 100; auto result_ide = simulate_endidemodel(tmax, result_dir); if (!result_ide) { diff --git a/cpp/models/ide_endemic_sird/computed_parameters.h b/cpp/models/ide_endemic_sird/computed_parameters.h index 49869088be..b1cd3950b6 100644 --- a/cpp/models/ide_endemic_sird/computed_parameters.h +++ b/cpp/models/ide_endemic_sird/computed_parameters.h @@ -261,6 +261,71 @@ class CompParameters m_W = sum; } + void set_equilibria() + { + // We start by setting the equilibrium for the infected compartments. + ScalarType p = (m_W / m_T[(int)InfectionTransition::InfectedToDead]) * + (parameters.get() - 1 / m_W - parameters.get()) - + parameters.get() / + (m_reproductionnumber_c - m_T[(int)InfectionTransition::InfectedToDead]); + ScalarType q = parameters.get() * m_W / + ((m_reproductionnumber_c - m_T[(int)InfectionTransition::InfectedToDead]) * + m_T[(int)InfectionTransition::InfectedToDead]) * + ((1 / m_W) - parameters.get() + parameters.get() - + m_reproductionnumber_c); + m_compartments_equilibrium[0][(int)InfectionState::Infected] = -p / 2 + std::sqrt((p / 2) * (p / 2) - q); + m_compartments_equilibrium[1][(int)InfectionState::Infected] = -p / 2 - std::sqrt((p / 2) * (p / 2) - q); + + // From this we set the other equilibria points. + // Susceptibles: + m_compartments_equilibrium[0][(int)InfectionState::Susceptible] = + parameters.get() / + (m_compartments_equilibrium[0][(int)InfectionState::Infected] * + (m_reproductionnumber_c / m_W - m_T[(int)InfectionTransition::InfectedToDead] / m_W) + + parameters.get()); + m_compartments_equilibrium[1][(int)InfectionState::Susceptible] = + parameters.get() / + (m_compartments_equilibrium[1][(int)InfectionState::Infected] * + (m_reproductionnumber_c / m_W - m_T[(int)InfectionTransition::InfectedToDead] / m_W) + + parameters.get()); + // Force of Infection: + m_FoI_equilibrium[0] = + m_compartments_equilibrium[0][(int)InfectionState::Infected] * (m_reproductionnumber_c / m_W); + m_FoI_equilibrium[1] = + m_compartments_equilibrium[1][(int)InfectionState::Infected] * (m_reproductionnumber_c / m_W); + // InfectedToDead: + m_transitions_equilibrium[0][(int)InfectionTransition::InfectedToDead] = + m_compartments_equilibrium[0][(int)InfectionState::Infected] * + (m_T[(int)InfectionTransition::InfectedToDead] / m_W); + m_transitions_equilibrium[1][(int)InfectionTransition::InfectedToDead] = + m_compartments_equilibrium[1][(int)InfectionState::Infected] * + (m_T[(int)InfectionTransition::InfectedToDead] / m_W); + // InfectedToRecovered: + m_transitions_equilibrium[0][(int)InfectionTransition::InfectedToRecovered] = + (m_compartments_equilibrium[0][(int)InfectionState::Susceptible] * m_FoI_equilibrium[0] + + (parameters.get() + + m_transitions_equilibrium[0][(int)InfectionTransition::InfectedToDead] - + parameters.get()) * + m_compartments_equilibrium[0][(int)InfectionState::Infected]) * + m_T[(int)InfectionTransition::InfectedToDead]; + m_transitions_equilibrium[1][(int)InfectionTransition::InfectedToRecovered] = + (m_compartments_equilibrium[1][(int)InfectionState::Susceptible] * m_FoI_equilibrium[0] + + (parameters.get() + + m_transitions_equilibrium[1][(int)InfectionTransition::InfectedToDead] - + parameters.get()) * + m_compartments_equilibrium[1][(int)InfectionState::Infected]) * + m_T[(int)InfectionTransition::InfectedToDead]; + // Recovered: + m_compartments_equilibrium[0][(int)InfectionState::Recovered] = + m_transitions_equilibrium[0][(int)InfectionTransition::InfectedToRecovered] / + (parameters.get() - + m_transitions_equilibrium[0][(int)InfectionTransition::InfectedToDead]); + m_compartments_equilibrium[1][(int)InfectionState::Recovered] = + m_transitions_equilibrium[1][(int)InfectionTransition::InfectedToRecovered] / + (parameters.get() - + m_transitions_equilibrium[1][(int)InfectionTransition::InfectedToDead]); + } + // ---- Private parameters. ---- TimeSeries m_statesinit; ///< TimeSeries containing the initial values for the compartments. ScalarType m_totalpopulationinit; @@ -284,6 +349,14 @@ class CompParameters std::vector m_T{std::vector((int)InfectionTransition::Count, 0.)}; ///< A vector // containing the approximated value for T_z1^z2 for every Flow z1 to z2. ScalarType m_W{0}; ///< ScalarType of the value W_i. + std::vector> m_compartments_equilibrium{std::vector>( + 2, std::vector((int)InfectionState::Count - 1, 0.))}; ///< Vector containing the + // two computed equilibria points for the compartments of NormModel. + std::vector> m_transitions_equilibrium{std::vector>( + 2, std::vector((int)InfectionState::Count - 1, 0.))}; ///< Vector containing the + // two computed equilibria points for the transitions of NormModel. + std::vector m_FoI_equilibrium{std::vector(2, 0.)}; ///< A Vector containing the two + // computed equilibria points for the force of infection of NormModel. // ---- Friend classes/functions. ---- friend class Model; friend class NormModel; diff --git a/cpp/models/ide_endemic_sird/simulation.cpp b/cpp/models/ide_endemic_sird/simulation.cpp index 07b96edccf..0bb33fdbfe 100644 --- a/cpp/models/ide_endemic_sird/simulation.cpp +++ b/cpp/models/ide_endemic_sird/simulation.cpp @@ -34,6 +34,7 @@ void Simulation::advance(ScalarType tmax) m_normmodel->compparameters->set_reproductionnumber_c(m_dt); m_normmodel->compparameters->set_T(m_dt); m_normmodel->compparameters->set_W(m_dt); + m_normmodel->compparameters->set_equilibria(); m_difference_normalizedcompartments.add_time_point(0); m_difference_normalizedFoI.add_time_point(0); diff --git a/cpp/models/ide_endemic_sird/simulation.h b/cpp/models/ide_endemic_sird/simulation.h index 8606db574c..a56227d8a1 100644 --- a/cpp/models/ide_endemic_sird/simulation.h +++ b/cpp/models/ide_endemic_sird/simulation.h @@ -155,6 +155,21 @@ class Simulation return m_model->compparameters->m_W; } + std::vector> const& get_Equilibirum_compartments() + { + return m_normmodel->compparameters->m_compartments_equilibrium; + } + + std::vector> const& get_Equilibirum_transitions() + { + return m_normmodel->compparameters->m_transitions_equilibrium; + } + + std::vector const& get_Equilibirum_FoI() + { + return m_normmodel->compparameters->m_FoI_equilibrium; + } + /** * @brief returns the simulation model used in simulation. */ From aa965f5bcb44a9da18d8962c284e220c8b615791 Mon Sep 17 00:00:00 2001 From: Hannah Tritzschak <162430585+hatrit@users.noreply.github.com> Date: Mon, 22 Sep 2025 09:23:59 +0200 Subject: [PATCH 22/22] small changes --- cpp/examples/ide_endemic_sird.cpp | 71 ++++++++++--------- .../ide_endemic_sird_save_results.cpp | 14 ++-- .../ide_endemic_sird/normalized_model.cpp | 13 +++- .../ide_endemic_sird/normalized_model.h | 3 + cpp/models/ide_endemic_sird/simulation.cpp | 3 + cpp/models/ide_endemic_sird/simulation.h | 5 ++ 6 files changed, 64 insertions(+), 45 deletions(-) diff --git a/cpp/examples/ide_endemic_sird.cpp b/cpp/examples/ide_endemic_sird.cpp index 7592e011fe..6e43b9e475 100644 --- a/cpp/examples/ide_endemic_sird.cpp +++ b/cpp/examples/ide_endemic_sird.cpp @@ -19,7 +19,7 @@ int main() { using Vec = mio::TimeSeries::Vector; - ScalarType tmax = 10; + ScalarType tmax = 100; ScalarType dt = 1.0; int num_states = static_cast(mio::endisird::InfectionState::Count); @@ -45,7 +45,7 @@ int main() // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - mio::SmootherCosine smoothcos(2.0); + mio::SmootherCosine smoothcos(8.0); mio::StateAgeFunctionWrapper delaydistribution(smoothcos); std::vector vec_delaydistribution(num_transitions, delaydistribution); @@ -109,12 +109,12 @@ int main() sim.advance(tmax); //Get the compartments of model and print them. - auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); - interpolated_results.print_table({"S", "I", "R", "D "}, 16, 8); + // auto interpolated_results = mio::interpolate_simulation_result(sim.get_compartments(), dt / 2.); + // interpolated_results.print_table({"S", "I", "R", "D "}, 16, 8); //Get the commpartments of normmodel and print them. - // auto interpolated_normresults = mio::interpolate_simulation_result(sim.get_normmodel_compartments(), dt / 2.); - // interpolated_normresults.print_table({"s", "i", "r"}, 16, 8); + auto interpolated_normresults = mio::interpolate_simulation_result(sim.get_normmodel_compartments(), dt / 2.); + interpolated_normresults.print_table({"s", "i", "r"}, 16, 8); // Uncomment to print the normalized compartments of model. // sim.get_normalizedcompartments().print_table({"S/N", "I/N", "R/N"}, 16, 8); @@ -134,43 +134,44 @@ int main() // Uncomment to print the force of infection of normmodel. // sim.get_normmodel_forceofinfections().print_table({"norm FoI"}, 16, 8); + sim.get_size().print_table({"sum"}, 16, 8); //Uncomment to print the reproduction number - std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; + // std::cout << "The reproduction number Rc = " << sim.get_reproductionnumber_c() << "\n"; // Uncomment to print the the values T_z1^z2 - for (int i = 0; i < (int)sim.get_T().size(); i++) { - std::cout << "T_" << i << " = " << sim.get_T()[i] << "\n"; - } + // for (int i = 0; i < (int)sim.get_T().size(); i++) { + // std::cout << "T_" << i << " = " << sim.get_T()[i] << "\n"; + // } // Uncomment to print W_i - std::cout << "W_i = " << sim.get_W() << "\n"; + // std::cout << "W_i = " << sim.get_W() << "\n"; // Uncomment to print the equilibria - std::cout << "l_1 = " << sim.get_Equilibirum_FoI()[0] << "\n"; - std::cout << "l_2 = " << sim.get_Equilibirum_FoI()[1] << "\n"; - std::cout << "s_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Susceptible] - << "\n"; - std::cout << "s_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Susceptible] - << "\n"; - std::cout << "i_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Infected] - << "\n"; - std::cout << "i_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Infected] - << "\n"; - std::cout << "r_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Recovered] - << "\n"; - std::cout << "r_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Recovered] - << "\n"; - std::cout << "sigmaid_1 = " - << sim.get_Equilibirum_transitions()[0][(int)mio::endisird::InfectionTransition::InfectedToDead] << "\n"; - std::cout << "sigmaid_2 = " - << sim.get_Equilibirum_transitions()[1][(int)mio::endisird::InfectionTransition::InfectedToDead] << "\n"; - std::cout << "sigmair_1 = " - << sim.get_Equilibirum_transitions()[0][(int)mio::endisird::InfectionTransition::InfectedToRecovered] - << "\n"; - std::cout << "sigmair_2 = " - << sim.get_Equilibirum_transitions()[1][(int)mio::endisird::InfectionTransition::InfectedToRecovered] - << "\n"; + // std::cout << "l_1 = " << sim.get_Equilibirum_FoI()[0] << "\n"; + // std::cout << "l_2 = " << sim.get_Equilibirum_FoI()[1] << "\n"; + // std::cout << "s_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Susceptible] + // << "\n"; + // std::cout << "s_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Susceptible] + // << "\n"; + // std::cout << "i_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Infected] + // << "\n"; + // std::cout << "i_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Infected] + // << "\n"; + // std::cout << "r_1 = " << sim.get_Equilibirum_compartments()[0][(int)mio::endisird::InfectionState::Recovered] + // << "\n"; + // std::cout << "r_2 = " << sim.get_Equilibirum_compartments()[1][(int)mio::endisird::InfectionState::Recovered] + // << "\n"; + // std::cout << "sigmaid_1 = " + // << sim.get_Equilibirum_transitions()[0][(int)mio::endisird::InfectionTransition::InfectedToDead] << "\n"; + // std::cout << "sigmaid_2 = " + // << sim.get_Equilibirum_transitions()[1][(int)mio::endisird::InfectionTransition::InfectedToDead] << "\n"; + // std::cout << "sigmair_1 = " + // << sim.get_Equilibirum_transitions()[0][(int)mio::endisird::InfectionTransition::InfectedToRecovered] + // << "\n"; + // std::cout << "sigmair_2 = " + // << sim.get_Equilibirum_transitions()[1][(int)mio::endisird::InfectionTransition::InfectedToRecovered] + // << "\n"; // Uncomment to print the total population size. // sim.get_totalpopulations().print_table({"N"}, 16, 9); diff --git a/cpp/examples/ide_endemic_sird_save_results.cpp b/cpp/examples/ide_endemic_sird_save_results.cpp index bf51c309a2..39f37f5f91 100644 --- a/cpp/examples/ide_endemic_sird_save_results.cpp +++ b/cpp/examples/ide_endemic_sird_save_results.cpp @@ -29,9 +29,9 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = Vec vec_init(num_states); - vec_init[static_cast(mio::endisird::InfectionState::Susceptible)] = 100000.; - vec_init[static_cast(mio::endisird::InfectionState::Infected)] = 30.; - vec_init[static_cast(mio::endisird::InfectionState::Recovered)] = 0.; + vec_init[static_cast(mio::endisird::InfectionState::Susceptible)] = 87500.; + vec_init[static_cast(mio::endisird::InfectionState::Infected)] = 190.; + vec_init[static_cast(mio::endisird::InfectionState::Recovered)] = 12310.; vec_init[static_cast(mio::endisird::InfectionState::Dead)] = 0.; init.add_time_point(0, vec_init); @@ -44,7 +44,7 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = // mio::StateAgeFunctionWrapper delaydistribution(exp); // std::vector vec_delaydistribution(num_transitions, delaydistribution); - mio::SmootherCosine smoothcos(12.0); + mio::SmootherCosine smoothcos(8.0); mio::StateAgeFunctionWrapper delaydistribution(smoothcos); std::vector vec_delaydistribution(num_transitions, delaydistribution); @@ -82,8 +82,8 @@ mio::IOResult simulate_endidemodel(ScalarType tmax, std::string save_dir = computed_parameters.parameters.get() = exponential_prob; - computed_parameters.parameters.set(1e-1); - computed_parameters.parameters.set(2e-2); + computed_parameters.parameters.set(4e-3); + computed_parameters.parameters.set(3e-3); //computed_parameters.set_tol_for_support_max(1e-6); @@ -201,7 +201,7 @@ int main() std::string result_dir = "/localdata1/trit_ha/code/memilio-1/PythonPlotsEndIDESIRD/simulation_results/"; // Define tmax. - ScalarType tmax = 100; + ScalarType tmax = 4000; auto result_ide = simulate_endidemodel(tmax, result_dir); if (!result_ide) { diff --git a/cpp/models/ide_endemic_sird/normalized_model.cpp b/cpp/models/ide_endemic_sird/normalized_model.cpp index 4708ec2770..e924d9e345 100644 --- a/cpp/models/ide_endemic_sird/normalized_model.cpp +++ b/cpp/models/ide_endemic_sird/normalized_model.cpp @@ -1,6 +1,5 @@ #include "ide_endemic_sird/normalized_model.h" #include "ide_endemic_sird/computed_parameters.h" -#include "ide_endemic_sird/model.h" #include "ide_endemic_sird/parameters.h" #include "ide_endemic_sird/infection_state.h" #include "memilio/config.h" @@ -41,6 +40,7 @@ NormModel::NormModel(CompParameters const& compparams) 0, TimeSeries::Vector::Constant(static_cast(InfectionTransition::Count), 0.)); m_forceofinfection.add_time_point(0, TimeSeries::Vector::Constant(1, compparameters->m_NormFoI_0[0])); + m_size.add_time_point(0, TimeSeries::Vector::Constant(1, 1.0)); } bool NormModel::check_constraints() const @@ -122,7 +122,6 @@ void NormModel::flows_currents_timestep(ScalarType dt) m_forceofinfection[current_time_index - 1][0] * populations.get_last_value()[static_cast(InfectionState::Susceptible)]; - // Calculate the other Transitions with compute_flow. // Calculate the other Transitions with compute_flow. // Infected To Dead: compute_flow(Eigen::Index(InfectionTransition::InfectedToDead), @@ -196,7 +195,15 @@ void NormModel::update_compartments(ScalarType dt) { InfectionTransition::InfectedToRecovered, }, - true, dt); + false, dt); +} +void NormModel::compute_size() +{ + ScalarType sum = 0; + for (int state = 0; state < Eigen::Index(InfectionState::Count) - 1; state++) { + sum += populations.get_last_value()[state]; + } + m_size.get_last_value()[0] = sum; } void NormModel::compute_forceofinfection(ScalarType dt) diff --git a/cpp/models/ide_endemic_sird/normalized_model.h b/cpp/models/ide_endemic_sird/normalized_model.h index 97e877c749..e6cca2560d 100644 --- a/cpp/models/ide_endemic_sird/normalized_model.h +++ b/cpp/models/ide_endemic_sird/normalized_model.h @@ -129,6 +129,8 @@ class NormModel */ void update_compartments(ScalarType dt); + void compute_size(); + /** * @brief Computes the force of infection for the current last time in transitions. * @@ -142,6 +144,7 @@ class NormModel TimeSeries m_forceofinfection{ TimeSeries(1)}; ///< TimeSeries containing the Force of infection term for every time point, + TimeSeries m_size{TimeSeries(1)}; // ---- Friend classes/functions. ---- // In the Simulation class, the actual simulation is performed which is why it needs access to the here diff --git a/cpp/models/ide_endemic_sird/simulation.cpp b/cpp/models/ide_endemic_sird/simulation.cpp index 0bb33fdbfe..921e9e6bb4 100644 --- a/cpp/models/ide_endemic_sird/simulation.cpp +++ b/cpp/models/ide_endemic_sird/simulation.cpp @@ -76,6 +76,7 @@ void Simulation::advance(ScalarType tmax) m_normmodel->transitions.add_time_point(m_normmodel->transitions.get_last_time() + m_dt); m_normmodel->populations.add_time_point(m_normmodel->populations.get_last_time() + m_dt); m_normmodel->m_forceofinfection.add_time_point(m_normmodel->m_forceofinfection.get_last_time() + m_dt); + m_normmodel->m_size.add_time_point(m_normmodel->m_size.get_last_time() + m_dt); // Compute susceptibles: m_normmodel->compute_susceptibles(m_dt); @@ -86,6 +87,8 @@ void Simulation::advance(ScalarType tmax) // Compute remaining compartments: m_normmodel->update_compartments(m_dt); + m_normmodel->compute_size(); + // Compute m_forceofinfection; m_normmodel->compute_forceofinfection(m_dt); diff --git a/cpp/models/ide_endemic_sird/simulation.h b/cpp/models/ide_endemic_sird/simulation.h index a56227d8a1..7888303d1f 100644 --- a/cpp/models/ide_endemic_sird/simulation.h +++ b/cpp/models/ide_endemic_sird/simulation.h @@ -123,6 +123,11 @@ class Simulation return m_model->m_totalpopulation; } + TimeSeries const& get_size() + { + return m_normmodel->m_size; + } + /** * @brief Get the derivative of the total population of m_model. */