From 2d4aec10e0b6a80dddb6e05772671c523d19dd22 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:29:07 +0200 Subject: [PATCH 01/87] add model with Populations with Regions --- cpp/CMakeLists.txt | 1 + cpp/examples/CMakeLists.txt | 4 + cpp/examples/ode_sir_mobility.cpp | 63 +++++++ cpp/models/ode_sir_mobility/CMakeLists.txt | 12 ++ cpp/models/ode_sir_mobility/README.md | 21 +++ cpp/models/ode_sir_mobility/infection_state.h | 25 +++ cpp/models/ode_sir_mobility/model.cpp | 10 ++ cpp/models/ode_sir_mobility/model.h | 52 ++++++ cpp/models/ode_sir_mobility/parameters.h | 162 ++++++++++++++++++ cpp/models/ode_sir_mobility/regions.h | 26 +++ 10 files changed, 376 insertions(+) create mode 100644 cpp/examples/ode_sir_mobility.cpp create mode 100644 cpp/models/ode_sir_mobility/CMakeLists.txt create mode 100644 cpp/models/ode_sir_mobility/README.md create mode 100644 cpp/models/ode_sir_mobility/infection_state.h create mode 100644 cpp/models/ode_sir_mobility/model.cpp create mode 100644 cpp/models/ode_sir_mobility/model.h create mode 100644 cpp/models/ode_sir_mobility/parameters.h create mode 100644 cpp/models/ode_sir_mobility/regions.h diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index e7a3306c24..fec9d5b711 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -124,6 +124,7 @@ if(MEMILIO_BUILD_MODELS) add_subdirectory(models/ide_seir) add_subdirectory(models/ode_seir) add_subdirectory(models/ode_sir) + add_subdirectory(models/ode_sir_mobility) add_subdirectory(models/sde_sir) add_subdirectory(models/sde_sirs) endif() diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index e982766dc3..4b3250b7b3 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -26,6 +26,10 @@ add_executable(sde_sir_example sde_sir.cpp) target_link_libraries(sde_sir_example PRIVATE memilio sde_sir) target_compile_options(sde_sir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ode_sir_mobility_example ode_sir_mobility.cpp) +target_link_libraries(ode_sir_mobility_example PRIVATE memilio ode_sir_mobility) +target_compile_options(ode_sir_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(sde_sirs_example sde_sirs.cpp) target_link_libraries(sde_sirs_example PRIVATE memilio sde_sirs) target_compile_options(sde_sirs_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/examples/ode_sir_mobility.cpp b/cpp/examples/ode_sir_mobility.cpp new file mode 100644 index 0000000000..e7510298cb --- /dev/null +++ b/cpp/examples/ode_sir_mobility.cpp @@ -0,0 +1,63 @@ + +#include "memilio/compartments/simulation.h" +#include "memilio/math/euler.h" +#include "memilio/utils/logging.h" +#include "memilio/epidemiology/age_group.h" +#include "ode_sir_mobility/infection_state.h" +#include "ode_sir_mobility/model.h" +#include "ode_sir_mobility/parameters.h" +#include "ode_sir_mobility/regions.h" + +int main() +{ + mio::set_log_level(mio::LogLevel::debug); + + double t0 = 0.; + double tmax = 50.; + double dt = 0.1; + + double total_population = 1061000; + + mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); + + mio::osirmobility::Model model(5); + + model.populations[{mio::Index(mio::osirmobility::InfectionState::Infected, mio::osirmobility::Region(1))}] = 1000; + model.populations[{mio::Index(mio::osirmobility::InfectionState::Recovered, mio::osirmobility::Region(1))}] = 1000; + model.populations[{mio::Index(mio::osirmobility::InfectionState::Susceptible, mio::osirmobility::Region(1))}] = + total_population - + model.populations[{mio::Index(mio::osirmobility::InfectionState::Infected, mio::osirmobility::Region(1))}] - + model.populations[{mio::Index(mio::osirmobility::InfectionState::Recovered, mio::osirmobility::Region(1))}]; + model.parameters.set(2); + model.parameters.set(0.04); + model.parameters.get().get_baseline()(0, 0) = 2.7; + model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); + + auto integrator = std::make_shared(); + + model.check_constraints(); + + auto sir = simulate(t0, tmax, dt, model, integrator); + + bool print_to_terminal = true; + + if (print_to_terminal) { + std::vector vars = {"S", "I", "R"}; + printf("\n # t"); + for (size_t k = 0; k < (size_t)mio::osirmobility::InfectionState::Count; k++) { + printf(" %s", vars[k].c_str()); + } + + auto num_points = static_cast(sir.get_num_time_points()); + for (size_t i = 0; i < num_points; i++) { + printf("\n%.14f ", sir.get_time(i)); + Eigen::VectorXd res_j = sir.get_value(i); + for (size_t j = 0; j < (size_t)mio::osirmobility::InfectionState::Count; j++) { + printf(" %.14f", res_j[j]); + } + } + + Eigen::VectorXd res_j = sir.get_last_value(); + printf("\nnumber total: %f \n", res_j[0] + res_j[1] + res_j[2]); + } +} diff --git a/cpp/models/ode_sir_mobility/CMakeLists.txt b/cpp/models/ode_sir_mobility/CMakeLists.txt new file mode 100644 index 0000000000..55605f5c94 --- /dev/null +++ b/cpp/models/ode_sir_mobility/CMakeLists.txt @@ -0,0 +1,12 @@ +add_library(ode_sir_mobility + infection_state.h + model.h + model.cpp + parameters.h +) +target_link_libraries(ode_sir_mobility PUBLIC memilio) +target_include_directories(ode_sir_mobility PUBLIC + $ + $ +) +target_compile_options(ode_sir_mobility PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_sir_mobility/README.md b/cpp/models/ode_sir_mobility/README.md new file mode 100644 index 0000000000..77f5698546 --- /dev/null +++ b/cpp/models/ode_sir_mobility/README.md @@ -0,0 +1,21 @@ + +# ODE SIR compartment model + +This model is a very simple ODE model with only three compartments and few parameters, mostly for demonstration of the MEmilio framework: +- Susceptible, may become infected at any time +- Infected, will be recovered after some time +- Recovered, recovered from infectious process (dead or recovered) + +We assume simulations over short periods of time, so that the population size can be considered constant and birth as well as (natural) mortality rates can be ignored. + +Below is an overview of the model architecture and its compartments. + +![SIR_model](https://github.com/SciCompMod/memilio/assets/69154294/01c9a2ae-2f5c-4bad-b7f0-34de651f2c73) +| Mathematical variable | C++ variable name | Description | +|---------------------------- | --------------- | -------------------------------------------------------------------------------------------------- | +| $\phi$ | `ContactPatterns` | Daily contact rate / Number of daily contacts. | +| $\rho$ | `TransmissionProbabilityOnContact` | Transmission risk for people located in the Susceptible compartment. | +| $N$ | `populations.get_total()` | Total population. | +| $T_{I}$ | `TimeInfected` | Time in days an individual stays in the Infected compartment. | + +An example can be found in [examples/ode_sir.cpp](../../examples/ode_sir.cpp) diff --git a/cpp/models/ode_sir_mobility/infection_state.h b/cpp/models/ode_sir_mobility/infection_state.h new file mode 100644 index 0000000000..dc98471c73 --- /dev/null +++ b/cpp/models/ode_sir_mobility/infection_state.h @@ -0,0 +1,25 @@ + +#ifndef ODESIRMOBILITY_INFECTIONSTATE_H +#define ODESIRMOBILITY_INFECTIONSTATE_H + +namespace mio +{ +namespace osirmobility +{ + +/** + * @brief The InfectionState enum describes the possible + * categories for the infectious state of persons + */ +enum class InfectionState +{ + Susceptible, + Infected, + Recovered, + Count +}; + +} // namespace osir +} // namespace mio + +#endif // ODESIR_INFECTIONSTATE_H diff --git a/cpp/models/ode_sir_mobility/model.cpp b/cpp/models/ode_sir_mobility/model.cpp new file mode 100644 index 0000000000..0f8bf7b573 --- /dev/null +++ b/cpp/models/ode_sir_mobility/model.cpp @@ -0,0 +1,10 @@ + +#include "ode_sir_mobility/model.h" + +namespace mio +{ +namespace osirmobility +{ + +} // namespace osir +} // namespace mio diff --git a/cpp/models/ode_sir_mobility/model.h b/cpp/models/ode_sir_mobility/model.h new file mode 100644 index 0000000000..8ba2678299 --- /dev/null +++ b/cpp/models/ode_sir_mobility/model.h @@ -0,0 +1,52 @@ + +#ifndef ODESIRMOBILITY_MODEL_H +#define ODESIRMOBILITY_MODEL_H + +#include "memilio/compartments/compartmentalmodel.h" +#include "memilio/epidemiology/populations.h" +#include "memilio/epidemiology/contact_matrix.h" +#include "memilio/mobility/graph.h" +#include "ode_sir_mobility/infection_state.h" +#include "ode_sir_mobility/parameters.h" +#include "ode_sir_mobility/regions.h" + +namespace mio +{ +namespace osirmobility +{ + +/******************** + * define the model * + ********************/ + +class Model : public CompartmentalModel, Parameters> +{ + using Base = CompartmentalModel, Parameters>; + +public: + Model(int num_regions) + : Base(Populations({InfectionState::Count, Region(num_regions)}, 0.), ParameterSet()) + { + } + + void get_derivatives(Eigen::Ref pop, Eigen::Ref y, double t, + Eigen::Ref dydt) const override + { + auto& params = this->parameters; + double coeffStoI = params.get().get_matrix_at(t)(0, 0) * + params.get() / populations.get_total(); + + dydt[(size_t)InfectionState::Susceptible] = + -coeffStoI * y[(size_t)InfectionState::Susceptible] * pop[(size_t)InfectionState::Infected]; + dydt[(size_t)InfectionState::Infected] = + coeffStoI * y[(size_t)InfectionState::Susceptible] * pop[(size_t)InfectionState::Infected] - + (1.0 / params.get()) * y[(size_t)InfectionState::Infected]; + dydt[(size_t)InfectionState::Recovered] = + (1.0 / params.get()) * y[(size_t)InfectionState::Infected]; + } +}; + +} // namespace osir +} // namespace mio + +#endif // ODESIR_MODEL_H diff --git a/cpp/models/ode_sir_mobility/parameters.h b/cpp/models/ode_sir_mobility/parameters.h new file mode 100644 index 0000000000..8a5d6b23d1 --- /dev/null +++ b/cpp/models/ode_sir_mobility/parameters.h @@ -0,0 +1,162 @@ + +#ifndef SIRMOBILITY_PARAMETERS_H +#define SIRMOBILITY_PARAMETERS_H + +#include "memilio/utils/uncertain_value.h" +#include "memilio/epidemiology/contact_matrix.h" +#include "memilio/utils/parameter_set.h" + +#include + +namespace mio +{ +namespace osirmobility +{ + +/******************************************* + * Define Parameters of the SIR model * + *******************************************/ + +/** + * @brief probability of getting infected from a contact + */ +struct TransmissionProbabilityOnContact { + using Type = UncertainValue; + static Type get_default() + { + return Type(1.0); + } + static std::string name() + { + return "TransmissionProbabilityOnContact"; + } +}; + +/** + * @brief the infectious time in day unit + */ +struct TimeInfected { + using Type = UncertainValue; + static Type get_default() + { + return Type(6.0); + } + static std::string name() + { + return "TimeInfected"; + } +}; + +/** + * @brief the contact patterns within the society are modelled using a ContactMatrix + */ +struct ContactPatterns { + using Type = ContactMatrix; + static Type get_default() + { + return Type{1}; + } + static std::string name() + { + return "ContactPatterns"; + } +}; + +using ParametersBase = ParameterSet; + +/** + * @brief Parameters of SIR model. + */ +class Parameters : public ParametersBase +{ +public: + Parameters() + : ParametersBase() + { + } + + /** + * @brief Checks whether all Parameters satisfy their corresponding constraints and applies them, if they do not. + * Time spans cannot be negative and probabilities can only take values between [0,1]. + * + * Attention: This function should be used with care. It is necessary for some test problems to run through quickly, + * but in a manual execution of an example, check_constraints() may be preferred. Note that the apply_constraints() + * function can and will not set Parameters to meaningful values in an epidemiological or virological context, + * as all models are designed to be transferable to multiple diseases. Consequently, only acceptable + * (like 0 or 1 for probabilities or small positive values for time spans) values are set here and a manual adaptation + * may often be necessary to have set meaningful values. + * + * @return Returns true if one ore more constraint were corrected, false otherwise. + */ + bool apply_constraints() + { + double tol_times = 1e-1; + + int corrected = false; + if (this->get() < tol_times) { + log_warning("Constraint check: Parameter TimeInfected changed from {:.4f} to {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->get(), tol_times); + this->get() = tol_times; + corrected = true; + } + if (this->get() < 0.0 || + this->get() > 1.0) { + log_warning("Constraint check: Parameter TransmissionProbabilityOnContact changed from {:0.4f} to {:d} ", + this->get(), 0.0); + this->get() = 0.0; + corrected = true; + } + return corrected; + } + + /** + * @brief Checks whether all Parameters satisfy their corresponding constraints and logs an error + * if constraints are not satisfied. + * @return Returns true if one constraint is not satisfied, otherwise false. + */ + bool check_constraints() const + { + double tol_times = 1e-1; + + if (this->get() < tol_times) { + log_error("Constraint check: Parameter TimeInfected {:.4f} smaller or equal {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->get(), 0.0); + return true; + } + if (this->get() < 0.0 || + this->get() > 1.0) { + log_error( + "Constraint check: Parameter TransmissionProbabilityOnContact {:.4f} smaller {:.4f} or greater {:.4f}", + this->get(), 0.0, 1.0); + return true; + } + return false; + } + +private: + Parameters(ParametersBase&& base) + : ParametersBase(std::move(base)) + { + } + +public: + /** + * deserialize an object of this class. + * @see mio::deserialize + */ + template + static IOResult deserialize(IOContext& io) + { + BOOST_OUTCOME_TRY(base, ParametersBase::deserialize(io)); + return success(Parameters(std::move(base))); + } +}; + +} // namespace osir +} // namespace mio + +#endif // SIR_PARAMETERS_H diff --git a/cpp/models/ode_sir_mobility/regions.h b/cpp/models/ode_sir_mobility/regions.h new file mode 100644 index 0000000000..d3c8b528a7 --- /dev/null +++ b/cpp/models/ode_sir_mobility/regions.h @@ -0,0 +1,26 @@ + +#ifndef ODESIRMOBILITY_REGIONS_H +#define ODESIRMOBILITY_REGIONS_H + +#include "memilio/utils/index.h" + +namespace mio +{ +namespace osirmobility +{ + +/** + * @brief The AgeGroup struct is used as a dynamically + * sized tag for all age dependent categories + */ +struct Region : public Index { + Region(size_t val) + : Index(val) + { + } +}; + +} // namespace osirmobility +} // namespace mio + +#endif From 941625639680870f5dbf19db2c8140a0165b9fc8 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:16:53 +0200 Subject: [PATCH 02/87] working SIR model without infections during commuting --- cpp/examples/CMakeLists.txt | 4 ++ cpp/examples/ode_sir_mobility_simple.cpp | 83 ++++++++++++++++++++++++ cpp/models/ode_sir_mobility/model.h | 58 +++++++++++------ cpp/models/ode_sir_mobility/parameters.h | 56 +++++++++++++--- 4 files changed, 174 insertions(+), 27 deletions(-) create mode 100644 cpp/examples/ode_sir_mobility_simple.cpp diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 4b3250b7b3..5f6e753cf0 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -30,6 +30,10 @@ add_executable(ode_sir_mobility_example ode_sir_mobility.cpp) target_link_libraries(ode_sir_mobility_example PRIVATE memilio ode_sir_mobility) target_compile_options(ode_sir_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ode_sir_mobility_example_simple ode_sir_mobility_simple.cpp) +target_link_libraries(ode_sir_mobility_example_simple PRIVATE memilio ode_sir_mobility) +target_compile_options(ode_sir_mobility_example_simple PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(sde_sirs_example sde_sirs.cpp) target_link_libraries(sde_sirs_example PRIVATE memilio sde_sirs) target_compile_options(sde_sirs_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/examples/ode_sir_mobility_simple.cpp b/cpp/examples/ode_sir_mobility_simple.cpp new file mode 100644 index 0000000000..69e77899d9 --- /dev/null +++ b/cpp/examples/ode_sir_mobility_simple.cpp @@ -0,0 +1,83 @@ + +#include "memilio/compartments/simulation.h" +#include "memilio/math/euler.h" +#include "memilio/utils/logging.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/io/mobility_io.h" +#include "ode_sir_mobility/infection_state.h" +#include "ode_sir_mobility/model.h" +#include "ode_sir_mobility/parameters.h" +#include "ode_sir_mobility/regions.h" +#include "ode_sir_mobility/contact_location.h" + +int main() +{ + mio::set_log_level(mio::LogLevel::debug); + + double t0 = 0.; + double tmax = 50.; + double dt = 1; + + size_t number_regions = 2; + size_t total_population_per_region = 10; + + mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); + + mio::osirmobility::Model model(number_regions); + + for (size_t i = 0; i < number_regions; i++) { + // model.populations[{mio::Index( + // mio::osirmobility::Region(i), mio::osirmobility::InfectionState::Infected)}] = 1; + model.populations[{mio::Index( + mio::osirmobility::Region(1), mio::osirmobility::InfectionState::Infected)}] = 5; + model.populations[{mio::Index( + mio::osirmobility::Region(0), mio::osirmobility::InfectionState::Infected)}] = 0; + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::osirmobility::InfectionState::Recovered)}] = 0; + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::osirmobility::InfectionState::Susceptible)}] = + total_population_per_region - + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::osirmobility::InfectionState::Infected)}] - + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::osirmobility::InfectionState::Recovered)}]; + } + + model.parameters.set(2); + model.parameters.set(0.04); + model.parameters.get().get_baseline()(0, 0) = 1.; + // model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); + model.parameters.get().push_back( + {mio::osirmobility::Region(0), mio::osirmobility::Region(1), 0.}); + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.5}); + + auto integrator = std::make_shared(); + + model.check_constraints(); + + auto sir = simulate(t0, tmax, dt, model, integrator); + + bool print_to_terminal = true; + + sir.print_table(); + + if (print_to_terminal) { + + std::vector vars = {"S", "I", "R"}; + printf("Number of time points :%d\n", static_cast(sir.get_num_time_points())); + printf("People in\n"); + + for (size_t k = 0; k < (size_t)mio::osirmobility::InfectionState::Count; k++) { + double dummy = 0; + + for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { + printf("\t %s[%d]: %.2f", vars[k].c_str(), (int)i, + sir.get_last_value()[k + (size_t)mio::osirmobility::InfectionState::Count * (int)i]); + dummy += sir.get_last_value()[k + (size_t)mio::osirmobility::InfectionState::Count * (int)i]; + } + + printf("\t %s_total: %.2f\n", vars[k].c_str(), dummy); + } + } +} diff --git a/cpp/models/ode_sir_mobility/model.h b/cpp/models/ode_sir_mobility/model.h index 8ba2678299..5eb8ca0fdd 100644 --- a/cpp/models/ode_sir_mobility/model.h +++ b/cpp/models/ode_sir_mobility/model.h @@ -2,10 +2,8 @@ #ifndef ODESIRMOBILITY_MODEL_H #define ODESIRMOBILITY_MODEL_H -#include "memilio/compartments/compartmentalmodel.h" +#include "memilio/compartments/flow_model.h" #include "memilio/epidemiology/populations.h" -#include "memilio/epidemiology/contact_matrix.h" -#include "memilio/mobility/graph.h" #include "ode_sir_mobility/infection_state.h" #include "ode_sir_mobility/parameters.h" #include "ode_sir_mobility/regions.h" @@ -19,34 +17,56 @@ namespace osirmobility * define the model * ********************/ -class Model : public CompartmentalModel, Parameters> +using Flows = TypeList, + Flow>; + +class Model : public FlowModel, Parameters, Flows> { - using Base = CompartmentalModel, Parameters>; + + using Base = FlowModel, Parameters, Flows>; public: Model(int num_regions) - : Base(Populations({InfectionState::Count, Region(num_regions)}, 0.), ParameterSet()) + : Base(Populations({Region(num_regions), InfectionState::Count}, 0.), ParameterSet(num_regions)) { } + // Einmal über den Vektor und später nochmal über die Regions - void get_derivatives(Eigen::Ref pop, Eigen::Ref y, double t, - Eigen::Ref dydt) const override + void get_flows(Eigen::Ref pop, Eigen::Ref y, double t, + Eigen::Ref flows) const override { auto& params = this->parameters; + auto& population = this->populations; + double coeffStoI = params.get().get_matrix_at(t)(0, 0) * - params.get() / populations.get_total(); - - dydt[(size_t)InfectionState::Susceptible] = - -coeffStoI * y[(size_t)InfectionState::Susceptible] * pop[(size_t)InfectionState::Infected]; - dydt[(size_t)InfectionState::Infected] = - coeffStoI * y[(size_t)InfectionState::Susceptible] * pop[(size_t)InfectionState::Infected] - - (1.0 / params.get()) * y[(size_t)InfectionState::Infected]; - dydt[(size_t)InfectionState::Recovered] = - (1.0 / params.get()) * y[(size_t)InfectionState::Infected]; + params.get() / population.get_total(); + + Region n_regions = params.get_num_regions(); + + for (auto edge : params.get()) { + auto start_region = get<0>(edge); + auto end_region = get<1>(edge); + auto strength = get(edge); + // s_n += h_mn/P_m * i_m + flows[get_flat_flow_index(start_region)] += + strength * pop[population.get_flat_index({end_region, InfectionState::Infected})]; + // s_m += h_mn/P_m * i_n + flows[get_flat_flow_index(end_region)] += + strength * pop[population.get_flat_index({start_region, InfectionState::Infected})]; + } + + for (auto i = Region(0); i < n_regions; i++) { + flows[get_flat_flow_index({i})] += + pop[population.get_flat_index({i, InfectionState::Infected})]; + flows[get_flat_flow_index({i})] *= + coeffStoI * y[population.get_flat_index({i, InfectionState::Susceptible})]; + flows[get_flat_flow_index({i})] = + (1.0 / params.get()) * y[population.get_flat_index({i, InfectionState::Infected})]; + } } }; -} // namespace osir +} // namespace osirmobility } // namespace mio -#endif // ODESIR_MODEL_H +#endif // ODESIRMOBILITY_MODEL_H diff --git a/cpp/models/ode_sir_mobility/parameters.h b/cpp/models/ode_sir_mobility/parameters.h index 8a5d6b23d1..a429bf1f26 100644 --- a/cpp/models/ode_sir_mobility/parameters.h +++ b/cpp/models/ode_sir_mobility/parameters.h @@ -5,6 +5,9 @@ #include "memilio/utils/uncertain_value.h" #include "memilio/epidemiology/contact_matrix.h" #include "memilio/utils/parameter_set.h" +#include "memilio/utils/custom_index_array.h" +#include +#include "regions.h" #include @@ -62,7 +65,35 @@ struct ContactPatterns { } }; -using ParametersBase = ParameterSet; +/** + * @brief The mean number of Persons migrating from one Region to another during a Time interval + */ +struct CommutingRatio { + using Type = std::vector>; + static Type get_default() + { + return Type({{Region(0), Region(0), 0.}}); + } + static std::string name() + { + return "CommutingRatio"; + } +}; + +struct ImpactCommuters { + using Type = UncertainValue; + static Type get_default() + { + return Type(1.0); + } + static std::string name() + { + return "ImpactCommuters"; + } +}; + +using ParametersBase = + ParameterSet; /** * @brief Parameters of SIR model. @@ -70,11 +101,17 @@ using ParametersBase = ParameterSet Date: Fri, 26 Apr 2024 14:39:52 +0200 Subject: [PATCH 03/87] add infections during commuting and age groups --- cpp/examples/ode_sir_mobility_simple.cpp | 139 +++++++++++++++++++---- cpp/models/ode_sir_mobility/model.h | 74 ++++++++---- cpp/models/ode_sir_mobility/parameters.h | 67 +++++++---- 3 files changed, 217 insertions(+), 63 deletions(-) diff --git a/cpp/examples/ode_sir_mobility_simple.cpp b/cpp/examples/ode_sir_mobility_simple.cpp index 69e77899d9..465a45ecfb 100644 --- a/cpp/examples/ode_sir_mobility_simple.cpp +++ b/cpp/examples/ode_sir_mobility_simple.cpp @@ -9,6 +9,99 @@ #include "ode_sir_mobility/parameters.h" #include "ode_sir_mobility/regions.h" #include "ode_sir_mobility/contact_location.h" +#include "memilio/io/io.h" + +mio::IOResult>>> read_path_mobility(const std::string& filename) +{ + BOOST_OUTCOME_TRY(num_lines, mio::count_lines(filename)); + + if (num_lines == 0) { + std::vector>> arr(0, std::vector>(0)); + return mio::success(arr); + } + + std::fstream file; + file.open(filename, std::ios::in); + if (!file.is_open()) { + return failure(mio::StatusCode::FileNotFound, filename); + } + + std::vector>> arr(std::sqrt(num_lines), + std::vector>(std::sqrt(num_lines))); + + try { + std::string tp; + while (getline(file, tp)) { + auto line = mio::split(tp, ' '); + int indx_x = std::stoi(line[0]); + int indx_y = std::stoi(line[1]); + if (indx_x != indx_y) { + auto path = std::accumulate(line.begin() + 2, line.end(), std::string("")); + + // string -> vector of integers + std::vector path_vec; + + // Remove the square brackets and \r + path = path.substr(1, path.size() - 3); + std::stringstream ss(path); + std::string token; + + // get numbers and save them in path_vec + while (std::getline(ss, token, ',')) { + path_vec.push_back(std::stoi(token)); + } + + // Sorted by end location + for (int number : path_vec) { + if (number != indx_x && number != indx_y) { + arr[indx_x][indx_y].push_back(number); + } + } + } + } + } + catch (std::runtime_error& ex) { + return failure(mio::StatusCode::InvalidFileFormat, filename + ": " + ex.what()); + } + + return mio::success(arr); +} + +mio::IOResult run(const std::string& filename, mio::osirmobility::Model& model) +{ + BOOST_OUTCOME_TRY(mobility_paths, read_path_mobility(filename)); + size_t n_regions = (size_t)model.parameters.get_num_regions(); + for (size_t i = 0; i < n_regions; i++) { + for (size_t j = 0; j < n_regions; j++) { + if (j == i) { + continue; + } + std::sort(mobility_paths[i][j].begin(), mobility_paths[i][j].end()); + std::vector intersection_int; + std::vector intersection_region(intersection_int.size(), + mio::osirmobility::Region(0)); + for (size_t k = 0; k < n_regions; k++) { + if (k == i || k == j) { + continue; + } + std::sort(mobility_paths[k][j].begin(), mobility_paths[k][j].end()); + std::set_intersection(mobility_paths[i][j].begin(), mobility_paths[i][j].end(), + mobility_paths[k][j].begin(), mobility_paths[k][j].end(), + std::back_inserter(intersection_int)); + + if (intersection_int.begin() != intersection_int.end()) { + intersection_region.push_back(mio::osirmobility::Region(k)); + intersection_int.pop_back(); + } + } + if (intersection_region.begin() != intersection_region.end()) { + model.parameters.get()[mio::Index( + mio::osirmobility::Region(i), mio::osirmobility::Region(j))] = intersection_region; + } + } + } + return mio::success(); +} int main() { @@ -18,39 +111,47 @@ int main() double tmax = 50.; double dt = 1; - size_t number_regions = 2; + size_t number_regions = 4; + size_t number_age_groups = 1; size_t total_population_per_region = 10; mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - mio::osirmobility::Model model(number_regions); + const std::string& filename = ""; + + mio::osirmobility::Model model(number_regions, number_age_groups); for (size_t i = 0; i < number_regions; i++) { - // model.populations[{mio::Index( - // mio::osirmobility::Region(i), mio::osirmobility::InfectionState::Infected)}] = 1; - model.populations[{mio::Index( - mio::osirmobility::Region(1), mio::osirmobility::InfectionState::Infected)}] = 5; - model.populations[{mio::Index( - mio::osirmobility::Region(0), mio::osirmobility::InfectionState::Infected)}] = 0; - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::osirmobility::InfectionState::Recovered)}] = 0; - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::osirmobility::InfectionState::Susceptible)}] = + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] = 1; + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered)}] = 0; + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Susceptible)}] = total_population_per_region - - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::osirmobility::InfectionState::Infected)}] - - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::osirmobility::InfectionState::Recovered)}]; + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] - + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered)}]; } model.parameters.set(2); model.parameters.set(0.04); + model.parameters.set(1.); model.parameters.get().get_baseline()(0, 0) = 1.; - // model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); - model.parameters.get().push_back( - {mio::osirmobility::Region(0), mio::osirmobility::Region(1), 0.}); + model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); model.parameters.get().push_back( {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.5}); + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(2), 0.8}); + model.parameters.get().push_back( + {mio::osirmobility::Region(2), mio::osirmobility::Region(0), 0.5}); + model.parameters.get().push_back( + {mio::osirmobility::Region(0), mio::osirmobility::Region(3), 1.0}); + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(3), 0.8}); + + auto preprocess = run(filename, model); auto integrator = std::make_shared(); diff --git a/cpp/models/ode_sir_mobility/model.h b/cpp/models/ode_sir_mobility/model.h index 5eb8ca0fdd..a121f2ae0a 100644 --- a/cpp/models/ode_sir_mobility/model.h +++ b/cpp/models/ode_sir_mobility/model.h @@ -7,6 +7,7 @@ #include "ode_sir_mobility/infection_state.h" #include "ode_sir_mobility/parameters.h" #include "ode_sir_mobility/regions.h" +#include "memilio/epidemiology/age_group.h" namespace mio { @@ -20,14 +21,15 @@ namespace osirmobility using Flows = TypeList, Flow>; -class Model : public FlowModel, Parameters, Flows> +class Model : public FlowModel, Parameters, Flows> { - using Base = FlowModel, Parameters, Flows>; + using Base = FlowModel, Parameters, Flows>; public: - Model(int num_regions) - : Base(Populations({Region(num_regions), InfectionState::Count}, 0.), ParameterSet(num_regions)) + Model(int num_regions, int num_agegroups) + : Base(Populations({Region(num_regions), AgeGroup(num_agegroups), InfectionState::Count}, 0.), + ParameterSet(num_regions, num_agegroups)) { } // Einmal über den Vektor und später nochmal über die Regions @@ -41,27 +43,53 @@ class Model : public FlowModel().get_matrix_at(t)(0, 0) * params.get() / population.get_total(); - Region n_regions = params.get_num_regions(); + Region n_regions = params.get_num_regions(); + AgeGroup n_agegroups = params.get_num_agegroups(); + for (auto age = AgeGroup(0); age < n_agegroups; age++) { + for (auto edge : params.get()) { + auto start_region = get<0>(edge); + auto end_region = get<1>(edge); + auto strength = get(edge); + if (start_region == end_region) { + continue; + } + // s_n += h_mn/P_m * i_m + flows[get_flat_flow_index( + {start_region, age})] += + strength * pop[population.get_flat_index({end_region, age, InfectionState::Infected})]; + // s_m += h_mn/P_m * i_n + flows[get_flat_flow_index({end_region, age})] += + strength * pop[population.get_flat_index({start_region, age, InfectionState::Infected})]; - for (auto edge : params.get()) { - auto start_region = get<0>(edge); - auto end_region = get<1>(edge); - auto strength = get(edge); - // s_n += h_mn/P_m * i_m - flows[get_flat_flow_index(start_region)] += - strength * pop[population.get_flat_index({end_region, InfectionState::Infected})]; - // s_m += h_mn/P_m * i_n - flows[get_flat_flow_index(end_region)] += - strength * pop[population.get_flat_index({start_region, InfectionState::Infected})]; - } + // s_n += gamma * h_nm/P_n * sum(h_km/P_k * p_nm,k * i_k) + for (auto edge_commuter : params.get()) { + auto start_region_commuter = get<0>(edge_commuter); + auto end_region_commuter = get<1>(edge_commuter); + auto strength_commuter = get(edge_commuter); + if (end_region_commuter != end_region || start_region_commuter == start_region || + ((std::find(params.get()[{start_region, end_region}].begin(), + params.get()[{start_region, end_region}].end(), + start_region_commuter)) == + params.get()[{start_region, end_region}].end())) { + continue; + } + auto test = params.get()[{start_region, end_region}]; + flows[get_flat_flow_index( + {start_region, age})] += + params.get() * strength * strength_commuter * + pop[population.get_flat_index({start_region_commuter, age, InfectionState::Infected})]; + } + } - for (auto i = Region(0); i < n_regions; i++) { - flows[get_flat_flow_index({i})] += - pop[population.get_flat_index({i, InfectionState::Infected})]; - flows[get_flat_flow_index({i})] *= - coeffStoI * y[population.get_flat_index({i, InfectionState::Susceptible})]; - flows[get_flat_flow_index({i})] = - (1.0 / params.get()) * y[population.get_flat_index({i, InfectionState::Infected})]; + for (auto i = Region(0); i < n_regions; i++) { + flows[get_flat_flow_index({i, age})] += + pop[population.get_flat_index({i, age, InfectionState::Infected})]; + flows[get_flat_flow_index({i, age})] *= + coeffStoI * y[population.get_flat_index({i, age, InfectionState::Susceptible})]; + flows[get_flat_flow_index({i, age})] = + (1.0 / params.get()) * + y[population.get_flat_index({i, age, InfectionState::Infected})]; + } } } }; diff --git a/cpp/models/ode_sir_mobility/parameters.h b/cpp/models/ode_sir_mobility/parameters.h index a429bf1f26..90e95dad3a 100644 --- a/cpp/models/ode_sir_mobility/parameters.h +++ b/cpp/models/ode_sir_mobility/parameters.h @@ -4,10 +4,10 @@ #include "memilio/utils/uncertain_value.h" #include "memilio/epidemiology/contact_matrix.h" +#include "memilio/epidemiology/age_group.h" #include "memilio/utils/parameter_set.h" #include "memilio/utils/custom_index_array.h" -#include -#include "regions.h" +#include "ode_sir_mobility/regions.h" #include @@ -16,16 +16,16 @@ namespace mio namespace osirmobility { -/******************************************* - * Define Parameters of the SIR model * - *******************************************/ +/**************************************************** + * Define Parameters of the SIR model with mobility * + ****************************************************/ /** - * @brief probability of getting infected from a contact - */ + * @brief Probability of getting infected from a contact. + */ struct TransmissionProbabilityOnContact { using Type = UncertainValue; - static Type get_default() + static Type get_default(Region) { return Type(1.0); } @@ -36,11 +36,11 @@ struct TransmissionProbabilityOnContact { }; /** - * @brief the infectious time in day unit + * @brief The infectious time in day unit. */ struct TimeInfected { using Type = UncertainValue; - static Type get_default() + static Type get_default(Region) { return Type(6.0); } @@ -51,11 +51,11 @@ struct TimeInfected { }; /** - * @brief the contact patterns within the society are modelled using a ContactMatrix + * @brief The contact patterns within the society are modelled using a ContactMatrix. */ struct ContactPatterns { using Type = ContactMatrix; - static Type get_default() + static Type get_default(Region) { return Type{1}; } @@ -66,11 +66,11 @@ struct ContactPatterns { }; /** - * @brief The mean number of Persons migrating from one Region to another during a Time interval - */ + * @brief The mean number of people migrating from one Region to another during a TimeStep. + */ struct CommutingRatio { using Type = std::vector>; - static Type get_default() + static Type get_default(Region) { return Type({{Region(0), Region(0), 0.}}); } @@ -80,11 +80,14 @@ struct CommutingRatio { } }; +/** + * @brief The ratio that regulates the infections during commuting. +*/ struct ImpactCommuters { using Type = UncertainValue; - static Type get_default() + static Type get_default(Region) { - return Type(1.0); + return Type(0.); } static std::string name() { @@ -92,8 +95,23 @@ struct ImpactCommuters { } }; -using ParametersBase = - ParameterSet; +/** + * @brief The Region%s that a person crosses when travelling from one Region to another. +*/ +struct PathIntersections { + using Type = CustomIndexArray, Region, Region>; + static Type get_default(Region size) + { + return Type({size, size}); + } + static std::string name() + { + return "PathIntersections"; + } +}; + +using ParametersBase = ParameterSet; /** * @brief Parameters of SIR model. @@ -101,9 +119,10 @@ using ParametersBase = class Parameters : public ParametersBase { public: - Parameters(Region num_regions) - : ParametersBase() //TODO: Is this fine? + Parameters(Region num_regions, AgeGroup num_agegroups) + : ParametersBase(num_regions) , m_num_regions{num_regions} + , m_num_agegroups(num_agegroups) { } @@ -112,6 +131,11 @@ class Parameters : public ParametersBase return m_num_regions; } + AgeGroup get_num_agegroups() const + { + return m_num_agegroups; + } + /** * @brief Checks whether all Parameters satisfy their corresponding constraints and applies them, if they do not. * Time spans cannot be negative and probabilities can only take values between [0,1]. @@ -194,6 +218,7 @@ class Parameters : public ParametersBase private: Region m_num_regions; + AgeGroup m_num_agegroups; }; } // namespace osirmobility From 2b883b6b358d5afe8e9b5360e1bcbf1cba1b8c6c Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Fri, 26 Apr 2024 15:16:11 +0200 Subject: [PATCH 04/87] read in mobility data for new model --- cpp/examples/ode_sir_mobility.cpp | 63 ------------------------ cpp/examples/ode_sir_mobility_simple.cpp | 36 ++++++++++++-- 2 files changed, 33 insertions(+), 66 deletions(-) delete mode 100644 cpp/examples/ode_sir_mobility.cpp diff --git a/cpp/examples/ode_sir_mobility.cpp b/cpp/examples/ode_sir_mobility.cpp deleted file mode 100644 index e7510298cb..0000000000 --- a/cpp/examples/ode_sir_mobility.cpp +++ /dev/null @@ -1,63 +0,0 @@ - -#include "memilio/compartments/simulation.h" -#include "memilio/math/euler.h" -#include "memilio/utils/logging.h" -#include "memilio/epidemiology/age_group.h" -#include "ode_sir_mobility/infection_state.h" -#include "ode_sir_mobility/model.h" -#include "ode_sir_mobility/parameters.h" -#include "ode_sir_mobility/regions.h" - -int main() -{ - mio::set_log_level(mio::LogLevel::debug); - - double t0 = 0.; - double tmax = 50.; - double dt = 0.1; - - double total_population = 1061000; - - mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - - mio::osirmobility::Model model(5); - - model.populations[{mio::Index(mio::osirmobility::InfectionState::Infected, mio::osirmobility::Region(1))}] = 1000; - model.populations[{mio::Index(mio::osirmobility::InfectionState::Recovered, mio::osirmobility::Region(1))}] = 1000; - model.populations[{mio::Index(mio::osirmobility::InfectionState::Susceptible, mio::osirmobility::Region(1))}] = - total_population - - model.populations[{mio::Index(mio::osirmobility::InfectionState::Infected, mio::osirmobility::Region(1))}] - - model.populations[{mio::Index(mio::osirmobility::InfectionState::Recovered, mio::osirmobility::Region(1))}]; - model.parameters.set(2); - model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 2.7; - model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); - - auto integrator = std::make_shared(); - - model.check_constraints(); - - auto sir = simulate(t0, tmax, dt, model, integrator); - - bool print_to_terminal = true; - - if (print_to_terminal) { - std::vector vars = {"S", "I", "R"}; - printf("\n # t"); - for (size_t k = 0; k < (size_t)mio::osirmobility::InfectionState::Count; k++) { - printf(" %s", vars[k].c_str()); - } - - auto num_points = static_cast(sir.get_num_time_points()); - for (size_t i = 0; i < num_points; i++) { - printf("\n%.14f ", sir.get_time(i)); - Eigen::VectorXd res_j = sir.get_value(i); - for (size_t j = 0; j < (size_t)mio::osirmobility::InfectionState::Count; j++) { - printf(" %.14f", res_j[j]); - } - } - - Eigen::VectorXd res_j = sir.get_last_value(); - printf("\nnumber total: %f \n", res_j[0] + res_j[1] + res_j[2]); - } -} diff --git a/cpp/examples/ode_sir_mobility_simple.cpp b/cpp/examples/ode_sir_mobility_simple.cpp index 465a45ecfb..dbae487f2c 100644 --- a/cpp/examples/ode_sir_mobility_simple.cpp +++ b/cpp/examples/ode_sir_mobility_simple.cpp @@ -67,7 +67,7 @@ mio::IOResult>>> read_path_mobility(con return mio::success(arr); } -mio::IOResult run(const std::string& filename, mio::osirmobility::Model& model) +mio::IOResult preprocess(const std::string& filename, mio::osirmobility::Model& model) { BOOST_OUTCOME_TRY(mobility_paths, read_path_mobility(filename)); size_t n_regions = (size_t)model.parameters.get_num_regions(); @@ -103,6 +103,35 @@ mio::IOResult run(const std::string& filename, mio::osirmobility::Model& m return mio::success(); } +mio::IOResult set_mobility_weights(const std::string& mobility_data, const std::string& trip_chains, + mio::osirmobility::Model& model, size_t number_regions) +{ + BOOST_OUTCOME_TRY(preprocess(trip_chains, model)); + // mobility between nodes + BOOST_OUTCOME_TRY(mobility_data_commuter, + mio::read_mobility_plain(mobility_data + "mobility" + "commuter_migration_scaled.txt")); + if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || + mobility_data_commuter.cols() != Eigen::Index(number_regions)) { + return mio::failure(mio::StatusCode::InvalidValue, + "Mobility matrices do not have the correct size. You may need to run " + "transformMobilitydata.py from pycode memilio epidata package."); + } + + for (auto age = mio::AgeGroup(0); age < model.parameters.get_num_agegroups(); age++) { + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + for (size_t county_idx_j = 0; county_idx_j < number_regions; ++county_idx_j) { + //commuters + auto population_i = model.populations.get_group_total(mio::osirmobility::Region(county_idx_i)); + auto commuter_coeff_ij = mobility_data_commuter(county_idx_i, county_idx_j) / population_i; + model.parameters.get().push_back( + {mio::osirmobility::Region(county_idx_i), mio::osirmobility::Region(county_idx_j), + commuter_coeff_ij}); + } + } + } + return mio::success(); +} + int main() { mio::set_log_level(mio::LogLevel::debug); @@ -117,7 +146,8 @@ int main() mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& filename = ""; + const std::string& mobility_data = ""; + const std::string& trip_chain_data = ""; mio::osirmobility::Model model(number_regions, number_age_groups); @@ -151,7 +181,7 @@ int main() model.parameters.get().push_back( {mio::osirmobility::Region(1), mio::osirmobility::Region(3), 0.8}); - auto preprocess = run(filename, model); + auto result_preprocess = set_mobility_weights(mobility_data, trip_chain_data, model, number_regions); auto integrator = std::make_shared(); From d49a048931b6fe343fcc699337f6f112879f798c Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Fri, 26 Apr 2024 15:19:09 +0200 Subject: [PATCH 05/87] only add edges if weight is big enough --- cpp/examples/ode_sir_mobility_simple.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cpp/examples/ode_sir_mobility_simple.cpp b/cpp/examples/ode_sir_mobility_simple.cpp index dbae487f2c..af24a94db2 100644 --- a/cpp/examples/ode_sir_mobility_simple.cpp +++ b/cpp/examples/ode_sir_mobility_simple.cpp @@ -8,7 +8,6 @@ #include "ode_sir_mobility/model.h" #include "ode_sir_mobility/parameters.h" #include "ode_sir_mobility/regions.h" -#include "ode_sir_mobility/contact_location.h" #include "memilio/io/io.h" mio::IOResult>>> read_path_mobility(const std::string& filename) @@ -123,9 +122,11 @@ mio::IOResult set_mobility_weights(const std::string& mobility_data, const //commuters auto population_i = model.populations.get_group_total(mio::osirmobility::Region(county_idx_i)); auto commuter_coeff_ij = mobility_data_commuter(county_idx_i, county_idx_j) / population_i; - model.parameters.get().push_back( - {mio::osirmobility::Region(county_idx_i), mio::osirmobility::Region(county_idx_j), - commuter_coeff_ij}); + if (commuter_coeff_ij > 4e-5) { + model.parameters.get().push_back( + {mio::osirmobility::Region(county_idx_i), mio::osirmobility::Region(county_idx_j), + commuter_coeff_ij}); + } } } } From 56c4dd4ce12e0d4a21ff9a9c5494db64fb7df992 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 8 May 2024 12:06:40 +0200 Subject: [PATCH 06/87] correct age resolution --- cpp/examples/CMakeLists.txt | 4 - ...bility_simple.cpp => ode_sir_mobility.cpp} | 0 cpp/models/ode_sir_mobility/model.h | 85 ++++++++++--------- 3 files changed, 46 insertions(+), 43 deletions(-) rename cpp/examples/{ode_sir_mobility_simple.cpp => ode_sir_mobility.cpp} (100%) diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 5f6e753cf0..4b3250b7b3 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -30,10 +30,6 @@ add_executable(ode_sir_mobility_example ode_sir_mobility.cpp) target_link_libraries(ode_sir_mobility_example PRIVATE memilio ode_sir_mobility) target_compile_options(ode_sir_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -add_executable(ode_sir_mobility_example_simple ode_sir_mobility_simple.cpp) -target_link_libraries(ode_sir_mobility_example_simple PRIVATE memilio ode_sir_mobility) -target_compile_options(ode_sir_mobility_example_simple PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - add_executable(sde_sirs_example sde_sirs.cpp) target_link_libraries(sde_sirs_example PRIVATE memilio sde_sirs) target_compile_options(sde_sirs_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/examples/ode_sir_mobility_simple.cpp b/cpp/examples/ode_sir_mobility.cpp similarity index 100% rename from cpp/examples/ode_sir_mobility_simple.cpp rename to cpp/examples/ode_sir_mobility.cpp diff --git a/cpp/models/ode_sir_mobility/model.h b/cpp/models/ode_sir_mobility/model.h index a121f2ae0a..3936b6180d 100644 --- a/cpp/models/ode_sir_mobility/model.h +++ b/cpp/models/ode_sir_mobility/model.h @@ -40,55 +40,62 @@ class Model : public FlowModelparameters; auto& population = this->populations; - double coeffStoI = params.get().get_matrix_at(t)(0, 0) * - params.get() / population.get_total(); - Region n_regions = params.get_num_regions(); AgeGroup n_agegroups = params.get_num_agegroups(); - for (auto age = AgeGroup(0); age < n_agegroups; age++) { - for (auto edge : params.get()) { - auto start_region = get<0>(edge); - auto end_region = get<1>(edge); - auto strength = get(edge); - if (start_region == end_region) { - continue; - } - // s_n += h_mn/P_m * i_m - flows[get_flat_flow_index( - {start_region, age})] += - strength * pop[population.get_flat_index({end_region, age, InfectionState::Infected})]; - // s_m += h_mn/P_m * i_n - flows[get_flat_flow_index({end_region, age})] += - strength * pop[population.get_flat_index({start_region, age, InfectionState::Infected})]; - // s_n += gamma * h_nm/P_n * sum(h_km/P_k * p_nm,k * i_k) - for (auto edge_commuter : params.get()) { - auto start_region_commuter = get<0>(edge_commuter); - auto end_region_commuter = get<1>(edge_commuter); - auto strength_commuter = get(edge_commuter); - if (end_region_commuter != end_region || start_region_commuter == start_region || - ((std::find(params.get()[{start_region, end_region}].begin(), - params.get()[{start_region, end_region}].end(), - start_region_commuter)) == - params.get()[{start_region, end_region}].end())) { + for (auto age_i = AgeGroup(0); age_i < n_agegroups; age_i++) { + for (auto age_j = AgeGroup(0); age_j < n_agegroups; age_j++) { + double coeffStoI = + params.get().get_matrix_at(t)(static_cast((size_t)age_i), + static_cast((size_t)age_j)) * + params.get() / population.get_group_total(age_j); + for (auto edge : params.get()) { + auto start_region = get<0>(edge); + auto end_region = get<1>(edge); + auto strength = get(edge); + if (start_region == end_region) { continue; } - auto test = params.get()[{start_region, end_region}]; + // s_n += h_mn/P_m * i_m + flows[get_flat_flow_index( + {start_region, age_i})] += + strength * pop[population.get_flat_index({end_region, age_j, InfectionState::Infected})]; + // s_m += h_mn/P_m * i_n + flows[get_flat_flow_index( + {end_region, age_i})] += + strength * pop[population.get_flat_index({start_region, age_j, InfectionState::Infected})]; + + // s_n += gamma * h_nm/P_n * sum(h_km/P_k * p_nm,k * i_k) + for (auto edge_commuter : params.get()) { + auto start_region_commuter = get<0>(edge_commuter); + auto end_region_commuter = get<1>(edge_commuter); + auto strength_commuter = get(edge_commuter); + if (end_region_commuter != end_region || start_region_commuter == start_region || + ((std::find(params.get()[{start_region, end_region}].begin(), + params.get()[{start_region, end_region}].end(), + start_region_commuter)) == + params.get()[{start_region, end_region}].end())) { + continue; + } + flows[get_flat_flow_index( + {start_region, age_i})] += + params.get() * strength * strength_commuter * + pop[population.get_flat_index({start_region_commuter, age_j, InfectionState::Infected})]; + } + } + for (auto region = Region(0); region < n_regions; region++) { + flows[get_flat_flow_index( + {region, age_i})] += pop[population.get_flat_index({region, age_j, InfectionState::Infected})]; flows[get_flat_flow_index( - {start_region, age})] += - params.get() * strength * strength_commuter * - pop[population.get_flat_index({start_region_commuter, age, InfectionState::Infected})]; + {region, age_i})] *= + coeffStoI * y[population.get_flat_index({region, age_j, InfectionState::Susceptible})]; } } - for (auto i = Region(0); i < n_regions; i++) { - flows[get_flat_flow_index({i, age})] += - pop[population.get_flat_index({i, age, InfectionState::Infected})]; - flows[get_flat_flow_index({i, age})] *= - coeffStoI * y[population.get_flat_index({i, age, InfectionState::Susceptible})]; - flows[get_flat_flow_index({i, age})] = + for (auto region = Region(0); region < n_regions; region++) { + flows[get_flat_flow_index({region, age_i})] = (1.0 / params.get()) * - y[population.get_flat_index({i, age, InfectionState::Infected})]; + y[population.get_flat_index({region, age_i, InfectionState::Infected})]; } } } From 0efa8db01eeed34f07f411d8373b935bb68057c0 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 10 Jun 2024 14:59:08 +0200 Subject: [PATCH 07/87] add tests --- cpp/examples/ode_sir_mobility.cpp | 56 +++-- cpp/models/ode_sir_mobility/model.h | 2 +- cpp/models/ode_sir_mobility/parameters.h | 40 ++++ cpp/tests/CMakeLists.txt | 1 + cpp/tests/test_odesirmobility.cpp | 248 +++++++++++++++++++++++ 5 files changed, 328 insertions(+), 19 deletions(-) create mode 100644 cpp/tests/test_odesirmobility.cpp diff --git a/cpp/examples/ode_sir_mobility.cpp b/cpp/examples/ode_sir_mobility.cpp index af24a94db2..afaea9860e 100644 --- a/cpp/examples/ode_sir_mobility.cpp +++ b/cpp/examples/ode_sir_mobility.cpp @@ -94,8 +94,8 @@ mio::IOResult preprocess(const std::string& filename, mio::osirmobility::M } } if (intersection_region.begin() != intersection_region.end()) { - model.parameters.get()[mio::Index( - mio::osirmobility::Region(i), mio::osirmobility::Region(j))] = intersection_region; + model.parameters.get()[{ + mio::osirmobility::Region(i), mio::osirmobility::Region(j)}] = intersection_region; } } } @@ -143,7 +143,7 @@ int main() size_t number_regions = 4; size_t number_age_groups = 1; - size_t total_population_per_region = 10; + size_t total_population_per_region = 5000; mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); @@ -154,7 +154,7 @@ int main() for (size_t i = 0; i < number_regions; i++) { model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] = 1; + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] = 50; model.populations[{mio::Index( mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered)}] = 0; model.populations[{mio::Index( @@ -171,16 +171,34 @@ int main() model.parameters.set(1.); model.parameters.get().get_baseline()(0, 0) = 1.; model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); + model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.5}); + {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.2}); model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(2), 0.8}); + {mio::osirmobility::Region(1), mio::osirmobility::Region(2), 0.6}); model.parameters.get().push_back( {mio::osirmobility::Region(2), mio::osirmobility::Region(0), 0.5}); model.parameters.get().push_back( {mio::osirmobility::Region(0), mio::osirmobility::Region(3), 1.0}); model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(3), 0.8}); + {mio::osirmobility::Region(1), mio::osirmobility::Region(3), 0.2}); + + model.parameters.get()[{mio::osirmobility::Region(0), + mio::osirmobility::Region(1)}] = {2}; + model.parameters.get()[{mio::osirmobility::Region(0), + mio::osirmobility::Region(3)}] = {2}; + model.parameters.get()[{mio::osirmobility::Region(1), + mio::osirmobility::Region(0)}] = {2}; + model.parameters.get()[{mio::osirmobility::Region(1), + mio::osirmobility::Region(2)}] = {0}; + model.parameters.get()[{mio::osirmobility::Region(1), + mio::osirmobility::Region(3)}] = {2}; + model.parameters.get()[{mio::osirmobility::Region(2), + mio::osirmobility::Region(1)}] = {0}; + model.parameters.get()[{mio::osirmobility::Region(3), + mio::osirmobility::Region(0)}] = {2}; + model.parameters.get()[{mio::osirmobility::Region(3), + mio::osirmobility::Region(1)}] = {2}; auto result_preprocess = set_mobility_weights(mobility_data, trip_chain_data, model, number_regions); @@ -197,19 +215,21 @@ int main() if (print_to_terminal) { std::vector vars = {"S", "I", "R"}; - printf("Number of time points :%d\n", static_cast(sir.get_num_time_points())); - printf("People in\n"); - - for (size_t k = 0; k < (size_t)mio::osirmobility::InfectionState::Count; k++) { - double dummy = 0; - - for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { - printf("\t %s[%d]: %.2f", vars[k].c_str(), (int)i, - sir.get_last_value()[k + (size_t)mio::osirmobility::InfectionState::Count * (int)i]); - dummy += sir.get_last_value()[k + (size_t)mio::osirmobility::InfectionState::Count * (int)i]; + printf("\n # t"); + for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { + for (size_t k = 0; k < (size_t)mio::osirmobility::InfectionState::Count; k++) { + printf(" %s_%d", vars[k].c_str(), (int)i); } + } - printf("\t %s_total: %.2f\n", vars[k].c_str(), dummy); + auto num_points = static_cast(sir.get_num_time_points()); + for (size_t i = 0; i < num_points; i++) { + printf("\n%.14f ", sir.get_time(i)); + for (size_t k = 0; k < (size_t)model.parameters.get_num_regions(); k++) { + for (size_t j = 0; j < (size_t)mio::osirmobility::InfectionState::Count; j++) { + printf(" %.14f", sir.get_value(i)[j + (size_t)mio::osirmobility::InfectionState::Count * (int)k]); + } + } } } } diff --git a/cpp/models/ode_sir_mobility/model.h b/cpp/models/ode_sir_mobility/model.h index 3936b6180d..dc1b019a79 100644 --- a/cpp/models/ode_sir_mobility/model.h +++ b/cpp/models/ode_sir_mobility/model.h @@ -27,7 +27,7 @@ class Model : public FlowModel, Parameters, Flows>; public: - Model(int num_regions, int num_agegroups) + Model(int num_regions, int num_agegroups = 1) : Base(Populations({Region(num_regions), AgeGroup(num_agegroups), InfectionState::Count}, 0.), ParameterSet(num_regions, num_agegroups)) { diff --git a/cpp/models/ode_sir_mobility/parameters.h b/cpp/models/ode_sir_mobility/parameters.h index 90e95dad3a..ba66109d98 100644 --- a/cpp/models/ode_sir_mobility/parameters.h +++ b/cpp/models/ode_sir_mobility/parameters.h @@ -169,6 +169,28 @@ class Parameters : public ParametersBase this->get() = 0.0; corrected = true; } + if (this->get() < 0.0 || this->get() > 1.0) { + log_warning("Constraint check: Parameter ImpactCommuters changed from {:.4f} to {:.4f}.", + this->get(), 0.0); + this->get() = 0.0; + corrected = true; + } + for (auto& i : this->get()) { + if (std::get(i) < 0.0 || std::get(i) > 1.0) { + log_warning("Constraint check: Parameter CommutingRatio changed from {:.4f} to {:.4f}.", + std::get(i), 0.0); + std::get(i) = 0.0; + corrected = true; + } + if (std::get<0>(i) < Region(0) || std::get<1>(i) < Region(0) || std::get<0>(i) >= m_num_regions || + std::get<1>(i) >= m_num_regions) { + log_warning( + "Constraint check: Removed entry of Parameter CommutingRatio because of non-existing Regions."); + auto it = std::find(this->get().begin(), this->get().end(), i); + this->get().erase(it); + corrected = true; + } + } return corrected; } @@ -195,6 +217,24 @@ class Parameters : public ParametersBase this->get(), 0.0, 1.0); return true; } + if (this->get() < 0.0 || this->get() > 1.0) { + log_error("Constraint check: Parameter ImpactCommuters {:.4f} smaller {:.4f} or greater {:.4f}", + this->get(), 0.0, 1.0); + return true; + } + for (auto i : this->get()) { + if (std::get(i) < 0.0 || std::get(i) > 1.0) { + log_error("Constraint check: Parameter CommutingRatio entry {:.4f} smaller {:.4f} or greater {:.4f}", + std::get(i), 0.0, 1.0); + return true; + } + if (std::get<0>(i) < Region(0) || std::get<1>(i) < Region(0) || std::get<0>(i) > m_num_regions || + std::get<1>(i) > m_num_regions) { + log_error("Constraint check: Parameter CommutingRatio has an entry with start or end Region that does " + "not appear in the model."); + return true; + } + } return false; } diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 9aae63e081..672ca234de 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -9,6 +9,7 @@ set(TESTSOURCES test_populations.cpp test_odeseir.cpp test_odesir.cpp + test_odesirmobility.cpp test_numericalIntegration.cpp test_smoother.cpp test_damping.cpp diff --git a/cpp/tests/test_odesirmobility.cpp b/cpp/tests/test_odesirmobility.cpp new file mode 100644 index 0000000000..13173ec405 --- /dev/null +++ b/cpp/tests/test_odesirmobility.cpp @@ -0,0 +1,248 @@ + +#include "load_test_data.h" +#include "memilio/config.h" +#include "memilio/utils/time_series.h" +#include "ode_sir_mobility/model.h" +#include "ode_sir_mobility/infection_state.h" +#include "ode_sir_mobility/parameters.h" +#include "memilio/math/euler.h" +#include "memilio/compartments/simulation.h" +#include +#include +#include + +TEST(TestOdeSirMobility, simulateDefault) +{ + double t0 = 0; + double tmax = 1; + double dt = 0.1; + + size_t num_regions = 4; + + mio::osirmobility::Model model(num_regions); + mio::TimeSeries result = simulate(t0, tmax, dt, model); + + EXPECT_NEAR(result.get_last_time(), tmax, 1e-10); +} + +TEST(TestOdeSirMobility, compareWithPreviousRun) +{ + // initialization + double t0 = 0.; + double tmax = 3.; + double dt = 0.1; + + size_t number_regions = 4; + size_t number_age_groups = 1; + size_t total_population_per_region = 5000; + + mio::osirmobility::Model model(number_regions, number_age_groups); + + for (size_t i = 0; i < number_regions; i++) { + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] = 50; + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered)}] = 0; + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Susceptible)}] = + total_population_per_region - + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] - + model.populations[{mio::Index( + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered)}]; + } + model.parameters.set(1.0); + model.parameters.set(2); + + model.parameters.get().get_baseline()(0, 0) = 2.7; + model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); + + model.parameters.set(1.); + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.2}); + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(2), 0.6}); + model.parameters.get().push_back( + {mio::osirmobility::Region(2), mio::osirmobility::Region(0), 0.5}); + model.parameters.get().push_back( + {mio::osirmobility::Region(0), mio::osirmobility::Region(3), 1.0}); + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(3), 0.2}); + + model.parameters.get()[{mio::osirmobility::Region(0), + mio::osirmobility::Region(1)}] = {2}; + model.parameters.get()[{mio::osirmobility::Region(0), + mio::osirmobility::Region(3)}] = {2}; + model.parameters.get()[{mio::osirmobility::Region(1), + mio::osirmobility::Region(0)}] = {2}; + model.parameters.get()[{mio::osirmobility::Region(1), + mio::osirmobility::Region(2)}] = {0}; + model.parameters.get()[{mio::osirmobility::Region(1), + mio::osirmobility::Region(3)}] = {2}; + model.parameters.get()[{mio::osirmobility::Region(2), + mio::osirmobility::Region(1)}] = {0}; + model.parameters.get()[{mio::osirmobility::Region(3), + mio::osirmobility::Region(0)}] = {2}; + model.parameters.get()[{mio::osirmobility::Region(3), + mio::osirmobility::Region(1)}] = {2}; + + std::vector> refData = load_test_data_csv("ode-sir-mobility-compare.csv"); + auto integrator = std::make_shared(); + auto result = mio::simulate(t0, tmax, dt, model, integrator); + + ASSERT_EQ(refData.size(), static_cast(result.get_num_time_points())); + + for (Eigen::Index irow = 0; irow < result.get_num_time_points(); ++irow) { + double t = refData[static_cast(irow)][0]; + auto rel_tol = 1e-6; + + //test result diverges at damping because of changes, not worth fixing at the moment + if (t > 11.0 && t < 13.0) { + //strong divergence around damping + rel_tol = 0.5; + } + else if (t > 13.0) { + //minor divergence after damping + rel_tol = 1e-2; + } + mio::unused(rel_tol); + + ASSERT_NEAR(t, result.get_times()[irow], 1e-12) << "at row " << irow; + + for (size_t icol = 0; icol < 12; ++icol) { + double ref = refData[static_cast(irow)][icol + 1]; + double actual = result[irow][icol]; + + double tol = rel_tol * ref; + ASSERT_NEAR(ref, actual, tol) << "at row " << irow; + } + } +} + +TEST(TestOdeSirMobility, checkPopulationConservation) +{ + // initialization + double t0 = 0.; + double tmax = 50.; + double dt = 0.1002004008016032; + + double population_per_region = 1061000; + mio::osirmobility::Region num_regions = 4; + + mio::osirmobility::Model model((size_t)num_regions); + + for (auto region = mio::osirmobility::Region(0); region < num_regions; ++region) { + model.populations[{region, mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected}] = 1000; + model.populations[{region, mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered}] = 1000; + model.populations[{region, mio::AgeGroup(0), mio::osirmobility::InfectionState::Susceptible}] = + population_per_region - + model.populations[{region, mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected}] - + model.populations[{region, mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered}]; + } + model.parameters.set(2); + model.parameters.set(0.04); + model.parameters.set(1.); + model.parameters.get().get_baseline()(0, 0) = 1.; + model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.5}); + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(2), 0.8}); + model.parameters.get().push_back( + {mio::osirmobility::Region(2), mio::osirmobility::Region(0), 0.5}); + model.parameters.get().push_back( + {mio::osirmobility::Region(0), mio::osirmobility::Region(3), 1.0}); + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(3), 0.8}); + + auto result = mio::simulate(t0, tmax, dt, model); + double num_persons = 0.0; + for (auto i = 0; i < result.get_last_value().size(); ++i) { + num_persons += result.get_last_value()[i]; + } + EXPECT_NEAR(num_persons, population_per_region * (size_t)num_regions, 1e-8); +} + +TEST(TestOdeSirMobility, check_constraints_parameters) +{ + mio::osirmobility::Region num_regions = 2; + + mio::osirmobility::Model model((size_t)num_regions); + model.parameters.set(6); + model.parameters.set(0.04); + model.parameters.set(1.); + model.parameters.get().get_baseline()(0, 0) = 10.; + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.5}); + + // model.check_constraints() combines the functions from population and parameters. + // We only want to test the functions for the parameters defined in parameters.h + ASSERT_EQ(model.parameters.check_constraints(), 0); + + mio::set_log_level(mio::LogLevel::off); + + model.parameters.set(0); + ASSERT_EQ(model.parameters.check_constraints(), 1); + + model.parameters.set(6); + model.parameters.set(10.); + ASSERT_EQ(model.parameters.check_constraints(), 1); + + model.parameters.set(0.04); + model.parameters.set(10.); + ASSERT_EQ(model.parameters.check_constraints(), 1); + + model.parameters.set(1.); + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 10.5}); + ASSERT_EQ(model.parameters.check_constraints(), 1); + + model.parameters.get().pop_back(); + model.parameters.get().push_back( + {mio::osirmobility::Region(2), mio::osirmobility::Region(0), 0.5}); + mio::set_log_level(mio::LogLevel::warn); +} + +TEST(TestOdeSirMobility, apply_constraints_parameters) +{ + const double tol_times = 1e-1; + mio::osirmobility::Region num_regions = 2; + + mio::osirmobility::Model model((size_t)num_regions); + model.parameters.set(6); + model.parameters.set(0.04); + model.parameters.set(1.); + model.parameters.get().get_baseline()(0, 0) = 10.; + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.5}); + + EXPECT_EQ(model.parameters.apply_constraints(), 0); + + mio::set_log_level(mio::LogLevel::off); + + model.parameters.set(-2.5); + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_EQ(model.parameters.get(), tol_times); + + model.parameters.set(10.); + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_NEAR(model.parameters.get(), 0.0, 1e-14); + + model.parameters.set(0.04); + model.parameters.set(10.); + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_NEAR(model.parameters.get(), 0.0, 1e-14); + + model.parameters.set(1.); + model.parameters.get().push_back( + {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 10.5}); + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_NEAR(std::get(model.parameters.get()[2]), 0.0, 1e-14); + + model.parameters.get().pop_back(); + model.parameters.get().push_back( + {mio::osirmobility::Region(2), mio::osirmobility::Region(0), 0.5}); + EXPECT_EQ(model.parameters.apply_constraints(), 1); + // EXPECT_EQ(model.parameters.get().size(), 2); // 1 by default + 1 added + mio::set_log_level(mio::LogLevel::warn); +} \ No newline at end of file From 05e3717a41cc6cc555f94f93cb9bdc559fa3b6b0 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 17 Jun 2024 14:42:24 +0200 Subject: [PATCH 08/87] add seir version of mobility model --- cpp/CMakeLists.txt | 1 + cpp/examples/CMakeLists.txt | 4 + cpp/examples/ode_seir_mobility.cpp | 238 ++++++++++++++ cpp/models/ode_seir_mobility/CMakeLists.txt | 13 + .../ode_seir_mobility/infection_state.h | 26 ++ cpp/models/ode_seir_mobility/model.cpp | 10 + cpp/models/ode_seir_mobility/model.h | 112 +++++++ cpp/models/ode_seir_mobility/parameters.h | 297 ++++++++++++++++++ cpp/models/ode_seir_mobility/regions.h | 26 ++ 9 files changed, 727 insertions(+) create mode 100644 cpp/examples/ode_seir_mobility.cpp create mode 100644 cpp/models/ode_seir_mobility/CMakeLists.txt create mode 100644 cpp/models/ode_seir_mobility/infection_state.h create mode 100644 cpp/models/ode_seir_mobility/model.cpp create mode 100644 cpp/models/ode_seir_mobility/model.h create mode 100644 cpp/models/ode_seir_mobility/parameters.h create mode 100644 cpp/models/ode_seir_mobility/regions.h diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index fec9d5b711..fd501cdd42 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -125,6 +125,7 @@ if(MEMILIO_BUILD_MODELS) add_subdirectory(models/ode_seir) add_subdirectory(models/ode_sir) add_subdirectory(models/ode_sir_mobility) + add_subdirectory(models/ode_seir_mobility) add_subdirectory(models/sde_sir) add_subdirectory(models/sde_sirs) endif() diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 4b3250b7b3..1e61f1cbce 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -30,6 +30,10 @@ add_executable(ode_sir_mobility_example ode_sir_mobility.cpp) target_link_libraries(ode_sir_mobility_example PRIVATE memilio ode_sir_mobility) target_compile_options(ode_sir_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ode_seir_mobility_example ode_seir_mobility.cpp) +target_link_libraries(ode_seir_mobility_example PRIVATE memilio ode_seir_mobility) +target_compile_options(ode_seir_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(sde_sirs_example sde_sirs.cpp) target_link_libraries(sde_sirs_example PRIVATE memilio sde_sirs) target_compile_options(sde_sirs_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/examples/ode_seir_mobility.cpp b/cpp/examples/ode_seir_mobility.cpp new file mode 100644 index 0000000000..75e5ce1141 --- /dev/null +++ b/cpp/examples/ode_seir_mobility.cpp @@ -0,0 +1,238 @@ + +#include "memilio/compartments/simulation.h" +#include "memilio/math/euler.h" +#include "memilio/utils/logging.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/io/mobility_io.h" +#include "models/ode_seir_mobility/infection_state.h" +#include "models/ode_seir_mobility/model.h" +#include "models/ode_seir_mobility/parameters.h" +#include "models/ode_seir_mobility/regions.h" +#include "memilio/io/io.h" + +mio::IOResult>>> read_path_mobility(const std::string& filename) +{ + BOOST_OUTCOME_TRY(num_lines, mio::count_lines(filename)); + + if (num_lines == 0) { + std::vector>> arr(0, std::vector>(0)); + return mio::success(arr); + } + + std::fstream file; + file.open(filename, std::ios::in); + if (!file.is_open()) { + return failure(mio::StatusCode::FileNotFound, filename); + } + + std::vector>> arr(std::sqrt(num_lines), + std::vector>(std::sqrt(num_lines))); + + try { + std::string tp; + while (getline(file, tp)) { + auto line = mio::split(tp, ' '); + int indx_x = std::stoi(line[0]); + int indx_y = std::stoi(line[1]); + if (indx_x != indx_y) { + auto path = std::accumulate(line.begin() + 2, line.end(), std::string("")); + + // string -> vector of integers + std::vector path_vec; + + // Remove the square brackets and \r + path = path.substr(1, path.size() - 3); + std::stringstream ss(path); + std::string token; + + // get numbers and save them in path_vec + while (std::getline(ss, token, ',')) { + path_vec.push_back(std::stoi(token)); + } + + // Sorted by end location + for (int number : path_vec) { + if (number != indx_x && number != indx_y) { + arr[indx_x][indx_y].push_back(number); + } + } + } + } + } + catch (std::runtime_error& ex) { + return failure(mio::StatusCode::InvalidFileFormat, filename + ": " + ex.what()); + } + + return mio::success(arr); +} + +mio::IOResult preprocess(const std::string& filename, mio::oseirmobility::Model& model) +{ + BOOST_OUTCOME_TRY(mobility_paths, read_path_mobility(filename)); + size_t n_regions = (size_t)model.parameters.get_num_regions(); + for (size_t i = 0; i < n_regions; i++) { + for (size_t j = 0; j < n_regions; j++) { + if (j == i) { + continue; + } + std::sort(mobility_paths[i][j].begin(), mobility_paths[i][j].end()); + std::vector intersection_int; + std::vector intersection_region(intersection_int.size(), + mio::oseirmobility::Region(0)); + for (size_t k = 0; k < n_regions; k++) { + if (k == i || k == j) { + continue; + } + std::sort(mobility_paths[k][j].begin(), mobility_paths[k][j].end()); + std::set_intersection(mobility_paths[i][j].begin(), mobility_paths[i][j].end(), + mobility_paths[k][j].begin(), mobility_paths[k][j].end(), + std::back_inserter(intersection_int)); + + if (intersection_int.begin() != intersection_int.end()) { + intersection_region.push_back(mio::oseirmobility::Region(k)); + intersection_int.pop_back(); + } + } + if (intersection_region.begin() != intersection_region.end()) { + model.parameters.get()[mio::Index( + mio::oseirmobility::Region(i), mio::oseirmobility::Region(j))] = intersection_region; + } + } + } + return mio::success(); +} + +mio::IOResult set_mobility_weights(const std::string& mobility_data, const std::string& trip_chains, + mio::oseirmobility::Model& model, size_t number_regions) +{ + BOOST_OUTCOME_TRY(preprocess(trip_chains, model)); + // mobility between nodes + BOOST_OUTCOME_TRY(mobility_data_commuter, + mio::read_mobility_plain(mobility_data + "mobility" + "commuter_migration_scaled.txt")); + if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || + mobility_data_commuter.cols() != Eigen::Index(number_regions)) { + return mio::failure(mio::StatusCode::InvalidValue, + "Mobility matrices do not have the correct size. You may need to run " + "transformMobilitydata.py from pycode memilio epidata package."); + } + + for (auto age = mio::AgeGroup(0); age < model.parameters.get_num_agegroups(); age++) { + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + for (size_t county_idx_j = 0; county_idx_j < number_regions; ++county_idx_j) { + //commuters + auto population_i = model.populations.get_group_total(mio::oseirmobility::Region(county_idx_i)); + auto commuter_coeff_ij = mobility_data_commuter(county_idx_i, county_idx_j) / population_i; + if (commuter_coeff_ij > 4e-5) { + model.parameters.get().push_back( + {mio::oseirmobility::Region(county_idx_i), mio::oseirmobility::Region(county_idx_j), + commuter_coeff_ij}); + } + } + } + } + return mio::success(); +} + +int main() +{ + mio::set_log_level(mio::LogLevel::debug); + + double t0 = 0.; + double tmax = 50.; + double dt = 1; + + size_t number_regions = 4; + size_t number_age_groups = 1; + size_t total_population_per_region = 10; + + mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); + + const std::string& mobility_data = ""; + const std::string& trip_chain_data = ""; + + mio::oseirmobility::Model model(number_regions, number_age_groups); + + for (size_t i = 0; i < number_regions; i++) { + model.populations[{mio::Index( + mio::oseirmobility::Region(i), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Infected)}] = 1; + model.populations[{mio::Index( + mio::oseirmobility::Region(i), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Recovered)}] = 0; + model.populations[{mio::Index( + mio::oseirmobility::Region(i), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Susceptible)}] = + total_population_per_region - + model + .populations[{mio::Index( + mio::oseirmobility::Region(i), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Infected)}] - + model + .populations[{mio::Index( + mio::oseirmobility::Region(i), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Recovered)}]; + } + + model.parameters.set(1); + model.parameters.set(2); + model.parameters.set(0.04); + model.parameters.set(1.); + model.parameters.get().get_baseline()(0, 0) = 1.; + model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); + + model.parameters.get().push_back( + {mio::oseirmobility::Region(1), mio::oseirmobility::Region(0), 0.2}); + model.parameters.get().push_back( + {mio::oseirmobility::Region(1), mio::oseirmobility::Region(2), 0.6}); + model.parameters.get().push_back( + {mio::oseirmobility::Region(2), mio::oseirmobility::Region(0), 0.5}); + model.parameters.get().push_back( + {mio::oseirmobility::Region(0), mio::oseirmobility::Region(3), 1.0}); + model.parameters.get().push_back( + {mio::oseirmobility::Region(1), mio::oseirmobility::Region(3), 0.2}); + + model.parameters.get()[{mio::oseirmobility::Region(0), + mio::oseirmobility::Region(1)}] = {2}; + model.parameters.get()[{mio::oseirmobility::Region(0), + mio::oseirmobility::Region(3)}] = {2}; + model.parameters.get()[{mio::oseirmobility::Region(1), + mio::oseirmobility::Region(0)}] = {2}; + model.parameters.get()[{mio::oseirmobility::Region(1), + mio::oseirmobility::Region(2)}] = {0}; + model.parameters.get()[{mio::oseirmobility::Region(1), + mio::oseirmobility::Region(3)}] = {2}; + model.parameters.get()[{mio::oseirmobility::Region(2), + mio::oseirmobility::Region(1)}] = {0}; + model.parameters.get()[{mio::oseirmobility::Region(3), + mio::oseirmobility::Region(0)}] = {2}; + model.parameters.get()[{mio::oseirmobility::Region(3), + mio::oseirmobility::Region(1)}] = {2}; + + // auto result_preprocess = set_mobility_weights(mobility_data, trip_chain_data, model, number_regions); + + auto integrator = std::make_shared(); + + model.check_constraints(); + + auto sir = simulate(t0, tmax, dt, model, integrator); + + bool print_to_terminal = true; + + sir.print_table(); + + if (print_to_terminal) { + + std::vector vars = {"S", "E", "I", "R"}; + printf("\n # t"); + for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { + for (size_t k = 0; k < (size_t)mio::oseirmobility::InfectionState::Count; k++) { + printf(" %s_%d", vars[k].c_str(), (int)i); + } + } + + auto num_points = static_cast(sir.get_num_time_points()); + for (size_t i = 0; i < num_points; i++) { + printf("\n%.14f ", sir.get_time(i)); + for (size_t k = 0; k < (size_t)model.parameters.get_num_regions(); k++) { + for (size_t j = 0; j < (size_t)mio::oseirmobility::InfectionState::Count; j++) { + printf(" %.14f", sir.get_value(i)[j + (size_t)mio::oseirmobility::InfectionState::Count * (int)k]); + } + } + } + } +} diff --git a/cpp/models/ode_seir_mobility/CMakeLists.txt b/cpp/models/ode_seir_mobility/CMakeLists.txt new file mode 100644 index 0000000000..ecf6e3112b --- /dev/null +++ b/cpp/models/ode_seir_mobility/CMakeLists.txt @@ -0,0 +1,13 @@ +add_library(ode_seir_mobility + infection_state.h + model.h + model.cpp + parameters.h + regions.h +) +target_link_libraries(ode_seir_mobility PUBLIC memilio) +target_include_directories(ode_seir_mobility PUBLIC + $ + $ +) +target_compile_options(ode_seir_mobility PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_seir_mobility/infection_state.h b/cpp/models/ode_seir_mobility/infection_state.h new file mode 100644 index 0000000000..f4207708b3 --- /dev/null +++ b/cpp/models/ode_seir_mobility/infection_state.h @@ -0,0 +1,26 @@ + +#ifndef ODESEIRMOBILITY_INFECTIONSTATE_H +#define ODESEIRMOBILITY_INFECTIONSTATE_H + +namespace mio +{ +namespace oseirmobility +{ + +/** + * @brief The InfectionState enum describes the possible + * categories for the infectious state of persons + */ +enum class InfectionState +{ + Susceptible, + Exposed, + Infected, + Recovered, + Count +}; + +} // namespace oseirmobility +} // namespace mio + +#endif // ODESEIR_INFECTIONSTATE_H diff --git a/cpp/models/ode_seir_mobility/model.cpp b/cpp/models/ode_seir_mobility/model.cpp new file mode 100644 index 0000000000..75494e52d6 --- /dev/null +++ b/cpp/models/ode_seir_mobility/model.cpp @@ -0,0 +1,10 @@ + +#include "ode_seir_mobility/model.h" + +namespace mio +{ +namespace oseirmobility +{ + +} // namespace oseirmobility +} // namespace mio diff --git a/cpp/models/ode_seir_mobility/model.h b/cpp/models/ode_seir_mobility/model.h new file mode 100644 index 0000000000..647a01dac1 --- /dev/null +++ b/cpp/models/ode_seir_mobility/model.h @@ -0,0 +1,112 @@ + +#ifndef ODESEIRMOBILITY_MODEL_H +#define ODESEIRMOBILITY_MODEL_H + +#include "memilio/compartments/flow_model.h" +#include "memilio/epidemiology/populations.h" +#include "models/ode_seir_mobility/infection_state.h" +#include "models/ode_seir_mobility/parameters.h" +#include "models/ode_seir_mobility/regions.h" +#include "memilio/epidemiology/age_group.h" + +namespace mio +{ +namespace oseirmobility +{ + +/******************** + * define the model * + ********************/ + +using Flows = TypeList, + Flow, + Flow>; + +class Model : public FlowModel, Parameters, Flows> +{ + + using Base = FlowModel, Parameters, Flows>; + +public: + Model(int num_regions, int num_agegroups = 1) + : Base(Populations({Region(num_regions), AgeGroup(num_agegroups), InfectionState::Count}, 0.), + ParameterSet(num_regions, num_agegroups)) + { + } + // Einmal über den Vektor und später nochmal über die Regions + + void get_flows(Eigen::Ref pop, Eigen::Ref y, double t, + Eigen::Ref flows) const override + { + auto& params = this->parameters; + auto& population = this->populations; + + Region n_regions = params.get_num_regions(); + AgeGroup n_agegroups = params.get_num_agegroups(); + + for (auto age_i = AgeGroup(0); age_i < n_agegroups; age_i++) { + for (auto age_j = AgeGroup(0); age_j < n_agegroups; age_j++) { + double coeffStoI = + params.get().get_matrix_at(t)(static_cast((size_t)age_i), + static_cast((size_t)age_j)) * + params.get() / population.get_group_total(age_j); + for (auto edge : params.get()) { + auto start_region = get<0>(edge); + auto end_region = get<1>(edge); + auto strength = get(edge); + if (start_region == end_region) { + continue; + } + // s_n += h_mn/P_m * i_m + flows[get_flat_flow_index( + {start_region, age_i})] += + strength * pop[population.get_flat_index({end_region, age_j, InfectionState::Infected})]; + // s_m += h_mn/P_m * i_n + flows[get_flat_flow_index( + {end_region, age_i})] += + strength * pop[population.get_flat_index({start_region, age_j, InfectionState::Infected})]; + + // s_n += gamma * h_nm/P_n * sum(h_km/P_k * p_nm,k * i_k) + for (auto edge_commuter : params.get()) { + auto start_region_commuter = get<0>(edge_commuter); + auto end_region_commuter = get<1>(edge_commuter); + auto strength_commuter = get(edge_commuter); + if (end_region_commuter != end_region || start_region_commuter == start_region || + ((std::find(params.get()[{start_region, end_region}].begin(), + params.get()[{start_region, end_region}].end(), + start_region_commuter)) == + params.get()[{start_region, end_region}].end())) { + continue; + } + flows[get_flat_flow_index( + {start_region, age_i})] += + params.get() * strength * strength_commuter * + pop[population.get_flat_index({start_region_commuter, age_j, InfectionState::Infected})]; + } + } + for (auto region = Region(0); region < n_regions; region++) { + flows[get_flat_flow_index({region, age_i})] += + pop[population.get_flat_index({region, age_j, InfectionState::Infected})]; + flows[get_flat_flow_index({region, age_i})] *= + coeffStoI * y[population.get_flat_index({region, age_j, InfectionState::Susceptible})]; + } + } + + for (auto region = Region(0); region < n_regions; region++) { + flows[get_flat_flow_index({region, age_i})] = + (1.0 / params.get()) * + y[population.get_flat_index({region, age_i, InfectionState::Exposed})]; + flows[get_flat_flow_index({region, age_i})] = + (1.0 / params.get()) * + y[population.get_flat_index({region, age_i, InfectionState::Infected})]; + // flows[get_flat_flow_index({region, age_i})] = 0.; + // flows[get_flat_flow_index({region, age_i})] = 0.; + } + } + } +}; + +} // namespace oseirmobility +} // namespace mio + +#endif // ODESEIRMOBILITY_MODEL_H diff --git a/cpp/models/ode_seir_mobility/parameters.h b/cpp/models/ode_seir_mobility/parameters.h new file mode 100644 index 0000000000..fa02511316 --- /dev/null +++ b/cpp/models/ode_seir_mobility/parameters.h @@ -0,0 +1,297 @@ + +#ifndef SEIRMOBILITY_PARAMETERS_H +#define SEIRMOBILITY_PARAMETERS_H + +#include "memilio/utils/uncertain_value.h" +#include "memilio/epidemiology/contact_matrix.h" +#include "memilio/epidemiology/age_group.h" +#include "memilio/utils/parameter_set.h" +#include "memilio/utils/custom_index_array.h" +#include "models/ode_seir_mobility/regions.h" + +#include + +namespace mio +{ +namespace oseirmobility +{ + +/**************************************************** + * Define Parameters of the SEIR model with mobility * + ****************************************************/ + +/** + * @brief Probability of getting infected from a contact. + */ +struct TransmissionProbabilityOnContact { + using Type = UncertainValue; + static Type get_default(Region) + { + return Type(1.0); + } + static std::string name() + { + return "TransmissionProbabilityOnContact"; + } +}; + +/** + * @brief the latent time in day unit + */ +struct TimeExposed { + using Type = UncertainValue; + static Type get_default() + { + return Type(5.2); + } + static std::string name() + { + return "TimeExposed"; + } +}; + +/** + * @brief The infectious time in day unit. + */ +struct TimeInfected { + using Type = UncertainValue; + static Type get_default(Region) + { + return Type(6.0); + } + static std::string name() + { + return "TimeInfected"; + } +}; + +/** + * @brief The contact patterns within the society are modelled using a ContactMatrix. + */ +struct ContactPatterns { + using Type = ContactMatrix; + static Type get_default(Region) + { + return Type{1}; + } + static std::string name() + { + return "ContactPatterns"; + } +}; + +/** + * @brief The mean number of people migrating from one Region to another during a TimeStep. + */ +struct CommutingRatio { + using Type = std::vector>; + static Type get_default(Region) + { + return Type({{Region(0), Region(0), 0.}}); + } + static std::string name() + { + return "CommutingRatio"; + } +}; + +/** + * @brief The ratio that regulates the infections during commuting. +*/ +struct ImpactCommuters { + using Type = UncertainValue; + static Type get_default(Region) + { + return Type(0.); + } + static std::string name() + { + return "ImpactCommuters"; + } +}; + +/** + * @brief The Region%s that a person crosses when travelling from one Region to another. +*/ +struct PathIntersections { + using Type = CustomIndexArray, Region, Region>; + static Type get_default(Region size) + { + return Type({size, size}); + } + static std::string name() + { + return "PathIntersections"; + } +}; + +using ParametersBase = ParameterSet; + +/** + * @brief Parameters of SEIR model. + */ +class Parameters : public ParametersBase +{ +public: + Parameters(Region num_regions, AgeGroup num_agegroups) + : ParametersBase(num_regions) + , m_num_regions{num_regions} + , m_num_agegroups(num_agegroups) + { + } + + Region get_num_regions() const + { + return m_num_regions; + } + + AgeGroup get_num_agegroups() const + { + return m_num_agegroups; + } + + /** + * @brief Checks whether all Parameters satisfy their corresponding constraints and applies them, if they do not. + * Time spans cannot be negative and probabilities can only take values between [0,1]. + * + * Attention: This function should be used with care. It is necessary for some test problems to run through quickly, + * but in a manual execution of an example, check_constraints() may be preferred. Note that the apply_constraints() + * function can and will not set Parameters to meaningful values in an epidemiological or virological context, + * as all models are designed to be transferable to multiple diseases. Consequently, only acceptable + * (like 0 or 1 for probabilities or small positive values for time spans) values are set here and a manual adaptation + * may often be necessary to have set meaningful values. + * + * @return Returns true if one ore more constraint were corrected, false otherwise. + */ + bool apply_constraints() + { + double tol_times = 1e-1; + + int corrected = false; + if (this->get() < tol_times) { + log_warning("Constraint check: Parameter TimeExposed changed from {:.4f} to {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->get(), tol_times); + this->get() = tol_times; + corrected = true; + } + if (this->get() < tol_times) { + log_warning("Constraint check: Parameter TimeInfected changed from {:.4f} to {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->get(), tol_times); + this->get() = tol_times; + corrected = true; + } + if (this->get() < 0.0 || + this->get() > 1.0) { + log_warning("Constraint check: Parameter TransmissionProbabilityOnContact changed from {:0.4f} to {:d} ", + this->get(), 0.0); + this->get() = 0.0; + corrected = true; + } + if (this->get() < 0.0 || this->get() > 1.0) { + log_warning("Constraint check: Parameter ImpactCommuters changed from {:.4f} to {:.4f}.", + this->get(), 0.0); + this->get() = 0.0; + corrected = true; + } + for (auto& i : this->get()) { + if (std::get(i) < 0.0 || std::get(i) > 1.0) { + log_warning("Constraint check: Parameter CommutingRatio changed from {:.4f} to {:.4f}.", + std::get(i), 0.0); + std::get(i) = 0.0; + corrected = true; + } + if (std::get<0>(i) < Region(0) || std::get<1>(i) < Region(0) || std::get<0>(i) >= m_num_regions || + std::get<1>(i) >= m_num_regions) { + log_warning( + "Constraint check: Removed entry of Parameter CommutingRatio because of non-existing Regions."); + auto it = std::find(this->get().begin(), this->get().end(), i); + this->get().erase(it); + corrected = true; + } + } + return corrected; + } + + /** + * @brief Checks whether all Parameters satisfy their corresponding constraints and logs an error + * if constraints are not satisfied. + * @return Returns true if one constraint is not satisfied, otherwise false. + */ + bool check_constraints() const + { + double tol_times = 1e-1; + + if (this->get() < tol_times) { + log_error("Constraint check: Parameter TimeExposed {:.4f} smaller or equal {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->get(), 0.0); + return true; + } + if (this->get() < tol_times) { + log_error("Constraint check: Parameter TimeInfected {:.4f} smaller or equal {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->get(), 0.0); + return true; + } + if (this->get() < 0.0 || + this->get() > 1.0) { + log_error( + "Constraint check: Parameter TransmissionProbabilityOnContact {:.4f} smaller {:.4f} or greater {:.4f}", + this->get(), 0.0, 1.0); + return true; + } + if (this->get() < 0.0 || this->get() > 1.0) { + log_error("Constraint check: Parameter ImpactCommuters {:.4f} smaller {:.4f} or greater {:.4f}", + this->get(), 0.0, 1.0); + return true; + } + for (auto i : this->get()) { + if (std::get(i) < 0.0 || std::get(i) > 1.0) { + log_error("Constraint check: Parameter CommutingRatio entry {:.4f} smaller {:.4f} or greater {:.4f}", + std::get(i), 0.0, 1.0); + return true; + } + if (std::get<0>(i) < Region(0) || std::get<1>(i) < Region(0) || std::get<0>(i) > m_num_regions || + std::get<1>(i) > m_num_regions) { + log_error("Constraint check: Parameter CommutingRatio has an entry with start or end Region that does " + "not appear in the model."); + return true; + } + } + return false; + } + +private: + // Parameters(ParametersBase&& base) + // : ParametersBase(std::move(base)) //TODO: Adjust + // { + // } + +public: + /** + * deserialize an object of this class. + * @see mio::deserialize + */ + template + static IOResult deserialize(IOContext& io) + { + BOOST_OUTCOME_TRY(base, ParametersBase::deserialize(io)); + return success(Parameters(std::move(base))); + } + +private: + Region m_num_regions; + AgeGroup m_num_agegroups; +}; + +} // namespace oseirmobility +} // namespace mio + +#endif // SEIR_PARAMETERS_H diff --git a/cpp/models/ode_seir_mobility/regions.h b/cpp/models/ode_seir_mobility/regions.h new file mode 100644 index 0000000000..4a8352b11b --- /dev/null +++ b/cpp/models/ode_seir_mobility/regions.h @@ -0,0 +1,26 @@ + +#ifndef ODESEIRMOBILITY_REGIONS_H +#define ODESEIRMOBILITY_REGIONS_H + +#include "memilio/utils/index.h" + +namespace mio +{ +namespace oseirmobility +{ + +/** + * @brief The AgeGroup struct is used as a dynamically + * sized tag for all age dependent categories + */ +struct Region : public Index { + Region(size_t val) + : Index(val) + { + } +}; + +} // namespace oseirmobility +} // namespace mio + +#endif From f475e3ca52a3ed3f74f6bdce9301138c253e06b4 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 17 Jun 2024 14:43:15 +0200 Subject: [PATCH 09/87] small adjustments sir version --- cpp/examples/ode_sir_mobility.cpp | 8 ++++---- cpp/models/ode_sir_mobility/CMakeLists.txt | 1 + cpp/models/ode_sir_mobility/model.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cpp/examples/ode_sir_mobility.cpp b/cpp/examples/ode_sir_mobility.cpp index afaea9860e..e8e986de7e 100644 --- a/cpp/examples/ode_sir_mobility.cpp +++ b/cpp/examples/ode_sir_mobility.cpp @@ -141,9 +141,9 @@ int main() double tmax = 50.; double dt = 1; - size_t number_regions = 4; + size_t number_regions = 1; size_t number_age_groups = 1; - size_t total_population_per_region = 5000; + size_t total_population_per_region = 10; mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); @@ -154,7 +154,7 @@ int main() for (size_t i = 0; i < number_regions; i++) { model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] = 50; + mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] = 1; model.populations[{mio::Index( mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered)}] = 0; model.populations[{mio::Index( @@ -200,7 +200,7 @@ int main() model.parameters.get()[{mio::osirmobility::Region(3), mio::osirmobility::Region(1)}] = {2}; - auto result_preprocess = set_mobility_weights(mobility_data, trip_chain_data, model, number_regions); + // auto result_preprocess = set_mobility_weights(mobility_data, trip_chain_data, model, number_regions); auto integrator = std::make_shared(); diff --git a/cpp/models/ode_sir_mobility/CMakeLists.txt b/cpp/models/ode_sir_mobility/CMakeLists.txt index 55605f5c94..3a2f54adeb 100644 --- a/cpp/models/ode_sir_mobility/CMakeLists.txt +++ b/cpp/models/ode_sir_mobility/CMakeLists.txt @@ -3,6 +3,7 @@ add_library(ode_sir_mobility model.h model.cpp parameters.h + regions.h ) target_link_libraries(ode_sir_mobility PUBLIC memilio) target_include_directories(ode_sir_mobility PUBLIC diff --git a/cpp/models/ode_sir_mobility/model.h b/cpp/models/ode_sir_mobility/model.h index dc1b019a79..3936b6180d 100644 --- a/cpp/models/ode_sir_mobility/model.h +++ b/cpp/models/ode_sir_mobility/model.h @@ -27,7 +27,7 @@ class Model : public FlowModel, Parameters, Flows>; public: - Model(int num_regions, int num_agegroups = 1) + Model(int num_regions, int num_agegroups) : Base(Populations({Region(num_regions), AgeGroup(num_agegroups), InfectionState::Count}, 0.), ParameterSet(num_regions, num_agegroups)) { From f19bcf625e39569aec9ae6cb8f43b7942b688315 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Tue, 18 Jun 2024 12:57:51 +0200 Subject: [PATCH 10/87] fixes after merge --- cpp/examples/ode_seir_mobility.cpp | 72 ++++----- cpp/examples/ode_sir_mobility.cpp | 66 ++++---- cpp/models/ode_seir_mobility/model.h | 87 ++++++----- cpp/models/ode_seir_mobility/parameters.h | 178 ++++++++++++---------- cpp/models/ode_sir_mobility/model.h | 74 ++++----- cpp/models/ode_sir_mobility/parameters.h | 136 +++++++++-------- 6 files changed, 334 insertions(+), 279 deletions(-) diff --git a/cpp/examples/ode_seir_mobility.cpp b/cpp/examples/ode_seir_mobility.cpp index 75e5ce1141..c6b9785639 100644 --- a/cpp/examples/ode_seir_mobility.cpp +++ b/cpp/examples/ode_seir_mobility.cpp @@ -12,7 +12,7 @@ mio::IOResult>>> read_path_mobility(const std::string& filename) { - BOOST_OUTCOME_TRY(num_lines, mio::count_lines(filename)); + BOOST_OUTCOME_TRY(auto&& num_lines, mio::count_lines(filename)); if (num_lines == 0) { std::vector>> arr(0, std::vector>(0)); @@ -66,9 +66,10 @@ mio::IOResult>>> read_path_mobility(con return mio::success(arr); } -mio::IOResult preprocess(const std::string& filename, mio::oseirmobility::Model& model) +template +mio::IOResult preprocess(const std::string& filename, mio::oseirmobility::Model& model) { - BOOST_OUTCOME_TRY(mobility_paths, read_path_mobility(filename)); + BOOST_OUTCOME_TRY(auto&& mobility_paths, read_path_mobility(filename)); size_t n_regions = (size_t)model.parameters.get_num_regions(); for (size_t i = 0; i < n_regions; i++) { for (size_t j = 0; j < n_regions; j++) { @@ -94,20 +95,21 @@ mio::IOResult preprocess(const std::string& filename, mio::oseirmobility:: } } if (intersection_region.begin() != intersection_region.end()) { - model.parameters.get()[mio::Index( - mio::oseirmobility::Region(i), mio::oseirmobility::Region(j))] = intersection_region; + model.parameters.template get()[{ + mio::oseirmobility::Region(i), mio::oseirmobility::Region(j)}] = intersection_region; } } } return mio::success(); } +template mio::IOResult set_mobility_weights(const std::string& mobility_data, const std::string& trip_chains, - mio::oseirmobility::Model& model, size_t number_regions) + mio::oseirmobility::Model& model, size_t number_regions) { BOOST_OUTCOME_TRY(preprocess(trip_chains, model)); // mobility between nodes - BOOST_OUTCOME_TRY(mobility_data_commuter, + BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, mio::read_mobility_plain(mobility_data + "mobility" + "commuter_migration_scaled.txt")); if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || mobility_data_commuter.cols() != Eigen::Index(number_regions)) { @@ -123,7 +125,7 @@ mio::IOResult set_mobility_weights(const std::string& mobility_data, const auto population_i = model.populations.get_group_total(mio::oseirmobility::Region(county_idx_i)); auto commuter_coeff_ij = mobility_data_commuter(county_idx_i, county_idx_j) / population_i; if (commuter_coeff_ij > 4e-5) { - model.parameters.get().push_back( + model.parameters.template get().push_back( {mio::oseirmobility::Region(county_idx_i), mio::oseirmobility::Region(county_idx_j), commuter_coeff_ij}); } @@ -137,43 +139,43 @@ int main() { mio::set_log_level(mio::LogLevel::debug); - double t0 = 0.; - double tmax = 50.; - double dt = 1; + ScalarType t0 = 0.; + ScalarType tmax = 50.; + ScalarType dt = 1; - size_t number_regions = 4; - size_t number_age_groups = 1; - size_t total_population_per_region = 10; + ScalarType number_regions = 4; + ScalarType number_age_groups = 1; + ScalarType total_population_per_region = 10; mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); const std::string& mobility_data = ""; const std::string& trip_chain_data = ""; - mio::oseirmobility::Model model(number_regions, number_age_groups); + mio::oseirmobility::Model model(number_regions, number_age_groups); for (size_t i = 0; i < number_regions; i++) { - model.populations[{mio::Index( - mio::oseirmobility::Region(i), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Infected)}] = 1; - model.populations[{mio::Index( - mio::oseirmobility::Region(i), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Recovered)}] = 0; - model.populations[{mio::Index( - mio::oseirmobility::Region(i), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Susceptible)}] = + model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), + mio::oseirmobility::InfectionState::Infected}] = 1; + model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), + mio::oseirmobility::InfectionState::Recovered}] = 0; + model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), + mio::oseirmobility::InfectionState::Susceptible}] = total_population_per_region - - model - .populations[{mio::Index( - mio::oseirmobility::Region(i), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Infected)}] - - model - .populations[{mio::Index( - mio::oseirmobility::Region(i), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Recovered)}]; + model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), + mio::oseirmobility::InfectionState::Infected}] - + model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), + mio::oseirmobility::InfectionState::Recovered}]; } - model.parameters.set(1); - model.parameters.set(2); - model.parameters.set(0.04); - model.parameters.set(1.); - model.parameters.get().get_baseline()(0, 0) = 1.; - model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); + model.parameters.set>(1); + model.parameters.set>(2); + model.parameters.set>(0.04); + model.parameters.set>(1.); + mio::ContactMatrixGroup& contact_matrix = + model.parameters.get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(1.0); + contact_matrix[0].add_damping(0.6, mio::SimulationTime(12.5)); model.parameters.get().push_back( {mio::oseirmobility::Region(1), mio::oseirmobility::Region(0), 0.2}); @@ -205,7 +207,8 @@ int main() // auto result_preprocess = set_mobility_weights(mobility_data, trip_chain_data, model, number_regions); - auto integrator = std::make_shared(); + std::shared_ptr> integrator = + std::make_shared>(); model.check_constraints(); @@ -234,5 +237,6 @@ int main() } } } + printf("\n"); } } diff --git a/cpp/examples/ode_sir_mobility.cpp b/cpp/examples/ode_sir_mobility.cpp index e8e986de7e..46dca6739e 100644 --- a/cpp/examples/ode_sir_mobility.cpp +++ b/cpp/examples/ode_sir_mobility.cpp @@ -12,7 +12,7 @@ mio::IOResult>>> read_path_mobility(const std::string& filename) { - BOOST_OUTCOME_TRY(num_lines, mio::count_lines(filename)); + BOOST_OUTCOME_TRY(auto&& num_lines, mio::count_lines(filename)); if (num_lines == 0) { std::vector>> arr(0, std::vector>(0)); @@ -66,9 +66,10 @@ mio::IOResult>>> read_path_mobility(con return mio::success(arr); } -mio::IOResult preprocess(const std::string& filename, mio::osirmobility::Model& model) +template +mio::IOResult preprocess(const std::string& filename, mio::osirmobility::Model& model) { - BOOST_OUTCOME_TRY(mobility_paths, read_path_mobility(filename)); + BOOST_OUTCOME_TRY(auto&& mobility_paths, read_path_mobility(filename)); size_t n_regions = (size_t)model.parameters.get_num_regions(); for (size_t i = 0; i < n_regions; i++) { for (size_t j = 0; j < n_regions; j++) { @@ -94,7 +95,7 @@ mio::IOResult preprocess(const std::string& filename, mio::osirmobility::M } } if (intersection_region.begin() != intersection_region.end()) { - model.parameters.get()[{ + model.parameters.template get()[{ mio::osirmobility::Region(i), mio::osirmobility::Region(j)}] = intersection_region; } } @@ -102,12 +103,13 @@ mio::IOResult preprocess(const std::string& filename, mio::osirmobility::M return mio::success(); } +template mio::IOResult set_mobility_weights(const std::string& mobility_data, const std::string& trip_chains, - mio::osirmobility::Model& model, size_t number_regions) + mio::osirmobility::Model& model, size_t number_regions) { BOOST_OUTCOME_TRY(preprocess(trip_chains, model)); // mobility between nodes - BOOST_OUTCOME_TRY(mobility_data_commuter, + BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, mio::read_mobility_plain(mobility_data + "mobility" + "commuter_migration_scaled.txt")); if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || mobility_data_commuter.cols() != Eigen::Index(number_regions)) { @@ -123,7 +125,7 @@ mio::IOResult set_mobility_weights(const std::string& mobility_data, const auto population_i = model.populations.get_group_total(mio::osirmobility::Region(county_idx_i)); auto commuter_coeff_ij = mobility_data_commuter(county_idx_i, county_idx_j) / population_i; if (commuter_coeff_ij > 4e-5) { - model.parameters.get().push_back( + model.parameters.template get().push_back( {mio::osirmobility::Region(county_idx_i), mio::osirmobility::Region(county_idx_j), commuter_coeff_ij}); } @@ -137,40 +139,42 @@ int main() { mio::set_log_level(mio::LogLevel::debug); - double t0 = 0.; - double tmax = 50.; - double dt = 1; + ScalarType t0 = 0.; + ScalarType tmax = 50.; + ScalarType dt = 1; - size_t number_regions = 1; - size_t number_age_groups = 1; - size_t total_population_per_region = 10; + ScalarType number_regions = 4; + ScalarType number_age_groups = 1; + ScalarType total_population_per_region = 10; mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); const std::string& mobility_data = ""; const std::string& trip_chain_data = ""; - mio::osirmobility::Model model(number_regions, number_age_groups); + mio::osirmobility::Model model(number_regions, number_age_groups); for (size_t i = 0; i < number_regions; i++) { - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] = 1; - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered)}] = 0; - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Susceptible)}] = + model.populations[{mio::osirmobility::Region(i), mio::AgeGroup(0), + mio::osirmobility::InfectionState::Infected}] = 1; + model.populations[{mio::osirmobility::Region(i), mio::AgeGroup(0), + mio::osirmobility::InfectionState::Recovered}] = 0; + model.populations[{mio::osirmobility::Region(i), mio::AgeGroup(0), + mio::osirmobility::InfectionState::Susceptible}] = total_population_per_region - - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] - - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered)}]; + model.populations[{mio::osirmobility::Region(i), mio::AgeGroup(0), + mio::osirmobility::InfectionState::Infected}] - + model.populations[{mio::osirmobility::Region(i), mio::AgeGroup(0), + mio::osirmobility::InfectionState::Recovered}]; } - model.parameters.set(2); - model.parameters.set(0.04); - model.parameters.set(1.); - model.parameters.get().get_baseline()(0, 0) = 1.; - model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); + model.parameters.set>(2); + model.parameters.set>(0.04); + model.parameters.set>(1.); + mio::ContactMatrixGroup& contact_matrix = + model.parameters.get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(1.0); + contact_matrix[0].add_damping(0.6, mio::SimulationTime(12.5)); model.parameters.get().push_back( {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.2}); @@ -202,7 +206,8 @@ int main() // auto result_preprocess = set_mobility_weights(mobility_data, trip_chain_data, model, number_regions); - auto integrator = std::make_shared(); + std::shared_ptr> integrator = + std::make_shared>(); model.check_constraints(); @@ -231,5 +236,6 @@ int main() } } } + printf("\n"); } } diff --git a/cpp/models/ode_seir_mobility/model.h b/cpp/models/ode_seir_mobility/model.h index 647a01dac1..7308b874a2 100644 --- a/cpp/models/ode_seir_mobility/model.h +++ b/cpp/models/ode_seir_mobility/model.h @@ -22,35 +22,41 @@ using Flows = TypeList, Flow>; -class Model : public FlowModel, Parameters, Flows> +template +class Model : public FlowModel, + Parameters, Flows> { - using Base = FlowModel, Parameters, Flows>; + using Base = + FlowModel, Parameters, Flows>; public: - Model(int num_regions, int num_agegroups = 1) - : Base(Populations({Region(num_regions), AgeGroup(num_agegroups), InfectionState::Count}, 0.), - ParameterSet(num_regions, num_agegroups)) + using typename Base::ParameterSet; + using typename Base::Populations; + + Model(int num_regions, int num_agegroups) + : Base(Populations({Region(num_regions), AgeGroup(num_agegroups), InfectionState::Count}), + ParameterSet(Region(num_regions), AgeGroup(num_agegroups))) { } // Einmal über den Vektor und später nochmal über die Regions - void get_flows(Eigen::Ref pop, Eigen::Ref y, double t, - Eigen::Ref flows) const override + void get_flows(Eigen::Ref> pop, Eigen::Ref> y, FP t, + Eigen::Ref> flows) const override { - auto& params = this->parameters; - auto& population = this->populations; - - Region n_regions = params.get_num_regions(); - AgeGroup n_agegroups = params.get_num_agegroups(); - - for (auto age_i = AgeGroup(0); age_i < n_agegroups; age_i++) { - for (auto age_j = AgeGroup(0); age_j < n_agegroups; age_j++) { - double coeffStoI = - params.get().get_matrix_at(t)(static_cast((size_t)age_i), - static_cast((size_t)age_j)) * - params.get() / population.get_group_total(age_j); - for (auto edge : params.get()) { + const auto& params = this->parameters; + const auto& population = this->populations; + + const Index n_age_groups = reduce_index>(params.get_num_agegroups()); + const Index n_regions = reduce_index>(params.get_num_regions()); + + for (auto age_i : make_index_range(n_age_groups)) { + for (auto age_j : make_index_range(n_age_groups)) { + double coeffStoI = params.template get>().get_cont_freq_mat().get_matrix_at(t)( + age_i.get(), age_j.get()) * + params.template get>()[age_i] / + population.get_group_total(age_j); + for (auto edge : params.template get()) { auto start_region = get<0>(edge); auto end_region = get<1>(edge); auto strength = get(edge); @@ -58,49 +64,48 @@ class Model : public FlowModel( + flows[Base::template get_flat_flow_index( {start_region, age_i})] += strength * pop[population.get_flat_index({end_region, age_j, InfectionState::Infected})]; // s_m += h_mn/P_m * i_n - flows[get_flat_flow_index( + flows[Base::template get_flat_flow_index( {end_region, age_i})] += strength * pop[population.get_flat_index({start_region, age_j, InfectionState::Infected})]; // s_n += gamma * h_nm/P_n * sum(h_km/P_k * p_nm,k * i_k) - for (auto edge_commuter : params.get()) { + for (auto edge_commuter : params.template get()) { auto start_region_commuter = get<0>(edge_commuter); auto end_region_commuter = get<1>(edge_commuter); auto strength_commuter = get(edge_commuter); if (end_region_commuter != end_region || start_region_commuter == start_region || - ((std::find(params.get()[{start_region, end_region}].begin(), - params.get()[{start_region, end_region}].end(), + ((std::find(params.template get()[{start_region, end_region}].begin(), + params.template get()[{start_region, end_region}].end(), start_region_commuter)) == - params.get()[{start_region, end_region}].end())) { + params.template get()[{start_region, end_region}].end())) { continue; } - flows[get_flat_flow_index( + flows[Base::template get_flat_flow_index( {start_region, age_i})] += - params.get() * strength * strength_commuter * + params.template get>() * strength * strength_commuter * pop[population.get_flat_index({start_region_commuter, age_j, InfectionState::Infected})]; } } - for (auto region = Region(0); region < n_regions; region++) { - flows[get_flat_flow_index({region, age_i})] += - pop[population.get_flat_index({region, age_j, InfectionState::Infected})]; - flows[get_flat_flow_index({region, age_i})] *= + for (auto region : make_index_range(n_regions)) { + flows[Base::template get_flat_flow_index( + {region, age_i})] += pop[population.get_flat_index({region, age_j, InfectionState::Infected})]; + flows[Base::template get_flat_flow_index( + {region, age_i})] *= coeffStoI * y[population.get_flat_index({region, age_j, InfectionState::Susceptible})]; } } - for (auto region = Region(0); region < n_regions; region++) { - flows[get_flat_flow_index({region, age_i})] = - (1.0 / params.get()) * - y[population.get_flat_index({region, age_i, InfectionState::Exposed})]; - flows[get_flat_flow_index({region, age_i})] = - (1.0 / params.get()) * - y[population.get_flat_index({region, age_i, InfectionState::Infected})]; - // flows[get_flat_flow_index({region, age_i})] = 0.; - // flows[get_flat_flow_index({region, age_i})] = 0.; + for (auto region : make_index_range(n_regions)) { + flows[Base::template get_flat_flow_index( + {region, age_i})] = (1.0 / params.template get>()[age_i]) * + y[population.get_flat_index({region, age_i, InfectionState::Exposed})]; + flows[Base::template get_flat_flow_index( + {region, age_i})] = (1.0 / params.template get>()[age_i]) * + y[population.get_flat_index({region, age_i, InfectionState::Infected})]; } } } diff --git a/cpp/models/ode_seir_mobility/parameters.h b/cpp/models/ode_seir_mobility/parameters.h index fa02511316..c2a02f83e4 100644 --- a/cpp/models/ode_seir_mobility/parameters.h +++ b/cpp/models/ode_seir_mobility/parameters.h @@ -2,8 +2,8 @@ #ifndef SEIRMOBILITY_PARAMETERS_H #define SEIRMOBILITY_PARAMETERS_H +#include "memilio/epidemiology/uncertain_matrix.h" #include "memilio/utils/uncertain_value.h" -#include "memilio/epidemiology/contact_matrix.h" #include "memilio/epidemiology/age_group.h" #include "memilio/utils/parameter_set.h" #include "memilio/utils/custom_index_array.h" @@ -23,11 +23,12 @@ namespace oseirmobility /** * @brief Probability of getting infected from a contact. */ +template struct TransmissionProbabilityOnContact { - using Type = UncertainValue; - static Type get_default(Region) + using Type = CustomIndexArray, AgeGroup>; + static Type get_default(Region, AgeGroup size) { - return Type(1.0); + return Type(size, 1.0); } static std::string name() { @@ -36,13 +37,14 @@ struct TransmissionProbabilityOnContact { }; /** - * @brief the latent time in day unit - */ + * @brief the latent time in day unit + */ +template struct TimeExposed { - using Type = UncertainValue; - static Type get_default() + using Type = CustomIndexArray, AgeGroup>; + static Type get_default(Region, AgeGroup size) { - return Type(5.2); + return Type(size, 5.2); } static std::string name() { @@ -51,13 +53,14 @@ struct TimeExposed { }; /** - * @brief The infectious time in day unit. - */ + * @brief The infectious time in day unit. + */ +template struct TimeInfected { - using Type = UncertainValue; - static Type get_default(Region) + using Type = CustomIndexArray, AgeGroup>; + static Type get_default(Region, AgeGroup size) { - return Type(6.0); + return Type(size, 6.0); } static std::string name() { @@ -68,11 +71,12 @@ struct TimeInfected { /** * @brief The contact patterns within the society are modelled using a ContactMatrix. */ +template struct ContactPatterns { - using Type = ContactMatrix; - static Type get_default(Region) + using Type = UncertainContactMatrix; + static Type get_default(Region, AgeGroup size) { - return Type{1}; + return Type(1, static_cast((size_t)size)); } static std::string name() { @@ -85,7 +89,7 @@ struct ContactPatterns { */ struct CommutingRatio { using Type = std::vector>; - static Type get_default(Region) + static Type get_default(Region, AgeGroup) { return Type({{Region(0), Region(0), 0.}}); } @@ -98,9 +102,10 @@ struct CommutingRatio { /** * @brief The ratio that regulates the infections during commuting. */ +template struct ImpactCommuters { - using Type = UncertainValue; - static Type get_default(Region) + using Type = UncertainValue; + static Type get_default(Region, AgeGroup) { return Type(0.); } @@ -115,7 +120,7 @@ struct ImpactCommuters { */ struct PathIntersections { using Type = CustomIndexArray, Region, Region>; - static Type get_default(Region size) + static Type get_default(Region size, AgeGroup) { return Type({size, size}); } @@ -125,17 +130,19 @@ struct PathIntersections { } }; -using ParametersBase = ParameterSet; +template +using ParametersBase = ParameterSet, TimeExposed, TimeInfected, + ContactPatterns, CommutingRatio, ImpactCommuters, PathIntersections>; /** * @brief Parameters of SEIR model. */ -class Parameters : public ParametersBase +template +class Parameters : public ParametersBase { public: Parameters(Region num_regions, AgeGroup num_agegroups) - : ParametersBase(num_regions) + : ParametersBase(num_regions, num_agegroups) , m_num_regions{num_regions} , m_num_agegroups(num_agegroups) { @@ -169,36 +176,42 @@ class Parameters : public ParametersBase double tol_times = 1e-1; int corrected = false; - if (this->get() < tol_times) { - log_warning("Constraint check: Parameter TimeExposed changed from {:.4f} to {:.4f}. Please note that " - "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " - "and reset parameters.", - this->get(), tol_times); - this->get() = tol_times; - corrected = true; - } - if (this->get() < tol_times) { - log_warning("Constraint check: Parameter TimeInfected changed from {:.4f} to {:.4f}. Please note that " - "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " - "and reset parameters.", - this->get(), tol_times); - this->get() = tol_times; - corrected = true; - } - if (this->get() < 0.0 || - this->get() > 1.0) { - log_warning("Constraint check: Parameter TransmissionProbabilityOnContact changed from {:0.4f} to {:d} ", - this->get(), 0.0); - this->get() = 0.0; - corrected = true; + + for (auto i = AgeGroup(0); i < AgeGroup(m_num_agegroups); i++) { + if (this->template get>()[i] < tol_times) { + log_warning( + "Constraint check: Parameter TimeInfected changed from {:.4f} to {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->template get>()[i], tol_times); + this->template get>()[i] = tol_times; + corrected = true; + } + if (this->template get() < tol_times) { + log_warning( + "Constraint check: Parameter TimeInfected changed from {:.4f} to {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->template get>()[i], tol_times); + this->template get>()[i] = tol_times; + corrected = true; + } + if (this->template get>()[i] < 0.0 || + this->template get>()[i] > 1.0) { + log_warning( + "Constraint check: Parameter TransmissionProbabilityOnContact changed from {:0.4f} to {:d} ", + this->template get>()[i], 0.0); + this->template get>() = 0.0; + corrected = true; + } } - if (this->get() < 0.0 || this->get() > 1.0) { + if (this->template get>() < 0.0 || this->template get>() > 1.0) { log_warning("Constraint check: Parameter ImpactCommuters changed from {:.4f} to {:.4f}.", - this->get(), 0.0); - this->get() = 0.0; - corrected = true; + this->template get>(), 0.0); + this->template get>() = 0.0; + corrected = true; } - for (auto& i : this->get()) { + for (auto& i : this->template get()) { if (std::get(i) < 0.0 || std::get(i) > 1.0) { log_warning("Constraint check: Parameter CommutingRatio changed from {:.4f} to {:.4f}.", std::get(i), 0.0); @@ -209,8 +222,9 @@ class Parameters : public ParametersBase std::get<1>(i) >= m_num_regions) { log_warning( "Constraint check: Removed entry of Parameter CommutingRatio because of non-existing Regions."); - auto it = std::find(this->get().begin(), this->get().end(), i); - this->get().erase(it); + auto it = std::find(this->template get().begin(), + this->template get().end(), i); + this->template get().erase(it); corrected = true; } } @@ -226,33 +240,37 @@ class Parameters : public ParametersBase { double tol_times = 1e-1; - if (this->get() < tol_times) { - log_error("Constraint check: Parameter TimeExposed {:.4f} smaller or equal {:.4f}. Please note that " - "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " - "and reset parameters.", - this->get(), 0.0); - return true; - } - if (this->get() < tol_times) { - log_error("Constraint check: Parameter TimeInfected {:.4f} smaller or equal {:.4f}. Please note that " - "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " - "and reset parameters.", - this->get(), 0.0); - return true; - } - if (this->get() < 0.0 || - this->get() > 1.0) { - log_error( - "Constraint check: Parameter TransmissionProbabilityOnContact {:.4f} smaller {:.4f} or greater {:.4f}", - this->get(), 0.0, 1.0); - return true; + for (auto i = AgeGroup(0); i < AgeGroup(m_num_agegroups); i++) { + if (this->template get>()[i] < tol_times) { + log_error( + "Constraint check: Parameter TimeExposed {:.4f} smaller or equal {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->template get>()[i], 0.0); + return true; + } + if (this->template get>()[i] < tol_times) { + log_error( + "Constraint check: Parameter TimeInfected {:.4f} smaller or equal {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->template get>()[i], 0.0); + return true; + } + if (this->template get>()[i] < 0.0 || + this->template get>()[i] > 1.0) { + log_error("Constraint check: Parameter TransmissionProbabilityOnContact {:.4f} smaller {:.4f} or " + "greater {:.4f}", + this->template get>()[i], 0.0, 1.0); + return true; + } } - if (this->get() < 0.0 || this->get() > 1.0) { + if (this->template get>() < 0.0 || this->template get>() > 1.0) { log_error("Constraint check: Parameter ImpactCommuters {:.4f} smaller {:.4f} or greater {:.4f}", - this->get(), 0.0, 1.0); + this->template get>(), 0.0, 1.0); return true; } - for (auto i : this->get()) { + for (auto i : this->template get()) { if (std::get(i) < 0.0 || std::get(i) > 1.0) { log_error("Constraint check: Parameter CommutingRatio entry {:.4f} smaller {:.4f} or greater {:.4f}", std::get(i), 0.0, 1.0); @@ -260,8 +278,8 @@ class Parameters : public ParametersBase } if (std::get<0>(i) < Region(0) || std::get<1>(i) < Region(0) || std::get<0>(i) > m_num_regions || std::get<1>(i) > m_num_regions) { - log_error("Constraint check: Parameter CommutingRatio has an entry with start or end Region that does " - "not appear in the model."); + log_error("Constraint check: Parameter CommutingRatio has an entry with start or end Region " + "that does not appear in the model."); return true; } } @@ -282,7 +300,7 @@ class Parameters : public ParametersBase template static IOResult deserialize(IOContext& io) { - BOOST_OUTCOME_TRY(base, ParametersBase::deserialize(io)); + BOOST_OUTCOME_TRY(auto&& base, ParametersBase::deserialize(io)); return success(Parameters(std::move(base))); } diff --git a/cpp/models/ode_sir_mobility/model.h b/cpp/models/ode_sir_mobility/model.h index 3936b6180d..82cebe7b76 100644 --- a/cpp/models/ode_sir_mobility/model.h +++ b/cpp/models/ode_sir_mobility/model.h @@ -21,35 +21,41 @@ namespace osirmobility using Flows = TypeList, Flow>; -class Model : public FlowModel, Parameters, Flows> +template +class Model : public FlowModel, + Parameters, Flows> { - using Base = FlowModel, Parameters, Flows>; + using Base = + FlowModel, Parameters, Flows>; public: + using typename Base::ParameterSet; + using typename Base::Populations; + Model(int num_regions, int num_agegroups) - : Base(Populations({Region(num_regions), AgeGroup(num_agegroups), InfectionState::Count}, 0.), - ParameterSet(num_regions, num_agegroups)) + : Base(Populations({Region(num_regions), AgeGroup(num_agegroups), InfectionState::Count}), + ParameterSet(Region(num_regions), AgeGroup(num_agegroups))) { } // Einmal über den Vektor und später nochmal über die Regions - void get_flows(Eigen::Ref pop, Eigen::Ref y, double t, - Eigen::Ref flows) const override + void get_flows(Eigen::Ref> pop, Eigen::Ref> y, FP t, + Eigen::Ref> flows) const override { - auto& params = this->parameters; - auto& population = this->populations; - - Region n_regions = params.get_num_regions(); - AgeGroup n_agegroups = params.get_num_agegroups(); - - for (auto age_i = AgeGroup(0); age_i < n_agegroups; age_i++) { - for (auto age_j = AgeGroup(0); age_j < n_agegroups; age_j++) { - double coeffStoI = - params.get().get_matrix_at(t)(static_cast((size_t)age_i), - static_cast((size_t)age_j)) * - params.get() / population.get_group_total(age_j); - for (auto edge : params.get()) { + const auto& params = this->parameters; + const auto& population = this->populations; + + const Index n_age_groups = reduce_index>(params.get_num_agegroups()); + const Index n_regions = reduce_index>(params.get_num_regions()); + + for (auto age_i : make_index_range(n_age_groups)) { + for (auto age_j : make_index_range(n_age_groups)) { + double coeffStoI = params.template get>().get_cont_freq_mat().get_matrix_at(t)( + age_i.get(), age_j.get()) * + params.template get>()[age_i] / + population.get_group_total(age_j); + for (auto edge : params.template get()) { auto start_region = get<0>(edge); auto end_region = get<1>(edge); auto strength = get(edge); @@ -57,45 +63,45 @@ class Model : public FlowModel( + flows[Base::template get_flat_flow_index( {start_region, age_i})] += strength * pop[population.get_flat_index({end_region, age_j, InfectionState::Infected})]; // s_m += h_mn/P_m * i_n - flows[get_flat_flow_index( + flows[Base::template get_flat_flow_index( {end_region, age_i})] += strength * pop[population.get_flat_index({start_region, age_j, InfectionState::Infected})]; // s_n += gamma * h_nm/P_n * sum(h_km/P_k * p_nm,k * i_k) - for (auto edge_commuter : params.get()) { + for (auto edge_commuter : params.template get()) { auto start_region_commuter = get<0>(edge_commuter); auto end_region_commuter = get<1>(edge_commuter); auto strength_commuter = get(edge_commuter); if (end_region_commuter != end_region || start_region_commuter == start_region || - ((std::find(params.get()[{start_region, end_region}].begin(), - params.get()[{start_region, end_region}].end(), + ((std::find(params.template get()[{start_region, end_region}].begin(), + params.template get()[{start_region, end_region}].end(), start_region_commuter)) == - params.get()[{start_region, end_region}].end())) { + params.template get()[{start_region, end_region}].end())) { continue; } - flows[get_flat_flow_index( + flows[Base::template get_flat_flow_index( {start_region, age_i})] += - params.get() * strength * strength_commuter * + params.template get>() * strength * strength_commuter * pop[population.get_flat_index({start_region_commuter, age_j, InfectionState::Infected})]; } } - for (auto region = Region(0); region < n_regions; region++) { - flows[get_flat_flow_index( + for (auto region : make_index_range(n_regions)) { + flows[Base::template get_flat_flow_index( {region, age_i})] += pop[population.get_flat_index({region, age_j, InfectionState::Infected})]; - flows[get_flat_flow_index( + flows[Base::template get_flat_flow_index( {region, age_i})] *= coeffStoI * y[population.get_flat_index({region, age_j, InfectionState::Susceptible})]; } } - for (auto region = Region(0); region < n_regions; region++) { - flows[get_flat_flow_index({region, age_i})] = - (1.0 / params.get()) * - y[population.get_flat_index({region, age_i, InfectionState::Infected})]; + for (auto region : make_index_range(n_regions)) { + flows[Base::template get_flat_flow_index( + {region, age_i})] = (1.0 / params.template get>()[age_i]) * + y[population.get_flat_index({region, age_i, InfectionState::Infected})]; } } } diff --git a/cpp/models/ode_sir_mobility/parameters.h b/cpp/models/ode_sir_mobility/parameters.h index ba66109d98..cceb5f2dc3 100644 --- a/cpp/models/ode_sir_mobility/parameters.h +++ b/cpp/models/ode_sir_mobility/parameters.h @@ -2,8 +2,8 @@ #ifndef SIRMOBILITY_PARAMETERS_H #define SIRMOBILITY_PARAMETERS_H +#include "memilio/epidemiology/uncertain_matrix.h" #include "memilio/utils/uncertain_value.h" -#include "memilio/epidemiology/contact_matrix.h" #include "memilio/epidemiology/age_group.h" #include "memilio/utils/parameter_set.h" #include "memilio/utils/custom_index_array.h" @@ -23,11 +23,12 @@ namespace osirmobility /** * @brief Probability of getting infected from a contact. */ +template struct TransmissionProbabilityOnContact { - using Type = UncertainValue; - static Type get_default(Region) + using Type = CustomIndexArray, AgeGroup>; + static Type get_default(Region, AgeGroup size) { - return Type(1.0); + return Type(size, 1.0); } static std::string name() { @@ -36,13 +37,14 @@ struct TransmissionProbabilityOnContact { }; /** - * @brief The infectious time in day unit. - */ + * @brief The infectious time in day unit. + */ +template struct TimeInfected { - using Type = UncertainValue; - static Type get_default(Region) + using Type = CustomIndexArray, AgeGroup>; + static Type get_default(Region, AgeGroup size) { - return Type(6.0); + return Type(size, 6.0); } static std::string name() { @@ -53,11 +55,12 @@ struct TimeInfected { /** * @brief The contact patterns within the society are modelled using a ContactMatrix. */ +template struct ContactPatterns { - using Type = ContactMatrix; - static Type get_default(Region) + using Type = UncertainContactMatrix; + static Type get_default(Region, AgeGroup size) { - return Type{1}; + return Type(1, static_cast((size_t)size)); } static std::string name() { @@ -70,7 +73,7 @@ struct ContactPatterns { */ struct CommutingRatio { using Type = std::vector>; - static Type get_default(Region) + static Type get_default(Region, AgeGroup) { return Type({{Region(0), Region(0), 0.}}); } @@ -83,9 +86,10 @@ struct CommutingRatio { /** * @brief The ratio that regulates the infections during commuting. */ +template struct ImpactCommuters { - using Type = UncertainValue; - static Type get_default(Region) + using Type = UncertainValue; + static Type get_default(Region, AgeGroup) { return Type(0.); } @@ -100,7 +104,7 @@ struct ImpactCommuters { */ struct PathIntersections { using Type = CustomIndexArray, Region, Region>; - static Type get_default(Region size) + static Type get_default(Region size, AgeGroup) { return Type({size, size}); } @@ -110,17 +114,19 @@ struct PathIntersections { } }; -using ParametersBase = ParameterSet; +template +using ParametersBase = ParameterSet, TimeInfected, ContactPatterns, + CommutingRatio, ImpactCommuters, PathIntersections>; /** * @brief Parameters of SIR model. */ -class Parameters : public ParametersBase +template +class Parameters : public ParametersBase { public: Parameters(Region num_regions, AgeGroup num_agegroups) - : ParametersBase(num_regions) + : ParametersBase(num_regions, num_agegroups) , m_num_regions{num_regions} , m_num_agegroups(num_agegroups) { @@ -154,28 +160,33 @@ class Parameters : public ParametersBase double tol_times = 1e-1; int corrected = false; - if (this->get() < tol_times) { - log_warning("Constraint check: Parameter TimeInfected changed from {:.4f} to {:.4f}. Please note that " - "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " - "and reset parameters.", - this->get(), tol_times); - this->get() = tol_times; - corrected = true; - } - if (this->get() < 0.0 || - this->get() > 1.0) { - log_warning("Constraint check: Parameter TransmissionProbabilityOnContact changed from {:0.4f} to {:d} ", - this->get(), 0.0); - this->get() = 0.0; - corrected = true; + + for (auto i = AgeGroup(0); i < AgeGroup(m_num_agegroups); i++) { + if (this->template get>()[i] < tol_times) { + log_warning( + "Constraint check: Parameter TimeInfected changed from {:.4f} to {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->template get>()[i], tol_times); + this->template get>()[i] = tol_times; + corrected = true; + } + if (this->template get>()[i] < 0.0 || + this->template get>()[i] > 1.0) { + log_warning( + "Constraint check: Parameter TransmissionProbabilityOnContact changed from {:0.4f} to {:d} ", + this->template get>()[i], 0.0); + this->template get>() = 0.0; + corrected = true; + } } - if (this->get() < 0.0 || this->get() > 1.0) { + if (this->template get>() < 0.0 || this->template get>() > 1.0) { log_warning("Constraint check: Parameter ImpactCommuters changed from {:.4f} to {:.4f}.", - this->get(), 0.0); - this->get() = 0.0; - corrected = true; + this->template get>(), 0.0); + this->template get>() = 0.0; + corrected = true; } - for (auto& i : this->get()) { + for (auto& i : this->template get()) { if (std::get(i) < 0.0 || std::get(i) > 1.0) { log_warning("Constraint check: Parameter CommutingRatio changed from {:.4f} to {:.4f}.", std::get(i), 0.0); @@ -186,8 +197,9 @@ class Parameters : public ParametersBase std::get<1>(i) >= m_num_regions) { log_warning( "Constraint check: Removed entry of Parameter CommutingRatio because of non-existing Regions."); - auto it = std::find(this->get().begin(), this->get().end(), i); - this->get().erase(it); + auto it = std::find(this->template get().begin(), + this->template get().end(), i); + this->template get().erase(it); corrected = true; } } @@ -203,26 +215,30 @@ class Parameters : public ParametersBase { double tol_times = 1e-1; - if (this->get() < tol_times) { - log_error("Constraint check: Parameter TimeInfected {:.4f} smaller or equal {:.4f}. Please note that " - "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " - "and reset parameters.", - this->get(), 0.0); - return true; - } - if (this->get() < 0.0 || - this->get() > 1.0) { - log_error( - "Constraint check: Parameter TransmissionProbabilityOnContact {:.4f} smaller {:.4f} or greater {:.4f}", - this->get(), 0.0, 1.0); - return true; + for (auto i = AgeGroup(0); i < AgeGroup(m_num_agegroups); i++) { + + if (this->template get>()[i] < tol_times) { + log_error( + "Constraint check: Parameter TimeInfected {:.4f} smaller or equal {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->template get>()[i], 0.0); + return true; + } + if (this->template get>()[i] < 0.0 || + this->template get>()[i] > 1.0) { + log_error("Constraint check: Parameter TransmissionProbabilityOnContact {:.4f} smaller {:.4f} or " + "greater {:.4f}", + this->template get>()[i], 0.0, 1.0); + return true; + } } - if (this->get() < 0.0 || this->get() > 1.0) { + if (this->template get>() < 0.0 || this->template get>() > 1.0) { log_error("Constraint check: Parameter ImpactCommuters {:.4f} smaller {:.4f} or greater {:.4f}", - this->get(), 0.0, 1.0); + this->template get>(), 0.0, 1.0); return true; } - for (auto i : this->get()) { + for (auto i : this->template get()) { if (std::get(i) < 0.0 || std::get(i) > 1.0) { log_error("Constraint check: Parameter CommutingRatio entry {:.4f} smaller {:.4f} or greater {:.4f}", std::get(i), 0.0, 1.0); @@ -230,8 +246,8 @@ class Parameters : public ParametersBase } if (std::get<0>(i) < Region(0) || std::get<1>(i) < Region(0) || std::get<0>(i) > m_num_regions || std::get<1>(i) > m_num_regions) { - log_error("Constraint check: Parameter CommutingRatio has an entry with start or end Region that does " - "not appear in the model."); + log_error("Constraint check: Parameter CommutingRatio has an entry with start or end Region " + "that does not appear in the model."); return true; } } @@ -252,7 +268,7 @@ class Parameters : public ParametersBase template static IOResult deserialize(IOContext& io) { - BOOST_OUTCOME_TRY(base, ParametersBase::deserialize(io)); + BOOST_OUTCOME_TRY(auto&& base, ParametersBase::deserialize(io)); return success(Parameters(std::move(base))); } From 6ace8cf3d0b92586c6077a36514fd5202d1d62fe Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:05:13 +0200 Subject: [PATCH 11/87] Renaming --- cpp/models/ode_seir_mobility/model.h | 3 ++- cpp/models/ode_seir_mobility/parameters.h | 30 +++++++++++++---------- cpp/models/ode_sir_mobility/model.h | 3 ++- cpp/models/ode_sir_mobility/parameters.h | 25 ++++++++++--------- cpp/tests/test_odesirmobility.cpp | 18 +++++++------- 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/cpp/models/ode_seir_mobility/model.h b/cpp/models/ode_seir_mobility/model.h index 7308b874a2..a40db1474a 100644 --- a/cpp/models/ode_seir_mobility/model.h +++ b/cpp/models/ode_seir_mobility/model.h @@ -86,7 +86,8 @@ class Model : public FlowModel( {start_region, age_i})] += - params.template get>() * strength * strength_commuter * + params.template get>() * strength * + strength_commuter * pop[population.get_flat_index({start_region_commuter, age_j, InfectionState::Infected})]; } } diff --git a/cpp/models/ode_seir_mobility/parameters.h b/cpp/models/ode_seir_mobility/parameters.h index c2a02f83e4..0b27284c9d 100644 --- a/cpp/models/ode_seir_mobility/parameters.h +++ b/cpp/models/ode_seir_mobility/parameters.h @@ -103,7 +103,7 @@ struct CommutingRatio { * @brief The ratio that regulates the infections during commuting. */ template -struct ImpactCommuters { +struct ImpactTransmissionDuringCommuting { using Type = UncertainValue; static Type get_default(Region, AgeGroup) { @@ -111,7 +111,7 @@ struct ImpactCommuters { } static std::string name() { - return "ImpactCommuters"; + return "ImpactTransmissionDuringCommuting"; } }; @@ -131,8 +131,9 @@ struct PathIntersections { }; template -using ParametersBase = ParameterSet, TimeExposed, TimeInfected, - ContactPatterns, CommutingRatio, ImpactCommuters, PathIntersections>; +using ParametersBase = + ParameterSet, TimeExposed, TimeInfected, ContactPatterns, + CommutingRatio, ImpactTransmissionDuringCommuting, PathIntersections>; /** * @brief Parameters of SEIR model. @@ -187,7 +188,7 @@ class Parameters : public ParametersBase this->template get>()[i] = tol_times; corrected = true; } - if (this->template get() < tol_times) { + if (this->template get>()[i] < tol_times) { log_warning( "Constraint check: Parameter TimeInfected changed from {:.4f} to {:.4f}. Please note that " "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " @@ -205,11 +206,12 @@ class Parameters : public ParametersBase corrected = true; } } - if (this->template get>() < 0.0 || this->template get>() > 1.0) { - log_warning("Constraint check: Parameter ImpactCommuters changed from {:.4f} to {:.4f}.", - this->template get>(), 0.0); - this->template get>() = 0.0; - corrected = true; + if (this->template get>() < 0.0 || + this->template get>() > 1.0) { + log_warning("Constraint check: Parameter ImpactTransmissionDuringCommuting changed from {:.4f} to {:.4f}.", + this->template get>(), 0.0); + this->template get>() = 0.0; + corrected = true; } for (auto& i : this->template get()) { if (std::get(i) < 0.0 || std::get(i) > 1.0) { @@ -265,9 +267,11 @@ class Parameters : public ParametersBase return true; } } - if (this->template get>() < 0.0 || this->template get>() > 1.0) { - log_error("Constraint check: Parameter ImpactCommuters {:.4f} smaller {:.4f} or greater {:.4f}", - this->template get>(), 0.0, 1.0); + if (this->template get>() < 0.0 || + this->template get>() > 1.0) { + log_error( + "Constraint check: Parameter ImpactTransmissionDuringCommuting {:.4f} smaller {:.4f} or greater {:.4f}", + this->template get>(), 0.0, 1.0); return true; } for (auto i : this->template get()) { diff --git a/cpp/models/ode_sir_mobility/model.h b/cpp/models/ode_sir_mobility/model.h index 82cebe7b76..30ef675728 100644 --- a/cpp/models/ode_sir_mobility/model.h +++ b/cpp/models/ode_sir_mobility/model.h @@ -85,7 +85,8 @@ class Model : public FlowModel( {start_region, age_i})] += - params.template get>() * strength * strength_commuter * + params.template get>() * strength * + strength_commuter * pop[population.get_flat_index({start_region_commuter, age_j, InfectionState::Infected})]; } } diff --git a/cpp/models/ode_sir_mobility/parameters.h b/cpp/models/ode_sir_mobility/parameters.h index cceb5f2dc3..18f7110543 100644 --- a/cpp/models/ode_sir_mobility/parameters.h +++ b/cpp/models/ode_sir_mobility/parameters.h @@ -87,7 +87,7 @@ struct CommutingRatio { * @brief The ratio that regulates the infections during commuting. */ template -struct ImpactCommuters { +struct ImpactTransmissionDuringCommuting { using Type = UncertainValue; static Type get_default(Region, AgeGroup) { @@ -95,7 +95,7 @@ struct ImpactCommuters { } static std::string name() { - return "ImpactCommuters"; + return "ImpactTransmissionDuringCommuting"; } }; @@ -116,7 +116,7 @@ struct PathIntersections { template using ParametersBase = ParameterSet, TimeInfected, ContactPatterns, - CommutingRatio, ImpactCommuters, PathIntersections>; + CommutingRatio, ImpactTransmissionDuringCommuting, PathIntersections>; /** * @brief Parameters of SIR model. @@ -180,11 +180,12 @@ class Parameters : public ParametersBase corrected = true; } } - if (this->template get>() < 0.0 || this->template get>() > 1.0) { - log_warning("Constraint check: Parameter ImpactCommuters changed from {:.4f} to {:.4f}.", - this->template get>(), 0.0); - this->template get>() = 0.0; - corrected = true; + if (this->template get>() < 0.0 || + this->template get>() > 1.0) { + log_warning("Constraint check: Parameter ImpactTransmissionDuringCommuting changed from {:.4f} to {:.4f}.", + this->template get>(), 0.0); + this->template get>() = 0.0; + corrected = true; } for (auto& i : this->template get()) { if (std::get(i) < 0.0 || std::get(i) > 1.0) { @@ -233,9 +234,11 @@ class Parameters : public ParametersBase return true; } } - if (this->template get>() < 0.0 || this->template get>() > 1.0) { - log_error("Constraint check: Parameter ImpactCommuters {:.4f} smaller {:.4f} or greater {:.4f}", - this->template get>(), 0.0, 1.0); + if (this->template get>() < 0.0 || + this->template get>() > 1.0) { + log_error( + "Constraint check: Parameter ImpactTransmissionDuringCommuting {:.4f} smaller {:.4f} or greater {:.4f}", + this->template get>(), 0.0, 1.0); return true; } for (auto i : this->template get()) { diff --git a/cpp/tests/test_odesirmobility.cpp b/cpp/tests/test_odesirmobility.cpp index 13173ec405..247a8622ff 100644 --- a/cpp/tests/test_odesirmobility.cpp +++ b/cpp/tests/test_odesirmobility.cpp @@ -57,7 +57,7 @@ TEST(TestOdeSirMobility, compareWithPreviousRun) model.parameters.get().get_baseline()(0, 0) = 2.7; model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); - model.parameters.set(1.); + model.parameters.set(1.); model.parameters.get().push_back( {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.2}); model.parameters.get().push_back( @@ -141,7 +141,7 @@ TEST(TestOdeSirMobility, checkPopulationConservation) } model.parameters.set(2); model.parameters.set(0.04); - model.parameters.set(1.); + model.parameters.set(1.); model.parameters.get().get_baseline()(0, 0) = 1.; model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); model.parameters.get().push_back( @@ -170,7 +170,7 @@ TEST(TestOdeSirMobility, check_constraints_parameters) mio::osirmobility::Model model((size_t)num_regions); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.set(1.); + model.parameters.set(1.); model.parameters.get().get_baseline()(0, 0) = 10.; model.parameters.get().push_back( {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.5}); @@ -189,10 +189,10 @@ TEST(TestOdeSirMobility, check_constraints_parameters) ASSERT_EQ(model.parameters.check_constraints(), 1); model.parameters.set(0.04); - model.parameters.set(10.); + model.parameters.set(10.); ASSERT_EQ(model.parameters.check_constraints(), 1); - model.parameters.set(1.); + model.parameters.set(1.); model.parameters.get().push_back( {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 10.5}); ASSERT_EQ(model.parameters.check_constraints(), 1); @@ -211,7 +211,7 @@ TEST(TestOdeSirMobility, apply_constraints_parameters) mio::osirmobility::Model model((size_t)num_regions); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.set(1.); + model.parameters.set(1.); model.parameters.get().get_baseline()(0, 0) = 10.; model.parameters.get().push_back( {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.5}); @@ -229,11 +229,11 @@ TEST(TestOdeSirMobility, apply_constraints_parameters) EXPECT_NEAR(model.parameters.get(), 0.0, 1e-14); model.parameters.set(0.04); - model.parameters.set(10.); + model.parameters.set(10.); EXPECT_EQ(model.parameters.apply_constraints(), 1); - EXPECT_NEAR(model.parameters.get(), 0.0, 1e-14); + EXPECT_NEAR(model.parameters.get(), 0.0, 1e-14); - model.parameters.set(1.); + model.parameters.set(1.); model.parameters.get().push_back( {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 10.5}); EXPECT_EQ(model.parameters.apply_constraints(), 1); From 232f7057080ac866eea0a5f9575f8f1334202109 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:06:16 +0200 Subject: [PATCH 12/87] Renaming --- cpp/examples/ode_sir_mobility.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/examples/ode_sir_mobility.cpp b/cpp/examples/ode_sir_mobility.cpp index 46dca6739e..7aaf725e45 100644 --- a/cpp/examples/ode_sir_mobility.cpp +++ b/cpp/examples/ode_sir_mobility.cpp @@ -170,7 +170,7 @@ int main() model.parameters.set>(2); model.parameters.set>(0.04); - model.parameters.set>(1.); + model.parameters.set>(1.); mio::ContactMatrixGroup& contact_matrix = model.parameters.get>().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(1.0); From 6045e1fed46e6e3b93d5a1dfb64bbe9ec718c8d5 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:07:31 +0200 Subject: [PATCH 13/87] Set up examples for comparison --- cpp/examples/graph.cpp | 29 +++++-- cpp/examples/ode_seir_mobility.cpp | 129 ++++++++++++----------------- 2 files changed, 77 insertions(+), 81 deletions(-) diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index ecd5100882..06dd3ceff6 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -22,9 +22,12 @@ #include "ode_seir/parameters.h" #include "memilio/mobility/metapopulation_mobility_instant.h" #include "memilio/compartments/simulation.h" +#include "memilio/io/result_io.h" int main() { + mio::set_log_level(mio::LogLevel::off); + const auto t0 = 0.; const auto tmax = 10.; const auto dt = 0.5; //time step of migration, daily migration every second step @@ -34,9 +37,11 @@ int main() // set population model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 10000; + model.parameters.set>(1.); + // set transition times - model.parameters.set>(1); - model.parameters.set>(1); + model.parameters.set>(3.); + model.parameters.set>(5.); // set contact matrix mio::ContactMatrixGroup& contact_matrix = model.parameters.get>().get_cont_freq_mat(); @@ -47,9 +52,9 @@ int main() auto model_group2 = model; //some contact restrictions in group 1 - mio::ContactMatrixGroup& contact_matrix1 = - model_group1.parameters.get>().get_cont_freq_mat(); - contact_matrix1[0].add_damping(0.5, mio::SimulationTime(5)); + // mio::ContactMatrixGroup& contact_matrix1 = + // model_group1.parameters.get>().get_cont_freq_mat(); + // contact_matrix1[0].add_damping(0.5, mio::SimulationTime(5)); //infection starts in group 1 model_group1.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 9990; @@ -65,5 +70,19 @@ int main() sim.advance(tmax); + auto result_graph = std::move(sim).get_graph(); + auto result = mio::interpolate_simulation_result(result_graph); + + std::vector county_ids(result_graph.nodes().size()); + std::transform(result_graph.nodes().begin(), result_graph.nodes().end(), county_ids.begin(), [](auto& n) { + return n.id; + }); + + // auto save_result_status = save_result(result, county_ids, 1, "graph_result.h5"); + + for (auto&& node : result_graph.nodes()) { + node.property.get_result().print_table(); + } + return 0; } diff --git a/cpp/examples/ode_seir_mobility.cpp b/cpp/examples/ode_seir_mobility.cpp index c6b9785639..1e5d0cb1cd 100644 --- a/cpp/examples/ode_seir_mobility.cpp +++ b/cpp/examples/ode_seir_mobility.cpp @@ -9,6 +9,7 @@ #include "models/ode_seir_mobility/parameters.h" #include "models/ode_seir_mobility/regions.h" #include "memilio/io/io.h" +#include "memilio/io/result_io.h" mio::IOResult>>> read_path_mobility(const std::string& filename) { @@ -140,12 +141,12 @@ int main() mio::set_log_level(mio::LogLevel::debug); ScalarType t0 = 0.; - ScalarType tmax = 50.; + ScalarType tmax = 10.; ScalarType dt = 1; - ScalarType number_regions = 4; - ScalarType number_age_groups = 1; - ScalarType total_population_per_region = 10; + std::vector region_ids = {1001, 1002}; + ScalarType number_regions = region_ids.size(); + ScalarType number_age_groups = 1; mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); @@ -153,90 +154,66 @@ int main() const std::string& trip_chain_data = ""; mio::oseirmobility::Model model(number_regions, number_age_groups); + model.populations[{mio::oseirmobility::Region(0), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Exposed}] = + 10; + model.populations[{mio::oseirmobility::Region(0), mio::AgeGroup(0), + mio::oseirmobility::InfectionState::Susceptible}] = 9990; + model.populations[{mio::oseirmobility::Region(1), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Exposed}] = + 0; + model.populations[{mio::oseirmobility::Region(1), mio::AgeGroup(0), + mio::oseirmobility::InfectionState::Susceptible}] = 10000; - for (size_t i = 0; i < number_regions; i++) { - model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), - mio::oseirmobility::InfectionState::Infected}] = 1; - model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), - mio::oseirmobility::InfectionState::Recovered}] = 0; - model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), - mio::oseirmobility::InfectionState::Susceptible}] = - total_population_per_region - - model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), - mio::oseirmobility::InfectionState::Infected}] - - model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), - mio::oseirmobility::InfectionState::Recovered}]; - } + model.parameters.set>(1.); + + model.parameters.set>(3.); + model.parameters.set>(5.); - model.parameters.set>(1); - model.parameters.set>(2); - model.parameters.set>(0.04); - model.parameters.set>(1.); + model.parameters.set>(0.); mio::ContactMatrixGroup& contact_matrix = - model.parameters.get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(1.0); - contact_matrix[0].add_damping(0.6, mio::SimulationTime(12.5)); + model.parameters.get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(2.7); + // contact_matrix[0].add_damping(0.5, mio::SimulationTime(5)); model.parameters.get().push_back( - {mio::oseirmobility::Region(1), mio::oseirmobility::Region(0), 0.2}); - model.parameters.get().push_back( - {mio::oseirmobility::Region(1), mio::oseirmobility::Region(2), 0.6}); - model.parameters.get().push_back( - {mio::oseirmobility::Region(2), mio::oseirmobility::Region(0), 0.5}); + {mio::oseirmobility::Region(0), mio::oseirmobility::Region(1), 0.03}); model.parameters.get().push_back( - {mio::oseirmobility::Region(0), mio::oseirmobility::Region(3), 1.0}); - model.parameters.get().push_back( - {mio::oseirmobility::Region(1), mio::oseirmobility::Region(3), 0.2}); - - model.parameters.get()[{mio::oseirmobility::Region(0), - mio::oseirmobility::Region(1)}] = {2}; - model.parameters.get()[{mio::oseirmobility::Region(0), - mio::oseirmobility::Region(3)}] = {2}; - model.parameters.get()[{mio::oseirmobility::Region(1), - mio::oseirmobility::Region(0)}] = {2}; - model.parameters.get()[{mio::oseirmobility::Region(1), - mio::oseirmobility::Region(2)}] = {0}; - model.parameters.get()[{mio::oseirmobility::Region(1), - mio::oseirmobility::Region(3)}] = {2}; - model.parameters.get()[{mio::oseirmobility::Region(2), - mio::oseirmobility::Region(1)}] = {0}; - model.parameters.get()[{mio::oseirmobility::Region(3), - mio::oseirmobility::Region(0)}] = {2}; - model.parameters.get()[{mio::oseirmobility::Region(3), - mio::oseirmobility::Region(1)}] = {2}; - - // auto result_preprocess = set_mobility_weights(mobility_data, trip_chain_data, model, number_regions); - - std::shared_ptr> integrator = - std::make_shared>(); + {mio::oseirmobility::Region(1), mio::oseirmobility::Region(0), 0.03}); + + using DefaultIntegratorCore = + mio::ControlledStepperWrapper; + + std::shared_ptr> integrator = std::make_shared(); model.check_constraints(); - auto sir = simulate(t0, tmax, dt, model, integrator); + auto result_from_sim = simulate(t0, tmax, dt, model, integrator); - bool print_to_terminal = true; + auto save_result_status = + mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_test.h5"); - sir.print_table(); + // bool print_to_terminal = true; - if (print_to_terminal) { + // sir.print_table(); - std::vector vars = {"S", "E", "I", "R"}; - printf("\n # t"); - for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { - for (size_t k = 0; k < (size_t)mio::oseirmobility::InfectionState::Count; k++) { - printf(" %s_%d", vars[k].c_str(), (int)i); - } - } + // if (print_to_terminal) { - auto num_points = static_cast(sir.get_num_time_points()); - for (size_t i = 0; i < num_points; i++) { - printf("\n%.14f ", sir.get_time(i)); - for (size_t k = 0; k < (size_t)model.parameters.get_num_regions(); k++) { - for (size_t j = 0; j < (size_t)mio::oseirmobility::InfectionState::Count; j++) { - printf(" %.14f", sir.get_value(i)[j + (size_t)mio::oseirmobility::InfectionState::Count * (int)k]); - } - } - } - printf("\n"); - } + // std::vector vars = {"S", "E", "I", "R"}; + // printf("\n # t"); + // for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { + // for (size_t k = 0; k < (size_t)mio::oseirmobility::InfectionState::Count; k++) { + // printf(" %s_%d", vars[k].c_str(), (int)i); + // } + // } + + // auto num_points = static_cast(sir.get_num_time_points()); + // for (size_t i = 0; i < num_points; i++) { + // printf("\n%.14f ", sir.get_time(i)); + // for (size_t k = 0; k < (size_t)model.parameters.get_num_regions(); k++) { + // for (size_t j = 0; j < (size_t)mio::oseirmobility::InfectionState::Count; j++) { + // printf(" %.14f", sir.get_value(i)[j + (size_t)mio::oseirmobility::InfectionState::Count * (int)k]); + // } + // } + // } + // printf("\n"); + // } } From dfdac2deb65e8b7b034a19e704e2d5e9b5775a55 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:14:10 +0200 Subject: [PATCH 14/87] changes for plots and corrections --- cpp/examples/graph.cpp | 4 +- cpp/examples/ode_seir_mobility.cpp | 8 +- cpp/models/ode_seir_mobility/model.h | 12 +- tools/plot_results_mobilitymodels.py | 164 +++++++++++++++++++++++++++ 4 files changed, 177 insertions(+), 11 deletions(-) create mode 100644 tools/plot_results_mobilitymodels.py diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index 06dd3ceff6..3b8767a686 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -26,8 +26,6 @@ int main() { - mio::set_log_level(mio::LogLevel::off); - const auto t0 = 0.; const auto tmax = 10.; const auto dt = 0.5; //time step of migration, daily migration every second step @@ -78,7 +76,7 @@ int main() return n.id; }); - // auto save_result_status = save_result(result, county_ids, 1, "graph_result.h5"); + auto save_result_status = save_result(result, county_ids, 1, "graph_result.h5"); for (auto&& node : result_graph.nodes()) { node.property.get_result().print_table(); diff --git a/cpp/examples/ode_seir_mobility.cpp b/cpp/examples/ode_seir_mobility.cpp index 1e5d0cb1cd..cfba2c1e8f 100644 --- a/cpp/examples/ode_seir_mobility.cpp +++ b/cpp/examples/ode_seir_mobility.cpp @@ -175,9 +175,9 @@ int main() // contact_matrix[0].add_damping(0.5, mio::SimulationTime(5)); model.parameters.get().push_back( - {mio::oseirmobility::Region(0), mio::oseirmobility::Region(1), 0.03}); + {mio::oseirmobility::Region(0), mio::oseirmobility::Region(1), 0.01}); model.parameters.get().push_back( - {mio::oseirmobility::Region(1), mio::oseirmobility::Region(0), 0.03}); + {mio::oseirmobility::Region(1), mio::oseirmobility::Region(0), 0.01}); using DefaultIntegratorCore = mio::ControlledStepperWrapper; @@ -189,11 +189,11 @@ int main() auto result_from_sim = simulate(t0, tmax, dt, model, integrator); auto save_result_status = - mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_test.h5"); + mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result.h5"); // bool print_to_terminal = true; - // sir.print_table(); + // result_from_sim.print_table(); // if (print_to_terminal) { diff --git a/cpp/models/ode_seir_mobility/model.h b/cpp/models/ode_seir_mobility/model.h index a40db1474a..c99eb732c9 100644 --- a/cpp/models/ode_seir_mobility/model.h +++ b/cpp/models/ode_seir_mobility/model.h @@ -52,10 +52,6 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t)( - age_i.get(), age_j.get()) * - params.template get>()[age_i] / - population.get_group_total(age_j); for (auto edge : params.template get()) { auto start_region = get<0>(edge); auto end_region = get<1>(edge); @@ -92,6 +88,14 @@ class Model : public FlowModel({(size_t)region, 1}); + auto const population_region_age = population_region.template slice({(size_t)age_j, 1}); + double population_size = + std::accumulate(population_region_age.begin(), population_region_age.end(), 0.); + double coeffStoI = + params.template get>().get_cont_freq_mat().get_matrix_at(t)(age_i.get(), + age_j.get()) * + params.template get>()[age_i] / population_size; flows[Base::template get_flat_flow_index( {region, age_i})] += pop[population.get_flat_index({region, age_j, InfectionState::Infected})]; flows[Base::template get_flat_flow_index( diff --git a/tools/plot_results_mobilitymodels.py b/tools/plot_results_mobilitymodels.py new file mode 100644 index 0000000000..4eb997c724 --- /dev/null +++ b/tools/plot_results_mobilitymodels.py @@ -0,0 +1,164 @@ +import h5py +import os +import matplotlib.pyplot as plt + +import memilio.epidata.getDataIntoPandasDataFrame as gd + +# Define compartments. +secir_dict = {0: 'Susceptible', 1: 'Exposed', 2: 'Infected', 3: 'Recovered'} + +# Define color and style to be used while plotting for different models to make plots consistent. +color_dict = {0: '#1f77b4', + 1:'#2ca02c' + } +linestyle_dict = {"ODE": 'solid', + "Graph": 'dashdot' + } + +def compare_all_compartments(files, legendplot, filename_plot="compare_compartments"): + + fig, axs = plt.subplots( + 2, 2, sharex='all', num=filename_plot, tight_layout=False) + + # Add simulation results to plot. + for file in range(len(files)): + # Load data. + h5file = h5py.File(str(files[file]) + '.h5', 'r') + + number_regions = len(list(h5file.keys())) + for region in range(number_regions): + if (len(list(h5file[list(h5file.keys())[region]].keys())) > 3): + data = h5file[list(h5file.keys())[region]] + dates = data['Time'][:] + + number_regions = len(list(h5file[list(h5file.keys())[region]].keys())) - 2 + for region in range(number_regions): + total = data['Group'+str(region+1)][:, :] + if (total.shape[1] != 4): + raise gd.DataError("Expected a different number of compartments.") + # Plot result. + if legendplot[file] in linestyle_dict: + for i in range(4): + axs[int(i/2), i % 2].plot(dates, + total[:, i], label=legendplot[file] +" Region "+ str(region), linewidth=1.2, + linestyle=linestyle_dict[legendplot[file]], + color=color_dict[region]) + else: + for i in range(4): + axs[int(i/2), i % 2].plot(dates, + total[:, i], label=legendplot[file], linewidth=1.2) + else: + data = h5file[list(h5file.keys())[region]] + dates = data['Time'][:] + # As there should be only one Group, total is the simulation result. + total = data['Total'][:, :] + if (total.shape[1] != 4): + raise gd.DataError("Expected a different number of compartments.") + # Plot result. + if legendplot[file] in linestyle_dict: + for i in range(4): + axs[int(i/2), i % 2].plot(dates, + total[:, i], label=legendplot[file] +" Region "+ str(region), linewidth=1.2, + linestyle=linestyle_dict[legendplot[file]], + color=color_dict[region]) + else: + for i in range(4): + axs[int(i/2), i % 2].plot(dates, + total[:, i], label=legendplot[file], linewidth=1.2) + h5file.close() + + # Define some characteristics of the plot. + for i in range(4): + axs[int(i/2), i % 2].set_title(secir_dict[i], fontsize=8) + axs[int(i/2), i % 2].set_xlim(left=0, right=dates[-1]) + axs[int(i/2), i % 2].grid(True, linestyle='--') + axs[int(i/2), i % 2].tick_params(axis='y', labelsize=7) + axs[int(i/2), i % 2].tick_params(axis='x', labelsize=7) + # axs[int(i/2), i % 2].xaxis.set_ticks(np.arange(0, dates[-1]+1, 5)) + + fig.supxlabel('Time (in days)', fontsize=9) + + lines, labels = axs[0, 0].get_legend_handles_labels() + lgd = fig.legend(lines, labels, ncol=len(legendplot), loc='outside lower center', + fontsize=10, bbox_to_anchor=(0.5, - 0.06), bbox_transform=fig.transFigure) + + plt.tight_layout(pad=0, w_pad=0.5, h_pad=0.1) + plt.subplots_adjust(bottom=0.09) + + # Save result. + if not os.path.isdir('Plots'): + os.makedirs('Plots') + fig.savefig('Plots/'+filename_plot+'.png', + bbox_extra_artists=(lgd,), bbox_inches='tight', dpi=500) + + +def plot_new_infections(files, ylim, legendplot, filename_plot="compare_new_infections"): + + plt.figure(filename_plot) + + # Add simulation results to plot. + for file in range(len(files)): + # Load data. + h5file = h5py.File(str(files[file]) + '.h5', 'r') + + number_regions = len(list(h5file.keys())) + for region in range(number_regions): + if (len(list(h5file[list(h5file.keys())[region]].keys())) > 3): + data = h5file[list(h5file.keys())[region]] + dates = data['Time'][:] + + number_regions = len(list(h5file[list(h5file.keys())[region]].keys())) - 2 + for region_ in range(number_regions): + total = data['Group'+str(region_+1)][:, :] + if (total.shape[1] != 4): + raise gd.DataError( + "Expected a different number of compartments.") + incidence = (total[:-1, 0]-total[1:, 0])/(dates[1:]-dates[:-1]) + # Plot result. + if legendplot[file] in linestyle_dict: + plt.plot(dates[1:], incidence, linewidth=1.2, + linestyle=linestyle_dict[legendplot[file]], color=color_dict[region_]) + else: + plt.plot(dates[1:], incidence, linewidth=1.2) + else: + data = h5file[list(h5file.keys())[region]] + dates = data['Time'][:] + # As there should be only one Group, total is the simulation result. + total = data['Total'][:, :] + if (total.shape[1] != 4): + raise gd.DataError( + "Expected a different number of compartments.") + incidence = (total[:-1, 0]-total[1:, 0])/(dates[1:]-dates[:-1]) + # Plot result. + if legendplot[file] in linestyle_dict: + plt.plot(dates[1:], incidence, linewidth=1.2, + linestyle=linestyle_dict[legendplot[file]], color=color_dict[region]) + else: + plt.plot(dates[1:], incidence, linewidth=1.2) + + h5file.close() + + plt.xlabel('Time (in days)', fontsize=16) + # plt.xticks(np.arange(0, dates[-1]+1, 5)) + plt.yticks(fontsize=9) + plt.ylabel('New infections per day', fontsize=14) + plt.ylim(bottom=0, top=ylim) + plt.xlim(left=0, right=dates[-1]) + plt.legend(legendplot, fontsize=14, framealpha=0.5) + plt.grid(True, linestyle='--') + plt.tight_layout() + + # Save result. + if not os.path.isdir('Plots'): + os.makedirs('Plots') + plt.savefig('Plots/'+filename_plot+'.png', bbox_inches='tight', dpi=500) + + +if __name__ == '__main__': + data_dir = os.path.join(os.path.dirname(__file__), "..", "cpp", "build") + plot_new_infections([os.path.join(data_dir, "ode_result"), + os.path.join(data_dir, "graph_result")], + 2e3, legendplot=list(["ODE","Graph"])) + compare_all_compartments([os.path.join(data_dir, "ode_result"), + os.path.join(data_dir, "graph_result")], + legendplot=list(["ODE", "Graph"])) From 16a07dad83ca9886f63721176bd3820fcd56ceec Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:44:16 +0200 Subject: [PATCH 15/87] add improved model --- cpp/examples/ode_seir_mobility_improved.cpp | 114 +++++++ .../ode_seir_mobility_improved/CMakeLists.txt | 13 + .../infection_state.h | 26 ++ .../ode_seir_mobility_improved/model.cpp | 10 + cpp/models/ode_seir_mobility_improved/model.h | 96 ++++++ .../ode_seir_mobility_improved/parameters.h | 307 ++++++++++++++++++ .../ode_seir_mobility_improved/regions.h | 26 ++ 7 files changed, 592 insertions(+) create mode 100644 cpp/examples/ode_seir_mobility_improved.cpp create mode 100644 cpp/models/ode_seir_mobility_improved/CMakeLists.txt create mode 100644 cpp/models/ode_seir_mobility_improved/infection_state.h create mode 100644 cpp/models/ode_seir_mobility_improved/model.cpp create mode 100644 cpp/models/ode_seir_mobility_improved/model.h create mode 100644 cpp/models/ode_seir_mobility_improved/parameters.h create mode 100644 cpp/models/ode_seir_mobility_improved/regions.h diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp new file mode 100644 index 0000000000..94a87f63ad --- /dev/null +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -0,0 +1,114 @@ + +#include "memilio/compartments/simulation.h" +#include "memilio/math/euler.h" +#include "memilio/utils/logging.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/io/mobility_io.h" +#include "models/ode_seir_mobility_improved/infection_state.h" +#include "models/ode_seir_mobility_improved/model.h" +#include "models/ode_seir_mobility_improved/parameters.h" +#include "models/ode_seir_mobility_improved/regions.h" +#include "memilio/io/io.h" +#include "memilio/io/result_io.h" +#include "Eigen/Sparse" + +int main() +{ + mio::set_log_level(mio::LogLevel::debug); + + ScalarType t0 = 0.; + ScalarType tmax = 15.; + ScalarType dt = 1; + + std::vector region_ids = {1001, 1002}; + ScalarType number_regions = region_ids.size(); + ScalarType number_age_groups = 1; + + mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); + + const std::string& mobility_data = ""; + const std::string& trip_chain_data = ""; + + mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); + model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Exposed}] = 10; + model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 9990; + model.populations[{mio::oseirmobilityimproved::Region(1), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; + model.populations[{mio::oseirmobilityimproved::Region(1), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + + model.parameters.set>(1.); + + model.parameters.set>(3.); + model.parameters.set>(5.); + + model.parameters.set>(0.); + mio::ContactMatrixGroup& contact_matrix = + model.parameters.get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(2.7); + + // contact_matrix[0].add_damping(0.5, mio::SimulationTime(5)); + + Eigen::SparseMatrix& commuting_strengths = + model.parameters.get>(); + commuting_strengths.insert(0, 0) = 0.95; + commuting_strengths.insert(0, 1) = 0.05; + commuting_strengths.insert(1, 0) = 0.01; + commuting_strengths.insert(1, 1) = 0.99; + + auto& population = model.parameters.get>(); + for (int n = 0; n < commuting_strengths.outerSize(); ++n) { + population[{mio::oseirmobilityimproved::Region(n)}] += + model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); + auto x = population[{mio::oseirmobilityimproved::Region(0)}]; + mio::unused(x); + for (Eigen::SparseMatrix::InnerIterator it(commuting_strengths, n); it; ++it) { + auto start_population = model.populations.get_group_total(mio::oseirmobilityimproved::Region(it.row())); + population[{mio::oseirmobilityimproved::Region(it.row())}] -= it.value() * start_population; + x = population[{mio::oseirmobilityimproved::Region(0)}]; + population[{mio::oseirmobilityimproved::Region(it.col())}] += it.value() * start_population; + x = population[{mio::oseirmobilityimproved::Region(0)}]; + } + } + + using DefaultIntegratorCore = + mio::ControlledStepperWrapper; + + std::shared_ptr> integrator = std::make_shared(); + + model.check_constraints(); + + auto result_from_sim = simulate(t0, tmax, dt, model, integrator); + + auto save_result_status = + mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_improved.h5"); + + // bool print_to_terminal = true; + + // result_from_sim.print_table(); + + // if (print_to_terminal) { + + // std::vector vars = {"S", "E", "I", "R"}; + // printf("\n # t"); + // for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { + // for (size_t k = 0; k < (size_t)mio::oseirmobilityimproved::InfectionState::Count; k++) { + // printf(" %s_%d", vars[k].c_str(), (int)i); + // } + // } + + // auto num_points = static_cast(result_from_sim.get_num_time_points()); + // for (size_t i = 0; i < num_points; i++) { + // printf("\n%.14f ", result_from_sim.get_time(i)); + // for (size_t k = 0; k < (size_t)model.parameters.get_num_regions(); k++) { + // for (size_t j = 0; j < (size_t)mio::oseirmobilityimproved::InfectionState::Count; j++) { + // printf(" %.14f", result_from_sim.get_value( + // i)[j + (size_t)mio::oseirmobilityimproved::InfectionState::Count * (int)k]); + // } + // } + // } + // printf("\n"); + // } +} diff --git a/cpp/models/ode_seir_mobility_improved/CMakeLists.txt b/cpp/models/ode_seir_mobility_improved/CMakeLists.txt new file mode 100644 index 0000000000..82261701db --- /dev/null +++ b/cpp/models/ode_seir_mobility_improved/CMakeLists.txt @@ -0,0 +1,13 @@ +add_library(ode_seir_mobility_improved + infection_state.h + model.h + model.cpp + parameters.h + regions.h +) +target_link_libraries(ode_seir_mobility_improved PUBLIC memilio) +target_include_directories(ode_seir_mobility_improved PUBLIC + $ + $ +) +target_compile_options(ode_seir_mobility_improved PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_seir_mobility_improved/infection_state.h b/cpp/models/ode_seir_mobility_improved/infection_state.h new file mode 100644 index 0000000000..750a6415b7 --- /dev/null +++ b/cpp/models/ode_seir_mobility_improved/infection_state.h @@ -0,0 +1,26 @@ + +#ifndef ODESEIRMOBILITYIMPROVED_INFECTIONSTATE_H +#define ODESEIRMOBILITYIMPROVED_INFECTIONSTATE_H + +namespace mio +{ +namespace oseirmobilityimproved +{ + +/** + * @brief The InfectionState enum describes the possible + * categories for the infectious state of persons + */ +enum class InfectionState +{ + Susceptible, + Exposed, + Infected, + Recovered, + Count +}; + +} // namespace oseirmobilityimproved +} // namespace mio + +#endif // ODESEIR_INFECTIONSTATE_H diff --git a/cpp/models/ode_seir_mobility_improved/model.cpp b/cpp/models/ode_seir_mobility_improved/model.cpp new file mode 100644 index 0000000000..567a8a1e86 --- /dev/null +++ b/cpp/models/ode_seir_mobility_improved/model.cpp @@ -0,0 +1,10 @@ + +#include "ode_seir_mobility_improved/model.h" + +namespace mio +{ +namespace oseirmobilityimproved +{ + +} // namespace oseirmobilityimproved +} // namespace mio diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h new file mode 100644 index 0000000000..90dd9ab9ca --- /dev/null +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -0,0 +1,96 @@ + +#ifndef ODESEIRMOBILITYIMPROVED_MODEL_H +#define ODESEIRMOBILITYIMPROVED_MODEL_H + +#include "memilio/compartments/flow_model.h" +#include "memilio/epidemiology/populations.h" +#include "models/ode_seir_mobility_improved/infection_state.h" +#include "models/ode_seir_mobility_improved/parameters.h" +#include "models/ode_seir_mobility_improved/regions.h" +#include "memilio/epidemiology/age_group.h" + +namespace mio +{ +namespace oseirmobilityimproved +{ + +/******************** + * define the model * + ********************/ + +using Flows = TypeList, + Flow, + Flow>; + +template +class Model : public FlowModel, + Parameters, Flows> +{ + + using Base = + FlowModel, Parameters, Flows>; + +public: + using typename Base::ParameterSet; + using typename Base::Populations; + + Model(int num_regions, int num_agegroups) + : Base(Populations({Region(num_regions), AgeGroup(num_agegroups), InfectionState::Count}), + ParameterSet(Region(num_regions), AgeGroup(num_agegroups))) + { + } + // Einmal über den Vektor und später nochmal über die Regions + + void get_flows(Eigen::Ref> pop, Eigen::Ref> y, FP t, + Eigen::Ref> flows) const override + { + const auto& params = this->parameters; + const auto& population = this->populations; + const auto& commuting_strengths = params.template get>(); + + const Index n_age_groups = reduce_index>(params.get_num_agegroups()); + const Index n_regions = reduce_index>(params.get_num_regions()); + + CustomIndexArray infectives_per_region(n_regions); + for (auto age_i : make_index_range(n_age_groups)) { + for (auto age_j : make_index_range(n_age_groups)) { + for (int n = 0; n < commuting_strengths.outerSize(); ++n) { + infectives_per_region[Region(n)] = + 0.5 * pop[population.get_flat_index({Region(n), age_j, InfectionState::Infected})] * + commuting_strengths.coeff(n, n); + for (Eigen::SparseMatrix::InnerIterator it(commuting_strengths, n); it; ++it) { + infectives_per_region[Region(n)] += + 0.5 * pop[population.get_flat_index({Region(it.row()), age_j, InfectionState::Infected})] * + it.value(); + } + } + double coeffStoI = params.template get>().get_cont_freq_mat().get_matrix_at(t)( + age_i.get(), age_j.get()) * + params.template get>()[age_i]; + for (int n = 0; n < commuting_strengths.outerSize(); ++n) { + for (Eigen::SparseMatrix::InnerIterator it(commuting_strengths, n); it; ++it) { + flows[Base::template get_flat_flow_index( + {Region(it.row()), age_i})] += it.value() * infectives_per_region[Region(it.col())] / + params.template get>()[Region(it.col())]; + } + } + for (auto region : make_index_range(n_regions)) { + flows[Base::template get_flat_flow_index( + {region, age_i})] *= + coeffStoI * y[population.get_flat_index({region, age_j, InfectionState::Susceptible})]; + flows[Base::template get_flat_flow_index( + {region, age_i})] = (1.0 / params.template get>()[age_i]) * + y[population.get_flat_index({region, age_i, InfectionState::Exposed})]; + flows[Base::template get_flat_flow_index( + {region, age_i})] = (1.0 / params.template get>()[age_i]) * + y[population.get_flat_index({region, age_i, InfectionState::Infected})]; + } + } + } + } +}; // namespace oseirmobilityimproved + +} // namespace oseirmobilityimproved +} // namespace mio + +#endif // ODESEIRMOBILITY_MODEL_H diff --git a/cpp/models/ode_seir_mobility_improved/parameters.h b/cpp/models/ode_seir_mobility_improved/parameters.h new file mode 100644 index 0000000000..817881108d --- /dev/null +++ b/cpp/models/ode_seir_mobility_improved/parameters.h @@ -0,0 +1,307 @@ + +#ifndef SEIRMOBILITY_PARAMETERS_H +#define SEIRMOBILITY_PARAMETERS_H + +#include "memilio/epidemiology/uncertain_matrix.h" +#include "memilio/utils/uncertain_value.h" +#include "memilio/epidemiology/age_group.h" +#include "memilio/utils/parameter_set.h" +#include "memilio/utils/custom_index_array.h" +#include "models/ode_seir_mobility_improved/regions.h" +#include "Eigen/Sparse" + +#include + +namespace mio +{ +namespace oseirmobilityimproved +{ + +/**************************************************** + * Define Parameters of the SEIR model with mobility * + ****************************************************/ + +/** + * @brief Probability of getting infected from a contact. + */ +template +struct TransmissionProbabilityOnContact { + using Type = CustomIndexArray, AgeGroup>; + static Type get_default(Region, AgeGroup size) + { + return Type(size, 1.0); + } + static std::string name() + { + return "TransmissionProbabilityOnContact"; + } +}; + +/** + * @brief the latent time in day unit + */ +template +struct TimeExposed { + using Type = CustomIndexArray, AgeGroup>; + static Type get_default(Region, AgeGroup size) + { + return Type(size, 5.2); + } + static std::string name() + { + return "TimeExposed"; + } +}; + +/** + * @brief The infectious time in day unit. + */ +template +struct TimeInfected { + using Type = CustomIndexArray, AgeGroup>; + static Type get_default(Region, AgeGroup size) + { + return Type(size, 6.0); + } + static std::string name() + { + return "TimeInfected"; + } +}; + +/** + * @brief The contact patterns within the society are modelled using a ContactMatrix. + */ +template +struct ContactPatterns { + using Type = UncertainContactMatrix; + static Type get_default(Region, AgeGroup size) + { + return Type(1, static_cast((size_t)size)); + } + static std::string name() + { + return "ContactPatterns"; + } +}; + +/** + * @brief The ratio that regulates the infections during commuting. +*/ +template +struct ImpactTransmissionDuringCommuting { + using Type = UncertainValue; + static Type get_default(Region, AgeGroup) + { + return Type(0.); + } + static std::string name() + { + return "ImpactTransmissionDuringCommuting"; + } +}; + +/** + * @brief The Region%s that a person crosses when travelling from one Region to another. +*/ +struct PathIntersections { + using Type = CustomIndexArray, Region, Region>; + static Type get_default(Region, AgeGroup) + { + return Type({Region(0), Region(0)}); + } + static std::string name() + { + return "PathIntersections"; + } +}; + +/** + * @brief The commuting weights are modelled using a SparseMatrix. + */ +template +struct CommutingStrengths { + using Type = Eigen::SparseMatrix; + static Type get_default(Region size, AgeGroup) + { + return Type(static_cast((size_t)size), static_cast((size_t)size)); + } + static std::string name() + { + return "CommutingStrengths"; + } +}; + +/** + * @brief The Region%s that a person crosses when travelling from one Region to another. + */ +template +struct PopulationSizes { + using Type = CustomIndexArray; + static Type get_default(Region size, AgeGroup) + { + return Type(size, 0.); + } + static std::string name() + { + return "PopulationSizes"; + } +}; + +template +using ParametersBase = + ParameterSet, TimeExposed, TimeInfected, ContactPatterns, + ImpactTransmissionDuringCommuting, PathIntersections, CommutingStrengths, PopulationSizes>; + +/** + * @brief Parameters of SEIR model. + */ +template +class Parameters : public ParametersBase +{ +public: + Parameters(Region num_regions, AgeGroup num_agegroups) + : ParametersBase(num_regions, num_agegroups) + , m_num_regions{num_regions} + , m_num_agegroups(num_agegroups) + { + } + + Region get_num_regions() const + { + return m_num_regions; + } + + AgeGroup get_num_agegroups() const + { + return m_num_agegroups; + } + + /** + * @brief Checks whether all Parameters satisfy their corresponding constraints and applies them, if they do not. + * Time spans cannot be negative and probabilities can only take values between [0,1]. + * + * Attention: This function should be used with care. It is necessary for some test problems to run through quickly, + * but in a manual execution of an example, check_constraints() may be preferred. Note that the apply_constraints() + * function can and will not set Parameters to meaningful values in an epidemiological or virological context, + * as all models are designed to be transferable to multiple diseases. Consequently, only acceptable + * (like 0 or 1 for probabilities or small positive values for time spans) values are set here and a manual adaptation + * may often be necessary to have set meaningful values. + * + * @return Returns true if one ore more constraint were corrected, false otherwise. + */ + bool apply_constraints() + { + double tol_times = 1e-1; + + int corrected = false; + + for (auto i = AgeGroup(0); i < AgeGroup(m_num_agegroups); i++) { + if (this->template get>()[i] < tol_times) { + log_warning( + "Constraint check: Parameter TimeInfected changed from {:.4f} to {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->template get>()[i], tol_times); + this->template get>()[i] = tol_times; + corrected = true; + } + if (this->template get>()[i] < tol_times) { + log_warning( + "Constraint check: Parameter TimeInfected changed from {:.4f} to {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->template get>()[i], tol_times); + this->template get>()[i] = tol_times; + corrected = true; + } + if (this->template get>()[i] < 0.0 || + this->template get>()[i] > 1.0) { + log_warning( + "Constraint check: Parameter TransmissionProbabilityOnContact changed from {:0.4f} to {:d} ", + this->template get>()[i], 0.0); + this->template get>() = 0.0; + corrected = true; + } + } + if (this->template get>() < 0.0 || + this->template get>() > 1.0) { + log_warning("Constraint check: Parameter ImpactTransmissionDuringCommuting changed from {:.4f} to {:.4f}.", + this->template get>(), 0.0); + this->template get>() = 0.0; + corrected = true; + } + return corrected; + } + + /** + * @brief Checks whether all Parameters satisfy their corresponding constraints and logs an error + * if constraints are not satisfied. + * @return Returns true if one constraint is not satisfied, otherwise false. + */ + bool check_constraints() const + { + double tol_times = 1e-1; + + for (auto i = AgeGroup(0); i < AgeGroup(m_num_agegroups); i++) { + if (this->template get>()[i] < tol_times) { + log_error( + "Constraint check: Parameter TimeExposed {:.4f} smaller or equal {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->template get>()[i], 0.0); + return true; + } + if (this->template get>()[i] < tol_times) { + log_error( + "Constraint check: Parameter TimeInfected {:.4f} smaller or equal {:.4f}. Please note that " + "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " + "and reset parameters.", + this->template get>()[i], 0.0); + return true; + } + if (this->template get>()[i] < 0.0 || + this->template get>()[i] > 1.0) { + log_error("Constraint check: Parameter TransmissionProbabilityOnContact {:.4f} smaller {:.4f} or " + "greater {:.4f}", + this->template get>()[i], 0.0, 1.0); + return true; + } + } + if (this->template get>() < 0.0 || + this->template get>() > 1.0) { + log_error( + "Constraint check: Parameter ImpactTransmissionDuringCommuting {:.4f} smaller {:.4f} or greater {:.4f}", + this->template get>(), 0.0, 1.0); + return true; + } + return false; + } + +private: + // Parameters(ParametersBase&& base) + // : ParametersBase(std::move(base)) //TODO: Adjust + // { + // } + +public: + /** + * deserialize an object of this class. + * @see mio::deserialize + */ + template + static IOResult deserialize(IOContext& io) + { + BOOST_OUTCOME_TRY(auto&& base, ParametersBase::deserialize(io)); + return success(Parameters(std::move(base))); + } + +private: + Region m_num_regions; + AgeGroup m_num_agegroups; +}; + +} // namespace oseirmobilityimproved +} // namespace mio + +#endif // SEIR_PARAMETERS_H diff --git a/cpp/models/ode_seir_mobility_improved/regions.h b/cpp/models/ode_seir_mobility_improved/regions.h new file mode 100644 index 0000000000..f9feca907f --- /dev/null +++ b/cpp/models/ode_seir_mobility_improved/regions.h @@ -0,0 +1,26 @@ + +#ifndef ODESEIRMOBILITYIMPROVED_REGIONS_H +#define ODESEIRMOBILITYIMPROVED_REGIONS_H + +#include "memilio/utils/index.h" + +namespace mio +{ +namespace oseirmobilityimproved +{ + +/** + * @brief The AgeGroup struct is used as a dynamically + * sized tag for all age dependent categories + */ +struct Region : public Index { + Region(size_t val) + : Index(val) + { + } +}; + +} // namespace oseirmobilityimproved +} // namespace mio + +#endif From 23196bc7d2bd792da5f2ed23986857129bd3e184 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:52:56 +0200 Subject: [PATCH 16/87] changes for comparing simulations --- cpp/CMakeLists.txt | 2 ++ cpp/examples/CMakeLists.txt | 8 ++++++++ cpp/examples/graph.cpp | 4 ++-- cpp/examples/ode_seir_mobility.cpp | 13 +++++++------ 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index b832cabfab..ed4372290a 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -129,6 +129,8 @@ if(MEMILIO_BUILD_MODELS) add_subdirectory(models/ode_seair) add_subdirectory(models/ode_sir) add_subdirectory(models/ode_sir_mobility) + # add_subdirectory(models/ode_seir_mobility_massaction) + add_subdirectory(models/ode_seir_mobility_improved) add_subdirectory(models/ode_seir_mobility) add_subdirectory(models/sde_sir) add_subdirectory(models/sde_sirs) diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 6a12daf6ef..8dc1089d3a 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -38,6 +38,14 @@ add_executable(ode_seir_mobility_example ode_seir_mobility.cpp) target_link_libraries(ode_seir_mobility_example PRIVATE memilio ode_seir_mobility) target_compile_options(ode_seir_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +# add_executable(ode_seir_mobility_example_massaction ode_seir_mobility_massaction.cpp) +# target_link_libraries(ode_seir_mobility_example_massaction PRIVATE memilio ode_seir_mobility_massaction) +# target_compile_options(ode_seir_mobility_example_massaction PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + +add_executable(ode_seir_mobility_example_improved ode_seir_mobility_improved.cpp) +target_link_libraries(ode_seir_mobility_example_improved PRIVATE memilio ode_seir_mobility_improved) +target_compile_options(ode_seir_mobility_example_improved PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(sde_sirs_example sde_sirs.cpp) target_link_libraries(sde_sirs_example PRIVATE memilio sde_sirs) target_compile_options(sde_sirs_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index 3b8767a686..bf15588032 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -27,7 +27,7 @@ int main() { const auto t0 = 0.; - const auto tmax = 10.; + const auto tmax = 15.; const auto dt = 0.5; //time step of migration, daily migration every second step mio::oseir::Model<> model(1); @@ -61,7 +61,7 @@ int main() mio::Graph>>, mio::MigrationEdge<>> g; g.add_node(1001, model_group1, t0); g.add_node(1002, model_group2, t0); - g.add_edge(0, 1, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.01)); + g.add_edge(0, 1, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.05)); g.add_edge(1, 0, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.01)); auto sim = mio::make_migration_sim(t0, dt, std::move(g)); diff --git a/cpp/examples/ode_seir_mobility.cpp b/cpp/examples/ode_seir_mobility.cpp index cfba2c1e8f..d2e20185cf 100644 --- a/cpp/examples/ode_seir_mobility.cpp +++ b/cpp/examples/ode_seir_mobility.cpp @@ -79,8 +79,7 @@ mio::IOResult preprocess(const std::string& filename, mio::oseirmobility:: } std::sort(mobility_paths[i][j].begin(), mobility_paths[i][j].end()); std::vector intersection_int; - std::vector intersection_region(intersection_int.size(), - mio::oseirmobility::Region(0)); + std::vector intersection_region; for (size_t k = 0; k < n_regions; k++) { if (k == i || k == j) { continue; @@ -141,8 +140,8 @@ int main() mio::set_log_level(mio::LogLevel::debug); ScalarType t0 = 0.; - ScalarType tmax = 10.; - ScalarType dt = 1; + ScalarType tmax = 15.; + ScalarType dt = 0.5; std::vector region_ids = {1001, 1002}; ScalarType number_regions = region_ids.size(); @@ -163,6 +162,8 @@ int main() model.populations[{mio::oseirmobility::Region(1), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Susceptible}] = 10000; + // auto result_preprocess = set_mobility_weights(mobility_data, trip_chain_data, model, number_regions); + model.parameters.set>(1.); model.parameters.set>(3.); @@ -175,7 +176,7 @@ int main() // contact_matrix[0].add_damping(0.5, mio::SimulationTime(5)); model.parameters.get().push_back( - {mio::oseirmobility::Region(0), mio::oseirmobility::Region(1), 0.01}); + {mio::oseirmobility::Region(0), mio::oseirmobility::Region(1), 0.05}); model.parameters.get().push_back( {mio::oseirmobility::Region(1), mio::oseirmobility::Region(0), 0.01}); @@ -189,7 +190,7 @@ int main() auto result_from_sim = simulate(t0, tmax, dt, model, integrator); auto save_result_status = - mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result.h5"); + mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_standard.h5"); // bool print_to_terminal = true; From bfc2562ddcd7a433db92e291e5a95bf1aee9b675 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:00:00 +0200 Subject: [PATCH 17/87] adjust plot file --- tools/plot_results_mobilitymodels.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/plot_results_mobilitymodels.py b/tools/plot_results_mobilitymodels.py index 4eb997c724..47a853882b 100644 --- a/tools/plot_results_mobilitymodels.py +++ b/tools/plot_results_mobilitymodels.py @@ -11,7 +11,8 @@ color_dict = {0: '#1f77b4', 1:'#2ca02c' } -linestyle_dict = {"ODE": 'solid', +linestyle_dict = {"ODE SI": 'dashed', + "ODE Improved": 'dotted', "Graph": 'dashdot' } @@ -156,9 +157,11 @@ def plot_new_infections(files, ylim, legendplot, filename_plot="compare_new_infe if __name__ == '__main__': data_dir = os.path.join(os.path.dirname(__file__), "..", "cpp", "build") - plot_new_infections([os.path.join(data_dir, "ode_result"), + plot_new_infections([os.path.join(data_dir, "ode_result_standard"), + os.path.join(data_dir, "ode_result_improved"), os.path.join(data_dir, "graph_result")], - 2e3, legendplot=list(["ODE","Graph"])) - compare_all_compartments([os.path.join(data_dir, "ode_result"), + 2e3, legendplot=list(["ODE SI", "ODE Improved","Graph"])) + compare_all_compartments([os.path.join(data_dir, "ode_result_standard"), + os.path.join(data_dir, "ode_result_improved"), os.path.join(data_dir, "graph_result")], - legendplot=list(["ODE", "Graph"])) + legendplot=list(["ODE SI", "ODE Improved","Graph"])) From c6b56e965f7b0b98f49cbf78448ca614d0d3b010 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:21:37 +0200 Subject: [PATCH 18/87] reformat py file --- tools/plot_results_mobilitymodels.py | 126 +++++++++++++++++---------- 1 file changed, 81 insertions(+), 45 deletions(-) diff --git a/tools/plot_results_mobilitymodels.py b/tools/plot_results_mobilitymodels.py index 47a853882b..756454acd3 100644 --- a/tools/plot_results_mobilitymodels.py +++ b/tools/plot_results_mobilitymodels.py @@ -7,17 +7,22 @@ # Define compartments. secir_dict = {0: 'Susceptible', 1: 'Exposed', 2: 'Infected', 3: 'Recovered'} -# Define color and style to be used while plotting for different models to make plots consistent. +# Define color and style to be used while plotting for different models to +# make plots consistent. color_dict = {0: '#1f77b4', - 1:'#2ca02c' + 1: '#2ca02c' } linestyle_dict = {"ODE SI": 'dashed', "ODE Improved": 'dotted', "Graph": 'dashdot' } -def compare_all_compartments(files, legendplot, filename_plot="compare_compartments"): - + +def compare_all_compartments( + files, + legendplot, + filename_plot="compare_compartments"): + fig, axs = plt.subplots( 2, 2, sharex='all', num=filename_plot, tight_layout=False) @@ -32,55 +37,67 @@ def compare_all_compartments(files, legendplot, filename_plot="compare_compartme data = h5file[list(h5file.keys())[region]] dates = data['Time'][:] - number_regions = len(list(h5file[list(h5file.keys())[region]].keys())) - 2 + number_regions = len( + list(h5file[list(h5file.keys())[region]].keys())) - 2 for region in range(number_regions): - total = data['Group'+str(region+1)][:, :] + total = data['Group' + str(region + 1)][:, :] if (total.shape[1] != 4): - raise gd.DataError("Expected a different number of compartments.") + raise gd.DataError( + "Expected a different number of compartments.") # Plot result. if legendplot[file] in linestyle_dict: for i in range(4): - axs[int(i/2), i % 2].plot(dates, - total[:, i], label=legendplot[file] +" Region "+ str(region), linewidth=1.2, - linestyle=linestyle_dict[legendplot[file]], - color=color_dict[region]) + axs[int(i / 2), + i % 2].plot(dates, + total[:, + i], + label=legendplot[file] + " Region " + str(region), + linewidth=1.2, + linestyle=linestyle_dict[legendplot[file]], + color=color_dict[region]) else: for i in range(4): - axs[int(i/2), i % 2].plot(dates, - total[:, i], label=legendplot[file], linewidth=1.2) + axs[int(i / 2), i % 2].plot(dates, total[:, i], + label=legendplot[file], linewidth=1.2) else: data = h5file[list(h5file.keys())[region]] dates = data['Time'][:] - # As there should be only one Group, total is the simulation result. + # As there should be only one Group, total is the simulation + # result. total = data['Total'][:, :] if (total.shape[1] != 4): - raise gd.DataError("Expected a different number of compartments.") + raise gd.DataError( + "Expected a different number of compartments.") # Plot result. if legendplot[file] in linestyle_dict: for i in range(4): - axs[int(i/2), i % 2].plot(dates, - total[:, i], label=legendplot[file] +" Region "+ str(region), linewidth=1.2, - linestyle=linestyle_dict[legendplot[file]], - color=color_dict[region]) + axs[int(i / 2), + i % 2].plot(dates, + total[:, + i], + label=legendplot[file] + " Region " + str(region), + linewidth=1.2, + linestyle=linestyle_dict[legendplot[file]], + color=color_dict[region]) else: for i in range(4): - axs[int(i/2), i % 2].plot(dates, - total[:, i], label=legendplot[file], linewidth=1.2) + axs[int(i / 2), i % 2].plot(dates, total[:, i], + label=legendplot[file], linewidth=1.2) h5file.close() # Define some characteristics of the plot. for i in range(4): - axs[int(i/2), i % 2].set_title(secir_dict[i], fontsize=8) - axs[int(i/2), i % 2].set_xlim(left=0, right=dates[-1]) - axs[int(i/2), i % 2].grid(True, linestyle='--') - axs[int(i/2), i % 2].tick_params(axis='y', labelsize=7) - axs[int(i/2), i % 2].tick_params(axis='x', labelsize=7) + axs[int(i / 2), i % 2].set_title(secir_dict[i], fontsize=8) + axs[int(i / 2), i % 2].set_xlim(left=0, right=dates[-1]) + axs[int(i / 2), i % 2].grid(True, linestyle='--') + axs[int(i / 2), i % 2].tick_params(axis='y', labelsize=7) + axs[int(i / 2), i % 2].tick_params(axis='x', labelsize=7) # axs[int(i/2), i % 2].xaxis.set_ticks(np.arange(0, dates[-1]+1, 5)) fig.supxlabel('Time (in days)', fontsize=9) lines, labels = axs[0, 0].get_legend_handles_labels() - lgd = fig.legend(lines, labels, ncol=len(legendplot), loc='outside lower center', + lgd = fig.legend(lines, labels, ncol=len(legendplot), loc='outside lower center', fontsize=10, bbox_to_anchor=(0.5, - 0.06), bbox_transform=fig.transFigure) plt.tight_layout(pad=0, w_pad=0.5, h_pad=0.1) @@ -89,11 +106,15 @@ def compare_all_compartments(files, legendplot, filename_plot="compare_compartme # Save result. if not os.path.isdir('Plots'): os.makedirs('Plots') - fig.savefig('Plots/'+filename_plot+'.png', + fig.savefig('Plots/' + filename_plot + '.png', bbox_extra_artists=(lgd,), bbox_inches='tight', dpi=500) -def plot_new_infections(files, ylim, legendplot, filename_plot="compare_new_infections"): +def plot_new_infections( + files, + ylim, + legendplot, + filename_plot="compare_new_infections"): plt.figure(filename_plot) @@ -108,32 +129,42 @@ def plot_new_infections(files, ylim, legendplot, filename_plot="compare_new_infe data = h5file[list(h5file.keys())[region]] dates = data['Time'][:] - number_regions = len(list(h5file[list(h5file.keys())[region]].keys())) - 2 + number_regions = len( + list(h5file[list(h5file.keys())[region]].keys())) - 2 for region_ in range(number_regions): - total = data['Group'+str(region_+1)][:, :] + total = data['Group' + str(region_ + 1)][:, :] if (total.shape[1] != 4): raise gd.DataError( "Expected a different number of compartments.") - incidence = (total[:-1, 0]-total[1:, 0])/(dates[1:]-dates[:-1]) + incidence = (total[:-1, 0] - total[1:, 0] + ) / (dates[1:] - dates[:-1]) # Plot result. if legendplot[file] in linestyle_dict: - plt.plot(dates[1:], incidence, linewidth=1.2, - linestyle=linestyle_dict[legendplot[file]], color=color_dict[region_]) + plt.plot(dates[1:], + incidence, + linewidth=1.2, + linestyle=linestyle_dict[legendplot[file]], + color=color_dict[region_]) else: plt.plot(dates[1:], incidence, linewidth=1.2) - else: + else: data = h5file[list(h5file.keys())[region]] dates = data['Time'][:] - # As there should be only one Group, total is the simulation result. + # As there should be only one Group, total is the simulation + # result. total = data['Total'][:, :] if (total.shape[1] != 4): raise gd.DataError( "Expected a different number of compartments.") - incidence = (total[:-1, 0]-total[1:, 0])/(dates[1:]-dates[:-1]) + incidence = (total[:-1, 0] - total[1:, 0]) / \ + (dates[1:] - dates[:-1]) # Plot result. if legendplot[file] in linestyle_dict: - plt.plot(dates[1:], incidence, linewidth=1.2, - linestyle=linestyle_dict[legendplot[file]], color=color_dict[region]) + plt.plot(dates[1:], + incidence, + linewidth=1.2, + linestyle=linestyle_dict[legendplot[file]], + color=color_dict[region]) else: plt.plot(dates[1:], incidence, linewidth=1.2) @@ -152,16 +183,21 @@ def plot_new_infections(files, ylim, legendplot, filename_plot="compare_new_infe # Save result. if not os.path.isdir('Plots'): os.makedirs('Plots') - plt.savefig('Plots/'+filename_plot+'.png', bbox_inches='tight', dpi=500) + plt.savefig( + 'Plots/' + + filename_plot + + '.png', + bbox_inches='tight', + dpi=500) if __name__ == '__main__': data_dir = os.path.join(os.path.dirname(__file__), "..", "cpp", "build") plot_new_infections([os.path.join(data_dir, "ode_result_standard"), - os.path.join(data_dir, "ode_result_improved"), + os.path.join(data_dir, "ode_result_improved"), os.path.join(data_dir, "graph_result")], - 2e3, legendplot=list(["ODE SI", "ODE Improved","Graph"])) + 2e3, legendplot=list(["ODE SI", "ODE Improved", "Graph"])) compare_all_compartments([os.path.join(data_dir, "ode_result_standard"), - os.path.join(data_dir, "ode_result_improved"), - os.path.join(data_dir, "graph_result")], - legendplot=list(["ODE SI", "ODE Improved","Graph"])) + os.path.join(data_dir, "ode_result_improved"), + os.path.join(data_dir, "graph_result")], + legendplot=list(["ODE SI", "ODE Improved", "Graph"])) From 5e51d696b464ee5ebeea82f1b9dc049a7948842b Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:26:59 +0200 Subject: [PATCH 19/87] py file --- tools/plot_results_mobilitymodels.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/plot_results_mobilitymodels.py b/tools/plot_results_mobilitymodels.py index 756454acd3..5290c58c80 100644 --- a/tools/plot_results_mobilitymodels.py +++ b/tools/plot_results_mobilitymodels.py @@ -51,7 +51,8 @@ def compare_all_compartments( i % 2].plot(dates, total[:, i], - label=legendplot[file] + " Region " + str(region), + label=legendplot[file] + + " Region " + str(region), linewidth=1.2, linestyle=linestyle_dict[legendplot[file]], color=color_dict[region]) @@ -75,7 +76,8 @@ def compare_all_compartments( i % 2].plot(dates, total[:, i], - label=legendplot[file] + " Region " + str(region), + label=legendplot[file] + + " Region " + str(region), linewidth=1.2, linestyle=linestyle_dict[legendplot[file]], color=color_dict[region]) From 0eff4d157805acca1d042675429bb7b72a4f38b9 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:28:15 +0200 Subject: [PATCH 20/87] py file --- tools/plot_results_mobilitymodels.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/plot_results_mobilitymodels.py b/tools/plot_results_mobilitymodels.py index 5290c58c80..0426ca7747 100644 --- a/tools/plot_results_mobilitymodels.py +++ b/tools/plot_results_mobilitymodels.py @@ -51,7 +51,7 @@ def compare_all_compartments( i % 2].plot(dates, total[:, i], - label=legendplot[file] + + label=legendplot[file] + " Region " + str(region), linewidth=1.2, linestyle=linestyle_dict[legendplot[file]], @@ -76,7 +76,7 @@ def compare_all_compartments( i % 2].plot(dates, total[:, i], - label=legendplot[file] + + label=legendplot[file] + " Region " + str(region), linewidth=1.2, linestyle=linestyle_dict[legendplot[file]], From 3d3b0076df30c371f241936e58ef286b1e336b63 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:56:31 +0200 Subject: [PATCH 21/87] change commuting strengths to contact matrix and implement indicator function --- cpp/examples/graph.cpp | 2 +- cpp/examples/ode_seir_mobility_improved.cpp | 33 ++++++------- cpp/models/ode_seir_mobility_improved/model.h | 47 ++++++++++--------- .../ode_seir_mobility_improved/parameters.h | 8 ++-- 4 files changed, 46 insertions(+), 44 deletions(-) diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index b465a5b412..11c43fa4f4 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -28,7 +28,7 @@ int main() { const auto t0 = 0.; const auto tmax = 15.; - const auto dt = 0.5; //time step of migration, daily migration every second step + const auto dt = 0.5; //time step of mobility, daily mobility every second step mio::oseir::Model<> model(1); diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index 94a87f63ad..339a10ab9c 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -18,7 +18,7 @@ int main() ScalarType t0 = 0.; ScalarType tmax = 15.; - ScalarType dt = 1; + ScalarType dt = 0.5; std::vector region_ids = {1001, 1002}; ScalarType number_regions = region_ids.size(); @@ -48,31 +48,28 @@ int main() mio::ContactMatrixGroup& contact_matrix = model.parameters.get>().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(2.7); - // contact_matrix[0].add_damping(0.5, mio::SimulationTime(5)); - Eigen::SparseMatrix& commuting_strengths = - model.parameters.get>(); - commuting_strengths.insert(0, 0) = 0.95; - commuting_strengths.insert(0, 1) = 0.05; - commuting_strengths.insert(1, 0) = 0.01; - commuting_strengths.insert(1, 1) = 0.99; + mio::ContactMatrixGroup& commuting_strengths = + model.parameters.get>().get_cont_freq_mat(); + Eigen::MatrixXd values(2, 2); + values(0, 0) = 0.95; + values(0, 1) = 0.05; + values(1, 0) = 0.01; + values(1, 1) = 0.99; + commuting_strengths[0].get_baseline() = values; auto& population = model.parameters.get>(); - for (int n = 0; n < commuting_strengths.outerSize(); ++n) { + for (int n = 0; n < number_regions; ++n) { population[{mio::oseirmobilityimproved::Region(n)}] += model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); - auto x = population[{mio::oseirmobilityimproved::Region(0)}]; - mio::unused(x); - for (Eigen::SparseMatrix::InnerIterator it(commuting_strengths, n); it; ++it) { - auto start_population = model.populations.get_group_total(mio::oseirmobilityimproved::Region(it.row())); - population[{mio::oseirmobilityimproved::Region(it.row())}] -= it.value() * start_population; - x = population[{mio::oseirmobilityimproved::Region(0)}]; - population[{mio::oseirmobilityimproved::Region(it.col())}] += it.value() * start_population; - x = population[{mio::oseirmobilityimproved::Region(0)}]; + for (int m = 0; m < number_regions; ++m) { + population[{mio::oseirmobilityimproved::Region(n)}] -= + values(n, m) * model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); + population[{mio::oseirmobilityimproved::Region(m)}] += + values(n, m) * model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); } } - using DefaultIntegratorCore = mio::ControlledStepperWrapper; diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index 90dd9ab9ca..6ad066a626 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -39,41 +39,46 @@ class Model : public FlowModel> pop, Eigen::Ref> y, FP t, Eigen::Ref> flows) const override { - const auto& params = this->parameters; - const auto& population = this->populations; - const auto& commuting_strengths = params.template get>(); - + const auto& params = this->parameters; + const auto& population = this->populations; + const auto& commuting_strengths = + params.template get>().get_cont_freq_mat().get_matrix_at(t); const Index n_age_groups = reduce_index>(params.get_num_agegroups()); const Index n_regions = reduce_index>(params.get_num_regions()); - CustomIndexArray infectives_per_region(n_regions); for (auto age_i : make_index_range(n_age_groups)) { for (auto age_j : make_index_range(n_age_groups)) { - for (int n = 0; n < commuting_strengths.outerSize(); ++n) { - infectives_per_region[Region(n)] = - 0.5 * pop[population.get_flat_index({Region(n), age_j, InfectionState::Infected})] * - commuting_strengths.coeff(n, n); - for (Eigen::SparseMatrix::InnerIterator it(commuting_strengths, n); it; ++it) { - infectives_per_region[Region(n)] += - 0.5 * pop[population.get_flat_index({Region(it.row()), age_j, InfectionState::Infected})] * - it.value(); + Eigen::VectorXd infectives_per_region = Eigen::VectorXd::Zero((size_t)n_regions); + for (auto region_n : make_index_range(n_regions)) { + if (fmod(t, 1.) < 0.5) { // fmod = modulo for doubles + infectives_per_region(region_n.get()) = + commuting_strengths(region_n.get(), region_n.get()) * + pop[population.get_flat_index({region_n, age_j, InfectionState::Infected})]; + } + else { + for (auto region_m : make_index_range(n_regions)) { + infectives_per_region(region_n.get()) += + commuting_strengths(region_m.get(), region_n.get()) * + pop[population.get_flat_index({region_m, age_j, InfectionState::Infected})]; + } } } - double coeffStoI = params.template get>().get_cont_freq_mat().get_matrix_at(t)( - age_i.get(), age_j.get()) * - params.template get>()[age_i]; - for (int n = 0; n < commuting_strengths.outerSize(); ++n) { - for (Eigen::SparseMatrix::InnerIterator it(commuting_strengths, n); it; ++it) { + for (auto region_n : make_index_range(n_regions)) { + for (auto region_m : make_index_range(n_regions)) { flows[Base::template get_flat_flow_index( - {Region(it.row()), age_i})] += it.value() * infectives_per_region[Region(it.col())] / - params.template get>()[Region(it.col())]; + {region_n, age_i})] += commuting_strengths(region_n.get(), region_m.get()) * + infectives_per_region(region_m.get()) / + params.template get>()[region_m]; } } + + double coeffStoI = params.template get>().get_cont_freq_mat().get_matrix_at(t)( + age_i.get(), age_j.get()) * + params.template get>()[age_i]; for (auto region : make_index_range(n_regions)) { flows[Base::template get_flat_flow_index( {region, age_i})] *= diff --git a/cpp/models/ode_seir_mobility_improved/parameters.h b/cpp/models/ode_seir_mobility_improved/parameters.h index 817881108d..05ac04ae5d 100644 --- a/cpp/models/ode_seir_mobility_improved/parameters.h +++ b/cpp/models/ode_seir_mobility_improved/parameters.h @@ -117,14 +117,14 @@ struct PathIntersections { }; /** - * @brief The commuting weights are modelled using a SparseMatrix. - */ + * @brief The contact patterns within different Region%s are modelled using a ContactMatrix. + */ template struct CommutingStrengths { - using Type = Eigen::SparseMatrix; + using Type = UncertainContactMatrix; static Type get_default(Region size, AgeGroup) { - return Type(static_cast((size_t)size), static_cast((size_t)size)); + return Type(1, static_cast((size_t)size)); } static std::string name() { From 9f0fba713a639d095da9f5b71695d390e44e170c Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:39:43 +0200 Subject: [PATCH 22/87] return to factor 0.5 --- cpp/examples/ode_seir_mobility_improved.cpp | 12 ++++++------ cpp/models/ode_seir_mobility_improved/model.h | 15 ++++----------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index 339a10ab9c..a550219562 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -53,10 +53,10 @@ int main() mio::ContactMatrixGroup& commuting_strengths = model.parameters.get>().get_cont_freq_mat(); Eigen::MatrixXd values(2, 2); - values(0, 0) = 0.95; - values(0, 1) = 0.05; - values(1, 0) = 0.01; - values(1, 1) = 0.99; + values(0, 0) = 0.975; + values(0, 1) = 0.025; + values(1, 0) = 0.005; + values(1, 1) = 0.995; commuting_strengths[0].get_baseline() = values; auto& population = model.parameters.get>(); @@ -79,8 +79,8 @@ int main() auto result_from_sim = simulate(t0, tmax, dt, model, integrator); - auto save_result_status = - mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_improved.h5"); + auto save_result_status = mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, + "ode_result_improved_factor.h5"); // bool print_to_terminal = true; diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index 6ad066a626..8b07be34d2 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -54,17 +54,10 @@ class Model : public FlowModel Date: Tue, 8 Oct 2024 11:46:21 +0200 Subject: [PATCH 23/87] read in data and time measurement 400 counties --- cpp/examples/ode_seir_mobility_improved.cpp | 82 +++++++++++++++------ 1 file changed, 58 insertions(+), 24 deletions(-) diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index a550219562..2e070998d7 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -10,7 +10,36 @@ #include "models/ode_seir_mobility_improved/regions.h" #include "memilio/io/io.h" #include "memilio/io/result_io.h" -#include "Eigen/Sparse" + +#include + +template +mio::IOResult set_mobility_weights(const std::string& mobility_data, mio::oseirmobilityimproved::Model& model, + size_t number_regions) +{ + // mobility between nodes + BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, + mio::read_mobility_plain(mobility_data + "mobility/" + "commuter_migration_scaled.txt")); + if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || + mobility_data_commuter.cols() != Eigen::Index(number_regions)) { + return mio::failure(mio::StatusCode::InvalidValue, + "Mobility matrices do not have the correct size. You may need to run " + "transformMobilitydata.py from pycode memilio epidata package."); + } + + for (auto age = mio::AgeGroup(0); age < model.parameters.get_num_agegroups(); age++) { + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + auto population_i = model.populations.get_group_total(mio::oseirmobilityimproved::Region(county_idx_i)); + mobility_data_commuter.row(county_idx_i) /= 2 * population_i; + mobility_data_commuter(county_idx_i, county_idx_i) = + 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); + } + model.parameters.template get>() + .get_cont_freq_mat()[0] + .get_baseline() = mobility_data_commuter; + } + return mio::success(); +} int main() { @@ -20,24 +49,25 @@ int main() ScalarType tmax = 15.; ScalarType dt = 0.5; - std::vector region_ids = {1001, 1002}; - ScalarType number_regions = region_ids.size(); + // std::vector region_ids = {1001, 1002}; + ScalarType number_regions = 400; ScalarType number_age_groups = 1; mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& mobility_data = ""; - const std::string& trip_chain_data = ""; + const std::string& mobility_data = ""; mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Exposed}] = 10; + mio::oseirmobilityimproved::InfectionState::Exposed}] = 100; model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 9990; - model.populations[{mio::oseirmobilityimproved::Region(1), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; - model.populations[{mio::oseirmobilityimproved::Region(1), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 99900; + for (int i = 1; i < number_regions; i++) { + model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; + model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 100000; + } model.parameters.set>(1.); @@ -50,14 +80,9 @@ int main() contact_matrix[0].get_baseline().setConstant(2.7); // contact_matrix[0].add_damping(0.5, mio::SimulationTime(5)); + auto result_preprocess = set_mobility_weights(mobility_data, model, number_regions); mio::ContactMatrixGroup& commuting_strengths = model.parameters.get>().get_cont_freq_mat(); - Eigen::MatrixXd values(2, 2); - values(0, 0) = 0.975; - values(0, 1) = 0.025; - values(1, 0) = 0.005; - values(1, 1) = 0.995; - commuting_strengths[0].get_baseline() = values; auto& population = model.parameters.get>(); for (int n = 0; n < number_regions; ++n) { @@ -65,22 +90,31 @@ int main() model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); for (int m = 0; m < number_regions; ++m) { population[{mio::oseirmobilityimproved::Region(n)}] -= - values(n, m) * model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); + commuting_strengths[0].get_baseline()(n, m) * + model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); population[{mio::oseirmobilityimproved::Region(m)}] += - values(n, m) * model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); + commuting_strengths[0].get_baseline()(n, m) * + model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); } } - using DefaultIntegratorCore = - mio::ControlledStepperWrapper; + // using DefaultIntegratorCore = + // mio::ControlledStepperWrapper; - std::shared_ptr> integrator = std::make_shared(); + std::shared_ptr> integrator = std::make_shared>(); model.check_constraints(); + printf("Start Simulation\n"); + auto t1 = std::chrono::high_resolution_clock::now(); auto result_from_sim = simulate(t0, tmax, dt, model, integrator); + auto t2 = std::chrono::high_resolution_clock::now(); + + std::chrono::duration ms_double = t2 - t1; + + printf("Runtime: %f\n", ms_double.count()); - auto save_result_status = mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, - "ode_result_improved_factor.h5"); + // auto save_result_status = + // mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_test.h5"); // bool print_to_terminal = true; From 06950d962e009a815c21fd7097014b36b6c5a9d1 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:19:47 +0200 Subject: [PATCH 24/87] small corrections model --- cpp/examples/ode_seir_mobility_improved.cpp | 14 ++++++-------- cpp/models/ode_seir_mobility_improved/model.h | 7 +++++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index 2e070998d7..06bd82ef49 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -19,7 +19,7 @@ mio::IOResult set_mobility_weights(const std::string& mobility_data, mio:: { // mobility between nodes BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, - mio::read_mobility_plain(mobility_data + "mobility/" + "commuter_migration_scaled.txt")); + mio::read_mobility_plain(mobility_data + "/mobility" + "/commuter_migration_test.txt")); if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || mobility_data_commuter.cols() != Eigen::Index(number_regions)) { return mio::failure(mio::StatusCode::InvalidValue, @@ -55,7 +55,7 @@ int main() mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& mobility_data = ""; + const std::string& mobility_data = "/home/gers_ca/code/memilio/data"; mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), @@ -86,15 +86,13 @@ int main() auto& population = model.parameters.get>(); for (int n = 0; n < number_regions; ++n) { - population[{mio::oseirmobilityimproved::Region(n)}] += - model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); + auto population_n = model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); + population[{mio::oseirmobilityimproved::Region(n)}] += population_n; for (int m = 0; m < number_regions; ++m) { population[{mio::oseirmobilityimproved::Region(n)}] -= - commuting_strengths[0].get_baseline()(n, m) * - model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); + 2 * commuting_strengths[0].get_baseline()(n, m) * population_n; population[{mio::oseirmobilityimproved::Region(m)}] += - commuting_strengths[0].get_baseline()(n, m) * - model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); + 2 * commuting_strengths[0].get_baseline()(n, m) * population_n; } } // using DefaultIntegratorCore = diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index 8b07be34d2..cbe06a9fbb 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -49,7 +49,6 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t); const Index n_age_groups = reduce_index>(params.get_num_agegroups()); const Index n_regions = reduce_index>(params.get_num_regions()); - for (auto age_i : make_index_range(n_age_groups)) { for (auto age_j : make_index_range(n_age_groups)) { Eigen::VectorXd infectives_per_region = Eigen::VectorXd::Zero((size_t)n_regions); @@ -61,9 +60,13 @@ class Model : public FlowModel( + {region_n, age_i})] += 0.5 * commuting_strengths(region_n.get(), region_n.get()) * + infectives_per_region(region_n.get()) / + params.template get>()[region_n]; for (auto region_m : make_index_range(n_regions)) { flows[Base::template get_flat_flow_index( - {region_n, age_i})] += commuting_strengths(region_n.get(), region_m.get()) * + {region_n, age_i})] += 0.5 * commuting_strengths(region_n.get(), region_m.get()) * infectives_per_region(region_m.get()) / params.template get>()[region_m]; } From aad78a91cd1ef5a45351b7f08f198319061b4931 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:06:54 +0200 Subject: [PATCH 25/87] corrections again --- cpp/examples/ode_seir_mobility_improved.cpp | 4 ++-- cpp/models/ode_seir_mobility_improved/model.h | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index 06bd82ef49..aea5d08376 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -90,9 +90,9 @@ int main() population[{mio::oseirmobilityimproved::Region(n)}] += population_n; for (int m = 0; m < number_regions; ++m) { population[{mio::oseirmobilityimproved::Region(n)}] -= - 2 * commuting_strengths[0].get_baseline()(n, m) * population_n; + commuting_strengths[0].get_baseline()(n, m) * population_n; population[{mio::oseirmobilityimproved::Region(m)}] += - 2 * commuting_strengths[0].get_baseline()(n, m) * population_n; + commuting_strengths[0].get_baseline()(n, m) * population_n; } } // using DefaultIntegratorCore = diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index cbe06a9fbb..e4af53aeac 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -60,13 +60,9 @@ class Model : public FlowModel( - {region_n, age_i})] += 0.5 * commuting_strengths(region_n.get(), region_n.get()) * - infectives_per_region(region_n.get()) / - params.template get>()[region_n]; for (auto region_m : make_index_range(n_regions)) { flows[Base::template get_flat_flow_index( - {region_n, age_i})] += 0.5 * commuting_strengths(region_n.get(), region_m.get()) * + {region_n, age_i})] += commuting_strengths(region_n.get(), region_m.get()) * infectives_per_region(region_m.get()) / params.template get>()[region_m]; } From 2bdb791477726b7d5410421fd1e80a18edb48898 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:07:15 +0200 Subject: [PATCH 26/87] change integrator in graph model --- cpp/examples/graph.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index 11c43fa4f4..65e913b1ed 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -61,6 +61,10 @@ int main() mio::Graph>>, mio::MobilityEdge<>> g; g.add_node(1001, model_group1, t0); g.add_node(1002, model_group2, t0); + for (auto& node : g.nodes()) { + node.property.get_simulation().set_integrator(std::make_shared>()); + node.property.get_simulation().get_dt() = dt; + } g.add_edge(0, 1, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.05)); g.add_edge(1, 0, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.01)); From 3c6f6306d348298f938b23a9496bfb56fb183401 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 7 Nov 2024 20:18:30 +0100 Subject: [PATCH 27/87] fix bug with age groups and discard transmissions during commuting --- cpp/models/ode_seir_mobility_improved/model.h | 50 ++++++++++------- .../ode_seir_mobility_improved/parameters.h | 54 ++----------------- .../ode_seir_mobility_improved/regions.h | 4 +- 3 files changed, 38 insertions(+), 70 deletions(-) diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index e4af53aeac..3353e5c2e7 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -37,6 +37,8 @@ class Model : public FlowModel({Region(num_regions), AgeGroup(num_agegroups)})) { } @@ -60,31 +62,43 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t)( + age_i.get(), age_j.get()) * + params.template get>()[age_i]; + + flow_SE_helper += + pop[population.get_flat_index({region_n, age_j, InfectionState::Infected})] * Nj_inv; for (auto region_m : make_index_range(n_regions)) { - flows[Base::template get_flat_flow_index( - {region_n, age_i})] += commuting_strengths(region_n.get(), region_m.get()) * - infectives_per_region(region_m.get()) / - params.template get>()[region_m]; + flow_SE_helper += commuting_strengths(region_n.get(), region_m.get()) * + infectives_per_region(region_m.get()) / + m_population_after_commuting[{region_n, age_j}]; } - } - - double coeffStoI = params.template get>().get_cont_freq_mat().get_matrix_at(t)( - age_i.get(), age_j.get()) * - params.template get>()[age_i]; - for (auto region : make_index_range(n_regions)) { flows[Base::template get_flat_flow_index( - {region, age_i})] *= - coeffStoI * y[population.get_flat_index({region, age_j, InfectionState::Susceptible})]; - flows[Base::template get_flat_flow_index( - {region, age_i})] = (1.0 / params.template get>()[age_i]) * - y[population.get_flat_index({region, age_i, InfectionState::Exposed})]; - flows[Base::template get_flat_flow_index( - {region, age_i})] = (1.0 / params.template get>()[age_i]) * - y[population.get_flat_index({region, age_i, InfectionState::Infected})]; + {region_n, age_i})] += + flow_SE_helper * coeffStoI * + y[population.get_flat_index({region_n, age_j, InfectionState::Susceptible})]; } } + for (auto region : make_index_range(n_regions)) { + flows[Base::template get_flat_flow_index( + {region, age_i})] = (1.0 / params.template get>()[age_i]) * + y[population.get_flat_index({region, age_i, InfectionState::Exposed})]; + flows[Base::template get_flat_flow_index( + {region, age_i})] = (1.0 / params.template get>()[age_i]) * + y[population.get_flat_index({region, age_i, InfectionState::Infected})]; + } } } + + mio::Populations m_population_after_commuting; }; // namespace oseirmobilityimproved } // namespace oseirmobilityimproved diff --git a/cpp/models/ode_seir_mobility_improved/parameters.h b/cpp/models/ode_seir_mobility_improved/parameters.h index 05ac04ae5d..49c548207f 100644 --- a/cpp/models/ode_seir_mobility_improved/parameters.h +++ b/cpp/models/ode_seir_mobility_improved/parameters.h @@ -86,38 +86,7 @@ struct ContactPatterns { }; /** - * @brief The ratio that regulates the infections during commuting. -*/ -template -struct ImpactTransmissionDuringCommuting { - using Type = UncertainValue; - static Type get_default(Region, AgeGroup) - { - return Type(0.); - } - static std::string name() - { - return "ImpactTransmissionDuringCommuting"; - } -}; - -/** - * @brief The Region%s that a person crosses when travelling from one Region to another. -*/ -struct PathIntersections { - using Type = CustomIndexArray, Region, Region>; - static Type get_default(Region, AgeGroup) - { - return Type({Region(0), Region(0)}); - } - static std::string name() - { - return "PathIntersections"; - } -}; - -/** - * @brief The contact patterns within different Region%s are modelled using a ContactMatrix. + * @brief The contact patterns between different Region%s are modelled using a ContactMatrix. */ template struct CommutingStrengths { @@ -133,7 +102,7 @@ struct CommutingStrengths { }; /** - * @brief The Region%s that a person crosses when travelling from one Region to another. + * @brief The sizes of the populations after commuting. */ template struct PopulationSizes { @@ -149,9 +118,8 @@ struct PopulationSizes { }; template -using ParametersBase = - ParameterSet, TimeExposed, TimeInfected, ContactPatterns, - ImpactTransmissionDuringCommuting, PathIntersections, CommutingStrengths, PopulationSizes>; +using ParametersBase = ParameterSet, TimeExposed, TimeInfected, + ContactPatterns, CommutingStrengths, PopulationSizes>; /** * @brief Parameters of SEIR model. @@ -224,13 +192,6 @@ class Parameters : public ParametersBase corrected = true; } } - if (this->template get>() < 0.0 || - this->template get>() > 1.0) { - log_warning("Constraint check: Parameter ImpactTransmissionDuringCommuting changed from {:.4f} to {:.4f}.", - this->template get>(), 0.0); - this->template get>() = 0.0; - corrected = true; - } return corrected; } @@ -268,13 +229,6 @@ class Parameters : public ParametersBase return true; } } - if (this->template get>() < 0.0 || - this->template get>() > 1.0) { - log_error( - "Constraint check: Parameter ImpactTransmissionDuringCommuting {:.4f} smaller {:.4f} or greater {:.4f}", - this->template get>(), 0.0, 1.0); - return true; - } return false; } diff --git a/cpp/models/ode_seir_mobility_improved/regions.h b/cpp/models/ode_seir_mobility_improved/regions.h index f9feca907f..d5f7657138 100644 --- a/cpp/models/ode_seir_mobility_improved/regions.h +++ b/cpp/models/ode_seir_mobility_improved/regions.h @@ -10,8 +10,8 @@ namespace oseirmobilityimproved { /** - * @brief The AgeGroup struct is used as a dynamically - * sized tag for all age dependent categories + * @brief The Region struct is used as a dynamically + * sized tag for all region dependent categories */ struct Region : public Index { Region(size_t val) From aa6b393a1380456441c475c760002dc84d51c069 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 7 Nov 2024 21:56:39 +0100 Subject: [PATCH 28/87] adapt structure of old model --- cpp/examples/ode_seir_mobility.cpp | 146 ++++------------------ cpp/models/ode_seir_mobility/model.h | 72 ++++------- cpp/models/ode_seir_mobility/parameters.h | 89 ++----------- 3 files changed, 53 insertions(+), 254 deletions(-) diff --git a/cpp/examples/ode_seir_mobility.cpp b/cpp/examples/ode_seir_mobility.cpp index d2e20185cf..7fe6903d1d 100644 --- a/cpp/examples/ode_seir_mobility.cpp +++ b/cpp/examples/ode_seir_mobility.cpp @@ -11,106 +11,13 @@ #include "memilio/io/io.h" #include "memilio/io/result_io.h" -mio::IOResult>>> read_path_mobility(const std::string& filename) -{ - BOOST_OUTCOME_TRY(auto&& num_lines, mio::count_lines(filename)); - - if (num_lines == 0) { - std::vector>> arr(0, std::vector>(0)); - return mio::success(arr); - } - - std::fstream file; - file.open(filename, std::ios::in); - if (!file.is_open()) { - return failure(mio::StatusCode::FileNotFound, filename); - } - - std::vector>> arr(std::sqrt(num_lines), - std::vector>(std::sqrt(num_lines))); - - try { - std::string tp; - while (getline(file, tp)) { - auto line = mio::split(tp, ' '); - int indx_x = std::stoi(line[0]); - int indx_y = std::stoi(line[1]); - if (indx_x != indx_y) { - auto path = std::accumulate(line.begin() + 2, line.end(), std::string("")); - - // string -> vector of integers - std::vector path_vec; - - // Remove the square brackets and \r - path = path.substr(1, path.size() - 3); - std::stringstream ss(path); - std::string token; - - // get numbers and save them in path_vec - while (std::getline(ss, token, ',')) { - path_vec.push_back(std::stoi(token)); - } - - // Sorted by end location - for (int number : path_vec) { - if (number != indx_x && number != indx_y) { - arr[indx_x][indx_y].push_back(number); - } - } - } - } - } - catch (std::runtime_error& ex) { - return failure(mio::StatusCode::InvalidFileFormat, filename + ": " + ex.what()); - } - - return mio::success(arr); -} - -template -mio::IOResult preprocess(const std::string& filename, mio::oseirmobility::Model& model) -{ - BOOST_OUTCOME_TRY(auto&& mobility_paths, read_path_mobility(filename)); - size_t n_regions = (size_t)model.parameters.get_num_regions(); - for (size_t i = 0; i < n_regions; i++) { - for (size_t j = 0; j < n_regions; j++) { - if (j == i) { - continue; - } - std::sort(mobility_paths[i][j].begin(), mobility_paths[i][j].end()); - std::vector intersection_int; - std::vector intersection_region; - for (size_t k = 0; k < n_regions; k++) { - if (k == i || k == j) { - continue; - } - std::sort(mobility_paths[k][j].begin(), mobility_paths[k][j].end()); - std::set_intersection(mobility_paths[i][j].begin(), mobility_paths[i][j].end(), - mobility_paths[k][j].begin(), mobility_paths[k][j].end(), - std::back_inserter(intersection_int)); - - if (intersection_int.begin() != intersection_int.end()) { - intersection_region.push_back(mio::oseirmobility::Region(k)); - intersection_int.pop_back(); - } - } - if (intersection_region.begin() != intersection_region.end()) { - model.parameters.template get()[{ - mio::oseirmobility::Region(i), mio::oseirmobility::Region(j)}] = intersection_region; - } - } - } - return mio::success(); -} - template -mio::IOResult set_mobility_weights(const std::string& mobility_data, const std::string& trip_chains, - mio::oseirmobility::Model& model, size_t number_regions) +mio::IOResult set_mobility_weights(const std::string& mobility_data, mio::oseirmobility::Model& model, + size_t number_regions) { - BOOST_OUTCOME_TRY(preprocess(trip_chains, model)); // mobility between nodes BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, - mio::read_mobility_plain(mobility_data + "mobility" + "commuter_migration_scaled.txt")); + mio::read_mobility_plain(mobility_data + "/mobility" + "/commuter_migration_test.txt")); if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || mobility_data_commuter.cols() != Eigen::Index(number_regions)) { return mio::failure(mio::StatusCode::InvalidValue, @@ -118,20 +25,13 @@ mio::IOResult set_mobility_weights(const std::string& mobility_data, const "transformMobilitydata.py from pycode memilio epidata package."); } - for (auto age = mio::AgeGroup(0); age < model.parameters.get_num_agegroups(); age++) { - for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { - for (size_t county_idx_j = 0; county_idx_j < number_regions; ++county_idx_j) { - //commuters - auto population_i = model.populations.get_group_total(mio::oseirmobility::Region(county_idx_i)); - auto commuter_coeff_ij = mobility_data_commuter(county_idx_i, county_idx_j) / population_i; - if (commuter_coeff_ij > 4e-5) { - model.parameters.template get().push_back( - {mio::oseirmobility::Region(county_idx_i), mio::oseirmobility::Region(county_idx_j), - commuter_coeff_ij}); - } - } - } + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + auto population_i = model.populations.get_group_total(mio::oseirmobility::Region(county_idx_i)); + mobility_data_commuter.row(county_idx_i) /= population_i; } + model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = + mobility_data_commuter; + return mio::success(); } @@ -141,44 +41,40 @@ int main() ScalarType t0 = 0.; ScalarType tmax = 15.; - ScalarType dt = 0.5; + ScalarType dt = 0.1; - std::vector region_ids = {1001, 1002}; - ScalarType number_regions = region_ids.size(); + ScalarType number_regions = 2; + std::vector region_ids(number_regions); + iota(region_ids.begin(), region_ids.end(), 1); ScalarType number_age_groups = 1; mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& mobility_data = ""; - const std::string& trip_chain_data = ""; + const std::string& mobility_data = ""; mio::oseirmobility::Model model(number_regions, number_age_groups); model.populations[{mio::oseirmobility::Region(0), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Exposed}] = 10; model.populations[{mio::oseirmobility::Region(0), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Susceptible}] = 9990; - model.populations[{mio::oseirmobility::Region(1), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Exposed}] = - 0; - model.populations[{mio::oseirmobility::Region(1), mio::AgeGroup(0), - mio::oseirmobility::InfectionState::Susceptible}] = 10000; - - // auto result_preprocess = set_mobility_weights(mobility_data, trip_chain_data, model, number_regions); + for (int i = 1; i < number_regions; i++) { + model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), + mio::oseirmobility::InfectionState::Exposed}] = 0; + model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), + mio::oseirmobility::InfectionState::Susceptible}] = 10000; + } model.parameters.set>(1.); model.parameters.set>(3.); model.parameters.set>(5.); - model.parameters.set>(0.); mio::ContactMatrixGroup& contact_matrix = model.parameters.get>().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(2.7); // contact_matrix[0].add_damping(0.5, mio::SimulationTime(5)); - model.parameters.get().push_back( - {mio::oseirmobility::Region(0), mio::oseirmobility::Region(1), 0.05}); - model.parameters.get().push_back( - {mio::oseirmobility::Region(1), mio::oseirmobility::Region(0), 0.01}); + auto result_preprocess = set_mobility_weights(mobility_data, model, number_regions); using DefaultIntegratorCore = mio::ControlledStepperWrapper; diff --git a/cpp/models/ode_seir_mobility/model.h b/cpp/models/ode_seir_mobility/model.h index c99eb732c9..3bc20c567d 100644 --- a/cpp/models/ode_seir_mobility/model.h +++ b/cpp/models/ode_seir_mobility/model.h @@ -46,64 +46,42 @@ class Model : public FlowModelparameters; const auto& population = this->populations; - + const auto& commuting_strengths = + params.template get>().get_cont_freq_mat().get_matrix_at(t); const Index n_age_groups = reduce_index>(params.get_num_agegroups()); const Index n_regions = reduce_index>(params.get_num_regions()); for (auto age_i : make_index_range(n_age_groups)) { for (auto age_j : make_index_range(n_age_groups)) { - for (auto edge : params.template get()) { - auto start_region = get<0>(edge); - auto end_region = get<1>(edge); - auto strength = get(edge); - if (start_region == end_region) { - continue; - } - // s_n += h_mn/P_m * i_m - flows[Base::template get_flat_flow_index( - {start_region, age_i})] += - strength * pop[population.get_flat_index({end_region, age_j, InfectionState::Infected})]; - // s_m += h_mn/P_m * i_n - flows[Base::template get_flat_flow_index( - {end_region, age_i})] += - strength * pop[population.get_flat_index({start_region, age_j, InfectionState::Infected})]; - - // s_n += gamma * h_nm/P_n * sum(h_km/P_k * p_nm,k * i_k) - for (auto edge_commuter : params.template get()) { - auto start_region_commuter = get<0>(edge_commuter); - auto end_region_commuter = get<1>(edge_commuter); - auto strength_commuter = get(edge_commuter); - if (end_region_commuter != end_region || start_region_commuter == start_region || - ((std::find(params.template get()[{start_region, end_region}].begin(), - params.template get()[{start_region, end_region}].end(), - start_region_commuter)) == - params.template get()[{start_region, end_region}].end())) { + for (auto region_n : make_index_range(n_regions)) { + FP flow_SE_helper = 0; + const size_t Sj = population.get_flat_index({region_n, age_j, InfectionState::Susceptible}); + const size_t Ej = population.get_flat_index({region_n, age_j, InfectionState::Exposed}); + const size_t Ij = population.get_flat_index({region_n, age_j, InfectionState::Infected}); + const size_t Rj = population.get_flat_index({region_n, age_j, InfectionState::Recovered}); + + const double Nj_inv = 1.0 / (pop[Sj] + pop[Ej] + pop[Ij] + pop[Rj]); + + double coeffStoI = params.template get>().get_cont_freq_mat().get_matrix_at(t)( + age_i.get(), age_j.get()) * + params.template get>()[age_i] * Nj_inv; + + for (auto region_m : make_index_range(n_regions)) { + if (region_n == region_m) { + flow_SE_helper += + pop[population.get_flat_index({region_n, age_j, InfectionState::Infected})]; continue; } - flows[Base::template get_flat_flow_index( - {start_region, age_i})] += - params.template get>() * strength * - strength_commuter * - pop[population.get_flat_index({start_region_commuter, age_j, InfectionState::Infected})]; + flow_SE_helper += (commuting_strengths(region_n.get(), region_m.get()) + + commuting_strengths(region_m.get(), region_n.get())) * + pop[population.get_flat_index({region_m, age_j, InfectionState::Infected})]; } - } - for (auto region : make_index_range(n_regions)) { - auto const population_region = population.template slice({(size_t)region, 1}); - auto const population_region_age = population_region.template slice({(size_t)age_j, 1}); - double population_size = - std::accumulate(population_region_age.begin(), population_region_age.end(), 0.); - double coeffStoI = - params.template get>().get_cont_freq_mat().get_matrix_at(t)(age_i.get(), - age_j.get()) * - params.template get>()[age_i] / population_size; - flows[Base::template get_flat_flow_index( - {region, age_i})] += pop[population.get_flat_index({region, age_j, InfectionState::Infected})]; flows[Base::template get_flat_flow_index( - {region, age_i})] *= - coeffStoI * y[population.get_flat_index({region, age_j, InfectionState::Susceptible})]; + {region_n, age_i})] += + flow_SE_helper * coeffStoI * + y[population.get_flat_index({region_n, age_j, InfectionState::Susceptible})]; } } - for (auto region : make_index_range(n_regions)) { flows[Base::template get_flat_flow_index( {region, age_i})] = (1.0 / params.template get>()[age_i]) * diff --git a/cpp/models/ode_seir_mobility/parameters.h b/cpp/models/ode_seir_mobility/parameters.h index 0b27284c9d..ca6fd99f1f 100644 --- a/cpp/models/ode_seir_mobility/parameters.h +++ b/cpp/models/ode_seir_mobility/parameters.h @@ -85,55 +85,24 @@ struct ContactPatterns { }; /** - * @brief The mean number of people migrating from one Region to another during a TimeStep. + * @brief The contact patterns between different Region%s are modelled using a ContactMatrix. */ -struct CommutingRatio { - using Type = std::vector>; - static Type get_default(Region, AgeGroup) - { - return Type({{Region(0), Region(0), 0.}}); - } - static std::string name() - { - return "CommutingRatio"; - } -}; - -/** - * @brief The ratio that regulates the infections during commuting. -*/ template -struct ImpactTransmissionDuringCommuting { - using Type = UncertainValue; - static Type get_default(Region, AgeGroup) - { - return Type(0.); - } - static std::string name() - { - return "ImpactTransmissionDuringCommuting"; - } -}; - -/** - * @brief The Region%s that a person crosses when travelling from one Region to another. -*/ -struct PathIntersections { - using Type = CustomIndexArray, Region, Region>; +struct CommutingStrengths { + using Type = UncertainContactMatrix; static Type get_default(Region size, AgeGroup) { - return Type({size, size}); + return Type(1, static_cast((size_t)size)); } static std::string name() { - return "PathIntersections"; + return "CommutingStrengths"; } }; template -using ParametersBase = - ParameterSet, TimeExposed, TimeInfected, ContactPatterns, - CommutingRatio, ImpactTransmissionDuringCommuting, PathIntersections>; +using ParametersBase = ParameterSet, TimeExposed, TimeInfected, + ContactPatterns, CommutingStrengths>; /** * @brief Parameters of SEIR model. @@ -206,30 +175,6 @@ class Parameters : public ParametersBase corrected = true; } } - if (this->template get>() < 0.0 || - this->template get>() > 1.0) { - log_warning("Constraint check: Parameter ImpactTransmissionDuringCommuting changed from {:.4f} to {:.4f}.", - this->template get>(), 0.0); - this->template get>() = 0.0; - corrected = true; - } - for (auto& i : this->template get()) { - if (std::get(i) < 0.0 || std::get(i) > 1.0) { - log_warning("Constraint check: Parameter CommutingRatio changed from {:.4f} to {:.4f}.", - std::get(i), 0.0); - std::get(i) = 0.0; - corrected = true; - } - if (std::get<0>(i) < Region(0) || std::get<1>(i) < Region(0) || std::get<0>(i) >= m_num_regions || - std::get<1>(i) >= m_num_regions) { - log_warning( - "Constraint check: Removed entry of Parameter CommutingRatio because of non-existing Regions."); - auto it = std::find(this->template get().begin(), - this->template get().end(), i); - this->template get().erase(it); - corrected = true; - } - } return corrected; } @@ -267,26 +212,6 @@ class Parameters : public ParametersBase return true; } } - if (this->template get>() < 0.0 || - this->template get>() > 1.0) { - log_error( - "Constraint check: Parameter ImpactTransmissionDuringCommuting {:.4f} smaller {:.4f} or greater {:.4f}", - this->template get>(), 0.0, 1.0); - return true; - } - for (auto i : this->template get()) { - if (std::get(i) < 0.0 || std::get(i) > 1.0) { - log_error("Constraint check: Parameter CommutingRatio entry {:.4f} smaller {:.4f} or greater {:.4f}", - std::get(i), 0.0, 1.0); - return true; - } - if (std::get<0>(i) < Region(0) || std::get<1>(i) < Region(0) || std::get<0>(i) > m_num_regions || - std::get<1>(i) > m_num_regions) { - log_error("Constraint check: Parameter CommutingRatio has an entry with start or end Region " - "that does not appear in the model."); - return true; - } - } return false; } From e6e6d70e29f9af0e13c3bbf0f21ce9927a649aeb Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Fri, 8 Nov 2024 14:29:20 +0100 Subject: [PATCH 29/87] add computation of basis reproduction number for old model --- cpp/models/ode_seir_mobility/model.h | 123 +++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 9 deletions(-) diff --git a/cpp/models/ode_seir_mobility/model.h b/cpp/models/ode_seir_mobility/model.h index 3bc20c567d..1d2aa11eba 100644 --- a/cpp/models/ode_seir_mobility/model.h +++ b/cpp/models/ode_seir_mobility/model.h @@ -8,6 +8,12 @@ #include "models/ode_seir_mobility/parameters.h" #include "models/ode_seir_mobility/regions.h" #include "memilio/epidemiology/age_group.h" +#include "memilio/utils/time_series.h" + +GCC_CLANG_DIAGNOSTIC(push) +GCC_CLANG_DIAGNOSTIC(ignored "-Wshadow") +#include +GCC_CLANG_DIAGNOSTIC(pop) namespace mio { @@ -39,7 +45,6 @@ class Model : public FlowModel> pop, Eigen::Ref> y, FP t, Eigen::Ref> flows) const override @@ -52,8 +57,8 @@ class Model : public FlowModel n_regions = reduce_index>(params.get_num_regions()); for (auto age_i : make_index_range(n_age_groups)) { - for (auto age_j : make_index_range(n_age_groups)) { - for (auto region_n : make_index_range(n_regions)) { + for (auto region_n : make_index_range(n_regions)) { + for (auto age_j : make_index_range(n_age_groups)) { FP flow_SE_helper = 0; const size_t Sj = population.get_flat_index({region_n, age_j, InfectionState::Susceptible}); const size_t Ej = population.get_flat_index({region_n, age_j, InfectionState::Exposed}); @@ -81,17 +86,117 @@ class Model : public FlowModel( - {region, age_i})] = (1.0 / params.template get>()[age_i]) * - y[population.get_flat_index({region, age_i, InfectionState::Exposed})]; + {region_n, age_i})] = (1.0 / params.template get>()[age_i]) * + y[population.get_flat_index({region_n, age_i, InfectionState::Exposed})]; flows[Base::template get_flat_flow_index( - {region, age_i})] = (1.0 / params.template get>()[age_i]) * - y[population.get_flat_index({region, age_i, InfectionState::Infected})]; + {region_n, age_i})] = (1.0 / params.template get>()[age_i]) * + y[population.get_flat_index({region_n, age_i, InfectionState::Infected})]; } } } + + /** + *@brief Computes the reproduction number at a given index time of the Model output obtained by the Simulation. + *@param t_idx The index time at which the reproduction number is computed. + *@param y The TimeSeries obtained from the Model Simulation. + *@returns The computed reproduction number at the provided index time. + */ + IOResult get_reproduction_number(size_t t_idx, const mio::TimeSeries& y) + { + if (!(t_idx < static_cast(y.get_num_time_points()))) { + return mio::failure(mio::StatusCode::OutOfRange, "t_idx is not a valid index for the TimeSeries"); + } + + auto const& params = this->parameters; + auto const& pop = this->populations; + + const size_t num_age_groups = (size_t)params.get_num_agegroups(); + const size_t num_regions = (size_t)params.get_num_regions(); + constexpr size_t num_infected_compartments = 2; + const size_t total_infected_compartments = num_infected_compartments * num_age_groups * num_regions; + + ContactMatrixGroup const& contact_matrix = params.template get>(); + ContactMatrixGroup const& commuting_strengths = params.template get>(); + + Eigen::MatrixXd F = Eigen::MatrixXd::Zero(total_infected_compartments, total_infected_compartments); + Eigen::MatrixXd V = Eigen::MatrixXd::Zero(total_infected_compartments, total_infected_compartments); + + for (auto i = AgeGroup(0); i < AgeGroup(num_age_groups); i++) { + for (auto n = Region(0); n < Region(num_regions); n++) { + size_t Si = pop.get_flat_index({n, i, InfectionState::Susceptible}); + for (auto j = AgeGroup(0); j < AgeGroup(num_age_groups); j++) { + for (auto m = Region(0); m < Region(num_regions); m++) { + auto const population_region = pop.template slice({(size_t)m, 1}); + auto const population_region_age = population_region.template slice({(size_t)j, 1}); + auto Njm = std::accumulate(population_region_age.begin(), population_region_age.end(), 0.); + + if (n == m) { + double coeffStoE = contact_matrix.get_matrix_at(y.get_time(t_idx))(i.get(), j.get()) * + params.template get>()[i] / + Njm; + F((size_t)i * num_regions + (size_t)n, + num_age_groups * num_regions + (size_t)j * num_regions + (size_t)m) = + coeffStoE * y.get_value(t_idx)[Si]; + } + else { + double coeffStoE = + contact_matrix.get_matrix_at(y.get_time(t_idx))(i.get(), j.get()) * + params.template get>()[i] * + (commuting_strengths.get_matrix_at(y.get_time(t_idx))(n.get(), m.get()) + + commuting_strengths.get_matrix_at(y.get_time(t_idx))(m.get(), n.get())) / + Njm; + F((size_t)i * num_regions + (size_t)n, + num_age_groups * num_regions + (size_t)j * num_regions + (size_t)m) = + coeffStoE * y.get_value(t_idx)[Si]; + } + } + } + + double T_Ei = params.template get>()[i]; + double T_Ii = params.template get>()[i]; + V((size_t)i * num_regions + (size_t)n, (size_t)i * num_regions + (size_t)n) = 1.0 / T_Ei; + V(num_age_groups * num_regions + (size_t)i * num_regions + (size_t)n, + (size_t)i * num_regions + (size_t)n) = -1.0 / T_Ei; + V(num_age_groups * num_regions + (size_t)i * num_regions + (size_t)n, + num_age_groups * num_regions + (size_t)i * num_regions + (size_t)n) = 1.0 / T_Ii; + } + } + + V = V.inverse(); + + Eigen::MatrixXd NextGenMatrix = Eigen::MatrixXd::Zero(total_infected_compartments, total_infected_compartments); + NextGenMatrix = F * V; + + //Compute the largest eigenvalue in absolute value + Eigen::ComplexEigenSolver ces; + + ces.compute(NextGenMatrix); + const Eigen::VectorXcd eigen_vals = ces.eigenvalues(); + + Eigen::VectorXd eigen_vals_abs; + eigen_vals_abs.resize(eigen_vals.size()); + + for (int i = 0; i < eigen_vals.size(); i++) { + eigen_vals_abs[i] = std::abs(eigen_vals[i]); + } + return mio::success(eigen_vals_abs.maxCoeff()); + } + + /** + *@brief Computes the reproduction number for all time points of the Model output obtained by the Simulation. + *@param y The TimeSeries obtained from the Model Simulation. + *@returns vector containing all reproduction numbers + */ + Eigen::VectorXd get_reproduction_numbers(const mio::TimeSeries& y) + { + auto num_time_points = y.get_num_time_points(); + Eigen::VectorXd temp(num_time_points); + for (size_t i = 0; i < static_cast(num_time_points); i++) { + temp[i] = get_reproduction_number(i, y).value(); + } + return temp; + } }; } // namespace oseirmobility From 649467c3680d2a664cf244fdb95ad8001a3c6049 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 20 Nov 2024 19:33:04 +0100 Subject: [PATCH 30/87] add computation of basis reproduction numbers and changes for counting FLOPs --- cpp/examples/graph.cpp | 1 - cpp/examples/ode_seir_mobility.cpp | 3 + cpp/examples/ode_seir_mobility_improved.cpp | 63 ++++++----- cpp/models/ode_seir/model.h | 2 +- cpp/models/ode_seir_mobility_improved/model.h | 106 ++++++++++++++++++ 5 files changed, 144 insertions(+), 31 deletions(-) diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index 65e913b1ed..b060e1bcb2 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -63,7 +63,6 @@ int main() g.add_node(1002, model_group2, t0); for (auto& node : g.nodes()) { node.property.get_simulation().set_integrator(std::make_shared>()); - node.property.get_simulation().get_dt() = dt; } g.add_edge(0, 1, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.05)); g.add_edge(1, 0, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.01)); diff --git a/cpp/examples/ode_seir_mobility.cpp b/cpp/examples/ode_seir_mobility.cpp index 7fe6903d1d..4cdab666b7 100644 --- a/cpp/examples/ode_seir_mobility.cpp +++ b/cpp/examples/ode_seir_mobility.cpp @@ -88,6 +88,9 @@ int main() auto save_result_status = mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_standard.h5"); + auto reproduction_numbers = model.get_reproduction_numbers(result_from_sim); + std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; + // bool print_to_terminal = true; // result_from_sim.print_table(); diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index aea5d08376..4f7e819512 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -27,17 +27,15 @@ mio::IOResult set_mobility_weights(const std::string& mobility_data, mio:: "transformMobilitydata.py from pycode memilio epidata package."); } - for (auto age = mio::AgeGroup(0); age < model.parameters.get_num_agegroups(); age++) { - for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { - auto population_i = model.populations.get_group_total(mio::oseirmobilityimproved::Region(county_idx_i)); - mobility_data_commuter.row(county_idx_i) /= 2 * population_i; - mobility_data_commuter(county_idx_i, county_idx_i) = - 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); - } - model.parameters.template get>() - .get_cont_freq_mat()[0] - .get_baseline() = mobility_data_commuter; + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + auto population_i = model.populations.get_group_total(mio::oseirmobilityimproved::Region(county_idx_i)); + mobility_data_commuter.row(county_idx_i) /= population_i; + mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); } + model.parameters.template get>() + .get_cont_freq_mat()[0] + .get_baseline() = mobility_data_commuter; + return mio::success(); } @@ -47,26 +45,27 @@ int main() ScalarType t0 = 0.; ScalarType tmax = 15.; - ScalarType dt = 0.5; + ScalarType dt = 0.1; - // std::vector region_ids = {1001, 1002}; - ScalarType number_regions = 400; + ScalarType number_regions = 2; + std::vector region_ids(number_regions); + iota(region_ids.begin(), region_ids.end(), 1); ScalarType number_age_groups = 1; mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& mobility_data = "/home/gers_ca/code/memilio/data"; + const std::string& mobility_data = ""; mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Exposed}] = 100; + mio::oseirmobilityimproved::InfectionState::Exposed}] = 10; model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 99900; + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 9990; for (int i = 1; i < number_regions; i++) { model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(0), mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 100000; + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; } model.parameters.set>(1.); @@ -74,7 +73,6 @@ int main() model.parameters.set>(3.); model.parameters.set>(5.); - model.parameters.set>(0.); mio::ContactMatrixGroup& contact_matrix = model.parameters.get>().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(2.7); @@ -84,15 +82,20 @@ int main() mio::ContactMatrixGroup& commuting_strengths = model.parameters.get>().get_cont_freq_mat(); - auto& population = model.parameters.get>(); - for (int n = 0; n < number_regions; ++n) { - auto population_n = model.populations.get_group_total(mio::oseirmobilityimproved::Region(n)); - population[{mio::oseirmobilityimproved::Region(n)}] += population_n; - for (int m = 0; m < number_regions; ++m) { - population[{mio::oseirmobilityimproved::Region(n)}] -= - commuting_strengths[0].get_baseline()(n, m) * population_n; - population[{mio::oseirmobilityimproved::Region(m)}] += - commuting_strengths[0].get_baseline()(n, m) * population_n; + auto& population = model.m_population_after_commuting; + for (int region_n = 0; region_n < number_regions; ++region_n) { + for (int age = 0; age < number_age_groups; ++age) { + auto const population_region = + model.populations.template slice({(size_t)region_n, 1}); + auto const population_region_age = population_region.template slice({(size_t)age, 1}); + auto population_n = std::accumulate(population_region_age.begin(), population_region_age.end(), 0.); + population[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += population_n; + for (int region_m = 0; region_m < number_regions; ++region_m) { + population[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= + commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; + population[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += + commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; + } } } // using DefaultIntegratorCore = @@ -111,9 +114,11 @@ int main() printf("Runtime: %f\n", ms_double.count()); - // auto save_result_status = - // mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_test.h5"); + auto save_result_status = + mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_test.h5"); + auto reproduction_numbers = model.get_reproduction_numbers(result_from_sim); + std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; // bool print_to_terminal = true; // result_from_sim.print_table(); diff --git a/cpp/models/ode_seir/model.h b/cpp/models/ode_seir/model.h index fa3bf4db93..3614ebc25e 100644 --- a/cpp/models/ode_seir/model.h +++ b/cpp/models/ode_seir/model.h @@ -80,7 +80,7 @@ class Model const size_t Ii = this->populations.get_flat_index({i, InfectionState::Infected}); for (auto j : make_index_range(age_groups)) { - const size_t Sj = this->populations.get_flat_index({i, InfectionState::Susceptible}); + const size_t Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); const size_t Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); const size_t Ij = this->populations.get_flat_index({j, InfectionState::Infected}); const size_t Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index 3353e5c2e7..aa29e3cb0a 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -8,6 +8,12 @@ #include "models/ode_seir_mobility_improved/parameters.h" #include "models/ode_seir_mobility_improved/regions.h" #include "memilio/epidemiology/age_group.h" +#include "memilio/utils/time_series.h" + +GCC_CLANG_DIAGNOSTIC(push) +GCC_CLANG_DIAGNOSTIC(ignored "-Wshadow") +#include +GCC_CLANG_DIAGNOSTIC(pop) namespace mio { @@ -98,6 +104,106 @@ class Model : public FlowModel get_reproduction_number(size_t t_idx, const mio::TimeSeries& y) + { + if (!(t_idx < static_cast(y.get_num_time_points()))) { + return mio::failure(mio::StatusCode::OutOfRange, "t_idx is not a valid index for the TimeSeries"); + } + + auto const& params = this->parameters; + auto const& pop = this->populations; + + const size_t num_age_groups = (size_t)params.get_num_agegroups(); + const size_t num_regions = (size_t)params.get_num_regions(); + constexpr size_t num_infected_compartments = 2; + const size_t total_infected_compartments = num_infected_compartments * num_age_groups * num_regions; + + ContactMatrixGroup const& contact_matrix = params.template get>(); + ContactMatrixGroup const& commuting_strengths = params.template get>(); + + Eigen::MatrixXd F = Eigen::MatrixXd::Zero(total_infected_compartments, total_infected_compartments); + Eigen::MatrixXd V = Eigen::MatrixXd::Zero(total_infected_compartments, total_infected_compartments); + + for (auto i = AgeGroup(0); i < AgeGroup(num_age_groups); i++) { + for (auto n = Region(0); n < Region(num_regions); n++) { + size_t Si = pop.get_flat_index({n, i, InfectionState::Susceptible}); + for (auto j = AgeGroup(0); j < AgeGroup(num_age_groups); j++) { + for (auto m = Region(0); m < Region(num_regions); m++) { + auto const population_region = pop.template slice({(size_t)m, 1}); + auto const population_region_age = population_region.template slice({(size_t)j, 1}); + auto Njm = std::accumulate(population_region_age.begin(), population_region_age.end(), 0.); + + double coeffStoE = 0.5 * contact_matrix.get_matrix_at(y.get_time(t_idx))(i.get(), j.get()) * + params.template get>()[i]; + if (n == m) { + F((size_t)i * num_regions + (size_t)n, + num_age_groups * num_regions + (size_t)j * num_regions + (size_t)m) += + coeffStoE * y.get_value(t_idx)[Si] / Njm; + } + for (auto k = Region(0); k < Region(num_regions); k++) { + auto test = commuting_strengths.get_matrix_at(y.get_time(t_idx))(n.get(), k.get()); + mio::unused(test); + F((size_t)i * num_regions + (size_t)n, + num_age_groups * num_regions + (size_t)j * num_regions + (size_t)m) += + coeffStoE * y.get_value(t_idx)[Si] * + commuting_strengths.get_matrix_at(y.get_time(t_idx))(n.get(), k.get()) * + commuting_strengths.get_matrix_at(y.get_time(t_idx))(m.get(), k.get()) / + m_population_after_commuting[{k, j}]; + } + } + } + + double T_Ei = params.template get>()[i]; + double T_Ii = params.template get>()[i]; + V((size_t)i * num_regions + (size_t)n, (size_t)i * num_regions + (size_t)n) = 1.0 / T_Ei; + V(num_age_groups * num_regions + (size_t)i * num_regions + (size_t)n, + (size_t)i * num_regions + (size_t)n) = -1.0 / T_Ei; + V(num_age_groups * num_regions + (size_t)i * num_regions + (size_t)n, + num_age_groups * num_regions + (size_t)i * num_regions + (size_t)n) = 1.0 / T_Ii; + } + } + + V = V.inverse(); + + Eigen::MatrixXd NextGenMatrix = Eigen::MatrixXd::Zero(total_infected_compartments, total_infected_compartments); + NextGenMatrix = F * V; + + //Compute the largest eigenvalue in absolute value + Eigen::ComplexEigenSolver ces; + + ces.compute(NextGenMatrix); + const Eigen::VectorXcd eigen_vals = ces.eigenvalues(); + + Eigen::VectorXd eigen_vals_abs; + eigen_vals_abs.resize(eigen_vals.size()); + + for (int i = 0; i < eigen_vals.size(); i++) { + eigen_vals_abs[i] = std::abs(eigen_vals[i]); + } + return mio::success(eigen_vals_abs.maxCoeff()); + } + + /** + *@brief Computes the reproduction number for all time points of the Model output obtained by the Simulation. + *@param y The TimeSeries obtained from the Model Simulation. + *@returns vector containing all reproduction numbers + */ + Eigen::VectorXd get_reproduction_numbers(const mio::TimeSeries& y) + { + auto num_time_points = y.get_num_time_points(); + Eigen::VectorXd temp(num_time_points); + for (size_t i = 0; i < static_cast(num_time_points); i++) { + temp[i] = get_reproduction_number(i, y).value(); + } + return temp; + } + mio::Populations m_population_after_commuting; }; // namespace oseirmobilityimproved From 4239fa748ca6248cc7dc3c4773a0cac4856b3442 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 28 Nov 2024 15:40:44 +0100 Subject: [PATCH 31/87] small cleanup --- cpp/examples/ode_seir_mobility_improved.cpp | 37 ++++----------------- 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index 4f7e819512..32d2685647 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -85,10 +85,11 @@ int main() auto& population = model.m_population_after_commuting; for (int region_n = 0; region_n < number_regions; ++region_n) { for (int age = 0; age < number_age_groups; ++age) { - auto const population_region = - model.populations.template slice({(size_t)region_n, 1}); - auto const population_region_age = population_region.template slice({(size_t)age, 1}); - auto population_n = std::accumulate(population_region_age.begin(), population_region_age.end(), 0.); + double population_n = 0; + for (size_t state = 0; state < (size_t)mio::oseirmobilityimproved::InfectionState::Count; state++) { + population_n += model.populations[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), + mio::oseirmobilityimproved::InfectionState(state)}]; + } population[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += population_n; for (int region_m = 0; region_m < number_regions; ++region_m) { population[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= @@ -119,30 +120,6 @@ int main() auto reproduction_numbers = model.get_reproduction_numbers(result_from_sim); std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; - // bool print_to_terminal = true; - - // result_from_sim.print_table(); - - // if (print_to_terminal) { - - // std::vector vars = {"S", "E", "I", "R"}; - // printf("\n # t"); - // for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { - // for (size_t k = 0; k < (size_t)mio::oseirmobilityimproved::InfectionState::Count; k++) { - // printf(" %s_%d", vars[k].c_str(), (int)i); - // } - // } - - // auto num_points = static_cast(result_from_sim.get_num_time_points()); - // for (size_t i = 0; i < num_points; i++) { - // printf("\n%.14f ", result_from_sim.get_time(i)); - // for (size_t k = 0; k < (size_t)model.parameters.get_num_regions(); k++) { - // for (size_t j = 0; j < (size_t)mio::oseirmobilityimproved::InfectionState::Count; j++) { - // printf(" %.14f", result_from_sim.get_value( - // i)[j + (size_t)mio::oseirmobilityimproved::InfectionState::Count * (int)k]); - // } - // } - // } - // printf("\n"); - // } + + result_from_sim.print_table(); } From 2c4de486d2e4f99f0cc8f34860464227847bd6b8 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Sun, 1 Dec 2024 21:21:13 +0100 Subject: [PATCH 32/87] read in population data --- cpp/examples/CMakeLists.txt | 4 + cpp/examples/graph_extended.cpp | 109 ++++++++++ cpp/examples/ode_seir.cpp | 44 ++-- cpp/examples/ode_seir_mobility_improved.cpp | 200 ++++++++++++------ cpp/models/ode_seir_mobility_improved/model.h | 25 +-- 5 files changed, 287 insertions(+), 95 deletions(-) create mode 100644 cpp/examples/graph_extended.cpp diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index b92f70dfd6..733ca7cf47 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -100,6 +100,10 @@ add_executable(graph_example graph.cpp) target_link_libraries(graph_example PRIVATE memilio ode_seir) target_compile_options(graph_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(graph_example_extended graph_extended.cpp) +target_link_libraries(graph_example_extended PRIVATE memilio ode_seir) +target_compile_options(graph_example_extended PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(graph_stochastic_mobility_example graph_stochastic_mobility.cpp) target_link_libraries(graph_stochastic_mobility_example PRIVATE memilio ode_secir) target_compile_options(graph_stochastic_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/examples/graph_extended.cpp b/cpp/examples/graph_extended.cpp new file mode 100644 index 0000000000..e963c1e631 --- /dev/null +++ b/cpp/examples/graph_extended.cpp @@ -0,0 +1,109 @@ + +#include "ode_seir/model.h" +#include "ode_seir/infection_state.h" +#include "ode_seir/parameters.h" +#include "memilio/mobility/metapopulation_mobility_instant.h" +#include "memilio/compartments/simulation.h" +#include "memilio/io/result_io.h" + +#include + +mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double dt) +{ + // global parameters + const int num_age_groups = 1; + mio::oseir::Parameters params(num_age_groups); + mio::Populations population( + {mio::AgeGroup(num_age_groups), mio::oseir::InfectionState::Count}); + params.set>(1.); + + // set transition times + params.set>(3.); + params.set>(5.); + + // set contact matrix + params.get>().get_cont_freq_mat()[0].get_baseline().setConstant(7.95); + + population[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 10000; + + // graph of counties with populations and local parameters + // and mobility between counties + mio::Graph>>, mio::MobilityEdge<>> params_graph; + + std::vector> nodes(2, mio::oseir::Model(int(size_t(params.get_num_groups())))); + for (auto& node : nodes) { + node.parameters = params; + node.populations = population; + } + nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 9990; + nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] = 10; + + for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { + params_graph.add_node(node_idx, nodes[node_idx]); + } + + BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, + mio::read_mobility_plain((data_dir / "mobility" / "commuter_migration_test.txt").string())); + if (mobility_data_commuter.rows() != Eigen::Index(params_graph.nodes().size()) || + mobility_data_commuter.cols() != Eigen::Index(params_graph.nodes().size())) { + return mio::failure(mio::StatusCode::InvalidValue, + "Mobility matrices do not have the correct size. You may need to run " + "transformMobilitydata.py from pycode memilio epidata package."); + } + + for (size_t county_idx_i = 0; county_idx_i < params_graph.nodes().size(); ++county_idx_i) { + for (size_t county_idx_j = 0; county_idx_j < params_graph.nodes().size(); ++county_idx_j) { + auto& populations = params_graph.nodes()[county_idx_i].property.get_simulation().get_model().populations; + + auto commuter_coeff_ij = mobility_data_commuter(county_idx_i, county_idx_j) / populations.get_total(); + params_graph.add_edge( + county_idx_i, county_idx_j, + Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, commuter_coeff_ij)); + } + } + + for (auto& node : params_graph.nodes()) { + node.property.get_simulation().set_integrator(std::make_shared>()); + } + + auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); + + printf("Start Simulation\n"); + auto t1 = std::chrono::high_resolution_clock::now(); + sim.advance(tmax); + auto t2 = std::chrono::high_resolution_clock::now(); + + std::chrono::duration ms_double = t2 - t1; + + printf("Runtime: %f\n", ms_double.count()); + + auto result_graph = std::move(sim).get_graph(); + auto result = mio::interpolate_simulation_result(result_graph); + + std::vector county_ids(result_graph.nodes().size()); + std::transform(result_graph.nodes().begin(), result_graph.nodes().end(), county_ids.begin(), [](auto& n) { + return n.id; + }); + + auto save_result_status = save_result(result, county_ids, 1, "graph_result.h5"); + result_graph.nodes()[0].property.get_result().print_table(); + result_graph.nodes()[1].property.get_result().print_table(); + // for (auto&& node : result_graph.nodes()) { + // node.property.get_result().print_table(); + // } + + return mio::success(); +} + +int main() +{ + const auto t0 = 0.; + const auto tmax = 1.; + const auto dt = 0.5; //time step of mobility, daily mobility every second step + + const std::string& data_dir = ""; + + auto result = run(data_dir, t0, tmax, dt); + + return 0; +} diff --git a/cpp/examples/ode_seir.cpp b/cpp/examples/ode_seir.cpp index 875372959e..c4e0bd0269 100644 --- a/cpp/examples/ode_seir.cpp +++ b/cpp/examples/ode_seir.cpp @@ -22,6 +22,7 @@ #include "ode_seir/parameters.h" #include "memilio/compartments/simulation.h" #include "memilio/utils/logging.h" +#include "memilio/math/euler.h" #include "memilio/utils/time_series.h" #include "memilio/utils/time_series.h" @@ -31,34 +32,41 @@ int main() mio::set_log_level(mio::LogLevel::debug); ScalarType t0 = 0; - ScalarType tmax = 50.; - ScalarType dt = 1.0; + ScalarType tmax = 0.2; + ScalarType dt = 0.1; mio::log_info("Simulating ODE SEIR; t={} ... {} with dt = {}.", t0, tmax, dt); - mio::oseir::Model model(1); + int number_agegroups = 6; + mio::oseir::Model model(number_agegroups); - ScalarType total_population = 10000; - model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] = 100; - model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Infected}] = 100; - model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Recovered}] = 100; - model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = - total_population - model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] - - model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Infected}] - - model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Recovered}]; + ScalarType total_population = 286922; + for (int i = 0; i < number_agegroups; i++) { + model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Exposed}] = 10; + model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Infected}] = 0; + model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Recovered}] = 0; + model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Susceptible}] = + total_population - model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Exposed}] - + model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Infected}] - + model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Recovered}]; + } - model.parameters.set>(5.2); - model.parameters.set>(6); - model.parameters.set>(0.1); + model.parameters.set>(3.); + model.parameters.set>(5.); + model.parameters.set>(1.); mio::ContactMatrixGroup& contact_matrix = model.parameters.get>(); - contact_matrix[0].get_baseline().setConstant(2.7); - contact_matrix[0].add_damping(0.7, mio::SimulationTime(30.)); + contact_matrix[0].get_baseline().setConstant(7.95); + // contact_matrix[0].add_damping(0.7, mio::SimulationTime(30.)); model.check_constraints(); + std::shared_ptr> integrator = std::make_shared>(); - auto seir = simulate(t0, tmax, dt, model); + auto seir = simulate(t0, tmax, dt, model, integrator); + + auto reproduction_numbers = model.get_reproduction_numbers(seir); + std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; seir.print_table({"S", "E", "I", "R"}); - std::cout << "\nnumber total: " << seir.get_last_value().sum() << "\n"; + // std::cout << "\nnumber total: " << seir.get_last_value().sum() << "\n"; } diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index 32d2685647..db065dcebf 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -10,95 +10,170 @@ #include "models/ode_seir_mobility_improved/regions.h" #include "memilio/io/io.h" #include "memilio/io/result_io.h" +#include "memilio/io/epi_data.h" #include template -mio::IOResult set_mobility_weights(const std::string& mobility_data, mio::oseirmobilityimproved::Model& model, - size_t number_regions) +mio::IOResult set_population_data(mio::oseirmobilityimproved::Model& model, + const std::string& population_data_path) { - // mobility between nodes - BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, - mio::read_mobility_plain(mobility_data + "/mobility" + "/commuter_migration_test.txt")); - if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || - mobility_data_commuter.cols() != Eigen::Index(number_regions)) { - return mio::failure(mio::StatusCode::InvalidValue, - "Mobility matrices do not have the correct size. You may need to run " - "transformMobilitydata.py from pycode memilio epidata package."); - } - - for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { - auto population_i = model.populations.get_group_total(mio::oseirmobilityimproved::Region(county_idx_i)); - mobility_data_commuter.row(county_idx_i) /= population_i; - mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); + BOOST_OUTCOME_TRY(auto&& node_ids, mio::get_node_ids(population_data_path, true, true)); + + BOOST_OUTCOME_TRY(const auto&& population_data, mio::read_population_data(population_data_path, true)); + + for (auto&& entry : population_data) { + auto it = std::find_if(node_ids.begin(), node_ids.end(), [&entry](auto r) { + return r == 0 || + (entry.county_id && mio::regions::StateId(r) == mio::regions::get_state_id(int(*entry.county_id))) || + (entry.county_id && mio::regions::CountyId(r) == *entry.county_id) || + (entry.district_id && mio::regions::DistrictId(r) == *entry.district_id); + }); + if (it != node_ids.end()) { + auto region_idx = size_t(it - node_ids.begin()); + for (size_t age = 0; age < (size_t)model.parameters.get_num_agegroups(); age++) { + model.populations[{mio::oseirmobilityimproved::Region(region_idx), mio::AgeGroup(age), + mio::oseirmobilityimproved::InfectionState::Susceptible}] = + entry.population[mio::AgeGroup(age)]; + } + } } - model.parameters.template get>() - .get_cont_freq_mat()[0] - .get_baseline() = mobility_data_commuter; return mio::success(); } -int main() +template +mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& model, const std::string& mobility_data) { - mio::set_log_level(mio::LogLevel::debug); - - ScalarType t0 = 0.; - ScalarType tmax = 15.; - ScalarType dt = 0.1; - - ScalarType number_regions = 2; - std::vector region_ids(number_regions); - iota(region_ids.begin(), region_ids.end(), 1); - ScalarType number_age_groups = 1; - - mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); + size_t number_regions = (size_t)model.parameters.get_num_regions(); + if (number_regions == 1) { + model.parameters.template get>() + .get_cont_freq_mat()[0] + .get_baseline() + .setConstant(1.0); + + return mio::success(); + } + else { + // mobility between nodes + BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, mio::read_mobility_plain(mobility_data)); + if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || + mobility_data_commuter.cols() != Eigen::Index(number_regions)) { + return mio::failure(mio::StatusCode::InvalidValue, + "Mobility matrices do not have the correct size. You may need to run " + "transformMobilitydata.py from pycode memilio epidata package."); + } - const std::string& mobility_data = ""; + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + auto population_i = model.populations.get_group_total(mio::oseirmobilityimproved::Region(county_idx_i)); + auto test = population_i; + mobility_data_commuter.row(county_idx_i) /= population_i; + mio::unused(test); + mobility_data_commuter(county_idx_i, county_idx_i) = + 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); + } + model.parameters.template get>() + .get_cont_freq_mat()[0] + .get_baseline() = mobility_data_commuter; - mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); - model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Exposed}] = 10; - model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 9990; - for (int i = 1; i < number_regions; i++) { - model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; - model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + return mio::success(); } +} - model.parameters.set>(1.); - - model.parameters.set>(3.); - model.parameters.set>(5.); +template +mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Model& model, + const std::string& population_data_path, + const std::string& mobility_data) +{ + BOOST_OUTCOME_TRY(set_population_data(model, population_data_path)); + mio::unused(population_data_path); + + auto& populations = model.populations; + auto& parameters = model.parameters; + + size_t number_regions = (size_t)parameters.get_num_regions(); + size_t number_age_groups = (size_t)parameters.get_num_agegroups(); + + // for (size_t j = 0; j < number_age_groups; j++) { + // populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), + // mio::oseirmobilityimproved::InfectionState::Exposed}] = 10; + // populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), + // mio::oseirmobilityimproved::InfectionState::Susceptible}] = 631207; + // auto test = populations.get_group_total(mio::oseirmobilityimproved::Region(0)); + // mio::unused(test); + // for (size_t i = 1; i < number_regions; i++) { + // model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), + // mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; + // model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), + // mio::oseirmobilityimproved::InfectionState::Susceptible}] = 503707; + // } + // } + + BOOST_OUTCOME_TRY(set_mobility_weights(model, mobility_data)); + + populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(3), + mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; + populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(3), + mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; mio::ContactMatrixGroup& contact_matrix = - model.parameters.get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(2.7); - // contact_matrix[0].add_damping(0.5, mio::SimulationTime(5)); + parameters.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(7.95); + + parameters.template set>(1.); + + parameters.template set>(3.); + parameters.template set>(5.); - auto result_preprocess = set_mobility_weights(mobility_data, model, number_regions); mio::ContactMatrixGroup& commuting_strengths = - model.parameters.get>().get_cont_freq_mat(); + parameters.template get>().get_cont_freq_mat(); - auto& population = model.m_population_after_commuting; - for (int region_n = 0; region_n < number_regions; ++region_n) { - for (int age = 0; age < number_age_groups; ++age) { + auto& population_after_commuting = model.m_population_after_commuting; + for (size_t region_n = 0; region_n < number_regions; ++region_n) { + for (size_t age = 0; age < number_age_groups; ++age) { double population_n = 0; for (size_t state = 0; state < (size_t)mio::oseirmobilityimproved::InfectionState::Count; state++) { - population_n += model.populations[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), - mio::oseirmobilityimproved::InfectionState(state)}]; + population_n += populations[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), + mio::oseirmobilityimproved::InfectionState(state)}]; } - population[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += population_n; - for (int region_m = 0; region_m < number_regions; ++region_m) { - population[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= + population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += + population_n; + for (size_t region_m = 0; region_m < number_regions; ++region_m) { + population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; - population[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += + population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; + auto test = + population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}]; + mio::unused(test); } } } + + return mio::success(); +} + +int main() +{ + mio::set_log_level(mio::LogLevel::debug); + + ScalarType t0 = 0.; + ScalarType tmax = 1.0; + ScalarType dt = 0.1; + + ScalarType number_regions = 3; + std::vector region_ids(number_regions); + iota(region_ids.begin(), region_ids.end(), 1); + ScalarType number_age_groups = 6; + + mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); + + const std::string& mobility_data = ""; + const std::string& population_data = ""; + + mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); + auto result_prepare_simulation = set_parameters_and_population(model, population_data, mobility_data); + // using DefaultIntegratorCore = // mio::ControlledStepperWrapper; @@ -114,12 +189,11 @@ int main() std::chrono::duration ms_double = t2 - t1; printf("Runtime: %f\n", ms_double.count()); + result_from_sim.print_table({"S", "E", "I", "R"}); auto save_result_status = mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_test.h5"); auto reproduction_numbers = model.get_reproduction_numbers(result_from_sim); std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; - - result_from_sim.print_table(); } diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index aa29e3cb0a..182c46cc22 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -135,22 +135,19 @@ class Model : public FlowModel({(size_t)m, 1}); - auto const population_region_age = population_region.template slice({(size_t)j, 1}); + auto const population_region = pop.template slice({m.get(), 1}); + auto const population_region_age = population_region.template slice({j.get(), 1}); auto Njm = std::accumulate(population_region_age.begin(), population_region_age.end(), 0.); double coeffStoE = 0.5 * contact_matrix.get_matrix_at(y.get_time(t_idx))(i.get(), j.get()) * params.template get>()[i]; if (n == m) { - F((size_t)i * num_regions + (size_t)n, - num_age_groups * num_regions + (size_t)j * num_regions + (size_t)m) += - coeffStoE * y.get_value(t_idx)[Si] / Njm; + F(i.get() * num_regions + n.get(), num_age_groups * num_regions + j.get() * num_regions + + m.get()) += coeffStoE * y.get_value(t_idx)[Si] / Njm; } for (auto k = Region(0); k < Region(num_regions); k++) { - auto test = commuting_strengths.get_matrix_at(y.get_time(t_idx))(n.get(), k.get()); - mio::unused(test); - F((size_t)i * num_regions + (size_t)n, - num_age_groups * num_regions + (size_t)j * num_regions + (size_t)m) += + F(i.get() * num_regions + n.get(), + num_age_groups * num_regions + j.get() * num_regions + m.get()) += coeffStoE * y.get_value(t_idx)[Si] * commuting_strengths.get_matrix_at(y.get_time(t_idx))(n.get(), k.get()) * commuting_strengths.get_matrix_at(y.get_time(t_idx))(m.get(), k.get()) / @@ -161,11 +158,11 @@ class Model : public FlowModel>()[i]; double T_Ii = params.template get>()[i]; - V((size_t)i * num_regions + (size_t)n, (size_t)i * num_regions + (size_t)n) = 1.0 / T_Ei; - V(num_age_groups * num_regions + (size_t)i * num_regions + (size_t)n, - (size_t)i * num_regions + (size_t)n) = -1.0 / T_Ei; - V(num_age_groups * num_regions + (size_t)i * num_regions + (size_t)n, - num_age_groups * num_regions + (size_t)i * num_regions + (size_t)n) = 1.0 / T_Ii; + V(i.get() * num_regions + n.get(), i.get() * num_regions + n.get()) = 1.0 / T_Ei; + V(num_age_groups * num_regions + i.get() * num_regions + n.get(), i.get() * num_regions + n.get()) = + -1.0 / T_Ei; + V(num_age_groups * num_regions + i.get() * num_regions + n.get(), + num_age_groups * num_regions + i.get() * num_regions + n.get()) = 1.0 / T_Ii; } } From ce86fb6bd7e5f904aca4c0202b6d23a5486561a0 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Sun, 1 Dec 2024 22:00:17 +0100 Subject: [PATCH 33/87] debugging artefacts --- cpp/examples/ode_seir_mobility_improved.cpp | 23 ++------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index db065dcebf..f03421a0de 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -86,7 +86,6 @@ mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Mo const std::string& mobility_data) { BOOST_OUTCOME_TRY(set_population_data(model, population_data_path)); - mio::unused(population_data_path); auto& populations = model.populations; auto& parameters = model.parameters; @@ -94,21 +93,6 @@ mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Mo size_t number_regions = (size_t)parameters.get_num_regions(); size_t number_age_groups = (size_t)parameters.get_num_agegroups(); - // for (size_t j = 0; j < number_age_groups; j++) { - // populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), - // mio::oseirmobilityimproved::InfectionState::Exposed}] = 10; - // populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), - // mio::oseirmobilityimproved::InfectionState::Susceptible}] = 631207; - // auto test = populations.get_group_total(mio::oseirmobilityimproved::Region(0)); - // mio::unused(test); - // for (size_t i = 1; i < number_regions; i++) { - // model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - // mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; - // model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - // mio::oseirmobilityimproved::InfectionState::Susceptible}] = 503707; - // } - // } - BOOST_OUTCOME_TRY(set_mobility_weights(model, mobility_data)); populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(3), @@ -143,9 +127,6 @@ mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Mo commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; - auto test = - population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}]; - mio::unused(test); } } } @@ -158,10 +139,10 @@ int main() mio::set_log_level(mio::LogLevel::debug); ScalarType t0 = 0.; - ScalarType tmax = 1.0; + ScalarType tmax = 0.2; ScalarType dt = 0.1; - ScalarType number_regions = 3; + ScalarType number_regions = 53; std::vector region_ids(number_regions); iota(region_ids.begin(), region_ids.end(), 1); ScalarType number_age_groups = 6; From d3781189cb410233830adc0f7c6b7ea9e02e32ae Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:38:00 +0100 Subject: [PATCH 34/87] more cleanup and provide demo population for a number of agegroups different than 6 --- cpp/examples/ode_seir_mobility_improved.cpp | 35 +++++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index f03421a0de..0ab5a3d46d 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -39,6 +39,7 @@ mio::IOResult set_population_data(mio::oseirmobilityimproved::Model& m } } + printf("Setting population data successful.\n"); return mio::success(); } @@ -66,9 +67,7 @@ mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { auto population_i = model.populations.get_group_total(mio::oseirmobilityimproved::Region(county_idx_i)); - auto test = population_i; mobility_data_commuter.row(county_idx_i) /= population_i; - mio::unused(test); mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); } @@ -76,6 +75,7 @@ mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& .get_cont_freq_mat()[0] .get_baseline() = mobility_data_commuter; + printf("Setting mobility weights successful.\n"); return mio::success(); } } @@ -85,21 +85,36 @@ mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Mo const std::string& population_data_path, const std::string& mobility_data) { - BOOST_OUTCOME_TRY(set_population_data(model, population_data_path)); - auto& populations = model.populations; auto& parameters = model.parameters; size_t number_regions = (size_t)parameters.get_num_regions(); size_t number_age_groups = (size_t)parameters.get_num_agegroups(); + if (number_age_groups != 6) { + printf("Data is not compatible, using demo population instead.\n"); + for (size_t j = 0; j < number_age_groups; j++) { + model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), + mio::oseirmobilityimproved::InfectionState::Exposed}] = 10; + model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 9990; + for (size_t i = 1; i < number_regions; i++) { + model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), + mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; + model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + } + } + } + else { + BOOST_OUTCOME_TRY(set_population_data(model, population_data_path)); + populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(1), + mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; + populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(1), + mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; + } BOOST_OUTCOME_TRY(set_mobility_weights(model, mobility_data)); - populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(3), - mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; - populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(3), - mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; - mio::ContactMatrixGroup& contact_matrix = parameters.template get>().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(7.95); @@ -170,7 +185,7 @@ int main() std::chrono::duration ms_double = t2 - t1; printf("Runtime: %f\n", ms_double.count()); - result_from_sim.print_table({"S", "E", "I", "R"}); + result_from_sim.print_table(); auto save_result_status = mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_test.h5"); From 33a2dd585a792f0985af8822ab92e039e9c331dd Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:12:46 +0100 Subject: [PATCH 35/87] read in contact matrices, set age resolved parameters, restructure --- cpp/examples/ode_seir_mobility_improved.cpp | 130 ++++++++++++++++---- 1 file changed, 108 insertions(+), 22 deletions(-) diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index 0ab5a3d46d..128dd295a4 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -14,13 +14,105 @@ #include +/** + * Set epidemiological parameters of Sars-CoV-2 for a immune-naive + * population and wild type variant. + * @param params Object that the parameters will be added to. + * @returns Currently generates no errors. + */ +mio::IOResult set_covid_parameters(mio::oseirmobilityimproved::Parameters& params) +{ + params.template set>(3.335); + if ((size_t)params.get_num_agegroups() == 6) { + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; + } + else { + params.template set>(8.); + + params.template set>(0.07); + } + + printf("Setting epidemiological parameters successful.\n"); + return mio::success(); +} + +/** + * indices of contact matrix corresponding to locations where contacts occur. + */ +enum class ContactLocation +{ + Home = 0, + School, + Work, + Other, + Count, +}; + +static const std::map contact_locations = {{ContactLocation::Home, "home"}, + {ContactLocation::School, "school_pf_eig"}, + {ContactLocation::Work, "work"}, + {ContactLocation::Other, "other"}}; + +/** + * Set contact matrices. + * Reads contact matrices from files in the data directory. + * @param data_dir data directory. + * @param params Object that the contact matrices will be added to. + * @returns any io errors that happen during reading of the files. + */ +mio::IOResult set_contact_matrices(const fs::path& data_dir, + mio::oseirmobilityimproved::Parameters& params) +{ + if ((size_t)params.get_num_agegroups() == 6) { + //TODO: io error handling + auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_agegroups())); + for (auto&& contact_location : contact_locations) { + BOOST_OUTCOME_TRY(auto&& baseline, + mio::read_mobility_plain( + (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); + BOOST_OUTCOME_TRY(auto&& minimum, + mio::read_mobility_plain( + (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); + contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; + contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; + } + params.get>() = + mio::UncertainContactMatrix(contact_matrices); + } + + else { + mio::ContactMatrixGroup& contact_matrix = + params.get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(7.95 / (size_t)params.get_num_agegroups()); + } + + printf("Setting contact matrices successful.\n"); + return mio::success(); +} + template -mio::IOResult set_population_data(mio::oseirmobilityimproved::Model& model, - const std::string& population_data_path) +mio::IOResult set_population_data(mio::oseirmobilityimproved::Model& model, const fs::path& data_dir) { - BOOST_OUTCOME_TRY(auto&& node_ids, mio::get_node_ids(population_data_path, true, true)); + BOOST_OUTCOME_TRY( + auto&& node_ids, + mio::get_node_ids((data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true, + true)); - BOOST_OUTCOME_TRY(const auto&& population_data, mio::read_population_data(population_data_path, true)); + BOOST_OUTCOME_TRY(const auto&& population_data, + mio::read_population_data( + (data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true)); for (auto&& entry : population_data) { auto it = std::find_if(node_ids.begin(), node_ids.end(), [&entry](auto r) { @@ -44,7 +136,7 @@ mio::IOResult set_population_data(mio::oseirmobilityimproved::Model& m } template -mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& model, const std::string& mobility_data) +mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& model, const fs::path& data_dir) { size_t number_regions = (size_t)model.parameters.get_num_regions(); if (number_regions == 1) { @@ -57,7 +149,8 @@ mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& } else { // mobility between nodes - BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, mio::read_mobility_plain(mobility_data)); + BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, + mio::read_mobility_plain((data_dir / "mobility" / "commuter_mobility_nrw.txt").string())); if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || mobility_data_commuter.cols() != Eigen::Index(number_regions)) { return mio::failure(mio::StatusCode::InvalidValue, @@ -82,8 +175,7 @@ mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& template mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Model& model, - const std::string& population_data_path, - const std::string& mobility_data) + const fs::path& data_dir) { auto& populations = model.populations; auto& parameters = model.parameters; @@ -97,32 +189,27 @@ mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Mo model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), mio::oseirmobilityimproved::InfectionState::Exposed}] = 10; model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 9990; + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 99990; for (size_t i = 1; i < number_regions; i++) { model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 100000; } } } else { - BOOST_OUTCOME_TRY(set_population_data(model, population_data_path)); + BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(1), mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(1), mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; } - BOOST_OUTCOME_TRY(set_mobility_weights(model, mobility_data)); - - mio::ContactMatrixGroup& contact_matrix = - parameters.template get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(7.95); + BOOST_OUTCOME_TRY(set_mobility_weights(model, data_dir)); - parameters.template set>(1.); + BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters)) - parameters.template set>(3.); - parameters.template set>(5.); + BOOST_OUTCOME_TRY(set_covid_parameters(parameters)); mio::ContactMatrixGroup& commuting_strengths = parameters.template get>().get_cont_freq_mat(); @@ -164,11 +251,10 @@ int main() mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& mobility_data = ""; - const std::string& population_data = ""; + const std::string& data_dir = ""; mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); - auto result_prepare_simulation = set_parameters_and_population(model, population_data, mobility_data); + auto result_prepare_simulation = set_parameters_and_population(model, data_dir); // using DefaultIntegratorCore = // mio::ControlledStepperWrapper; From c1bd747660fc6be40be5e954ff69bb1bf7ca4701 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Tue, 3 Dec 2024 20:11:08 +0100 Subject: [PATCH 36/87] add bool for using population from data --- cpp/examples/ode_seir_mobility_improved.cpp | 43 ++++++++++++--------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index 128dd295a4..c3ff687a90 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -20,10 +20,11 @@ * @param params Object that the parameters will be added to. * @returns Currently generates no errors. */ -mio::IOResult set_covid_parameters(mio::oseirmobilityimproved::Parameters& params) +mio::IOResult set_covid_parameters(mio::oseirmobilityimproved::Parameters& params, + bool synthetic_population) { params.template set>(3.335); - if ((size_t)params.get_num_agegroups() == 6) { + if (!synthetic_population) { params.get>()[mio::AgeGroup(0)] = 8.0096875; params.get>()[mio::AgeGroup(1)] = 8.0096875; params.get>()[mio::AgeGroup(2)] = 8.2182; @@ -73,9 +74,10 @@ static const std::map contact_locations = {{Contac * @returns any io errors that happen during reading of the files. */ mio::IOResult set_contact_matrices(const fs::path& data_dir, - mio::oseirmobilityimproved::Parameters& params) + mio::oseirmobilityimproved::Parameters& params, + bool synthetic_population) { - if ((size_t)params.get_num_agegroups() == 6) { + if (!synthetic_population) { //TODO: io error handling auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_agegroups())); for (auto&& contact_location : contact_locations) { @@ -91,7 +93,6 @@ mio::IOResult set_contact_matrices(const fs::path& data_dir, params.get>() = mio::UncertainContactMatrix(contact_matrices); } - else { mio::ContactMatrixGroup& contact_matrix = params.get>().get_cont_freq_mat(); @@ -175,7 +176,7 @@ mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& template mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Model& model, - const fs::path& data_dir) + const fs::path& data_dir, bool synthetic_population) { auto& populations = model.populations; auto& parameters = model.parameters; @@ -183,33 +184,33 @@ mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Mo size_t number_regions = (size_t)parameters.get_num_regions(); size_t number_age_groups = (size_t)parameters.get_num_agegroups(); - if (number_age_groups != 6) { - printf("Data is not compatible, using demo population instead.\n"); + if (synthetic_population) { + printf("Data is not compatible, using synthetic population instead.\n"); for (size_t j = 0; j < number_age_groups; j++) { model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), mio::oseirmobilityimproved::InfectionState::Exposed}] = 10; model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 99990; + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 9990; for (size_t i = 1; i < number_regions; i++) { model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 100000; + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; } } } else { BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); - populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(1), + populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; - populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(1), + populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; } BOOST_OUTCOME_TRY(set_mobility_weights(model, data_dir)); - BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters)) + BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters, synthetic_population)) - BOOST_OUTCOME_TRY(set_covid_parameters(parameters)); + BOOST_OUTCOME_TRY(set_covid_parameters(parameters, synthetic_population)); mio::ContactMatrixGroup& commuting_strengths = parameters.template get>().get_cont_freq_mat(); @@ -241,20 +242,24 @@ int main() mio::set_log_level(mio::LogLevel::debug); ScalarType t0 = 0.; - ScalarType tmax = 0.2; + ScalarType tmax = 5.; ScalarType dt = 0.1; ScalarType number_regions = 53; std::vector region_ids(number_regions); iota(region_ids.begin(), region_ids.end(), 1); ScalarType number_age_groups = 6; + bool synthetic_population = false; + if (number_age_groups != 6) { + synthetic_population = true; + } mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); const std::string& data_dir = ""; mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); - auto result_prepare_simulation = set_parameters_and_population(model, data_dir); + auto result_prepare_simulation = set_parameters_and_population(model, data_dir, synthetic_population); // using DefaultIntegratorCore = // mio::ControlledStepperWrapper; @@ -271,11 +276,11 @@ int main() std::chrono::duration ms_double = t2 - t1; printf("Runtime: %f\n", ms_double.count()); - result_from_sim.print_table(); + // result_from_sim.print_table(); auto save_result_status = mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_test.h5"); - auto reproduction_numbers = model.get_reproduction_numbers(result_from_sim); - std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; + // auto reproduction_numbers = model.get_reproduction_numbers(result_from_sim); + // std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; } From df22f5417e4abf0e4cfefb6591b0df0e7c010842 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Tue, 3 Dec 2024 20:12:19 +0100 Subject: [PATCH 37/87] read in data for graph model --- cpp/examples/graph_extended.cpp | 213 ++++++++++++++++++++++++++++---- 1 file changed, 188 insertions(+), 25 deletions(-) diff --git a/cpp/examples/graph_extended.cpp b/cpp/examples/graph_extended.cpp index e963c1e631..67e671ac89 100644 --- a/cpp/examples/graph_extended.cpp +++ b/cpp/examples/graph_extended.cpp @@ -5,45 +5,209 @@ #include "memilio/mobility/metapopulation_mobility_instant.h" #include "memilio/compartments/simulation.h" #include "memilio/io/result_io.h" +#include "memilio/io/epi_data.h" #include +/** + * indices of contact matrix corresponding to locations where contacts occur. + */ +enum class ContactLocation +{ + Home = 0, + School, + Work, + Other, + Count, +}; + +static const std::map contact_locations = {{ContactLocation::Home, "home"}, + {ContactLocation::School, "school_pf_eig"}, + {ContactLocation::Work, "work"}, + {ContactLocation::Other, "other"}}; + +/** + * Set contact matrices. + * Reads contact matrices from files in the data directory. + * @param data_dir data directory. + * @param params Object that the contact matrices will be added to. + * @returns any io errors that happen during reading of the files. + */ +mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseir::Parameters& params, + bool synthetic_population) +{ + if (!synthetic_population) { + //TODO: io error handling + auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_groups())); + for (auto&& contact_location : contact_locations) { + BOOST_OUTCOME_TRY(auto&& baseline, + mio::read_mobility_plain( + (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); + BOOST_OUTCOME_TRY(auto&& minimum, + mio::read_mobility_plain( + (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); + contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; + contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; + } + params.get>() = mio::UncertainContactMatrix(contact_matrices); + } + else { + mio::ContactMatrixGroup& contact_matrix = params.get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(7.95 / (size_t)params.get_num_groups()); + } + + printf("Setting contact matrices successful.\n"); + return mio::success(); +} + +/** + * Set epidemiological parameters of Sars-CoV-2 for a immune-naive + * population and wild type variant. + * @param params Object that the parameters will be added to. + * @returns Currently generates no errors. + */ +mio::IOResult set_covid_parameters(mio::oseir::Parameters& params, bool synthetic_population) +{ + params.template set>(3.335); + if (!synthetic_population) { + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; + } + else { + params.template set>(8.); + + params.template set>(0.07); + } + + printf("Setting epidemiological parameters successful.\n"); + return mio::success(); +} + +mio::IOResult>> set_population_data(const fs::path& data_dir, + mio::oseir::Parameters& params) +{ + BOOST_OUTCOME_TRY( + auto&& node_ids, + mio::get_node_ids((data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true, + true)); + size_t number_regions = node_ids.size(); + + std::vector> nodes(number_regions, + mio::oseir::Model(int(size_t(params.get_num_groups())))); + + for (auto& node : nodes) { + node.parameters = params; + } + + BOOST_OUTCOME_TRY(const auto&& population_data, + mio::read_population_data( + (data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true)); + + std::vector> vnum_population(node_ids.size(), + std::vector((size_t)params.get_num_groups(), 0.0)); + + for (auto&& entry : population_data) { + auto it = std::find_if(node_ids.begin(), node_ids.end(), [&entry](auto r) { + return r == 0 || + (entry.county_id && mio::regions::StateId(r) == mio::regions::get_state_id(int(*entry.county_id))) || + (entry.county_id && mio::regions::CountyId(r) == *entry.county_id) || + (entry.district_id && mio::regions::DistrictId(r) == *entry.district_id); + }); + if (it != node_ids.end()) { + auto region_idx = size_t(it - node_ids.begin()); + auto& num_population = vnum_population[region_idx]; + for (size_t age = 0; age < num_population.size(); age++) { + num_population[age] += entry.population[mio::AgeGroup(age)]; + } + } + } + + for (size_t region = 0; region < node_ids.size(); region++) { + auto num_groups = nodes[region].parameters.get_num_groups(); + for (auto i = mio::AgeGroup(0); i < num_groups; i++) { + nodes[region].populations.template set_difference_from_group_total( + {i, mio::oseir::InfectionState::Susceptible}, vnum_population[region][size_t(i)]); + } + } + nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; + nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; + + return mio::success(nodes); +} + +mio::IOResult>> +set_synthetic_population_data(mio::oseir::Parameters& params) +{ + size_t number_regions = 3; + + std::vector> nodes(number_regions, + mio::oseir::Model(int(size_t(params.get_num_groups())))); + + mio::Populations population( + {params.get_num_groups(), mio::oseir::InfectionState::Count}); + + for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { + population[{i, mio::oseir::InfectionState::Susceptible}] = 10000; + } + for (auto& node : nodes) { + node.parameters = params; + node.populations = population; + } + for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { + nodes[0].populations[{i, mio::oseir::InfectionState::Exposed}] = 10; + nodes[0].populations[{i, mio::oseir::InfectionState::Susceptible}] = 9990; + } + + return mio::success(nodes); +} + mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double dt) { // global parameters - const int num_age_groups = 1; + bool synthetic_population = false; + const int num_age_groups = 6; + if (num_age_groups != 6) { + synthetic_population = true; + } mio::oseir::Parameters params(num_age_groups); - mio::Populations population( - {mio::AgeGroup(num_age_groups), mio::oseir::InfectionState::Count}); - params.set>(1.); - // set transition times - params.set>(3.); - params.set>(5.); + BOOST_OUTCOME_TRY(set_covid_parameters(params, synthetic_population)); // set contact matrix - params.get>().get_cont_freq_mat()[0].get_baseline().setConstant(7.95); - - population[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 10000; + BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, params, synthetic_population)); // graph of counties with populations and local parameters // and mobility between counties mio::Graph>>, mio::MobilityEdge<>> params_graph; - std::vector> nodes(2, mio::oseir::Model(int(size_t(params.get_num_groups())))); - for (auto& node : nodes) { - node.parameters = params; - node.populations = population; + if (synthetic_population) { + BOOST_OUTCOME_TRY(auto&& nodes, set_synthetic_population_data(params)); + for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { + params_graph.add_node(node_idx, nodes[node_idx]); + } + printf("Setting synthetic population successful.\n"); } - nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 9990; - nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] = 10; - - for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { - params_graph.add_node(node_idx, nodes[node_idx]); + else { + BOOST_OUTCOME_TRY(auto&& nodes, set_population_data(data_dir, params)); + for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { + params_graph.add_node(node_idx, nodes[node_idx]); + } + printf("Setting population from data successful.\n"); } BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, - mio::read_mobility_plain((data_dir / "mobility" / "commuter_migration_test.txt").string())); + mio::read_mobility_plain((data_dir / "mobility" / "commuter_mobility_nrw.txt").string())); if (mobility_data_commuter.rows() != Eigen::Index(params_graph.nodes().size()) || mobility_data_commuter.cols() != Eigen::Index(params_graph.nodes().size())) { return mio::failure(mio::StatusCode::InvalidValue, @@ -58,7 +222,8 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double auto commuter_coeff_ij = mobility_data_commuter(county_idx_i, county_idx_j) / populations.get_total(); params_graph.add_edge( county_idx_i, county_idx_j, - Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, commuter_coeff_ij)); + Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count * size_t(params.get_num_groups()), + commuter_coeff_ij)); } } @@ -88,9 +253,7 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double auto save_result_status = save_result(result, county_ids, 1, "graph_result.h5"); result_graph.nodes()[0].property.get_result().print_table(); result_graph.nodes()[1].property.get_result().print_table(); - // for (auto&& node : result_graph.nodes()) { - // node.property.get_result().print_table(); - // } + result_graph.nodes()[2].property.get_result().print_table(); return mio::success(); } @@ -98,7 +261,7 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double int main() { const auto t0 = 0.; - const auto tmax = 1.; + const auto tmax = 5.; const auto dt = 0.5; //time step of mobility, daily mobility every second step const std::string& data_dir = ""; From 7b307794d6282422afb32e3058fe759e98d98b27 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 12 Dec 2024 18:12:32 +0100 Subject: [PATCH 38/87] simulation for nrw, plots and a bug fix --- cpp/examples/graph_extended.cpp | 39 +-- cpp/examples/ode_seir_mobility_improved.cpp | 18 +- cpp/models/ode_seir_mobility_improved/model.h | 2 +- pycode/examples/plot/plotResultsMapNRW.py | 235 ++++++++++++++++++ .../memilio/epidata/getNRWCounties.py | 54 ++++ 5 files changed, 319 insertions(+), 29 deletions(-) create mode 100644 pycode/examples/plot/plotResultsMapNRW.py create mode 100644 pycode/memilio-epidata/memilio/epidata/getNRWCounties.py diff --git a/cpp/examples/graph_extended.cpp b/cpp/examples/graph_extended.cpp index 67e671ac89..311994f33e 100644 --- a/cpp/examples/graph_extended.cpp +++ b/cpp/examples/graph_extended.cpp @@ -85,22 +85,18 @@ mio::IOResult set_covid_parameters(mio::oseir::Parameters& params, params.get>()[mio::AgeGroup(5)] = 0.175; } else { - params.template set>(8.); + params.template set>(8.097612257); - params.template set>(0.07); + params.template set>(0.07333); } printf("Setting epidemiological parameters successful.\n"); return mio::success(); } -mio::IOResult>> set_population_data(const fs::path& data_dir, - mio::oseir::Parameters& params) +mio::IOResult>> +set_population_data(const fs::path& data_dir, mio::oseir::Parameters& params, std::vector node_ids) { - BOOST_OUTCOME_TRY( - auto&& node_ids, - mio::get_node_ids((data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true, - true)); size_t number_regions = node_ids.size(); std::vector> nodes(number_regions, @@ -140,8 +136,8 @@ mio::IOResult>> set_population_data(const {i, mio::oseir::InfectionState::Susceptible}, vnum_population[region][size_t(i)]); } } - nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; - nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; + nodes[27].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; + nodes[27].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; return mio::success(nodes); } @@ -149,7 +145,7 @@ mio::IOResult>> set_population_data(const mio::IOResult>> set_synthetic_population_data(mio::oseir::Parameters& params) { - size_t number_regions = 3; + size_t number_regions = 53; std::vector> nodes(number_regions, mio::oseir::Model(int(size_t(params.get_num_groups())))); @@ -158,15 +154,15 @@ set_synthetic_population_data(mio::oseir::Parameters& params) {params.get_num_groups(), mio::oseir::InfectionState::Count}); for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { - population[{i, mio::oseir::InfectionState::Susceptible}] = 10000; + population[{i, mio::oseir::InfectionState::Susceptible}] = 1000000; } for (auto& node : nodes) { node.parameters = params; node.populations = population; } for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { - nodes[0].populations[{i, mio::oseir::InfectionState::Exposed}] = 10; - nodes[0].populations[{i, mio::oseir::InfectionState::Susceptible}] = 9990; + nodes[0].populations[{i, mio::oseir::InfectionState::Exposed}] = 100; + nodes[0].populations[{i, mio::oseir::InfectionState::Susceptible}] = 999900; } return mio::success(nodes); @@ -191,17 +187,22 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double // and mobility between counties mio::Graph>>, mio::MobilityEdge<>> params_graph; + BOOST_OUTCOME_TRY( + auto&& node_ids, + mio::get_node_ids((data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true, + true)); + if (synthetic_population) { BOOST_OUTCOME_TRY(auto&& nodes, set_synthetic_population_data(params)); for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { - params_graph.add_node(node_idx, nodes[node_idx]); + params_graph.add_node(node_ids[node_idx], nodes[node_idx]); } printf("Setting synthetic population successful.\n"); } else { - BOOST_OUTCOME_TRY(auto&& nodes, set_population_data(data_dir, params)); + BOOST_OUTCOME_TRY(auto&& nodes, set_population_data(data_dir, params, node_ids)); for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { - params_graph.add_node(node_idx, nodes[node_idx]); + params_graph.add_node(node_ids[node_idx], nodes[node_idx]); } printf("Setting population from data successful.\n"); } @@ -250,7 +251,7 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double return n.id; }); - auto save_result_status = save_result(result, county_ids, 1, "graph_result.h5"); + auto save_result_status = save_result(result, county_ids, num_age_groups, "graph_result_nrw.h5"); result_graph.nodes()[0].property.get_result().print_table(); result_graph.nodes()[1].property.get_result().print_table(); result_graph.nodes()[2].property.get_result().print_table(); @@ -261,7 +262,7 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double int main() { const auto t0 = 0.; - const auto tmax = 5.; + const auto tmax = 15.; const auto dt = 0.5; //time step of mobility, daily mobility every second step const std::string& data_dir = ""; diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index c3ff687a90..7a2577b517 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -40,9 +40,9 @@ mio::IOResult set_covid_parameters(mio::oseirmobilityimproved::Parameters< params.get>()[mio::AgeGroup(5)] = 0.175; } else { - params.template set>(8.); + params.template set>(8.097612257); - params.template set>(0.07); + params.template set>(0.07333); } printf("Setting epidemiological parameters successful.\n"); @@ -188,22 +188,22 @@ mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Mo printf("Data is not compatible, using synthetic population instead.\n"); for (size_t j = 0; j < number_age_groups; j++) { model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Exposed}] = 10; + mio::oseirmobilityimproved::InfectionState::Exposed}] = 100; model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 9990; + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 999900; for (size_t i = 1; i < number_regions; i++) { model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 1000000; } } } else { BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); - populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), + populations[{mio::oseirmobilityimproved::Region(27), mio::AgeGroup(0), mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; - populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), + populations[{mio::oseirmobilityimproved::Region(27), mio::AgeGroup(0), mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; } BOOST_OUTCOME_TRY(set_mobility_weights(model, data_dir)); @@ -242,7 +242,7 @@ int main() mio::set_log_level(mio::LogLevel::debug); ScalarType t0 = 0.; - ScalarType tmax = 5.; + ScalarType tmax = 15.; ScalarType dt = 0.1; ScalarType number_regions = 53; @@ -279,7 +279,7 @@ int main() // result_from_sim.print_table(); auto save_result_status = - mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_test.h5"); + mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_nrw.h5"); // auto reproduction_numbers = model.get_reproduction_numbers(result_from_sim); // std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index 182c46cc22..4853be89ad 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -90,7 +90,7 @@ class Model : public FlowModel( {region_n, age_i})] += flow_SE_helper * coeffStoI * - y[population.get_flat_index({region_n, age_j, InfectionState::Susceptible})]; + y[population.get_flat_index({region_n, age_i, InfectionState::Susceptible})]; } } for (auto region : make_index_range(n_regions)) { diff --git a/pycode/examples/plot/plotResultsMapNRW.py b/pycode/examples/plot/plotResultsMapNRW.py new file mode 100644 index 0000000000..ff0f5692a2 --- /dev/null +++ b/pycode/examples/plot/plotResultsMapNRW.py @@ -0,0 +1,235 @@ + +import datetime as dt +import os.path + +import numpy as np +import pandas as pd + +import geopandas +from matplotlib.gridspec import GridSpec + +from memilio.epidata import geoModificationGermany as geoger + +import memilio.epidata.getPopulationData as gpd +from memilio.epidata import getDataIntoPandasDataFrame as gd +import memilio.plot.plotMap as pm + +import matplotlib.pyplot as plt +import matplotlib.colors as mcolors + + +def plot_map_nrw(data: pd.DataFrame, + scale_colors: np.array([0, 1]), + legend: list = [], + title: str = '', + plot_colorbar: bool = True, + output_path: str = '', + fig_name: str = 'customPlot', + dpi: int = 300, + outercolor='white', + log_scale=False): + """! Plots region-specific information onto a interactive html map and + returning svg and png image. Allows the comparisons of a variable list of + data sets. + + @param[in] data Data to be plotted. First column must contain regional + specifier, following columns will be plotted for comparison. + @param[in] scale_colors Array of min-max-values to scale colorbar. + @param[in] legend List subtitles for different columns. Can be list of + empty strings. + @param[in] title Title of the plot. + @param[in] plot_colorbar Defines if a colorbar will be plotted. + @param[in] output_path Output path for the figure. + @param[in] fig_name Name of the figure created. + @param[in] dpi Dots-per-inch value for the exported figure. + @param[in] outercolor Background color of the plot image. + @param[in] log_scale Defines if the colorbar is plotted in log scale. + """ + region_classifier = data.columns[0] + region_data = data[region_classifier].to_numpy().astype(int) + + data_columns = data.columns[1:] + # Read and filter map data. + if np.isin(region_data, geoger.get_county_ids()).all(): + try: + map_data = geopandas.read_file( + os.path.join( + os.getcwd(), + 'tools/vg2500_12-31.utm32s.shape/vg2500/VG2500_KRS.shp')) + if '16056' in map_data.ARS.values: + map_data = pm.merge_eisenach(map_data) + # Remove information for plot. + map_data = map_data[['ARS', 'GEN', 'NUTS', 'geometry']] + # Use string values as in shape data file. + data[region_classifier] = data[region_classifier].astype( + 'str').str.zfill(5) + except FileNotFoundError: + pm.print_manual_download( + 'Georeferenzierung: UTM32s, Format: shape (ZIP, 5 MB)', + 'https://gdz.bkg.bund.de/index.php/default/verwaltungsgebiete-1-2-500-000-stand-31-12-vg2500-12-31.html') + else: + raise gd.DataError('Provide shape files regions to be plotted.') + + # Remove regions that are not input data table. + map_data = map_data[map_data.ARS.isin(data[region_classifier])] + + data['new_index'] = map_data.index.array + data = data.set_index('new_index') + + map_data[data_columns] = data.loc[:, data_columns] + + for i in range(len(data_columns)): + if legend[i] == '': + fname = 'data_column_' + str(i) + else: + fname = str(legend[i].replace(' ', '_')) + pm.save_interactive(data[data_columns[i]], os.path.join( + output_path, fname) + '.html', map_data, scale_colors) + + fig = plt.figure(figsize=(3.5 * len(data_columns), 3), facecolor=outercolor) + # Use n+2 many columns (1: legend + 2: empty space + 3-n: data sets) and + # n+2 rows where the top row is used for a potential title, the second row + # for the content and all other rows have height zero. + height_ratios = [0.05, 1, 0] + if len(data_columns) > 1: + height_ratios = height_ratios + [ + 0.0 for i in range(len(data_columns)-1)] + gs = GridSpec( + len(data_columns) + 2, len(data_columns) + 2, figure=fig, + width_ratios=[1 for i in range(len(data_columns))] + [0.1, 0.2], + height_ratios=height_ratios) + + # Use top row for title. + tax = fig.add_subplot(gs[0, :]) + tax.set_axis_off() + tax.set_title(title, fontsize=16) + if plot_colorbar: + # Prepare colorbar. + cax = fig.add_subplot(gs[1, -2]) + + else: + cax = None + + if log_scale: + norm = mcolors.LogNorm(vmin=scale_colors[0], vmax=scale_colors[1]) + + for i in range(len(data_columns)): + + cmap = 'viridis' + ax = fig.add_subplot(gs[1, i]) + if log_scale: + map_data.plot(data_columns[i], ax=ax, legend=False, + norm=norm, cmap=cmap) + + elif cax is not None: + map_data.plot(data_columns[i], ax=ax, cax=cax, legend=True, + vmin=scale_colors[0], vmax=scale_colors[1]) + else: + # Do not plot colorbar. + map_data.plot(data_columns[i], ax=ax, legend=False, + vmin=scale_colors[0], vmax=scale_colors[1]) + + ax.set_title(legend[i], fontsize=12) + ax.set_axis_off() + + sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) + sm.set_array([]) + cbar = fig.colorbar(sm, cax=cax) + cbar.set_ticks([scale_colors[0], scale_colors[1]]) + cbar.set_ticklabels([f'{scale_colors[0]:.4e}', f'{scale_colors[1]:.4e}']) + + plt.subplots_adjust(bottom=0.1) + plt.savefig(os.path.join(output_path, fig_name + '.png'), dpi=dpi) + + +if __name__ == '__main__': + + files_input = {'Data set 1': 'cpp/build/ode_result_nrw', + 'Data set 2': 'cpp/build/graph_result_nrw'} # Result file of equation-based model has to be first + file_format = 'h5' + # Define age groups which will be considered through filtering + # Keep keys and values as well as its assignment constant, remove entries + # if only part of the population should be plotted or considered, e.g., by + # setting: + # age_groups = {1: '5-14', 2: '15-34'} + age_groups = {0: '0-4', 1: '5-14', 2: '15-34', + 3: '35-59', 4: '60-79', 5: '80+'} + if len(age_groups) == 6: + filter_age = None + else: + if file_format == 'json': + filter_age = [val for val in age_groups.values()] + else: + filter_age = ['Group' + str(key) for key in age_groups.keys()] + + relative = True + + date = 14 + + i = 0 + for file in files_input.values(): + # MEmilio backend hdf5 example + if(i == 0): # result file of equation-based model has to be first + df = pm.extract_data( + file, region_spec=None, column=None, date=date, + filters={'Group': filter_age, 'InfectionState': [2]}, + output='matrix', + file_format=file_format) + df['Group'] = df.Group.str.extract('(\d+)') + df['Group'] = df['Group'].apply(pd.to_numeric, errors='coerce') + # df['Region'] = df['Group'] + df['Region'] = (df['Group']-1) // len(age_groups) + df = df.groupby(['Region'], as_index=False).agg({'Count': "sum"}) + + ids = geoger.get_county_ids() + ids = [id for id in ids if str(id).startswith('5')] + # ids = [5111, 5112, 5113] + + if len(ids) != len(df): + raise gd.DataError("Data is not compatible with number of NRW counties.") + + df['Region'] = ids + else: + df = pm.extract_data( + file, region_spec=None, column=None, date=date, + filters={'Group': filter_age, 'InfectionState': [2]}, + file_format=file_format) + + df = df.apply(pd.to_numeric, errors='coerce') + + if relative: + + try: + population = pd.read_json( + 'data/pydata/Germany/county_current_population.json') + # pandas>1.5 raise FileNotFoundError instead of ValueError + except (ValueError, FileNotFoundError): + print("Population data was not found. Download it from the internet.") + population = gpd.get_population_data( + read_data=False, file_format=file_format, + out_folder='data/pydata/Germany/', no_raw=True, + merge_eisenach=True) + + # For fitting of different age groups we need format ">X". + age_group_values = list(age_groups.values()) + age_group_values[-1] = age_group_values[-1].replace('80+', '>79') + # scale data + df = pm.scale_dataframe_relative(df, age_group_values, population) + + if i == 0: + dfs_all = pd.DataFrame(df.iloc[:, 0]) + + dfs_all[df.columns[-1] + ' ' + str(i)] = df[df.columns[-1]] + i += 1 + + min_val = dfs_all[dfs_all.columns[1:]].min().min() + max_val = dfs_all[dfs_all.columns[1:]].max().max() + + plot_map_nrw( + dfs_all, scale_colors=[min_val, max_val], + legend=['', ''], + title='NRW - Simulation Day 10', plot_colorbar=True, + output_path=os.path.dirname(__file__), + fig_name='NRWPlot', dpi=300, + outercolor='white', + log_scale=True) diff --git a/pycode/memilio-epidata/memilio/epidata/getNRWCounties.py b/pycode/memilio-epidata/memilio/epidata/getNRWCounties.py new file mode 100644 index 0000000000..a2c04550df --- /dev/null +++ b/pycode/memilio-epidata/memilio/epidata/getNRWCounties.py @@ -0,0 +1,54 @@ +import os + +import numpy as np +import pandas as pd + +from memilio.epidata import geoModificationGermany as geoger +from memilio.epidata import getDataIntoPandasDataFrame as gd + +def main(): + """! Main program entry.""" + + arg_dict = gd.cli("commuter_official") + + directory = arg_dict['out_folder'].split('/pydata')[0] + directory_mobility = os.path.join(directory, 'mobility/') + directory_population = os.path.join(directory, 'pydata/Germany/') + mobility_file = 'commuter_mobility' + population_file = 'county_current_population' + + mobility_matrix = pd.read_csv( + os.path.join(directory_mobility + mobility_file + '.txt'), + sep=' ', header=None) + + # get county and state IDs + countyIDs = geoger.get_county_ids() + stateIDs = geoger.get_state_ids() + # get state ID to county ID map + stateID_to_countyID = geoger.get_stateid_to_countyids_map() + + # iterate over state_to_county map and replace IDs by numbering 0, ..., n + state_indices = [] + county_indices = [] + for state, counties in stateID_to_countyID.items(): + state_indices.append(stateIDs.index(state)) + county_indices.append( + np.array([countyIDs.index(county) for county in counties])) + + mobility_matrix_nrw = mobility_matrix.loc[county_indices[4], county_indices[4]] + + gd.write_dataframe( + mobility_matrix_nrw, directory_mobility, mobility_file + '_nrw', 'txt', + param_dict={'sep': ' ', 'header': None, 'index': False}) + + population = pd.read_json(os.path.join(directory_population + population_file + '.json')) + population_nrw = population.loc[county_indices[4]] + gd.write_dataframe(population_nrw, directory_population, population_file + '_nrw', 'json') + + + + + +if __name__ == "__main__": + + main() From f49a4976efc2d1bbae370e7f6e6e43aacb1e7e0c Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:10:51 +0100 Subject: [PATCH 39/87] add timing example --- cpp/examples/ode_seir_mobility_timing.cpp | 180 ++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 cpp/examples/ode_seir_mobility_timing.cpp diff --git a/cpp/examples/ode_seir_mobility_timing.cpp b/cpp/examples/ode_seir_mobility_timing.cpp new file mode 100644 index 0000000000..55d568fd24 --- /dev/null +++ b/cpp/examples/ode_seir_mobility_timing.cpp @@ -0,0 +1,180 @@ +/* +* Copyright (C) 2020-2024 MEmilio +* +* Authors: Carlotta Gerstein +* +* Contact: Martin J. Kuehn +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "memilio/compartments/simulation.h" +#include "memilio/math/euler.h" +#include "memilio/utils/custom_index_array.h" +#include "models/ode_seir_mobility_improved/infection_state.h" +#include "models/ode_seir_mobility_improved/model.h" +#include "models/ode_seir_mobility_improved/parameters.h" +#include "models/ode_seir_mobility_improved/regions.h" + +#include + +template +void set_contact_matrix(mio::oseirmobilityimproved::Model& model) +{ + Eigen::MatrixXd contact_matrix_eigen(6, 6); + contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, 0.0161, + 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, 0.0458, 0.1939, + 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; + mio::ContactMatrixGroup& contact_matrix = + model.parameters.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline() = contact_matrix_eigen; +} + +/** + * Set epidemiological parameters of Sars-CoV-2 for a immune-naive + * population and wild type variant. + * @param params Object that the parameters will be added to. + * @returns Currently generates no errors. + */ +void set_covid_parameters(mio::oseirmobilityimproved::Parameters& params) +{ + params.template set>(3.335); + + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; +} + +template +void set_mobility_weights(mio::oseirmobilityimproved::Model& model) +{ + size_t number_regions = (size_t)model.parameters.get_num_regions(); + double fraction_commuter = 1. / (2 * number_regions); + Eigen::MatrixXd mobility_data_commuter = + Eigen::MatrixXd::Constant(number_regions, number_regions, fraction_commuter) - + fraction_commuter * + Eigen::MatrixXd::Identity(number_regions, number_regions); // Ensure that the diagonal is zero + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); + } + model.parameters.template get>() + .get_cont_freq_mat()[0] + .get_baseline() = mobility_data_commuter; +} + +template +void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) +{ + auto& populations = model.populations; + auto& parameters = model.parameters; + + size_t number_regions = (size_t)parameters.get_num_regions(); + size_t number_age_groups = (size_t)parameters.get_num_agegroups(); + for (size_t j = 0; j < number_age_groups; j++) { + model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), + mio::oseirmobilityimproved::InfectionState::Exposed}] = 100; + model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 999900; + for (size_t i = 1; i < number_regions; i++) { + model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), + mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; + model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 1000000; + } + } + set_mobility_weights(model); + + set_contact_matrix(model); + + set_covid_parameters(parameters); + + mio::ContactMatrixGroup& commuting_strengths = + parameters.template get>().get_cont_freq_mat(); + + auto& population_after_commuting = model.m_population_after_commuting; + for (size_t region_n = 0; region_n < number_regions; ++region_n) { + for (size_t age = 0; age < number_age_groups; ++age) { + double population_n = 0; + for (size_t state = 0; state < (size_t)mio::oseirmobilityimproved::InfectionState::Count; state++) { + population_n += populations[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), + mio::oseirmobilityimproved::InfectionState(state)}]; + } + population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += + population_n; + for (size_t region_m = 0; region_m < number_regions; ++region_m) { + population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= + commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; + population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += + commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; + } + } + } +} + +void simulate(size_t num_warm_up_runs, size_t num_runs, ScalarType tmax) +{ + ScalarType t0 = 0.; + ScalarType dt = 0.1; + + constexpr size_t number_regions = NUM_REGIONS; + std::vector region_ids(number_regions); + iota(region_ids.begin(), region_ids.end(), 1); + ScalarType number_age_groups = 6; + + mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); + set_parameters_and_population(model); + + // using DefaultIntegratorCore = + // mio::ControlledStepperWrapper; + + std::shared_ptr> integrator = std::make_shared>(); + + std::cout << "{ \"Regions\": " << number_regions << ", " << std::endl; + + // Warm up runs. + for (size_t i = 0; i < num_warm_up_runs; i++) { + simulate(t0, tmax, dt, model, integrator); + } + + // Runs with timing. + ScalarType total = 0; + for (size_t i = 0; i < num_runs; i++) { + total -= omp_get_wtime(); + auto result_from_sim = simulate(t0, tmax, dt, model, integrator); + total += omp_get_wtime(); + } + std::cout << "\"Time\": " << total / num_runs << "\n}," << std::endl; +} + +int main(int argc, char** argv) +{ + const ScalarType tmax = 2; + size_t warm_up = 10; + size_t num_runs = 100; + if (argc > 2) { + warm_up = std::stod(argv[1]); + num_runs = std::stod(argv[2]); + } + simulate(warm_up, num_runs, tmax); + return 0; +} From 64744ab5b4d11baee354743dc4e9617c0da4f013 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:24:54 +0100 Subject: [PATCH 40/87] cmake changes for timing --- cpp/examples/CMakeLists.txt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 733ca7cf47..09df245e27 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -38,9 +38,16 @@ add_executable(ode_seir_mobility_example ode_seir_mobility.cpp) target_link_libraries(ode_seir_mobility_example PRIVATE memilio ode_seir_mobility) target_compile_options(ode_seir_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -# add_executable(ode_seir_mobility_example_massaction ode_seir_mobility_massaction.cpp) -# target_link_libraries(ode_seir_mobility_example_massaction PRIVATE memilio ode_seir_mobility_massaction) -# target_compile_options(ode_seir_mobility_example_massaction PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +if (MEMILIO_ENABLE_OPENMP) + if(NOT DEFINED NUM_REGIONS) + set(NUM_REGIONS "42") + endif() + add_definitions(-DNUM_REGIONS=${NUM_REGIONS}) + + add_executable(ode_seir_mobility_example_timing ode_seir_mobility_timing.cpp) + target_link_libraries(ode_seir_mobility_example_timing PRIVATE memilio ode_seir_mobility_improved) + target_compile_options(ode_seir_mobility_example_timing PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +endif() add_executable(ode_seir_mobility_example_improved ode_seir_mobility_improved.cpp) target_link_libraries(ode_seir_mobility_example_improved PRIVATE memilio ode_seir_mobility_improved) From a26210457da6d391010d81776d5c583e94228a3c Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Fri, 13 Dec 2024 15:52:44 +0100 Subject: [PATCH 41/87] fix bug for measuring runtimes and graph timing example --- cpp/examples/CMakeLists.txt | 17 +-- cpp/examples/graph_timing.cpp | 154 ++++++++++++++++++++++ cpp/examples/ode_seir_mobility_timing.cpp | 22 ++-- 3 files changed, 173 insertions(+), 20 deletions(-) create mode 100644 cpp/examples/graph_timing.cpp diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 09df245e27..aac77c0dbc 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -39,14 +39,9 @@ target_link_libraries(ode_seir_mobility_example PRIVATE memilio ode_seir_mobilit target_compile_options(ode_seir_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) if (MEMILIO_ENABLE_OPENMP) - if(NOT DEFINED NUM_REGIONS) - set(NUM_REGIONS "42") - endif() - add_definitions(-DNUM_REGIONS=${NUM_REGIONS}) - - add_executable(ode_seir_mobility_example_timing ode_seir_mobility_timing.cpp) - target_link_libraries(ode_seir_mobility_example_timing PRIVATE memilio ode_seir_mobility_improved) - target_compile_options(ode_seir_mobility_example_timing PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(ode_seir_mobility_timing ode_seir_mobility_timing.cpp) + target_link_libraries(ode_seir_mobility_timing PRIVATE memilio ode_seir_mobility_improved) + target_compile_options(ode_seir_mobility_timing PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) endif() add_executable(ode_seir_mobility_example_improved ode_seir_mobility_improved.cpp) @@ -111,6 +106,12 @@ add_executable(graph_example_extended graph_extended.cpp) target_link_libraries(graph_example_extended PRIVATE memilio ode_seir) target_compile_options(graph_example_extended PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +if (MEMILIO_ENABLE_OPENMP) + add_executable(graph_timing graph_timing.cpp) + target_link_libraries(graph_timing PRIVATE memilio ode_seir) + target_compile_options(graph_timing PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +endif() + add_executable(graph_stochastic_mobility_example graph_stochastic_mobility.cpp) target_link_libraries(graph_stochastic_mobility_example PRIVATE memilio ode_secir) target_compile_options(graph_stochastic_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/examples/graph_timing.cpp b/cpp/examples/graph_timing.cpp new file mode 100644 index 0000000000..62c04f7eab --- /dev/null +++ b/cpp/examples/graph_timing.cpp @@ -0,0 +1,154 @@ + +#include "ode_seir/model.h" +#include "ode_seir/infection_state.h" +#include "ode_seir/parameters.h" +#include "memilio/mobility/metapopulation_mobility_instant.h" +#include "memilio/compartments/simulation.h" + +#include + +void set_contact_matrices(mio::oseir::Parameters& params) +{ + Eigen::MatrixXd contact_matrix_eigen(6, 6); + contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, 0.0161, + 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, 0.0458, 0.1939, + 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; + mio::ContactMatrixGroup& contact_matrix = params.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline() = contact_matrix_eigen; +} + +/** + * Set epidemiological parameters of Sars-CoV-2 for a immune-naive + * population and wild type variant. + * @param params Object that the parameters will be added to. + * @returns Currently generates no errors. + */ +void set_covid_parameters(mio::oseir::Parameters& params) +{ + params.template set>(3.335); + + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; +} + +void set_population_data(mio::oseir::Parameters& params, + mio::Graph>>, + mio::MobilityEdge<>>& params_graph, + size_t number_regions) +{ + std::vector> nodes(number_regions, + mio::oseir::Model(int(size_t(params.get_num_groups())))); + + mio::Populations population( + {params.get_num_groups(), mio::oseir::InfectionState::Count}); + + for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { + population[{i, mio::oseir::InfectionState::Susceptible}] = 1000000; + } + for (auto& node : nodes) { + node.parameters = params; + node.populations = population; + } + for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { + nodes[0].populations[{i, mio::oseir::InfectionState::Exposed}] = 100; + nodes[0].populations[{i, mio::oseir::InfectionState::Susceptible}] = 999900; + } + + for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { + params_graph.add_node(node_idx, nodes[node_idx]); + } +} + +void set_parameters_and_population(mio::Graph>>, + mio::MobilityEdge<>>& params_graph, + size_t number_regions) +{ + const int num_age_groups = 6; + + mio::oseir::Parameters params(num_age_groups); + + set_covid_parameters(params); + + // set contact matrix + set_contact_matrices(params); + + set_population_data(params, params_graph, number_regions); + + for (size_t county_idx_i = 0; county_idx_i < params_graph.nodes().size(); ++county_idx_i) { + for (size_t county_idx_j = 0; county_idx_j < params_graph.nodes().size(); ++county_idx_j) { + double commuter_coeff_ij = 1. / (2 * number_regions); + if (county_idx_i == county_idx_j) { + commuter_coeff_ij = 0; + } + params_graph.add_edge( + county_idx_i, county_idx_j, + Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count * size_t(params.get_num_groups()), + commuter_coeff_ij)); + } + } + + for (auto& node : params_graph.nodes()) { + node.property.get_simulation().set_integrator(std::make_shared>()); + } +} + +void simulate(size_t num_warm_up_runs, size_t num_runs, size_t number_regions, ScalarType tmax) +{ + ScalarType t0 = 0.; + ScalarType dt = 0.1; + + mio::Graph>>, mio::MobilityEdge<>> params_graph; + + set_parameters_and_population(params_graph, number_regions); + + // using DefaultIntegratorCore = + // mio::ControlledStepperWrapper; + + std::shared_ptr> integrator = std::make_shared>(); + + std::cout << "{ \"Regions\": " << number_regions << ", " << std::endl; + + // Warm up runs. + for (size_t i = 0; i < num_warm_up_runs; i++) { + auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); + sim.advance(tmax); + } + + // Runs with timing. + ScalarType total = 0; + for (size_t i = 0; i < num_runs; i++) { + auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); + total -= omp_get_wtime(); + sim.advance(tmax); + total += omp_get_wtime(); + auto result_graph = std::move(sim).get_graph(); + result_graph.nodes()[0].property.get_result().print_table(); + } + std::cout << "\"Time\": " << total / num_runs << "\n}," << std::endl; +} + +int main(int argc, char** argv) +{ + const ScalarType tmax = 20; + size_t warm_up = 10; + size_t num_runs = 100; + size_t num_regions = 10; + if (argc > 3) { + warm_up = std::stod(argv[1]); + num_runs = std::stod(argv[2]); + num_regions = std::stod(argv[3]); + } + simulate(warm_up, num_runs, num_regions, tmax); + return 0; +} diff --git a/cpp/examples/ode_seir_mobility_timing.cpp b/cpp/examples/ode_seir_mobility_timing.cpp index 55d568fd24..f74fe37404 100644 --- a/cpp/examples/ode_seir_mobility_timing.cpp +++ b/cpp/examples/ode_seir_mobility_timing.cpp @@ -131,14 +131,10 @@ void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) } } -void simulate(size_t num_warm_up_runs, size_t num_runs, ScalarType tmax) +void simulate(size_t num_warm_up_runs, size_t num_runs, size_t number_regions, ScalarType tmax) { - ScalarType t0 = 0.; - ScalarType dt = 0.1; - - constexpr size_t number_regions = NUM_REGIONS; - std::vector region_ids(number_regions); - iota(region_ids.begin(), region_ids.end(), 1); + ScalarType t0 = 0.; + ScalarType dt = 0.1; ScalarType number_age_groups = 6; mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); @@ -168,13 +164,15 @@ void simulate(size_t num_warm_up_runs, size_t num_runs, ScalarType tmax) int main(int argc, char** argv) { - const ScalarType tmax = 2; + const ScalarType tmax = 20; size_t warm_up = 10; size_t num_runs = 100; - if (argc > 2) { - warm_up = std::stod(argv[1]); - num_runs = std::stod(argv[2]); + size_t num_regions = 10; + if (argc > 3) { + warm_up = std::stod(argv[1]); + num_runs = std::stod(argv[2]); + num_regions = std::stod(argv[3]); } - simulate(warm_up, num_runs, tmax); + simulate(warm_up, num_runs, num_regions, tmax); return 0; } From 565141c6bf6e4e94c401ee0b85bf5c390b103acf Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Fri, 13 Dec 2024 21:04:02 +0100 Subject: [PATCH 42/87] fix bug for graph timing --- cpp/examples/graph_timing.cpp | 51 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/cpp/examples/graph_timing.cpp b/cpp/examples/graph_timing.cpp index 62c04f7eab..692df8b4b4 100644 --- a/cpp/examples/graph_timing.cpp +++ b/cpp/examples/graph_timing.cpp @@ -103,7 +103,7 @@ void set_parameters_and_population(mio::Graph; + auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); + auto start_time = omp_get_wtime(); + sim.advance(tmax); + auto end_time = omp_get_wtime(); - std::shared_ptr> integrator = std::make_shared>(); + return end_time - start_time; +} - std::cout << "{ \"Regions\": " << number_regions << ", " << std::endl; +int main(int argc, char** argv) +{ + const ScalarType tmax = 1; + size_t warm_up = 1; + size_t num_runs = 2; + size_t num_regions = 5; + if (argc > 3) { + warm_up = std::stod(argv[1]); + num_runs = std::stod(argv[2]); + num_regions = std::stod(argv[3]); + } + std::cout << "{ \"Regions\": " << num_regions << ", " << std::endl; // Warm up runs. - for (size_t i = 0; i < num_warm_up_runs; i++) { - auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); - sim.advance(tmax); + for (size_t i = 0; i < warm_up; i++) { + double warm_up_time = simulate(num_regions, tmax); + mio::unused(warm_up_time); } // Runs with timing. ScalarType total = 0; for (size_t i = 0; i < num_runs; i++) { - auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); - total -= omp_get_wtime(); - sim.advance(tmax); - total += omp_get_wtime(); - auto result_graph = std::move(sim).get_graph(); - result_graph.nodes()[0].property.get_result().print_table(); + double run_time = simulate(num_regions, tmax); + total += run_time; } std::cout << "\"Time\": " << total / num_runs << "\n}," << std::endl; -} -int main(int argc, char** argv) -{ - const ScalarType tmax = 20; - size_t warm_up = 10; - size_t num_runs = 100; - size_t num_regions = 10; - if (argc > 3) { - warm_up = std::stod(argv[1]); - num_runs = std::stod(argv[2]); - num_regions = std::stod(argv[3]); - } - simulate(warm_up, num_runs, num_regions, tmax); return 0; } From 9f36912859295ce12496f37ecad5cb40a5d877bb Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 16 Dec 2024 21:29:25 +0100 Subject: [PATCH 43/87] fix things for runtime measurements --- cpp/examples/graph_timing.cpp | 13 +++++++------ cpp/examples/ode_seir_mobility_timing.cpp | 5 ++--- cpp/memilio/compartments/simulation.h | 9 ++++++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/cpp/examples/graph_timing.cpp b/cpp/examples/graph_timing.cpp index 692df8b4b4..3f6d2ae172 100644 --- a/cpp/examples/graph_timing.cpp +++ b/cpp/examples/graph_timing.cpp @@ -106,13 +106,14 @@ void set_parameters_and_population(mio::Graph>>, mio::MobilityEdge<>> params_graph; set_parameters_and_population(params_graph, number_regions); - auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); + auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); + mio::set_log_level(mio::LogLevel::off); auto start_time = omp_get_wtime(); sim.advance(tmax); auto end_time = omp_get_wtime(); @@ -122,10 +123,10 @@ double simulate(size_t number_regions, ScalarType tmax) int main(int argc, char** argv) { - const ScalarType tmax = 1; - size_t warm_up = 1; - size_t num_runs = 2; - size_t num_regions = 5; + const ScalarType tmax = 20; + size_t warm_up = 10; + size_t num_runs = 100; + size_t num_regions = 10; if (argc > 3) { warm_up = std::stod(argv[1]); num_runs = std::stod(argv[2]); diff --git a/cpp/examples/ode_seir_mobility_timing.cpp b/cpp/examples/ode_seir_mobility_timing.cpp index f74fe37404..17c080884e 100644 --- a/cpp/examples/ode_seir_mobility_timing.cpp +++ b/cpp/examples/ode_seir_mobility_timing.cpp @@ -155,9 +155,8 @@ void simulate(size_t num_warm_up_runs, size_t num_runs, size_t number_regions, S // Runs with timing. ScalarType total = 0; for (size_t i = 0; i < num_runs; i++) { - total -= omp_get_wtime(); - auto result_from_sim = simulate(t0, tmax, dt, model, integrator); - total += omp_get_wtime(); + double runtime = simulate(t0, tmax, dt, model, integrator); + total += runtime; } std::cout << "\"Time\": " << total / num_runs << "\n}," << std::endl; } diff --git a/cpp/memilio/compartments/simulation.h b/cpp/memilio/compartments/simulation.h index 8b3307f87f..23a627d7f9 100644 --- a/cpp/memilio/compartments/simulation.h +++ b/cpp/memilio/compartments/simulation.h @@ -26,6 +26,8 @@ #include "memilio/math/stepper_wrapper.h" #include "memilio/utils/time_series.h" +#include + namespace mio { @@ -213,16 +215,17 @@ using is_compartment_model_simulation = * @tparam Sim A Simulation that can simulate the model. */ template > -TimeSeries simulate(FP t0, FP tmax, FP dt, Model const& model, - std::shared_ptr> integrator = nullptr) +double simulate(FP t0, FP tmax, FP dt, Model const& model, std::shared_ptr> integrator = nullptr) { model.check_constraints(); Sim sim(model, t0, dt); if (integrator) { sim.set_integrator(integrator); } + double start_time = omp_get_wtime(); sim.advance(tmax); - return sim.get_result(); + double end_time = omp_get_wtime(); + return end_time - start_time; } } // namespace mio From ee57c8f82ef7242aba3e196056dfaf16025d7f9d Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:38:45 +0100 Subject: [PATCH 44/87] add plotfiles, small correction in the model and maybe optimizations --- cpp/models/ode_seir_mobility_improved/model.h | 63 ++++++----- tools/plot_mobility_runtimes.py | 99 ++++++++++++++++ .../plot_results_mobility.py | 107 ++++++++++++------ 3 files changed, 204 insertions(+), 65 deletions(-) create mode 100644 tools/plot_mobility_runtimes.py rename pycode/examples/plot/plotResultsMapNRW.py => tools/plot_results_mobility.py (78%) diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index 4853be89ad..470266fe5e 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -57,49 +57,56 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t); const Index n_age_groups = reduce_index>(params.get_num_agegroups()); const Index n_regions = reduce_index>(params.get_num_regions()); - for (auto age_i : make_index_range(n_age_groups)) { - for (auto age_j : make_index_range(n_age_groups)) { + for (size_t age_i = 0; age_i < (size_t)n_age_groups; age_i++) { + for (size_t age_j = 0; age_j < (size_t)n_age_groups; age_j++) { Eigen::VectorXd infectives_per_region = Eigen::VectorXd::Zero((size_t)n_regions); - for (auto region_n : make_index_range(n_regions)) { - for (auto region_m : make_index_range(n_regions)) { - infectives_per_region(region_n.get()) += - commuting_strengths(region_m.get(), region_n.get()) * - pop[population.get_flat_index({region_m, age_j, InfectionState::Infected})]; + for (size_t region_n = 0; region_n < (size_t)n_regions; region_n++) { + for (size_t region_m = 0; region_m < (size_t)n_regions; region_m++) { + infectives_per_region(region_n) += + commuting_strengths(region_m, region_n) * + pop[population.get_flat_index( + {Region(region_m), AgeGroup(age_j), InfectionState::Infected})]; } } - for (auto region_n : make_index_range(n_regions)) { + for (size_t region_n = 0; region_n < (size_t)n_regions; region_n++) { FP flow_SE_helper = 0; - const size_t Sj = population.get_flat_index({region_n, age_j, InfectionState::Susceptible}); - const size_t Ej = population.get_flat_index({region_n, age_j, InfectionState::Exposed}); - const size_t Ij = population.get_flat_index({region_n, age_j, InfectionState::Infected}); - const size_t Rj = population.get_flat_index({region_n, age_j, InfectionState::Recovered}); + const size_t Ej = + population.get_flat_index({Region(region_n), AgeGroup(age_j), InfectionState::Exposed}); + const size_t Ij = + population.get_flat_index({Region(region_n), AgeGroup(age_j), InfectionState::Infected}); + const size_t Rj = + population.get_flat_index({Region(region_n), AgeGroup(age_j), InfectionState::Recovered}); + const size_t Sj = + population.get_flat_index({Region(region_n), AgeGroup(age_j), InfectionState::Susceptible}); const double Nj_inv = 1.0 / (pop[Sj] + pop[Ej] + pop[Ij] + pop[Rj]); - double coeffStoI = 0.5 * - params.template get>().get_cont_freq_mat().get_matrix_at(t)( - age_i.get(), age_j.get()) * - params.template get>()[age_i]; + double coeffStoI = + 0.5 * + params.template get>().get_cont_freq_mat().get_matrix_at(t)(age_i, age_j) * + params.template get>()[AgeGroup(age_i)]; flow_SE_helper += - pop[population.get_flat_index({region_n, age_j, InfectionState::Infected})] * Nj_inv; - for (auto region_m : make_index_range(n_regions)) { - flow_SE_helper += commuting_strengths(region_n.get(), region_m.get()) * - infectives_per_region(region_m.get()) / - m_population_after_commuting[{region_n, age_j}]; + pop[population.get_flat_index({Region(region_n), AgeGroup(age_j), InfectionState::Infected})] * + Nj_inv; + for (size_t region_m = 0; region_m < (size_t)n_regions; region_m++) { + flow_SE_helper += commuting_strengths(region_n, region_m) * infectives_per_region(region_m) / + m_population_after_commuting[{Region(region_m), AgeGroup(age_j)}]; } flows[Base::template get_flat_flow_index( - {region_n, age_i})] += + {Region(region_n), AgeGroup(age_i)})] += flow_SE_helper * coeffStoI * - y[population.get_flat_index({region_n, age_i, InfectionState::Susceptible})]; + y[population.get_flat_index({Region(region_n), AgeGroup(age_i), InfectionState::Susceptible})]; } } - for (auto region : make_index_range(n_regions)) { + for (size_t region = 0; region < (size_t)n_regions; region++) { flows[Base::template get_flat_flow_index( - {region, age_i})] = (1.0 / params.template get>()[age_i]) * - y[population.get_flat_index({region, age_i, InfectionState::Exposed})]; + {Region(region), AgeGroup(age_i)})] = + (1.0 / params.template get>()[AgeGroup(age_i)]) * + y[population.get_flat_index({Region(region), AgeGroup(age_i), InfectionState::Exposed})]; flows[Base::template get_flat_flow_index( - {region, age_i})] = (1.0 / params.template get>()[age_i]) * - y[population.get_flat_index({region, age_i, InfectionState::Infected})]; + {Region(region), AgeGroup(age_i)})] = + (1.0 / params.template get>()[AgeGroup(age_i)]) * + y[population.get_flat_index({Region(region), AgeGroup(age_i), InfectionState::Infected})]; } } } diff --git a/tools/plot_mobility_runtimes.py b/tools/plot_mobility_runtimes.py new file mode 100644 index 0000000000..437f34149c --- /dev/null +++ b/tools/plot_mobility_runtimes.py @@ -0,0 +1,99 @@ +import matplotlib.pyplot as plt +import pandas as pd + +import os +import json +import re + +colors = ["tab:blue", "tab:orange", "tab:green", + "tab:red", "tab:purple", "tab:brown"] +fontsize_labels = 16 +fontsize_legends = 12 + +models = ['Equation-based model', 'Graph-based model'] + +def plot_runtime(file, name=''): + fig = plt.figure() + df = pd.read_json(file) + + plt.plot(df["Regions"], df["Time"], + linestyle='--', marker='o', linewidth=1.2) + plt.ylim(bottom=0.) + plt.xlim(left=0., right=df["Regions"].max()+1) + plt.xlabel('Number of regions', fontsize=fontsize_labels) + plt.ylabel('Run time [seconds]', fontsize=fontsize_labels) + plt.yticks(fontsize=fontsize_legends) + plt.xticks(fontsize=fontsize_legends) + plt.grid(True, linestyle='--') + plt.tight_layout() + + plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') + name = os.path.splitext(os.path.basename(file))[0] + plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) + +def compare_runtimes(files, name='', title='', models=[]): + merged_df = pd.DataFrame() + i = 0 + for file in files: + df = pd.read_json(file) + + df.rename(columns={'Time': models[i]}, inplace=True) + + if merged_df.empty: + merged_df = df + else: + merged_df = pd.merge(merged_df, df, on='Regions', how='outer') + i = i+1 + + merged_df = merged_df.set_index('Regions') + for column in merged_df.columns: + # plt.plot(merged_df['Regions'], column, + # linestyle='--', marker='o', linewidth=1.2) + plt.plot(merged_df.index, merged_df[column], label=column, + linestyle='--', marker='o', linewidth=1.2) + plt.ylim(bottom=0.) + plt.xlim(left=merged_df.index.min()-1, right=merged_df.index.max()+1) + plt.xlabel('Number of regions', fontsize=fontsize_labels) + plt.ylabel('Run time [seconds]', fontsize=fontsize_labels) + plt.yticks(fontsize=fontsize_legends) + plt.xticks(fontsize=fontsize_legends) + plt.grid(True, linestyle='--') + plt.legend() + plt.title(title) + plt.tight_layout() + + plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') + plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) + plt.close() + +if __name__ == "__main__": + result_dir = os.path.join(os.path.dirname(__file__), '../results') + + result_equationbased_start = os.path.join(result_dir, 'timing_equationbased_start.json') + result_equationbased = os.path.join(result_dir, 'timing_equationbased.json') + result_equationbased_O3 = os.path.join(result_dir, 'timing_equationbased_O3.json') + result_equationbased_O2 = os.path.join(result_dir, 'timing_equationbased_O2.json') + result_equationbased_O1 = os.path.join(result_dir, 'timing_equationbased_O1.json') + result_equationbased_O0 = os.path.join(result_dir, 'timing_equationbased_O0.json') + result_graphbased_start = os.path.join(result_dir, 'timing_graphbased_start.json') + result_graphbased = os.path.join(result_dir, 'timing_graphbased.json') + result_graphbased_smallsteps = os.path.join(result_dir, 'timing_graphbased_01steps.json') + result_graphbased_unoptimized = os.path.join(result_dir, 'timing_graphbased_unoptimized.json') + + result_equationbased_mod4_0 = os.path.join(result_dir, 'timing_equationbased_mod4_0.json') + result_equationbased_mod4_1 = os.path.join(result_dir, 'timing_equationbased_mod4_1.json') + result_equationbased_mod4_2 = os.path.join(result_dir, 'timing_equationbased_mod4_2.json') + result_equationbased_mod4_3 = os.path.join(result_dir, 'timing_equationbased_mod4_3.json') + + results_start = [result_equationbased_start, result_graphbased_start] + results = [result_equationbased, result_graphbased, result_graphbased_smallsteps] + results_unoptimized = [result_equationbased_O3, result_equationbased_O2, result_equationbased_O1, result_equationbased_O0] + results_mod4 = [result_equationbased_mod4_0, result_equationbased_mod4_1, result_equationbased_mod4_2, result_equationbased_mod4_3] + + # plot_runtime(result_equationbased) + # plot_runtime(result_graphbased) + + # compare_runtimes(results_start,name='compare_runtimes_start', title='Runtimes for Euler Method', models=models) + compare_runtimes(results, name='compare_runtimes', title='Runtimes for Euler Method', models=['Equation-based model', 'Graph-based model', 'Graph-based model with dt=0.1']) + compare_runtimes(results_unoptimized, name='compare_runtimes_unoptimized', title='Runtimes for Euler Method', models=['-O3', '-O2', '-O1', '-O0']) + compare_runtimes(results_mod4, name='compare_runtimes_mod4', title='Runtimes for Euler Method', models=['%4=0', '%4=1', '%4=2', '%4=3']) diff --git a/pycode/examples/plot/plotResultsMapNRW.py b/tools/plot_results_mobility.py similarity index 78% rename from pycode/examples/plot/plotResultsMapNRW.py rename to tools/plot_results_mobility.py index ff0f5692a2..99854994ae 100644 --- a/pycode/examples/plot/plotResultsMapNRW.py +++ b/tools/plot_results_mobility.py @@ -1,6 +1,7 @@ import datetime as dt import os.path +import h5py import numpy as np import pandas as pd @@ -17,6 +18,11 @@ import matplotlib.pyplot as plt import matplotlib.colors as mcolors +compartments = {'Susceptible': 0, + 'Exposed': 1, + 'Infected': 2, + 'Recovered': 3} + def plot_map_nrw(data: pd.DataFrame, scale_colors: np.array([0, 1]), @@ -115,7 +121,7 @@ def plot_map_nrw(data: pd.DataFrame, for i in range(len(data_columns)): - cmap = 'viridis' + cmap = 'inferno' ax = fig.add_subplot(gs[1, i]) if log_scale: map_data.plot(data_columns[i], ax=ax, legend=False, @@ -140,35 +146,33 @@ def plot_map_nrw(data: pd.DataFrame, plt.subplots_adjust(bottom=0.1) plt.savefig(os.path.join(output_path, fig_name + '.png'), dpi=dpi) - - -if __name__ == '__main__': - - files_input = {'Data set 1': 'cpp/build/ode_result_nrw', - 'Data set 2': 'cpp/build/graph_result_nrw'} # Result file of equation-based model has to be first - file_format = 'h5' - # Define age groups which will be considered through filtering - # Keep keys and values as well as its assignment constant, remove entries - # if only part of the population should be plotted or considered, e.g., by - # setting: - # age_groups = {1: '5-14', 2: '15-34'} + plt.close() + +def plot_maps(files, output_dir, name=''): + + for date in range(10, 50, 10): + dfs_all = extract_nrw_data_and_combine(files=files, date=date) + + min_val = dfs_all[dfs_all.columns[1:]].min().min() + max_val = dfs_all[dfs_all.columns[1:]].max().max() + + plot_map_nrw( + dfs_all, scale_colors=[min_val, max_val], + legend=['', ''], + title='NRW - Simulation Day '+str(date), plot_colorbar=True, + output_path=output_dir, + fig_name=name+str(date), dpi=900, + outercolor='white', + log_scale=True) + +def extract_nrw_data_and_combine(files, date): age_groups = {0: '0-4', 1: '5-14', 2: '15-34', 3: '35-59', 4: '60-79', 5: '80+'} - if len(age_groups) == 6: - filter_age = None - else: - if file_format == 'json': - filter_age = [val for val in age_groups.values()] - else: - filter_age = ['Group' + str(key) for key in age_groups.keys()] - + filter_age = None relative = True - date = 14 - i = 0 - for file in files_input.values(): - # MEmilio backend hdf5 example + for file in files.values(): if(i == 0): # result file of equation-based model has to be first df = pm.extract_data( file, region_spec=None, column=None, date=date, @@ -194,7 +198,7 @@ def plot_map_nrw(data: pd.DataFrame, file, region_spec=None, column=None, date=date, filters={'Group': filter_age, 'InfectionState': [2]}, file_format=file_format) - + df = df.apply(pd.to_numeric, errors='coerce') if relative: @@ -222,14 +226,43 @@ def plot_map_nrw(data: pd.DataFrame, dfs_all[df.columns[-1] + ' ' + str(i)] = df[df.columns[-1]] i += 1 - min_val = dfs_all[dfs_all.columns[1:]].min().min() - max_val = dfs_all[dfs_all.columns[1:]].max().max() - - plot_map_nrw( - dfs_all, scale_colors=[min_val, max_val], - legend=['', ''], - title='NRW - Simulation Day 10', plot_colorbar=True, - output_path=os.path.dirname(__file__), - fig_name='NRWPlot', dpi=300, - outercolor='white', - log_scale=True) + return dfs_all + + +def plot_total_compartment(files, output_dir, compartment = 'Infected', name='', title=''): + + i = 0 + for file in files.values(): + # Load data. + h5file = h5py.File(file + '.h5', 'r') + if i == 0: + dates = h5file['1']['Time'][:] + data = h5file['1']['Total'][:,compartments[compartment]] + plt.plot(dates, data, label='Equation-based model') + else: + df = pd.DataFrame() + regions = list(h5file.keys()) + for i in range(len(regions)): + df['Region'+str(i)] = h5file[regions[i]]['Total'][:, compartments[compartment]] + df['Total'] = df.sum(axis=1) + df['Time'] = h5file['5111']['Time'][:] # hardcoded + plt.plot(df['Time'], df['Total'], label='Graph-based model') + + i = i+1 + + plt.title(title) + plt.legend() + plt.savefig(os.path.join(output_dir, name + '.png'), dpi=300) + plt.close() + + +if __name__ == '__main__': + + files_input = {'Data set 1': 'cpp/build/ode_result_nrw', + 'Data set 2': 'cpp/build/graph_result_nrw'} # Result file of equation-based model has to be first + file_format = 'h5' + + plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') + + plot_maps(files=files_input,output_dir=plot_dir, name='NRWPlotDay') + plot_total_compartment(files=files_input, output_dir=plot_dir, compartment='Infected', name='infectives_total', title='Total infectives') From d8b321f1d19c1cd8b19c6c07b2bea42b5046db3b Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:25:51 +0100 Subject: [PATCH 45/87] mini optimizations and small changes for timing runs --- cpp/examples/graph_extended.cpp | 6 ++-- cpp/examples/graph_timing.cpp | 35 +++++++++++++++---- cpp/examples/ode_seir_mobility_improved.cpp | 12 +++---- cpp/examples/ode_seir_mobility_timing.cpp | 4 ++- cpp/memilio/compartments/simulation.h | 17 ++++++++- cpp/models/ode_seir_mobility_improved/model.h | 14 ++++---- 6 files changed, 61 insertions(+), 27 deletions(-) diff --git a/cpp/examples/graph_extended.cpp b/cpp/examples/graph_extended.cpp index 311994f33e..0fe7db0272 100644 --- a/cpp/examples/graph_extended.cpp +++ b/cpp/examples/graph_extended.cpp @@ -170,6 +170,7 @@ set_synthetic_population_data(mio::oseir::Parameters& params) mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double dt) { + mio::set_log_level(mio::LogLevel::off); // global parameters bool synthetic_population = false; const int num_age_groups = 6; @@ -252,9 +253,6 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double }); auto save_result_status = save_result(result, county_ids, num_age_groups, "graph_result_nrw.h5"); - result_graph.nodes()[0].property.get_result().print_table(); - result_graph.nodes()[1].property.get_result().print_table(); - result_graph.nodes()[2].property.get_result().print_table(); return mio::success(); } @@ -262,7 +260,7 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double int main() { const auto t0 = 0.; - const auto tmax = 15.; + const auto tmax = 50.; const auto dt = 0.5; //time step of mobility, daily mobility every second step const std::string& data_dir = ""; diff --git a/cpp/examples/graph_timing.cpp b/cpp/examples/graph_timing.cpp index 3f6d2ae172..8759125419 100644 --- a/cpp/examples/graph_timing.cpp +++ b/cpp/examples/graph_timing.cpp @@ -103,7 +103,7 @@ void set_parameters_and_population(mio::Graph>>, mio::MobilityEdge<>> params_graph; + + set_parameters_and_population(params_graph, number_regions); + + auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); + sim.advance(tmax); + + auto result_graph = std::move(sim).get_graph(); + + int num_steps = 0; + for (auto&& node : result_graph.nodes()) { + num_steps += node.property.get_result().get_num_time_points() - 1; + } + + return num_steps; +} + int main(int argc, char** argv) { + mio::set_log_level(mio::LogLevel::off); const ScalarType tmax = 20; size_t warm_up = 10; size_t num_runs = 100; @@ -135,15 +157,16 @@ int main(int argc, char** argv) std::cout << "{ \"Regions\": " << num_regions << ", " << std::endl; // Warm up runs. + int num_steps = 0; for (size_t i = 0; i < warm_up; i++) { - double warm_up_time = simulate(num_regions, tmax); - mio::unused(warm_up_time); + num_steps = simulate_steps(num_regions, tmax); } + std::cout << "\"Steps\": " << num_steps / num_regions << "," << std::endl; // Runs with timing. ScalarType total = 0; for (size_t i = 0; i < num_runs; i++) { - double run_time = simulate(num_regions, tmax); + double run_time = simulate_runtime(num_regions, tmax); total += run_time; } std::cout << "\"Time\": " << total / num_runs << "\n}," << std::endl; diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index 7a2577b517..a07e4ac53d 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -242,12 +242,10 @@ int main() mio::set_log_level(mio::LogLevel::debug); ScalarType t0 = 0.; - ScalarType tmax = 15.; + ScalarType tmax = 50.; ScalarType dt = 0.1; - ScalarType number_regions = 53; - std::vector region_ids(number_regions); - iota(region_ids.begin(), region_ids.end(), 1); + ScalarType number_regions = 53; ScalarType number_age_groups = 6; bool synthetic_population = false; if (number_age_groups != 6) { @@ -279,8 +277,8 @@ int main() // result_from_sim.print_table(); auto save_result_status = - mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_nrw.h5"); + mio::save_result({result_from_sim}, {1}, number_regions * number_age_groups, "ode_result_nrw.h5"); - // auto reproduction_numbers = model.get_reproduction_numbers(result_from_sim); - // std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; + auto basic_reproduction_number = model.get_reproduction_number(0, result_from_sim).value(); + std::cout << "\nbasis reproduction number: " << basic_reproduction_number << "\n"; } diff --git a/cpp/examples/ode_seir_mobility_timing.cpp b/cpp/examples/ode_seir_mobility_timing.cpp index 17c080884e..bd1052420f 100644 --- a/cpp/examples/ode_seir_mobility_timing.cpp +++ b/cpp/examples/ode_seir_mobility_timing.cpp @@ -151,11 +151,13 @@ void simulate(size_t num_warm_up_runs, size_t num_runs, size_t number_regions, S for (size_t i = 0; i < num_warm_up_runs; i++) { simulate(t0, tmax, dt, model, integrator); } + auto result = simulate(t0, tmax, dt, model, integrator); + std::cout << "\"Steps\": " << result.get_num_time_points() << "," << std::endl; // Runs with timing. ScalarType total = 0; for (size_t i = 0; i < num_runs; i++) { - double runtime = simulate(t0, tmax, dt, model, integrator); + double runtime = simulate_runtime(t0, tmax, dt, model, integrator); total += runtime; } std::cout << "\"Time\": " << total / num_runs << "\n}," << std::endl; diff --git a/cpp/memilio/compartments/simulation.h b/cpp/memilio/compartments/simulation.h index 23a627d7f9..b887744430 100644 --- a/cpp/memilio/compartments/simulation.h +++ b/cpp/memilio/compartments/simulation.h @@ -215,7 +215,22 @@ using is_compartment_model_simulation = * @tparam Sim A Simulation that can simulate the model. */ template > -double simulate(FP t0, FP tmax, FP dt, Model const& model, std::shared_ptr> integrator = nullptr) +TimeSeries simulate(FP t0, FP tmax, FP dt, Model const& model, + std::shared_ptr> integrator = nullptr) +{ + model.check_constraints(); + Sim sim(model, t0, dt); + if (integrator) { + sim.set_integrator(integrator); + } + sim.advance(tmax); + return sim.get_result(); +} + +/*Same function, used for timing*/ +template > +double simulate_runtime(FP t0, FP tmax, FP dt, Model const& model, + std::shared_ptr> integrator = nullptr) { model.check_constraints(); Sim sim(model, t0, dt); diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index 470266fe5e..dea693d579 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -70,24 +70,22 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t)(age_i, age_j) * params.template get>()[AgeGroup(age_i)]; - flow_SE_helper += - pop[population.get_flat_index({Region(region_n), AgeGroup(age_j), InfectionState::Infected})] * - Nj_inv; + flow_SE_helper += pop[Ijn] * Nj_inv; for (size_t region_m = 0; region_m < (size_t)n_regions; region_m++) { flow_SE_helper += commuting_strengths(region_n, region_m) * infectives_per_region(region_m) / m_population_after_commuting[{Region(region_m), AgeGroup(age_j)}]; From 7dc7e44309dd47f232d5573b893bd996a0641d5b Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:27:35 +0100 Subject: [PATCH 46/87] add simulations for paper model and comparison of basic reproduction number --- cpp/examples/ode_seir.cpp | 183 ++++++++++++++++--- cpp/examples/ode_seir_mobility.cpp | 282 +++++++++++++++++++++-------- 2 files changed, 365 insertions(+), 100 deletions(-) diff --git a/cpp/examples/ode_seir.cpp b/cpp/examples/ode_seir.cpp index c4e0bd0269..48049ab24d 100644 --- a/cpp/examples/ode_seir.cpp +++ b/cpp/examples/ode_seir.cpp @@ -26,40 +26,175 @@ #include "memilio/utils/time_series.h" #include "memilio/utils/time_series.h" +#include "memilio/io/io.h" +#include "memilio/io/result_io.h" +#include "memilio/io/epi_data.h" + +/** + * Set epidemiological parameters of Sars-CoV-2 for a immune-naive + * population and wild type variant. + * @param params Object that the parameters will be added to. + * @returns Currently generates no errors. + */ +mio::IOResult set_covid_parameters(mio::oseir::Parameters& params, bool synthetic_population) +{ + params.template set>(3.335); + if (!synthetic_population) { + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; + } + else { + params.template set>(8.097612257); + + params.template set>(0.07333); + } + + printf("Setting epidemiological parameters successful.\n"); + return mio::success(); +} + +/** + * indices of contact matrix corresponding to locations where contacts occur. + */ +enum class ContactLocation +{ + Home = 0, + School, + Work, + Other, + Count, +}; + +static const std::map contact_locations = {{ContactLocation::Home, "home"}, + {ContactLocation::School, "school_pf_eig"}, + {ContactLocation::Work, "work"}, + {ContactLocation::Other, "other"}}; + +/** + * Set contact matrices. + * Reads contact matrices from files in the data directory. + * @param data_dir data directory. + * @param params Object that the contact matrices will be added to. + * @returns any io errors that happen during reading of the files. + */ +mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseir::Parameters& params, + bool synthetic_population) +{ + if (!synthetic_population) { + //TODO: io error handling + auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_groups())); + for (auto&& contact_location : contact_locations) { + BOOST_OUTCOME_TRY(auto&& baseline, + mio::read_mobility_plain( + (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); + BOOST_OUTCOME_TRY(auto&& minimum, + mio::read_mobility_plain( + (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); + contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; + contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; + } + params.get>() = mio::UncertainContactMatrix(contact_matrices); + } + else { + mio::ContactMatrixGroup& contact_matrix = params.get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(7.95 / (size_t)params.get_num_groups()); + } + + printf("Setting contact matrices successful.\n"); + return mio::success(); +} + +template +mio::IOResult set_population_data(mio::oseir::Model& model, const fs::path& data_dir) +{ + BOOST_OUTCOME_TRY( + auto&& node_ids, + mio::get_node_ids((data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true, + true)); + + BOOST_OUTCOME_TRY(const auto&& population_data, + mio::read_population_data( + (data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true)); + + for (auto&& entry : population_data) { + auto it = std::find_if(node_ids.begin(), node_ids.end(), [&entry](auto r) { + return r == 0 || + (entry.county_id && mio::regions::StateId(r) == mio::regions::get_state_id(int(*entry.county_id))) || + (entry.county_id && mio::regions::CountyId(r) == *entry.county_id) || + (entry.district_id && mio::regions::DistrictId(r) == *entry.district_id); + }); + if (it != node_ids.end()) { + for (size_t age = 0; age < (size_t)model.parameters.get_num_groups(); age++) { + model.populations[{mio::AgeGroup(age), mio::oseir::InfectionState::Susceptible}] += + entry.population[mio::AgeGroup(age)]; + } + } + } + + printf("Setting population data successful.\n"); + return mio::success(); +} +template +mio::IOResult set_parameters_and_population(mio::oseir::Model& model, const fs::path& data_dir, + bool synthetic_population) +{ + auto& populations = model.populations; + auto& parameters = model.parameters; + + size_t number_age_groups = (size_t)parameters.get_num_groups(); + + if (synthetic_population) { + printf("Data is not compatible, using synthetic population instead.\n"); + for (size_t j = 0; j < number_age_groups; j++) { + model.populations[{mio::AgeGroup(j), mio::oseir::InfectionState::Exposed}] = 100; + model.populations[{mio::AgeGroup(j), mio::oseir::InfectionState::Susceptible}] = 999900; + } + } + else { + BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); + populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; + populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; + } + + BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters, synthetic_population)) + + BOOST_OUTCOME_TRY(set_covid_parameters(parameters, synthetic_population)); + + return mio::success(); +} int main() { mio::set_log_level(mio::LogLevel::debug); - ScalarType t0 = 0; - ScalarType tmax = 0.2; + ScalarType t0 = 0.; + ScalarType tmax = 50.; ScalarType dt = 0.1; - mio::log_info("Simulating ODE SEIR; t={} ... {} with dt = {}.", t0, tmax, dt); - - int number_agegroups = 6; - mio::oseir::Model model(number_agegroups); - - ScalarType total_population = 286922; - for (int i = 0; i < number_agegroups; i++) { - model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Exposed}] = 10; - model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Infected}] = 0; - model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Recovered}] = 0; - model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Susceptible}] = - total_population - model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Exposed}] - - model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Infected}] - - model.populations[{mio::AgeGroup(i), mio::oseir::InfectionState::Recovered}]; + ScalarType number_age_groups = 6; + bool synthetic_population = false; + if (number_age_groups != 6) { + synthetic_population = true; } - model.parameters.set>(3.); - model.parameters.set>(5.); - model.parameters.set>(1.); + mio::log_info("Simulating ODE SEIR; t={} ... {} with dt = {}.", t0, tmax, dt); + + const std::string& data_dir = ""; - mio::ContactMatrixGroup& contact_matrix = model.parameters.get>(); - contact_matrix[0].get_baseline().setConstant(7.95); - // contact_matrix[0].add_damping(0.7, mio::SimulationTime(30.)); + mio::oseir::Model model(number_age_groups); + auto result_prepare_simulation = set_parameters_and_population(model, data_dir, synthetic_population); - model.check_constraints(); std::shared_ptr> integrator = std::make_shared>(); auto seir = simulate(t0, tmax, dt, model, integrator); @@ -67,6 +202,6 @@ int main() auto reproduction_numbers = model.get_reproduction_numbers(seir); std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; - seir.print_table({"S", "E", "I", "R"}); + // seir.print_table({"S", "E", "I", "R"}); // std::cout << "\nnumber total: " << seir.get_last_value().sum() << "\n"; } diff --git a/cpp/examples/ode_seir_mobility.cpp b/cpp/examples/ode_seir_mobility.cpp index 4cdab666b7..f77b795935 100644 --- a/cpp/examples/ode_seir_mobility.cpp +++ b/cpp/examples/ode_seir_mobility.cpp @@ -9,28 +9,201 @@ #include "models/ode_seir_mobility/parameters.h" #include "models/ode_seir_mobility/regions.h" #include "memilio/io/io.h" -#include "memilio/io/result_io.h" +#include "memilio/io/epi_data.h" + +/** + * Set epidemiological parameters of Sars-CoV-2 for a immune-naive + * population and wild type variant. + * @param params Object that the parameters will be added to. + * @returns Currently generates no errors. + */ +mio::IOResult set_covid_parameters(mio::oseirmobility::Parameters& params, bool synthetic_population) +{ + params.template set>(3.335); + if (!synthetic_population) { + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; + } + else { + params.template set>(8.097612257); + + params.template set>(0.07333); + } + + printf("Setting epidemiological parameters successful.\n"); + return mio::success(); +} + +/** + * indices of contact matrix corresponding to locations where contacts occur. + */ +enum class ContactLocation +{ + Home = 0, + School, + Work, + Other, + Count, +}; + +static const std::map contact_locations = {{ContactLocation::Home, "home"}, + {ContactLocation::School, "school_pf_eig"}, + {ContactLocation::Work, "work"}, + {ContactLocation::Other, "other"}}; + +/** + * Set contact matrices. + * Reads contact matrices from files in the data directory. + * @param data_dir data directory. + * @param params Object that the contact matrices will be added to. + * @returns any io errors that happen during reading of the files. + */ +mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseirmobility::Parameters& params, + bool synthetic_population) +{ + if (!synthetic_population) { + //TODO: io error handling + auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_agegroups())); + for (auto&& contact_location : contact_locations) { + BOOST_OUTCOME_TRY(auto&& baseline, + mio::read_mobility_plain( + (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); + BOOST_OUTCOME_TRY(auto&& minimum, + mio::read_mobility_plain( + (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); + contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; + contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; + } + params.get>() = + mio::UncertainContactMatrix(contact_matrices); + } + else { + mio::ContactMatrixGroup& contact_matrix = + params.get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(7.95 / (size_t)params.get_num_agegroups()); + } + + printf("Setting contact matrices successful.\n"); + return mio::success(); +} + +template +mio::IOResult set_population_data(mio::oseirmobility::Model& model, const fs::path& data_dir) +{ + BOOST_OUTCOME_TRY( + auto&& node_ids, + mio::get_node_ids((data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true, + true)); + + BOOST_OUTCOME_TRY(const auto&& population_data, + mio::read_population_data( + (data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true)); + + for (auto&& entry : population_data) { + auto it = std::find_if(node_ids.begin(), node_ids.end(), [&entry](auto r) { + return r == 0 || + (entry.county_id && mio::regions::StateId(r) == mio::regions::get_state_id(int(*entry.county_id))) || + (entry.county_id && mio::regions::CountyId(r) == *entry.county_id) || + (entry.district_id && mio::regions::DistrictId(r) == *entry.district_id); + }); + if (it != node_ids.end()) { + auto region_idx = size_t(it - node_ids.begin()); + for (size_t age = 0; age < (size_t)model.parameters.get_num_agegroups(); age++) { + model.populations[{mio::oseirmobility::Region(region_idx), mio::AgeGroup(age), + mio::oseirmobility::InfectionState::Susceptible}] = + entry.population[mio::AgeGroup(age)]; + } + } + } + + printf("Setting population data successful.\n"); + return mio::success(); +} template -mio::IOResult set_mobility_weights(const std::string& mobility_data, mio::oseirmobility::Model& model, - size_t number_regions) +mio::IOResult set_mobility_weights(mio::oseirmobility::Model& model, const fs::path& data_dir) { - // mobility between nodes - BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, - mio::read_mobility_plain(mobility_data + "/mobility" + "/commuter_migration_test.txt")); - if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || - mobility_data_commuter.cols() != Eigen::Index(number_regions)) { - return mio::failure(mio::StatusCode::InvalidValue, - "Mobility matrices do not have the correct size. You may need to run " - "transformMobilitydata.py from pycode memilio epidata package."); + size_t number_regions = (size_t)model.parameters.get_num_regions(); + if (number_regions == 1) { + model.parameters.template get>() + .get_cont_freq_mat()[0] + .get_baseline() + .setConstant(1.0); + + return mio::success(); + } + else { + // mobility between nodes + BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, + mio::read_mobility_plain((data_dir / "mobility" / "commuter_mobility_nrw.txt").string())); + if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || + mobility_data_commuter.cols() != Eigen::Index(number_regions)) { + return mio::failure(mio::StatusCode::InvalidValue, + "Mobility matrices do not have the correct size. You may need to run " + "transformMobilitydata.py from pycode memilio epidata package."); + } + + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + auto population_i = model.populations.get_group_total(mio::oseirmobility::Region(county_idx_i)); + mobility_data_commuter.row(county_idx_i) /= population_i; + } + model.parameters.template get>() + .get_cont_freq_mat()[0] + .get_baseline() = mobility_data_commuter; + + printf("Setting mobility weights successful.\n"); + return mio::success(); } +} - for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { - auto population_i = model.populations.get_group_total(mio::oseirmobility::Region(county_idx_i)); - mobility_data_commuter.row(county_idx_i) /= population_i; +template +mio::IOResult set_parameters_and_population(mio::oseirmobility::Model& model, const fs::path& data_dir, + bool synthetic_population) +{ + auto& populations = model.populations; + auto& parameters = model.parameters; + + size_t number_regions = (size_t)parameters.get_num_regions(); + size_t number_age_groups = (size_t)parameters.get_num_agegroups(); + + if (synthetic_population) { + printf("Data is not compatible, using synthetic population instead.\n"); + for (size_t j = 0; j < number_age_groups; j++) { + model.populations[{mio::oseirmobility::Region(0), mio::AgeGroup(j), + mio::oseirmobility::InfectionState::Exposed}] = 100; + model.populations[{mio::oseirmobility::Region(0), mio::AgeGroup(j), + mio::oseirmobility::InfectionState::Susceptible}] = 999900; + for (size_t i = 1; i < number_regions; i++) { + model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(j), + mio::oseirmobility::InfectionState::Exposed}] = 0; + model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(j), + mio::oseirmobility::InfectionState::Susceptible}] = 1000000; + } + } + } + else { + BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); + populations[{mio::oseirmobility::Region(27), mio::AgeGroup(0), + mio::oseirmobility::InfectionState::Susceptible}] -= 100; + populations[{mio::oseirmobility::Region(27), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Exposed}] += + 100; } - model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = - mobility_data_commuter; + BOOST_OUTCOME_TRY(set_mobility_weights(model, data_dir)); + + BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters, synthetic_population)) + + BOOST_OUTCOME_TRY(set_covid_parameters(parameters, synthetic_population)); return mio::success(); } @@ -40,80 +213,37 @@ int main() mio::set_log_level(mio::LogLevel::debug); ScalarType t0 = 0.; - ScalarType tmax = 15.; + ScalarType tmax = 50.; ScalarType dt = 0.1; - ScalarType number_regions = 2; + ScalarType number_regions = 53; std::vector region_ids(number_regions); iota(region_ids.begin(), region_ids.end(), 1); - ScalarType number_age_groups = 1; + ScalarType number_age_groups = 6; + bool synthetic_population = false; + if (number_age_groups != 6) { + synthetic_population = true; + } mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& mobility_data = ""; + const std::string& data_dir = ""; mio::oseirmobility::Model model(number_regions, number_age_groups); - model.populations[{mio::oseirmobility::Region(0), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Exposed}] = - 10; - model.populations[{mio::oseirmobility::Region(0), mio::AgeGroup(0), - mio::oseirmobility::InfectionState::Susceptible}] = 9990; - for (int i = 1; i < number_regions; i++) { - model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), - mio::oseirmobility::InfectionState::Exposed}] = 0; - model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(0), - mio::oseirmobility::InfectionState::Susceptible}] = 10000; - } - - model.parameters.set>(1.); + auto result_prepare_simulation = set_parameters_and_population(model, data_dir, synthetic_population); - model.parameters.set>(3.); - model.parameters.set>(5.); + // using DefaultIntegratorCore = + // mio::ControlledStepperWrapper; - mio::ContactMatrixGroup& contact_matrix = - model.parameters.get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(2.7); - // contact_matrix[0].add_damping(0.5, mio::SimulationTime(5)); - - auto result_preprocess = set_mobility_weights(mobility_data, model, number_regions); - - using DefaultIntegratorCore = - mio::ControlledStepperWrapper; - - std::shared_ptr> integrator = std::make_shared(); + std::shared_ptr> integrator = std::make_shared>(); model.check_constraints(); auto result_from_sim = simulate(t0, tmax, dt, model, integrator); - auto save_result_status = - mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_standard.h5"); - - auto reproduction_numbers = model.get_reproduction_numbers(result_from_sim); - std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; - - // bool print_to_terminal = true; - - // result_from_sim.print_table(); - - // if (print_to_terminal) { - - // std::vector vars = {"S", "E", "I", "R"}; - // printf("\n # t"); - // for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { - // for (size_t k = 0; k < (size_t)mio::oseirmobility::InfectionState::Count; k++) { - // printf(" %s_%d", vars[k].c_str(), (int)i); - // } - // } - - // auto num_points = static_cast(sir.get_num_time_points()); - // for (size_t i = 0; i < num_points; i++) { - // printf("\n%.14f ", sir.get_time(i)); - // for (size_t k = 0; k < (size_t)model.parameters.get_num_regions(); k++) { - // for (size_t j = 0; j < (size_t)mio::oseirmobility::InfectionState::Count; j++) { - // printf(" %.14f", sir.get_value(i)[j + (size_t)mio::oseirmobility::InfectionState::Count * (int)k]); - // } - // } - // } - // printf("\n"); - // } + // auto save_result_status = + // mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_standard2.h5"); + + auto basic_reproduction_number = model.get_reproduction_number(0, result_from_sim).value(); + std::cout << "\nbasis reproduction number: " << basic_reproduction_number << "\n"; } From 90a8d3e15e4966ade09a372eb0871e4d75e3454c Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:29:18 +0100 Subject: [PATCH 47/87] small changes in plots --- tools/plot_results_mobility.py | 49 +++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/tools/plot_results_mobility.py b/tools/plot_results_mobility.py index 99854994ae..21a0523d75 100644 --- a/tools/plot_results_mobility.py +++ b/tools/plot_results_mobility.py @@ -96,7 +96,7 @@ def plot_map_nrw(data: pd.DataFrame, # Use n+2 many columns (1: legend + 2: empty space + 3-n: data sets) and # n+2 rows where the top row is used for a potential title, the second row # for the content and all other rows have height zero. - height_ratios = [0.05, 1, 0] + height_ratios = [0.25, 1, 0] if len(data_columns) > 1: height_ratios = height_ratios + [ 0.0 for i in range(len(data_columns)-1)] @@ -135,7 +135,7 @@ def plot_map_nrw(data: pd.DataFrame, map_data.plot(data_columns[i], ax=ax, legend=False, vmin=scale_colors[0], vmax=scale_colors[1]) - ax.set_title(legend[i], fontsize=12) + ax.set_title(legend[i], fontsize=10) ax.set_axis_off() sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) @@ -148,9 +148,9 @@ def plot_map_nrw(data: pd.DataFrame, plt.savefig(os.path.join(output_path, fig_name + '.png'), dpi=dpi) plt.close() -def plot_maps(files, output_dir, name=''): +def plot_maps(files, output_dir, legend, name=''): - for date in range(10, 50, 10): + for date in range(10, 21, 10): dfs_all = extract_nrw_data_and_combine(files=files, date=date) min_val = dfs_all[dfs_all.columns[1:]].min().min() @@ -158,7 +158,7 @@ def plot_maps(files, output_dir, name=''): plot_map_nrw( dfs_all, scale_colors=[min_val, max_val], - legend=['', ''], + legend=legend, title='NRW - Simulation Day '+str(date), plot_colorbar=True, output_path=output_dir, fig_name=name+str(date), dpi=900, @@ -173,7 +173,8 @@ def extract_nrw_data_and_combine(files, date): i = 0 for file in files.values(): - if(i == 0): # result file of equation-based model has to be first + model_type = os.path.basename(file).split('_')[0] + if model_type == 'ode': # result file of equation-based model has to be first df = pm.extract_data( file, region_spec=None, column=None, date=date, filters={'Group': filter_age, 'InfectionState': [2]}, @@ -187,7 +188,6 @@ def extract_nrw_data_and_combine(files, date): ids = geoger.get_county_ids() ids = [id for id in ids if str(id).startswith('5')] - # ids = [5111, 5112, 5113] if len(ids) != len(df): raise gd.DataError("Data is not compatible with number of NRW counties.") @@ -229,26 +229,27 @@ def extract_nrw_data_and_combine(files, date): return dfs_all -def plot_total_compartment(files, output_dir, compartment = 'Infected', name='', title=''): +def plot_total_compartment(files, output_dir, legend, compartment = 'Infected', name='', title=''): - i = 0 + file_idx = 0 for file in files.values(): + model_type = os.path.basename(file).split('_')[0] # Load data. h5file = h5py.File(file + '.h5', 'r') - if i == 0: + if model_type=='ode': dates = h5file['1']['Time'][:] data = h5file['1']['Total'][:,compartments[compartment]] - plt.plot(dates, data, label='Equation-based model') + plt.plot(dates, data, label=legend[file_idx]) else: df = pd.DataFrame() regions = list(h5file.keys()) for i in range(len(regions)): df['Region'+str(i)] = h5file[regions[i]]['Total'][:, compartments[compartment]] df['Total'] = df.sum(axis=1) - df['Time'] = h5file['5111']['Time'][:] # hardcoded - plt.plot(df['Time'], df['Total'], label='Graph-based model') + df['Time'] = h5file[regions[0]]['Time'][:] # hardcoded + plt.plot(df['Time'], df['Total'], label=legend[file_idx], linestyle='dashed') - i = i+1 + file_idx = file_idx+1 plt.title(title) plt.legend() @@ -258,11 +259,23 @@ def plot_total_compartment(files, output_dir, compartment = 'Infected', name='', if __name__ == '__main__': - files_input = {'Data set 1': 'cpp/build/ode_result_nrw', - 'Data set 2': 'cpp/build/graph_result_nrw'} # Result file of equation-based model has to be first + files_input = {'Data set 1': 'cpp/build/ode_result_timing', + 'Data set 3': 'cpp/build/graph_result_timing'}#, + # 'Data set 2': 'cpp/build/ode_result_standard2'} + files_compare_solver = {'Data set 1': 'cpp/build/ode_result_nrw_euler', + 'Data set 2': 'cpp/build/ode_result_nrw_adaptive', + 'Data set 3': 'cpp/build/graph_result_nrw_euler', + 'Data set 4': 'cpp/build/graph_result_nrw_adaptive'} file_format = 'h5' + models = ['ODE Metapopulation model', + 'Graph-based hybrid ODE model', + 'ODE Metapopulation model (Wang)'] + plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') - plot_maps(files=files_input,output_dir=plot_dir, name='NRWPlotDay') - plot_total_compartment(files=files_input, output_dir=plot_dir, compartment='Infected', name='infectives_total', title='Total infectives') + plot_maps(files={'Ode': 'cpp/build/graph_result_timing'}, output_dir=plot_dir, legend=['ODE'], name='TimingTest') + plot_total_compartment(files={'Ode': 'cpp/build/graph_result_timing'}, output_dir=plot_dir, legend=['Graph'], + compartment='Infected', name='timing_test', title='Total infectives') + # plot_total_compartment(files=files_input, output_dir=plot_dir, legend=['ODE', 'Graph'], + # compartment='Infected', name='infectives_total', title='Total infectives') From c78c996242577805e2429177faa7a63c13a9b9b4 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Fri, 20 Dec 2024 14:15:16 +0100 Subject: [PATCH 48/87] fix runtime maybe --- cpp/models/ode_seir_mobility_improved/model.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index dea693d579..061be62017 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -59,15 +59,18 @@ class Model : public FlowModel n_regions = reduce_index>(params.get_num_regions()); for (size_t age_i = 0; age_i < (size_t)n_age_groups; age_i++) { for (size_t age_j = 0; age_j < (size_t)n_age_groups; age_j++) { - Eigen::VectorXd infectives_per_region = Eigen::VectorXd::Zero((size_t)n_regions); + Eigen::VectorXd infectious_share_per_region = Eigen::VectorXd::Zero((size_t)n_regions); for (size_t region_n = 0; region_n < (size_t)n_regions; region_n++) { for (size_t region_m = 0; region_m < (size_t)n_regions; region_m++) { - infectives_per_region(region_n) += + infectious_share_per_region(region_n) += commuting_strengths(region_m, region_n) * pop[population.get_flat_index( {Region(region_m), AgeGroup(age_j), InfectionState::Infected})]; } + infectious_share_per_region(region_n) /= + m_population_after_commuting[{Region(region_n), AgeGroup(age_j)}]; } + Eigen::VectorXd infections_due_commuting = commuting_strengths * infectious_share_per_region; for (size_t region_n = 0; region_n < (size_t)n_regions; region_n++) { FP flow_SE_helper = 0; const size_t Ejn = @@ -85,11 +88,7 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t)(age_i, age_j) * params.template get>()[AgeGroup(age_i)]; - flow_SE_helper += pop[Ijn] * Nj_inv; - for (size_t region_m = 0; region_m < (size_t)n_regions; region_m++) { - flow_SE_helper += commuting_strengths(region_n, region_m) * infectives_per_region(region_m) / - m_population_after_commuting[{Region(region_m), AgeGroup(age_j)}]; - } + flow_SE_helper += pop[Ijn] * Nj_inv + infections_due_commuting(region_n); flows[Base::template get_flat_flow_index( {Region(region_n), AgeGroup(age_i)})] += flow_SE_helper * coeffStoI * From cd056b5c7d2c429036e3d5919b9c1450423e79e2 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Tue, 31 Dec 2024 19:37:16 +0100 Subject: [PATCH 49/87] adjust timing examples for single age group --- cpp/examples/graph_timing.cpp | 66 ++++++++++++-------- cpp/examples/ode_seir_mobility_timing.cpp | 75 ++++++++++++++--------- 2 files changed, 88 insertions(+), 53 deletions(-) diff --git a/cpp/examples/graph_timing.cpp b/cpp/examples/graph_timing.cpp index 8759125419..2041a9768c 100644 --- a/cpp/examples/graph_timing.cpp +++ b/cpp/examples/graph_timing.cpp @@ -7,14 +7,23 @@ #include +bool age_groups = true; + void set_contact_matrices(mio::oseir::Parameters& params) { - Eigen::MatrixXd contact_matrix_eigen(6, 6); - contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, 0.0161, - 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, 0.0458, 0.1939, - 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; - mio::ContactMatrixGroup& contact_matrix = params.template get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline() = contact_matrix_eigen; + if (age_groups) { + Eigen::MatrixXd contact_matrix_eigen(6, 6); + contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, + 0.0161, 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, + 0.0458, 0.1939, 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; + mio::ContactMatrixGroup& contact_matrix = + params.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline() = contact_matrix_eigen; + } + else { + mio::ContactMatrixGroup& contact_matrix = params.get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(7.95); + } } /** @@ -27,19 +36,25 @@ void set_covid_parameters(mio::oseir::Parameters& params) { params.template set>(3.335); - params.get>()[mio::AgeGroup(0)] = 8.0096875; - params.get>()[mio::AgeGroup(1)] = 8.0096875; - params.get>()[mio::AgeGroup(2)] = 8.2182; - params.get>()[mio::AgeGroup(3)] = 8.1158; - params.get>()[mio::AgeGroup(4)] = 8.033; - params.get>()[mio::AgeGroup(5)] = 7.985; - - params.get>()[mio::AgeGroup(0)] = 0.03; - params.get>()[mio::AgeGroup(1)] = 0.06; - params.get>()[mio::AgeGroup(2)] = 0.06; - params.get>()[mio::AgeGroup(3)] = 0.06; - params.get>()[mio::AgeGroup(4)] = 0.09; - params.get>()[mio::AgeGroup(5)] = 0.175; + if (age_groups) { + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; + } + else { + params.get>()[mio::AgeGroup(0)] = 0.07333; + params.get>()[mio::AgeGroup(0)] = 8.097612257; + } } void set_population_data(mio::oseir::Parameters& params, @@ -60,10 +75,10 @@ void set_population_data(mio::oseir::Parameters& params, node.parameters = params; node.populations = population; } - for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { - nodes[0].populations[{i, mio::oseir::InfectionState::Exposed}] = 100; - nodes[0].populations[{i, mio::oseir::InfectionState::Susceptible}] = 999900; - } + // for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { + nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; + nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; + // } for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { params_graph.add_node(node_idx, nodes[node_idx]); @@ -74,7 +89,10 @@ void set_parameters_and_population(mio::Graph>& params_graph, size_t number_regions) { - const int num_age_groups = 6; + int num_age_groups = 1; + if (age_groups) { + num_age_groups = 6; + } mio::oseir::Parameters params(num_age_groups); diff --git a/cpp/examples/ode_seir_mobility_timing.cpp b/cpp/examples/ode_seir_mobility_timing.cpp index bd1052420f..9fd9c0823f 100644 --- a/cpp/examples/ode_seir_mobility_timing.cpp +++ b/cpp/examples/ode_seir_mobility_timing.cpp @@ -28,16 +28,25 @@ #include +bool age_groups = true; + template void set_contact_matrix(mio::oseirmobilityimproved::Model& model) { - Eigen::MatrixXd contact_matrix_eigen(6, 6); - contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, 0.0161, - 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, 0.0458, 0.1939, - 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; - mio::ContactMatrixGroup& contact_matrix = - model.parameters.template get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline() = contact_matrix_eigen; + if (age_groups) { + Eigen::MatrixXd contact_matrix_eigen(6, 6); + contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, + 0.0161, 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, + 0.0458, 0.1939, 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; + mio::ContactMatrixGroup& contact_matrix = + model.parameters.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline() = contact_matrix_eigen; + } + { + mio::ContactMatrixGroup& contact_matrix = + model.parameters.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(7.95); + } } /** @@ -50,19 +59,25 @@ void set_covid_parameters(mio::oseirmobilityimproved::Parameters& params { params.template set>(3.335); - params.get>()[mio::AgeGroup(0)] = 8.0096875; - params.get>()[mio::AgeGroup(1)] = 8.0096875; - params.get>()[mio::AgeGroup(2)] = 8.2182; - params.get>()[mio::AgeGroup(3)] = 8.1158; - params.get>()[mio::AgeGroup(4)] = 8.033; - params.get>()[mio::AgeGroup(5)] = 7.985; - - params.get>()[mio::AgeGroup(0)] = 0.03; - params.get>()[mio::AgeGroup(1)] = 0.06; - params.get>()[mio::AgeGroup(2)] = 0.06; - params.get>()[mio::AgeGroup(3)] = 0.06; - params.get>()[mio::AgeGroup(4)] = 0.09; - params.get>()[mio::AgeGroup(5)] = 0.175; + if (age_groups) { + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; + } + else { + params.get>()[mio::AgeGroup(0)] = 0.07333; + params.get>()[mio::AgeGroup(0)] = 8.097612257; + } } template @@ -91,17 +106,15 @@ void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) size_t number_regions = (size_t)parameters.get_num_regions(); size_t number_age_groups = (size_t)parameters.get_num_agegroups(); for (size_t j = 0; j < number_age_groups; j++) { - model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Exposed}] = 100; - model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 999900; - for (size_t i = 1; i < number_regions; i++) { - model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; + for (size_t i = 0; i < number_regions; i++) { model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 1000000; + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; } } + model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; + model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; set_mobility_weights(model); set_contact_matrix(model); @@ -133,9 +146,13 @@ void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) void simulate(size_t num_warm_up_runs, size_t num_runs, size_t number_regions, ScalarType tmax) { + mio::set_log_level(mio::LogLevel::off); ScalarType t0 = 0.; ScalarType dt = 0.1; - ScalarType number_age_groups = 6; + ScalarType number_age_groups = 1; + if (age_groups) { + number_age_groups = 6; + } mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); set_parameters_and_population(model); From fba237ae9e7197238f5467cc9997a50fb651a920 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 9 Jan 2025 09:15:26 +0100 Subject: [PATCH 50/87] remove prints from simulations --- cpp/examples/graph_extended.cpp | 22 +--- cpp/examples/ode_seir_mobility_improved.cpp | 136 +++++++------------- 2 files changed, 50 insertions(+), 108 deletions(-) diff --git a/cpp/examples/graph_extended.cpp b/cpp/examples/graph_extended.cpp index 0fe7db0272..5fde967f6d 100644 --- a/cpp/examples/graph_extended.cpp +++ b/cpp/examples/graph_extended.cpp @@ -7,8 +7,6 @@ #include "memilio/io/result_io.h" #include "memilio/io/epi_data.h" -#include - /** * indices of contact matrix corresponding to locations where contacts occur. */ @@ -136,8 +134,8 @@ set_population_data(const fs::path& data_dir, mio::oseir::Parameters& pa {i, mio::oseir::InfectionState::Susceptible}, vnum_population[region][size_t(i)]); } } - nodes[27].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; - nodes[27].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; + nodes[27].populations[{mio::AgeGroup(4), mio::oseir::InfectionState::Susceptible}] -= 100; + nodes[27].populations[{mio::AgeGroup(4), mio::oseir::InfectionState::Exposed}] += 100; return mio::success(nodes); } @@ -229,20 +227,14 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double } } - for (auto& node : params_graph.nodes()) { - node.property.get_simulation().set_integrator(std::make_shared>()); - } + // for (auto& node : params_graph.nodes()) { + // node.property.get_simulation().set_integrator(std::make_shared>()); + // } auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); printf("Start Simulation\n"); - auto t1 = std::chrono::high_resolution_clock::now(); sim.advance(tmax); - auto t2 = std::chrono::high_resolution_clock::now(); - - std::chrono::duration ms_double = t2 - t1; - - printf("Runtime: %f\n", ms_double.count()); auto result_graph = std::move(sim).get_graph(); auto result = mio::interpolate_simulation_result(result_graph); @@ -252,7 +244,7 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double return n.id; }); - auto save_result_status = save_result(result, county_ids, num_age_groups, "graph_result_nrw.h5"); + auto save_result_status = save_result(result, county_ids, num_age_groups, "graph_result_nrw_adaptive.h5"); return mio::success(); } @@ -260,7 +252,7 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double int main() { const auto t0 = 0.; - const auto tmax = 50.; + const auto tmax = 100.; const auto dt = 0.5; //time step of mobility, daily mobility every second step const std::string& data_dir = ""; diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/ode_seir_mobility_improved.cpp index a07e4ac53d..92565b552d 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/ode_seir_mobility_improved.cpp @@ -12,39 +12,28 @@ #include "memilio/io/result_io.h" #include "memilio/io/epi_data.h" -#include - /** * Set epidemiological parameters of Sars-CoV-2 for a immune-naive * population and wild type variant. * @param params Object that the parameters will be added to. * @returns Currently generates no errors. */ -mio::IOResult set_covid_parameters(mio::oseirmobilityimproved::Parameters& params, - bool synthetic_population) +mio::IOResult set_covid_parameters(mio::oseirmobilityimproved::Parameters& params) { params.template set>(3.335); - if (!synthetic_population) { - params.get>()[mio::AgeGroup(0)] = 8.0096875; - params.get>()[mio::AgeGroup(1)] = 8.0096875; - params.get>()[mio::AgeGroup(2)] = 8.2182; - params.get>()[mio::AgeGroup(3)] = 8.1158; - params.get>()[mio::AgeGroup(4)] = 8.033; - params.get>()[mio::AgeGroup(5)] = 7.985; - - params.get>()[mio::AgeGroup(0)] = 0.03; - params.get>()[mio::AgeGroup(1)] = 0.06; - params.get>()[mio::AgeGroup(2)] = 0.06; - params.get>()[mio::AgeGroup(3)] = 0.06; - params.get>()[mio::AgeGroup(4)] = 0.09; - params.get>()[mio::AgeGroup(5)] = 0.175; - } - else { - params.template set>(8.097612257); - - params.template set>(0.07333); - } - + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; printf("Setting epidemiological parameters successful.\n"); return mio::success(); } @@ -74,30 +63,22 @@ static const std::map contact_locations = {{Contac * @returns any io errors that happen during reading of the files. */ mio::IOResult set_contact_matrices(const fs::path& data_dir, - mio::oseirmobilityimproved::Parameters& params, - bool synthetic_population) + mio::oseirmobilityimproved::Parameters& params) { - if (!synthetic_population) { - //TODO: io error handling - auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_agegroups())); - for (auto&& contact_location : contact_locations) { - BOOST_OUTCOME_TRY(auto&& baseline, - mio::read_mobility_plain( - (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); - BOOST_OUTCOME_TRY(auto&& minimum, - mio::read_mobility_plain( - (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); - contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; - contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; - } - params.get>() = - mio::UncertainContactMatrix(contact_matrices); - } - else { - mio::ContactMatrixGroup& contact_matrix = - params.get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(7.95 / (size_t)params.get_num_agegroups()); + //TODO: io error handling + auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_agegroups())); + for (auto&& contact_location : contact_locations) { + BOOST_OUTCOME_TRY(auto&& baseline, + mio::read_mobility_plain( + (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); + BOOST_OUTCOME_TRY(auto&& minimum, + mio::read_mobility_plain( + (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); + contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; + contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; } + params.get>() = + mio::UncertainContactMatrix(contact_matrices); printf("Setting contact matrices successful.\n"); return mio::success(); @@ -176,7 +157,7 @@ mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& template mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Model& model, - const fs::path& data_dir, bool synthetic_population) + const fs::path& data_dir) { auto& populations = model.populations; auto& parameters = model.parameters; @@ -184,33 +165,17 @@ mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Mo size_t number_regions = (size_t)parameters.get_num_regions(); size_t number_age_groups = (size_t)parameters.get_num_agegroups(); - if (synthetic_population) { - printf("Data is not compatible, using synthetic population instead.\n"); - for (size_t j = 0; j < number_age_groups; j++) { - model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Exposed}] = 100; - model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 999900; - for (size_t i = 1; i < number_regions; i++) { - model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Exposed}] = 0; - model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 1000000; - } - } - } - else { - BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); - populations[{mio::oseirmobilityimproved::Region(27), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; - populations[{mio::oseirmobilityimproved::Region(27), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; - } + BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); + populations[{mio::oseirmobilityimproved::Region(27), mio::AgeGroup(4), + mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; + populations[{mio::oseirmobilityimproved::Region(27), mio::AgeGroup(4), + mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; + BOOST_OUTCOME_TRY(set_mobility_weights(model, data_dir)); - BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters, synthetic_population)) + BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters)) - BOOST_OUTCOME_TRY(set_covid_parameters(parameters, synthetic_population)); + BOOST_OUTCOME_TRY(set_covid_parameters(parameters)); mio::ContactMatrixGroup& commuting_strengths = parameters.template get>().get_cont_freq_mat(); @@ -242,43 +207,28 @@ int main() mio::set_log_level(mio::LogLevel::debug); ScalarType t0 = 0.; - ScalarType tmax = 50.; + ScalarType tmax = 100.; ScalarType dt = 0.1; ScalarType number_regions = 53; ScalarType number_age_groups = 6; - bool synthetic_population = false; - if (number_age_groups != 6) { - synthetic_population = true; - } mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); const std::string& data_dir = ""; mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); - auto result_prepare_simulation = set_parameters_and_population(model, data_dir, synthetic_population); - - // using DefaultIntegratorCore = - // mio::ControlledStepperWrapper; + auto result_prepare_simulation = set_parameters_and_population(model, data_dir); - std::shared_ptr> integrator = std::make_shared>(); + // std::shared_ptr> integrator = std::make_shared>(); model.check_constraints(); printf("Start Simulation\n"); - auto t1 = std::chrono::high_resolution_clock::now(); - auto result_from_sim = simulate(t0, tmax, dt, model, integrator); - auto t2 = std::chrono::high_resolution_clock::now(); + auto result_from_sim = simulate(t0, tmax, dt, model); - std::chrono::duration ms_double = t2 - t1; - - printf("Runtime: %f\n", ms_double.count()); - // result_from_sim.print_table(); + auto result = mio::interpolate_simulation_result(result_from_sim); auto save_result_status = - mio::save_result({result_from_sim}, {1}, number_regions * number_age_groups, "ode_result_nrw.h5"); - - auto basic_reproduction_number = model.get_reproduction_number(0, result_from_sim).value(); - std::cout << "\nbasis reproduction number: " << basic_reproduction_number << "\n"; + mio::save_result({result}, {1}, number_regions * number_age_groups, "ode_result_nrw_adaptive_test.h5"); } From 363bf85a00711170dafa3bd2f1ad86e9803c8151 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 9 Jan 2025 09:18:04 +0100 Subject: [PATCH 51/87] add examples for basic reproduction numbers, and measurements of steps --- cpp/examples/CMakeLists.txt | 12 ++ cpp/examples/basic_reproduction_numbers.cpp | 196 ++++++++++++++++++++ cpp/examples/graph_steps.cpp | 163 ++++++++++++++++ cpp/examples/ode_seir_mobility_steps.cpp | 181 ++++++++++++++++++ 4 files changed, 552 insertions(+) create mode 100644 cpp/examples/basic_reproduction_numbers.cpp create mode 100644 cpp/examples/graph_steps.cpp create mode 100644 cpp/examples/ode_seir_mobility_steps.cpp diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index aac77c0dbc..1d5cc48c03 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -44,6 +44,14 @@ if (MEMILIO_ENABLE_OPENMP) target_compile_options(ode_seir_mobility_timing PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) endif() +add_executable(ode_seir_mobility_steps ode_seir_mobility_steps.cpp) +target_link_libraries(ode_seir_mobility_steps PRIVATE memilio ode_seir_mobility_improved) +target_compile_options(ode_seir_mobility_steps PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + +add_executable(basic_reproduction_numbers basic_reproduction_numbers.cpp) +target_link_libraries(basic_reproduction_numbers PRIVATE memilio ode_seir) +target_compile_options(basic_reproduction_numbers PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(ode_seir_mobility_example_improved ode_seir_mobility_improved.cpp) target_link_libraries(ode_seir_mobility_example_improved PRIVATE memilio ode_seir_mobility_improved) target_compile_options(ode_seir_mobility_example_improved PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) @@ -106,6 +114,10 @@ add_executable(graph_example_extended graph_extended.cpp) target_link_libraries(graph_example_extended PRIVATE memilio ode_seir) target_compile_options(graph_example_extended PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(graph_steps graph_steps.cpp) +target_link_libraries(graph_steps PRIVATE memilio ode_seir) +target_compile_options(graph_steps PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + if (MEMILIO_ENABLE_OPENMP) add_executable(graph_timing graph_timing.cpp) target_link_libraries(graph_timing PRIVATE memilio ode_seir) diff --git a/cpp/examples/basic_reproduction_numbers.cpp b/cpp/examples/basic_reproduction_numbers.cpp new file mode 100644 index 0000000000..71cabd73f3 --- /dev/null +++ b/cpp/examples/basic_reproduction_numbers.cpp @@ -0,0 +1,196 @@ + +#include "models/ode_seir/model.h" +#include "models/ode_seir_mobility/model.h" +// #include "models/ode_seir_mobility_improved/model.h" + +#include "memilio/math/euler.h" +#include "memilio/compartments/simulation.h" +#include "memilio/utils/custom_index_array.h" + +Eigen::MatrixXd get_contact_matrix() +{ + Eigen::MatrixXd contact_matrix_eigen(6, 6); + contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, 0.0161, + 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, 0.0458, 0.1939, + 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; + + return contact_matrix_eigen; +} + +const ScalarType TimeExposed[] = {3.335, 3.335, 3.335, 3.335, 3.335, 3.335}; +const ScalarType TimeInfected[] = {8.0096875, 8.0096875, 8.2182, 8.1158, 8.033, 7.985}; +const ScalarType TransmissionProbabilityOnContact[] = {0.03, 0.06, 0.06, 0.06, 0.09, 0.175}; + +void seir(size_t number_regions, ScalarType tmax) +{ + mio::set_log_level(mio::LogLevel::off); + ScalarType t0 = 0.; + ScalarType dt = 0.1; + ScalarType number_age_groups = 6; + + mio::oseir::Model model(number_age_groups); + auto& population = model.populations; + + for (size_t j = 0; j < number_age_groups; j++) { + + population[{mio::AgeGroup(j), mio::oseir::InfectionState::Susceptible}] = number_regions * 10000; + } + population[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; + population[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; + + mio::ContactMatrixGroup& contact_matrix = + model.parameters.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline() = get_contact_matrix(); + + for (size_t j = 0; j < number_age_groups; j++) { + model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = + TransmissionProbabilityOnContact[j]; + } + + std::shared_ptr> integrator = std::make_shared>(); + + auto result = simulate(t0, tmax, dt, model, integrator); + + auto basic_reproduction_number = model.get_reproduction_number(t0, result).value(); + std::cout << "\"SEIR\": " << basic_reproduction_number << ", " << std::endl; +} + +void wang(size_t number_regions, ScalarType tmax) +{ + mio::set_log_level(mio::LogLevel::off); + ScalarType t0 = 0.; + ScalarType dt = 0.1; + ScalarType number_age_groups = 6; + + mio::oseirmobility::Model model(number_regions, number_age_groups); + auto& population = model.populations; + + for (size_t j = 0; j < number_age_groups; j++) { + for (size_t i = 0; i < number_regions; i++) { + population[{mio::oseirmobility::Region(i), mio::AgeGroup(j), + mio::oseirmobility::InfectionState::Susceptible}] = 10000; + } + } + population[{mio::oseirmobility::Region(0), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Exposed}] += 100; + population[{mio::oseirmobility::Region(0), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Susceptible}] -= + 100; + + double fraction_commuter = 1. / (2 * number_regions); + Eigen::MatrixXd mobility_data_commuter = + Eigen::MatrixXd::Constant(number_regions, number_regions, fraction_commuter) - + fraction_commuter * + Eigen::MatrixXd::Identity(number_regions, number_regions); // Ensure that the diagonal is zero + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); + } + model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = + mobility_data_commuter; + + mio::ContactMatrixGroup& contact_matrix = + model.parameters.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline() = get_contact_matrix(); + + for (size_t j = 0; j < number_age_groups; j++) { + model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = + TransmissionProbabilityOnContact[j]; + } + + std::shared_ptr> integrator = std::make_shared>(); + + auto result = simulate(t0, tmax, dt, model, integrator); + + auto basic_reproduction_number = model.get_reproduction_number(t0, result).value(); + std::cout << "\"Wang\": " << basic_reproduction_number << "}" << std::endl; +} + +// void metapopulation(size_t number_regions, ScalarType tmax) +// { +// mio::set_log_level(mio::LogLevel::off); +// ScalarType t0 = 0.; +// ScalarType dt = 0.1; +// ScalarType number_age_groups = 6; + +// mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); +// auto& population = model.populations; + +// for (size_t j = 0; j < number_age_groups; j++) { +// for (size_t i = 0; i < number_regions; i++) { +// population[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), +// mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; +// } +// } +// population[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), +// mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; +// population[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), +// mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; + +// double fraction_commuter = 1. / (2 * number_regions); +// Eigen::MatrixXd mobility_data_commuter = +// Eigen::MatrixXd::Constant(number_regions, number_regions, fraction_commuter) - +// fraction_commuter * +// Eigen::MatrixXd::Identity(number_regions, number_regions); // Ensure that the diagonal is zero +// for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { +// mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); +// } +// model.parameters.template get>() +// .get_cont_freq_mat()[0] +// .get_baseline() = mobility_data_commuter; + +// mio::ContactMatrixGroup& contact_matrix = +// model.parameters.template get>().get_cont_freq_mat(); +// contact_matrix[0].get_baseline() = get_contact_matrix(); + +// for (size_t j = 0; j < number_age_groups; j++) { +// model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; +// model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; +// model.parameters +// .template get>()[mio::AgeGroup(j)] = +// TransmissionProbabilityOnContact[j]; +// } + +// mio::ContactMatrixGroup& commuting_strengths = +// model.parameters.template get>().get_cont_freq_mat(); + +// auto& population_after_commuting = model.m_population_after_commuting; +// for (size_t region_n = 0; region_n < number_regions; ++region_n) { +// for (size_t age = 0; age < number_age_groups; ++age) { +// double population_n = 0; +// for (size_t state = 0; state < (size_t)mio::oseirmobilityimproved::InfectionState::Count; state++) { +// population_n += population[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), +// mio::oseirmobilityimproved::InfectionState(state)}]; +// } +// population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += +// population_n; +// for (size_t region_m = 0; region_m < number_regions; ++region_m) { +// population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= +// commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; +// population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += +// commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; +// } +// } +// } + +// std::shared_ptr> integrator = std::make_shared>(); + +// auto result = simulate(t0, tmax, dt, model, integrator); + +// auto basic_reproduction_number = model.get_reproduction_number(t0, result).value(); +// std::cout << "\"Metapopulation\": " << basic_reproduction_number << "}" << std::endl; +// } + +int main() +{ + const ScalarType tmax = 1.; + size_t num_regions = 150; + + std::cout << "{ \"Regions\": " << num_regions << ", " << std::endl; + + seir(num_regions, tmax); + wang(num_regions, tmax); + // metapopulation(num_regions, tmax); + return 0; +} \ No newline at end of file diff --git a/cpp/examples/graph_steps.cpp b/cpp/examples/graph_steps.cpp new file mode 100644 index 0000000000..d1b2479d64 --- /dev/null +++ b/cpp/examples/graph_steps.cpp @@ -0,0 +1,163 @@ + +#include "ode_seir/model.h" +#include "ode_seir/infection_state.h" +#include "ode_seir/parameters.h" +#include "memilio/mobility/metapopulation_mobility_instant.h" +#include "memilio/compartments/simulation.h" + +#include + +bool age_groups = true; + +void set_contact_matrices(mio::oseir::Parameters& params) +{ + if (age_groups) { + Eigen::MatrixXd contact_matrix_eigen(6, 6); + contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, + 0.0161, 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, + 0.0458, 0.1939, 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; + mio::ContactMatrixGroup& contact_matrix = + params.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline() = contact_matrix_eigen; + } + else { + mio::ContactMatrixGroup& contact_matrix = params.get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(7.95); + } +} + +/** + * Set epidemiological parameters of Sars-CoV-2 for a immune-naive + * population and wild type variant. + * @param params Object that the parameters will be added to. + * @returns Currently generates no errors. + */ +void set_covid_parameters(mio::oseir::Parameters& params) +{ + params.template set>(3.335); + + if (age_groups) { + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; + } + else { + params.get>()[mio::AgeGroup(0)] = 0.07333; + params.get>()[mio::AgeGroup(0)] = 8.097612257; + } +} + +void set_population_data(mio::oseir::Parameters& params, + mio::Graph>>, + mio::MobilityEdge<>>& params_graph, + size_t number_regions) +{ + std::vector> nodes(number_regions, + mio::oseir::Model(int(size_t(params.get_num_groups())))); + + mio::Populations population( + {params.get_num_groups(), mio::oseir::InfectionState::Count}); + + for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { + population[{i, mio::oseir::InfectionState::Susceptible}] = 10000; + } + for (auto& node : nodes) { + node.parameters = params; + node.populations = population; + } + // for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { + nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; + nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; + // } + + for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { + params_graph.add_node(node_idx, nodes[node_idx]); + } +} + +void set_parameters_and_population(mio::Graph>>, + mio::MobilityEdge<>>& params_graph, + size_t number_regions) +{ + int num_age_groups = 1; + if (age_groups) { + num_age_groups = 6; + } + + mio::oseir::Parameters params(num_age_groups); + + set_covid_parameters(params); + + // set contact matrix + set_contact_matrices(params); + + set_population_data(params, params_graph, number_regions); + + for (size_t county_idx_i = 0; county_idx_i < params_graph.nodes().size(); ++county_idx_i) { + for (size_t county_idx_j = 0; county_idx_j < params_graph.nodes().size(); ++county_idx_j) { + double commuter_coeff_ij = 1. / (2 * number_regions); + if (county_idx_i == county_idx_j) { + commuter_coeff_ij = 0; + } + params_graph.add_edge( + county_idx_i, county_idx_j, + Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count * size_t(params.get_num_groups()), + commuter_coeff_ij)); + } + } +} + +void simulate(ScalarType tol, ScalarType tmax) +{ + ScalarType t0 = 0.; + ScalarType dt = 0.5; + size_t number_regions = 100; + + mio::Graph>>, mio::MobilityEdge<>> params_graph; + + set_parameters_and_population(params_graph, number_regions); + + using DefaultIntegratorCore = + mio::ControlledStepperWrapper; + + for (auto& node : params_graph.nodes()) { + node.property.get_simulation().set_integrator(std::make_shared(tol)); + } + + auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); + sim.advance(tmax); + + auto result_graph = std::move(sim).get_graph(); + + for (auto&& node : result_graph.nodes()) { + std::cout << " \"Steps Region " << node.id << "\": " << node.property.get_result().get_num_time_points() - 1 + << "," << std::endl; + } +} + +int main(int argc, char** argv) +{ + mio::set_log_level(mio::LogLevel::off); + const ScalarType tmax = 10; + ScalarType tol = 1e-2; + + if (argc > 1) { + tol = std::stod(argv[1]); + } + + std::cout << "{ \"Absolute tolerance\": " << tol << ", " << std::endl; + simulate(tol, tmax); + std::cout << "\n}," << std::endl; + + return 0; +} diff --git a/cpp/examples/ode_seir_mobility_steps.cpp b/cpp/examples/ode_seir_mobility_steps.cpp new file mode 100644 index 0000000000..6068214be9 --- /dev/null +++ b/cpp/examples/ode_seir_mobility_steps.cpp @@ -0,0 +1,181 @@ +/* +* Copyright (C) 2020-2024 MEmilio +* +* Authors: Carlotta Gerstein +* +* Contact: Martin J. Kuehn +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "memilio/compartments/simulation.h" +#include "memilio/math/euler.h" +#include "memilio/utils/custom_index_array.h" +#include "models/ode_seir_mobility_improved/infection_state.h" +#include "models/ode_seir_mobility_improved/model.h" +#include "models/ode_seir_mobility_improved/parameters.h" +#include "models/ode_seir_mobility_improved/regions.h" + +#include + +bool age_groups = true; + +template +void set_contact_matrix(mio::oseirmobilityimproved::Model& model) +{ + if (age_groups) { + Eigen::MatrixXd contact_matrix_eigen(6, 6); + contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, + 0.0161, 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, + 0.0458, 0.1939, 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; + mio::ContactMatrixGroup& contact_matrix = + model.parameters.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline() = contact_matrix_eigen; + } + { + mio::ContactMatrixGroup& contact_matrix = + model.parameters.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(7.95); + } +} + +/** + * Set epidemiological parameters of Sars-CoV-2 for a immune-naive + * population and wild type variant. + * @param params Object that the parameters will be added to. + * @returns Currently generates no errors. + */ +void set_covid_parameters(mio::oseirmobilityimproved::Parameters& params) +{ + params.template set>(3.335); + + if (age_groups) { + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; + } + else { + params.get>()[mio::AgeGroup(0)] = 0.07333; + params.get>()[mio::AgeGroup(0)] = 8.097612257; + } +} + +template +void set_mobility_weights(mio::oseirmobilityimproved::Model& model) +{ + size_t number_regions = (size_t)model.parameters.get_num_regions(); + double fraction_commuter = 1. / (2 * number_regions); + Eigen::MatrixXd mobility_data_commuter = + Eigen::MatrixXd::Constant(number_regions, number_regions, fraction_commuter) - + fraction_commuter * + Eigen::MatrixXd::Identity(number_regions, number_regions); // Ensure that the diagonal is zero + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); + } + model.parameters.template get>() + .get_cont_freq_mat()[0] + .get_baseline() = mobility_data_commuter; +} + +template +void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) +{ + auto& populations = model.populations; + auto& parameters = model.parameters; + + size_t number_regions = (size_t)parameters.get_num_regions(); + size_t number_age_groups = (size_t)parameters.get_num_agegroups(); + for (size_t j = 0; j < number_age_groups; j++) { + for (size_t i = 0; i < number_regions; i++) { + model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + } + } + model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; + model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; + set_mobility_weights(model); + + set_contact_matrix(model); + + set_covid_parameters(parameters); + + mio::ContactMatrixGroup& commuting_strengths = + parameters.template get>().get_cont_freq_mat(); + + auto& population_after_commuting = model.m_population_after_commuting; + for (size_t region_n = 0; region_n < number_regions; ++region_n) { + for (size_t age = 0; age < number_age_groups; ++age) { + double population_n = 0; + for (size_t state = 0; state < (size_t)mio::oseirmobilityimproved::InfectionState::Count; state++) { + population_n += populations[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), + mio::oseirmobilityimproved::InfectionState(state)}]; + } + population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += + population_n; + for (size_t region_m = 0; region_m < number_regions; ++region_m) { + population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= + commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; + population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += + commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; + } + } + } +} + +void simulate(ScalarType tol, ScalarType tmax) +{ + mio::set_log_level(mio::LogLevel::off); + ScalarType t0 = 0.; + ScalarType dt = 0.1; + size_t number_regions = 100; + ScalarType number_age_groups = 1; + if (age_groups) { + number_age_groups = 6; + } + + mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); + set_parameters_and_population(model); + using DefaultIntegratorCore = + mio::ControlledStepperWrapper; + + std::shared_ptr> integrator = std::make_shared(tol); + std::cout << "{ \"Absolute tolerance\": " << tol << ", " << std::endl; + + auto result = simulate(t0, tmax, dt, model, integrator); + std::cout << "\"Steps\": " << result.get_num_time_points() - 1 << "," << std::endl; +} + +int main(int argc, char** argv) +{ + const ScalarType tmax = 10; + ScalarType tol = 1e-12; + + if (argc > 1) { + tol = std::stod(argv[1]); + } + + simulate(tol, tmax); + return 0; +} From fd2bfdd2521a6561b2f4aba7599e84dd857e0cb1 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 9 Jan 2025 09:24:42 +0100 Subject: [PATCH 52/87] remove synthetic population for simulation --- cpp/examples/ode_seir_mobility.cpp | 135 ++++++++++------------------- 1 file changed, 44 insertions(+), 91 deletions(-) diff --git a/cpp/examples/ode_seir_mobility.cpp b/cpp/examples/ode_seir_mobility.cpp index f77b795935..6091d40db4 100644 --- a/cpp/examples/ode_seir_mobility.cpp +++ b/cpp/examples/ode_seir_mobility.cpp @@ -10,6 +10,7 @@ #include "models/ode_seir_mobility/regions.h" #include "memilio/io/io.h" #include "memilio/io/epi_data.h" +#include "memilio/io/result_io.h" /** * Set epidemiological parameters of Sars-CoV-2 for a immune-naive @@ -17,29 +18,22 @@ * @param params Object that the parameters will be added to. * @returns Currently generates no errors. */ -mio::IOResult set_covid_parameters(mio::oseirmobility::Parameters& params, bool synthetic_population) +mio::IOResult set_covid_parameters(mio::oseirmobility::Parameters& params) { params.template set>(3.335); - if (!synthetic_population) { - params.get>()[mio::AgeGroup(0)] = 8.0096875; - params.get>()[mio::AgeGroup(1)] = 8.0096875; - params.get>()[mio::AgeGroup(2)] = 8.2182; - params.get>()[mio::AgeGroup(3)] = 8.1158; - params.get>()[mio::AgeGroup(4)] = 8.033; - params.get>()[mio::AgeGroup(5)] = 7.985; - - params.get>()[mio::AgeGroup(0)] = 0.03; - params.get>()[mio::AgeGroup(1)] = 0.06; - params.get>()[mio::AgeGroup(2)] = 0.06; - params.get>()[mio::AgeGroup(3)] = 0.06; - params.get>()[mio::AgeGroup(4)] = 0.09; - params.get>()[mio::AgeGroup(5)] = 0.175; - } - else { - params.template set>(8.097612257); - - params.template set>(0.07333); - } + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; printf("Setting epidemiological parameters successful.\n"); return mio::success(); @@ -69,30 +63,21 @@ static const std::map contact_locations = {{Contac * @param params Object that the contact matrices will be added to. * @returns any io errors that happen during reading of the files. */ -mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseirmobility::Parameters& params, - bool synthetic_population) +mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseirmobility::Parameters& params) { - if (!synthetic_population) { - //TODO: io error handling - auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_agegroups())); - for (auto&& contact_location : contact_locations) { - BOOST_OUTCOME_TRY(auto&& baseline, - mio::read_mobility_plain( - (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); - BOOST_OUTCOME_TRY(auto&& minimum, - mio::read_mobility_plain( - (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); - contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; - contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; - } - params.get>() = - mio::UncertainContactMatrix(contact_matrices); - } - else { - mio::ContactMatrixGroup& contact_matrix = - params.get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(7.95 / (size_t)params.get_num_agegroups()); + //TODO: io error handling + auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_agegroups())); + for (auto&& contact_location : contact_locations) { + BOOST_OUTCOME_TRY(auto&& baseline, + mio::read_mobility_plain( + (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); + BOOST_OUTCOME_TRY(auto&& minimum, + mio::read_mobility_plain( + (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); + contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; + contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; } + params.get>() = mio::UncertainContactMatrix(contact_matrices); printf("Setting contact matrices successful.\n"); return mio::success(); @@ -168,42 +153,20 @@ mio::IOResult set_mobility_weights(mio::oseirmobility::Model& model, c } template -mio::IOResult set_parameters_and_population(mio::oseirmobility::Model& model, const fs::path& data_dir, - bool synthetic_population) +mio::IOResult set_parameters_and_population(mio::oseirmobility::Model& model, const fs::path& data_dir) { auto& populations = model.populations; auto& parameters = model.parameters; - size_t number_regions = (size_t)parameters.get_num_regions(); - size_t number_age_groups = (size_t)parameters.get_num_agegroups(); - - if (synthetic_population) { - printf("Data is not compatible, using synthetic population instead.\n"); - for (size_t j = 0; j < number_age_groups; j++) { - model.populations[{mio::oseirmobility::Region(0), mio::AgeGroup(j), - mio::oseirmobility::InfectionState::Exposed}] = 100; - model.populations[{mio::oseirmobility::Region(0), mio::AgeGroup(j), - mio::oseirmobility::InfectionState::Susceptible}] = 999900; - for (size_t i = 1; i < number_regions; i++) { - model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(j), - mio::oseirmobility::InfectionState::Exposed}] = 0; - model.populations[{mio::oseirmobility::Region(i), mio::AgeGroup(j), - mio::oseirmobility::InfectionState::Susceptible}] = 1000000; - } - } - } - else { - BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); - populations[{mio::oseirmobility::Region(27), mio::AgeGroup(0), - mio::oseirmobility::InfectionState::Susceptible}] -= 100; - populations[{mio::oseirmobility::Region(27), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Exposed}] += - 100; - } + BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); + populations[{mio::oseirmobility::Region(27), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Susceptible}] -= + 100; + populations[{mio::oseirmobility::Region(27), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Exposed}] += 100; BOOST_OUTCOME_TRY(set_mobility_weights(model, data_dir)); - BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters, synthetic_population)) + BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters)) - BOOST_OUTCOME_TRY(set_covid_parameters(parameters, synthetic_population)); + BOOST_OUTCOME_TRY(set_covid_parameters(parameters)); return mio::success(); } @@ -213,37 +176,27 @@ int main() mio::set_log_level(mio::LogLevel::debug); ScalarType t0 = 0.; - ScalarType tmax = 50.; + ScalarType tmax = 100.; ScalarType dt = 0.1; - ScalarType number_regions = 53; - std::vector region_ids(number_regions); - iota(region_ids.begin(), region_ids.end(), 1); + ScalarType number_regions = 53; ScalarType number_age_groups = 6; - bool synthetic_population = false; - if (number_age_groups != 6) { - synthetic_population = true; - } mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& data_dir = ""; + const std::string& data_dir = "/home/gers_ca/code/memilio/data"; mio::oseirmobility::Model model(number_regions, number_age_groups); - auto result_prepare_simulation = set_parameters_and_population(model, data_dir, synthetic_population); - - // using DefaultIntegratorCore = - // mio::ControlledStepperWrapper; + auto result_prepare_simulation = set_parameters_and_population(model, data_dir); - std::shared_ptr> integrator = std::make_shared>(); + // std::shared_ptr> integrator = std::make_shared>(); model.check_constraints(); - auto result_from_sim = simulate(t0, tmax, dt, model, integrator); + auto result_from_sim = simulate(t0, tmax, dt, model); - // auto save_result_status = - // mio::save_result({result_from_sim}, region_ids, number_regions * number_age_groups, "ode_result_standard2.h5"); + auto result = mio::interpolate_simulation_result(result_from_sim); - auto basic_reproduction_number = model.get_reproduction_number(0, result_from_sim).value(); - std::cout << "\nbasis reproduction number: " << basic_reproduction_number << "\n"; + auto save_result_status = + mio::save_result({result}, {1}, number_regions * number_age_groups, "ode_result_paper_nrw_adaptive.h5"); } From 33bf7a9dc00d783feb8aa698f1f15a770e9366bb Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 9 Jan 2025 09:25:27 +0100 Subject: [PATCH 53/87] small improvement model c --- cpp/models/ode_seir_mobility_improved/model.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index 061be62017..837bf78afb 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -72,7 +72,6 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t)(age_i, age_j) * params.template get>()[AgeGroup(age_i)]; - flow_SE_helper += pop[Ijn] * Nj_inv + infections_due_commuting(region_n); flows[Base::template get_flat_flow_index( {Region(region_n), AgeGroup(age_i)})] += - flow_SE_helper * coeffStoI * + (pop[Ijn] * Nj_inv + infections_due_commuting(region_n)) * coeffStoI * y[population.get_flat_index({Region(region_n), AgeGroup(age_i), InfectionState::Susceptible})]; } } From 24883f33e56447a3afbd8e16483f9fd0ca244083 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 9 Jan 2025 09:27:35 +0100 Subject: [PATCH 54/87] remove steps from timing example --- cpp/examples/graph_timing.cpp | 17 +++-------------- cpp/examples/ode_seir_mobility_timing.cpp | 16 ++++++---------- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/cpp/examples/graph_timing.cpp b/cpp/examples/graph_timing.cpp index 2041a9768c..7e7b9c2ba3 100644 --- a/cpp/examples/graph_timing.cpp +++ b/cpp/examples/graph_timing.cpp @@ -69,7 +69,7 @@ void set_population_data(mio::oseir::Parameters& params, {params.get_num_groups(), mio::oseir::InfectionState::Count}); for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { - population[{i, mio::oseir::InfectionState::Susceptible}] = 1000000; + population[{i, mio::oseir::InfectionState::Susceptible}] = 10000; } for (auto& node : nodes) { node.parameters = params; @@ -138,7 +138,7 @@ double simulate_runtime(size_t number_regions, ScalarType tmax) return end_time - start_time; } -int simulate_steps(size_t number_regions, ScalarType tmax) +void simulate(size_t number_regions, ScalarType tmax) { ScalarType t0 = 0.; ScalarType dt = 0.5; @@ -149,15 +149,6 @@ int simulate_steps(size_t number_regions, ScalarType tmax) auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); sim.advance(tmax); - - auto result_graph = std::move(sim).get_graph(); - - int num_steps = 0; - for (auto&& node : result_graph.nodes()) { - num_steps += node.property.get_result().get_num_time_points() - 1; - } - - return num_steps; } int main(int argc, char** argv) @@ -175,11 +166,9 @@ int main(int argc, char** argv) std::cout << "{ \"Regions\": " << num_regions << ", " << std::endl; // Warm up runs. - int num_steps = 0; for (size_t i = 0; i < warm_up; i++) { - num_steps = simulate_steps(num_regions, tmax); + simulate(num_regions, tmax); } - std::cout << "\"Steps\": " << num_steps / num_regions << "," << std::endl; // Runs with timing. ScalarType total = 0; diff --git a/cpp/examples/ode_seir_mobility_timing.cpp b/cpp/examples/ode_seir_mobility_timing.cpp index 9fd9c0823f..0b3b184941 100644 --- a/cpp/examples/ode_seir_mobility_timing.cpp +++ b/cpp/examples/ode_seir_mobility_timing.cpp @@ -107,14 +107,14 @@ void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) size_t number_age_groups = (size_t)parameters.get_num_agegroups(); for (size_t j = 0; j < number_age_groups; j++) { for (size_t i = 0; i < number_regions; i++) { - model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; } } - model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; - model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; + populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; + populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), + mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; set_mobility_weights(model); set_contact_matrix(model); @@ -157,9 +157,6 @@ void simulate(size_t num_warm_up_runs, size_t num_runs, size_t number_regions, S mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); set_parameters_and_population(model); - // using DefaultIntegratorCore = - // mio::ControlledStepperWrapper; - std::shared_ptr> integrator = std::make_shared>(); std::cout << "{ \"Regions\": " << number_regions << ", " << std::endl; @@ -169,7 +166,6 @@ void simulate(size_t num_warm_up_runs, size_t num_runs, size_t number_regions, S simulate(t0, tmax, dt, model, integrator); } auto result = simulate(t0, tmax, dt, model, integrator); - std::cout << "\"Steps\": " << result.get_num_time_points() << "," << std::endl; // Runs with timing. ScalarType total = 0; From 4db243def617d44961679b6fbca71143fbef6636 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 9 Jan 2025 09:31:28 +0100 Subject: [PATCH 55/87] changes in plots --- tools/basic_reproduction_numbers.py | 40 ++++++ tools/plot_mobility_runtimes.py | 130 +++++++++++++------ tools/plot_results_mobility.py | 188 +++++++++++++++++++++------- 3 files changed, 279 insertions(+), 79 deletions(-) create mode 100644 tools/basic_reproduction_numbers.py diff --git a/tools/basic_reproduction_numbers.py b/tools/basic_reproduction_numbers.py new file mode 100644 index 0000000000..d1ddfb0fc2 --- /dev/null +++ b/tools/basic_reproduction_numbers.py @@ -0,0 +1,40 @@ +from sympy import * +init_printing() + +# 2 Age Groups: +def calculate_eigenvalues_explicit(): + rho=[0.07333, 0.07333, 0.07333] + S=[9990, 10000, 10000] + N=[10000, 10000, 10000] + T_I=[8.097612257, 8.097612257, 8.097612257] + phi=[[7.95/3, 7.95/3, 7.95/3], + [7.95/3, 7.95/3, 7.95/3], + [7.95/3, 7.95/3, 7.95/3]] + value1 = -(-3*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]*N[1]*N[2]) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**2/(N[0]**2*N[1]**2*N[2]**2))/(3*(sqrt(-4*(-3*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]*N[1]*N[2]) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**2/(N[0]**2*N[1]**2*N[2]**2))**3 + (27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]**2*N[1]**2*N[2]**2) + 2*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**2)/2 + 27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(2*N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(2*N[0]**2*N[1]**2*N[2]**2) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**(1/3)) - (sqrt(-4*(-3*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]*N[1]*N[2]) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**2/(N[0]**2*N[1]**2*N[2]**2))**3 + (27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]**2*N[1]**2*N[2]**2) + 2*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**2)/2 + 27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(2*N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(2*N[0]**2*N[1]**2*N[2]**2) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**(1/3)/3 - (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])/(3*N[0]*N[1]*N[2]) + value2 = -(-3*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]*N[1]*N[2]) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**2/(N[0]**2*N[1]**2*N[2]**2))/(3*(-1/2 + sqrt(3)*I/2)*(sqrt(-4*(-3*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]*N[1]*N[2]) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**2/(N[0]**2*N[1]**2*N[2]**2))**3 + (27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]**2*N[1]**2*N[2]**2) + 2*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**2)/2 + 27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(2*N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(2*N[0]**2*N[1]**2*N[2]**2) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**(1/3)) - (-1/2 + sqrt(3)*I/2)*(sqrt(-4*(-3*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]*N[1]*N[2]) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**2/(N[0]**2*N[1]**2*N[2]**2))**3 + (27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]**2*N[1]**2*N[2]**2) + 2*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**2)/2 + 27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(2*N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(2*N[0]**2*N[1]**2*N[2]**2) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**(1/3)/3 - (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])/(3*N[0]*N[1]*N[2]) + value3 = -(-3*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]*N[1]*N[2]) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**2/(N[0]**2*N[1]**2*N[2]**2))/(3*(-1/2 - sqrt(3)*I/2)*(sqrt(-4*(-3*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]*N[1]*N[2]) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**2/(N[0]**2*N[1]**2*N[2]**2))**3 + (27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]**2*N[1]**2*N[2]**2) + 2*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**2)/2 + 27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(2*N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(2*N[0]**2*N[1]**2*N[2]**2) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**(1/3)) - (-1/2 - sqrt(3)*I/2)*(sqrt(-4*(-3*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]*N[1]*N[2]) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**2/(N[0]**2*N[1]**2*N[2]**2))**3 + (27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(N[0]**2*N[1]**2*N[2]**2) + 2*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**2)/2 + 27*(-S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][1]*phi[2][2]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][0]*phi[1][2]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][0]*phi[2][2]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][1]*phi[1][2]*phi[2][0]*rho[0]*rho[1]*rho[2] - S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][0]*phi[2][1]*rho[0]*rho[1]*rho[2] + S[0]*S[1]*S[2]*T_I[0]*T_I[1]*T_I[2]*phi[0][2]*phi[1][1]*phi[2][0]*rho[0]*rho[1]*rho[2])/(2*N[0]*N[1]*N[2]) - 9*(-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])*(N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][1]*phi[2][2]*rho[1]*rho[2] - N[0]*S[1]*S[2]*T_I[1]*T_I[2]*phi[1][2]*phi[2][1]*rho[1]*rho[2] + N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][0]*phi[2][2]*rho[0]*rho[2] - N[1]*S[0]*S[2]*T_I[0]*T_I[2]*phi[0][2]*phi[2][0]*rho[0]*rho[2] + N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][0]*phi[1][1]*rho[0]*rho[1] - N[2]*S[0]*S[1]*T_I[0]*T_I[1]*phi[0][1]*phi[1][0]*rho[0]*rho[1])/(2*N[0]**2*N[1]**2*N[2]**2) + (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])**3/(N[0]**3*N[1]**3*N[2]**3))**(1/3)/3 - (-N[0]*N[1]*S[2]*T_I[2]*phi[2][2]*rho[2] - N[0]*N[2]*S[1]*T_I[1]*phi[1][1]*rho[1] - N[1]*N[2]*S[0]*T_I[0]*phi[0][0]*rho[0])/(3*N[0]*N[1]*N[2]) + print(str(value1) + '\n' + str(value2) + '\n' + str(value3)) + +def calculate_eigenvalues(number_age_groups): + rho= symbols('rho[0]:%d'%number_age_groups) + S = symbols('S0:%d'%number_age_groups) + N = symbols('N0:%d'%number_age_groups) + T_I = symbols('T_I0:%d'%number_age_groups) + phi = [list(symbols('phi' + str(i) + '_0:%d'%number_age_groups)) for i in range(number_age_groups)] + # rho=[0.07333, 0.07333, 0.07333] + # S=[9990, 9990, 9990] + # N=[10000, 10000, 10000] + # T_I=[8.0096875, 8.0096875, 8.2182] + # phi=[[7.95/3, 7.95/3, 7.95/3], + # [7.95/3, 7.95/3, 7.95/3], + # [7.95/3, 7.95/3, 7.95/3]] + next_gen_matrix = zeros(number_age_groups, number_age_groups) + for i in range(number_age_groups): + for j in range(number_age_groups): + next_gen_matrix[i, j] = rho[i] * S[i] * phi[i][j] * T_I[j] / N[j] + p = next_gen_matrix.charpoly(lamda) + print(factor(p.as_expr())) + +if __name__ == '__main__': + calculate_eigenvalues(2) + # calculate_eigenvalues_explicit() \ No newline at end of file diff --git a/tools/plot_mobility_runtimes.py b/tools/plot_mobility_runtimes.py index 437f34149c..ba2f0f466e 100644 --- a/tools/plot_mobility_runtimes.py +++ b/tools/plot_mobility_runtimes.py @@ -1,12 +1,11 @@ import matplotlib.pyplot as plt import pandas as pd +import numpy as np import os -import json -import re -colors = ["tab:blue", "tab:orange", "tab:green", - "tab:red", "tab:purple", "tab:brown"] +colors = ['#1f77b4', '#2ca02c', '#ff7f0e'] +linestyles=['-', '--', '-.', ':'] fontsize_labels = 16 fontsize_legends = 12 @@ -18,8 +17,8 @@ def plot_runtime(file, name=''): plt.plot(df["Regions"], df["Time"], linestyle='--', marker='o', linewidth=1.2) - plt.ylim(bottom=0.) - plt.xlim(left=0., right=df["Regions"].max()+1) + plt.ylim(bottom=df['Time'].min()) + plt.xlim(left=df["Regions"].min()-1, right=df["Regions"].max()+1) plt.xlabel('Number of regions', fontsize=fontsize_labels) plt.ylabel('Run time [seconds]', fontsize=fontsize_labels) plt.yticks(fontsize=fontsize_legends) @@ -28,19 +27,92 @@ def plot_runtime(file, name=''): plt.tight_layout() plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') - name = os.path.splitext(os.path.basename(file))[0] + if name is None: + name = os.path.splitext(os.path.basename(file))[0] + plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) + plt.close() + +def plot_flops(name='number_flops'): + fig, ax = plt.subplots() + + def flops_equation_based(x, eta): + return (4*x**2+22*x+1)/eta + + def flops_graph_based(x, eta): + return (43*x**2+24*x/eta+2)*1 + + x = np.linspace(0, 400, 80) + + + for idx, eta in enumerate([0.05, 0.1, 0.2, 0.5]): + ax.plot(x, flops_equation_based(x, eta), linewidth=1.5, color=colors[0], linestyle=linestyles[idx], label='Model C, $\eta=$'+ str(eta)) + ax.plot(x, flops_graph_based(x, eta), linewidth=1.5, color=colors[1], linestyle=linestyles[idx], label='Model D, $\eta=$'+ str(eta)) + ax.set_ylim(bottom=0.) + ax.set_xlim(left=0., right=400.) + ax.set_xlabel('Number of regions', fontsize=fontsize_labels) + ax.set_ylabel('Number of FLOPs', fontsize=fontsize_labels) + + handles, labels = ax.get_legend_handles_labels() + sorted_handles_labels = sorted(zip(handles, labels), key=lambda x: x[1]) + + sorted_handles, sorted_labels = zip(*sorted_handles_labels) + + plt.tight_layout() + ax.legend(sorted_handles, sorted_labels, fontsize=fontsize_legends) + plt.grid(linestyle='--') + + plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') + plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) + plt.close() + + + +def compare_runtime_and_flops(files, name=''): + fig, ax1 = plt.subplots() + + for file in files: + df = pd.read_json(file) + + ax1.plot(df["Regions"], df["Time"], + linestyle='--', marker='o', linewidth=1.2, label=file) + + ax1.set_ylim(bottom=0.) + ax1.set_xlim(left=0., right=400.) + ax1.set_xlabel('Number of regions', fontsize=fontsize_labels) + ax1.set_ylabel('Run time [seconds]', fontsize=fontsize_labels) + + ax2 = ax1.twinx() + + def flops_equation_based(x): + return (4*x**2+22*x+1)*200 + + def flops_graph_based(x): + return (43*x**2+240*x+2)*20 + + x = np.linspace(0, 400, 400) + + ax2.plot(x, flops_equation_based(x), linestyle='--', linewidth=1.2) + ax2.plot(x, flops_graph_based(x), linestyle='--', linewidth=1.2) + ax2.set_ylabel('Number of FLOPs', fontsize=fontsize_labels) + ax2.set_ylim(bottom=0.) + + plt.tight_layout() + + plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) + plt.close() def compare_runtimes(files, name='', title='', models=[]): merged_df = pd.DataFrame() i = 0 for file in files: df = pd.read_json(file) - + df = df.filter(items=['Regions', 'Time']) + # df.drop(thisFilter, inplace=True, axis=1) df.rename(columns={'Time': models[i]}, inplace=True) if merged_df.empty: - merged_df = df + merged_df = df else: merged_df = pd.merge(merged_df, df, on='Regions', how='outer') i = i+1 @@ -69,31 +141,15 @@ def compare_runtimes(files, name='', title='', models=[]): if __name__ == "__main__": result_dir = os.path.join(os.path.dirname(__file__), '../results') - result_equationbased_start = os.path.join(result_dir, 'timing_equationbased_start.json') - result_equationbased = os.path.join(result_dir, 'timing_equationbased.json') - result_equationbased_O3 = os.path.join(result_dir, 'timing_equationbased_O3.json') - result_equationbased_O2 = os.path.join(result_dir, 'timing_equationbased_O2.json') - result_equationbased_O1 = os.path.join(result_dir, 'timing_equationbased_O1.json') - result_equationbased_O0 = os.path.join(result_dir, 'timing_equationbased_O0.json') - result_graphbased_start = os.path.join(result_dir, 'timing_graphbased_start.json') - result_graphbased = os.path.join(result_dir, 'timing_graphbased.json') - result_graphbased_smallsteps = os.path.join(result_dir, 'timing_graphbased_01steps.json') - result_graphbased_unoptimized = os.path.join(result_dir, 'timing_graphbased_unoptimized.json') - - result_equationbased_mod4_0 = os.path.join(result_dir, 'timing_equationbased_mod4_0.json') - result_equationbased_mod4_1 = os.path.join(result_dir, 'timing_equationbased_mod4_1.json') - result_equationbased_mod4_2 = os.path.join(result_dir, 'timing_equationbased_mod4_2.json') - result_equationbased_mod4_3 = os.path.join(result_dir, 'timing_equationbased_mod4_3.json') - - results_start = [result_equationbased_start, result_graphbased_start] - results = [result_equationbased, result_graphbased, result_graphbased_smallsteps] - results_unoptimized = [result_equationbased_O3, result_equationbased_O2, result_equationbased_O1, result_equationbased_O0] - results_mod4 = [result_equationbased_mod4_0, result_equationbased_mod4_1, result_equationbased_mod4_2, result_equationbased_mod4_3] - - # plot_runtime(result_equationbased) - # plot_runtime(result_graphbased) - - # compare_runtimes(results_start,name='compare_runtimes_start', title='Runtimes for Euler Method', models=models) - compare_runtimes(results, name='compare_runtimes', title='Runtimes for Euler Method', models=['Equation-based model', 'Graph-based model', 'Graph-based model with dt=0.1']) - compare_runtimes(results_unoptimized, name='compare_runtimes_unoptimized', title='Runtimes for Euler Method', models=['-O3', '-O2', '-O1', '-O0']) - compare_runtimes(results_mod4, name='compare_runtimes_mod4', title='Runtimes for Euler Method', models=['%4=0', '%4=1', '%4=2', '%4=3']) + result_equationbased_euler = os.path.join(result_dir, 'timing_equationbased_euler.json') + result_equationbased_noage_euler = os.path.join(result_dir, 'timing_equationbased_noage_euler.json') + result_graphbased_euler = os.path.join(result_dir, 'timing_graphbased_euler.json') + result_graphbased_noage_euler = os.path.join(result_dir, 'timing_graphbased_noage_euler.json') + + results_euler = [result_equationbased_euler, result_graphbased_euler] + results_euler_noage = [result_equationbased_noage_euler, result_graphbased_noage_euler] + + # compare_runtimes(results_euler, name='compare_runtimes_euler', models=models) + # compare_runtimes(results_euler_noage, name='compare_runtimes_euler_noage', models=models) + # compare_runtime_and_flops(results_euler_noage, 'compare_runtimes_and_flops') + plot_flops() diff --git a/tools/plot_results_mobility.py b/tools/plot_results_mobility.py index 21a0523d75..f8121c5676 100644 --- a/tools/plot_results_mobility.py +++ b/tools/plot_results_mobility.py @@ -17,6 +17,7 @@ import matplotlib.pyplot as plt import matplotlib.colors as mcolors +from matplotlib.ticker import FormatStrFormatter compartments = {'Susceptible': 0, 'Exposed': 1, @@ -33,7 +34,8 @@ def plot_map_nrw(data: pd.DataFrame, fig_name: str = 'customPlot', dpi: int = 300, outercolor='white', - log_scale=False): + log_scale=False, + cmap='viridis'): """! Plots region-specific information onto a interactive html map and returning svg and png image. Allows the comparisons of a variable list of data sets. @@ -96,13 +98,19 @@ def plot_map_nrw(data: pd.DataFrame, # Use n+2 many columns (1: legend + 2: empty space + 3-n: data sets) and # n+2 rows where the top row is used for a potential title, the second row # for the content and all other rows have height zero. - height_ratios = [0.25, 1, 0] - if len(data_columns) > 1: - height_ratios = height_ratios + [ - 0.0 for i in range(len(data_columns)-1)] - gs = GridSpec( - len(data_columns) + 2, len(data_columns) + 2, figure=fig, - width_ratios=[1 for i in range(len(data_columns))] + [0.1, 0.2], + height_ratios = [0.05, 1] + # if len(data_columns) > 1: + # height_ratios = height_ratios + [ + # 0.0 for i in range(len(data_columns)-1)] + if plot_colorbar: + gs = GridSpec( + 2, len(data_columns)+2, figure=fig, + width_ratios=[1 for i in range(len(data_columns))]+[0.1, 0.2], + height_ratios=height_ratios) + else: + gs = GridSpec( + 2, len(data_columns), figure=fig, + width_ratios=[1 for i in range(len(data_columns))], height_ratios=height_ratios) # Use top row for title. @@ -118,10 +126,11 @@ def plot_map_nrw(data: pd.DataFrame, if log_scale: norm = mcolors.LogNorm(vmin=scale_colors[0], vmax=scale_colors[1]) + else: + norm = mcolors.TwoSlopeNorm(vmin=scale_colors[0], vmax=scale_colors[1], vcenter=0) for i in range(len(data_columns)): - cmap = 'inferno' ax = fig.add_subplot(gs[1, i]) if log_scale: map_data.plot(data_columns[i], ax=ax, legend=False, @@ -129,47 +138,113 @@ def plot_map_nrw(data: pd.DataFrame, elif cax is not None: map_data.plot(data_columns[i], ax=ax, cax=cax, legend=True, - vmin=scale_colors[0], vmax=scale_colors[1]) + vmin=scale_colors[0], vmax=scale_colors[1], cmap=cmap) else: # Do not plot colorbar. map_data.plot(data_columns[i], ax=ax, legend=False, - vmin=scale_colors[0], vmax=scale_colors[1]) + vmin=scale_colors[0], vmax=scale_colors[1], cmap=cmap) - ax.set_title(legend[i], fontsize=10) + ax.set_title(legend[i], fontsize=9) ax.set_axis_off() - sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) - sm.set_array([]) - cbar = fig.colorbar(sm, cax=cax) - cbar.set_ticks([scale_colors[0], scale_colors[1]]) - cbar.set_ticklabels([f'{scale_colors[0]:.4e}', f'{scale_colors[1]:.4e}']) - - plt.subplots_adjust(bottom=0.1) + if plot_colorbar: + sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) + sm.set_array([]) + cbar = fig.colorbar(sm, cax=cax) + # cbar.set_ticks([scale_colors[0], scale_colors[1]]) + # cbar.set_ticklabels([f'{scale_colors[0]:.3e}', f'{scale_colors[1]:.3e}'], fontsize=7) + + plt.subplots_adjust(bottom=0.1, left=0.1) + plt.tight_layout() plt.savefig(os.path.join(output_path, fig_name + '.png'), dpi=dpi) plt.close() def plot_maps(files, output_dir, legend, name=''): - for date in range(10, 21, 10): - dfs_all = extract_nrw_data_and_combine(files=files, date=date) + min_val = 10e-6 + max_val = 0.4 - min_val = dfs_all[dfs_all.columns[1:]].min().min() - max_val = dfs_all[dfs_all.columns[1:]].max().max() + cmap = 'viridis' + norm = mcolors.LogNorm(vmin=min_val, vmax=max_val) + sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) + sm.set_array([]) + cbar_fig, cax = plt.subplots(figsize=(12, 1)) + cbar = plt.colorbar(sm, orientation='horizontal', cax=cax) + cbar.ax.tick_params(labelsize=10) + cbar.set_ticks([min_val, max_val]) + cbar.ax.xaxis.set_major_formatter(FormatStrFormatter('%.5f')) + plt.subplots_adjust(bottom=0.3) + plt.savefig(os.path.join(output_dir, 'colorbar.png'), dpi=300) + plt.close() + + for date in range(10, 101, 20): + dfs_all = extract_nrw_data_and_combine(files=files, date=date) plot_map_nrw( dfs_all, scale_colors=[min_val, max_val], legend=legend, - title='NRW - Simulation Day '+str(date), plot_colorbar=True, + title='NRW - Simulation Day '+str(date), plot_colorbar=False, output_path=output_dir, fig_name=name+str(date), dpi=900, outercolor='white', log_scale=True) -def extract_nrw_data_and_combine(files, date): +def plot_difference_2D(files, output_dir): + fig = plt.figure() + + df_dif = pd.DataFrame(columns=['Time', 'difference', 'absolute value']) + dates = [i for i in range(100)] + df_dif['Time'] = dates + df_dif.set_index('Time', inplace=True) + + total_population = 18190422. + + for date in range(100): + dfs_all = extract_nrw_data_and_combine(files=files, date=date, relative=False) + df_dif.loc[date,'difference'] = (dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]]).sum() / total_population + df_dif.loc[date,'absolute value'] = abs(dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]]).sum() / total_population + + # df_dif.set_index('Time', inplace=True) + df_dif['difference'].plot(label='Difference') + df_dif['absolute value'].plot(label='Difference in absolute value') + plt.legend() + plt.grid(linestyle='--') + plt.savefig(os.path.join(output_dir, 'difference2D.png')) + plt.close() + + +def plot_difference(files, output_dir): + fig = plt.figure() + + df_dif = pd.DataFrame(columns=['Region']) + + for date in range(60, 101, 10): + dfs_all = extract_nrw_data_and_combine(files=files, date=date, relative=True) + df_dif['Region'] = dfs_all['Region'] + + + df_dif['Count (rel)' + str(date)] = dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]] + + # df_dif = df_dif[df_dif['Count (rel)' + str(date)] > 0] + + min_val = df_dif.drop(columns=['Region']).min().min() + max_val = df_dif.drop(columns=['Region']).max().max() + maximum_abs = abs(max([min_val, max_val], key=abs)) + + plot_map_nrw( + df_dif, scale_colors=[-maximum_abs, maximum_abs], + legend=['Day ' + str(date) for date in range(60, 101, 10)], + title='Difference between ODE and graph-based model', plot_colorbar=True, + output_path=output_dir, + fig_name="difference", dpi=900, + outercolor='white', + log_scale=False, + cmap='seismic') + +def extract_nrw_data_and_combine(files, date, relative=True): age_groups = {0: '0-4', 1: '5-14', 2: '15-34', 3: '35-59', 4: '60-79', 5: '80+'} filter_age = None - relative = True i = 0 for file in files.values(): @@ -229,9 +304,13 @@ def extract_nrw_data_and_combine(files, date): return dfs_all -def plot_total_compartment(files, output_dir, legend, compartment = 'Infected', name='', title=''): +def plot_total_compartment(files, output_dir, legend, compartment = 'Infected', name='', ax=None, print_legend=True): + colors = ['#1f77b4', '#2ca02c', '#ff7f0e'] file_idx = 0 + if ax is None: + fig, ax = plt.subplots() + ax.grid(True, linestyle='--') for file in files.values(): model_type = os.path.basename(file).split('_')[0] # Load data. @@ -239,7 +318,9 @@ def plot_total_compartment(files, output_dir, legend, compartment = 'Infected', if model_type=='ode': dates = h5file['1']['Time'][:] data = h5file['1']['Total'][:,compartments[compartment]] - plt.plot(dates, data, label=legend[file_idx]) + ax.plot(dates, data, label=legend[file_idx], linewidth=2, color=colors[file_idx]) + ax.set_ylim(bottom=0.) + ax.set_xlim(left=0., right=dates.max()+1) else: df = pd.DataFrame() regions = list(h5file.keys()) @@ -247,35 +328,58 @@ def plot_total_compartment(files, output_dir, legend, compartment = 'Infected', df['Region'+str(i)] = h5file[regions[i]]['Total'][:, compartments[compartment]] df['Total'] = df.sum(axis=1) df['Time'] = h5file[regions[0]]['Time'][:] # hardcoded - plt.plot(df['Time'], df['Total'], label=legend[file_idx], linestyle='dashed') + ax.plot(df['Time'], df['Total'], label=legend[file_idx], linewidth=1.2, color=colors[file_idx]) + ax.set_ylim(bottom=0.) + ax.set_xlim(left=0., right=df['Time'].max()+1) + # ax.legend() file_idx = file_idx+1 - plt.title(title) - plt.legend() + plt.tight_layout() + if print_legend: + plt.legend() plt.savefig(os.path.join(output_dir, name + '.png'), dpi=300) + + return ax + +def compare_compartments(files, output_dir, legend): + fig, axs = plt.subplots( + 2, 2, sharex='all') + axs = axs.flatten() + for i, compartment in enumerate(compartments.keys()): + plot_total_compartment(files=files, output_dir=output_dir, legend=legend, compartment=compartment, ax=axs[i], print_legend=False) + plt.tight_layout() + plt.subplots_adjust(bottom=0.15) + lines, labels = axs[0].get_legend_handles_labels() + fig.legend(lines, labels, ncol=len(models), loc='center', + fontsize=10, bbox_to_anchor=(0.5, 0.05)) + plt.savefig(os.path.join(output_dir, 'compare_all_compartments.png'), dpi=300) plt.close() if __name__ == '__main__': - files_input = {'Data set 1': 'cpp/build/ode_result_timing', - 'Data set 3': 'cpp/build/graph_result_timing'}#, - # 'Data set 2': 'cpp/build/ode_result_standard2'} + results_euler = {'Model B': 'cpp/build/ode_result_paper_nrw_euler', + 'Model C': 'cpp/build/ode_result_nrw_euler', + 'Model D': 'cpp/build/graph_result_nrw_euler'} + results_adaptive = {'Model B': 'cpp/build/ode_result_paper_nrw_adaptive', + 'Model C': 'cpp/build/ode_result_nrw_adaptive', + 'Model D': 'cpp/build/graph_result_nrw_adaptive'} files_compare_solver = {'Data set 1': 'cpp/build/ode_result_nrw_euler', 'Data set 2': 'cpp/build/ode_result_nrw_adaptive', 'Data set 3': 'cpp/build/graph_result_nrw_euler', 'Data set 4': 'cpp/build/graph_result_nrw_adaptive'} file_format = 'h5' - models = ['ODE Metapopulation model', - 'Graph-based hybrid ODE model', - 'ODE Metapopulation model (Wang)'] + models = ['Model B', + 'Model C', + 'Model D'] plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') - plot_maps(files={'Ode': 'cpp/build/graph_result_timing'}, output_dir=plot_dir, legend=['ODE'], name='TimingTest') - plot_total_compartment(files={'Ode': 'cpp/build/graph_result_timing'}, output_dir=plot_dir, legend=['Graph'], - compartment='Infected', name='timing_test', title='Total infectives') - # plot_total_compartment(files=files_input, output_dir=plot_dir, legend=['ODE', 'Graph'], - # compartment='Infected', name='infectives_total', title='Total infectives') + plot_maps(files=results_adaptive, output_dir=plot_dir, legend=models, name='NRWAdaptiveDay') + # plot_difference_2D(files={key: value for key, value in results_adaptive.items() if key in { + # 'Model C', 'Model D'}}, output_dir=plot_dir) + compare_compartments(files=results_adaptive, output_dir=plot_dir, legend=models) + # plot_total_compartment(files=results_adaptive, output_dir=plot_dir, legend=models, + # compartment='Infected', name='infectives', title='Total infectives') From 8084deb89bd1c30dc1f83e72071b5cf7b78cec5d Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Sun, 12 Jan 2025 05:15:47 +0100 Subject: [PATCH 56/87] fix bug in model b --- cpp/examples/ode_seir_mobility.cpp | 2 +- cpp/models/ode_seir_mobility/model.h | 26 ++++++++++++------- cpp/models/ode_seir_mobility_improved/model.h | 8 +++--- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/cpp/examples/ode_seir_mobility.cpp b/cpp/examples/ode_seir_mobility.cpp index 6091d40db4..4b5600a215 100644 --- a/cpp/examples/ode_seir_mobility.cpp +++ b/cpp/examples/ode_seir_mobility.cpp @@ -184,7 +184,7 @@ int main() mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& data_dir = "/home/gers_ca/code/memilio/data"; + const std::string& data_dir = ""; mio::oseirmobility::Model model(number_regions, number_age_groups); auto result_prepare_simulation = set_parameters_and_population(model, data_dir); diff --git a/cpp/models/ode_seir_mobility/model.h b/cpp/models/ode_seir_mobility/model.h index 1d2aa11eba..a63841757a 100644 --- a/cpp/models/ode_seir_mobility/model.h +++ b/cpp/models/ode_seir_mobility/model.h @@ -60,31 +60,37 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t)( age_i.get(), age_j.get()) * - params.template get>()[age_i] * Nj_inv; + params.template get>()[age_i]; for (auto region_m : make_index_range(n_regions)) { + const size_t Sjm = population.get_flat_index({region_m, age_j, InfectionState::Susceptible}); + const size_t Ejm = population.get_flat_index({region_m, age_j, InfectionState::Exposed}); + const size_t Ijm = population.get_flat_index({region_m, age_j, InfectionState::Infected}); + const size_t Rjm = population.get_flat_index({region_m, age_j, InfectionState::Recovered}); + + const double Njm_inv = 1.0 / (pop[Sjm] + pop[Ejm] + pop[Ijm] + pop[Rjm]); if (region_n == region_m) { flow_SE_helper += - pop[population.get_flat_index({region_n, age_j, InfectionState::Infected})]; + pop[population.get_flat_index({region_n, age_j, InfectionState::Infected})] * Njn_inv; continue; } - flow_SE_helper += (commuting_strengths(region_n.get(), region_m.get()) + - commuting_strengths(region_m.get(), region_n.get())) * + flow_SE_helper += (commuting_strengths(region_n.get(), region_m.get()) * Njm_inv + + commuting_strengths(region_m.get(), region_n.get()) * Njn_inv) * pop[population.get_flat_index({region_m, age_j, InfectionState::Infected})]; } flows[Base::template get_flat_flow_index( {region_n, age_i})] += flow_SE_helper * coeffStoI * - y[population.get_flat_index({region_n, age_j, InfectionState::Susceptible})]; + y[population.get_flat_index({region_n, age_i, InfectionState::Susceptible})]; } flows[Base::template get_flat_flow_index( {region_n, age_i})] = (1.0 / params.template get>()[age_i]) * diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index 837bf78afb..b8469169b2 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -96,12 +96,12 @@ class Model : public FlowModel( {Region(region), AgeGroup(age_i)})] = - (1.0 / params.template get>()[AgeGroup(age_i)]) * - y[population.get_flat_index({Region(region), AgeGroup(age_i), InfectionState::Exposed})]; + y[population.get_flat_index({Region(region), AgeGroup(age_i), InfectionState::Exposed})] / + params.template get>()[AgeGroup(age_i)]; flows[Base::template get_flat_flow_index( {Region(region), AgeGroup(age_i)})] = - (1.0 / params.template get>()[AgeGroup(age_i)]) * - y[population.get_flat_index({Region(region), AgeGroup(age_i), InfectionState::Infected})]; + y[population.get_flat_index({Region(region), AgeGroup(age_i), InfectionState::Infected})] / + params.template get>()[AgeGroup(age_i)]; } } } From 9b8780356a788fd8079761281d771399aeadab20 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Sun, 12 Jan 2025 05:54:05 +0100 Subject: [PATCH 57/87] fix bug in computation of basic reproduction number as well --- cpp/models/ode_seir_mobility/model.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/cpp/models/ode_seir_mobility/model.h b/cpp/models/ode_seir_mobility/model.h index a63841757a..1f775495ae 100644 --- a/cpp/models/ode_seir_mobility/model.h +++ b/cpp/models/ode_seir_mobility/model.h @@ -132,10 +132,15 @@ class Model : public FlowModel({(size_t)n, 1}); + auto const population_region_age_nj = population_region_n.template slice({(size_t)j, 1}); + auto Njn = std::accumulate(population_region_age_nj.begin(), population_region_age_nj.end(), 0.); for (auto m = Region(0); m < Region(num_regions); m++) { - auto const population_region = pop.template slice({(size_t)m, 1}); - auto const population_region_age = population_region.template slice({(size_t)j, 1}); - auto Njm = std::accumulate(population_region_age.begin(), population_region_age.end(), 0.); + auto const population_region_m = pop.template slice({(size_t)m, 1}); + auto const population_region_age_mj = + population_region_m.template slice({(size_t)j, 1}); + auto Njm = + std::accumulate(population_region_age_mj.begin(), population_region_age_mj.end(), 0.); if (n == m) { double coeffStoE = contact_matrix.get_matrix_at(y.get_time(t_idx))(i.get(), j.get()) * @@ -149,9 +154,9 @@ class Model : public FlowModel>()[i] * - (commuting_strengths.get_matrix_at(y.get_time(t_idx))(n.get(), m.get()) + + (commuting_strengths.get_matrix_at(y.get_time(t_idx))(n.get(), m.get()) / Njm + commuting_strengths.get_matrix_at(y.get_time(t_idx))(m.get(), n.get())) / - Njm; + Njn; F((size_t)i * num_regions + (size_t)n, num_age_groups * num_regions + (size_t)j * num_regions + (size_t)m) = coeffStoE * y.get_value(t_idx)[Si]; From f7f3eca5a2d27263f0e189d0717145d84c6ce4fb Mon Sep 17 00:00:00 2001 From: Gerstein Date: Tue, 14 Jan 2025 13:37:08 +0100 Subject: [PATCH 58/87] add likwid test example --- cpp/examples/likwid_test.cpp | 12 ++++++++++++ shellscripts/likwid_test.sh | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 cpp/examples/likwid_test.cpp create mode 100644 shellscripts/likwid_test.sh diff --git a/cpp/examples/likwid_test.cpp b/cpp/examples/likwid_test.cpp new file mode 100644 index 0000000000..c82df95579 --- /dev/null +++ b/cpp/examples/likwid_test.cpp @@ -0,0 +1,12 @@ +#include + +int main() +{ + const size_t n=1e9; + double s, a[n]; + for(size_t i=0; i<1e5; i++){ + for(size_t j=0; j Date: Tue, 14 Jan 2025 14:29:09 +0100 Subject: [PATCH 59/87] new likwid example --- cpp/examples/likwid_test.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/cpp/examples/likwid_test.cpp b/cpp/examples/likwid_test.cpp index c82df95579..d2f26a0b56 100644 --- a/cpp/examples/likwid_test.cpp +++ b/cpp/examples/likwid_test.cpp @@ -1,12 +1,20 @@ -#include +#include + +double work(double* a, size_t n) { + double s = 0; + for (size_t j=0; j Date: Fri, 17 Jan 2025 12:40:21 +0100 Subject: [PATCH 60/87] likwid examples --- cpp/examples/CMakeLists.txt | 6 ++++-- cpp/examples/graph_timing.cpp | 14 ++++++++----- cpp/examples/ode_seir_mobility_timing.cpp | 11 +++++++--- cpp/thirdparty/CMakeLists.txt | 2 +- shellscripts/likwid_equationbased.sh | 25 +++++++++++++++++++++++ shellscripts/likwid_graphbased.sh | 25 +++++++++++++++++++++++ 6 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 shellscripts/likwid_equationbased.sh create mode 100644 shellscripts/likwid_graphbased.sh diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 1d5cc48c03..03b1261f1e 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -40,8 +40,9 @@ target_compile_options(ode_seir_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENA if (MEMILIO_ENABLE_OPENMP) add_executable(ode_seir_mobility_timing ode_seir_mobility_timing.cpp) - target_link_libraries(ode_seir_mobility_timing PRIVATE memilio ode_seir_mobility_improved) + target_link_libraries(ode_seir_mobility_timing PRIVATE memilio ode_seir_mobility_improved likwid stdc++) target_compile_options(ode_seir_mobility_timing PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + target_compile_definitions(ode_seir_mobility_timing PRIVATE "-DLIKWID_PERFMON") endif() add_executable(ode_seir_mobility_steps ode_seir_mobility_steps.cpp) @@ -120,8 +121,9 @@ target_compile_options(graph_steps PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ER if (MEMILIO_ENABLE_OPENMP) add_executable(graph_timing graph_timing.cpp) - target_link_libraries(graph_timing PRIVATE memilio ode_seir) + target_link_libraries(graph_timing PRIVATE memilio ode_seir likwid stdc++) target_compile_options(graph_timing PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + target_compile_definitions(graph_timing PRIVATE "-DLIKWID_PERFMON") endif() add_executable(graph_stochastic_mobility_example graph_stochastic_mobility.cpp) diff --git a/cpp/examples/graph_timing.cpp b/cpp/examples/graph_timing.cpp index 7e7b9c2ba3..1d0c5abcd8 100644 --- a/cpp/examples/graph_timing.cpp +++ b/cpp/examples/graph_timing.cpp @@ -5,9 +5,10 @@ #include "memilio/mobility/metapopulation_mobility_instant.h" #include "memilio/compartments/simulation.h" +#include #include -bool age_groups = true; +bool age_groups = false; void set_contact_matrices(mio::oseir::Parameters& params) { @@ -69,16 +70,14 @@ void set_population_data(mio::oseir::Parameters& params, {params.get_num_groups(), mio::oseir::InfectionState::Count}); for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { - population[{i, mio::oseir::InfectionState::Susceptible}] = 10000; + population[{i, mio::oseir::InfectionState::Susceptible}] = 60000; } for (auto& node : nodes) { node.parameters = params; node.populations = population; } - // for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; nodes[0].populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; - // } for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { params_graph.add_node(node_idx, nodes[node_idx]); @@ -131,9 +130,12 @@ double simulate_runtime(size_t number_regions, ScalarType tmax) set_parameters_and_population(params_graph, number_regions); auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); + + LIKWID_MARKER_START("simulate"); auto start_time = omp_get_wtime(); sim.advance(tmax); auto end_time = omp_get_wtime(); + LIKWID_MARKER_STOP("simulate"); return end_time - start_time; } @@ -154,7 +156,7 @@ void simulate(size_t number_regions, ScalarType tmax) int main(int argc, char** argv) { mio::set_log_level(mio::LogLevel::off); - const ScalarType tmax = 20; + const ScalarType tmax = 100; size_t warm_up = 10; size_t num_runs = 100; size_t num_regions = 10; @@ -172,10 +174,12 @@ int main(int argc, char** argv) // Runs with timing. ScalarType total = 0; + LIKWID_MARKER_INIT; for (size_t i = 0; i < num_runs; i++) { double run_time = simulate_runtime(num_regions, tmax); total += run_time; } + LIKWID_MARKER_CLOSE; std::cout << "\"Time\": " << total / num_runs << "\n}," << std::endl; return 0; diff --git a/cpp/examples/ode_seir_mobility_timing.cpp b/cpp/examples/ode_seir_mobility_timing.cpp index 0b3b184941..50c16ae3f5 100644 --- a/cpp/examples/ode_seir_mobility_timing.cpp +++ b/cpp/examples/ode_seir_mobility_timing.cpp @@ -26,9 +26,10 @@ #include "models/ode_seir_mobility_improved/parameters.h" #include "models/ode_seir_mobility_improved/regions.h" +#include #include -bool age_groups = true; +bool age_groups = false; template void set_contact_matrix(mio::oseirmobilityimproved::Model& model) @@ -108,7 +109,7 @@ void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) for (size_t j = 0; j < number_age_groups; j++) { for (size_t i = 0; i < number_regions; i++) { populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 60000; } } populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), @@ -169,16 +170,20 @@ void simulate(size_t num_warm_up_runs, size_t num_runs, size_t number_regions, S // Runs with timing. ScalarType total = 0; + LIKWID_MARKER_INIT; for (size_t i = 0; i < num_runs; i++) { + LIKWID_MARKER_START("simulate"); double runtime = simulate_runtime(t0, tmax, dt, model, integrator); total += runtime; + LIKWID_MARKER_STOP("simulate"); } + LIKWID_MARKER_CLOSE; std::cout << "\"Time\": " << total / num_runs << "\n}," << std::endl; } int main(int argc, char** argv) { - const ScalarType tmax = 20; + const ScalarType tmax = 100; size_t warm_up = 10; size_t num_runs = 100; size_t num_regions = 10; diff --git a/cpp/thirdparty/CMakeLists.txt b/cpp/thirdparty/CMakeLists.txt index 582cdb81ba..7b34358721 100644 --- a/cpp/thirdparty/CMakeLists.txt +++ b/cpp/thirdparty/CMakeLists.txt @@ -96,7 +96,7 @@ if(MEMILIO_USE_BUNDLED_BOOST) add_library(boost INTERFACE) add_dependencies(boost boost-bootstrap) add_library(Boost::boost ALIAS boost) - target_include_directories(boost SYSTEM INTERFACE $) + target_include_directories(boost INTERFACE $) if (NOT MSVC) target_compile_options(boost INTERFACE "-Wno-c++20-attribute-extensions") diff --git a/shellscripts/likwid_equationbased.sh b/shellscripts/likwid_equationbased.sh new file mode 100644 index 0000000000..edad0d115f --- /dev/null +++ b/shellscripts/likwid_equationbased.sh @@ -0,0 +1,25 @@ +#!/bin/bash +#SBATCH -N 1 +#SBATCH -n 1 +#SBATCH -c 1 +#SBATCH --exclusive +#SBATCH -t 5-0:00:00 +#SBATCH --output=likwid_equationbased-%A.out +#SBATCH --error=likwid_equationbased-%A.err +#SBATCH --exclude="be-cpu05, be-gpu01" +#SBATCH --job-name=likwid_mobilitymodels + +warm_up_runs=0 +runs=50 +regions=400 + +module purge +module load PrgEnv/gcc12-openmpi + +echo Running $1 on node $SLURM_JOB_NODELIST with $warm_up_runs warm up runs and $runs runs. +cd ../cpp/build +rm -rf CMakeCache.txt CMakeFiles/ +cmake -DCMAKE_BUILD_TYPE="Release" -DMEMILIO_ENABLE_OPENMP=ON -DMEMILIO_ENABLE_WARNINGS_AS_ERRORS=OFF .. +cmake --build . --target ode_seir_mobility_timing + +srun --cpu-bind=cores --cpus-per-task=1 --cpu-freq=2200000-2200000 likwid-perfctr -C 0 -g MEM_DP -m ./bin/ode_seir_mobility_timing $warm_up_runs $runs $regions diff --git a/shellscripts/likwid_graphbased.sh b/shellscripts/likwid_graphbased.sh new file mode 100644 index 0000000000..0438da669d --- /dev/null +++ b/shellscripts/likwid_graphbased.sh @@ -0,0 +1,25 @@ +#!/bin/bash +#SBATCH -N 1 +#SBATCH -n 1 +#SBATCH -c 1 +#SBATCH --exclusive +#SBATCH -t 5-0:00:00 +#SBATCH --output=likwid_graphbased-%A.out +#SBATCH --error=likwid_graphbased-%A.err +#SBATCH --exclude="be-cpu05, be-gpu01" +#SBATCH --job-name=likwid_mobilitymodels + +warm_up_runs=0 +runs=50 +regions=400 + +module purge +module load PrgEnv/gcc12-openmpi + +echo Running $1 on node $SLURM_JOB_NODELIST with $warm_up_runs warm up runs and $runs runs. +cd ../cpp/build +rm -rf CMakeCache.txt CMakeFiles/ +cmake -DCMAKE_BUILD_TYPE="Release" -DMEMILIO_ENABLE_OPENMP=ON -DMEMILIO_ENABLE_WARNINGS_AS_ERRORS=OFF .. +cmake --build . --target graph_timing + +srun --cpu-bind=cores --cpus-per-task=1 --cpu-freq=2200000-2200000 likwid-perfctr -C 0 -g MEM_DP -m ./bin/graph_timing $warm_up_runs $runs $regions From 172998aab79bd2986b715df2285d685ac83c447c Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 23 Jan 2025 09:54:16 +0100 Subject: [PATCH 61/87] optimize model --- cpp/models/ode_seir_mobility_improved/model.h | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_seir_mobility_improved/model.h index b8469169b2..653da6e7bb 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_seir_mobility_improved/model.h @@ -57,20 +57,22 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t); const Index n_age_groups = reduce_index>(params.get_num_agegroups()); const Index n_regions = reduce_index>(params.get_num_regions()); + + Eigen::MatrixXd infectious_share_per_region = Eigen::MatrixXd::Zero((size_t)n_regions, (size_t)n_age_groups); for (size_t age_i = 0; age_i < (size_t)n_age_groups; age_i++) { - for (size_t age_j = 0; age_j < (size_t)n_age_groups; age_j++) { - Eigen::VectorXd infectious_share_per_region = Eigen::VectorXd::Zero((size_t)n_regions); - for (size_t region_n = 0; region_n < (size_t)n_regions; region_n++) { - for (size_t region_m = 0; region_m < (size_t)n_regions; region_m++) { - infectious_share_per_region(region_n) += - commuting_strengths(region_m, region_n) * - pop[population.get_flat_index( - {Region(region_m), AgeGroup(age_j), InfectionState::Infected})]; - } - infectious_share_per_region(region_n) /= - m_population_after_commuting[{Region(region_n), AgeGroup(age_j)}]; + for (size_t region_n = 0; region_n < (size_t)n_regions; region_n++) { + for (size_t region_m = 0; region_m < (size_t)n_regions; region_m++) { + infectious_share_per_region(region_n, age_i) += + commuting_strengths(region_m, region_n) * + pop[population.get_flat_index({Region(region_m), AgeGroup(age_i), InfectionState::Infected})]; } - Eigen::VectorXd infections_due_commuting = commuting_strengths * infectious_share_per_region; + infectious_share_per_region(region_n, age_i) /= + m_population_after_commuting[{Region(region_n), AgeGroup(age_i)}]; + } + } + Eigen::MatrixXd infections_due_commuting = commuting_strengths * infectious_share_per_region; + for (size_t age_i = 0; age_i < (size_t)n_age_groups; age_i++) { + for (size_t age_j = 0; age_j < (size_t)n_age_groups; age_j++) { for (size_t region_n = 0; region_n < (size_t)n_regions; region_n++) { const size_t Ejn = population.get_flat_index({Region(region_n), AgeGroup(age_j), InfectionState::Exposed}); @@ -89,7 +91,7 @@ class Model : public FlowModel( {Region(region_n), AgeGroup(age_i)})] += - (pop[Ijn] * Nj_inv + infections_due_commuting(region_n)) * coeffStoI * + (pop[Ijn] * Nj_inv + infections_due_commuting(region_n, age_j)) * coeffStoI * y[population.get_flat_index({Region(region_n), AgeGroup(age_i), InfectionState::Susceptible})]; } } From 87faada0e1156d042565f56fd6d6290039d3df24 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 14:43:55 +0100 Subject: [PATCH 62/87] cleanup timing files --- cpp/examples/graph_timing.cpp | 11 +++-------- cpp/examples/ode_seir_mobility_timing.cpp | 7 +------ 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/cpp/examples/graph_timing.cpp b/cpp/examples/graph_timing.cpp index 1d0c5abcd8..e32abde8b3 100644 --- a/cpp/examples/graph_timing.cpp +++ b/cpp/examples/graph_timing.cpp @@ -5,7 +5,6 @@ #include "memilio/mobility/metapopulation_mobility_instant.h" #include "memilio/compartments/simulation.h" -#include #include bool age_groups = false; @@ -129,13 +128,11 @@ double simulate_runtime(size_t number_regions, ScalarType tmax) set_parameters_and_population(params_graph, number_regions); - auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); - - LIKWID_MARKER_START("simulate"); + auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); + auto start_time = omp_get_wtime(); sim.advance(tmax); auto end_time = omp_get_wtime(); - LIKWID_MARKER_STOP("simulate"); return end_time - start_time; } @@ -156,7 +153,7 @@ void simulate(size_t number_regions, ScalarType tmax) int main(int argc, char** argv) { mio::set_log_level(mio::LogLevel::off); - const ScalarType tmax = 100; + const ScalarType tmax = 20; size_t warm_up = 10; size_t num_runs = 100; size_t num_regions = 10; @@ -174,12 +171,10 @@ int main(int argc, char** argv) // Runs with timing. ScalarType total = 0; - LIKWID_MARKER_INIT; for (size_t i = 0; i < num_runs; i++) { double run_time = simulate_runtime(num_regions, tmax); total += run_time; } - LIKWID_MARKER_CLOSE; std::cout << "\"Time\": " << total / num_runs << "\n}," << std::endl; return 0; diff --git a/cpp/examples/ode_seir_mobility_timing.cpp b/cpp/examples/ode_seir_mobility_timing.cpp index 50c16ae3f5..088cf28c3c 100644 --- a/cpp/examples/ode_seir_mobility_timing.cpp +++ b/cpp/examples/ode_seir_mobility_timing.cpp @@ -26,7 +26,6 @@ #include "models/ode_seir_mobility_improved/parameters.h" #include "models/ode_seir_mobility_improved/regions.h" -#include #include bool age_groups = false; @@ -170,20 +169,16 @@ void simulate(size_t num_warm_up_runs, size_t num_runs, size_t number_regions, S // Runs with timing. ScalarType total = 0; - LIKWID_MARKER_INIT; for (size_t i = 0; i < num_runs; i++) { - LIKWID_MARKER_START("simulate"); double runtime = simulate_runtime(t0, tmax, dt, model, integrator); total += runtime; - LIKWID_MARKER_STOP("simulate"); } - LIKWID_MARKER_CLOSE; std::cout << "\"Time\": " << total / num_runs << "\n}," << std::endl; } int main(int argc, char** argv) { - const ScalarType tmax = 100; + const ScalarType tmax = 20; size_t warm_up = 10; size_t num_runs = 100; size_t num_regions = 10; From 45cad87b8f93ef777a570eaaecf65978efd20a00 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 14:54:23 +0100 Subject: [PATCH 63/87] cleanup step files --- cpp/examples/graph_steps.cpp | 11 ++++++----- cpp/examples/ode_seir_mobility_steps.cpp | 22 +--------------------- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/cpp/examples/graph_steps.cpp b/cpp/examples/graph_steps.cpp index d1b2479d64..48f0c6cfeb 100644 --- a/cpp/examples/graph_steps.cpp +++ b/cpp/examples/graph_steps.cpp @@ -139,10 +139,11 @@ void simulate(ScalarType tol, ScalarType tmax) auto result_graph = std::move(sim).get_graph(); - for (auto&& node : result_graph.nodes()) { - std::cout << " \"Steps Region " << node.id << "\": " << node.property.get_result().get_num_time_points() - 1 - << "," << std::endl; - } + std::cout << " \"Regions\": " << number_regions << "," << std::endl; + std::cout << " \"Steps Hotspot\": " << result_graph.nodes()[0].property.get_result().get_num_time_points() - 1 + << "," << std::endl; + std::cout << " \"Steps other Regions\": " + << result_graph.nodes()[99].property.get_result().get_num_time_points() - 1; } int main(int argc, char** argv) @@ -157,7 +158,7 @@ int main(int argc, char** argv) std::cout << "{ \"Absolute tolerance\": " << tol << ", " << std::endl; simulate(tol, tmax); - std::cout << "\n}," << std::endl; + std::cout << "}," << std::endl; return 0; } diff --git a/cpp/examples/ode_seir_mobility_steps.cpp b/cpp/examples/ode_seir_mobility_steps.cpp index 6068214be9..fea55e786d 100644 --- a/cpp/examples/ode_seir_mobility_steps.cpp +++ b/cpp/examples/ode_seir_mobility_steps.cpp @@ -1,25 +1,5 @@ -/* -* Copyright (C) 2020-2024 MEmilio -* -* Authors: Carlotta Gerstein -* -* Contact: Martin J. Kuehn -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ #include "memilio/compartments/simulation.h" -#include "memilio/math/euler.h" #include "memilio/utils/custom_index_array.h" #include "models/ode_seir_mobility_improved/infection_state.h" #include "models/ode_seir_mobility_improved/model.h" @@ -164,7 +144,7 @@ void simulate(ScalarType tol, ScalarType tmax) std::cout << "{ \"Absolute tolerance\": " << tol << ", " << std::endl; auto result = simulate(t0, tmax, dt, model, integrator); - std::cout << "\"Steps\": " << result.get_num_time_points() - 1 << "," << std::endl; + std::cout << "\"Steps\": " << result.get_num_time_points() - 1 << "}," << std::endl; } int main(int argc, char** argv) From b0e98271e475bcc169cfa1f55022a9f533fe21af Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:21:01 +0100 Subject: [PATCH 64/87] restructure for thesis submission --- cpp/CMakeLists.txt | 4 +- cpp/examples/CMakeLists.txt | 54 ++-- cpp/examples/basic_reproduction_numbers.cpp | 196 ------------ .../basic_reproduction_number_modela.cpp | 66 ++++ .../basic_reproduction_number_modelb.cpp | 79 +++++ .../basic_reproduction_number_modelc.cpp | 101 +++++++ .../graph_nrw.cpp} | 0 .../{ => examples_thesis}/graph_steps.cpp | 0 .../{ => examples_thesis}/graph_timing.cpp | 0 .../ode_metapop_liu_nrw.cpp} | 0 .../ode_metapop_nrw.cpp} | 10 +- .../ode_metapop_steps.cpp} | 8 +- .../ode_metapop_timing.cpp} | 8 +- cpp/examples/ode_sir_mobility.cpp | 241 --------------- cpp/models/ode_metapop/CMakeLists.txt | 13 + .../infection_state.h | 0 .../model.cpp | 2 +- .../model.h | 6 +- .../parameters.h | 2 +- .../regions.h | 0 .../ode_seir_mobility_improved/CMakeLists.txt | 13 - cpp/models/ode_sir_mobility/CMakeLists.txt | 13 - cpp/models/ode_sir_mobility/README.md | 21 -- cpp/models/ode_sir_mobility/infection_state.h | 25 -- cpp/models/ode_sir_mobility/model.cpp | 10 - cpp/models/ode_sir_mobility/model.h | 114 ------- cpp/models/ode_sir_mobility/parameters.h | 286 ------------------ cpp/models/ode_sir_mobility/regions.h | 26 -- 28 files changed, 307 insertions(+), 991 deletions(-) delete mode 100644 cpp/examples/basic_reproduction_numbers.cpp create mode 100644 cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp create mode 100644 cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp create mode 100644 cpp/examples/examples_thesis/basic_reproduction_number_modelc.cpp rename cpp/examples/{graph_extended.cpp => examples_thesis/graph_nrw.cpp} (100%) rename cpp/examples/{ => examples_thesis}/graph_steps.cpp (100%) rename cpp/examples/{ => examples_thesis}/graph_timing.cpp (100%) rename cpp/examples/{ode_seir_mobility.cpp => examples_thesis/ode_metapop_liu_nrw.cpp} (100%) rename cpp/examples/{ode_seir_mobility_improved.cpp => examples_thesis/ode_metapop_nrw.cpp} (97%) rename cpp/examples/{ode_seir_mobility_steps.cpp => examples_thesis/ode_metapop_steps.cpp} (97%) rename cpp/examples/{ode_seir_mobility_timing.cpp => examples_thesis/ode_metapop_timing.cpp} (97%) delete mode 100644 cpp/examples/ode_sir_mobility.cpp create mode 100644 cpp/models/ode_metapop/CMakeLists.txt rename cpp/models/{ode_seir_mobility_improved => ode_metapop}/infection_state.h (100%) rename cpp/models/{ode_seir_mobility_improved => ode_metapop}/model.cpp (70%) rename cpp/models/{ode_seir_mobility_improved => ode_metapop}/model.h (98%) rename cpp/models/{ode_seir_mobility_improved => ode_metapop}/parameters.h (99%) rename cpp/models/{ode_seir_mobility_improved => ode_metapop}/regions.h (100%) delete mode 100644 cpp/models/ode_seir_mobility_improved/CMakeLists.txt delete mode 100644 cpp/models/ode_sir_mobility/CMakeLists.txt delete mode 100644 cpp/models/ode_sir_mobility/README.md delete mode 100644 cpp/models/ode_sir_mobility/infection_state.h delete mode 100644 cpp/models/ode_sir_mobility/model.cpp delete mode 100644 cpp/models/ode_sir_mobility/model.h delete mode 100644 cpp/models/ode_sir_mobility/parameters.h delete mode 100644 cpp/models/ode_sir_mobility/regions.h diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 72bf24afe2..754597f74c 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -151,9 +151,7 @@ if(MEMILIO_BUILD_MODELS) add_subdirectory(models/ode_seir) add_subdirectory(models/ode_seair) add_subdirectory(models/ode_sir) - add_subdirectory(models/ode_sir_mobility) - # add_subdirectory(models/ode_seir_mobility_massaction) - add_subdirectory(models/ode_seir_mobility_improved) + add_subdirectory(models/ode_metapop) add_subdirectory(models/ode_seir_mobility) add_subdirectory(models/sde_sir) add_subdirectory(models/sde_sirs) diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 03b1261f1e..a9d14cf7ef 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -30,32 +30,36 @@ add_executable(sde_sir_example sde_sir.cpp) target_link_libraries(sde_sir_example PRIVATE memilio sde_sir) target_compile_options(sde_sir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -add_executable(ode_sir_mobility_example ode_sir_mobility.cpp) -target_link_libraries(ode_sir_mobility_example PRIVATE memilio ode_sir_mobility) -target_compile_options(ode_sir_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -add_executable(ode_seir_mobility_example ode_seir_mobility.cpp) -target_link_libraries(ode_seir_mobility_example PRIVATE memilio ode_seir_mobility) -target_compile_options(ode_seir_mobility_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ode_metapop_liu_nrw examples_thesis/ode_metapop_liu_nrw.cpp) +target_link_libraries(ode_metapop_liu_nrw PRIVATE memilio ode_seir_mobility) +target_compile_options(ode_metapop_liu_nrw PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) if (MEMILIO_ENABLE_OPENMP) - add_executable(ode_seir_mobility_timing ode_seir_mobility_timing.cpp) - target_link_libraries(ode_seir_mobility_timing PRIVATE memilio ode_seir_mobility_improved likwid stdc++) - target_compile_options(ode_seir_mobility_timing PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - target_compile_definitions(ode_seir_mobility_timing PRIVATE "-DLIKWID_PERFMON") + add_executable(ode_metapop_timing examples_thesis/ode_metapop_timing.cpp) + target_link_libraries(ode_metapop_timing PRIVATE memilio ode_metapop likwid stdc++) + target_compile_options(ode_metapop_timing PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + target_compile_definitions(ode_metapop_timing PRIVATE "-DLIKWID_PERFMON") endif() -add_executable(ode_seir_mobility_steps ode_seir_mobility_steps.cpp) -target_link_libraries(ode_seir_mobility_steps PRIVATE memilio ode_seir_mobility_improved) -target_compile_options(ode_seir_mobility_steps PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ode_metapop_steps examples_thesis/ode_metapop_steps.cpp) +target_link_libraries(ode_metapop_steps PRIVATE memilio ode_metapop) +target_compile_options(ode_metapop_steps PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + +add_executable(basic_reproduction_number_modela examples_thesis/basic_reproduction_number_modela.cpp) +target_link_libraries(basic_reproduction_number_modela PRIVATE memilio ode_seir_mobility) +target_compile_options(basic_reproduction_number_modela PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + +add_executable(basic_reproduction_number_modelb examples_thesis/basic_reproduction_number_modelb.cpp) +target_link_libraries(basic_reproduction_number_modelb PRIVATE memilio ode_seir_mobility) +target_compile_options(basic_reproduction_number_modelb PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -add_executable(basic_reproduction_numbers basic_reproduction_numbers.cpp) -target_link_libraries(basic_reproduction_numbers PRIVATE memilio ode_seir) -target_compile_options(basic_reproduction_numbers PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(basic_reproduction_number_modelc examples_thesis/basic_reproduction_number_modelc.cpp) +target_link_libraries(basic_reproduction_number_modelc PRIVATE memilio ode_metapop) +target_compile_options(basic_reproduction_number_modelc PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -add_executable(ode_seir_mobility_example_improved ode_seir_mobility_improved.cpp) -target_link_libraries(ode_seir_mobility_example_improved PRIVATE memilio ode_seir_mobility_improved) -target_compile_options(ode_seir_mobility_example_improved PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ode_metapop_example_nrw examples_thesis/ode_metapop_nrw.cpp) +target_link_libraries(ode_metapop_example_nrw PRIVATE memilio ode_metapop) +target_compile_options(ode_metapop_example_nrw PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) add_executable(sde_sirs_example sde_sirs.cpp) target_link_libraries(sde_sirs_example PRIVATE memilio sde_sirs) @@ -111,16 +115,16 @@ add_executable(graph_example graph.cpp) target_link_libraries(graph_example PRIVATE memilio ode_seir) target_compile_options(graph_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -add_executable(graph_example_extended graph_extended.cpp) -target_link_libraries(graph_example_extended PRIVATE memilio ode_seir) -target_compile_options(graph_example_extended PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(graph_example_nrw examples_thesis/graph_nrw.cpp) +target_link_libraries(graph_example_nrw PRIVATE memilio ode_seir) +target_compile_options(graph_example_nrw PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -add_executable(graph_steps graph_steps.cpp) +add_executable(graph_steps examples_thesis/graph_steps.cpp) target_link_libraries(graph_steps PRIVATE memilio ode_seir) target_compile_options(graph_steps PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) if (MEMILIO_ENABLE_OPENMP) - add_executable(graph_timing graph_timing.cpp) + add_executable(graph_timing examples_thesis/graph_timing.cpp) target_link_libraries(graph_timing PRIVATE memilio ode_seir likwid stdc++) target_compile_options(graph_timing PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) target_compile_definitions(graph_timing PRIVATE "-DLIKWID_PERFMON") diff --git a/cpp/examples/basic_reproduction_numbers.cpp b/cpp/examples/basic_reproduction_numbers.cpp deleted file mode 100644 index 71cabd73f3..0000000000 --- a/cpp/examples/basic_reproduction_numbers.cpp +++ /dev/null @@ -1,196 +0,0 @@ - -#include "models/ode_seir/model.h" -#include "models/ode_seir_mobility/model.h" -// #include "models/ode_seir_mobility_improved/model.h" - -#include "memilio/math/euler.h" -#include "memilio/compartments/simulation.h" -#include "memilio/utils/custom_index_array.h" - -Eigen::MatrixXd get_contact_matrix() -{ - Eigen::MatrixXd contact_matrix_eigen(6, 6); - contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, 0.0161, - 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, 0.0458, 0.1939, - 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; - - return contact_matrix_eigen; -} - -const ScalarType TimeExposed[] = {3.335, 3.335, 3.335, 3.335, 3.335, 3.335}; -const ScalarType TimeInfected[] = {8.0096875, 8.0096875, 8.2182, 8.1158, 8.033, 7.985}; -const ScalarType TransmissionProbabilityOnContact[] = {0.03, 0.06, 0.06, 0.06, 0.09, 0.175}; - -void seir(size_t number_regions, ScalarType tmax) -{ - mio::set_log_level(mio::LogLevel::off); - ScalarType t0 = 0.; - ScalarType dt = 0.1; - ScalarType number_age_groups = 6; - - mio::oseir::Model model(number_age_groups); - auto& population = model.populations; - - for (size_t j = 0; j < number_age_groups; j++) { - - population[{mio::AgeGroup(j), mio::oseir::InfectionState::Susceptible}] = number_regions * 10000; - } - population[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; - population[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; - - mio::ContactMatrixGroup& contact_matrix = - model.parameters.template get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline() = get_contact_matrix(); - - for (size_t j = 0; j < number_age_groups; j++) { - model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; - model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; - model.parameters.template get>()[mio::AgeGroup(j)] = - TransmissionProbabilityOnContact[j]; - } - - std::shared_ptr> integrator = std::make_shared>(); - - auto result = simulate(t0, tmax, dt, model, integrator); - - auto basic_reproduction_number = model.get_reproduction_number(t0, result).value(); - std::cout << "\"SEIR\": " << basic_reproduction_number << ", " << std::endl; -} - -void wang(size_t number_regions, ScalarType tmax) -{ - mio::set_log_level(mio::LogLevel::off); - ScalarType t0 = 0.; - ScalarType dt = 0.1; - ScalarType number_age_groups = 6; - - mio::oseirmobility::Model model(number_regions, number_age_groups); - auto& population = model.populations; - - for (size_t j = 0; j < number_age_groups; j++) { - for (size_t i = 0; i < number_regions; i++) { - population[{mio::oseirmobility::Region(i), mio::AgeGroup(j), - mio::oseirmobility::InfectionState::Susceptible}] = 10000; - } - } - population[{mio::oseirmobility::Region(0), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Exposed}] += 100; - population[{mio::oseirmobility::Region(0), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Susceptible}] -= - 100; - - double fraction_commuter = 1. / (2 * number_regions); - Eigen::MatrixXd mobility_data_commuter = - Eigen::MatrixXd::Constant(number_regions, number_regions, fraction_commuter) - - fraction_commuter * - Eigen::MatrixXd::Identity(number_regions, number_regions); // Ensure that the diagonal is zero - for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { - mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); - } - model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = - mobility_data_commuter; - - mio::ContactMatrixGroup& contact_matrix = - model.parameters.template get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline() = get_contact_matrix(); - - for (size_t j = 0; j < number_age_groups; j++) { - model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; - model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; - model.parameters.template get>()[mio::AgeGroup(j)] = - TransmissionProbabilityOnContact[j]; - } - - std::shared_ptr> integrator = std::make_shared>(); - - auto result = simulate(t0, tmax, dt, model, integrator); - - auto basic_reproduction_number = model.get_reproduction_number(t0, result).value(); - std::cout << "\"Wang\": " << basic_reproduction_number << "}" << std::endl; -} - -// void metapopulation(size_t number_regions, ScalarType tmax) -// { -// mio::set_log_level(mio::LogLevel::off); -// ScalarType t0 = 0.; -// ScalarType dt = 0.1; -// ScalarType number_age_groups = 6; - -// mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); -// auto& population = model.populations; - -// for (size_t j = 0; j < number_age_groups; j++) { -// for (size_t i = 0; i < number_regions; i++) { -// population[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), -// mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; -// } -// } -// population[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), -// mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; -// population[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), -// mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; - -// double fraction_commuter = 1. / (2 * number_regions); -// Eigen::MatrixXd mobility_data_commuter = -// Eigen::MatrixXd::Constant(number_regions, number_regions, fraction_commuter) - -// fraction_commuter * -// Eigen::MatrixXd::Identity(number_regions, number_regions); // Ensure that the diagonal is zero -// for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { -// mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); -// } -// model.parameters.template get>() -// .get_cont_freq_mat()[0] -// .get_baseline() = mobility_data_commuter; - -// mio::ContactMatrixGroup& contact_matrix = -// model.parameters.template get>().get_cont_freq_mat(); -// contact_matrix[0].get_baseline() = get_contact_matrix(); - -// for (size_t j = 0; j < number_age_groups; j++) { -// model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; -// model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; -// model.parameters -// .template get>()[mio::AgeGroup(j)] = -// TransmissionProbabilityOnContact[j]; -// } - -// mio::ContactMatrixGroup& commuting_strengths = -// model.parameters.template get>().get_cont_freq_mat(); - -// auto& population_after_commuting = model.m_population_after_commuting; -// for (size_t region_n = 0; region_n < number_regions; ++region_n) { -// for (size_t age = 0; age < number_age_groups; ++age) { -// double population_n = 0; -// for (size_t state = 0; state < (size_t)mio::oseirmobilityimproved::InfectionState::Count; state++) { -// population_n += population[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), -// mio::oseirmobilityimproved::InfectionState(state)}]; -// } -// population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += -// population_n; -// for (size_t region_m = 0; region_m < number_regions; ++region_m) { -// population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= -// commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; -// population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += -// commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; -// } -// } -// } - -// std::shared_ptr> integrator = std::make_shared>(); - -// auto result = simulate(t0, tmax, dt, model, integrator); - -// auto basic_reproduction_number = model.get_reproduction_number(t0, result).value(); -// std::cout << "\"Metapopulation\": " << basic_reproduction_number << "}" << std::endl; -// } - -int main() -{ - const ScalarType tmax = 1.; - size_t num_regions = 150; - - std::cout << "{ \"Regions\": " << num_regions << ", " << std::endl; - - seir(num_regions, tmax); - wang(num_regions, tmax); - // metapopulation(num_regions, tmax); - return 0; -} \ No newline at end of file diff --git a/cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp b/cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp new file mode 100644 index 0000000000..01d96bba61 --- /dev/null +++ b/cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp @@ -0,0 +1,66 @@ + +#include "models/ode_seir/model.h" +#include "models/ode_seir_mobility/model.h" + +#include "memilio/math/euler.h" +#include "memilio/compartments/simulation.h" +#include "memilio/utils/custom_index_array.h" + +Eigen::MatrixXd get_contact_matrix() +{ + Eigen::MatrixXd contact_matrix_eigen(6, 6); + contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, 0.0161, + 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, 0.0458, 0.1939, + 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; + + return contact_matrix_eigen; +} + +const ScalarType TimeExposed[] = {3.335, 3.335, 3.335, 3.335, 3.335, 3.335}; +const ScalarType TimeInfected[] = {8.0096875, 8.0096875, 8.2182, 8.1158, 8.033, 7.985}; +const ScalarType TransmissionProbabilityOnContact[] = {0.03, 0.06, 0.06, 0.06, 0.09, 0.175}; + +void calculate_basic_reproduction_number(size_t number_regions, ScalarType tmax) +{ + mio::set_log_level(mio::LogLevel::off); + ScalarType t0 = 0.; + ScalarType dt = 0.1; + ScalarType number_age_groups = 6; + + mio::oseir::Model model(number_age_groups); + auto& population = model.populations; + + for (size_t j = 0; j < number_age_groups; j++) { + + population[{mio::AgeGroup(j), mio::oseir::InfectionState::Susceptible}] = number_regions * 10000; + } + + mio::ContactMatrixGroup& contact_matrix = + model.parameters.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline() = get_contact_matrix(); + + for (size_t j = 0; j < number_age_groups; j++) { + model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = + TransmissionProbabilityOnContact[j]; + } + + std::shared_ptr> integrator = std::make_shared>(); + + auto result = simulate(t0, tmax, dt, model, integrator); + + auto basic_reproduction_number = model.get_reproduction_number(t0, result).value(); + std::cout << "\"Model A\": " << basic_reproduction_number << ", " << std::endl; +} + +int main() +{ + const ScalarType tmax = 1.; + size_t num_regions = 1; + + std::cout << "{ \"Regions\": " << num_regions << ", " << std::endl; + + calculate_basic_reproduction_number(num_regions, tmax); + return 0; +} \ No newline at end of file diff --git a/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp b/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp new file mode 100644 index 0000000000..a2e6b0c5cf --- /dev/null +++ b/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp @@ -0,0 +1,79 @@ + +#include "models/ode_seir/model.h" +#include "models/ode_seir_mobility/model.h" + +#include "memilio/math/euler.h" +#include "memilio/compartments/simulation.h" +#include "memilio/utils/custom_index_array.h" + +Eigen::MatrixXd get_contact_matrix() +{ + Eigen::MatrixXd contact_matrix_eigen(6, 6); + contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, 0.0161, + 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, 0.0458, 0.1939, + 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; + + return contact_matrix_eigen; +} + +const ScalarType TimeExposed[] = {3.335, 3.335, 3.335, 3.335, 3.335, 3.335}; +const ScalarType TimeInfected[] = {8.0096875, 8.0096875, 8.2182, 8.1158, 8.033, 7.985}; +const ScalarType TransmissionProbabilityOnContact[] = {0.03, 0.06, 0.06, 0.06, 0.09, 0.175}; + +void calculate_basic_reproduction_number(size_t number_regions, ScalarType tmax) +{ + mio::set_log_level(mio::LogLevel::off); + ScalarType t0 = 0.; + ScalarType dt = 0.1; + ScalarType number_age_groups = 6; + + mio::oseirmobility::Model model(number_regions, number_age_groups); + auto& population = model.populations; + + for (size_t j = 0; j < number_age_groups; j++) { + for (size_t i = 0; i < number_regions; i++) { + population[{mio::oseirmobility::Region(i), mio::AgeGroup(j), + mio::oseirmobility::InfectionState::Susceptible}] = 10000; + } + } + + double fraction_commuter = 1. / (2 * number_regions); + Eigen::MatrixXd mobility_data_commuter = + Eigen::MatrixXd::Constant(number_regions, number_regions, fraction_commuter) - + fraction_commuter * + Eigen::MatrixXd::Identity(number_regions, number_regions); // Ensure that the diagonal is zero + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); + } + model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = + mobility_data_commuter; + + mio::ContactMatrixGroup& contact_matrix = + model.parameters.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline() = get_contact_matrix(); + + for (size_t j = 0; j < number_age_groups; j++) { + model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = + TransmissionProbabilityOnContact[j]; + } + + std::shared_ptr> integrator = std::make_shared>(); + + auto result = simulate(t0, tmax, dt, model, integrator); + + auto basic_reproduction_number = model.get_reproduction_number(t0, result).value(); + std::cout << "\"Model B\": " << basic_reproduction_number << "}" << std::endl; +} + +int main() +{ + const ScalarType tmax = 1.; + size_t num_regions = 1; + + std::cout << "{ \"Regions\": " << num_regions << ", " << std::endl; + + calculate_basic_reproduction_number(num_regions, tmax); + return 0; +} \ No newline at end of file diff --git a/cpp/examples/examples_thesis/basic_reproduction_number_modelc.cpp b/cpp/examples/examples_thesis/basic_reproduction_number_modelc.cpp new file mode 100644 index 0000000000..f1de131aec --- /dev/null +++ b/cpp/examples/examples_thesis/basic_reproduction_number_modelc.cpp @@ -0,0 +1,101 @@ +#include "models/ode_metapop/model.h" + +#include "memilio/math/euler.h" +#include "memilio/compartments/simulation.h" +#include "memilio/utils/custom_index_array.h" + +Eigen::MatrixXd get_contact_matrix() +{ + Eigen::MatrixXd contact_matrix_eigen(6, 6); + contact_matrix_eigen << 3.9547, 1.1002, 2.9472, 2.05, 0.3733, 0.0445, 0.3327, 3.5892, 1.236, 1.9208, 0.2681, 0.0161, + 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, 0.0458, 0.1939, + 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; + + return contact_matrix_eigen; +} + +const ScalarType TimeExposed[] = {3.335, 3.335, 3.335, 3.335, 3.335, 3.335}; +const ScalarType TimeInfected[] = {8.0096875, 8.0096875, 8.2182, 8.1158, 8.033, 7.985}; +const ScalarType TransmissionProbabilityOnContact[] = {0.03, 0.06, 0.06, 0.06, 0.09, 0.175}; + +void calculate_basic_reproduction_number(size_t number_regions, ScalarType tmax) +{ + mio::set_log_level(mio::LogLevel::off); + ScalarType t0 = 0.; + ScalarType dt = 0.1; + ScalarType number_age_groups = 6; + + mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); + auto& population = model.populations; + + for (size_t j = 0; j < number_age_groups; j++) { + for (size_t i = 0; i < number_regions; i++) { + population[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), + mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + } + } + + double fraction_commuter = 1. / (2 * number_regions); + Eigen::MatrixXd mobility_data_commuter = + Eigen::MatrixXd::Constant(number_regions, number_regions, fraction_commuter) - + fraction_commuter * + Eigen::MatrixXd::Identity(number_regions, number_regions); // Ensure that the diagonal is zero + for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { + mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); + } + model.parameters.template get>() + .get_cont_freq_mat()[0] + .get_baseline() = mobility_data_commuter; + + mio::ContactMatrixGroup& contact_matrix = + model.parameters.template get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline() = get_contact_matrix(); + + for (size_t j = 0; j < number_age_groups; j++) { + model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; + model.parameters + .template get>()[mio::AgeGroup(j)] = + TransmissionProbabilityOnContact[j]; + } + + mio::ContactMatrixGroup& commuting_strengths = + model.parameters.template get>().get_cont_freq_mat(); + + auto& population_after_commuting = model.m_population_after_commuting; + for (size_t region_n = 0; region_n < number_regions; ++region_n) { + for (size_t age = 0; age < number_age_groups; ++age) { + double population_n = 0; + for (size_t state = 0; state < (size_t)mio::oseirmobilityimproved::InfectionState::Count; state++) { + population_n += population[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), + mio::oseirmobilityimproved::InfectionState(state)}]; + } + population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += + population_n; + for (size_t region_m = 0; region_m < number_regions; ++region_m) { + population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= + commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; + population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += + commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; + } + } + } + + std::shared_ptr> integrator = std::make_shared>(); + + auto result = simulate(t0, tmax, dt, model, integrator); + + auto basic_reproduction_number = model.get_reproduction_number(t0, result).value(); + std::cout << "\"Metapopulation\": " << basic_reproduction_number << "}" << std::endl; +} + +int main() +{ + const ScalarType tmax = 1.; + size_t num_regions = 1; + + std::cout << "{ \"Regions\": " << num_regions << ", " << std::endl; + + calculate_basic_reproduction_number(num_regions, tmax); + return 0; +} \ No newline at end of file diff --git a/cpp/examples/graph_extended.cpp b/cpp/examples/examples_thesis/graph_nrw.cpp similarity index 100% rename from cpp/examples/graph_extended.cpp rename to cpp/examples/examples_thesis/graph_nrw.cpp diff --git a/cpp/examples/graph_steps.cpp b/cpp/examples/examples_thesis/graph_steps.cpp similarity index 100% rename from cpp/examples/graph_steps.cpp rename to cpp/examples/examples_thesis/graph_steps.cpp diff --git a/cpp/examples/graph_timing.cpp b/cpp/examples/examples_thesis/graph_timing.cpp similarity index 100% rename from cpp/examples/graph_timing.cpp rename to cpp/examples/examples_thesis/graph_timing.cpp diff --git a/cpp/examples/ode_seir_mobility.cpp b/cpp/examples/examples_thesis/ode_metapop_liu_nrw.cpp similarity index 100% rename from cpp/examples/ode_seir_mobility.cpp rename to cpp/examples/examples_thesis/ode_metapop_liu_nrw.cpp diff --git a/cpp/examples/ode_seir_mobility_improved.cpp b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp similarity index 97% rename from cpp/examples/ode_seir_mobility_improved.cpp rename to cpp/examples/examples_thesis/ode_metapop_nrw.cpp index 92565b552d..d14691dcce 100644 --- a/cpp/examples/ode_seir_mobility_improved.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp @@ -4,10 +4,10 @@ #include "memilio/utils/logging.h" #include "memilio/utils/custom_index_array.h" #include "memilio/io/mobility_io.h" -#include "models/ode_seir_mobility_improved/infection_state.h" -#include "models/ode_seir_mobility_improved/model.h" -#include "models/ode_seir_mobility_improved/parameters.h" -#include "models/ode_seir_mobility_improved/regions.h" +#include "models/ode_metapop/infection_state.h" +#include "models/ode_metapop/model.h" +#include "models/ode_metapop/parameters.h" +#include "models/ode_metapop/regions.h" #include "memilio/io/io.h" #include "memilio/io/result_io.h" #include "memilio/io/epi_data.h" @@ -230,5 +230,5 @@ int main() auto result = mio::interpolate_simulation_result(result_from_sim); auto save_result_status = - mio::save_result({result}, {1}, number_regions * number_age_groups, "ode_result_nrw_adaptive_test.h5"); + mio::save_result({result}, {1}, number_regions * number_age_groups, "ode_result_nrw_adaptive.h5"); } diff --git a/cpp/examples/ode_seir_mobility_steps.cpp b/cpp/examples/examples_thesis/ode_metapop_steps.cpp similarity index 97% rename from cpp/examples/ode_seir_mobility_steps.cpp rename to cpp/examples/examples_thesis/ode_metapop_steps.cpp index fea55e786d..72ac4bbef8 100644 --- a/cpp/examples/ode_seir_mobility_steps.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_steps.cpp @@ -1,10 +1,10 @@ #include "memilio/compartments/simulation.h" #include "memilio/utils/custom_index_array.h" -#include "models/ode_seir_mobility_improved/infection_state.h" -#include "models/ode_seir_mobility_improved/model.h" -#include "models/ode_seir_mobility_improved/parameters.h" -#include "models/ode_seir_mobility_improved/regions.h" +#include "models/ode_metapop/infection_state.h" +#include "models/ode_metapop/model.h" +#include "models/ode_metapop/parameters.h" +#include "models/ode_metapop/regions.h" #include diff --git a/cpp/examples/ode_seir_mobility_timing.cpp b/cpp/examples/examples_thesis/ode_metapop_timing.cpp similarity index 97% rename from cpp/examples/ode_seir_mobility_timing.cpp rename to cpp/examples/examples_thesis/ode_metapop_timing.cpp index 088cf28c3c..f915dd9eb2 100644 --- a/cpp/examples/ode_seir_mobility_timing.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_timing.cpp @@ -21,10 +21,10 @@ #include "memilio/compartments/simulation.h" #include "memilio/math/euler.h" #include "memilio/utils/custom_index_array.h" -#include "models/ode_seir_mobility_improved/infection_state.h" -#include "models/ode_seir_mobility_improved/model.h" -#include "models/ode_seir_mobility_improved/parameters.h" -#include "models/ode_seir_mobility_improved/regions.h" +#include "models/ode_metapop/infection_state.h" +#include "models/ode_metapop/model.h" +#include "models/ode_metapop/parameters.h" +#include "models/ode_metapop/regions.h" #include diff --git a/cpp/examples/ode_sir_mobility.cpp b/cpp/examples/ode_sir_mobility.cpp deleted file mode 100644 index 7aaf725e45..0000000000 --- a/cpp/examples/ode_sir_mobility.cpp +++ /dev/null @@ -1,241 +0,0 @@ - -#include "memilio/compartments/simulation.h" -#include "memilio/math/euler.h" -#include "memilio/utils/logging.h" -#include "memilio/utils/custom_index_array.h" -#include "memilio/io/mobility_io.h" -#include "ode_sir_mobility/infection_state.h" -#include "ode_sir_mobility/model.h" -#include "ode_sir_mobility/parameters.h" -#include "ode_sir_mobility/regions.h" -#include "memilio/io/io.h" - -mio::IOResult>>> read_path_mobility(const std::string& filename) -{ - BOOST_OUTCOME_TRY(auto&& num_lines, mio::count_lines(filename)); - - if (num_lines == 0) { - std::vector>> arr(0, std::vector>(0)); - return mio::success(arr); - } - - std::fstream file; - file.open(filename, std::ios::in); - if (!file.is_open()) { - return failure(mio::StatusCode::FileNotFound, filename); - } - - std::vector>> arr(std::sqrt(num_lines), - std::vector>(std::sqrt(num_lines))); - - try { - std::string tp; - while (getline(file, tp)) { - auto line = mio::split(tp, ' '); - int indx_x = std::stoi(line[0]); - int indx_y = std::stoi(line[1]); - if (indx_x != indx_y) { - auto path = std::accumulate(line.begin() + 2, line.end(), std::string("")); - - // string -> vector of integers - std::vector path_vec; - - // Remove the square brackets and \r - path = path.substr(1, path.size() - 3); - std::stringstream ss(path); - std::string token; - - // get numbers and save them in path_vec - while (std::getline(ss, token, ',')) { - path_vec.push_back(std::stoi(token)); - } - - // Sorted by end location - for (int number : path_vec) { - if (number != indx_x && number != indx_y) { - arr[indx_x][indx_y].push_back(number); - } - } - } - } - } - catch (std::runtime_error& ex) { - return failure(mio::StatusCode::InvalidFileFormat, filename + ": " + ex.what()); - } - - return mio::success(arr); -} - -template -mio::IOResult preprocess(const std::string& filename, mio::osirmobility::Model& model) -{ - BOOST_OUTCOME_TRY(auto&& mobility_paths, read_path_mobility(filename)); - size_t n_regions = (size_t)model.parameters.get_num_regions(); - for (size_t i = 0; i < n_regions; i++) { - for (size_t j = 0; j < n_regions; j++) { - if (j == i) { - continue; - } - std::sort(mobility_paths[i][j].begin(), mobility_paths[i][j].end()); - std::vector intersection_int; - std::vector intersection_region(intersection_int.size(), - mio::osirmobility::Region(0)); - for (size_t k = 0; k < n_regions; k++) { - if (k == i || k == j) { - continue; - } - std::sort(mobility_paths[k][j].begin(), mobility_paths[k][j].end()); - std::set_intersection(mobility_paths[i][j].begin(), mobility_paths[i][j].end(), - mobility_paths[k][j].begin(), mobility_paths[k][j].end(), - std::back_inserter(intersection_int)); - - if (intersection_int.begin() != intersection_int.end()) { - intersection_region.push_back(mio::osirmobility::Region(k)); - intersection_int.pop_back(); - } - } - if (intersection_region.begin() != intersection_region.end()) { - model.parameters.template get()[{ - mio::osirmobility::Region(i), mio::osirmobility::Region(j)}] = intersection_region; - } - } - } - return mio::success(); -} - -template -mio::IOResult set_mobility_weights(const std::string& mobility_data, const std::string& trip_chains, - mio::osirmobility::Model& model, size_t number_regions) -{ - BOOST_OUTCOME_TRY(preprocess(trip_chains, model)); - // mobility between nodes - BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, - mio::read_mobility_plain(mobility_data + "mobility" + "commuter_migration_scaled.txt")); - if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || - mobility_data_commuter.cols() != Eigen::Index(number_regions)) { - return mio::failure(mio::StatusCode::InvalidValue, - "Mobility matrices do not have the correct size. You may need to run " - "transformMobilitydata.py from pycode memilio epidata package."); - } - - for (auto age = mio::AgeGroup(0); age < model.parameters.get_num_agegroups(); age++) { - for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { - for (size_t county_idx_j = 0; county_idx_j < number_regions; ++county_idx_j) { - //commuters - auto population_i = model.populations.get_group_total(mio::osirmobility::Region(county_idx_i)); - auto commuter_coeff_ij = mobility_data_commuter(county_idx_i, county_idx_j) / population_i; - if (commuter_coeff_ij > 4e-5) { - model.parameters.template get().push_back( - {mio::osirmobility::Region(county_idx_i), mio::osirmobility::Region(county_idx_j), - commuter_coeff_ij}); - } - } - } - } - return mio::success(); -} - -int main() -{ - mio::set_log_level(mio::LogLevel::debug); - - ScalarType t0 = 0.; - ScalarType tmax = 50.; - ScalarType dt = 1; - - ScalarType number_regions = 4; - ScalarType number_age_groups = 1; - ScalarType total_population_per_region = 10; - - mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - - const std::string& mobility_data = ""; - const std::string& trip_chain_data = ""; - - mio::osirmobility::Model model(number_regions, number_age_groups); - - for (size_t i = 0; i < number_regions; i++) { - model.populations[{mio::osirmobility::Region(i), mio::AgeGroup(0), - mio::osirmobility::InfectionState::Infected}] = 1; - model.populations[{mio::osirmobility::Region(i), mio::AgeGroup(0), - mio::osirmobility::InfectionState::Recovered}] = 0; - model.populations[{mio::osirmobility::Region(i), mio::AgeGroup(0), - mio::osirmobility::InfectionState::Susceptible}] = - total_population_per_region - - model.populations[{mio::osirmobility::Region(i), mio::AgeGroup(0), - mio::osirmobility::InfectionState::Infected}] - - model.populations[{mio::osirmobility::Region(i), mio::AgeGroup(0), - mio::osirmobility::InfectionState::Recovered}]; - } - - model.parameters.set>(2); - model.parameters.set>(0.04); - model.parameters.set>(1.); - mio::ContactMatrixGroup& contact_matrix = - model.parameters.get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(1.0); - contact_matrix[0].add_damping(0.6, mio::SimulationTime(12.5)); - - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.2}); - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(2), 0.6}); - model.parameters.get().push_back( - {mio::osirmobility::Region(2), mio::osirmobility::Region(0), 0.5}); - model.parameters.get().push_back( - {mio::osirmobility::Region(0), mio::osirmobility::Region(3), 1.0}); - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(3), 0.2}); - - model.parameters.get()[{mio::osirmobility::Region(0), - mio::osirmobility::Region(1)}] = {2}; - model.parameters.get()[{mio::osirmobility::Region(0), - mio::osirmobility::Region(3)}] = {2}; - model.parameters.get()[{mio::osirmobility::Region(1), - mio::osirmobility::Region(0)}] = {2}; - model.parameters.get()[{mio::osirmobility::Region(1), - mio::osirmobility::Region(2)}] = {0}; - model.parameters.get()[{mio::osirmobility::Region(1), - mio::osirmobility::Region(3)}] = {2}; - model.parameters.get()[{mio::osirmobility::Region(2), - mio::osirmobility::Region(1)}] = {0}; - model.parameters.get()[{mio::osirmobility::Region(3), - mio::osirmobility::Region(0)}] = {2}; - model.parameters.get()[{mio::osirmobility::Region(3), - mio::osirmobility::Region(1)}] = {2}; - - // auto result_preprocess = set_mobility_weights(mobility_data, trip_chain_data, model, number_regions); - - std::shared_ptr> integrator = - std::make_shared>(); - - model.check_constraints(); - - auto sir = simulate(t0, tmax, dt, model, integrator); - - bool print_to_terminal = true; - - sir.print_table(); - - if (print_to_terminal) { - - std::vector vars = {"S", "I", "R"}; - printf("\n # t"); - for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { - for (size_t k = 0; k < (size_t)mio::osirmobility::InfectionState::Count; k++) { - printf(" %s_%d", vars[k].c_str(), (int)i); - } - } - - auto num_points = static_cast(sir.get_num_time_points()); - for (size_t i = 0; i < num_points; i++) { - printf("\n%.14f ", sir.get_time(i)); - for (size_t k = 0; k < (size_t)model.parameters.get_num_regions(); k++) { - for (size_t j = 0; j < (size_t)mio::osirmobility::InfectionState::Count; j++) { - printf(" %.14f", sir.get_value(i)[j + (size_t)mio::osirmobility::InfectionState::Count * (int)k]); - } - } - } - printf("\n"); - } -} diff --git a/cpp/models/ode_metapop/CMakeLists.txt b/cpp/models/ode_metapop/CMakeLists.txt new file mode 100644 index 0000000000..5b8a8c87f2 --- /dev/null +++ b/cpp/models/ode_metapop/CMakeLists.txt @@ -0,0 +1,13 @@ +add_library(ode_metapop + infection_state.h + model.h + model.cpp + parameters.h + regions.h +) +target_link_libraries(ode_metapop PUBLIC memilio) +target_include_directories(ode_metapop PUBLIC + $ + $ +) +target_compile_options(ode_metapop PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_seir_mobility_improved/infection_state.h b/cpp/models/ode_metapop/infection_state.h similarity index 100% rename from cpp/models/ode_seir_mobility_improved/infection_state.h rename to cpp/models/ode_metapop/infection_state.h diff --git a/cpp/models/ode_seir_mobility_improved/model.cpp b/cpp/models/ode_metapop/model.cpp similarity index 70% rename from cpp/models/ode_seir_mobility_improved/model.cpp rename to cpp/models/ode_metapop/model.cpp index 567a8a1e86..c92073842e 100644 --- a/cpp/models/ode_seir_mobility_improved/model.cpp +++ b/cpp/models/ode_metapop/model.cpp @@ -1,5 +1,5 @@ -#include "ode_seir_mobility_improved/model.h" +#include "ode_metapop/model.h" namespace mio { diff --git a/cpp/models/ode_seir_mobility_improved/model.h b/cpp/models/ode_metapop/model.h similarity index 98% rename from cpp/models/ode_seir_mobility_improved/model.h rename to cpp/models/ode_metapop/model.h index 653da6e7bb..39be459899 100644 --- a/cpp/models/ode_seir_mobility_improved/model.h +++ b/cpp/models/ode_metapop/model.h @@ -4,9 +4,9 @@ #include "memilio/compartments/flow_model.h" #include "memilio/epidemiology/populations.h" -#include "models/ode_seir_mobility_improved/infection_state.h" -#include "models/ode_seir_mobility_improved/parameters.h" -#include "models/ode_seir_mobility_improved/regions.h" +#include "models/ode_metapop/infection_state.h" +#include "models/ode_metapop/parameters.h" +#include "models/ode_metapop/regions.h" #include "memilio/epidemiology/age_group.h" #include "memilio/utils/time_series.h" diff --git a/cpp/models/ode_seir_mobility_improved/parameters.h b/cpp/models/ode_metapop/parameters.h similarity index 99% rename from cpp/models/ode_seir_mobility_improved/parameters.h rename to cpp/models/ode_metapop/parameters.h index 49c548207f..aa337acafb 100644 --- a/cpp/models/ode_seir_mobility_improved/parameters.h +++ b/cpp/models/ode_metapop/parameters.h @@ -7,7 +7,7 @@ #include "memilio/epidemiology/age_group.h" #include "memilio/utils/parameter_set.h" #include "memilio/utils/custom_index_array.h" -#include "models/ode_seir_mobility_improved/regions.h" +#include "models/ode_metapop/regions.h" #include "Eigen/Sparse" #include diff --git a/cpp/models/ode_seir_mobility_improved/regions.h b/cpp/models/ode_metapop/regions.h similarity index 100% rename from cpp/models/ode_seir_mobility_improved/regions.h rename to cpp/models/ode_metapop/regions.h diff --git a/cpp/models/ode_seir_mobility_improved/CMakeLists.txt b/cpp/models/ode_seir_mobility_improved/CMakeLists.txt deleted file mode 100644 index 82261701db..0000000000 --- a/cpp/models/ode_seir_mobility_improved/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_library(ode_seir_mobility_improved - infection_state.h - model.h - model.cpp - parameters.h - regions.h -) -target_link_libraries(ode_seir_mobility_improved PUBLIC memilio) -target_include_directories(ode_seir_mobility_improved PUBLIC - $ - $ -) -target_compile_options(ode_seir_mobility_improved PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_sir_mobility/CMakeLists.txt b/cpp/models/ode_sir_mobility/CMakeLists.txt deleted file mode 100644 index 3a2f54adeb..0000000000 --- a/cpp/models/ode_sir_mobility/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_library(ode_sir_mobility - infection_state.h - model.h - model.cpp - parameters.h - regions.h -) -target_link_libraries(ode_sir_mobility PUBLIC memilio) -target_include_directories(ode_sir_mobility PUBLIC - $ - $ -) -target_compile_options(ode_sir_mobility PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_sir_mobility/README.md b/cpp/models/ode_sir_mobility/README.md deleted file mode 100644 index 77f5698546..0000000000 --- a/cpp/models/ode_sir_mobility/README.md +++ /dev/null @@ -1,21 +0,0 @@ - -# ODE SIR compartment model - -This model is a very simple ODE model with only three compartments and few parameters, mostly for demonstration of the MEmilio framework: -- Susceptible, may become infected at any time -- Infected, will be recovered after some time -- Recovered, recovered from infectious process (dead or recovered) - -We assume simulations over short periods of time, so that the population size can be considered constant and birth as well as (natural) mortality rates can be ignored. - -Below is an overview of the model architecture and its compartments. - -![SIR_model](https://github.com/SciCompMod/memilio/assets/69154294/01c9a2ae-2f5c-4bad-b7f0-34de651f2c73) -| Mathematical variable | C++ variable name | Description | -|---------------------------- | --------------- | -------------------------------------------------------------------------------------------------- | -| $\phi$ | `ContactPatterns` | Daily contact rate / Number of daily contacts. | -| $\rho$ | `TransmissionProbabilityOnContact` | Transmission risk for people located in the Susceptible compartment. | -| $N$ | `populations.get_total()` | Total population. | -| $T_{I}$ | `TimeInfected` | Time in days an individual stays in the Infected compartment. | - -An example can be found in [examples/ode_sir.cpp](../../examples/ode_sir.cpp) diff --git a/cpp/models/ode_sir_mobility/infection_state.h b/cpp/models/ode_sir_mobility/infection_state.h deleted file mode 100644 index dc98471c73..0000000000 --- a/cpp/models/ode_sir_mobility/infection_state.h +++ /dev/null @@ -1,25 +0,0 @@ - -#ifndef ODESIRMOBILITY_INFECTIONSTATE_H -#define ODESIRMOBILITY_INFECTIONSTATE_H - -namespace mio -{ -namespace osirmobility -{ - -/** - * @brief The InfectionState enum describes the possible - * categories for the infectious state of persons - */ -enum class InfectionState -{ - Susceptible, - Infected, - Recovered, - Count -}; - -} // namespace osir -} // namespace mio - -#endif // ODESIR_INFECTIONSTATE_H diff --git a/cpp/models/ode_sir_mobility/model.cpp b/cpp/models/ode_sir_mobility/model.cpp deleted file mode 100644 index 0f8bf7b573..0000000000 --- a/cpp/models/ode_sir_mobility/model.cpp +++ /dev/null @@ -1,10 +0,0 @@ - -#include "ode_sir_mobility/model.h" - -namespace mio -{ -namespace osirmobility -{ - -} // namespace osir -} // namespace mio diff --git a/cpp/models/ode_sir_mobility/model.h b/cpp/models/ode_sir_mobility/model.h deleted file mode 100644 index 30ef675728..0000000000 --- a/cpp/models/ode_sir_mobility/model.h +++ /dev/null @@ -1,114 +0,0 @@ - -#ifndef ODESIRMOBILITY_MODEL_H -#define ODESIRMOBILITY_MODEL_H - -#include "memilio/compartments/flow_model.h" -#include "memilio/epidemiology/populations.h" -#include "ode_sir_mobility/infection_state.h" -#include "ode_sir_mobility/parameters.h" -#include "ode_sir_mobility/regions.h" -#include "memilio/epidemiology/age_group.h" - -namespace mio -{ -namespace osirmobility -{ - -/******************** - * define the model * - ********************/ - -using Flows = TypeList, - Flow>; - -template -class Model : public FlowModel, - Parameters, Flows> -{ - - using Base = - FlowModel, Parameters, Flows>; - -public: - using typename Base::ParameterSet; - using typename Base::Populations; - - Model(int num_regions, int num_agegroups) - : Base(Populations({Region(num_regions), AgeGroup(num_agegroups), InfectionState::Count}), - ParameterSet(Region(num_regions), AgeGroup(num_agegroups))) - { - } - // Einmal über den Vektor und später nochmal über die Regions - - void get_flows(Eigen::Ref> pop, Eigen::Ref> y, FP t, - Eigen::Ref> flows) const override - { - const auto& params = this->parameters; - const auto& population = this->populations; - - const Index n_age_groups = reduce_index>(params.get_num_agegroups()); - const Index n_regions = reduce_index>(params.get_num_regions()); - - for (auto age_i : make_index_range(n_age_groups)) { - for (auto age_j : make_index_range(n_age_groups)) { - double coeffStoI = params.template get>().get_cont_freq_mat().get_matrix_at(t)( - age_i.get(), age_j.get()) * - params.template get>()[age_i] / - population.get_group_total(age_j); - for (auto edge : params.template get()) { - auto start_region = get<0>(edge); - auto end_region = get<1>(edge); - auto strength = get(edge); - if (start_region == end_region) { - continue; - } - // s_n += h_mn/P_m * i_m - flows[Base::template get_flat_flow_index( - {start_region, age_i})] += - strength * pop[population.get_flat_index({end_region, age_j, InfectionState::Infected})]; - // s_m += h_mn/P_m * i_n - flows[Base::template get_flat_flow_index( - {end_region, age_i})] += - strength * pop[population.get_flat_index({start_region, age_j, InfectionState::Infected})]; - - // s_n += gamma * h_nm/P_n * sum(h_km/P_k * p_nm,k * i_k) - for (auto edge_commuter : params.template get()) { - auto start_region_commuter = get<0>(edge_commuter); - auto end_region_commuter = get<1>(edge_commuter); - auto strength_commuter = get(edge_commuter); - if (end_region_commuter != end_region || start_region_commuter == start_region || - ((std::find(params.template get()[{start_region, end_region}].begin(), - params.template get()[{start_region, end_region}].end(), - start_region_commuter)) == - params.template get()[{start_region, end_region}].end())) { - continue; - } - flows[Base::template get_flat_flow_index( - {start_region, age_i})] += - params.template get>() * strength * - strength_commuter * - pop[population.get_flat_index({start_region_commuter, age_j, InfectionState::Infected})]; - } - } - for (auto region : make_index_range(n_regions)) { - flows[Base::template get_flat_flow_index( - {region, age_i})] += pop[population.get_flat_index({region, age_j, InfectionState::Infected})]; - flows[Base::template get_flat_flow_index( - {region, age_i})] *= - coeffStoI * y[population.get_flat_index({region, age_j, InfectionState::Susceptible})]; - } - } - - for (auto region : make_index_range(n_regions)) { - flows[Base::template get_flat_flow_index( - {region, age_i})] = (1.0 / params.template get>()[age_i]) * - y[population.get_flat_index({region, age_i, InfectionState::Infected})]; - } - } - } -}; - -} // namespace osirmobility -} // namespace mio - -#endif // ODESIRMOBILITY_MODEL_H diff --git a/cpp/models/ode_sir_mobility/parameters.h b/cpp/models/ode_sir_mobility/parameters.h deleted file mode 100644 index 18f7110543..0000000000 --- a/cpp/models/ode_sir_mobility/parameters.h +++ /dev/null @@ -1,286 +0,0 @@ - -#ifndef SIRMOBILITY_PARAMETERS_H -#define SIRMOBILITY_PARAMETERS_H - -#include "memilio/epidemiology/uncertain_matrix.h" -#include "memilio/utils/uncertain_value.h" -#include "memilio/epidemiology/age_group.h" -#include "memilio/utils/parameter_set.h" -#include "memilio/utils/custom_index_array.h" -#include "ode_sir_mobility/regions.h" - -#include - -namespace mio -{ -namespace osirmobility -{ - -/**************************************************** - * Define Parameters of the SIR model with mobility * - ****************************************************/ - -/** - * @brief Probability of getting infected from a contact. - */ -template -struct TransmissionProbabilityOnContact { - using Type = CustomIndexArray, AgeGroup>; - static Type get_default(Region, AgeGroup size) - { - return Type(size, 1.0); - } - static std::string name() - { - return "TransmissionProbabilityOnContact"; - } -}; - -/** - * @brief The infectious time in day unit. - */ -template -struct TimeInfected { - using Type = CustomIndexArray, AgeGroup>; - static Type get_default(Region, AgeGroup size) - { - return Type(size, 6.0); - } - static std::string name() - { - return "TimeInfected"; - } -}; - -/** - * @brief The contact patterns within the society are modelled using a ContactMatrix. - */ -template -struct ContactPatterns { - using Type = UncertainContactMatrix; - static Type get_default(Region, AgeGroup size) - { - return Type(1, static_cast((size_t)size)); - } - static std::string name() - { - return "ContactPatterns"; - } -}; - -/** - * @brief The mean number of people migrating from one Region to another during a TimeStep. - */ -struct CommutingRatio { - using Type = std::vector>; - static Type get_default(Region, AgeGroup) - { - return Type({{Region(0), Region(0), 0.}}); - } - static std::string name() - { - return "CommutingRatio"; - } -}; - -/** - * @brief The ratio that regulates the infections during commuting. -*/ -template -struct ImpactTransmissionDuringCommuting { - using Type = UncertainValue; - static Type get_default(Region, AgeGroup) - { - return Type(0.); - } - static std::string name() - { - return "ImpactTransmissionDuringCommuting"; - } -}; - -/** - * @brief The Region%s that a person crosses when travelling from one Region to another. -*/ -struct PathIntersections { - using Type = CustomIndexArray, Region, Region>; - static Type get_default(Region size, AgeGroup) - { - return Type({size, size}); - } - static std::string name() - { - return "PathIntersections"; - } -}; - -template -using ParametersBase = ParameterSet, TimeInfected, ContactPatterns, - CommutingRatio, ImpactTransmissionDuringCommuting, PathIntersections>; - -/** - * @brief Parameters of SIR model. - */ -template -class Parameters : public ParametersBase -{ -public: - Parameters(Region num_regions, AgeGroup num_agegroups) - : ParametersBase(num_regions, num_agegroups) - , m_num_regions{num_regions} - , m_num_agegroups(num_agegroups) - { - } - - Region get_num_regions() const - { - return m_num_regions; - } - - AgeGroup get_num_agegroups() const - { - return m_num_agegroups; - } - - /** - * @brief Checks whether all Parameters satisfy their corresponding constraints and applies them, if they do not. - * Time spans cannot be negative and probabilities can only take values between [0,1]. - * - * Attention: This function should be used with care. It is necessary for some test problems to run through quickly, - * but in a manual execution of an example, check_constraints() may be preferred. Note that the apply_constraints() - * function can and will not set Parameters to meaningful values in an epidemiological or virological context, - * as all models are designed to be transferable to multiple diseases. Consequently, only acceptable - * (like 0 or 1 for probabilities or small positive values for time spans) values are set here and a manual adaptation - * may often be necessary to have set meaningful values. - * - * @return Returns true if one ore more constraint were corrected, false otherwise. - */ - bool apply_constraints() - { - double tol_times = 1e-1; - - int corrected = false; - - for (auto i = AgeGroup(0); i < AgeGroup(m_num_agegroups); i++) { - if (this->template get>()[i] < tol_times) { - log_warning( - "Constraint check: Parameter TimeInfected changed from {:.4f} to {:.4f}. Please note that " - "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " - "and reset parameters.", - this->template get>()[i], tol_times); - this->template get>()[i] = tol_times; - corrected = true; - } - if (this->template get>()[i] < 0.0 || - this->template get>()[i] > 1.0) { - log_warning( - "Constraint check: Parameter TransmissionProbabilityOnContact changed from {:0.4f} to {:d} ", - this->template get>()[i], 0.0); - this->template get>() = 0.0; - corrected = true; - } - } - if (this->template get>() < 0.0 || - this->template get>() > 1.0) { - log_warning("Constraint check: Parameter ImpactTransmissionDuringCommuting changed from {:.4f} to {:.4f}.", - this->template get>(), 0.0); - this->template get>() = 0.0; - corrected = true; - } - for (auto& i : this->template get()) { - if (std::get(i) < 0.0 || std::get(i) > 1.0) { - log_warning("Constraint check: Parameter CommutingRatio changed from {:.4f} to {:.4f}.", - std::get(i), 0.0); - std::get(i) = 0.0; - corrected = true; - } - if (std::get<0>(i) < Region(0) || std::get<1>(i) < Region(0) || std::get<0>(i) >= m_num_regions || - std::get<1>(i) >= m_num_regions) { - log_warning( - "Constraint check: Removed entry of Parameter CommutingRatio because of non-existing Regions."); - auto it = std::find(this->template get().begin(), - this->template get().end(), i); - this->template get().erase(it); - corrected = true; - } - } - return corrected; - } - - /** - * @brief Checks whether all Parameters satisfy their corresponding constraints and logs an error - * if constraints are not satisfied. - * @return Returns true if one constraint is not satisfied, otherwise false. - */ - bool check_constraints() const - { - double tol_times = 1e-1; - - for (auto i = AgeGroup(0); i < AgeGroup(m_num_agegroups); i++) { - - if (this->template get>()[i] < tol_times) { - log_error( - "Constraint check: Parameter TimeInfected {:.4f} smaller or equal {:.4f}. Please note that " - "unreasonably small compartment stays lead to massively increased run time. Consider to cancel " - "and reset parameters.", - this->template get>()[i], 0.0); - return true; - } - if (this->template get>()[i] < 0.0 || - this->template get>()[i] > 1.0) { - log_error("Constraint check: Parameter TransmissionProbabilityOnContact {:.4f} smaller {:.4f} or " - "greater {:.4f}", - this->template get>()[i], 0.0, 1.0); - return true; - } - } - if (this->template get>() < 0.0 || - this->template get>() > 1.0) { - log_error( - "Constraint check: Parameter ImpactTransmissionDuringCommuting {:.4f} smaller {:.4f} or greater {:.4f}", - this->template get>(), 0.0, 1.0); - return true; - } - for (auto i : this->template get()) { - if (std::get(i) < 0.0 || std::get(i) > 1.0) { - log_error("Constraint check: Parameter CommutingRatio entry {:.4f} smaller {:.4f} or greater {:.4f}", - std::get(i), 0.0, 1.0); - return true; - } - if (std::get<0>(i) < Region(0) || std::get<1>(i) < Region(0) || std::get<0>(i) > m_num_regions || - std::get<1>(i) > m_num_regions) { - log_error("Constraint check: Parameter CommutingRatio has an entry with start or end Region " - "that does not appear in the model."); - return true; - } - } - return false; - } - -private: - // Parameters(ParametersBase&& base) - // : ParametersBase(std::move(base)) //TODO: Adjust - // { - // } - -public: - /** - * deserialize an object of this class. - * @see mio::deserialize - */ - template - static IOResult deserialize(IOContext& io) - { - BOOST_OUTCOME_TRY(auto&& base, ParametersBase::deserialize(io)); - return success(Parameters(std::move(base))); - } - -private: - Region m_num_regions; - AgeGroup m_num_agegroups; -}; - -} // namespace osirmobility -} // namespace mio - -#endif // SIR_PARAMETERS_H diff --git a/cpp/models/ode_sir_mobility/regions.h b/cpp/models/ode_sir_mobility/regions.h deleted file mode 100644 index d3c8b528a7..0000000000 --- a/cpp/models/ode_sir_mobility/regions.h +++ /dev/null @@ -1,26 +0,0 @@ - -#ifndef ODESIRMOBILITY_REGIONS_H -#define ODESIRMOBILITY_REGIONS_H - -#include "memilio/utils/index.h" - -namespace mio -{ -namespace osirmobility -{ - -/** - * @brief The AgeGroup struct is used as a dynamically - * sized tag for all age dependent categories - */ -struct Region : public Index { - Region(size_t val) - : Index(val) - { - } -}; - -} // namespace osirmobility -} // namespace mio - -#endif From 9f8334fa53300446508aa80760296d548c4f4b31 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:21:35 +0100 Subject: [PATCH 65/87] add system flag for boost again --- cpp/thirdparty/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/thirdparty/CMakeLists.txt b/cpp/thirdparty/CMakeLists.txt index 7b34358721..582cdb81ba 100644 --- a/cpp/thirdparty/CMakeLists.txt +++ b/cpp/thirdparty/CMakeLists.txt @@ -96,7 +96,7 @@ if(MEMILIO_USE_BUNDLED_BOOST) add_library(boost INTERFACE) add_dependencies(boost boost-bootstrap) add_library(Boost::boost ALIAS boost) - target_include_directories(boost INTERFACE $) + target_include_directories(boost SYSTEM INTERFACE $) if (NOT MSVC) target_compile_options(boost INTERFACE "-Wno-c++20-attribute-extensions") From a4351e3e5c77f7e3a9b1514f2ac10b46e31993dc Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:48:40 +0100 Subject: [PATCH 66/87] rename ode_seir_mobility --- cpp/CMakeLists.txt | 2 +- cpp/examples/CMakeLists.txt | 6 +++--- .../examples_thesis/basic_reproduction_number_modela.cpp | 2 -- .../examples_thesis/basic_reproduction_number_modelb.cpp | 3 +-- .../{ode_metapop_liu_nrw.cpp => ode_metapop_wang_nrw.cpp} | 8 ++++---- .../CMakeLists.txt | 0 .../infection_state.h | 0 .../{ode_seir_mobility => ode_metapop_wang}/model.cpp | 2 +- .../{ode_seir_mobility => ode_metapop_wang}/model.h | 6 +++--- .../{ode_seir_mobility => ode_metapop_wang}/parameters.h | 2 +- .../{ode_seir_mobility => ode_metapop_wang}/regions.h | 0 11 files changed, 14 insertions(+), 17 deletions(-) rename cpp/examples/examples_thesis/{ode_metapop_liu_nrw.cpp => ode_metapop_wang_nrw.cpp} (97%) rename cpp/models/{ode_seir_mobility => ode_metapop_wang}/CMakeLists.txt (100%) rename cpp/models/{ode_seir_mobility => ode_metapop_wang}/infection_state.h (100%) rename cpp/models/{ode_seir_mobility => ode_metapop_wang}/model.cpp (71%) rename cpp/models/{ode_seir_mobility => ode_metapop_wang}/model.h (98%) rename cpp/models/{ode_seir_mobility => ode_metapop_wang}/parameters.h (99%) rename cpp/models/{ode_seir_mobility => ode_metapop_wang}/regions.h (100%) diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 754597f74c..97d549d3f9 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -152,7 +152,7 @@ if(MEMILIO_BUILD_MODELS) add_subdirectory(models/ode_seair) add_subdirectory(models/ode_sir) add_subdirectory(models/ode_metapop) - add_subdirectory(models/ode_seir_mobility) + add_subdirectory(models/ode_metapop_wang) add_subdirectory(models/sde_sir) add_subdirectory(models/sde_sirs) add_subdirectory(models/sde_seirvv) diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index a9d14cf7ef..8256dd8e29 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -30,9 +30,9 @@ add_executable(sde_sir_example sde_sir.cpp) target_link_libraries(sde_sir_example PRIVATE memilio sde_sir) target_compile_options(sde_sir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -add_executable(ode_metapop_liu_nrw examples_thesis/ode_metapop_liu_nrw.cpp) -target_link_libraries(ode_metapop_liu_nrw PRIVATE memilio ode_seir_mobility) -target_compile_options(ode_metapop_liu_nrw PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ode_metapop_wang_nrw examples_thesis/ode_metapop_wang_nrw.cpp) +target_link_libraries(ode_metapop_wang_nrw PRIVATE memilio ode_seir_mobility) +target_compile_options(ode_metapop_wang_nrw PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) if (MEMILIO_ENABLE_OPENMP) add_executable(ode_metapop_timing examples_thesis/ode_metapop_timing.cpp) diff --git a/cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp b/cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp index 01d96bba61..aa58d7cbea 100644 --- a/cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp +++ b/cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp @@ -1,6 +1,4 @@ - #include "models/ode_seir/model.h" -#include "models/ode_seir_mobility/model.h" #include "memilio/math/euler.h" #include "memilio/compartments/simulation.h" diff --git a/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp b/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp index a2e6b0c5cf..bfd52b3113 100644 --- a/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp +++ b/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp @@ -1,6 +1,5 @@ -#include "models/ode_seir/model.h" -#include "models/ode_seir_mobility/model.h" +#include "models/ode_metapop_wang/model.h" #include "memilio/math/euler.h" #include "memilio/compartments/simulation.h" diff --git a/cpp/examples/examples_thesis/ode_metapop_liu_nrw.cpp b/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp similarity index 97% rename from cpp/examples/examples_thesis/ode_metapop_liu_nrw.cpp rename to cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp index 4b5600a215..4802cb8852 100644 --- a/cpp/examples/examples_thesis/ode_metapop_liu_nrw.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp @@ -4,10 +4,10 @@ #include "memilio/utils/logging.h" #include "memilio/utils/custom_index_array.h" #include "memilio/io/mobility_io.h" -#include "models/ode_seir_mobility/infection_state.h" -#include "models/ode_seir_mobility/model.h" -#include "models/ode_seir_mobility/parameters.h" -#include "models/ode_seir_mobility/regions.h" +#include "models/ode_metapop_wang/infection_state.h" +#include "models/ode_metapop_wang/model.h" +#include "models/ode_metapop_wang/parameters.h" +#include "models/ode_metapop_wang/regions.h" #include "memilio/io/io.h" #include "memilio/io/epi_data.h" #include "memilio/io/result_io.h" diff --git a/cpp/models/ode_seir_mobility/CMakeLists.txt b/cpp/models/ode_metapop_wang/CMakeLists.txt similarity index 100% rename from cpp/models/ode_seir_mobility/CMakeLists.txt rename to cpp/models/ode_metapop_wang/CMakeLists.txt diff --git a/cpp/models/ode_seir_mobility/infection_state.h b/cpp/models/ode_metapop_wang/infection_state.h similarity index 100% rename from cpp/models/ode_seir_mobility/infection_state.h rename to cpp/models/ode_metapop_wang/infection_state.h diff --git a/cpp/models/ode_seir_mobility/model.cpp b/cpp/models/ode_metapop_wang/model.cpp similarity index 71% rename from cpp/models/ode_seir_mobility/model.cpp rename to cpp/models/ode_metapop_wang/model.cpp index 75494e52d6..b8420ea023 100644 --- a/cpp/models/ode_seir_mobility/model.cpp +++ b/cpp/models/ode_metapop_wang/model.cpp @@ -1,5 +1,5 @@ -#include "ode_seir_mobility/model.h" +#include "ode_metapop_wang/model.h" namespace mio { diff --git a/cpp/models/ode_seir_mobility/model.h b/cpp/models/ode_metapop_wang/model.h similarity index 98% rename from cpp/models/ode_seir_mobility/model.h rename to cpp/models/ode_metapop_wang/model.h index 1f775495ae..493a39e96a 100644 --- a/cpp/models/ode_seir_mobility/model.h +++ b/cpp/models/ode_metapop_wang/model.h @@ -4,9 +4,9 @@ #include "memilio/compartments/flow_model.h" #include "memilio/epidemiology/populations.h" -#include "models/ode_seir_mobility/infection_state.h" -#include "models/ode_seir_mobility/parameters.h" -#include "models/ode_seir_mobility/regions.h" +#include "models/ode_metapop_wang/infection_state.h" +#include "models/ode_metapop_wang/parameters.h" +#include "models/ode_metapop_wang/regions.h" #include "memilio/epidemiology/age_group.h" #include "memilio/utils/time_series.h" diff --git a/cpp/models/ode_seir_mobility/parameters.h b/cpp/models/ode_metapop_wang/parameters.h similarity index 99% rename from cpp/models/ode_seir_mobility/parameters.h rename to cpp/models/ode_metapop_wang/parameters.h index ca6fd99f1f..af1b5559aa 100644 --- a/cpp/models/ode_seir_mobility/parameters.h +++ b/cpp/models/ode_metapop_wang/parameters.h @@ -7,7 +7,7 @@ #include "memilio/epidemiology/age_group.h" #include "memilio/utils/parameter_set.h" #include "memilio/utils/custom_index_array.h" -#include "models/ode_seir_mobility/regions.h" +#include "models/ode_metapop_wang/regions.h" #include diff --git a/cpp/models/ode_seir_mobility/regions.h b/cpp/models/ode_metapop_wang/regions.h similarity index 100% rename from cpp/models/ode_seir_mobility/regions.h rename to cpp/models/ode_metapop_wang/regions.h From f18a2ef3963176b1df1481f1c448e9f06b618211 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:22:53 +0100 Subject: [PATCH 67/87] rename namespaces of metapopulation models --- cpp/examples/CMakeLists.txt | 18 +-- .../basic_reproduction_number_modelb.cpp | 16 +-- .../basic_reproduction_number_modelc.cpp | 35 +++-- cpp/examples/examples_thesis/graph_nrw.cpp | 129 +++++------------- .../examples_thesis/ode_metapop_nrw.cpp | 85 ++++++------ .../examples_thesis/ode_metapop_steps.cpp | 78 ++++++----- .../examples_thesis/ode_metapop_timing.cpp | 77 +++++------ .../examples_thesis/ode_metapop_wang_nrw.cpp | 66 ++++----- cpp/models/ode_metapop/infection_state.h | 4 +- cpp/models/ode_metapop/model.cpp | 4 +- cpp/models/ode_metapop/model.h | 6 +- cpp/models/ode_metapop/parameters.h | 4 +- cpp/models/ode_metapop/regions.h | 4 +- cpp/models/ode_metapop_wang/CMakeLists.txt | 8 +- cpp/models/ode_metapop_wang/infection_state.h | 4 +- cpp/models/ode_metapop_wang/model.cpp | 4 +- cpp/models/ode_metapop_wang/model.h | 4 +- cpp/models/ode_metapop_wang/parameters.h | 4 +- cpp/models/ode_metapop_wang/regions.h | 4 +- 19 files changed, 241 insertions(+), 313 deletions(-) diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 8256dd8e29..7bb45f95b6 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -31,7 +31,7 @@ target_link_libraries(sde_sir_example PRIVATE memilio sde_sir) target_compile_options(sde_sir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) add_executable(ode_metapop_wang_nrw examples_thesis/ode_metapop_wang_nrw.cpp) -target_link_libraries(ode_metapop_wang_nrw PRIVATE memilio ode_seir_mobility) +target_link_libraries(ode_metapop_wang_nrw PRIVATE memilio ode_metapop_wang) target_compile_options(ode_metapop_wang_nrw PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) if (MEMILIO_ENABLE_OPENMP) @@ -46,20 +46,20 @@ target_link_libraries(ode_metapop_steps PRIVATE memilio ode_metapop) target_compile_options(ode_metapop_steps PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) add_executable(basic_reproduction_number_modela examples_thesis/basic_reproduction_number_modela.cpp) -target_link_libraries(basic_reproduction_number_modela PRIVATE memilio ode_seir_mobility) +target_link_libraries(basic_reproduction_number_modela PRIVATE memilio ode_seir) target_compile_options(basic_reproduction_number_modela PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) add_executable(basic_reproduction_number_modelb examples_thesis/basic_reproduction_number_modelb.cpp) -target_link_libraries(basic_reproduction_number_modelb PRIVATE memilio ode_seir_mobility) +target_link_libraries(basic_reproduction_number_modelb PRIVATE memilio ode_metapop_wang) target_compile_options(basic_reproduction_number_modelb PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) add_executable(basic_reproduction_number_modelc examples_thesis/basic_reproduction_number_modelc.cpp) target_link_libraries(basic_reproduction_number_modelc PRIVATE memilio ode_metapop) target_compile_options(basic_reproduction_number_modelc PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -add_executable(ode_metapop_example_nrw examples_thesis/ode_metapop_nrw.cpp) -target_link_libraries(ode_metapop_example_nrw PRIVATE memilio ode_metapop) -target_compile_options(ode_metapop_example_nrw PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ode_metapop_nrw examples_thesis/ode_metapop_nrw.cpp) +target_link_libraries(ode_metapop_nrw PRIVATE memilio ode_metapop) +target_compile_options(ode_metapop_nrw PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) add_executable(sde_sirs_example sde_sirs.cpp) target_link_libraries(sde_sirs_example PRIVATE memilio sde_sirs) @@ -115,9 +115,9 @@ add_executable(graph_example graph.cpp) target_link_libraries(graph_example PRIVATE memilio ode_seir) target_compile_options(graph_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -add_executable(graph_example_nrw examples_thesis/graph_nrw.cpp) -target_link_libraries(graph_example_nrw PRIVATE memilio ode_seir) -target_compile_options(graph_example_nrw PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(graph_nrw examples_thesis/graph_nrw.cpp) +target_link_libraries(graph_nrw PRIVATE memilio ode_seir) +target_compile_options(graph_nrw PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) add_executable(graph_steps examples_thesis/graph_steps.cpp) target_link_libraries(graph_steps PRIVATE memilio ode_seir) diff --git a/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp b/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp index bfd52b3113..401e460b0e 100644 --- a/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp +++ b/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp @@ -26,13 +26,13 @@ void calculate_basic_reproduction_number(size_t number_regions, ScalarType tmax) ScalarType dt = 0.1; ScalarType number_age_groups = 6; - mio::oseirmobility::Model model(number_regions, number_age_groups); + mio::oseirmetapopwang::Model model(number_regions, number_age_groups); auto& population = model.populations; for (size_t j = 0; j < number_age_groups; j++) { for (size_t i = 0; i < number_regions; i++) { - population[{mio::oseirmobility::Region(i), mio::AgeGroup(j), - mio::oseirmobility::InfectionState::Susceptible}] = 10000; + population[{mio::oseirmetapopwang::Region(i), mio::AgeGroup(j), + mio::oseirmetapopwang::InfectionState::Susceptible}] = 10000; } } @@ -44,17 +44,17 @@ void calculate_basic_reproduction_number(size_t number_regions, ScalarType tmax) for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); } - model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = + model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = mobility_data_commuter; mio::ContactMatrixGroup& contact_matrix = - model.parameters.template get>().get_cont_freq_mat(); + model.parameters.template get>().get_cont_freq_mat(); contact_matrix[0].get_baseline() = get_contact_matrix(); for (size_t j = 0; j < number_age_groups; j++) { - model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; - model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; - model.parameters.template get>()[mio::AgeGroup(j)] = + model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = TransmissionProbabilityOnContact[j]; } diff --git a/cpp/examples/examples_thesis/basic_reproduction_number_modelc.cpp b/cpp/examples/examples_thesis/basic_reproduction_number_modelc.cpp index f1de131aec..683a8500c9 100644 --- a/cpp/examples/examples_thesis/basic_reproduction_number_modelc.cpp +++ b/cpp/examples/examples_thesis/basic_reproduction_number_modelc.cpp @@ -25,13 +25,13 @@ void calculate_basic_reproduction_number(size_t number_regions, ScalarType tmax) ScalarType dt = 0.1; ScalarType number_age_groups = 6; - mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); + mio::oseirmetapop::Model model(number_regions, number_age_groups); auto& population = model.populations; for (size_t j = 0; j < number_age_groups; j++) { for (size_t i = 0; i < number_regions; i++) { - population[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + population[{mio::oseirmetapop::Region(i), mio::AgeGroup(j), + mio::oseirmetapop::InfectionState::Susceptible}] = 10000; } } @@ -43,39 +43,36 @@ void calculate_basic_reproduction_number(size_t number_regions, ScalarType tmax) for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); } - model.parameters.template get>() - .get_cont_freq_mat()[0] - .get_baseline() = mobility_data_commuter; + model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = + mobility_data_commuter; mio::ContactMatrixGroup& contact_matrix = - model.parameters.template get>().get_cont_freq_mat(); + model.parameters.template get>().get_cont_freq_mat(); contact_matrix[0].get_baseline() = get_contact_matrix(); for (size_t j = 0; j < number_age_groups; j++) { - model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; - model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; - model.parameters - .template get>()[mio::AgeGroup(j)] = + model.parameters.template get>()[mio::AgeGroup(j)] = TimeExposed[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = TimeInfected[j]; + model.parameters.template get>()[mio::AgeGroup(j)] = TransmissionProbabilityOnContact[j]; } mio::ContactMatrixGroup& commuting_strengths = - model.parameters.template get>().get_cont_freq_mat(); + model.parameters.template get>().get_cont_freq_mat(); auto& population_after_commuting = model.m_population_after_commuting; for (size_t region_n = 0; region_n < number_regions; ++region_n) { for (size_t age = 0; age < number_age_groups; ++age) { double population_n = 0; - for (size_t state = 0; state < (size_t)mio::oseirmobilityimproved::InfectionState::Count; state++) { - population_n += population[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), - mio::oseirmobilityimproved::InfectionState(state)}]; + for (size_t state = 0; state < (size_t)mio::oseirmetapop::InfectionState::Count; state++) { + population_n += population[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age), + mio::oseirmetapop::InfectionState(state)}]; } - population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += - population_n; + population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] += population_n; for (size_t region_m = 0; region_m < number_regions; ++region_m) { - population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= + population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] -= commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; - population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += + population_after_commuting[{mio::oseirmetapop::Region(region_m), mio::AgeGroup(age)}] += commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; } } diff --git a/cpp/examples/examples_thesis/graph_nrw.cpp b/cpp/examples/examples_thesis/graph_nrw.cpp index 5fde967f6d..46dc1bd29f 100644 --- a/cpp/examples/examples_thesis/graph_nrw.cpp +++ b/cpp/examples/examples_thesis/graph_nrw.cpp @@ -31,28 +31,20 @@ static const std::map contact_locations = {{Contac * @param params Object that the contact matrices will be added to. * @returns any io errors that happen during reading of the files. */ -mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseir::Parameters& params, - bool synthetic_population) +mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseir::Parameters& params) { - if (!synthetic_population) { - //TODO: io error handling - auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_groups())); - for (auto&& contact_location : contact_locations) { - BOOST_OUTCOME_TRY(auto&& baseline, - mio::read_mobility_plain( - (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); - BOOST_OUTCOME_TRY(auto&& minimum, - mio::read_mobility_plain( - (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); - contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; - contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; - } - params.get>() = mio::UncertainContactMatrix(contact_matrices); - } - else { - mio::ContactMatrixGroup& contact_matrix = params.get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(7.95 / (size_t)params.get_num_groups()); + auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_groups())); + for (auto&& contact_location : contact_locations) { + BOOST_OUTCOME_TRY(auto&& baseline, + mio::read_mobility_plain( + (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); + BOOST_OUTCOME_TRY(auto&& minimum, + mio::read_mobility_plain( + (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); + contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; + contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; } + params.get>() = mio::UncertainContactMatrix(contact_matrices); printf("Setting contact matrices successful.\n"); return mio::success(); @@ -64,29 +56,22 @@ mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseir::P * @param params Object that the parameters will be added to. * @returns Currently generates no errors. */ -mio::IOResult set_covid_parameters(mio::oseir::Parameters& params, bool synthetic_population) +mio::IOResult set_covid_parameters(mio::oseir::Parameters& params) { params.template set>(3.335); - if (!synthetic_population) { - params.get>()[mio::AgeGroup(0)] = 8.0096875; - params.get>()[mio::AgeGroup(1)] = 8.0096875; - params.get>()[mio::AgeGroup(2)] = 8.2182; - params.get>()[mio::AgeGroup(3)] = 8.1158; - params.get>()[mio::AgeGroup(4)] = 8.033; - params.get>()[mio::AgeGroup(5)] = 7.985; - - params.get>()[mio::AgeGroup(0)] = 0.03; - params.get>()[mio::AgeGroup(1)] = 0.06; - params.get>()[mio::AgeGroup(2)] = 0.06; - params.get>()[mio::AgeGroup(3)] = 0.06; - params.get>()[mio::AgeGroup(4)] = 0.09; - params.get>()[mio::AgeGroup(5)] = 0.175; - } - else { - params.template set>(8.097612257); - - params.template set>(0.07333); - } + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; printf("Setting epidemiological parameters successful.\n"); return mio::success(); @@ -140,47 +125,18 @@ set_population_data(const fs::path& data_dir, mio::oseir::Parameters& pa return mio::success(nodes); } -mio::IOResult>> -set_synthetic_population_data(mio::oseir::Parameters& params) -{ - size_t number_regions = 53; - - std::vector> nodes(number_regions, - mio::oseir::Model(int(size_t(params.get_num_groups())))); - - mio::Populations population( - {params.get_num_groups(), mio::oseir::InfectionState::Count}); - - for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { - population[{i, mio::oseir::InfectionState::Susceptible}] = 1000000; - } - for (auto& node : nodes) { - node.parameters = params; - node.populations = population; - } - for (auto i = mio::AgeGroup(0); i < params.get_num_groups(); i++) { - nodes[0].populations[{i, mio::oseir::InfectionState::Exposed}] = 100; - nodes[0].populations[{i, mio::oseir::InfectionState::Susceptible}] = 999900; - } - - return mio::success(nodes); -} - mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double dt) { mio::set_log_level(mio::LogLevel::off); // global parameters - bool synthetic_population = false; - const int num_age_groups = 6; - if (num_age_groups != 6) { - synthetic_population = true; - } + const int num_age_groups = 6; + mio::oseir::Parameters params(num_age_groups); - BOOST_OUTCOME_TRY(set_covid_parameters(params, synthetic_population)); + BOOST_OUTCOME_TRY(set_covid_parameters(params)); // set contact matrix - BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, params, synthetic_population)); + BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, params)); // graph of counties with populations and local parameters // and mobility between counties @@ -191,20 +147,11 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double mio::get_node_ids((data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true, true)); - if (synthetic_population) { - BOOST_OUTCOME_TRY(auto&& nodes, set_synthetic_population_data(params)); - for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { - params_graph.add_node(node_ids[node_idx], nodes[node_idx]); - } - printf("Setting synthetic population successful.\n"); - } - else { - BOOST_OUTCOME_TRY(auto&& nodes, set_population_data(data_dir, params, node_ids)); - for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { - params_graph.add_node(node_ids[node_idx], nodes[node_idx]); - } - printf("Setting population from data successful.\n"); + BOOST_OUTCOME_TRY(auto&& nodes, set_population_data(data_dir, params, node_ids)); + for (size_t node_idx = 0; node_idx < nodes.size(); ++node_idx) { + params_graph.add_node(node_ids[node_idx], nodes[node_idx]); } + printf("Setting population from data successful.\n"); BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, mio::read_mobility_plain((data_dir / "mobility" / "commuter_mobility_nrw.txt").string())); @@ -227,10 +174,6 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double } } - // for (auto& node : params_graph.nodes()) { - // node.property.get_simulation().set_integrator(std::make_shared>()); - // } - auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); printf("Start Simulation\n"); @@ -244,7 +187,7 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double return n.id; }); - auto save_result_status = save_result(result, county_ids, num_age_groups, "graph_result_nrw_adaptive.h5"); + auto save_result_status = save_result(result, county_ids, num_age_groups, "graph_result_nrw.h5"); return mio::success(); } @@ -255,7 +198,7 @@ int main() const auto tmax = 100.; const auto dt = 0.5; //time step of mobility, daily mobility every second step - const std::string& data_dir = ""; + const std::string& data_dir = "/home/gers_ca/code/memilio/data"; auto result = run(data_dir, t0, tmax, dt); diff --git a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp index d14691dcce..f309cd9439 100644 --- a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp @@ -18,22 +18,22 @@ * @param params Object that the parameters will be added to. * @returns Currently generates no errors. */ -mio::IOResult set_covid_parameters(mio::oseirmobilityimproved::Parameters& params) +mio::IOResult set_covid_parameters(mio::oseirmetapop::Parameters& params) { - params.template set>(3.335); - params.get>()[mio::AgeGroup(0)] = 8.0096875; - params.get>()[mio::AgeGroup(1)] = 8.0096875; - params.get>()[mio::AgeGroup(2)] = 8.2182; - params.get>()[mio::AgeGroup(3)] = 8.1158; - params.get>()[mio::AgeGroup(4)] = 8.033; - params.get>()[mio::AgeGroup(5)] = 7.985; - - params.get>()[mio::AgeGroup(0)] = 0.03; - params.get>()[mio::AgeGroup(1)] = 0.06; - params.get>()[mio::AgeGroup(2)] = 0.06; - params.get>()[mio::AgeGroup(3)] = 0.06; - params.get>()[mio::AgeGroup(4)] = 0.09; - params.get>()[mio::AgeGroup(5)] = 0.175; + params.template set>(3.335); + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; printf("Setting epidemiological parameters successful.\n"); return mio::success(); } @@ -62,8 +62,7 @@ static const std::map contact_locations = {{Contac * @param params Object that the contact matrices will be added to. * @returns any io errors that happen during reading of the files. */ -mio::IOResult set_contact_matrices(const fs::path& data_dir, - mio::oseirmobilityimproved::Parameters& params) +mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseirmetapop::Parameters& params) { //TODO: io error handling auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_agegroups())); @@ -77,15 +76,14 @@ mio::IOResult set_contact_matrices(const fs::path& data_dir, contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; } - params.get>() = - mio::UncertainContactMatrix(contact_matrices); + params.get>() = mio::UncertainContactMatrix(contact_matrices); printf("Setting contact matrices successful.\n"); return mio::success(); } template -mio::IOResult set_population_data(mio::oseirmobilityimproved::Model& model, const fs::path& data_dir) +mio::IOResult set_population_data(mio::oseirmetapop::Model& model, const fs::path& data_dir) { BOOST_OUTCOME_TRY( auto&& node_ids, @@ -106,8 +104,8 @@ mio::IOResult set_population_data(mio::oseirmobilityimproved::Model& m if (it != node_ids.end()) { auto region_idx = size_t(it - node_ids.begin()); for (size_t age = 0; age < (size_t)model.parameters.get_num_agegroups(); age++) { - model.populations[{mio::oseirmobilityimproved::Region(region_idx), mio::AgeGroup(age), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = + model.populations[{mio::oseirmetapop::Region(region_idx), mio::AgeGroup(age), + mio::oseirmetapop::InfectionState::Susceptible}] = entry.population[mio::AgeGroup(age)]; } } @@ -118,11 +116,11 @@ mio::IOResult set_population_data(mio::oseirmobilityimproved::Model& m } template -mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& model, const fs::path& data_dir) +mio::IOResult set_mobility_weights(mio::oseirmetapop::Model& model, const fs::path& data_dir) { size_t number_regions = (size_t)model.parameters.get_num_regions(); if (number_regions == 1) { - model.parameters.template get>() + model.parameters.template get>() .get_cont_freq_mat()[0] .get_baseline() .setConstant(1.0); @@ -141,14 +139,13 @@ mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& } for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { - auto population_i = model.populations.get_group_total(mio::oseirmobilityimproved::Region(county_idx_i)); + auto population_i = model.populations.get_group_total(mio::oseirmetapop::Region(county_idx_i)); mobility_data_commuter.row(county_idx_i) /= population_i; mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); } - model.parameters.template get>() - .get_cont_freq_mat()[0] - .get_baseline() = mobility_data_commuter; + model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = + mobility_data_commuter; printf("Setting mobility weights successful.\n"); return mio::success(); @@ -156,8 +153,7 @@ mio::IOResult set_mobility_weights(mio::oseirmobilityimproved::Model& } template -mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Model& model, - const fs::path& data_dir) +mio::IOResult set_parameters_and_population(mio::oseirmetapop::Model& model, const fs::path& data_dir) { auto& populations = model.populations; auto& parameters = model.parameters; @@ -166,10 +162,9 @@ mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Mo size_t number_age_groups = (size_t)parameters.get_num_agegroups(); BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); - populations[{mio::oseirmobilityimproved::Region(27), mio::AgeGroup(4), - mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; - populations[{mio::oseirmobilityimproved::Region(27), mio::AgeGroup(4), - mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; + populations[{mio::oseirmetapop::Region(27), mio::AgeGroup(4), mio::oseirmetapop::InfectionState::Susceptible}] -= + 100; + populations[{mio::oseirmetapop::Region(27), mio::AgeGroup(4), mio::oseirmetapop::InfectionState::Exposed}] += 100; BOOST_OUTCOME_TRY(set_mobility_weights(model, data_dir)); @@ -178,22 +173,21 @@ mio::IOResult set_parameters_and_population(mio::oseirmobilityimproved::Mo BOOST_OUTCOME_TRY(set_covid_parameters(parameters)); mio::ContactMatrixGroup& commuting_strengths = - parameters.template get>().get_cont_freq_mat(); + parameters.template get>().get_cont_freq_mat(); auto& population_after_commuting = model.m_population_after_commuting; for (size_t region_n = 0; region_n < number_regions; ++region_n) { for (size_t age = 0; age < number_age_groups; ++age) { double population_n = 0; - for (size_t state = 0; state < (size_t)mio::oseirmobilityimproved::InfectionState::Count; state++) { - population_n += populations[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), - mio::oseirmobilityimproved::InfectionState(state)}]; + for (size_t state = 0; state < (size_t)mio::oseirmetapop::InfectionState::Count; state++) { + population_n += populations[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age), + mio::oseirmetapop::InfectionState(state)}]; } - population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += - population_n; + population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] += population_n; for (size_t region_m = 0; region_m < number_regions; ++region_m) { - population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= + population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] -= commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; - population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += + population_after_commuting[{mio::oseirmetapop::Region(region_m), mio::AgeGroup(age)}] += commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; } } @@ -215,9 +209,9 @@ int main() mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& data_dir = ""; + const std::string& data_dir = "/home/gers_ca/code/memilio/data"; - mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); + mio::oseirmetapop::Model model(number_regions, number_age_groups); auto result_prepare_simulation = set_parameters_and_population(model, data_dir); // std::shared_ptr> integrator = std::make_shared>(); @@ -229,6 +223,5 @@ int main() auto result = mio::interpolate_simulation_result(result_from_sim); - auto save_result_status = - mio::save_result({result}, {1}, number_regions * number_age_groups, "ode_result_nrw_adaptive.h5"); + auto save_result_status = mio::save_result({result}, {1}, number_regions * number_age_groups, "ode_result_nrw.h5"); } diff --git a/cpp/examples/examples_thesis/ode_metapop_steps.cpp b/cpp/examples/examples_thesis/ode_metapop_steps.cpp index 72ac4bbef8..7c6cb369a0 100644 --- a/cpp/examples/examples_thesis/ode_metapop_steps.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_steps.cpp @@ -11,7 +11,7 @@ bool age_groups = true; template -void set_contact_matrix(mio::oseirmobilityimproved::Model& model) +void set_contact_matrix(mio::oseirmetapop::Model& model) { if (age_groups) { Eigen::MatrixXd contact_matrix_eigen(6, 6); @@ -19,12 +19,12 @@ void set_contact_matrix(mio::oseirmobilityimproved::Model& model) 0.0161, 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, 0.0458, 0.1939, 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; mio::ContactMatrixGroup& contact_matrix = - model.parameters.template get>().get_cont_freq_mat(); + model.parameters.template get>().get_cont_freq_mat(); contact_matrix[0].get_baseline() = contact_matrix_eigen; } { mio::ContactMatrixGroup& contact_matrix = - model.parameters.template get>().get_cont_freq_mat(); + model.parameters.template get>().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(7.95); } } @@ -35,33 +35,33 @@ void set_contact_matrix(mio::oseirmobilityimproved::Model& model) * @param params Object that the parameters will be added to. * @returns Currently generates no errors. */ -void set_covid_parameters(mio::oseirmobilityimproved::Parameters& params) +void set_covid_parameters(mio::oseirmetapop::Parameters& params) { - params.template set>(3.335); + params.template set>(3.335); if (age_groups) { - params.get>()[mio::AgeGroup(0)] = 8.0096875; - params.get>()[mio::AgeGroup(1)] = 8.0096875; - params.get>()[mio::AgeGroup(2)] = 8.2182; - params.get>()[mio::AgeGroup(3)] = 8.1158; - params.get>()[mio::AgeGroup(4)] = 8.033; - params.get>()[mio::AgeGroup(5)] = 7.985; - - params.get>()[mio::AgeGroup(0)] = 0.03; - params.get>()[mio::AgeGroup(1)] = 0.06; - params.get>()[mio::AgeGroup(2)] = 0.06; - params.get>()[mio::AgeGroup(3)] = 0.06; - params.get>()[mio::AgeGroup(4)] = 0.09; - params.get>()[mio::AgeGroup(5)] = 0.175; + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; } else { - params.get>()[mio::AgeGroup(0)] = 0.07333; - params.get>()[mio::AgeGroup(0)] = 8.097612257; + params.get>()[mio::AgeGroup(0)] = 0.07333; + params.get>()[mio::AgeGroup(0)] = 8.097612257; } } template -void set_mobility_weights(mio::oseirmobilityimproved::Model& model) +void set_mobility_weights(mio::oseirmetapop::Model& model) { size_t number_regions = (size_t)model.parameters.get_num_regions(); double fraction_commuter = 1. / (2 * number_regions); @@ -72,13 +72,12 @@ void set_mobility_weights(mio::oseirmobilityimproved::Model& model) for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); } - model.parameters.template get>() - .get_cont_freq_mat()[0] - .get_baseline() = mobility_data_commuter; + model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = + mobility_data_commuter; } template -void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) +void set_parameters_and_population(mio::oseirmetapop::Model& model) { auto& populations = model.populations; auto& parameters = model.parameters; @@ -87,14 +86,14 @@ void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) size_t number_age_groups = (size_t)parameters.get_num_agegroups(); for (size_t j = 0; j < number_age_groups; j++) { for (size_t i = 0; i < number_regions; i++) { - model.populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 10000; + model.populations[{mio::oseirmetapop::Region(i), mio::AgeGroup(j), + mio::oseirmetapop::InfectionState::Susceptible}] = 10000; } } - model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; - model.populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; + model.populations[{mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed}] += + 100; + model.populations[{mio::oseirmetapop::Region(0), mio::AgeGroup(0), + mio::oseirmetapop::InfectionState::Susceptible}] -= 100; set_mobility_weights(model); set_contact_matrix(model); @@ -102,22 +101,21 @@ void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) set_covid_parameters(parameters); mio::ContactMatrixGroup& commuting_strengths = - parameters.template get>().get_cont_freq_mat(); + parameters.template get>().get_cont_freq_mat(); auto& population_after_commuting = model.m_population_after_commuting; for (size_t region_n = 0; region_n < number_regions; ++region_n) { for (size_t age = 0; age < number_age_groups; ++age) { double population_n = 0; - for (size_t state = 0; state < (size_t)mio::oseirmobilityimproved::InfectionState::Count; state++) { - population_n += populations[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), - mio::oseirmobilityimproved::InfectionState(state)}]; + for (size_t state = 0; state < (size_t)mio::oseirmetapop::InfectionState::Count; state++) { + population_n += populations[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age), + mio::oseirmetapop::InfectionState(state)}]; } - population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += - population_n; + population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] += population_n; for (size_t region_m = 0; region_m < number_regions; ++region_m) { - population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= + population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] -= commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; - population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += + population_after_commuting[{mio::oseirmetapop::Region(region_m), mio::AgeGroup(age)}] += commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; } } @@ -135,7 +133,7 @@ void simulate(ScalarType tol, ScalarType tmax) number_age_groups = 6; } - mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); + mio::oseirmetapop::Model model(number_regions, number_age_groups); set_parameters_and_population(model); using DefaultIntegratorCore = mio::ControlledStepperWrapper; diff --git a/cpp/examples/examples_thesis/ode_metapop_timing.cpp b/cpp/examples/examples_thesis/ode_metapop_timing.cpp index f915dd9eb2..7d09b72721 100644 --- a/cpp/examples/examples_thesis/ode_metapop_timing.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_timing.cpp @@ -31,7 +31,7 @@ bool age_groups = false; template -void set_contact_matrix(mio::oseirmobilityimproved::Model& model) +void set_contact_matrix(mio::oseirmetapop::Model& model) { if (age_groups) { Eigen::MatrixXd contact_matrix_eigen(6, 6); @@ -39,12 +39,12 @@ void set_contact_matrix(mio::oseirmobilityimproved::Model& model) 0.0161, 0.246, 0.7124, 5.6518, 3.2939, 0.2043, 0.0109, 0.1742, 0.8897, 3.3124, 4.5406, 0.4262, 0.0214, 0.0458, 0.1939, 0.5782, 1.3825, 1.473, 0.0704, 0.1083, 0.1448, 0.4728, 0.9767, 0.6266, 0.1724; mio::ContactMatrixGroup& contact_matrix = - model.parameters.template get>().get_cont_freq_mat(); + model.parameters.template get>().get_cont_freq_mat(); contact_matrix[0].get_baseline() = contact_matrix_eigen; } { mio::ContactMatrixGroup& contact_matrix = - model.parameters.template get>().get_cont_freq_mat(); + model.parameters.template get>().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(7.95); } } @@ -55,33 +55,33 @@ void set_contact_matrix(mio::oseirmobilityimproved::Model& model) * @param params Object that the parameters will be added to. * @returns Currently generates no errors. */ -void set_covid_parameters(mio::oseirmobilityimproved::Parameters& params) +void set_covid_parameters(mio::oseirmetapop::Parameters& params) { - params.template set>(3.335); + params.template set>(3.335); if (age_groups) { - params.get>()[mio::AgeGroup(0)] = 8.0096875; - params.get>()[mio::AgeGroup(1)] = 8.0096875; - params.get>()[mio::AgeGroup(2)] = 8.2182; - params.get>()[mio::AgeGroup(3)] = 8.1158; - params.get>()[mio::AgeGroup(4)] = 8.033; - params.get>()[mio::AgeGroup(5)] = 7.985; - - params.get>()[mio::AgeGroup(0)] = 0.03; - params.get>()[mio::AgeGroup(1)] = 0.06; - params.get>()[mio::AgeGroup(2)] = 0.06; - params.get>()[mio::AgeGroup(3)] = 0.06; - params.get>()[mio::AgeGroup(4)] = 0.09; - params.get>()[mio::AgeGroup(5)] = 0.175; + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; } else { - params.get>()[mio::AgeGroup(0)] = 0.07333; - params.get>()[mio::AgeGroup(0)] = 8.097612257; + params.get>()[mio::AgeGroup(0)] = 0.07333; + params.get>()[mio::AgeGroup(0)] = 8.097612257; } } template -void set_mobility_weights(mio::oseirmobilityimproved::Model& model) +void set_mobility_weights(mio::oseirmetapop::Model& model) { size_t number_regions = (size_t)model.parameters.get_num_regions(); double fraction_commuter = 1. / (2 * number_regions); @@ -92,13 +92,12 @@ void set_mobility_weights(mio::oseirmobilityimproved::Model& model) for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); } - model.parameters.template get>() - .get_cont_freq_mat()[0] - .get_baseline() = mobility_data_commuter; + model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = + mobility_data_commuter; } template -void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) +void set_parameters_and_population(mio::oseirmetapop::Model& model) { auto& populations = model.populations; auto& parameters = model.parameters; @@ -107,14 +106,13 @@ void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) size_t number_age_groups = (size_t)parameters.get_num_agegroups(); for (size_t j = 0; j < number_age_groups; j++) { for (size_t i = 0; i < number_regions; i++) { - populations[{mio::oseirmobilityimproved::Region(i), mio::AgeGroup(j), - mio::oseirmobilityimproved::InfectionState::Susceptible}] = 60000; + populations[{mio::oseirmetapop::Region(i), mio::AgeGroup(j), + mio::oseirmetapop::InfectionState::Susceptible}] = 60000; } } - populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Exposed}] += 100; - populations[{mio::oseirmobilityimproved::Region(0), mio::AgeGroup(0), - mio::oseirmobilityimproved::InfectionState::Susceptible}] -= 100; + populations[{mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed}] += 100; + populations[{mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible}] -= + 100; set_mobility_weights(model); set_contact_matrix(model); @@ -122,22 +120,21 @@ void set_parameters_and_population(mio::oseirmobilityimproved::Model& model) set_covid_parameters(parameters); mio::ContactMatrixGroup& commuting_strengths = - parameters.template get>().get_cont_freq_mat(); + parameters.template get>().get_cont_freq_mat(); auto& population_after_commuting = model.m_population_after_commuting; for (size_t region_n = 0; region_n < number_regions; ++region_n) { for (size_t age = 0; age < number_age_groups; ++age) { double population_n = 0; - for (size_t state = 0; state < (size_t)mio::oseirmobilityimproved::InfectionState::Count; state++) { - population_n += populations[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age), - mio::oseirmobilityimproved::InfectionState(state)}]; + for (size_t state = 0; state < (size_t)mio::oseirmetapop::InfectionState::Count; state++) { + population_n += populations[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age), + mio::oseirmetapop::InfectionState(state)}]; } - population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] += - population_n; + population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] += population_n; for (size_t region_m = 0; region_m < number_regions; ++region_m) { - population_after_commuting[{mio::oseirmobilityimproved::Region(region_n), mio::AgeGroup(age)}] -= + population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] -= commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; - population_after_commuting[{mio::oseirmobilityimproved::Region(region_m), mio::AgeGroup(age)}] += + population_after_commuting[{mio::oseirmetapop::Region(region_m), mio::AgeGroup(age)}] += commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; } } @@ -154,7 +151,7 @@ void simulate(size_t num_warm_up_runs, size_t num_runs, size_t number_regions, S number_age_groups = 6; } - mio::oseirmobilityimproved::Model model(number_regions, number_age_groups); + mio::oseirmetapop::Model model(number_regions, number_age_groups); set_parameters_and_population(model); std::shared_ptr> integrator = std::make_shared>(); diff --git a/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp b/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp index 4802cb8852..a61a97b844 100644 --- a/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp @@ -18,22 +18,22 @@ * @param params Object that the parameters will be added to. * @returns Currently generates no errors. */ -mio::IOResult set_covid_parameters(mio::oseirmobility::Parameters& params) +mio::IOResult set_covid_parameters(mio::oseirmetapopwang::Parameters& params) { - params.template set>(3.335); - params.get>()[mio::AgeGroup(0)] = 8.0096875; - params.get>()[mio::AgeGroup(1)] = 8.0096875; - params.get>()[mio::AgeGroup(2)] = 8.2182; - params.get>()[mio::AgeGroup(3)] = 8.1158; - params.get>()[mio::AgeGroup(4)] = 8.033; - params.get>()[mio::AgeGroup(5)] = 7.985; - - params.get>()[mio::AgeGroup(0)] = 0.03; - params.get>()[mio::AgeGroup(1)] = 0.06; - params.get>()[mio::AgeGroup(2)] = 0.06; - params.get>()[mio::AgeGroup(3)] = 0.06; - params.get>()[mio::AgeGroup(4)] = 0.09; - params.get>()[mio::AgeGroup(5)] = 0.175; + params.template set>(3.335); + params.get>()[mio::AgeGroup(0)] = 8.0096875; + params.get>()[mio::AgeGroup(1)] = 8.0096875; + params.get>()[mio::AgeGroup(2)] = 8.2182; + params.get>()[mio::AgeGroup(3)] = 8.1158; + params.get>()[mio::AgeGroup(4)] = 8.033; + params.get>()[mio::AgeGroup(5)] = 7.985; + + params.get>()[mio::AgeGroup(0)] = 0.03; + params.get>()[mio::AgeGroup(1)] = 0.06; + params.get>()[mio::AgeGroup(2)] = 0.06; + params.get>()[mio::AgeGroup(3)] = 0.06; + params.get>()[mio::AgeGroup(4)] = 0.09; + params.get>()[mio::AgeGroup(5)] = 0.175; printf("Setting epidemiological parameters successful.\n"); return mio::success(); @@ -63,7 +63,7 @@ static const std::map contact_locations = {{Contac * @param params Object that the contact matrices will be added to. * @returns any io errors that happen during reading of the files. */ -mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseirmobility::Parameters& params) +mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseirmetapopwang::Parameters& params) { //TODO: io error handling auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_agegroups())); @@ -77,14 +77,15 @@ mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseirmob contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; } - params.get>() = mio::UncertainContactMatrix(contact_matrices); + params.get>() = + mio::UncertainContactMatrix(contact_matrices); printf("Setting contact matrices successful.\n"); return mio::success(); } template -mio::IOResult set_population_data(mio::oseirmobility::Model& model, const fs::path& data_dir) +mio::IOResult set_population_data(mio::oseirmetapopwang::Model& model, const fs::path& data_dir) { BOOST_OUTCOME_TRY( auto&& node_ids, @@ -105,8 +106,8 @@ mio::IOResult set_population_data(mio::oseirmobility::Model& model, co if (it != node_ids.end()) { auto region_idx = size_t(it - node_ids.begin()); for (size_t age = 0; age < (size_t)model.parameters.get_num_agegroups(); age++) { - model.populations[{mio::oseirmobility::Region(region_idx), mio::AgeGroup(age), - mio::oseirmobility::InfectionState::Susceptible}] = + model.populations[{mio::oseirmetapopwang::Region(region_idx), mio::AgeGroup(age), + mio::oseirmetapopwang::InfectionState::Susceptible}] = entry.population[mio::AgeGroup(age)]; } } @@ -117,11 +118,11 @@ mio::IOResult set_population_data(mio::oseirmobility::Model& model, co } template -mio::IOResult set_mobility_weights(mio::oseirmobility::Model& model, const fs::path& data_dir) +mio::IOResult set_mobility_weights(mio::oseirmetapopwang::Model& model, const fs::path& data_dir) { size_t number_regions = (size_t)model.parameters.get_num_regions(); if (number_regions == 1) { - model.parameters.template get>() + model.parameters.template get>() .get_cont_freq_mat()[0] .get_baseline() .setConstant(1.0); @@ -140,10 +141,10 @@ mio::IOResult set_mobility_weights(mio::oseirmobility::Model& model, c } for (size_t county_idx_i = 0; county_idx_i < number_regions; ++county_idx_i) { - auto population_i = model.populations.get_group_total(mio::oseirmobility::Region(county_idx_i)); + auto population_i = model.populations.get_group_total(mio::oseirmetapopwang::Region(county_idx_i)); mobility_data_commuter.row(county_idx_i) /= population_i; } - model.parameters.template get>() + model.parameters.template get>() .get_cont_freq_mat()[0] .get_baseline() = mobility_data_commuter; @@ -153,15 +154,16 @@ mio::IOResult set_mobility_weights(mio::oseirmobility::Model& model, c } template -mio::IOResult set_parameters_and_population(mio::oseirmobility::Model& model, const fs::path& data_dir) +mio::IOResult set_parameters_and_population(mio::oseirmetapopwang::Model& model, const fs::path& data_dir) { auto& populations = model.populations; auto& parameters = model.parameters; BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); - populations[{mio::oseirmobility::Region(27), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Susceptible}] -= - 100; - populations[{mio::oseirmobility::Region(27), mio::AgeGroup(0), mio::oseirmobility::InfectionState::Exposed}] += 100; + populations[{mio::oseirmetapopwang::Region(27), mio::AgeGroup(0), + mio::oseirmetapopwang::InfectionState::Susceptible}] -= 100; + populations[{mio::oseirmetapopwang::Region(27), mio::AgeGroup(0), + mio::oseirmetapopwang::InfectionState::Exposed}] += 100; BOOST_OUTCOME_TRY(set_mobility_weights(model, data_dir)); BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters)) @@ -184,13 +186,11 @@ int main() mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& data_dir = ""; + const std::string& data_dir = "/home/gers_ca/code/memilio/data"; - mio::oseirmobility::Model model(number_regions, number_age_groups); + mio::oseirmetapopwang::Model model(number_regions, number_age_groups); auto result_prepare_simulation = set_parameters_and_population(model, data_dir); - // std::shared_ptr> integrator = std::make_shared>(); - model.check_constraints(); auto result_from_sim = simulate(t0, tmax, dt, model); @@ -198,5 +198,5 @@ int main() auto result = mio::interpolate_simulation_result(result_from_sim); auto save_result_status = - mio::save_result({result}, {1}, number_regions * number_age_groups, "ode_result_paper_nrw_adaptive.h5"); + mio::save_result({result}, {1}, number_regions * number_age_groups, "ode_result_wang_nrw.h5"); } diff --git a/cpp/models/ode_metapop/infection_state.h b/cpp/models/ode_metapop/infection_state.h index 750a6415b7..03a2b70080 100644 --- a/cpp/models/ode_metapop/infection_state.h +++ b/cpp/models/ode_metapop/infection_state.h @@ -4,7 +4,7 @@ namespace mio { -namespace oseirmobilityimproved +namespace oseirmetapop { /** @@ -20,7 +20,7 @@ enum class InfectionState Count }; -} // namespace oseirmobilityimproved +} // namespace oseirmetapop } // namespace mio #endif // ODESEIR_INFECTIONSTATE_H diff --git a/cpp/models/ode_metapop/model.cpp b/cpp/models/ode_metapop/model.cpp index c92073842e..04ea73c6f3 100644 --- a/cpp/models/ode_metapop/model.cpp +++ b/cpp/models/ode_metapop/model.cpp @@ -3,8 +3,8 @@ namespace mio { -namespace oseirmobilityimproved +namespace oseirmetapop { -} // namespace oseirmobilityimproved +} // namespace oseirmetapop } // namespace mio diff --git a/cpp/models/ode_metapop/model.h b/cpp/models/ode_metapop/model.h index 39be459899..86a7bab73b 100644 --- a/cpp/models/ode_metapop/model.h +++ b/cpp/models/ode_metapop/model.h @@ -17,7 +17,7 @@ GCC_CLANG_DIAGNOSTIC(pop) namespace mio { -namespace oseirmobilityimproved +namespace oseirmetapop { /******************** @@ -206,9 +206,9 @@ class Model : public FlowModel m_population_after_commuting; -}; // namespace oseirmobilityimproved +}; // namespace oseirmetapop -} // namespace oseirmobilityimproved +} // namespace oseirmetapop } // namespace mio #endif // ODESEIRMOBILITY_MODEL_H diff --git a/cpp/models/ode_metapop/parameters.h b/cpp/models/ode_metapop/parameters.h index aa337acafb..3379e8c05e 100644 --- a/cpp/models/ode_metapop/parameters.h +++ b/cpp/models/ode_metapop/parameters.h @@ -14,7 +14,7 @@ namespace mio { -namespace oseirmobilityimproved +namespace oseirmetapop { /**************************************************** @@ -255,7 +255,7 @@ class Parameters : public ParametersBase AgeGroup m_num_agegroups; }; -} // namespace oseirmobilityimproved +} // namespace oseirmetapop } // namespace mio #endif // SEIR_PARAMETERS_H diff --git a/cpp/models/ode_metapop/regions.h b/cpp/models/ode_metapop/regions.h index d5f7657138..41f37337e2 100644 --- a/cpp/models/ode_metapop/regions.h +++ b/cpp/models/ode_metapop/regions.h @@ -6,7 +6,7 @@ namespace mio { -namespace oseirmobilityimproved +namespace oseirmetapop { /** @@ -20,7 +20,7 @@ struct Region : public Index { } }; -} // namespace oseirmobilityimproved +} // namespace oseirmetapop } // namespace mio #endif diff --git a/cpp/models/ode_metapop_wang/CMakeLists.txt b/cpp/models/ode_metapop_wang/CMakeLists.txt index ecf6e3112b..fefa3afae1 100644 --- a/cpp/models/ode_metapop_wang/CMakeLists.txt +++ b/cpp/models/ode_metapop_wang/CMakeLists.txt @@ -1,13 +1,13 @@ -add_library(ode_seir_mobility +add_library(ode_metapop_wang infection_state.h model.h model.cpp parameters.h regions.h ) -target_link_libraries(ode_seir_mobility PUBLIC memilio) -target_include_directories(ode_seir_mobility PUBLIC +target_link_libraries(ode_metapop_wang PUBLIC memilio) +target_include_directories(ode_metapop_wang PUBLIC $ $ ) -target_compile_options(ode_seir_mobility PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +target_compile_options(ode_metapop_wang PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_metapop_wang/infection_state.h b/cpp/models/ode_metapop_wang/infection_state.h index f4207708b3..9caf8c4d17 100644 --- a/cpp/models/ode_metapop_wang/infection_state.h +++ b/cpp/models/ode_metapop_wang/infection_state.h @@ -4,7 +4,7 @@ namespace mio { -namespace oseirmobility +namespace oseirmetapopwang { /** @@ -20,7 +20,7 @@ enum class InfectionState Count }; -} // namespace oseirmobility +} // namespace oseirmetapopwang } // namespace mio #endif // ODESEIR_INFECTIONSTATE_H diff --git a/cpp/models/ode_metapop_wang/model.cpp b/cpp/models/ode_metapop_wang/model.cpp index b8420ea023..3e93120de1 100644 --- a/cpp/models/ode_metapop_wang/model.cpp +++ b/cpp/models/ode_metapop_wang/model.cpp @@ -3,8 +3,8 @@ namespace mio { -namespace oseirmobility +namespace oseirmetapopwang { -} // namespace oseirmobility +} // namespace oseirmetapopwang } // namespace mio diff --git a/cpp/models/ode_metapop_wang/model.h b/cpp/models/ode_metapop_wang/model.h index 493a39e96a..fdb693d159 100644 --- a/cpp/models/ode_metapop_wang/model.h +++ b/cpp/models/ode_metapop_wang/model.h @@ -17,7 +17,7 @@ GCC_CLANG_DIAGNOSTIC(pop) namespace mio { -namespace oseirmobility +namespace oseirmetapopwang { /******************** @@ -210,7 +210,7 @@ class Model : public FlowModel AgeGroup m_num_agegroups; }; -} // namespace oseirmobility +} // namespace oseirmetapopwang } // namespace mio #endif // SEIR_PARAMETERS_H diff --git a/cpp/models/ode_metapop_wang/regions.h b/cpp/models/ode_metapop_wang/regions.h index 4a8352b11b..361217436d 100644 --- a/cpp/models/ode_metapop_wang/regions.h +++ b/cpp/models/ode_metapop_wang/regions.h @@ -6,7 +6,7 @@ namespace mio { -namespace oseirmobility +namespace oseirmetapopwang { /** @@ -20,7 +20,7 @@ struct Region : public Index { } }; -} // namespace oseirmobility +} // namespace oseirmetapopwang } // namespace mio #endif From 779583226fa189d45aa4f0fbbc3d33cd1464f052 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:24:05 +0100 Subject: [PATCH 68/87] small corrections --- cpp/examples/examples_thesis/graph_nrw.cpp | 2 +- cpp/examples/examples_thesis/ode_metapop_nrw.cpp | 4 +--- cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cpp/examples/examples_thesis/graph_nrw.cpp b/cpp/examples/examples_thesis/graph_nrw.cpp index 46dc1bd29f..fca1fb589f 100644 --- a/cpp/examples/examples_thesis/graph_nrw.cpp +++ b/cpp/examples/examples_thesis/graph_nrw.cpp @@ -198,7 +198,7 @@ int main() const auto tmax = 100.; const auto dt = 0.5; //time step of mobility, daily mobility every second step - const std::string& data_dir = "/home/gers_ca/code/memilio/data"; + const std::string& data_dir = ""; auto result = run(data_dir, t0, tmax, dt); diff --git a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp index f309cd9439..42187e7805 100644 --- a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp @@ -209,13 +209,11 @@ int main() mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& data_dir = "/home/gers_ca/code/memilio/data"; + const std::string& data_dir = ""; mio::oseirmetapop::Model model(number_regions, number_age_groups); auto result_prepare_simulation = set_parameters_and_population(model, data_dir); - // std::shared_ptr> integrator = std::make_shared>(); - model.check_constraints(); printf("Start Simulation\n"); diff --git a/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp b/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp index a61a97b844..62f200fcb8 100644 --- a/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp @@ -186,7 +186,7 @@ int main() mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& data_dir = "/home/gers_ca/code/memilio/data"; + const std::string& data_dir = ""; mio::oseirmetapopwang::Model model(number_regions, number_age_groups); auto result_prepare_simulation = set_parameters_and_population(model, data_dir); From 995f59bd43932e2bd612b287dee8ab313f021b8f Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 20:43:42 +0100 Subject: [PATCH 69/87] cleanup plot file results --- tools/plot_results_mobility.py | 159 +++++++++++++++++++++------------ 1 file changed, 101 insertions(+), 58 deletions(-) diff --git a/tools/plot_results_mobility.py b/tools/plot_results_mobility.py index f8121c5676..5c350225e6 100644 --- a/tools/plot_results_mobility.py +++ b/tools/plot_results_mobility.py @@ -35,7 +35,8 @@ def plot_map_nrw(data: pd.DataFrame, dpi: int = 300, outercolor='white', log_scale=False, - cmap='viridis'): + cmap='viridis', + fontsize=10): """! Plots region-specific information onto a interactive html map and returning svg and png image. Allows the comparisons of a variable list of data sets. @@ -134,25 +135,25 @@ def plot_map_nrw(data: pd.DataFrame, ax = fig.add_subplot(gs[1, i]) if log_scale: map_data.plot(data_columns[i], ax=ax, legend=False, - norm=norm, cmap=cmap) + norm=norm, cmap=cmap, edgecolor='black', linewidth=0.1) elif cax is not None: map_data.plot(data_columns[i], ax=ax, cax=cax, legend=True, - vmin=scale_colors[0], vmax=scale_colors[1], cmap=cmap) + vmin=scale_colors[0], vmax=scale_colors[1], cmap=cmap, edgecolor='black', linewidth=0.1) else: # Do not plot colorbar. map_data.plot(data_columns[i], ax=ax, legend=False, - vmin=scale_colors[0], vmax=scale_colors[1], cmap=cmap) + vmin=scale_colors[0], vmax=scale_colors[1], cmap=cmap, edgecolor='black', linewidth=0.1) - ax.set_title(legend[i], fontsize=9) + ax.set_title(legend[i], fontsize=fontsize) ax.set_axis_off() if plot_colorbar: sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) sm.set_array([]) cbar = fig.colorbar(sm, cax=cax) - # cbar.set_ticks([scale_colors[0], scale_colors[1]]) - # cbar.set_ticklabels([f'{scale_colors[0]:.3e}', f'{scale_colors[1]:.3e}'], fontsize=7) + cbar.set_ticks([scale_colors[0], scale_colors[1]]) + cbar.set_ticklabels([f'{scale_colors[0]:.3e}', f'{scale_colors[1]:.3e}'], fontsize=7) plt.subplots_adjust(bottom=0.1, left=0.1) plt.tight_layout() @@ -161,8 +162,17 @@ def plot_map_nrw(data: pd.DataFrame, def plot_maps(files, output_dir, legend, name=''): - min_val = 10e-6 - max_val = 0.4 + dfs = {} + min_vals = [] + max_vals = [] + + for date in range(10, 101, 20): + dfs[date] = extract_nrw_data_and_combine(files=files, date=date, relative=True) + min_vals.append(dfs[date].drop(columns='Region').min().min()) + max_vals.append(dfs[date].drop(columns='Region').max().max()) + + min_val = min(min_vals) + max_val = max(max_vals) cmap = 'viridis' norm = mcolors.LogNorm(vmin=min_val, vmax=max_val) @@ -170,26 +180,26 @@ def plot_maps(files, output_dir, legend, name=''): sm.set_array([]) cbar_fig, cax = plt.subplots(figsize=(12, 1)) cbar = plt.colorbar(sm, orientation='horizontal', cax=cax) - cbar.ax.tick_params(labelsize=10) - cbar.set_ticks([min_val, max_val]) - cbar.ax.xaxis.set_major_formatter(FormatStrFormatter('%.5f')) + cbar.ax.tick_params(labelsize=12) + # cbar.set_ticks([min_val, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, max_val]) + # cbar.ax.xaxis.set_major_formatter(FormatStrFormatter('%.5f')) + plt.tight_layout() plt.subplots_adjust(bottom=0.3) plt.savefig(os.path.join(output_dir, 'colorbar.png'), dpi=300) plt.close() for date in range(10, 101, 20): - dfs_all = extract_nrw_data_and_combine(files=files, date=date) - plot_map_nrw( - dfs_all, scale_colors=[min_val, max_val], + dfs[date], scale_colors=[min_val, max_val], legend=legend, title='NRW - Simulation Day '+str(date), plot_colorbar=False, output_path=output_dir, fig_name=name+str(date), dpi=900, outercolor='white', - log_scale=True) + log_scale=True, + fontsize=13) -def plot_difference_2D(files, output_dir): +def plot_difference(files, output_dir): fig = plt.figure() df_dif = pd.DataFrame(columns=['Time', 'difference', 'absolute value']) @@ -202,41 +212,76 @@ def plot_difference_2D(files, output_dir): for date in range(100): dfs_all = extract_nrw_data_and_combine(files=files, date=date, relative=False) df_dif.loc[date,'difference'] = (dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]]).sum() / total_population - df_dif.loc[date,'absolute value'] = abs(dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]]).sum() / total_population + df_dif.loc[date,'absolute value'] = (dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]]).abs().sum() / total_population - # df_dif.set_index('Time', inplace=True) - df_dif['difference'].plot(label='Difference') - df_dif['absolute value'].plot(label='Difference in absolute value') + df_dif['difference'].plot(label='Relative difference') + df_dif['absolute value'].plot(label='Relative difference in absolute value') + plt.xlim(left=0., right=101.) + plt.tight_layout() plt.legend() plt.grid(linestyle='--') plt.savefig(os.path.join(output_dir, 'difference2D.png')) plt.close() -def plot_difference(files, output_dir): - fig = plt.figure() +def plot_difference_maps(files, output_dir): + + df_dif1 = pd.DataFrame(columns=['Region']) + df_dif2 = pd.DataFrame(columns=['Region']) - df_dif = pd.DataFrame(columns=['Region']) + for date in range(10, 51, 10): + dfs_all = extract_nrw_data_and_combine(files=files, date=date, relative=True) + df_dif1['Region'] = dfs_all['Region'] + df_dif1['Count (rel)' + str(date)] = dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]] for date in range(60, 101, 10): dfs_all = extract_nrw_data_and_combine(files=files, date=date, relative=True) - df_dif['Region'] = dfs_all['Region'] - + df_dif2['Region'] = dfs_all['Region'] - df_dif['Count (rel)' + str(date)] = dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]] - - # df_dif = df_dif[df_dif['Count (rel)' + str(date)] > 0] - min_val = df_dif.drop(columns=['Region']).min().min() - max_val = df_dif.drop(columns=['Region']).max().max() + df_dif2['Count (rel)' + str(date)] = dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]] + + + min_val1 = df_dif1.drop(columns=['Region']).min().min() + max_val1 = df_dif1.drop(columns=['Region']).max().max() + min_val2 = df_dif2.drop(columns=['Region']).min().min() + max_val2 = df_dif2.drop(columns=['Region']).max().max() + min_val = min(min_val1, min_val2) + max_val = max(max_val1, max_val2) maximum_abs = abs(max([min_val, max_val], key=abs)) + cmap = 'seismic' + norm = mcolors.TwoSlopeNorm(vmin=-maximum_abs, vmax=maximum_abs, vcenter=0) + sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm) + sm.set_array([]) + cbar_fig, cax = plt.subplots(figsize=(12, 1)) + cbar = plt.colorbar(sm, orientation='horizontal', cax=cax) + ticks = np.linspace(-maximum_abs, maximum_abs, 10) + cbar.ax.tick_params(labelsize=13) + cbar.set_ticks(ticks) + cbar.ax.xaxis.set_major_formatter(FormatStrFormatter('%.3f')) + plt.tight_layout() + plt.subplots_adjust(bottom=0.3) + plt.savefig(os.path.join(output_dir, 'colorbar_difference.png'), dpi=900) + plt.close() + plot_map_nrw( - df_dif, scale_colors=[-maximum_abs, maximum_abs], + df_dif1, scale_colors=[-maximum_abs, maximum_abs], + legend=['Day ' + str(date) for date in range(10, 51, 10)], + title='', plot_colorbar=False, + output_path=output_dir, + fig_name="difference10-50", dpi=900, + outercolor='white', + log_scale=False, + cmap='seismic', + fontsize=17) + + plot_map_nrw( + df_dif2, scale_colors=[-maximum_abs, maximum_abs], legend=['Day ' + str(date) for date in range(60, 101, 10)], - title='Difference between ODE and graph-based model', plot_colorbar=True, + title='', plot_colorbar=False, output_path=output_dir, - fig_name="difference", dpi=900, + fig_name="difference60-100", dpi=900, outercolor='white', log_scale=False, cmap='seismic') @@ -249,7 +294,7 @@ def extract_nrw_data_and_combine(files, date, relative=True): i = 0 for file in files.values(): model_type = os.path.basename(file).split('_')[0] - if model_type == 'ode': # result file of equation-based model has to be first + if model_type == 'ode': df = pm.extract_data( file, region_spec=None, column=None, date=date, filters={'Group': filter_age, 'InfectionState': [2]}, @@ -319,22 +364,26 @@ def plot_total_compartment(files, output_dir, legend, compartment = 'Infected', dates = h5file['1']['Time'][:] data = h5file['1']['Total'][:,compartments[compartment]] ax.plot(dates, data, label=legend[file_idx], linewidth=2, color=colors[file_idx]) - ax.set_ylim(bottom=0.) + ax.set_title(compartment, fontsize=8) + # ax.set_ylim(bottom=0.) ax.set_xlim(left=0., right=dates.max()+1) else: df = pd.DataFrame() regions = list(h5file.keys()) + population=0 for i in range(len(regions)): + for comp in compartments.keys(): + population += h5file[regions[i]]['Total'][:, compartments[comp]] df['Region'+str(i)] = h5file[regions[i]]['Total'][:, compartments[compartment]] df['Total'] = df.sum(axis=1) df['Time'] = h5file[regions[0]]['Time'][:] # hardcoded - ax.plot(df['Time'], df['Total'], label=legend[file_idx], linewidth=1.2, color=colors[file_idx]) + ax.plot(df['Time'], df['Total'], label=legend[file_idx], linewidth=1.5, color=colors[file_idx], linestyle='--') + ax.set_title(compartment, fontsize=8) ax.set_ylim(bottom=0.) ax.set_xlim(left=0., right=df['Time'].max()+1) - # ax.legend() file_idx = file_idx+1 - + ax.tick_params(labelsize=7, ) plt.tight_layout() if print_legend: plt.legend() @@ -359,27 +408,21 @@ def compare_compartments(files, output_dir, legend): if __name__ == '__main__': - results_euler = {'Model B': 'cpp/build/ode_result_paper_nrw_euler', - 'Model C': 'cpp/build/ode_result_nrw_euler', - 'Model D': 'cpp/build/graph_result_nrw_euler'} - results_adaptive = {'Model B': 'cpp/build/ode_result_paper_nrw_adaptive', - 'Model C': 'cpp/build/ode_result_nrw_adaptive', - 'Model D': 'cpp/build/graph_result_nrw_adaptive'} - files_compare_solver = {'Data set 1': 'cpp/build/ode_result_nrw_euler', - 'Data set 2': 'cpp/build/ode_result_nrw_adaptive', - 'Data set 3': 'cpp/build/graph_result_nrw_euler', - 'Data set 4': 'cpp/build/graph_result_nrw_adaptive'} + results = {'Model B': 'results/ode_result_wang_nrw', + 'Model C': 'results/ode_result_nrw', + 'Model D': 'results/graph_result_nrw'} + file_format = 'h5' - models = ['Model B', - 'Model C', - 'Model D'] + models = ['Model B (ODE)', + 'Model C (ODE)', + 'Model D (Graph-ODE)'] plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') - plot_maps(files=results_adaptive, output_dir=plot_dir, legend=models, name='NRWAdaptiveDay') - # plot_difference_2D(files={key: value for key, value in results_adaptive.items() if key in { - # 'Model C', 'Model D'}}, output_dir=plot_dir) - compare_compartments(files=results_adaptive, output_dir=plot_dir, legend=models) - # plot_total_compartment(files=results_adaptive, output_dir=plot_dir, legend=models, - # compartment='Infected', name='infectives', title='Total infectives') + plot_maps(files=results, output_dir=plot_dir, legend=models, name='NRWAdaptiveDay') + plot_difference_maps(files={key: value for key, value in results.items() if key in { + 'Model C', 'Model D'}}, output_dir=plot_dir) + plot_difference(files={key: value for key, value in results.items() if key in { + 'Model C', 'Model D'}}, output_dir=plot_dir) + compare_compartments(files=results, output_dir=plot_dir, legend=models) From 32c74ad838804c3a1451a8a03afee58cdb03faf4 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 20:46:54 +0100 Subject: [PATCH 70/87] cleanup plot file runtimes --- tools/plot_mobility_runtimes.py | 127 ++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 29 deletions(-) diff --git a/tools/plot_mobility_runtimes.py b/tools/plot_mobility_runtimes.py index ba2f0f466e..cae92f1d19 100644 --- a/tools/plot_mobility_runtimes.py +++ b/tools/plot_mobility_runtimes.py @@ -9,7 +9,7 @@ fontsize_labels = 16 fontsize_legends = 12 -models = ['Equation-based model', 'Graph-based model'] +models = ['Model C (ODE)', 'Model D (Graph-ODE)'] def plot_runtime(file, name=''): fig = plt.figure() @@ -36,21 +36,21 @@ def plot_flops(name='number_flops'): fig, ax = plt.subplots() def flops_equation_based(x, eta): - return (4*x**2+22*x+1)/eta + return (4*x**2+22*x)/eta def flops_graph_based(x, eta): - return (43*x**2+24*x/eta+2)*1 + return (43*x**2+23*x/eta) x = np.linspace(0, 400, 80) for idx, eta in enumerate([0.05, 0.1, 0.2, 0.5]): - ax.plot(x, flops_equation_based(x, eta), linewidth=1.5, color=colors[0], linestyle=linestyles[idx], label='Model C, $\eta=$'+ str(eta)) - ax.plot(x, flops_graph_based(x, eta), linewidth=1.5, color=colors[1], linestyle=linestyles[idx], label='Model D, $\eta=$'+ str(eta)) + ax.plot(x, flops_equation_based(x, eta), linewidth=1.5, linestyle=linestyles[idx], color=colors[0], label=models[0]+', $h=$'+ str(eta)) + ax.plot(x, flops_graph_based(x, eta), linewidth=1.5, linestyle=linestyles[idx], color=colors[1], label=models[1]+', $h=$'+ str(eta)) ax.set_ylim(bottom=0.) ax.set_xlim(left=0., right=400.) ax.set_xlabel('Number of regions', fontsize=fontsize_labels) - ax.set_ylabel('Number of FLOPs', fontsize=fontsize_labels) + ax.set_ylabel('Number of FLOP', fontsize=fontsize_labels) handles, labels = ax.get_legend_handles_labels() sorted_handles_labels = sorted(zip(handles, labels), key=lambda x: x[1]) @@ -65,16 +65,15 @@ def flops_graph_based(x, eta): plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) plt.close() - - def compare_runtime_and_flops(files, name=''): fig, ax1 = plt.subplots() + plt.grid(True, linestyle='--') - for file in files: + for idx, file in enumerate(files): df = pd.read_json(file) ax1.plot(df["Regions"], df["Time"], - linestyle='--', marker='o', linewidth=1.2, label=file) + linestyle='--', marker='o', linewidth=1.2, label=models[idx]) ax1.set_ylim(bottom=0.) ax1.set_xlim(left=0., right=400.) @@ -84,19 +83,26 @@ def compare_runtime_and_flops(files, name=''): ax2 = ax1.twinx() def flops_equation_based(x): - return (4*x**2+22*x+1)*200 + return (4*x**2+22*x)*200 def flops_graph_based(x): - return (43*x**2+240*x+2)*20 + return (43*x**2+230*x)*20 x = np.linspace(0, 400, 400) - ax2.plot(x, flops_equation_based(x), linestyle='--', linewidth=1.2) - ax2.plot(x, flops_graph_based(x), linestyle='--', linewidth=1.2) - ax2.set_ylabel('Number of FLOPs', fontsize=fontsize_labels) + ax2.plot(x, flops_equation_based(x), linewidth=2, color='darkblue', label='FLOP Model C') + ax2.plot(x, flops_graph_based(x), linewidth=2, color='#e02313', label='FLOP Model D') + ax2.set_ylabel('Number of FLOP', fontsize=fontsize_labels) ax2.set_ylim(bottom=0.) + handles1, labels1 = ax1.get_legend_handles_labels() + handles2, labels2 = ax2.get_legend_handles_labels() + + handles = handles1 + handles2 + labels = labels1 + labels2 + plt.tight_layout() + fig.legend(handles, labels, loc='upper left', bbox_to_anchor=(0.125, 0.925), ncols=2) plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) @@ -108,7 +114,6 @@ def compare_runtimes(files, name='', title='', models=[]): for file in files: df = pd.read_json(file) df = df.filter(items=['Regions', 'Time']) - # df.drop(thisFilter, inplace=True, axis=1) df.rename(columns={'Time': models[i]}, inplace=True) if merged_df.empty: @@ -119,8 +124,6 @@ def compare_runtimes(files, name='', title='', models=[]): merged_df = merged_df.set_index('Regions') for column in merged_df.columns: - # plt.plot(merged_df['Regions'], column, - # linestyle='--', marker='o', linewidth=1.2) plt.plot(merged_df.index, merged_df[column], label=column, linestyle='--', marker='o', linewidth=1.2) plt.ylim(bottom=0.) @@ -130,7 +133,67 @@ def compare_runtimes(files, name='', title='', models=[]): plt.yticks(fontsize=fontsize_legends) plt.xticks(fontsize=fontsize_legends) plt.grid(True, linestyle='--') - plt.legend() + plt.legend(fontsize=fontsize_legends) + plt.title(title) + plt.tight_layout() + + plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') + plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) + plt.close() + +def plot_steps(files, name='', models=[]): + for idx, file in enumerate(files): + df = pd.read_json(file) + df.set_index('Absolute tolerance', inplace=True) + model_type = os.path.basename(file).split('_')[0] + if model_type == 'ode': + plt.plot(df, label=models[idx], color=colors[idx]) + else: + plt.plot(df['Steps Hotspot'], color=colors[idx], label=models[idx]) + plt.plot(df['Steps other Regions'], color=colors[idx]) + plt.fill_between(df.index, df['Steps Hotspot'], df['Steps other Regions'], color=colors[idx], alpha=0.15) + + plt.ylim(bottom=10.) + plt.xlim(left=df.index.min()/1.2, right=df.index.max()*1.2) + plt.yticks(fontsize=fontsize_legends) + plt.xticks(df.index, fontsize=fontsize_legends) + + plt.xscale('log') + plt.gca().invert_xaxis() + plt.ylabel('Number of steps', fontsize=fontsize_labels) + plt.xlabel('Absolute tolerance', fontsize=fontsize_labels) + plt.grid(True, linestyle='--') + plt.legend(fontsize=fontsize_legends) + + plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') + plt.savefig(os.path.join(plot_dir, 'compare_steps.png'), bbox_inches='tight', dpi=500) + plt.close() + +def plot_quotient(files, name='', title='', models=[]): + merged_df = pd.DataFrame() + i = 0 + for file in files: + df = pd.read_json(file) + df = df.filter(items=['Regions', 'Time']) + df.rename(columns={'Time': models[i]}, inplace=True) + + if merged_df.empty: + merged_df = df + else: + merged_df = pd.merge(merged_df, df, on='Regions', how='outer') + i = i+1 + + merged_df = merged_df.set_index('Regions') + plt.plot(merged_df.index, merged_df[models[1]]/merged_df[models[0]], label='Quotient', + linestyle='--', marker='o', linewidth=1.2) + plt.ylim(bottom=0.) + plt.xlim(left=merged_df.index.min()-1, right=merged_df.index.max()+1) + plt.xlabel('Number of regions', fontsize=fontsize_labels) + plt.ylabel('Run time [seconds]', fontsize=fontsize_labels) + plt.yticks(fontsize=fontsize_legends) + plt.xticks(fontsize=fontsize_legends) + plt.grid(True, linestyle='--') + plt.legend(fontsize=fontsize_legends) plt.title(title) plt.tight_layout() @@ -141,15 +204,21 @@ def compare_runtimes(files, name='', title='', models=[]): if __name__ == "__main__": result_dir = os.path.join(os.path.dirname(__file__), '../results') - result_equationbased_euler = os.path.join(result_dir, 'timing_equationbased_euler.json') - result_equationbased_noage_euler = os.path.join(result_dir, 'timing_equationbased_noage_euler.json') - result_graphbased_euler = os.path.join(result_dir, 'timing_graphbased_euler.json') - result_graphbased_noage_euler = os.path.join(result_dir, 'timing_graphbased_noage_euler.json') + ode_timing_euler = os.path.join(result_dir, 'ode_timing_euler.json') + ode_timing_noage_euler = os.path.join(result_dir, 'ode_timing_noage_euler.json') + graphbased_timing_euler = os.path.join(result_dir, 'graphbased_timing_euler.json') + graphbased_timing_noage_euler = os.path.join(result_dir, 'graphbased_timing_noage_euler.json') + + ode_steps = os.path.join(result_dir, 'ode_steps.json') + graphbased_steps = os.path.join(result_dir, 'graphbased_steps.json') - results_euler = [result_equationbased_euler, result_graphbased_euler] - results_euler_noage = [result_equationbased_noage_euler, result_graphbased_noage_euler] + timings_euler = [ode_timing_euler, graphbased_timing_euler] + timings_euler_noage = [ode_timing_noage_euler, graphbased_timing_noage_euler] - # compare_runtimes(results_euler, name='compare_runtimes_euler', models=models) - # compare_runtimes(results_euler_noage, name='compare_runtimes_euler_noage', models=models) - # compare_runtime_and_flops(results_euler_noage, 'compare_runtimes_and_flops') - plot_flops() + compare_runtimes(timings_euler, name='compare_runtimes_euler', models=models) + compare_runtimes(timings_euler_noage, name='compare_runtimes_euler_noage', models=models) + plot_quotient(timings_euler, name='quotient', title='Quotient', models=models) + plot_quotient(timings_euler_noage, name='quotient_noage', title='Quotient', models=models) + compare_runtime_and_flops(timings_euler_noage, 'compare_runtimes_and_flops') + plot_flops('number_flops') + plot_steps([ode_steps, graphbased_steps], models=models) From 629e8869933ccc654c30696328aa944f395f6c7b Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:23:02 +0100 Subject: [PATCH 71/87] change colors in plots --- tools/plot_mobility_runtimes.py | 2 +- tools/plot_results_mobility.py | 12 +- tools/plot_results_mobilitymodels.py | 205 --------------------------- 3 files changed, 7 insertions(+), 212 deletions(-) delete mode 100644 tools/plot_results_mobilitymodels.py diff --git a/tools/plot_mobility_runtimes.py b/tools/plot_mobility_runtimes.py index cae92f1d19..a773e26479 100644 --- a/tools/plot_mobility_runtimes.py +++ b/tools/plot_mobility_runtimes.py @@ -91,7 +91,7 @@ def flops_graph_based(x): x = np.linspace(0, 400, 400) ax2.plot(x, flops_equation_based(x), linewidth=2, color='darkblue', label='FLOP Model C') - ax2.plot(x, flops_graph_based(x), linewidth=2, color='#e02313', label='FLOP Model D') + ax2.plot(x, flops_graph_based(x), linewidth=2, color='#9C180D', label='FLOP Model D') ax2.set_ylabel('Number of FLOP', fontsize=fontsize_labels) ax2.set_ylim(bottom=0.) diff --git a/tools/plot_results_mobility.py b/tools/plot_results_mobility.py index 5c350225e6..d4f3f6266c 100644 --- a/tools/plot_results_mobility.py +++ b/tools/plot_results_mobility.py @@ -351,7 +351,7 @@ def extract_nrw_data_and_combine(files, date, relative=True): def plot_total_compartment(files, output_dir, legend, compartment = 'Infected', name='', ax=None, print_legend=True): - colors = ['#1f77b4', '#2ca02c', '#ff7f0e'] + colors = ['#2ca02c', '#ff7f0e', '#9C180D'] file_idx = 0 if ax is None: fig, ax = plt.subplots() @@ -420,9 +420,9 @@ def compare_compartments(files, output_dir, legend): plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') - plot_maps(files=results, output_dir=plot_dir, legend=models, name='NRWAdaptiveDay') - plot_difference_maps(files={key: value for key, value in results.items() if key in { - 'Model C', 'Model D'}}, output_dir=plot_dir) - plot_difference(files={key: value for key, value in results.items() if key in { - 'Model C', 'Model D'}}, output_dir=plot_dir) + # plot_maps(files=results, output_dir=plot_dir, legend=models, name='NRWAdaptiveDay') + # plot_difference_maps(files={key: value for key, value in results.items() if key in { + # 'Model C', 'Model D'}}, output_dir=plot_dir) + # plot_difference(files={key: value for key, value in results.items() if key in { + # 'Model C', 'Model D'}}, output_dir=plot_dir) compare_compartments(files=results, output_dir=plot_dir, legend=models) diff --git a/tools/plot_results_mobilitymodels.py b/tools/plot_results_mobilitymodels.py deleted file mode 100644 index 0426ca7747..0000000000 --- a/tools/plot_results_mobilitymodels.py +++ /dev/null @@ -1,205 +0,0 @@ -import h5py -import os -import matplotlib.pyplot as plt - -import memilio.epidata.getDataIntoPandasDataFrame as gd - -# Define compartments. -secir_dict = {0: 'Susceptible', 1: 'Exposed', 2: 'Infected', 3: 'Recovered'} - -# Define color and style to be used while plotting for different models to -# make plots consistent. -color_dict = {0: '#1f77b4', - 1: '#2ca02c' - } -linestyle_dict = {"ODE SI": 'dashed', - "ODE Improved": 'dotted', - "Graph": 'dashdot' - } - - -def compare_all_compartments( - files, - legendplot, - filename_plot="compare_compartments"): - - fig, axs = plt.subplots( - 2, 2, sharex='all', num=filename_plot, tight_layout=False) - - # Add simulation results to plot. - for file in range(len(files)): - # Load data. - h5file = h5py.File(str(files[file]) + '.h5', 'r') - - number_regions = len(list(h5file.keys())) - for region in range(number_regions): - if (len(list(h5file[list(h5file.keys())[region]].keys())) > 3): - data = h5file[list(h5file.keys())[region]] - dates = data['Time'][:] - - number_regions = len( - list(h5file[list(h5file.keys())[region]].keys())) - 2 - for region in range(number_regions): - total = data['Group' + str(region + 1)][:, :] - if (total.shape[1] != 4): - raise gd.DataError( - "Expected a different number of compartments.") - # Plot result. - if legendplot[file] in linestyle_dict: - for i in range(4): - axs[int(i / 2), - i % 2].plot(dates, - total[:, - i], - label=legendplot[file] + - " Region " + str(region), - linewidth=1.2, - linestyle=linestyle_dict[legendplot[file]], - color=color_dict[region]) - else: - for i in range(4): - axs[int(i / 2), i % 2].plot(dates, total[:, i], - label=legendplot[file], linewidth=1.2) - else: - data = h5file[list(h5file.keys())[region]] - dates = data['Time'][:] - # As there should be only one Group, total is the simulation - # result. - total = data['Total'][:, :] - if (total.shape[1] != 4): - raise gd.DataError( - "Expected a different number of compartments.") - # Plot result. - if legendplot[file] in linestyle_dict: - for i in range(4): - axs[int(i / 2), - i % 2].plot(dates, - total[:, - i], - label=legendplot[file] + - " Region " + str(region), - linewidth=1.2, - linestyle=linestyle_dict[legendplot[file]], - color=color_dict[region]) - else: - for i in range(4): - axs[int(i / 2), i % 2].plot(dates, total[:, i], - label=legendplot[file], linewidth=1.2) - h5file.close() - - # Define some characteristics of the plot. - for i in range(4): - axs[int(i / 2), i % 2].set_title(secir_dict[i], fontsize=8) - axs[int(i / 2), i % 2].set_xlim(left=0, right=dates[-1]) - axs[int(i / 2), i % 2].grid(True, linestyle='--') - axs[int(i / 2), i % 2].tick_params(axis='y', labelsize=7) - axs[int(i / 2), i % 2].tick_params(axis='x', labelsize=7) - # axs[int(i/2), i % 2].xaxis.set_ticks(np.arange(0, dates[-1]+1, 5)) - - fig.supxlabel('Time (in days)', fontsize=9) - - lines, labels = axs[0, 0].get_legend_handles_labels() - lgd = fig.legend(lines, labels, ncol=len(legendplot), loc='outside lower center', - fontsize=10, bbox_to_anchor=(0.5, - 0.06), bbox_transform=fig.transFigure) - - plt.tight_layout(pad=0, w_pad=0.5, h_pad=0.1) - plt.subplots_adjust(bottom=0.09) - - # Save result. - if not os.path.isdir('Plots'): - os.makedirs('Plots') - fig.savefig('Plots/' + filename_plot + '.png', - bbox_extra_artists=(lgd,), bbox_inches='tight', dpi=500) - - -def plot_new_infections( - files, - ylim, - legendplot, - filename_plot="compare_new_infections"): - - plt.figure(filename_plot) - - # Add simulation results to plot. - for file in range(len(files)): - # Load data. - h5file = h5py.File(str(files[file]) + '.h5', 'r') - - number_regions = len(list(h5file.keys())) - for region in range(number_regions): - if (len(list(h5file[list(h5file.keys())[region]].keys())) > 3): - data = h5file[list(h5file.keys())[region]] - dates = data['Time'][:] - - number_regions = len( - list(h5file[list(h5file.keys())[region]].keys())) - 2 - for region_ in range(number_regions): - total = data['Group' + str(region_ + 1)][:, :] - if (total.shape[1] != 4): - raise gd.DataError( - "Expected a different number of compartments.") - incidence = (total[:-1, 0] - total[1:, 0] - ) / (dates[1:] - dates[:-1]) - # Plot result. - if legendplot[file] in linestyle_dict: - plt.plot(dates[1:], - incidence, - linewidth=1.2, - linestyle=linestyle_dict[legendplot[file]], - color=color_dict[region_]) - else: - plt.plot(dates[1:], incidence, linewidth=1.2) - else: - data = h5file[list(h5file.keys())[region]] - dates = data['Time'][:] - # As there should be only one Group, total is the simulation - # result. - total = data['Total'][:, :] - if (total.shape[1] != 4): - raise gd.DataError( - "Expected a different number of compartments.") - incidence = (total[:-1, 0] - total[1:, 0]) / \ - (dates[1:] - dates[:-1]) - # Plot result. - if legendplot[file] in linestyle_dict: - plt.plot(dates[1:], - incidence, - linewidth=1.2, - linestyle=linestyle_dict[legendplot[file]], - color=color_dict[region]) - else: - plt.plot(dates[1:], incidence, linewidth=1.2) - - h5file.close() - - plt.xlabel('Time (in days)', fontsize=16) - # plt.xticks(np.arange(0, dates[-1]+1, 5)) - plt.yticks(fontsize=9) - plt.ylabel('New infections per day', fontsize=14) - plt.ylim(bottom=0, top=ylim) - plt.xlim(left=0, right=dates[-1]) - plt.legend(legendplot, fontsize=14, framealpha=0.5) - plt.grid(True, linestyle='--') - plt.tight_layout() - - # Save result. - if not os.path.isdir('Plots'): - os.makedirs('Plots') - plt.savefig( - 'Plots/' + - filename_plot + - '.png', - bbox_inches='tight', - dpi=500) - - -if __name__ == '__main__': - data_dir = os.path.join(os.path.dirname(__file__), "..", "cpp", "build") - plot_new_infections([os.path.join(data_dir, "ode_result_standard"), - os.path.join(data_dir, "ode_result_improved"), - os.path.join(data_dir, "graph_result")], - 2e3, legendplot=list(["ODE SI", "ODE Improved", "Graph"])) - compare_all_compartments([os.path.join(data_dir, "ode_result_standard"), - os.path.join(data_dir, "ode_result_improved"), - os.path.join(data_dir, "graph_result")], - legendplot=list(["ODE SI", "ODE Improved", "Graph"])) From c61dac5f6c0db1437e66b195b9d7b2f9c172a6ac Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:26:03 +0100 Subject: [PATCH 72/87] add shellscripts for runtimes and steps --- shellscripts/steps_mobilitymodels.sh | 20 ++++++++++++++++++++ shellscripts/timing_mobilitymodels.sh | 27 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 shellscripts/steps_mobilitymodels.sh create mode 100644 shellscripts/timing_mobilitymodels.sh diff --git a/shellscripts/steps_mobilitymodels.sh b/shellscripts/steps_mobilitymodels.sh new file mode 100644 index 0000000000..c2c6d80d1f --- /dev/null +++ b/shellscripts/steps_mobilitymodels.sh @@ -0,0 +1,20 @@ +#!/bin/sh +#SBATCH -N 1 +#SBATCH -n 1 +#SBATCH -c 1 +#SBATCH --exclusive +#SBATCH -t 5-0:00:00 +#SBATCH --output=steps_equationbased-%A.out +#SBATCH --error=steps_equationbased-%A.err +#SBATCH --exclude="be-cpu05, be-gpu01" +#SBATCH --job-name=steps_mobilitymodels + +echo Running $1 on node $SLURM_JOB_NODELIST. +cd ../cpp/build +cmake -DCMAKE_BUILD_TYPE="Release" -DMEMILIO_ENABLE_OPENMP=ON .. +cmake --build . --target $1 + +for i in $(seq 2 12) +do + srun --cpu-bind=core --cpus-per-task=1 ./bin/$1 1e-$i +done \ No newline at end of file diff --git a/shellscripts/timing_mobilitymodels.sh b/shellscripts/timing_mobilitymodels.sh new file mode 100644 index 0000000000..a0d28bb84e --- /dev/null +++ b/shellscripts/timing_mobilitymodels.sh @@ -0,0 +1,27 @@ +#!/bin/bash +#SBATCH -N 1 +#SBATCH -n 1 +#SBATCH -c 1 +#SBATCH --exclusive +#SBATCH -t 5-0:00:00 +#SBATCH --output=timing_equationbased_noage_euler-%A.out +#SBATCH --error=timing_equationbased_noage_euler-%A.err +#SBATCH --exclude="be-cpu05, be-gpu01" +#SBATCH --job-name=timing_mobilitymodels + +warm_up_runs=10 +runs=100 + +echo Running $1 on node $SLURM_JOB_NODELIST with $warm_up_runs warm up runs and $runs runs. +cd ../cpp/build +rm -rf CMakeCache.txt CMakeFiles/ +cmake -DCMAKE_BUILD_TYPE="Release" -DMEMILIO_ENABLE_OPENMP=ON .. +cmake --build . --target $1 +for i in $(seq 1 1 4) +do + srun --cpu-bind=core --cpus-per-task=1 ./bin/$1 $warm_up_runs $runs $i +done +for i in $(seq 300 5 350) +do + srun --cpu-bind=core --cpus-per-task=1 ./bin/$1 $warm_up_runs $runs $i +done From 6e56e39bea8fac9a5b0e5f16a07c397d87bbaea1 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:39:16 +0100 Subject: [PATCH 73/87] delete redundant plot --- tools/plot_mobility_runtimes.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/tools/plot_mobility_runtimes.py b/tools/plot_mobility_runtimes.py index a773e26479..df0bc87aa9 100644 --- a/tools/plot_mobility_runtimes.py +++ b/tools/plot_mobility_runtimes.py @@ -11,27 +11,6 @@ models = ['Model C (ODE)', 'Model D (Graph-ODE)'] -def plot_runtime(file, name=''): - fig = plt.figure() - df = pd.read_json(file) - - plt.plot(df["Regions"], df["Time"], - linestyle='--', marker='o', linewidth=1.2) - plt.ylim(bottom=df['Time'].min()) - plt.xlim(left=df["Regions"].min()-1, right=df["Regions"].max()+1) - plt.xlabel('Number of regions', fontsize=fontsize_labels) - plt.ylabel('Run time [seconds]', fontsize=fontsize_labels) - plt.yticks(fontsize=fontsize_legends) - plt.xticks(fontsize=fontsize_legends) - plt.grid(True, linestyle='--') - plt.tight_layout() - - plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') - if name is None: - name = os.path.splitext(os.path.basename(file))[0] - plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) - plt.close() - def plot_flops(name='number_flops'): fig, ax = plt.subplots() From d84d5a361c6204a5a136b44c57e37429c787138a Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 10 Mar 2025 14:50:24 +0100 Subject: [PATCH 74/87] optimizations ode model --- cpp/models/ode_metapop/model.h | 34 +++++++++++++++-------------- cpp/models/ode_metapop/parameters.h | 32 +++++++++++++-------------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/cpp/models/ode_metapop/model.h b/cpp/models/ode_metapop/model.h index 86a7bab73b..d4e1490578 100644 --- a/cpp/models/ode_metapop/model.h +++ b/cpp/models/ode_metapop/model.h @@ -53,27 +53,29 @@ class Model : public FlowModelparameters; const auto& population = this->populations; - const auto& commuting_strengths = + const Eigen::MatrixXd commuting_strengths = params.template get>().get_cont_freq_mat().get_matrix_at(t); - const Index n_age_groups = reduce_index>(params.get_num_agegroups()); - const Index n_regions = reduce_index>(params.get_num_regions()); - - Eigen::MatrixXd infectious_share_per_region = Eigen::MatrixXd::Zero((size_t)n_regions, (size_t)n_age_groups); - for (size_t age_i = 0; age_i < (size_t)n_age_groups; age_i++) { - for (size_t region_n = 0; region_n < (size_t)n_regions; region_n++) { - for (size_t region_m = 0; region_m < (size_t)n_regions; region_m++) { - infectious_share_per_region(region_n, age_i) += - commuting_strengths(region_m, region_n) * - pop[population.get_flat_index({Region(region_m), AgeGroup(age_i), InfectionState::Infected})]; - } + const size_t n_age_groups = (size_t)params.get_num_agegroups(); + const size_t n_regions = (size_t)params.get_num_regions(); + + Eigen::MatrixXd infected_pop(n_regions, n_age_groups); + for (size_t region_n = 0; region_n < n_regions; region_n++) { + for (size_t age_i = 0; age_i < n_age_groups; age_i++) { + infected_pop(region_n, age_i) = + pop[population.get_flat_index({Region(region_n), AgeGroup(age_i), InfectionState::Infected})]; + } + } + Eigen::MatrixXd infectious_share_per_region = commuting_strengths.transpose() * infected_pop; + for (size_t region_n = 0; region_n < n_regions; region_n++) { + for (size_t age_i = 0; age_i < n_age_groups; age_i++) { infectious_share_per_region(region_n, age_i) /= m_population_after_commuting[{Region(region_n), AgeGroup(age_i)}]; } } Eigen::MatrixXd infections_due_commuting = commuting_strengths * infectious_share_per_region; - for (size_t age_i = 0; age_i < (size_t)n_age_groups; age_i++) { - for (size_t age_j = 0; age_j < (size_t)n_age_groups; age_j++) { - for (size_t region_n = 0; region_n < (size_t)n_regions; region_n++) { + for (size_t age_i = 0; age_i < n_age_groups; age_i++) { + for (size_t age_j = 0; age_j < n_age_groups; age_j++) { + for (size_t region_n = 0; region_n < n_regions; region_n++) { const size_t Ejn = population.get_flat_index({Region(region_n), AgeGroup(age_j), InfectionState::Exposed}); const size_t Ijn = @@ -95,7 +97,7 @@ class Model : public FlowModel( {Region(region), AgeGroup(age_i)})] = y[population.get_flat_index({Region(region), AgeGroup(age_i), InfectionState::Exposed})] / diff --git a/cpp/models/ode_metapop/parameters.h b/cpp/models/ode_metapop/parameters.h index 3379e8c05e..82e97f486e 100644 --- a/cpp/models/ode_metapop/parameters.h +++ b/cpp/models/ode_metapop/parameters.h @@ -101,25 +101,25 @@ struct CommutingStrengths { } }; -/** - * @brief The sizes of the populations after commuting. - */ -template -struct PopulationSizes { - using Type = CustomIndexArray; - static Type get_default(Region size, AgeGroup) - { - return Type(size, 0.); - } - static std::string name() - { - return "PopulationSizes"; - } -}; +// /** +// * @brief The infectious time in day unit. +// */ +// template +// struct PopulationAfterCommuting { +// using Type = CustomIndexArray; +// static Type get_default(Region size_region, AgeGroup size_agegroups) +// { +// return Type({size_region, size_agegroups}, 0.); +// } +// static std::string name() +// { +// return "TimeInfected"; +// } +// }; template using ParametersBase = ParameterSet, TimeExposed, TimeInfected, - ContactPatterns, CommutingStrengths, PopulationSizes>; + ContactPatterns, CommutingStrengths>; /** * @brief Parameters of SEIR model. From a5540f9444c947966d0674a80ea54bb1700fcb6c Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Thu, 27 Mar 2025 10:27:50 +0100 Subject: [PATCH 75/87] remove old examples --- cpp/examples/graph.cpp | 36 ++----- cpp/examples/likwid_test.cpp | 20 ---- cpp/examples/ode_seir.cpp | 187 +++++------------------------------ 3 files changed, 30 insertions(+), 213 deletions(-) delete mode 100644 cpp/examples/likwid_test.cpp diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index b060e1bcb2..7f8a7db4fd 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -22,12 +22,11 @@ #include "ode_seir/parameters.h" #include "memilio/mobility/metapopulation_mobility_instant.h" #include "memilio/compartments/simulation.h" -#include "memilio/io/result_io.h" int main() { const auto t0 = 0.; - const auto tmax = 15.; + const auto tmax = 10.; const auto dt = 0.5; //time step of mobility, daily mobility every second step mio::oseir::Model<> model(1); @@ -35,11 +34,9 @@ int main() // set population model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 10000; - model.parameters.set>(1.); - // set transition times - model.parameters.set>(3.); - model.parameters.set>(5.); + model.parameters.set>(1); + model.parameters.set>(1); // set contact matrix mio::ContactMatrixGroup& contact_matrix = model.parameters.get>().get_cont_freq_mat(); @@ -49,10 +46,10 @@ int main() auto model_group1 = model; auto model_group2 = model; - //some contact restrictions in group 1 - // mio::ContactMatrixGroup& contact_matrix1 = - // model_group1.parameters.get>().get_cont_freq_mat(); - // contact_matrix1[0].add_damping(0.5, mio::SimulationTime(5)); + // some contact restrictions in group 1 + mio::ContactMatrixGroup& contact_matrix1 = + model_group1.parameters.get>().get_cont_freq_mat(); + contact_matrix1[0].add_damping(0.5, mio::SimulationTime(5)); //infection starts in group 1 model_group1.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 9990; @@ -61,29 +58,12 @@ int main() mio::Graph>>, mio::MobilityEdge<>> g; g.add_node(1001, model_group1, t0); g.add_node(1002, model_group2, t0); - for (auto& node : g.nodes()) { - node.property.get_simulation().set_integrator(std::make_shared>()); - } - g.add_edge(0, 1, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.05)); + g.add_edge(0, 1, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.01)); g.add_edge(1, 0, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.01)); auto sim = mio::make_mobility_sim(t0, dt, std::move(g)); sim.advance(tmax); - auto result_graph = std::move(sim).get_graph(); - auto result = mio::interpolate_simulation_result(result_graph); - - std::vector county_ids(result_graph.nodes().size()); - std::transform(result_graph.nodes().begin(), result_graph.nodes().end(), county_ids.begin(), [](auto& n) { - return n.id; - }); - - auto save_result_status = save_result(result, county_ids, 1, "graph_result.h5"); - - for (auto&& node : result_graph.nodes()) { - node.property.get_result().print_table(); - } - return 0; } diff --git a/cpp/examples/likwid_test.cpp b/cpp/examples/likwid_test.cpp deleted file mode 100644 index d2f26a0b56..0000000000 --- a/cpp/examples/likwid_test.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include - -double work(double* a, size_t n) { - double s = 0; - for (size_t j=0; j set_covid_parameters(mio::oseir::Parameters& params, bool synthetic_population) -{ - params.template set>(3.335); - if (!synthetic_population) { - params.get>()[mio::AgeGroup(0)] = 8.0096875; - params.get>()[mio::AgeGroup(1)] = 8.0096875; - params.get>()[mio::AgeGroup(2)] = 8.2182; - params.get>()[mio::AgeGroup(3)] = 8.1158; - params.get>()[mio::AgeGroup(4)] = 8.033; - params.get>()[mio::AgeGroup(5)] = 7.985; - - params.get>()[mio::AgeGroup(0)] = 0.03; - params.get>()[mio::AgeGroup(1)] = 0.06; - params.get>()[mio::AgeGroup(2)] = 0.06; - params.get>()[mio::AgeGroup(3)] = 0.06; - params.get>()[mio::AgeGroup(4)] = 0.09; - params.get>()[mio::AgeGroup(5)] = 0.175; - } - else { - params.template set>(8.097612257); - - params.template set>(0.07333); - } - - printf("Setting epidemiological parameters successful.\n"); - return mio::success(); -} - -/** - * indices of contact matrix corresponding to locations where contacts occur. - */ -enum class ContactLocation -{ - Home = 0, - School, - Work, - Other, - Count, -}; - -static const std::map contact_locations = {{ContactLocation::Home, "home"}, - {ContactLocation::School, "school_pf_eig"}, - {ContactLocation::Work, "work"}, - {ContactLocation::Other, "other"}}; - -/** - * Set contact matrices. - * Reads contact matrices from files in the data directory. - * @param data_dir data directory. - * @param params Object that the contact matrices will be added to. - * @returns any io errors that happen during reading of the files. - */ -mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseir::Parameters& params, - bool synthetic_population) -{ - if (!synthetic_population) { - //TODO: io error handling - auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_groups())); - for (auto&& contact_location : contact_locations) { - BOOST_OUTCOME_TRY(auto&& baseline, - mio::read_mobility_plain( - (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); - BOOST_OUTCOME_TRY(auto&& minimum, - mio::read_mobility_plain( - (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); - contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; - contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; - } - params.get>() = mio::UncertainContactMatrix(contact_matrices); - } - else { - mio::ContactMatrixGroup& contact_matrix = params.get>().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(7.95 / (size_t)params.get_num_groups()); - } - - printf("Setting contact matrices successful.\n"); - return mio::success(); -} - -template -mio::IOResult set_population_data(mio::oseir::Model& model, const fs::path& data_dir) -{ - BOOST_OUTCOME_TRY( - auto&& node_ids, - mio::get_node_ids((data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true, - true)); - - BOOST_OUTCOME_TRY(const auto&& population_data, - mio::read_population_data( - (data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true)); - - for (auto&& entry : population_data) { - auto it = std::find_if(node_ids.begin(), node_ids.end(), [&entry](auto r) { - return r == 0 || - (entry.county_id && mio::regions::StateId(r) == mio::regions::get_state_id(int(*entry.county_id))) || - (entry.county_id && mio::regions::CountyId(r) == *entry.county_id) || - (entry.district_id && mio::regions::DistrictId(r) == *entry.district_id); - }); - if (it != node_ids.end()) { - for (size_t age = 0; age < (size_t)model.parameters.get_num_groups(); age++) { - model.populations[{mio::AgeGroup(age), mio::oseir::InfectionState::Susceptible}] += - entry.population[mio::AgeGroup(age)]; - } - } - } - - printf("Setting population data successful.\n"); - return mio::success(); -} -template -mio::IOResult set_parameters_and_population(mio::oseir::Model& model, const fs::path& data_dir, - bool synthetic_population) -{ - auto& populations = model.populations; - auto& parameters = model.parameters; - - size_t number_age_groups = (size_t)parameters.get_num_groups(); - - if (synthetic_population) { - printf("Data is not compatible, using synthetic population instead.\n"); - for (size_t j = 0; j < number_age_groups; j++) { - model.populations[{mio::AgeGroup(j), mio::oseir::InfectionState::Exposed}] = 100; - model.populations[{mio::AgeGroup(j), mio::oseir::InfectionState::Susceptible}] = 999900; - } - } - else { - BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); - populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; - populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; - } - - BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters, synthetic_population)) - - BOOST_OUTCOME_TRY(set_covid_parameters(parameters, synthetic_population)); - - return mio::success(); -} int main() { mio::set_log_level(mio::LogLevel::debug); - ScalarType t0 = 0.; + ScalarType t0 = 0; ScalarType tmax = 50.; - ScalarType dt = 0.1; - - ScalarType number_age_groups = 6; - bool synthetic_population = false; - if (number_age_groups != 6) { - synthetic_population = true; - } + ScalarType dt = 1.0; mio::log_info("Simulating ODE SEIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& data_dir = ""; + mio::oseir::Model model(1); + + ScalarType total_population = 10000; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] = 100; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Infected}] = 100; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Recovered}] = 100; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = + total_population - model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] - + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Infected}] - + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Recovered}]; - mio::oseir::Model model(number_age_groups); - auto result_prepare_simulation = set_parameters_and_population(model, data_dir, synthetic_population); + model.parameters.set>(5.2); + model.parameters.set>(6); + model.parameters.set>(0.1); - std::shared_ptr> integrator = std::make_shared>(); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get>(); + contact_matrix[0].get_baseline().setConstant(2.7); + contact_matrix[0].add_damping(0.7, mio::SimulationTime(30.)); - auto seir = simulate(t0, tmax, dt, model, integrator); + model.check_constraints(); - auto reproduction_numbers = model.get_reproduction_numbers(seir); - std::cout << "\nbasis reproduction number: " << reproduction_numbers[0] << "\n"; + auto seir = simulate(t0, tmax, dt, model); - // seir.print_table({"S", "E", "I", "R"}); - // std::cout << "\nnumber total: " << seir.get_last_value().sum() << "\n"; + seir.print_table({"S", "E", "I", "R"}); + std::cout << "\nnumber total: " << seir.get_last_value().sum() << "\n"; } From 1291acdb23a1da67aedd705d43d02838a52cac8b Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Fri, 28 Mar 2025 16:10:41 +0100 Subject: [PATCH 76/87] format python file --- .../memilio/epidata/getNRWCounties.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pycode/memilio-epidata/memilio/epidata/getNRWCounties.py b/pycode/memilio-epidata/memilio/epidata/getNRWCounties.py index a2c04550df..0f737f89dc 100644 --- a/pycode/memilio-epidata/memilio/epidata/getNRWCounties.py +++ b/pycode/memilio-epidata/memilio/epidata/getNRWCounties.py @@ -6,6 +6,7 @@ from memilio.epidata import geoModificationGermany as geoger from memilio.epidata import getDataIntoPandasDataFrame as gd + def main(): """! Main program entry.""" @@ -26,7 +27,7 @@ def main(): stateIDs = geoger.get_state_ids() # get state ID to county ID map stateID_to_countyID = geoger.get_stateid_to_countyids_map() - + # iterate over state_to_county map and replace IDs by numbering 0, ..., n state_indices = [] county_indices = [] @@ -34,19 +35,19 @@ def main(): state_indices.append(stateIDs.index(state)) county_indices.append( np.array([countyIDs.index(county) for county in counties])) - - mobility_matrix_nrw = mobility_matrix.loc[county_indices[4], county_indices[4]] + + mobility_matrix_nrw = mobility_matrix.loc[county_indices[4], + county_indices[4]] gd.write_dataframe( mobility_matrix_nrw, directory_mobility, mobility_file + '_nrw', 'txt', param_dict={'sep': ' ', 'header': None, 'index': False}) - - population = pd.read_json(os.path.join(directory_population + population_file + '.json')) - population_nrw = population.loc[county_indices[4]] - gd.write_dataframe(population_nrw, directory_population, population_file + '_nrw', 'json') - - + population = pd.read_json(os.path.join( + directory_population + population_file + '.json')) + population_nrw = population.loc[county_indices[4]] + gd.write_dataframe(population_nrw, directory_population, + population_file + '_nrw', 'json') if __name__ == "__main__": From d4e93418cb64d697af2c1e587232b4055b7aa61d Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Fri, 28 Mar 2025 16:12:53 +0100 Subject: [PATCH 77/87] format more python files --- tools/plot_mobility_runtimes.py | 107 ++++++++++++------- tools/plot_results_mobility.py | 182 ++++++++++++++++++++------------ 2 files changed, 182 insertions(+), 107 deletions(-) diff --git a/tools/plot_mobility_runtimes.py b/tools/plot_mobility_runtimes.py index df0bc87aa9..dce00b1ff0 100644 --- a/tools/plot_mobility_runtimes.py +++ b/tools/plot_mobility_runtimes.py @@ -5,27 +5,35 @@ import os colors = ['#1f77b4', '#2ca02c', '#ff7f0e'] -linestyles=['-', '--', '-.', ':'] +linestyles = ['-', '--', '-.', ':'] fontsize_labels = 16 fontsize_legends = 12 models = ['Model C (ODE)', 'Model D (Graph-ODE)'] + def plot_flops(name='number_flops'): fig, ax = plt.subplots() def flops_equation_based(x, eta): - return (4*x**2+22*x)/eta - + return (4*x**2+22*x)/eta + def flops_graph_based(x, eta): - return (43*x**2+23*x/eta) - + return (43*x**2+23*x/eta) + x = np.linspace(0, 400, 80) - for idx, eta in enumerate([0.05, 0.1, 0.2, 0.5]): - ax.plot(x, flops_equation_based(x, eta), linewidth=1.5, linestyle=linestyles[idx], color=colors[0], label=models[0]+', $h=$'+ str(eta)) - ax.plot(x, flops_graph_based(x, eta), linewidth=1.5, linestyle=linestyles[idx], color=colors[1], label=models[1]+', $h=$'+ str(eta)) + ax.plot( + x, flops_equation_based(x, eta), + linewidth=1.5, linestyle=linestyles[idx], + color=colors[0], + label=models[0] + ', $h=$' + str(eta)) + ax.plot( + x, flops_graph_based(x, eta), + linewidth=1.5, linestyle=linestyles[idx], + color=colors[1], + label=models[1] + ', $h=$' + str(eta)) ax.set_ylim(bottom=0.) ax.set_xlim(left=0., right=400.) ax.set_xlabel('Number of regions', fontsize=fontsize_labels) @@ -44,15 +52,16 @@ def flops_graph_based(x, eta): plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) plt.close() + def compare_runtime_and_flops(files, name=''): - fig, ax1 = plt.subplots() + fig, ax1 = plt.subplots() plt.grid(True, linestyle='--') - + for idx, file in enumerate(files): df = pd.read_json(file) ax1.plot(df["Regions"], df["Time"], - linestyle='--', marker='o', linewidth=1.2, label=models[idx]) + linestyle='--', marker='o', linewidth=1.2, label=models[idx]) ax1.set_ylim(bottom=0.) ax1.set_xlim(left=0., right=400.) @@ -62,15 +71,17 @@ def compare_runtime_and_flops(files, name=''): ax2 = ax1.twinx() def flops_equation_based(x): - return (4*x**2+22*x)*200 - + return (4*x**2+22*x)*200 + def flops_graph_based(x): - return (43*x**2+230*x)*20 - + return (43*x**2+230*x)*20 + x = np.linspace(0, 400, 400) - - ax2.plot(x, flops_equation_based(x), linewidth=2, color='darkblue', label='FLOP Model C') - ax2.plot(x, flops_graph_based(x), linewidth=2, color='#9C180D', label='FLOP Model D') + + ax2.plot(x, flops_equation_based(x), linewidth=2, + color='darkblue', label='FLOP Model C') + ax2.plot(x, flops_graph_based(x), linewidth=2, + color='#9C180D', label='FLOP Model D') ax2.set_ylabel('Number of FLOP', fontsize=fontsize_labels) ax2.set_ylim(bottom=0.) @@ -81,12 +92,14 @@ def flops_graph_based(x): labels = labels1 + labels2 plt.tight_layout() - fig.legend(handles, labels, loc='upper left', bbox_to_anchor=(0.125, 0.925), ncols=2) + fig.legend(handles, labels, loc='upper left', + bbox_to_anchor=(0.125, 0.925), ncols=2) plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) plt.close() - + + def compare_runtimes(files, name='', title='', models=[]): merged_df = pd.DataFrame() i = 0 @@ -104,7 +117,7 @@ def compare_runtimes(files, name='', title='', models=[]): merged_df = merged_df.set_index('Regions') for column in merged_df.columns: plt.plot(merged_df.index, merged_df[column], label=column, - linestyle='--', marker='o', linewidth=1.2) + linestyle='--', marker='o', linewidth=1.2) plt.ylim(bottom=0.) plt.xlim(left=merged_df.index.min()-1, right=merged_df.index.max()+1) plt.xlabel('Number of regions', fontsize=fontsize_labels) @@ -120,18 +133,23 @@ def compare_runtimes(files, name='', title='', models=[]): plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) plt.close() + def plot_steps(files, name='', models=[]): for idx, file in enumerate(files): df = pd.read_json(file) df.set_index('Absolute tolerance', inplace=True) model_type = os.path.basename(file).split('_')[0] - if model_type == 'ode': + if model_type == 'ode': plt.plot(df, label=models[idx], color=colors[idx]) else: plt.plot(df['Steps Hotspot'], color=colors[idx], label=models[idx]) plt.plot(df['Steps other Regions'], color=colors[idx]) - plt.fill_between(df.index, df['Steps Hotspot'], df['Steps other Regions'], color=colors[idx], alpha=0.15) - + plt.fill_between( + df.index, df['Steps Hotspot'], + df['Steps other Regions'], + color=colors[idx], + alpha=0.15) + plt.ylim(bottom=10.) plt.xlim(left=df.index.min()/1.2, right=df.index.max()*1.2) plt.yticks(fontsize=fontsize_legends) @@ -145,9 +163,12 @@ def plot_steps(files, name='', models=[]): plt.legend(fontsize=fontsize_legends) plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') - plt.savefig(os.path.join(plot_dir, 'compare_steps.png'), bbox_inches='tight', dpi=500) + plt.savefig( + os.path.join(plot_dir, 'compare_steps.png'), + bbox_inches='tight', dpi=500) plt.close() + def plot_quotient(files, name='', title='', models=[]): merged_df = pd.DataFrame() i = 0 @@ -163,8 +184,9 @@ def plot_quotient(files, name='', title='', models=[]): i = i+1 merged_df = merged_df.set_index('Regions') - plt.plot(merged_df.index, merged_df[models[1]]/merged_df[models[0]], label='Quotient', - linestyle='--', marker='o', linewidth=1.2) + plt.plot( + merged_df.index, merged_df[models[1]] / merged_df[models[0]], + label='Quotient', linestyle='--', marker='o', linewidth=1.2) plt.ylim(bottom=0.) plt.xlim(left=merged_df.index.min()-1, right=merged_df.index.max()+1) plt.xlabel('Number of regions', fontsize=fontsize_labels) @@ -180,24 +202,35 @@ def plot_quotient(files, name='', title='', models=[]): plt.savefig(os.path.join(plot_dir, name), bbox_inches='tight', dpi=500) plt.close() + if __name__ == "__main__": result_dir = os.path.join(os.path.dirname(__file__), '../results') ode_timing_euler = os.path.join(result_dir, 'ode_timing_euler.json') - ode_timing_noage_euler = os.path.join(result_dir, 'ode_timing_noage_euler.json') - graphbased_timing_euler = os.path.join(result_dir, 'graphbased_timing_euler.json') - graphbased_timing_noage_euler = os.path.join(result_dir, 'graphbased_timing_noage_euler.json') + ode_timing_noage_euler = os.path.join( + result_dir, 'ode_timing_noage_euler.json') + graphbased_timing_euler = os.path.join( + result_dir, 'graphbased_timing_euler.json') + graphbased_timing_noage_euler = os.path.join( + result_dir, 'graphbased_timing_noage_euler.json') ode_steps = os.path.join(result_dir, 'ode_steps.json') graphbased_steps = os.path.join(result_dir, 'graphbased_steps.json') timings_euler = [ode_timing_euler, graphbased_timing_euler] - timings_euler_noage = [ode_timing_noage_euler, graphbased_timing_noage_euler] - - compare_runtimes(timings_euler, name='compare_runtimes_euler', models=models) - compare_runtimes(timings_euler_noage, name='compare_runtimes_euler_noage', models=models) - plot_quotient(timings_euler, name='quotient', title='Quotient', models=models) - plot_quotient(timings_euler_noage, name='quotient_noage', title='Quotient', models=models) - compare_runtime_and_flops(timings_euler_noage, 'compare_runtimes_and_flops') + timings_euler_noage = [ode_timing_noage_euler, + graphbased_timing_noage_euler] + + compare_runtimes( + timings_euler, name='compare_runtimes_euler', models=models) + compare_runtimes( + timings_euler_noage, name='compare_runtimes_euler_noage', + models=models) + plot_quotient(timings_euler, name='quotient', + title='Quotient', models=models) + plot_quotient(timings_euler_noage, name='quotient_noage', + title='Quotient', models=models) + compare_runtime_and_flops( + timings_euler_noage, 'compare_runtimes_and_flops') plot_flops('number_flops') plot_steps([ode_steps, graphbased_steps], models=models) diff --git a/tools/plot_results_mobility.py b/tools/plot_results_mobility.py index d4f3f6266c..43e1909f8b 100644 --- a/tools/plot_results_mobility.py +++ b/tools/plot_results_mobility.py @@ -26,17 +26,17 @@ def plot_map_nrw(data: pd.DataFrame, - scale_colors: np.array([0, 1]), - legend: list = [], - title: str = '', - plot_colorbar: bool = True, - output_path: str = '', - fig_name: str = 'customPlot', - dpi: int = 300, - outercolor='white', - log_scale=False, - cmap='viridis', - fontsize=10): + scale_colors: np.array([0, 1]), + legend: list = [], + title: str = '', + plot_colorbar: bool = True, + output_path: str = '', + fig_name: str = 'customPlot', + dpi: int = 300, + outercolor='white', + log_scale=False, + cmap='viridis', + fontsize=10): """! Plots region-specific information onto a interactive html map and returning svg and png image. Allows the comparisons of a variable list of data sets. @@ -85,7 +85,7 @@ def plot_map_nrw(data: pd.DataFrame, data['new_index'] = map_data.index.array data = data.set_index('new_index') - map_data[data_columns] = data.loc[:, data_columns] + map_data[data_columns] = data.loc[:, data_columns] for i in range(len(data_columns)): if legend[i] == '': @@ -95,7 +95,8 @@ def plot_map_nrw(data: pd.DataFrame, pm.save_interactive(data[data_columns[i]], os.path.join( output_path, fname) + '.html', map_data, scale_colors) - fig = plt.figure(figsize=(3.5 * len(data_columns), 3), facecolor=outercolor) + fig = plt.figure(figsize=(3.5 * len(data_columns), 3), + facecolor=outercolor) # Use n+2 many columns (1: legend + 2: empty space + 3-n: data sets) and # n+2 rows where the top row is used for a potential title, the second row # for the content and all other rows have height zero. @@ -103,16 +104,16 @@ def plot_map_nrw(data: pd.DataFrame, # if len(data_columns) > 1: # height_ratios = height_ratios + [ # 0.0 for i in range(len(data_columns)-1)] - if plot_colorbar: + if plot_colorbar: gs = GridSpec( - 2, len(data_columns)+2, figure=fig, - width_ratios=[1 for i in range(len(data_columns))]+[0.1, 0.2], - height_ratios=height_ratios) + 2, len(data_columns)+2, figure=fig, + width_ratios=[1 for i in range(len(data_columns))]+[0.1, 0.2], + height_ratios=height_ratios) else: gs = GridSpec( - 2, len(data_columns), figure=fig, - width_ratios=[1 for i in range(len(data_columns))], - height_ratios=height_ratios) + 2, len(data_columns), figure=fig, + width_ratios=[1 for i in range(len(data_columns))], + height_ratios=height_ratios) # Use top row for title. tax = fig.add_subplot(gs[0, :]) @@ -128,22 +129,33 @@ def plot_map_nrw(data: pd.DataFrame, if log_scale: norm = mcolors.LogNorm(vmin=scale_colors[0], vmax=scale_colors[1]) else: - norm = mcolors.TwoSlopeNorm(vmin=scale_colors[0], vmax=scale_colors[1], vcenter=0) + norm = mcolors.TwoSlopeNorm( + vmin=scale_colors[0], + vmax=scale_colors[1], + vcenter=0) for i in range(len(data_columns)): ax = fig.add_subplot(gs[1, i]) if log_scale: - map_data.plot(data_columns[i], ax=ax, legend=False, - norm=norm, cmap=cmap, edgecolor='black', linewidth=0.1) + map_data.plot( + data_columns[i], + ax=ax, legend=False, norm=norm, cmap=cmap, edgecolor='black', + linewidth=0.1) elif cax is not None: - map_data.plot(data_columns[i], ax=ax, cax=cax, legend=True, - vmin=scale_colors[0], vmax=scale_colors[1], cmap=cmap, edgecolor='black', linewidth=0.1) + map_data.plot( + data_columns[i], + ax=ax, cax=cax, legend=True, vmin=scale_colors[0], + vmax=scale_colors[1], + cmap=cmap, edgecolor='black', linewidth=0.1) else: # Do not plot colorbar. - map_data.plot(data_columns[i], ax=ax, legend=False, - vmin=scale_colors[0], vmax=scale_colors[1], cmap=cmap, edgecolor='black', linewidth=0.1) + map_data.plot( + data_columns[i], + ax=ax, legend=False, vmin=scale_colors[0], + vmax=scale_colors[1], + cmap=cmap, edgecolor='black', linewidth=0.1) ax.set_title(legend[i], fontsize=fontsize) ax.set_axis_off() @@ -153,13 +165,16 @@ def plot_map_nrw(data: pd.DataFrame, sm.set_array([]) cbar = fig.colorbar(sm, cax=cax) cbar.set_ticks([scale_colors[0], scale_colors[1]]) - cbar.set_ticklabels([f'{scale_colors[0]:.3e}', f'{scale_colors[1]:.3e}'], fontsize=7) + cbar.set_ticklabels( + [f'{scale_colors[0]:.3e}', f'{scale_colors[1]:.3e}'], + fontsize=7) plt.subplots_adjust(bottom=0.1, left=0.1) plt.tight_layout() plt.savefig(os.path.join(output_path, fig_name + '.png'), dpi=dpi) plt.close() + def plot_maps(files, output_dir, legend, name=''): dfs = {} @@ -167,7 +182,8 @@ def plot_maps(files, output_dir, legend, name=''): max_vals = [] for date in range(10, 101, 20): - dfs[date] = extract_nrw_data_and_combine(files=files, date=date, relative=True) + dfs[date] = extract_nrw_data_and_combine( + files=files, date=date, relative=True) min_vals.append(dfs[date].drop(columns='Region').min().min()) max_vals.append(dfs[date].drop(columns='Region').max().max()) @@ -195,10 +211,11 @@ def plot_maps(files, output_dir, legend, name=''): title='NRW - Simulation Day '+str(date), plot_colorbar=False, output_path=output_dir, fig_name=name+str(date), dpi=900, - outercolor='white', - log_scale=True, + outercolor='white', + log_scale=True, fontsize=13) - + + def plot_difference(files, output_dir): fig = plt.figure() @@ -210,12 +227,16 @@ def plot_difference(files, output_dir): total_population = 18190422. for date in range(100): - dfs_all = extract_nrw_data_and_combine(files=files, date=date, relative=False) - df_dif.loc[date,'difference'] = (dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]]).sum() / total_population - df_dif.loc[date,'absolute value'] = (dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]]).abs().sum() / total_population - + dfs_all = extract_nrw_data_and_combine( + files=files, date=date, relative=False) + df_dif.loc[date, 'difference'] = ( + dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]]).sum() / total_population + df_dif.loc[date, 'absolute value'] = ( + dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]]).abs().sum() / total_population + df_dif['difference'].plot(label='Relative difference') - df_dif['absolute value'].plot(label='Relative difference in absolute value') + df_dif['absolute value'].plot( + label='Relative difference in absolute value') plt.xlim(left=0., right=101.) plt.tight_layout() plt.legend() @@ -223,24 +244,26 @@ def plot_difference(files, output_dir): plt.savefig(os.path.join(output_dir, 'difference2D.png')) plt.close() - + def plot_difference_maps(files, output_dir): df_dif1 = pd.DataFrame(columns=['Region']) df_dif2 = pd.DataFrame(columns=['Region']) for date in range(10, 51, 10): - dfs_all = extract_nrw_data_and_combine(files=files, date=date, relative=True) + dfs_all = extract_nrw_data_and_combine( + files=files, date=date, relative=True) df_dif1['Region'] = dfs_all['Region'] - df_dif1['Count (rel)' + str(date)] = dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]] + df_dif1['Count (rel)' + str(date)] = dfs_all[dfs_all.columns[1] + ] - dfs_all[dfs_all.columns[2]] for date in range(60, 101, 10): - dfs_all = extract_nrw_data_and_combine(files=files, date=date, relative=True) + dfs_all = extract_nrw_data_and_combine( + files=files, date=date, relative=True) df_dif2['Region'] = dfs_all['Region'] - - df_dif2['Count (rel)' + str(date)] = dfs_all[dfs_all.columns[1]] - dfs_all[dfs_all.columns[2]] - + df_dif2['Count (rel)' + str(date)] = dfs_all[dfs_all.columns[1] + ] - dfs_all[dfs_all.columns[2]] min_val1 = df_dif1.drop(columns=['Region']).min().min() max_val1 = df_dif1.drop(columns=['Region']).max().max() @@ -271,21 +294,22 @@ def plot_difference_maps(files, output_dir): title='', plot_colorbar=False, output_path=output_dir, fig_name="difference10-50", dpi=900, - outercolor='white', + outercolor='white', log_scale=False, - cmap='seismic', + cmap='seismic', fontsize=17) - + plot_map_nrw( df_dif2, scale_colors=[-maximum_abs, maximum_abs], legend=['Day ' + str(date) for date in range(60, 101, 10)], title='', plot_colorbar=False, output_path=output_dir, fig_name="difference60-100", dpi=900, - outercolor='white', + outercolor='white', log_scale=False, cmap='seismic') - + + def extract_nrw_data_and_combine(files, date, relative=True): age_groups = {0: '0-4', 1: '5-14', 2: '15-34', 3: '35-59', 4: '60-79', 5: '80+'} @@ -294,7 +318,7 @@ def extract_nrw_data_and_combine(files, date, relative=True): i = 0 for file in files.values(): model_type = os.path.basename(file).split('_')[0] - if model_type == 'ode': + if model_type == 'ode': df = pm.extract_data( file, region_spec=None, column=None, date=date, filters={'Group': filter_age, 'InfectionState': [2]}, @@ -310,7 +334,8 @@ def extract_nrw_data_and_combine(files, date, relative=True): ids = [id for id in ids if str(id).startswith('5')] if len(ids) != len(df): - raise gd.DataError("Data is not compatible with number of NRW counties.") + raise gd.DataError( + "Data is not compatible with number of NRW counties.") df['Region'] = ids else: @@ -318,7 +343,7 @@ def extract_nrw_data_and_combine(files, date, relative=True): file, region_spec=None, column=None, date=date, filters={'Group': filter_age, 'InfectionState': [2]}, file_format=file_format) - + df = df.apply(pd.to_numeric, errors='coerce') if relative: @@ -346,10 +371,12 @@ def extract_nrw_data_and_combine(files, date, relative=True): dfs_all[df.columns[-1] + ' ' + str(i)] = df[df.columns[-1]] i += 1 - return dfs_all - + return dfs_all -def plot_total_compartment(files, output_dir, legend, compartment = 'Infected', name='', ax=None, print_legend=True): + +def plot_total_compartment( + files, output_dir, legend, compartment='Infected', name='', ax=None, + print_legend=True): colors = ['#2ca02c', '#ff7f0e', '#9C180D'] file_idx = 0 @@ -360,24 +387,33 @@ def plot_total_compartment(files, output_dir, legend, compartment = 'Infected', model_type = os.path.basename(file).split('_')[0] # Load data. h5file = h5py.File(file + '.h5', 'r') - if model_type=='ode': + if model_type == 'ode': dates = h5file['1']['Time'][:] - data = h5file['1']['Total'][:,compartments[compartment]] - ax.plot(dates, data, label=legend[file_idx], linewidth=2, color=colors[file_idx]) + data = h5file['1']['Total'][:, compartments[compartment]] + ax.plot( + dates, data, label=legend[file_idx], + linewidth=2, color=colors[file_idx]) ax.set_title(compartment, fontsize=8) # ax.set_ylim(bottom=0.) ax.set_xlim(left=0., right=dates.max()+1) else: df = pd.DataFrame() regions = list(h5file.keys()) - population=0 + population = 0 for i in range(len(regions)): for comp in compartments.keys(): - population += h5file[regions[i]]['Total'][:, compartments[comp]] - df['Region'+str(i)] = h5file[regions[i]]['Total'][:, compartments[compartment]] + population += h5file[regions[i] + ]['Total'][:, compartments[comp]] + df['Region'+str(i)] = h5file[regions[i] + ]['Total'][:, compartments[compartment]] df['Total'] = df.sum(axis=1) - df['Time'] = h5file[regions[0]]['Time'][:] # hardcoded - ax.plot(df['Time'], df['Total'], label=legend[file_idx], linewidth=1.5, color=colors[file_idx], linestyle='--') + df['Time'] = h5file[regions[0]]['Time'][:] # hardcoded + ax.plot( + df['Time'], + df['Total'], + label=legend[file_idx], + linewidth=1.5, color=colors[file_idx], + linestyle='--') ax.set_title(compartment, fontsize=8) ax.set_ylim(bottom=0.) ax.set_xlim(left=0., right=df['Time'].max()+1) @@ -386,31 +422,37 @@ def plot_total_compartment(files, output_dir, legend, compartment = 'Infected', ax.tick_params(labelsize=7, ) plt.tight_layout() if print_legend: - plt.legend() + plt.legend() plt.savefig(os.path.join(output_dir, name + '.png'), dpi=300) return ax + def compare_compartments(files, output_dir, legend): fig, axs = plt.subplots( 2, 2, sharex='all') axs = axs.flatten() for i, compartment in enumerate(compartments.keys()): - plot_total_compartment(files=files, output_dir=output_dir, legend=legend, compartment=compartment, ax=axs[i], print_legend=False) + plot_total_compartment( + files=files, output_dir=output_dir, legend=legend, + compartment=compartment, ax=axs[i], + print_legend=False) plt.tight_layout() plt.subplots_adjust(bottom=0.15) lines, labels = axs[0].get_legend_handles_labels() fig.legend(lines, labels, ncol=len(models), loc='center', - fontsize=10, bbox_to_anchor=(0.5, 0.05)) - plt.savefig(os.path.join(output_dir, 'compare_all_compartments.png'), dpi=300) + fontsize=10, bbox_to_anchor=(0.5, 0.05)) + plt.savefig( + os.path.join(output_dir, 'compare_all_compartments.png'), + dpi=300) plt.close() if __name__ == '__main__': results = {'Model B': 'results/ode_result_wang_nrw', - 'Model C': 'results/ode_result_nrw', - 'Model D': 'results/graph_result_nrw'} + 'Model C': 'results/ode_result_nrw', + 'Model D': 'results/graph_result_nrw'} file_format = 'h5' @@ -419,7 +461,7 @@ def compare_compartments(files, output_dir, legend): 'Model D (Graph-ODE)'] plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') - + # plot_maps(files=results, output_dir=plot_dir, legend=models, name='NRWAdaptiveDay') # plot_difference_maps(files={key: value for key, value in results.items() if key in { # 'Model C', 'Model D'}}, output_dir=plot_dir) From c48fc8330110d5e2caa56998b7a93b1799ee19d9 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 31 Mar 2025 10:57:46 +0200 Subject: [PATCH 78/87] resolve pyupgrade issue --- tools/plot_results_mobility.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tools/plot_results_mobility.py b/tools/plot_results_mobility.py index 43e1909f8b..981781e3ab 100644 --- a/tools/plot_results_mobility.py +++ b/tools/plot_results_mobility.py @@ -1,4 +1,3 @@ - import datetime as dt import os.path import h5py @@ -324,9 +323,8 @@ def extract_nrw_data_and_combine(files, date, relative=True): filters={'Group': filter_age, 'InfectionState': [2]}, output='matrix', file_format=file_format) - df['Group'] = df.Group.str.extract('(\d+)') + df['Group'] = df.Group.str.extract(r'(\d+)') df['Group'] = df['Group'].apply(pd.to_numeric, errors='coerce') - # df['Region'] = df['Group'] df['Region'] = (df['Group']-1) // len(age_groups) df = df.groupby(['Region'], as_index=False).agg({'Count': "sum"}) @@ -462,9 +460,14 @@ def compare_compartments(files, output_dir, legend): plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') - # plot_maps(files=results, output_dir=plot_dir, legend=models, name='NRWAdaptiveDay') - # plot_difference_maps(files={key: value for key, value in results.items() if key in { - # 'Model C', 'Model D'}}, output_dir=plot_dir) - # plot_difference(files={key: value for key, value in results.items() if key in { - # 'Model C', 'Model D'}}, output_dir=plot_dir) + plot_maps(files=results, output_dir=plot_dir, + legend=models, name='NRWAdaptiveDay') + plot_difference_maps( + files={key: value for key, value in results.items() + if key in {'Model C', 'Model D'}}, + output_dir=plot_dir) + plot_difference( + files={key: value for key, value in results.items() + if key in {'Model C', 'Model D'}}, + output_dir=plot_dir) compare_compartments(files=results, output_dir=plot_dir, legend=models) From 678291793bee45f5464a248079ea91df34aecacc Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein <100771374+charlie0614@users.noreply.github.com> Date: Mon, 31 Mar 2025 13:45:13 +0200 Subject: [PATCH 79/87] commit likwid examples --- shellscripts/likwid_equationbased.sh | 7 +++++-- shellscripts/likwid_graphbased.sh | 12 +++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/shellscripts/likwid_equationbased.sh b/shellscripts/likwid_equationbased.sh index edad0d115f..e4980ff289 100644 --- a/shellscripts/likwid_equationbased.sh +++ b/shellscripts/likwid_equationbased.sh @@ -20,6 +20,9 @@ echo Running $1 on node $SLURM_JOB_NODELIST with $warm_up_runs warm up runs and cd ../cpp/build rm -rf CMakeCache.txt CMakeFiles/ cmake -DCMAKE_BUILD_TYPE="Release" -DMEMILIO_ENABLE_OPENMP=ON -DMEMILIO_ENABLE_WARNINGS_AS_ERRORS=OFF .. -cmake --build . --target ode_seir_mobility_timing +cmake --build . --target ode_metapop_timing -srun --cpu-bind=cores --cpus-per-task=1 --cpu-freq=2200000-2200000 likwid-perfctr -C 0 -g MEM_DP -m ./bin/ode_seir_mobility_timing $warm_up_runs $runs $regions +perf record -C 0 likwid-pin ./bin/ode_metapop_timing $warm_up_runs $runs $regions +perf report +# srun --cpu-bind=cores --cpus-per-task=1 --cpu-freq=2200000-2200000 valgrind --tool=massif --detailed-freq=2 ./bin/ode_metapop_timing $warm_up_runs $runs $regions +# srun --cpu-bind=cores --cpus-per-task=1 --cpu-freq=2200000-2200000 likwid-perfctr -C 0 -g MEM_DP -m ./bin/ode_metapop_timing $warm_up_runs $runs $regions diff --git a/shellscripts/likwid_graphbased.sh b/shellscripts/likwid_graphbased.sh index 0438da669d..4963e4e860 100644 --- a/shellscripts/likwid_graphbased.sh +++ b/shellscripts/likwid_graphbased.sh @@ -10,16 +10,18 @@ #SBATCH --job-name=likwid_mobilitymodels warm_up_runs=0 -runs=50 -regions=400 +runs=1 +regions=80 module purge -module load PrgEnv/gcc12-openmpi +module load PrgEnv/gcc13-openmpi echo Running $1 on node $SLURM_JOB_NODELIST with $warm_up_runs warm up runs and $runs runs. cd ../cpp/build rm -rf CMakeCache.txt CMakeFiles/ -cmake -DCMAKE_BUILD_TYPE="Release" -DMEMILIO_ENABLE_OPENMP=ON -DMEMILIO_ENABLE_WARNINGS_AS_ERRORS=OFF .. -cmake --build . --target graph_timing +CXX="g++ -fverbose-asm" cmake -DCMAKE_BUILD_TYPE="Release" -DMEMILIO_ENABLE_OPENMP=ON -DMEMILIO_ENABLE_WARNINGS_AS_ERRORS=OFF .. +# cmake --build . --target graph_timing +# perf record ./bin/graph_timing $warm_up_runs $runs $regions +# perf report srun --cpu-bind=cores --cpus-per-task=1 --cpu-freq=2200000-2200000 likwid-perfctr -C 0 -g MEM_DP -m ./bin/graph_timing $warm_up_runs $runs $regions From 51a28f4f78e4c901a8fc88c1c0ccec84253dd27d Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Wed, 2 Apr 2025 14:52:24 +0200 Subject: [PATCH 80/87] rename mio::Vector in metapop models --- cpp/models/ode_metapop/model.h | 4 ++-- cpp/models/ode_metapop_wang/model.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/models/ode_metapop/model.h b/cpp/models/ode_metapop/model.h index d4e1490578..eaad53b0e3 100644 --- a/cpp/models/ode_metapop/model.h +++ b/cpp/models/ode_metapop/model.h @@ -48,8 +48,8 @@ class Model : public FlowModel> pop, Eigen::Ref> y, FP t, - Eigen::Ref> flows) const override + void get_flows(Eigen::Ref> pop, Eigen::Ref> y, FP t, + Eigen::Ref> flows) const override { const auto& params = this->parameters; const auto& population = this->populations; diff --git a/cpp/models/ode_metapop_wang/model.h b/cpp/models/ode_metapop_wang/model.h index fdb693d159..a1bf45d44b 100644 --- a/cpp/models/ode_metapop_wang/model.h +++ b/cpp/models/ode_metapop_wang/model.h @@ -46,8 +46,8 @@ class Model : public FlowModel> pop, Eigen::Ref> y, FP t, - Eigen::Ref> flows) const override + void get_flows(Eigen::Ref> pop, Eigen::Ref> y, FP t, + Eigen::Ref> flows) const override { const auto& params = this->parameters; const auto& population = this->populations; From b9d0fbb47650274a48e40b8fc225b1eaec26b073 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Fri, 4 Apr 2025 12:55:46 +0200 Subject: [PATCH 81/87] adjust to changed data structure --- .../examples_thesis/ode_metapop_nrw.cpp | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp index 42187e7805..c7e0335b7e 100644 --- a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp @@ -67,12 +67,14 @@ mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseirmet //TODO: io error handling auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_agegroups())); for (auto&& contact_location : contact_locations) { - BOOST_OUTCOME_TRY(auto&& baseline, - mio::read_mobility_plain( - (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); - BOOST_OUTCOME_TRY(auto&& minimum, - mio::read_mobility_plain( - (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); + BOOST_OUTCOME_TRY( + auto&& baseline, + mio::read_mobility_plain( + (data_dir / "Germany" / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); + BOOST_OUTCOME_TRY( + auto&& minimum, + mio::read_mobility_plain( + (data_dir / "Germany" / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; } @@ -87,12 +89,12 @@ mio::IOResult set_population_data(mio::oseirmetapop::Model& model, con { BOOST_OUTCOME_TRY( auto&& node_ids, - mio::get_node_ids((data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true, + mio::get_node_ids((data_dir / "Germany" / "pydata" / "county_current_population_nrw.json").string(), true, true)); BOOST_OUTCOME_TRY(const auto&& population_data, mio::read_population_data( - (data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true)); + (data_dir / "Germany" / "pydata" / "county_current_population_nrw.json").string(), true)); for (auto&& entry : population_data) { auto it = std::find_if(node_ids.begin(), node_ids.end(), [&entry](auto r) { @@ -129,8 +131,9 @@ mio::IOResult set_mobility_weights(mio::oseirmetapop::Model& model, co } else { // mobility between nodes - BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, - mio::read_mobility_plain((data_dir / "mobility" / "commuter_mobility_nrw.txt").string())); + BOOST_OUTCOME_TRY( + auto&& mobility_data_commuter, + mio::read_mobility_plain((data_dir / "Germany" / "mobility" / "commuter_mobility_2022_nrw.txt").string())); if (mobility_data_commuter.rows() != Eigen::Index(number_regions) || mobility_data_commuter.cols() != Eigen::Index(number_regions)) { return mio::failure(mio::StatusCode::InvalidValue, @@ -209,7 +212,7 @@ int main() mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& data_dir = ""; + const std::string& data_dir = "/home/carlotta/code/memilio/data"; mio::oseirmetapop::Model model(number_regions, number_age_groups); auto result_prepare_simulation = set_parameters_and_population(model, data_dir); From 881cb5be1df9300ea6654403fc00765d7d0142d6 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Fri, 4 Apr 2025 12:56:12 +0200 Subject: [PATCH 82/87] adjust to changed data structure --- pycode/memilio-epidata/memilio/epidata/getNRWCounties.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pycode/memilio-epidata/memilio/epidata/getNRWCounties.py b/pycode/memilio-epidata/memilio/epidata/getNRWCounties.py index 0f737f89dc..5232f2a3b5 100644 --- a/pycode/memilio-epidata/memilio/epidata/getNRWCounties.py +++ b/pycode/memilio-epidata/memilio/epidata/getNRWCounties.py @@ -12,10 +12,11 @@ def main(): arg_dict = gd.cli("commuter_official") - directory = arg_dict['out_folder'].split('/pydata')[0] + directory = os.path.join( + arg_dict['out_folder'].split('/pydata/')[0], 'Germany/') directory_mobility = os.path.join(directory, 'mobility/') - directory_population = os.path.join(directory, 'pydata/Germany/') - mobility_file = 'commuter_mobility' + directory_population = os.path.join(directory, 'pydata/') + mobility_file = 'commuter_mobility_2022' population_file = 'county_current_population' mobility_matrix = pd.read_csv( From 86fdc27db8a3c17a6d0ccf51bda80ee2324f379b Mon Sep 17 00:00:00 2001 From: Kilian Volmer <13285635+kilianvolmer@users.noreply.github.com> Date: Wed, 16 Apr 2025 09:09:33 +0200 Subject: [PATCH 83/87] CHG: Adapt paths to new folder structure --- cpp/examples/examples_thesis/graph_nrw.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/examples/examples_thesis/graph_nrw.cpp b/cpp/examples/examples_thesis/graph_nrw.cpp index fca1fb589f..e0399b1069 100644 --- a/cpp/examples/examples_thesis/graph_nrw.cpp +++ b/cpp/examples/examples_thesis/graph_nrw.cpp @@ -37,10 +37,10 @@ mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseir::P for (auto&& contact_location : contact_locations) { BOOST_OUTCOME_TRY(auto&& baseline, mio::read_mobility_plain( - (data_dir / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); + (data_dir / "Germany" / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); BOOST_OUTCOME_TRY(auto&& minimum, mio::read_mobility_plain( - (data_dir / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); + (data_dir / "Germany" / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; } @@ -91,7 +91,7 @@ set_population_data(const fs::path& data_dir, mio::oseir::Parameters& pa BOOST_OUTCOME_TRY(const auto&& population_data, mio::read_population_data( - (data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true)); + (data_dir / "Germany" / "pydata" / "county_current_population_nrw.json").string(), true)); std::vector> vnum_population(node_ids.size(), std::vector((size_t)params.get_num_groups(), 0.0)); @@ -144,7 +144,7 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double BOOST_OUTCOME_TRY( auto&& node_ids, - mio::get_node_ids((data_dir / "pydata" / "Germany" / "county_current_population_nrw.json").string(), true, + mio::get_node_ids((data_dir / "Germany" / "pydata" / "county_current_population_nrw.json").string(), true, true)); BOOST_OUTCOME_TRY(auto&& nodes, set_population_data(data_dir, params, node_ids)); @@ -154,7 +154,7 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double printf("Setting population from data successful.\n"); BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, - mio::read_mobility_plain((data_dir / "mobility" / "commuter_mobility_nrw.txt").string())); + mio::read_mobility_plain((data_dir / "Germany" / "mobility" / "commuter_mobility_2022_nrw.txt").string())); if (mobility_data_commuter.rows() != Eigen::Index(params_graph.nodes().size()) || mobility_data_commuter.cols() != Eigen::Index(params_graph.nodes().size())) { return mio::failure(mio::StatusCode::InvalidValue, From 298636aa56dd19f86c2febc1dcd20ffe37edc17b Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Thu, 24 Apr 2025 16:16:53 +0200 Subject: [PATCH 84/87] adjustments for testing --- cpp/examples/examples_thesis/graph_nrw.cpp | 21 +- .../examples_thesis/ode_metapop_nrw.cpp | 30 +-- cpp/models/ode_metapop/model.h | 34 +++ cpp/models/ode_metapop/parameters.h | 28 +- cpp/tests/CMakeLists.txt | 2 +- cpp/tests/data/seir-compare.csv | 68 +++-- cpp/tests/test_odemetapop.cpp | 241 +++++++++++++++++ cpp/tests/test_odesirmobility.cpp | 248 ------------------ tools/plot_results_mobility.py | 28 +- 9 files changed, 344 insertions(+), 356 deletions(-) create mode 100644 cpp/tests/test_odemetapop.cpp delete mode 100644 cpp/tests/test_odesirmobility.cpp diff --git a/cpp/examples/examples_thesis/graph_nrw.cpp b/cpp/examples/examples_thesis/graph_nrw.cpp index e0399b1069..ead6798cc5 100644 --- a/cpp/examples/examples_thesis/graph_nrw.cpp +++ b/cpp/examples/examples_thesis/graph_nrw.cpp @@ -35,12 +35,14 @@ mio::IOResult set_contact_matrices(const fs::path& data_dir, mio::oseir::P { auto contact_matrices = mio::ContactMatrixGroup(contact_locations.size(), size_t(params.get_num_groups())); for (auto&& contact_location : contact_locations) { - BOOST_OUTCOME_TRY(auto&& baseline, - mio::read_mobility_plain( - (data_dir / "Germany" / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); - BOOST_OUTCOME_TRY(auto&& minimum, - mio::read_mobility_plain( - (data_dir / "Germany" / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); + BOOST_OUTCOME_TRY( + auto&& baseline, + mio::read_mobility_plain( + (data_dir / "Germany" / "contacts" / ("baseline_" + contact_location.second + ".txt")).string())); + BOOST_OUTCOME_TRY( + auto&& minimum, + mio::read_mobility_plain( + (data_dir / "Germany" / "contacts" / ("minimum_" + contact_location.second + ".txt")).string())); contact_matrices[size_t(contact_location.first)].get_baseline() = baseline; contact_matrices[size_t(contact_location.first)].get_minimum() = minimum; } @@ -144,7 +146,7 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double BOOST_OUTCOME_TRY( auto&& node_ids, - mio::get_node_ids((data_dir / "Germany" / "pydata" / "county_current_population_nrw.json").string(), true, + mio::get_node_ids((data_dir / "Germany" / "pydata" / "county_current_population_nrw.json").string(), true, true)); BOOST_OUTCOME_TRY(auto&& nodes, set_population_data(data_dir, params, node_ids)); @@ -153,8 +155,9 @@ mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double } printf("Setting population from data successful.\n"); - BOOST_OUTCOME_TRY(auto&& mobility_data_commuter, - mio::read_mobility_plain((data_dir / "Germany" / "mobility" / "commuter_mobility_2022_nrw.txt").string())); + BOOST_OUTCOME_TRY( + auto&& mobility_data_commuter, + mio::read_mobility_plain((data_dir / "Germany" / "mobility" / "commuter_mobility_2022_nrw.txt").string())); if (mobility_data_commuter.rows() != Eigen::Index(params_graph.nodes().size()) || mobility_data_commuter.cols() != Eigen::Index(params_graph.nodes().size())) { return mio::failure(mio::StatusCode::InvalidValue, diff --git a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp index c7e0335b7e..2352c33bc9 100644 --- a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp @@ -147,8 +147,8 @@ mio::IOResult set_mobility_weights(mio::oseirmetapop::Model& model, co mobility_data_commuter(county_idx_i, county_idx_i) = 1 - mobility_data_commuter.rowwise().sum()(county_idx_i); } - model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = - mobility_data_commuter; + + model.set_commuting_strengths(mobility_data_commuter); printf("Setting mobility weights successful.\n"); return mio::success(); @@ -161,9 +161,6 @@ mio::IOResult set_parameters_and_population(mio::oseirmetapop::Model& auto& populations = model.populations; auto& parameters = model.parameters; - size_t number_regions = (size_t)parameters.get_num_regions(); - size_t number_age_groups = (size_t)parameters.get_num_agegroups(); - BOOST_OUTCOME_TRY(set_population_data(model, data_dir)); populations[{mio::oseirmetapop::Region(27), mio::AgeGroup(4), mio::oseirmetapop::InfectionState::Susceptible}] -= 100; @@ -175,27 +172,6 @@ mio::IOResult set_parameters_and_population(mio::oseirmetapop::Model& BOOST_OUTCOME_TRY(set_covid_parameters(parameters)); - mio::ContactMatrixGroup& commuting_strengths = - parameters.template get>().get_cont_freq_mat(); - - auto& population_after_commuting = model.m_population_after_commuting; - for (size_t region_n = 0; region_n < number_regions; ++region_n) { - for (size_t age = 0; age < number_age_groups; ++age) { - double population_n = 0; - for (size_t state = 0; state < (size_t)mio::oseirmetapop::InfectionState::Count; state++) { - population_n += populations[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age), - mio::oseirmetapop::InfectionState(state)}]; - } - population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] += population_n; - for (size_t region_m = 0; region_m < number_regions; ++region_m) { - population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] -= - commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; - population_after_commuting[{mio::oseirmetapop::Region(region_m), mio::AgeGroup(age)}] += - commuting_strengths[0].get_baseline()(region_n, region_m) * population_n; - } - } - } - return mio::success(); } @@ -212,7 +188,7 @@ int main() mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - const std::string& data_dir = "/home/carlotta/code/memilio/data"; + const std::string& data_dir = ""; mio::oseirmetapop::Model model(number_regions, number_age_groups); auto result_prepare_simulation = set_parameters_and_population(model, data_dir); diff --git a/cpp/models/ode_metapop/model.h b/cpp/models/ode_metapop/model.h index eaad53b0e3..e934b2ddc4 100644 --- a/cpp/models/ode_metapop/model.h +++ b/cpp/models/ode_metapop/model.h @@ -207,6 +207,40 @@ class Model : public FlowModelparameters.template get>().get_cont_freq_mat()[0].get_baseline(); + commuting_strengths_param = commuting_strengths; + + auto number_regions = (size_t)this->parameters.get_num_regions(); + auto number_age_groups = (size_t)this->parameters.get_num_agegroups(); + auto& population = this->populations; + + for (size_t region_n = 0; region_n < number_regions; ++region_n) { + for (size_t age = 0; age < number_age_groups; ++age) { + double population_n = 0; + for (size_t state = 0; state < (size_t)mio::oseirmetapop::InfectionState::Count; state++) { + population_n += population[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age), + mio::oseirmetapop::InfectionState(state)}]; + } + m_population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] += population_n; + for (size_t region_m = 0; region_m < number_regions; ++region_m) { + m_population_after_commuting[{mio::oseirmetapop::Region(region_n), mio::AgeGroup(age)}] -= + commuting_strengths(region_n, region_m) * population_n; + m_population_after_commuting[{mio::oseirmetapop::Region(region_m), mio::AgeGroup(age)}] += + commuting_strengths(region_n, region_m) * population_n; + } + } + } + } + + void set_commuting_strengths() + { + auto number_regions = (size_t)this->parameters.get_num_regions(); + set_commuting_strengths(Eigen::MatrixXd::Identity(number_regions, number_regions)); + } + mio::Populations m_population_after_commuting; }; // namespace oseirmetapop diff --git a/cpp/models/ode_metapop/parameters.h b/cpp/models/ode_metapop/parameters.h index 82e97f486e..f68d9aecca 100644 --- a/cpp/models/ode_metapop/parameters.h +++ b/cpp/models/ode_metapop/parameters.h @@ -101,22 +101,6 @@ struct CommutingStrengths { } }; -// /** -// * @brief The infectious time in day unit. -// */ -// template -// struct PopulationAfterCommuting { -// using Type = CustomIndexArray; -// static Type get_default(Region size_region, AgeGroup size_agegroups) -// { -// return Type({size_region, size_agegroups}, 0.); -// } -// static std::string name() -// { -// return "TimeInfected"; -// } -// }; - template using ParametersBase = ParameterSet, TimeExposed, TimeInfected, ContactPatterns, CommutingStrengths>; @@ -202,7 +186,7 @@ class Parameters : public ParametersBase */ bool check_constraints() const { - double tol_times = 1e-1; + const double tol_times = 1e-1; for (auto i = AgeGroup(0); i < AgeGroup(m_num_agegroups); i++) { if (this->template get>()[i] < tol_times) { @@ -233,10 +217,12 @@ class Parameters : public ParametersBase } private: - // Parameters(ParametersBase&& base) - // : ParametersBase(std::move(base)) //TODO: Adjust - // { - // } + Parameters(ParametersBase&& base) + : ParametersBase(std::move(base)) + , m_num_regions(base.get_num_regions()) + , m_num_agegroups(base.get_num_agegroups()) + { + } public: /** diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 59049e2d85..9a0f0ffbc3 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -9,7 +9,6 @@ set(TESTSOURCES test_populations.cpp test_odeseir.cpp test_odesir.cpp - test_odesirmobility.cpp test_numericalIntegration.cpp test_smoother.cpp test_damping.cpp @@ -85,6 +84,7 @@ set(TESTSOURCES sanitizers.cpp temp_file_register.h test_graph_abm.cpp + test_odemetapop.cpp ) if(MEMILIO_HAS_JSONCPP) diff --git a/cpp/tests/data/seir-compare.csv b/cpp/tests/data/seir-compare.csv index 239da95a90..677c4dcb36 100644 --- a/cpp/tests/data/seir-compare.csv +++ b/cpp/tests/data/seir-compare.csv @@ -1,38 +1,32 @@ # t S E I R -0.00000000000000 1049000.00000000000000 10000.00000000000000 1000.00000000000000 1000.00000000000000 -0.10020040080160 1048713.73075449210592 10092.73973116525303 1139.90293509658432 1053.62657924606287 -0.55110220440882 1046987.03773772297427 10913.21433861356854 1722.35062247182555 1377.39730119167007 -1.06524485978665 1044199.67649725102820 12546.50135443816725 2352.64073874483029 1901.18140956591151 -1.66118286922071 1039882.88403208740056 15277.40751934598848 3124.57561811346159 2715.13283045316348 -2.35595933715807 1033223.08161422202829 19620.39802993273770 4178.99925471840470 3977.52110112678702 -3.17804724413681 1022601.74967979907524 26616.01552748418908 5774.46915014757906 6007.76564256919391 -4.16892733448395 1004653.68742704729084 38433.08942357360502 8426.31628393779829 9486.90686544130585 -5.39212393400959 971794.34643305663485 59899.25324166747305 13285.70435961234216 16020.69596566357177 -6.75385596665597 915651.03697983513121 95955.08135336369742 21680.78975441652437 27713.09191238471249 -8.11558799930235 832006.67458390793763 148023.69851912744343 34434.60167287031800 46535.02522409435187 -9.20410138553930 742390.77543479565065 201243.67541724219336 48438.55588028273633 68926.99326767947059 -10.35945756851834 627065.38188297860324 264857.50646954111289 66979.08704119051981 102098.02460628982226 -11.34283729342433 518682.01091470837127 318045.68243877496570 84889.94336055630993 139382.36328596036765 -11.68513854174272 480717.31176111887908 334517.08517993631540 91305.17626443399058 154460.42679451091681 -12.02743979006111 449239.68215949274600 343612.28946372546488 97522.08154542848933 170625.94683135347441 -12.49960760584322 422867.08470962184947 338890.87290152284550 104702.56547239044448 194539.47691646512249 -13.03235808080705 398884.25140891782939 328683.93571044335840 110212.60941252954945 223219.20346810953924 -14.00378887908028 356681.26272533729207 311129.32350503187627 115039.57091181630676 278149.84285781485960 -15.03718720382851 315875.18265972472727 291988.74967131868470 115307.25494283462467 337828.81272612238536 -16.23194039567660 275050.90921587980120 268405.82756743824575 111736.34426414610061 405806.91895253618713 -17.60257755885122 236467.00561473876587 239969.97161763752229 104511.92403225359158 480051.09873537049862 -19.16760479273252 201836.59999166175839 207309.78507492708741 94020.34686743725615 557833.26806597434916 -20.88659483428036 173106.68153741111746 173218.67543084506178 81416.90213117960957 633257.74090056458954 -22.69375340601369 150852.65998401606339 140995.97202733816812 68301.84864338369516 700849.51934526243713 -24.50091197774702 134557.73041747722891 113246.00119738388457 56197.14653868280584 756999.12184645654634 -26.41330860711764 121973.81911217638117 88824.00341652805218 44973.30425799178920 805228.87321330432314 -28.32570523648826 112813.90882977400906 69081.93155133874097 35528.60144885115733 843575.55817003664561 -30.38229100048863 105671.11442069984332 52351.75372552395129 27272.90021063667882 875704.23164314008318 -32.53203962405642 100321.51816427615995 38955.94707539147203 20499.60398380133847 901222.93077653169166 -34.80205851628455 96313.32349675761361 28382.83233381239552 15052.79886064722450 921251.04530878353398 -37.21697173781426 93330.24045060748176 20191.58383072874494 10772.64150247535326 936705.53421618917491 -39.81010816461136 91131.38117136582150 13966.76619385667800 7485.05937048995293 948416.79326428822242 -42.63010344500196 89531.23135069153795 9332.43326583900853 5018.01799063735871 957118.31739283283241 -45.75944493788541 88384.30794850864913 5954.72807288235890 3209.52003529808644 963451.44394331169315 -49.04133237767380 87631.65751046490914 3712.10967585467961 2003.95478390116250 967652.27802978013642 -50.00000000000000 87471.72565843837219 3232.86999470437786 1745.83765843541028 968549.56668842269573 \ No newline at end of file +0.00000000000000 1049000.00000000000000 10000.00000000000000 1000.00000000000000 1000.00000000000000 +0.10000000000000 1048988.58104405831546 9820.84180564139024 1137.10656898469369 1053.47058131574704 +0.55000000000000 1048921.19260577531531 9071.41760821554271 1638.35319813403248 1369.03658787526888 +1.25368521533823 1048777.92434315709397 8057.65350011104692 2124.42279256048960 2039.99936417154072 +2.04101569383354 1048587.09683475596830 7102.84469418988101 2376.22157266856857 2933.83689838560213 +2.91269832810373 1048361.93679713841993 6213.99866413117434 2435.36705174795952 3988.69748698247349 +3.86108598819142 1048118.75420537753962 5400.19422411334563 2352.80445087728185 5128.24711963193658 +4.89524280895636 1047868.37748317280784 4653.03293158922588 2176.80497774428613 6301.78460749369606 +6.04258168918588 1047616.18589280080050 3957.58132139215195 1942.12075092638770 7484.11203488072078 +7.31202455451348 1047371.24218315689359 3317.02549236070581 1678.99995750832181 8632.73236697410903 +8.72217138862949 1047139.50138118292671 2731.33236444458089 1409.47894176413433 9719.68731260833556 +10.29866521143641 1046925.20438532845583 2200.92070243870512 1148.83682853681012 10725.03808369601029 +11.26330707694919 1046814.32675929483958 1929.26662121211734 1011.11757043176715 11245.28904906113530 +11.83968766077253 1046756.44987186952494 1781.52131508086131 936.25838507353467 11525.77042797587637 +12.41606824459587 1046723.19954850582872 1625.83279033276176 865.62759542813637 11785.34006573311126 +13.23077263638088 1046694.73595185985323 1416.35921567730816 770.52174862369714 12118.38308383898402 +14.29229910912589 1046662.49569856002927 1183.90972509897119 656.95470024970564 12496.63987609106516 +15.86173338430521 1046623.51623129635118 908.91131129897394 513.59281557679321 12953.97964182766191 +17.54650957365405 1046591.22194189496804 684.75600965202909 391.12584655378078 13332.89620189897141 +19.45489021353186 1046563.91490716743283 497.04591109170804 285.73393899509000 13653.30524274554955 +21.64765095553324 1046541.53458704100922 344.06106027643995 198.49179269541142 13915.91255998686938 +24.28135793516138 1046523.50970833166502 221.21786470759676 127.85456271077467 14127.41786424956445 +27.15441528731246 1046511.08352608617861 136.64984898643644 79.03686722492844 14273.22975770212179 +30.02747263946354 1046503.40388168359641 84.41354759733713 48.83710200550596 14363.34546871330349 +32.90052999161462 1046498.65905382949859 52.14589751457984 30.17173192072158 14419.02331673489971 +35.77358734376570 1046495.72778672503773 32.21290587549021 18.63911728165846 14453.42019011756929 +38.64664469591678 1046493.91696999303531 19.89941326560179 11.51439924071712 14474.66921750034635 +41.51970204806786 1046492.79833600565325 12.29280080570297 7.11301775236865 14487.79584543603960 +44.39275940021894 1046492.10730175010394 7.59384068675560 4.39405288810484 14495.90480467486668 +47.26581675237001 1046491.68041715247091 4.69107240917980 2.71441480176851 14500.91409563640809 +50.00000000000000 1046491.42674924037419 2.96615872057889 1.71632120750472 14503.89077083145639 \ No newline at end of file diff --git a/cpp/tests/test_odemetapop.cpp b/cpp/tests/test_odemetapop.cpp new file mode 100644 index 0000000000..adfe07ecc6 --- /dev/null +++ b/cpp/tests/test_odemetapop.cpp @@ -0,0 +1,241 @@ + +#include "load_test_data.h" +#include "memilio/config.h" +#include "memilio/utils/time_series.h" +#include "ode_metapop/model.h" +#include "ode_metapop/infection_state.h" +#include "ode_metapop/parameters.h" +#include "memilio/math/euler.h" +#include "memilio/compartments/simulation.h" +#include +#include +#include + +class ModelTestOdeMetapop : public testing::Test +{ +public: + ModelTestOdeMetapop() + : model(1, 1) + { + } + double t0; + double tmax; + double dt; + double total_population; + mio::oseirmetapop::Model model; + +protected: + void SetUp() override + { + t0 = 0.; + tmax = 50.; + dt = 0.1; + + total_population = 1061000; + + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed)}] = 10000; + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Infected)}] = 1000; + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible)}] = + total_population - + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed)}] - + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Infected)}] - + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Recovered)}]; + + model.set_commuting_strengths(); + } +}; + +TEST_F(ModelTestOdeMetapop, simulateDefault) +{ + mio::TimeSeries result = simulate(t0, tmax, dt, model); + + EXPECT_NEAR(result.get_last_time(), tmax, 1e-10); +} + +TEST_F(ModelTestOdeMetapop, checkPopulationConservation) +{ + auto result = simulate(t0, tmax, dt, model); + double num_persons = result.get_last_value().sum(); + EXPECT_NEAR(num_persons, total_population, 1e-8); +} + +TEST_F(ModelTestOdeMetapop, check_constraints_parameters) +{ + model.parameters.set>(5.2); + model.parameters.set>(6); + model.parameters.set>(0.04); + + model.parameters.get>().get_cont_freq_mat()[0].get_baseline()(0, 0) = 10; + + // model.check_constraints() combines the functions from population and parameters. + // We only want to test the functions for the parameters defined in parameters.h + ASSERT_EQ(model.parameters.check_constraints(), 0); + + mio::set_log_level(mio::LogLevel::off); + model.parameters.set>(-5.2); + ASSERT_EQ(model.parameters.check_constraints(), 1); + + model.parameters.set>(5.2); + model.parameters.set>(0); + ASSERT_EQ(model.parameters.check_constraints(), 1); + + model.parameters.set>(6); + model.parameters.set>(10.); + ASSERT_EQ(model.parameters.check_constraints(), 1); + mio::set_log_level(mio::LogLevel::warn); +} + +TEST_F(ModelTestOdeMetapop, apply_constraints_parameters) +{ + const double tol_times = 1e-1; + model.parameters.set>(5.2); + model.parameters.set>(2); + model.parameters.set>(0.04); + mio::ContactMatrixGroup& contact_matrix = + model.parameters.get>().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(10); + + EXPECT_EQ(model.parameters.apply_constraints(), 0); + + mio::set_log_level(mio::LogLevel::off); + model.parameters.set>(-5.2); + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_EQ(model.parameters.get>()[(mio::AgeGroup)0], tol_times); + + model.parameters.set>(1e-5); + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_EQ(model.parameters.get>()[(mio::AgeGroup)0], tol_times); + + model.parameters.set>(10.); + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_NEAR(model.parameters.get>()[(mio::AgeGroup)0], + 0.0, 1e-14); + mio::set_log_level(mio::LogLevel::warn); +} + +// TEST_F(ModelTestOdeMetapop, compareSEIR) +// { +// model.parameters.set>(5.2); +// model.parameters.set>(2); +// model.parameters.set>(1.); +// model.parameters.get>().get_cont_freq_mat()[0].get_baseline()(0, 0) = +// 2.7; +// model.parameters.get>().get_cont_freq_mat()[0].add_damping( +// 0.6, mio::SimulationTime(12.5)); + +// model.check_constraints(); + +// auto result = simulate(t0, tmax, dt, model); +// std::vector> refData = load_test_data_csv("seir-compare.csv"); + +// ASSERT_EQ(refData.size(), static_cast(result.get_num_time_points())); + +// for (Eigen::Index irow = 0; irow < result.get_num_time_points(); ++irow) { +// double t = refData[static_cast(irow)][0]; +// auto rel_tol = 1e-6; + +// //test result diverges at damping because of changes, not worth fixing at the moment +// if (t > 11.0 && t < 13.0) { +// //strong divergence around damping +// rel_tol = 0.5; +// } +// else if (t > 13.0) { +// //minor divergence after damping +// rel_tol = 1e-2; +// } +// mio::unused(rel_tol); + +// ASSERT_NEAR(t, result.get_times()[irow], 1e-12) << "at row " << irow; + +// for (size_t icol = 0; icol < refData[static_cast(irow)].size() - 1; ++icol) { +// double ref = refData[static_cast(irow)][icol + 1]; +// double actual = result[irow][icol]; + +// double tol = rel_tol * ref; +// ASSERT_NEAR(ref, actual, tol) << "at row " << irow; +// } +// } +// } + +// TEST_F(ModelTestOdeMetapop, compareWithPreviousRun) +// { +// // initialization +// double t0 = 0.; +// double tmax = 3.; +// double dt = 0.1; + +// size_t number_regions = 4; +// size_t number_age_groups = 2; +// size_t total_population_per_region = 5000; + +// mio::oseirmetapop::Model model(number_regions, number_age_groups); + +// for (size_t age = 0; age < number_age_groups; age++) { +// for (size_t i = 0; i < number_regions; i++) { +// model.populations[{mio::Index( +// mio::oseirmetapop::Region(i), mio::AgeGroup(age), mio::oseirmetapop::InfectionState::Infected)}] = 50; +// model.populations[{mio::Index( +// mio::oseirmetapop::Region(i), mio::AgeGroup(age), mio::oseirmetapop::InfectionState::Recovered)}] = 0; +// model.populations[{mio::Index( +// mio::oseirmetapop::Region(i), mio::AgeGroup(age), mio::oseirmetapop::InfectionState::Susceptible)}] = +// total_population_per_region - +// model.populations[{mio::Index( +// mio::oseirmetapop::Region(i), mio::AgeGroup(age), mio::oseirmetapop::InfectionState::Infected)}] - +// model.populations[{mio::Index( +// mio::oseirmetapop::Region(i), mio::AgeGroup(age), mio::oseirmetapop::InfectionState::Recovered)}]; +// } +// } +// model.parameters.template set>(1.0); +// model.parameters.set>(2); + +// model.parameters.get>().get_cont_freq_mat()[0].get_baseline().setConstant(2.7); +// model.parameters.get>().get_cont_freq_mat()[0].add_damping( +// 0.6, mio::SimulationTime(12.5)); + +// Eigen::MatrixXd mobility_data_commuter(4, 4); +// mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0.5, 0., 0.5, 0., 0., 0., 0., 1.; +// model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = +// mobility_data_commuter; + +// std::vector> refData = load_test_data_csv("ode-seir-metapop-compare.csv"); +// std::shared_ptr> integrator = std::make_shared>(); +// auto result = mio::simulate>(t0, tmax, dt, model, integrator); + +// ASSERT_EQ(refData.size(), static_cast(result.get_num_time_points())); + +// for (Eigen::Index irow = 0; irow < result.get_num_time_points(); ++irow) { +// double t = refData[static_cast(irow)][0]; +// auto rel_tol = 1e-6; + +// //test result diverges at damping because of changes, not worth fixing at the moment +// if (t > 11.0 && t < 13.0) { +// //strong divergence around damping +// rel_tol = 0.5; +// } +// else if (t > 13.0) { +// //minor divergence after damping +// rel_tol = 1e-2; +// } +// mio::unused(rel_tol); + +// ASSERT_NEAR(t, result.get_times()[irow], 1e-12) << "at row " << irow; + +// for (size_t icol = 0; icol < 12; ++icol) { +// double ref = refData[static_cast(irow)][icol + 1]; +// double actual = result[irow][icol]; + +// double tol = rel_tol * ref; +// ASSERT_NEAR(ref, actual, tol) << "at row " << irow; +// } +// } +// } diff --git a/cpp/tests/test_odesirmobility.cpp b/cpp/tests/test_odesirmobility.cpp deleted file mode 100644 index 247a8622ff..0000000000 --- a/cpp/tests/test_odesirmobility.cpp +++ /dev/null @@ -1,248 +0,0 @@ - -#include "load_test_data.h" -#include "memilio/config.h" -#include "memilio/utils/time_series.h" -#include "ode_sir_mobility/model.h" -#include "ode_sir_mobility/infection_state.h" -#include "ode_sir_mobility/parameters.h" -#include "memilio/math/euler.h" -#include "memilio/compartments/simulation.h" -#include -#include -#include - -TEST(TestOdeSirMobility, simulateDefault) -{ - double t0 = 0; - double tmax = 1; - double dt = 0.1; - - size_t num_regions = 4; - - mio::osirmobility::Model model(num_regions); - mio::TimeSeries result = simulate(t0, tmax, dt, model); - - EXPECT_NEAR(result.get_last_time(), tmax, 1e-10); -} - -TEST(TestOdeSirMobility, compareWithPreviousRun) -{ - // initialization - double t0 = 0.; - double tmax = 3.; - double dt = 0.1; - - size_t number_regions = 4; - size_t number_age_groups = 1; - size_t total_population_per_region = 5000; - - mio::osirmobility::Model model(number_regions, number_age_groups); - - for (size_t i = 0; i < number_regions; i++) { - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] = 50; - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered)}] = 0; - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Susceptible)}] = - total_population_per_region - - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected)}] - - model.populations[{mio::Index( - mio::osirmobility::Region(i), mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered)}]; - } - model.parameters.set(1.0); - model.parameters.set(2); - - model.parameters.get().get_baseline()(0, 0) = 2.7; - model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); - - model.parameters.set(1.); - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.2}); - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(2), 0.6}); - model.parameters.get().push_back( - {mio::osirmobility::Region(2), mio::osirmobility::Region(0), 0.5}); - model.parameters.get().push_back( - {mio::osirmobility::Region(0), mio::osirmobility::Region(3), 1.0}); - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(3), 0.2}); - - model.parameters.get()[{mio::osirmobility::Region(0), - mio::osirmobility::Region(1)}] = {2}; - model.parameters.get()[{mio::osirmobility::Region(0), - mio::osirmobility::Region(3)}] = {2}; - model.parameters.get()[{mio::osirmobility::Region(1), - mio::osirmobility::Region(0)}] = {2}; - model.parameters.get()[{mio::osirmobility::Region(1), - mio::osirmobility::Region(2)}] = {0}; - model.parameters.get()[{mio::osirmobility::Region(1), - mio::osirmobility::Region(3)}] = {2}; - model.parameters.get()[{mio::osirmobility::Region(2), - mio::osirmobility::Region(1)}] = {0}; - model.parameters.get()[{mio::osirmobility::Region(3), - mio::osirmobility::Region(0)}] = {2}; - model.parameters.get()[{mio::osirmobility::Region(3), - mio::osirmobility::Region(1)}] = {2}; - - std::vector> refData = load_test_data_csv("ode-sir-mobility-compare.csv"); - auto integrator = std::make_shared(); - auto result = mio::simulate(t0, tmax, dt, model, integrator); - - ASSERT_EQ(refData.size(), static_cast(result.get_num_time_points())); - - for (Eigen::Index irow = 0; irow < result.get_num_time_points(); ++irow) { - double t = refData[static_cast(irow)][0]; - auto rel_tol = 1e-6; - - //test result diverges at damping because of changes, not worth fixing at the moment - if (t > 11.0 && t < 13.0) { - //strong divergence around damping - rel_tol = 0.5; - } - else if (t > 13.0) { - //minor divergence after damping - rel_tol = 1e-2; - } - mio::unused(rel_tol); - - ASSERT_NEAR(t, result.get_times()[irow], 1e-12) << "at row " << irow; - - for (size_t icol = 0; icol < 12; ++icol) { - double ref = refData[static_cast(irow)][icol + 1]; - double actual = result[irow][icol]; - - double tol = rel_tol * ref; - ASSERT_NEAR(ref, actual, tol) << "at row " << irow; - } - } -} - -TEST(TestOdeSirMobility, checkPopulationConservation) -{ - // initialization - double t0 = 0.; - double tmax = 50.; - double dt = 0.1002004008016032; - - double population_per_region = 1061000; - mio::osirmobility::Region num_regions = 4; - - mio::osirmobility::Model model((size_t)num_regions); - - for (auto region = mio::osirmobility::Region(0); region < num_regions; ++region) { - model.populations[{region, mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected}] = 1000; - model.populations[{region, mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered}] = 1000; - model.populations[{region, mio::AgeGroup(0), mio::osirmobility::InfectionState::Susceptible}] = - population_per_region - - model.populations[{region, mio::AgeGroup(0), mio::osirmobility::InfectionState::Infected}] - - model.populations[{region, mio::AgeGroup(0), mio::osirmobility::InfectionState::Recovered}]; - } - model.parameters.set(2); - model.parameters.set(0.04); - model.parameters.set(1.); - model.parameters.get().get_baseline()(0, 0) = 1.; - model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.5}); - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(2), 0.8}); - model.parameters.get().push_back( - {mio::osirmobility::Region(2), mio::osirmobility::Region(0), 0.5}); - model.parameters.get().push_back( - {mio::osirmobility::Region(0), mio::osirmobility::Region(3), 1.0}); - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(3), 0.8}); - - auto result = mio::simulate(t0, tmax, dt, model); - double num_persons = 0.0; - for (auto i = 0; i < result.get_last_value().size(); ++i) { - num_persons += result.get_last_value()[i]; - } - EXPECT_NEAR(num_persons, population_per_region * (size_t)num_regions, 1e-8); -} - -TEST(TestOdeSirMobility, check_constraints_parameters) -{ - mio::osirmobility::Region num_regions = 2; - - mio::osirmobility::Model model((size_t)num_regions); - model.parameters.set(6); - model.parameters.set(0.04); - model.parameters.set(1.); - model.parameters.get().get_baseline()(0, 0) = 10.; - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.5}); - - // model.check_constraints() combines the functions from population and parameters. - // We only want to test the functions for the parameters defined in parameters.h - ASSERT_EQ(model.parameters.check_constraints(), 0); - - mio::set_log_level(mio::LogLevel::off); - - model.parameters.set(0); - ASSERT_EQ(model.parameters.check_constraints(), 1); - - model.parameters.set(6); - model.parameters.set(10.); - ASSERT_EQ(model.parameters.check_constraints(), 1); - - model.parameters.set(0.04); - model.parameters.set(10.); - ASSERT_EQ(model.parameters.check_constraints(), 1); - - model.parameters.set(1.); - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 10.5}); - ASSERT_EQ(model.parameters.check_constraints(), 1); - - model.parameters.get().pop_back(); - model.parameters.get().push_back( - {mio::osirmobility::Region(2), mio::osirmobility::Region(0), 0.5}); - mio::set_log_level(mio::LogLevel::warn); -} - -TEST(TestOdeSirMobility, apply_constraints_parameters) -{ - const double tol_times = 1e-1; - mio::osirmobility::Region num_regions = 2; - - mio::osirmobility::Model model((size_t)num_regions); - model.parameters.set(6); - model.parameters.set(0.04); - model.parameters.set(1.); - model.parameters.get().get_baseline()(0, 0) = 10.; - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 0.5}); - - EXPECT_EQ(model.parameters.apply_constraints(), 0); - - mio::set_log_level(mio::LogLevel::off); - - model.parameters.set(-2.5); - EXPECT_EQ(model.parameters.apply_constraints(), 1); - EXPECT_EQ(model.parameters.get(), tol_times); - - model.parameters.set(10.); - EXPECT_EQ(model.parameters.apply_constraints(), 1); - EXPECT_NEAR(model.parameters.get(), 0.0, 1e-14); - - model.parameters.set(0.04); - model.parameters.set(10.); - EXPECT_EQ(model.parameters.apply_constraints(), 1); - EXPECT_NEAR(model.parameters.get(), 0.0, 1e-14); - - model.parameters.set(1.); - model.parameters.get().push_back( - {mio::osirmobility::Region(1), mio::osirmobility::Region(0), 10.5}); - EXPECT_EQ(model.parameters.apply_constraints(), 1); - EXPECT_NEAR(std::get(model.parameters.get()[2]), 0.0, 1e-14); - - model.parameters.get().pop_back(); - model.parameters.get().push_back( - {mio::osirmobility::Region(2), mio::osirmobility::Region(0), 0.5}); - EXPECT_EQ(model.parameters.apply_constraints(), 1); - // EXPECT_EQ(model.parameters.get().size(), 2); // 1 by default + 1 added - mio::set_log_level(mio::LogLevel::warn); -} \ No newline at end of file diff --git a/tools/plot_results_mobility.py b/tools/plot_results_mobility.py index 981781e3ab..3e8cc74d7c 100644 --- a/tools/plot_results_mobility.py +++ b/tools/plot_results_mobility.py @@ -215,7 +215,7 @@ def plot_maps(files, output_dir, legend, name=''): fontsize=13) -def plot_difference(files, output_dir): +def plot_difference(files, output_dir, name='difference2D'): fig = plt.figure() df_dif = pd.DataFrame(columns=['Time', 'difference', 'absolute value']) @@ -240,7 +240,7 @@ def plot_difference(files, output_dir): plt.tight_layout() plt.legend() plt.grid(linestyle='--') - plt.savefig(os.path.join(output_dir, 'difference2D.png')) + plt.savefig(os.path.join(output_dir, name)) plt.close() @@ -460,14 +460,16 @@ def compare_compartments(files, output_dir, legend): plot_dir = os.path.join(os.path.dirname(__file__), '../Plots') - plot_maps(files=results, output_dir=plot_dir, - legend=models, name='NRWAdaptiveDay') - plot_difference_maps( - files={key: value for key, value in results.items() - if key in {'Model C', 'Model D'}}, - output_dir=plot_dir) - plot_difference( - files={key: value for key, value in results.items() - if key in {'Model C', 'Model D'}}, - output_dir=plot_dir) - compare_compartments(files=results, output_dir=plot_dir, legend=models) + # plot_maps(files=results, output_dir=plot_dir, + # legend=models, name='NRWAdaptiveDay') + # plot_difference_maps( + # files={key: value for key, value in results.items() + # if key in {'Model C', 'Model D'}}, + # output_dir=plot_dir) + # plot_difference( + # files={key: value for key, value in results.items() + # if key in {'Model C', 'Model D'}}, + # output_dir=plot_dir) + # compare_compartments(files=results, output_dir=plot_dir, legend=models) + plot_difference(files={'Old result': 'cpp/build/ode_result_nrw_test', 'New result': 'cpp/build/ode_result_nrw'}, output_dir=plot_dir, name='difference_ode_results_test') + # plot_difference(files={'Old result': 'results/graph_result_nrw', 'New result': 'cpp/build/graph_result_nrw'}, output_dir=plot_dir, name='difference_graph_results') \ No newline at end of file From d7ba3c585f5ecbf27d93e948d6275c79543353fa Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Wed, 30 Apr 2025 13:04:21 +0200 Subject: [PATCH 85/87] add tests --- cpp/models/ode_metapop/model.h | 4 +- cpp/models/ode_metapop/parameters.h | 22 ++ cpp/tests/test_odemetapop.cpp | 386 ++++++++++++++++------------ 3 files changed, 247 insertions(+), 165 deletions(-) diff --git a/cpp/models/ode_metapop/model.h b/cpp/models/ode_metapop/model.h index e934b2ddc4..e560a20c16 100644 --- a/cpp/models/ode_metapop/model.h +++ b/cpp/models/ode_metapop/model.h @@ -86,14 +86,14 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t)(age_i, age_j) * params.template get>()[AgeGroup(age_i)]; flows[Base::template get_flat_flow_index( {Region(region_n), AgeGroup(age_i)})] += - (pop[Ijn] * Nj_inv + infections_due_commuting(region_n, age_j)) * coeffStoI * + (pop[Ijn] * Nj_inv + infections_due_commuting(region_n, age_j)) * coeffStoE * y[population.get_flat_index({Region(region_n), AgeGroup(age_i), InfectionState::Susceptible})]; } } diff --git a/cpp/models/ode_metapop/parameters.h b/cpp/models/ode_metapop/parameters.h index f68d9aecca..b410f2d86e 100644 --- a/cpp/models/ode_metapop/parameters.h +++ b/cpp/models/ode_metapop/parameters.h @@ -175,6 +175,18 @@ class Parameters : public ParametersBase this->template get>() = 0.0; corrected = true; } + if ((this->template get>().get_cont_freq_mat().get_matrix_at(0).rowwise().sum() - + Eigen::VectorXd::Ones((size_t)this->get_num_regions())) + .cwiseAbs() + .maxCoeff() > 1e-10 || + this->template get>().get_cont_freq_mat().get_matrix_at(0).minCoeff() < 0.0 || + this->template get>().get_cont_freq_mat().get_matrix_at(0).maxCoeff() > 1.0) { + log_warning("Constraint check: Parameter CommutingStrengths does not ensure that the number of people " + "staying equals the complement of those leaving. Running without commuting."); + this->template get>().get_cont_freq_mat()[0].get_baseline() = + Eigen::MatrixXd::Identity((size_t)this->get_num_regions(), (size_t)this->get_num_regions()); + return true; + } } return corrected; } @@ -212,6 +224,16 @@ class Parameters : public ParametersBase this->template get>()[i], 0.0, 1.0); return true; } + if ((this->template get>().get_cont_freq_mat().get_matrix_at(0).rowwise().sum() - + Eigen::VectorXd::Ones((size_t)this->get_num_regions())) + .cwiseAbs() + .maxCoeff() > 1e-10 || + this->template get>().get_cont_freq_mat().get_matrix_at(0).minCoeff() < 0.0 || + this->template get>().get_cont_freq_mat().get_matrix_at(0).maxCoeff() > 1.0) { + log_error("Constraint check: Parameter CommutingStrengths does not ensure that the number of people " + "staying equals the complement of those leaving."); + return true; + } } return false; } diff --git a/cpp/tests/test_odemetapop.cpp b/cpp/tests/test_odemetapop.cpp index adfe07ecc6..0ebaa64606 100644 --- a/cpp/tests/test_odemetapop.cpp +++ b/cpp/tests/test_odemetapop.cpp @@ -15,14 +15,14 @@ class ModelTestOdeMetapop : public testing::Test { public: ModelTestOdeMetapop() - : model(1, 1) + : model(4, 1) { } - double t0; - double tmax; - double dt; - double total_population; - mio::oseirmetapop::Model model; + ScalarType t0; + ScalarType tmax; + ScalarType dt; + ScalarType total_population_per_region; + mio::oseirmetapop::Model model; protected: void SetUp() override @@ -31,211 +31,271 @@ class ModelTestOdeMetapop : public testing::Test tmax = 50.; dt = 0.1; - total_population = 1061000; + total_population_per_region = 1061000; - model.populations[{mio::Index( - mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed)}] = 10000; - model.populations[{mio::Index( - mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index( - mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Recovered)}] = 1000; - model.populations[{mio::Index( - mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible)}] = - total_population - + for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { model.populations[{mio::Index( - mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed)}] - + mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed)}] = 10000; model.populations[{mio::Index( - mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Infected)}] - + mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Infected)}] = 1000; model.populations[{mio::Index( - mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Recovered)}]; - + mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index( + mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible)}] = + total_population_per_region - + model.populations[{ + mio::Index( + mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed)}] - + model.populations[{ + mio::Index( + mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Infected)}] - + model.populations[{ + mio::Index( + mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Recovered)}]; + } model.set_commuting_strengths(); } }; TEST_F(ModelTestOdeMetapop, simulateDefault) { - mio::TimeSeries result = simulate(t0, tmax, dt, model); + mio::TimeSeries result = simulate(t0, tmax, dt, model); EXPECT_NEAR(result.get_last_time(), tmax, 1e-10); } TEST_F(ModelTestOdeMetapop, checkPopulationConservation) { - auto result = simulate(t0, tmax, dt, model); - double num_persons = result.get_last_value().sum(); - EXPECT_NEAR(num_persons, total_population, 1e-8); + auto result = simulate(t0, tmax, dt, model); + ScalarType num_persons = result.get_last_value().sum(); + EXPECT_NEAR(num_persons, total_population_per_region * (size_t)model.parameters.get_num_regions(), 1e-9); } TEST_F(ModelTestOdeMetapop, check_constraints_parameters) { - model.parameters.set>(5.2); - model.parameters.set>(6); - model.parameters.set>(0.04); + model.parameters.set>(5.2); + model.parameters.set>(6); + model.parameters.set>(0.04); + + model.parameters.get>().get_cont_freq_mat()[0].get_baseline()(0, 0) = + 10; - model.parameters.get>().get_cont_freq_mat()[0].get_baseline()(0, 0) = 10; + Eigen::MatrixXd mobility_data_commuter((size_t)model.parameters.get_num_regions(), + (size_t)model.parameters.get_num_regions()); + mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0.0, 0.5, 0.5, 0., 0., 0., 0., 1.; + model.set_commuting_strengths(mobility_data_commuter); // model.check_constraints() combines the functions from population and parameters. // We only want to test the functions for the parameters defined in parameters.h ASSERT_EQ(model.parameters.check_constraints(), 0); mio::set_log_level(mio::LogLevel::off); - model.parameters.set>(-5.2); + model.parameters.set>(-5.2); ASSERT_EQ(model.parameters.check_constraints(), 1); - model.parameters.set>(5.2); - model.parameters.set>(0); + model.parameters.set>(5.2); + model.parameters.set>(0); ASSERT_EQ(model.parameters.check_constraints(), 1); - model.parameters.set>(6); - model.parameters.set>(10.); + model.parameters.set>(6); + model.parameters.set>(10.); ASSERT_EQ(model.parameters.check_constraints(), 1); + + model.parameters.set>(0.04); + mobility_data_commuter(0, 1) += 0.5; + model.set_commuting_strengths(mobility_data_commuter); + ASSERT_EQ(model.parameters.check_constraints(), 1); + + mobility_data_commuter(0, 1) = -0.5; + model.set_commuting_strengths(mobility_data_commuter); + ASSERT_EQ(model.parameters.check_constraints(), 1); + + mobility_data_commuter(0, 1) = 1.5; + model.set_commuting_strengths(mobility_data_commuter); + ASSERT_EQ(model.parameters.check_constraints(), 1); + mio::set_log_level(mio::LogLevel::warn); } TEST_F(ModelTestOdeMetapop, apply_constraints_parameters) { - const double tol_times = 1e-1; - model.parameters.set>(5.2); - model.parameters.set>(2); - model.parameters.set>(0.04); + const ScalarType tol_times = 1e-1; + model.parameters.set>(5.2); + model.parameters.set>(2); + model.parameters.set>(0.04); mio::ContactMatrixGroup& contact_matrix = - model.parameters.get>().get_cont_freq_mat(); + model.parameters.get>().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(10); + Eigen::MatrixXd mobility_data_commuter((size_t)model.parameters.get_num_regions(), + (size_t)model.parameters.get_num_regions()); + mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0.0, 0.5, 0.5, 0., 0., 0., 0., 1.; + model.set_commuting_strengths(mobility_data_commuter); + EXPECT_EQ(model.parameters.apply_constraints(), 0); mio::set_log_level(mio::LogLevel::off); - model.parameters.set>(-5.2); + model.parameters.set>(-5.2); EXPECT_EQ(model.parameters.apply_constraints(), 1); - EXPECT_EQ(model.parameters.get>()[(mio::AgeGroup)0], tol_times); + EXPECT_EQ(model.parameters.get>()[(mio::AgeGroup)0], tol_times); - model.parameters.set>(1e-5); + model.parameters.set>(1e-5); EXPECT_EQ(model.parameters.apply_constraints(), 1); - EXPECT_EQ(model.parameters.get>()[(mio::AgeGroup)0], tol_times); + EXPECT_EQ(model.parameters.get>()[(mio::AgeGroup)0], tol_times); - model.parameters.set>(10.); + model.parameters.set>(10.); EXPECT_EQ(model.parameters.apply_constraints(), 1); - EXPECT_NEAR(model.parameters.get>()[(mio::AgeGroup)0], - 0.0, 1e-14); + EXPECT_NEAR( + model.parameters.get>()[(mio::AgeGroup)0], 0.0, + 1e-14); + + model.parameters.set>(0.04); + mobility_data_commuter(0, 1) += 0.5; + model.set_commuting_strengths(mobility_data_commuter); + ASSERT_EQ(model.parameters.apply_constraints(), 1); + ASSERT_EQ(model.parameters.get>() + .get_cont_freq_mat()[0] + .get_baseline() + .isIdentity(), + true); + + mobility_data_commuter(0, 1) = -0.5; + model.set_commuting_strengths(mobility_data_commuter); + ASSERT_EQ(model.parameters.apply_constraints(), 1); + ASSERT_EQ(model.parameters.get>() + .get_cont_freq_mat()[0] + .get_baseline() + .isIdentity(), + true); + + mobility_data_commuter(0, 1) = 1.5; + model.set_commuting_strengths(mobility_data_commuter); + ASSERT_EQ(model.parameters.apply_constraints(), 1); + ASSERT_EQ(model.parameters.get>() + .get_cont_freq_mat()[0] + .get_baseline() + .isIdentity(), + true); + mio::set_log_level(mio::LogLevel::warn); } -// TEST_F(ModelTestOdeMetapop, compareSEIR) -// { -// model.parameters.set>(5.2); -// model.parameters.set>(2); -// model.parameters.set>(1.); -// model.parameters.get>().get_cont_freq_mat()[0].get_baseline()(0, 0) = -// 2.7; -// model.parameters.get>().get_cont_freq_mat()[0].add_damping( -// 0.6, mio::SimulationTime(12.5)); - -// model.check_constraints(); - -// auto result = simulate(t0, tmax, dt, model); -// std::vector> refData = load_test_data_csv("seir-compare.csv"); - -// ASSERT_EQ(refData.size(), static_cast(result.get_num_time_points())); - -// for (Eigen::Index irow = 0; irow < result.get_num_time_points(); ++irow) { -// double t = refData[static_cast(irow)][0]; -// auto rel_tol = 1e-6; - -// //test result diverges at damping because of changes, not worth fixing at the moment -// if (t > 11.0 && t < 13.0) { -// //strong divergence around damping -// rel_tol = 0.5; -// } -// else if (t > 13.0) { -// //minor divergence after damping -// rel_tol = 1e-2; -// } -// mio::unused(rel_tol); - -// ASSERT_NEAR(t, result.get_times()[irow], 1e-12) << "at row " << irow; - -// for (size_t icol = 0; icol < refData[static_cast(irow)].size() - 1; ++icol) { -// double ref = refData[static_cast(irow)][icol + 1]; -// double actual = result[irow][icol]; - -// double tol = rel_tol * ref; -// ASSERT_NEAR(ref, actual, tol) << "at row " << irow; -// } -// } -// } - -// TEST_F(ModelTestOdeMetapop, compareWithPreviousRun) -// { -// // initialization -// double t0 = 0.; -// double tmax = 3.; -// double dt = 0.1; - -// size_t number_regions = 4; -// size_t number_age_groups = 2; -// size_t total_population_per_region = 5000; - -// mio::oseirmetapop::Model model(number_regions, number_age_groups); - -// for (size_t age = 0; age < number_age_groups; age++) { -// for (size_t i = 0; i < number_regions; i++) { -// model.populations[{mio::Index( -// mio::oseirmetapop::Region(i), mio::AgeGroup(age), mio::oseirmetapop::InfectionState::Infected)}] = 50; -// model.populations[{mio::Index( -// mio::oseirmetapop::Region(i), mio::AgeGroup(age), mio::oseirmetapop::InfectionState::Recovered)}] = 0; -// model.populations[{mio::Index( -// mio::oseirmetapop::Region(i), mio::AgeGroup(age), mio::oseirmetapop::InfectionState::Susceptible)}] = -// total_population_per_region - -// model.populations[{mio::Index( -// mio::oseirmetapop::Region(i), mio::AgeGroup(age), mio::oseirmetapop::InfectionState::Infected)}] - -// model.populations[{mio::Index( -// mio::oseirmetapop::Region(i), mio::AgeGroup(age), mio::oseirmetapop::InfectionState::Recovered)}]; -// } -// } -// model.parameters.template set>(1.0); -// model.parameters.set>(2); - -// model.parameters.get>().get_cont_freq_mat()[0].get_baseline().setConstant(2.7); -// model.parameters.get>().get_cont_freq_mat()[0].add_damping( -// 0.6, mio::SimulationTime(12.5)); - -// Eigen::MatrixXd mobility_data_commuter(4, 4); -// mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0.5, 0., 0.5, 0., 0., 0., 0., 1.; -// model.parameters.template get>().get_cont_freq_mat()[0].get_baseline() = -// mobility_data_commuter; - -// std::vector> refData = load_test_data_csv("ode-seir-metapop-compare.csv"); -// std::shared_ptr> integrator = std::make_shared>(); -// auto result = mio::simulate>(t0, tmax, dt, model, integrator); - -// ASSERT_EQ(refData.size(), static_cast(result.get_num_time_points())); - -// for (Eigen::Index irow = 0; irow < result.get_num_time_points(); ++irow) { -// double t = refData[static_cast(irow)][0]; -// auto rel_tol = 1e-6; - -// //test result diverges at damping because of changes, not worth fixing at the moment -// if (t > 11.0 && t < 13.0) { -// //strong divergence around damping -// rel_tol = 0.5; -// } -// else if (t > 13.0) { -// //minor divergence after damping -// rel_tol = 1e-2; -// } -// mio::unused(rel_tol); - -// ASSERT_NEAR(t, result.get_times()[irow], 1e-12) << "at row " << irow; - -// for (size_t icol = 0; icol < 12; ++icol) { -// double ref = refData[static_cast(irow)][icol + 1]; -// double actual = result[irow][icol]; - -// double tol = rel_tol * ref; -// ASSERT_NEAR(ref, actual, tol) << "at row " << irow; -// } -// } -// } +TEST(TestOdeMetapop, compareSEIR) +{ + ScalarType t0 = 0; + ScalarType tmax = 50.; + ScalarType dt = 0.1; + + ScalarType total_population = 1061000; + + mio::oseirmetapop::Model model(1, 1); + + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed)}] = 10000; + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Infected)}] = 1000; + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible)}] = + total_population - + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed)}] - + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Infected)}] - + model.populations[{mio::Index( + mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Recovered)}]; + + // The model with a single region should correspond to the SEIR model. + model.parameters.set>(5.2); + model.parameters.set>(6); + model.parameters.set>(0.1); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get>(); + contact_matrix[0].get_baseline().setConstant(2.7); + contact_matrix[0].add_damping(0.6, mio::SimulationTime(12.5)); + + model.set_commuting_strengths(); + + model.check_constraints(); + + // Use the Euler integrator as adaptive methods make different time steps in this model due to restructured equations. + std::shared_ptr> integrator = std::make_shared>(); + + auto result = simulate(t0, tmax, dt, model, integrator); + std::vector> refData = load_test_data_csv("seir-compare-euler.csv"); + + ASSERT_EQ(refData.size(), static_cast(result.get_num_time_points())); + + for (Eigen::Index irow = 0; irow < result.get_num_time_points(); ++irow) { + ScalarType t = refData[static_cast(irow)][0]; + auto rel_tol = 1e-10; + + //test result diverges at damping because of changes, not worth fixing at the moment + if (t > 11.0 && t < 13.0) { + //strong divergence around damping + rel_tol = 0.5; + } + else if (t > 13.0) { + //minor divergence after damping + rel_tol = 1e-2; + } + mio::unused(rel_tol); + + ASSERT_NEAR(t, result.get_times()[irow], 1e-12) << "at row " << irow; + + for (size_t icol = 0; icol < refData[static_cast(irow)].size() - 1; ++icol) { + ScalarType ref = refData[static_cast(irow)][icol + 1]; + ScalarType actual = result[irow][icol]; + + ScalarType tol = rel_tol * ref; + ASSERT_NEAR(ref, actual, tol) << "at row " << irow; + } + } +} + +TEST_F(ModelTestOdeMetapop, compareWithPreviousRun) +{ + model.parameters.set>(5.2); + model.parameters.set>(6); + model.parameters.set>(0.1); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get>(); + contact_matrix[0].get_baseline().setConstant(2.7); + contact_matrix[0].add_damping(0.6, mio::SimulationTime(12.5)); + + Eigen::MatrixXd mobility_data_commuter((size_t)model.parameters.get_num_regions(), + (size_t)model.parameters.get_num_regions()); + mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0.0, 0.5, 0.5, 0., 0., 0., 0., 1.; + model.set_commuting_strengths(mobility_data_commuter); + + std::vector> refData = load_test_data_csv("ode-seir-metapop-compare.csv"); + std::shared_ptr> integrator = std::make_shared>(); + auto result = mio::simulate>(t0, tmax, dt, model, integrator); + + ASSERT_EQ(refData.size(), static_cast(result.get_num_time_points())); + + for (Eigen::Index irow = 0; irow < result.get_num_time_points(); ++irow) { + double t = refData[static_cast(irow)][0]; + auto rel_tol = 1e-6; + + //test result diverges at damping because of changes, not worth fixing at the moment + if (t > 11.0 && t < 13.0) { + //strong divergence around damping + rel_tol = 0.5; + } + else if (t > 13.0) { + //minor divergence after damping + rel_tol = 1e-2; + } + mio::unused(rel_tol); + + ASSERT_NEAR(t, result.get_times()[irow], 1e-12) << "at row " << irow; + + for (size_t icol = 0; icol < 12; ++icol) { + double ref = refData[static_cast(irow)][icol + 1]; + double actual = result[irow][icol]; + + double tol = rel_tol * ref; + ASSERT_NEAR(ref, actual, tol) << "at row " << irow; + } + } +} From e2f38648d06d9552e3a59c123d75b335648c2377 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Mon, 5 May 2025 15:19:01 +0200 Subject: [PATCH 86/87] continue working on tests and restructure population after commuting --- .../examples_thesis/ode_metapop_nrw.cpp | 5 +- cpp/models/ode_metapop/model.h | 22 +++--- cpp/models/ode_metapop/parameters.h | 73 +++++++++++++------ cpp/tests/test_odemetapop.cpp | 61 +++++++++++++--- 4 files changed, 115 insertions(+), 46 deletions(-) diff --git a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp index 2352c33bc9..7f4db879b3 100644 --- a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp +++ b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp @@ -122,10 +122,7 @@ mio::IOResult set_mobility_weights(mio::oseirmetapop::Model& model, co { size_t number_regions = (size_t)model.parameters.get_num_regions(); if (number_regions == 1) { - model.parameters.template get>() - .get_cont_freq_mat()[0] - .get_baseline() - .setConstant(1.0); + model.set_commuting_strengths(); return mio::success(); } diff --git a/cpp/models/ode_metapop/model.h b/cpp/models/ode_metapop/model.h index e560a20c16..47906d1232 100644 --- a/cpp/models/ode_metapop/model.h +++ b/cpp/models/ode_metapop/model.h @@ -43,8 +43,6 @@ class Model : public FlowModel({Region(num_regions), AgeGroup(num_agegroups)})) { } @@ -69,7 +67,7 @@ class Model : public FlowModel>()[{Region(region_n), AgeGroup(age_i)}]; } } Eigen::MatrixXd infections_due_commuting = commuting_strengths * infectious_share_per_region; @@ -132,6 +130,7 @@ class Model : public FlowModel>(); ContactMatrixGroup const& commuting_strengths = params.template get>(); + Populations const& population_after_commuting = params.template get>(); Eigen::MatrixXd F = Eigen::MatrixXd::Zero(total_infected_compartments, total_infected_compartments); Eigen::MatrixXd V = Eigen::MatrixXd::Zero(total_infected_compartments, total_infected_compartments); @@ -157,7 +156,7 @@ class Model : public FlowModelparameters.template get>().get_cont_freq_mat()[0].get_baseline(); commuting_strengths_param = commuting_strengths; - auto number_regions = (size_t)this->parameters.get_num_regions(); - auto number_age_groups = (size_t)this->parameters.get_num_agegroups(); - auto& population = this->populations; + auto number_regions = (size_t)this->parameters.get_num_regions(); + auto number_age_groups = (size_t)this->parameters.get_num_agegroups(); + auto& population = this->populations; + auto& population_after_commuting = this->parameters.template get>(); for (size_t region_n = 0; region_n < number_regions; ++region_n) { for (size_t age = 0; age < number_age_groups; ++age) { @@ -224,11 +224,11 @@ class Model : public FlowModelparameters.get_num_regions(); set_commuting_strengths(Eigen::MatrixXd::Identity(number_regions, number_regions)); } - - mio::Populations m_population_after_commuting; }; // namespace oseirmetapop } // namespace oseirmetapop diff --git a/cpp/models/ode_metapop/parameters.h b/cpp/models/ode_metapop/parameters.h index b410f2d86e..70bc13043b 100644 --- a/cpp/models/ode_metapop/parameters.h +++ b/cpp/models/ode_metapop/parameters.h @@ -101,9 +101,22 @@ struct CommutingStrengths { } }; +template +struct PopulationAfterCommuting { + using Type = Populations; + static Type get_default(Region size_regions, AgeGroup size_agegroups) + { + return Type({size_regions, size_agegroups}, 0.); + } + static std::string name() + { + return "PopulationAfterCommuting"; + } +}; + template using ParametersBase = ParameterSet, TimeExposed, TimeInfected, - ContactPatterns, CommutingStrengths>; + ContactPatterns, CommutingStrengths, PopulationAfterCommuting>; /** * @brief Parameters of SEIR model. @@ -175,19 +188,29 @@ class Parameters : public ParametersBase this->template get>() = 0.0; corrected = true; } - if ((this->template get>().get_cont_freq_mat().get_matrix_at(0).rowwise().sum() - - Eigen::VectorXd::Ones((size_t)this->get_num_regions())) - .cwiseAbs() - .maxCoeff() > 1e-10 || - this->template get>().get_cont_freq_mat().get_matrix_at(0).minCoeff() < 0.0 || - this->template get>().get_cont_freq_mat().get_matrix_at(0).maxCoeff() > 1.0) { - log_warning("Constraint check: Parameter CommutingStrengths does not ensure that the number of people " - "staying equals the complement of those leaving. Running without commuting."); - this->template get>().get_cont_freq_mat()[0].get_baseline() = - Eigen::MatrixXd::Identity((size_t)this->get_num_regions(), (size_t)this->get_num_regions()); - return true; + for (auto j = Region(0); j < Region(m_num_regions); j++) { + if (this->template get>()[{j, i}] <= 0.0) { + log_warning( + "Constraint check: Parameter PopulationAfterCommuting changed from {:.4f} to {:.4f}. Please " + "note that this only prevents division by zero. Consider to cancel and reset parameters.", + this->template get>()[{j, i}], 1.0); + this->template get>()[{j, i}] = 1.0; + corrected = true; + } } } + if ((this->template get>().get_cont_freq_mat().get_matrix_at(0).rowwise().sum() - + Eigen::VectorXd::Ones((size_t)this->get_num_regions())) + .cwiseAbs() + .maxCoeff() > 1e-10 || + this->template get>().get_cont_freq_mat().get_matrix_at(0).minCoeff() < 0.0 || + this->template get>().get_cont_freq_mat().get_matrix_at(0).maxCoeff() > 1.0) { + log_warning("Constraint check: Parameter CommutingStrengths does not ensure that the number of people " + "staying equals the complement of those leaving. Running without commuting."); + this->template get>().get_cont_freq_mat()[0].get_baseline() = + Eigen::MatrixXd::Identity((size_t)this->get_num_regions(), (size_t)this->get_num_regions()); + corrected = true; + } return corrected; } @@ -224,17 +247,25 @@ class Parameters : public ParametersBase this->template get>()[i], 0.0, 1.0); return true; } - if ((this->template get>().get_cont_freq_mat().get_matrix_at(0).rowwise().sum() - - Eigen::VectorXd::Ones((size_t)this->get_num_regions())) - .cwiseAbs() - .maxCoeff() > 1e-10 || - this->template get>().get_cont_freq_mat().get_matrix_at(0).minCoeff() < 0.0 || - this->template get>().get_cont_freq_mat().get_matrix_at(0).maxCoeff() > 1.0) { - log_error("Constraint check: Parameter CommutingStrengths does not ensure that the number of people " - "staying equals the complement of those leaving."); - return true; + for (auto j = Region(0); j < Region(m_num_regions); j++) { + if (this->template get>()[{j, i}] <= 0.0) { + log_error("Constraint check: Parameter PopulationAfterCommuting {:.4f} smaller or equal {:.4f}", + this->template get>()[{j, i}], 0.0); + return true; + } } } + if ((this->template get>().get_cont_freq_mat().get_matrix_at(0).rowwise().sum() - + Eigen::VectorXd::Ones((size_t)this->get_num_regions())) + .cwiseAbs() + .maxCoeff() > 1e-10 || + this->template get>().get_cont_freq_mat().get_matrix_at(0).minCoeff() < 0.0 || + this->template get>().get_cont_freq_mat().get_matrix_at(0).maxCoeff() > 1.0) { + log_error("Constraint check: Parameter CommutingStrengths does not ensure that the number of people " + "staying equals the complement of those leaving."); + return true; + } + return false; } diff --git a/cpp/tests/test_odemetapop.cpp b/cpp/tests/test_odemetapop.cpp index 0ebaa64606..bfedc322b5 100644 --- a/cpp/tests/test_odemetapop.cpp +++ b/cpp/tests/test_odemetapop.cpp @@ -82,7 +82,7 @@ TEST_F(ModelTestOdeMetapop, check_constraints_parameters) Eigen::MatrixXd mobility_data_commuter((size_t)model.parameters.get_num_regions(), (size_t)model.parameters.get_num_regions()); - mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0.0, 0.5, 0.5, 0., 0., 0., 0., 1.; + mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0., 0.5, 0.5, 0., 0., 0., 0., 1.; model.set_commuting_strengths(mobility_data_commuter); // model.check_constraints() combines the functions from population and parameters. @@ -107,10 +107,29 @@ TEST_F(ModelTestOdeMetapop, check_constraints_parameters) ASSERT_EQ(model.parameters.check_constraints(), 1); mobility_data_commuter(0, 1) = -0.5; + mobility_data_commuter(0, 2) = 0.75; + mobility_data_commuter(0, 3) = 0.75; model.set_commuting_strengths(mobility_data_commuter); ASSERT_EQ(model.parameters.check_constraints(), 1); mobility_data_commuter(0, 1) = 1.5; + mobility_data_commuter(0, 2) = 0.; + mobility_data_commuter(0, 3) = 0.; + model.set_commuting_strengths(mobility_data_commuter); + ASSERT_EQ(model.parameters.check_constraints(), 1); + + mobility_data_commuter(0, 0) = 0.; + mobility_data_commuter(0, 1) = 0.; + mobility_data_commuter(0, 2) = 0.; + mobility_data_commuter(0, 3) = 1.; + model.set_commuting_strengths(mobility_data_commuter); + model.parameters.set>( + mio::Populations( + {mio::oseirmetapop::Region(4), mio::AgeGroup(1)}, 0.)); + ASSERT_EQ(model.parameters.check_constraints(), 1); + + // Nobody commutes to region 2 + mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0., 0., 0.5, 0.5, 0., 0., 0., 1.; model.set_commuting_strengths(mobility_data_commuter); ASSERT_EQ(model.parameters.check_constraints(), 1); @@ -129,7 +148,7 @@ TEST_F(ModelTestOdeMetapop, apply_constraints_parameters) Eigen::MatrixXd mobility_data_commuter((size_t)model.parameters.get_num_regions(), (size_t)model.parameters.get_num_regions()); - mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0.0, 0.5, 0.5, 0., 0., 0., 0., 1.; + mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0., 0.5, 0.5, 0., 0., 0., 0., 1.; model.set_commuting_strengths(mobility_data_commuter); EXPECT_EQ(model.parameters.apply_constraints(), 0); @@ -152,31 +171,55 @@ TEST_F(ModelTestOdeMetapop, apply_constraints_parameters) model.parameters.set>(0.04); mobility_data_commuter(0, 1) += 0.5; model.set_commuting_strengths(mobility_data_commuter); - ASSERT_EQ(model.parameters.apply_constraints(), 1); - ASSERT_EQ(model.parameters.get>() + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_EQ(model.parameters.get>() .get_cont_freq_mat()[0] .get_baseline() .isIdentity(), true); mobility_data_commuter(0, 1) = -0.5; + mobility_data_commuter(0, 2) = 0.75; + mobility_data_commuter(0, 3) = 0.75; model.set_commuting_strengths(mobility_data_commuter); - ASSERT_EQ(model.parameters.apply_constraints(), 1); - ASSERT_EQ(model.parameters.get>() + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_EQ(model.parameters.get>() .get_cont_freq_mat()[0] .get_baseline() .isIdentity(), true); mobility_data_commuter(0, 1) = 1.5; + mobility_data_commuter(0, 2) = 0.; + mobility_data_commuter(0, 3) = 0.; model.set_commuting_strengths(mobility_data_commuter); - ASSERT_EQ(model.parameters.apply_constraints(), 1); - ASSERT_EQ(model.parameters.get>() + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_EQ(model.parameters.get>() .get_cont_freq_mat()[0] .get_baseline() .isIdentity(), true); + mobility_data_commuter(0, 0) = 0.; + mobility_data_commuter(0, 1) = 0.; + mobility_data_commuter(0, 2) = 0.; + mobility_data_commuter(0, 3) = 1.; + model.set_commuting_strengths(mobility_data_commuter); + model.parameters.set>( + mio::Populations( + {mio::oseirmetapop::Region(4), mio::AgeGroup(1)}, 0.)); + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_NEAR((model.parameters.get>()[{ + mio::oseirmetapop::Region(3), mio::AgeGroup(0)}]), + 1.0, tol_times); + + mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0., 0., 0.5, 0.5, 0., 0., 0., 1.; + model.set_commuting_strengths(mobility_data_commuter); + EXPECT_EQ(model.parameters.apply_constraints(), 1); + EXPECT_NEAR((model.parameters.get>()[{ + mio::oseirmetapop::Region(1), mio::AgeGroup(0)}]), + 1.0, tol_times); + mio::set_log_level(mio::LogLevel::warn); } @@ -264,7 +307,7 @@ TEST_F(ModelTestOdeMetapop, compareWithPreviousRun) Eigen::MatrixXd mobility_data_commuter((size_t)model.parameters.get_num_regions(), (size_t)model.parameters.get_num_regions()); - mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0.0, 0.5, 0.5, 0., 0., 0., 0., 1.; + mobility_data_commuter << 0., 0., 0., 1., 0.2, 0., 0.6, 0.2, 0., 0.5, 0.5, 0., 0., 0., 0., 1.; model.set_commuting_strengths(mobility_data_commuter); std::vector> refData = load_test_data_csv("ode-seir-metapop-compare.csv"); From 67e6d2236dfd858aea08901890af16aca1907cac Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Mon, 12 May 2025 10:54:44 +0200 Subject: [PATCH 87/87] add minimal metapop example --- cpp/examples/CMakeLists.txt | 4 +++ cpp/examples/ode_seir_metapop.cpp | 47 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 cpp/examples/ode_seir_metapop.cpp diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 80bbccb715..60b4ce4e9d 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -45,6 +45,10 @@ add_executable(ode_metapop_steps examples_thesis/ode_metapop_steps.cpp) target_link_libraries(ode_metapop_steps PRIVATE memilio ode_metapop) target_compile_options(ode_metapop_steps PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ode_metapop_seir_example ode_seir_metapop.cpp) +target_link_libraries(ode_metapop_seir_example PRIVATE memilio ode_metapop) +target_compile_options(ode_metapop_seir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(basic_reproduction_number_modela examples_thesis/basic_reproduction_number_modela.cpp) target_link_libraries(basic_reproduction_number_modela PRIVATE memilio ode_seir) target_compile_options(basic_reproduction_number_modela PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/examples/ode_seir_metapop.cpp b/cpp/examples/ode_seir_metapop.cpp new file mode 100644 index 0000000000..0c7519b1b0 --- /dev/null +++ b/cpp/examples/ode_seir_metapop.cpp @@ -0,0 +1,47 @@ +#include "memilio/compartments/simulation.h" +#include "memilio/utils/custom_index_array.h" +#include "models/ode_metapop/infection_state.h" +#include "models/ode_metapop/model.h" +#include "models/ode_metapop/parameters.h" +#include "models/ode_metapop/regions.h" + +#include + +int main() +{ + const ScalarType t0 = 0.; + const ScalarType tmax = 10; + ScalarType dt = 0.1; + + size_t number_regions = 3; + size_t number_age_groups = 1; + + mio::oseirmetapop::Model model(number_regions, number_age_groups); + + for (size_t i = 0; i < number_regions; i++) { + model.populations[{mio::oseirmetapop::Region(i), mio::AgeGroup(0), + mio::oseirmetapop::InfectionState::Susceptible}] = 10000; + } + + model.populations[{mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed}] += + 100; + model.populations[{mio::oseirmetapop::Region(0), mio::AgeGroup(0), + mio::oseirmetapop::InfectionState::Susceptible}] -= 100; + + Eigen::MatrixXd mobility_data_commuter(3, 3); + mobility_data_commuter << 0.4, 0.3, 0.3, 0.2, 0.7, 0.1, 0.4, 0.1, 0.5; + + model.set_commuting_strengths(mobility_data_commuter); + + model.parameters.template get>() + .get_cont_freq_mat()[0] + .get_baseline() + .setConstant(2.7); + + model.parameters.set>(3.335); + model.parameters.set>(8.097612257); + model.parameters.set>(0.07333); + + auto result = simulate(t0, tmax, dt, model); + return 0; +}