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 001/105] 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 002/105] 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 003/105] 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 004/105] 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 005/105] 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 006/105] 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 007/105] 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 008/105] 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 009/105] 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 010/105] 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 011/105] 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 012/105] 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 013/105] 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 014/105] 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 015/105] 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 016/105] 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 017/105] 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 018/105] 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 019/105] 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 020/105] 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 021/105] 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 022/105] 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 023/105] 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 024/105] 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 025/105] 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 026/105] 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 027/105] 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 028/105] 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 029/105] 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 030/105] 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 031/105] 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 032/105] 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 033/105] 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 034/105] 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 035/105] 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 036/105] 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 037/105] 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 038/105] 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 039/105] 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 040/105] 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 041/105] 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 042/105] 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 043/105] 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 044/105] 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 045/105] 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 046/105] 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 047/105] 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 048/105] 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 049/105] 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 050/105] 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 051/105] 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 052/105] 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 053/105] 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 054/105] 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 055/105] 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 056/105] 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 057/105] 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 058/105] 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 059/105] 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 060/105] 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 061/105] 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 062/105] 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 063/105] 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 064/105] 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 065/105] 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 066/105] 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 067/105] 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 068/105] 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 069/105] 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 070/105] 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 071/105] 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 072/105] 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 073/105] 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 074/105] 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 075/105] 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 076/105] 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 077/105] 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 078/105] 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 079/105] 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 080/105] 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 081/105] 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 082/105] 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 083/105] 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 084/105] 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 085/105] 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 086/105] 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 087/105] 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; +} From 77f2d972ac5a17ca76856de14a1f16b86ddc2c63 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Mon, 12 May 2025 14:21:35 +0200 Subject: [PATCH 088/105] delete thesis examples and rename model --- cpp/CMakeLists.txt | 3 +- cpp/examples/CMakeLists.txt | 54 +- .../basic_reproduction_number_modela.cpp | 64 --- .../basic_reproduction_number_modelb.cpp | 78 --- .../basic_reproduction_number_modelc.cpp | 98 ---- cpp/examples/examples_thesis/graph_nrw.cpp | 209 -------- cpp/examples/examples_thesis/graph_steps.cpp | 164 ------ cpp/examples/examples_thesis/graph_timing.cpp | 181 ------- .../examples_thesis/ode_metapop_nrw.cpp | 201 -------- .../examples_thesis/ode_metapop_steps.cpp | 159 ------ .../examples_thesis/ode_metapop_timing.cpp | 189 ------- .../examples_thesis/ode_metapop_wang_nrw.cpp | 202 -------- cpp/examples/ode_seir_metapop.cpp | 8 +- cpp/models/ode_metapop/CMakeLists.txt | 13 - cpp/models/ode_metapop_wang/infection_state.h | 26 - cpp/models/ode_metapop_wang/model.cpp | 10 - cpp/models/ode_metapop_wang/model.h | 216 -------- cpp/models/ode_metapop_wang/parameters.h | 244 --------- cpp/models/ode_metapop_wang/regions.h | 26 - .../CMakeLists.txt | 8 +- .../infection_state.h | 4 +- .../model.cpp | 0 .../{ode_metapop => ode_seir_metapop}/model.h | 10 +- .../parameters.h | 4 +- .../regions.h | 4 +- cpp/tests/data/seir-compare.csv | 2 +- docs/source/cpp/deterministic_metapop.rst | 48 ++ shellscripts/likwid_equationbased.sh | 28 -- shellscripts/likwid_graphbased.sh | 27 - shellscripts/likwid_test.sh | 16 - shellscripts/steps_mobilitymodels.sh | 20 - shellscripts/timing_mobilitymodels.sh | 27 - tools/basic_reproduction_numbers.py | 40 -- tools/plot_mobility_runtimes.py | 236 --------- tools/plot_results_mobility.py | 475 ------------------ 35 files changed, 73 insertions(+), 3021 deletions(-) delete mode 100644 cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp delete mode 100644 cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp delete mode 100644 cpp/examples/examples_thesis/basic_reproduction_number_modelc.cpp delete mode 100644 cpp/examples/examples_thesis/graph_nrw.cpp delete mode 100644 cpp/examples/examples_thesis/graph_steps.cpp delete mode 100644 cpp/examples/examples_thesis/graph_timing.cpp delete mode 100644 cpp/examples/examples_thesis/ode_metapop_nrw.cpp delete mode 100644 cpp/examples/examples_thesis/ode_metapop_steps.cpp delete mode 100644 cpp/examples/examples_thesis/ode_metapop_timing.cpp delete mode 100644 cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp delete mode 100644 cpp/models/ode_metapop/CMakeLists.txt delete mode 100644 cpp/models/ode_metapop_wang/infection_state.h delete mode 100644 cpp/models/ode_metapop_wang/model.cpp delete mode 100644 cpp/models/ode_metapop_wang/model.h delete mode 100644 cpp/models/ode_metapop_wang/parameters.h delete mode 100644 cpp/models/ode_metapop_wang/regions.h rename cpp/models/{ode_metapop_wang => ode_seir_metapop}/CMakeLists.txt (52%) rename cpp/models/{ode_metapop => ode_seir_metapop}/infection_state.h (78%) rename cpp/models/{ode_metapop => ode_seir_metapop}/model.cpp (100%) rename cpp/models/{ode_metapop => ode_seir_metapop}/model.h (98%) rename cpp/models/{ode_metapop => ode_seir_metapop}/parameters.h (99%) rename cpp/models/{ode_metapop => ode_seir_metapop}/regions.h (80%) create mode 100644 docs/source/cpp/deterministic_metapop.rst delete mode 100644 shellscripts/likwid_equationbased.sh delete mode 100644 shellscripts/likwid_graphbased.sh delete mode 100644 shellscripts/likwid_test.sh delete mode 100644 shellscripts/steps_mobilitymodels.sh delete mode 100644 shellscripts/timing_mobilitymodels.sh delete mode 100644 tools/basic_reproduction_numbers.py delete mode 100644 tools/plot_mobility_runtimes.py delete mode 100644 tools/plot_results_mobility.py diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 7d3c2f66c5..a3427928c8 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -163,8 +163,7 @@ if(MEMILIO_BUILD_MODELS) add_subdirectory(models/ode_seir) add_subdirectory(models/ode_seair) add_subdirectory(models/ode_sir) - add_subdirectory(models/ode_metapop) - add_subdirectory(models/ode_metapop_wang) + add_subdirectory(models/ode_seir_metapop) 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 06b8e5336d..96683ebd9d 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -30,41 +30,6 @@ 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_wang_nrw examples_thesis/ode_metapop_wang_nrw.cpp) -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) - 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_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}) - -add_executable(basic_reproduction_number_modelb examples_thesis/basic_reproduction_number_modelb.cpp) -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_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) target_compile_options(sde_sirs_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) @@ -127,25 +92,14 @@ add_executable(ode_secir_graph_example ode_secir_graph.cpp) target_link_libraries(ode_secir_graph_example PRIVATE memilio ode_secir) target_compile_options(ode_secir_graph_example 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) -target_compile_options(graph_steps PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - -if (MEMILIO_ENABLE_OPENMP) - 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") -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}) +add_executable(ode_metapop_seir_example ode_seir_metapop.cpp) +target_link_libraries(ode_metapop_seir_example PRIVATE memilio ode_seir_metapop) +target_compile_options(ode_metapop_seir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(abm_minimal_example abm_minimal.cpp) target_link_libraries(abm_minimal_example PRIVATE memilio abm) target_compile_options(abm_minimal_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp b/cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp deleted file mode 100644 index aa58d7cbea..0000000000 --- a/cpp/examples/examples_thesis/basic_reproduction_number_modela.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "models/ode_seir/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 deleted file mode 100644 index 401e460b0e..0000000000 --- a/cpp/examples/examples_thesis/basic_reproduction_number_modelb.cpp +++ /dev/null @@ -1,78 +0,0 @@ - -#include "models/ode_metapop_wang/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::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::oseirmetapopwang::Region(i), mio::AgeGroup(j), - mio::oseirmetapopwang::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 deleted file mode 100644 index 683a8500c9..0000000000 --- a/cpp/examples/examples_thesis/basic_reproduction_number_modelc.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#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::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::oseirmetapop::Region(i), mio::AgeGroup(j), - mio::oseirmetapop::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::oseirmetapop::InfectionState::Count; state++) { - population_n += population[{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; - } - } - } - - 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/examples_thesis/graph_nrw.cpp b/cpp/examples/examples_thesis/graph_nrw.cpp deleted file mode 100644 index ead6798cc5..0000000000 --- a/cpp/examples/examples_thesis/graph_nrw.cpp +++ /dev/null @@ -1,209 +0,0 @@ - -#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 "memilio/io/epi_data.h" - -/** - * 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) -{ - 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())); - 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(); -} - -/** - * 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) -{ - 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(); -} - -mio::IOResult>> -set_population_data(const fs::path& data_dir, mio::oseir::Parameters& params, std::vector node_ids) -{ - 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 / "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)); - - 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[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); -} - -mio::IOResult run(const fs::path& data_dir, double t0, double tmax, double dt) -{ - mio::set_log_level(mio::LogLevel::off); - // global parameters - const int num_age_groups = 6; - - mio::oseir::Parameters params(num_age_groups); - - BOOST_OUTCOME_TRY(set_covid_parameters(params)); - - // set contact matrix - BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, params)); - - // graph of counties with populations and local parameters - // and mobility between counties - mio::Graph>>, mio::MobilityEdge<>> params_graph; - - BOOST_OUTCOME_TRY( - auto&& node_ids, - 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)); - 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 / "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, - "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 * size_t(params.get_num_groups()), - commuter_coeff_ij)); - } - } - - auto sim = mio::make_mobility_sim(t0, dt, std::move(params_graph)); - - printf("Start Simulation\n"); - 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, num_age_groups, "graph_result_nrw.h5"); - - return mio::success(); -} - -int main() -{ - const auto t0 = 0.; - const auto tmax = 100.; - 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/examples_thesis/graph_steps.cpp b/cpp/examples/examples_thesis/graph_steps.cpp deleted file mode 100644 index 48f0c6cfeb..0000000000 --- a/cpp/examples/examples_thesis/graph_steps.cpp +++ /dev/null @@ -1,164 +0,0 @@ - -#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(); - - 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) -{ - 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 << "}," << std::endl; - - return 0; -} diff --git a/cpp/examples/examples_thesis/graph_timing.cpp b/cpp/examples/examples_thesis/graph_timing.cpp deleted file mode 100644 index e32abde8b3..0000000000 --- a/cpp/examples/examples_thesis/graph_timing.cpp +++ /dev/null @@ -1,181 +0,0 @@ - -#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 = false; - -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}] = 60000; - } - for (auto& node : nodes) { - node.parameters = params; - node.populations = population; - } - 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)); - } - } - - for (auto& node : params_graph.nodes()) { - node.property.get_simulation().set_integrator(std::make_shared>()); - } -} - -double simulate_runtime(size_t number_regions, ScalarType tmax) -{ - ScalarType t0 = 0.; - ScalarType dt = 0.5; - - 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 start_time = omp_get_wtime(); - sim.advance(tmax); - auto end_time = omp_get_wtime(); - - return end_time - start_time; -} - -void simulate(size_t number_regions, ScalarType tmax) -{ - ScalarType t0 = 0.; - ScalarType dt = 0.5; - - 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); -} - -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; - 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]); - } - - std::cout << "{ \"Regions\": " << num_regions << ", " << std::endl; - // Warm up runs. - for (size_t i = 0; i < warm_up; i++) { - simulate(num_regions, tmax); - } - - // Runs with timing. - ScalarType total = 0; - for (size_t i = 0; i < num_runs; i++) { - double run_time = simulate_runtime(num_regions, tmax); - total += run_time; - } - std::cout << "\"Time\": " << total / num_runs << "\n}," << std::endl; - - return 0; -} diff --git a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp b/cpp/examples/examples_thesis/ode_metapop_nrw.cpp deleted file mode 100644 index 7f4db879b3..0000000000 --- a/cpp/examples/examples_thesis/ode_metapop_nrw.cpp +++ /dev/null @@ -1,201 +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 "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" - -/** - * 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::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; - 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::oseirmetapop::Parameters& params) -{ - //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 / "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; - } - params.get>() = mio::UncertainContactMatrix(contact_matrices); - - printf("Setting contact matrices successful.\n"); - return mio::success(); -} - -template -mio::IOResult set_population_data(mio::oseirmetapop::Model& model, const fs::path& data_dir) -{ - BOOST_OUTCOME_TRY( - auto&& node_ids, - 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 / "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) { - 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::oseirmetapop::Region(region_idx), mio::AgeGroup(age), - mio::oseirmetapop::InfectionState::Susceptible}] = - entry.population[mio::AgeGroup(age)]; - } - } - } - - printf("Setting population data successful.\n"); - return mio::success(); -} - -template -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.set_commuting_strengths(); - - return mio::success(); - } - else { - // mobility between nodes - 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, - "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::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.set_commuting_strengths(mobility_data_commuter); - - printf("Setting mobility weights successful.\n"); - return mio::success(); - } -} - -template -mio::IOResult set_parameters_and_population(mio::oseirmetapop::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::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)); - - BOOST_OUTCOME_TRY(set_contact_matrices(data_dir, parameters)) - - BOOST_OUTCOME_TRY(set_covid_parameters(parameters)); - - return mio::success(); -} - -int main() -{ - mio::set_log_level(mio::LogLevel::debug); - - ScalarType t0 = 0.; - ScalarType tmax = 100.; - ScalarType dt = 0.1; - - ScalarType number_regions = 53; - ScalarType number_age_groups = 6; - - mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - - 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); - - model.check_constraints(); - - printf("Start Simulation\n"); - auto result_from_sim = simulate(t0, tmax, dt, model); - - 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.h5"); -} diff --git a/cpp/examples/examples_thesis/ode_metapop_steps.cpp b/cpp/examples/examples_thesis/ode_metapop_steps.cpp deleted file mode 100644 index 7c6cb369a0..0000000000 --- a/cpp/examples/examples_thesis/ode_metapop_steps.cpp +++ /dev/null @@ -1,159 +0,0 @@ - -#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 - -bool age_groups = true; - -template -void set_contact_matrix(mio::oseirmetapop::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::oseirmetapop::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::oseirmetapop::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::oseirmetapop::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::oseirmetapop::Region(i), mio::AgeGroup(j), - 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; - 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::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; - } - } - } -} - -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::oseirmetapop::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; -} diff --git a/cpp/examples/examples_thesis/ode_metapop_timing.cpp b/cpp/examples/examples_thesis/ode_metapop_timing.cpp deleted file mode 100644 index 7d09b72721..0000000000 --- a/cpp/examples/examples_thesis/ode_metapop_timing.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* -* 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_metapop/infection_state.h" -#include "models/ode_metapop/model.h" -#include "models/ode_metapop/parameters.h" -#include "models/ode_metapop/regions.h" - -#include - -bool age_groups = false; - -template -void set_contact_matrix(mio::oseirmetapop::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::oseirmetapop::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::oseirmetapop::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::oseirmetapop::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++) { - populations[{mio::oseirmetapop::Region(i), mio::AgeGroup(j), - mio::oseirmetapop::InfectionState::Susceptible}] = 60000; - } - } - 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); - - 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; - } - } - } -} - -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 = 1; - if (age_groups) { - number_age_groups = 6; - } - - mio::oseirmetapop::Model model(number_regions, number_age_groups); - set_parameters_and_population(model); - - 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); - } - auto result = simulate(t0, tmax, dt, model, integrator); - - // Runs with timing. - ScalarType total = 0; - for (size_t i = 0; i < num_runs; i++) { - double runtime = simulate_runtime(t0, tmax, dt, model, integrator); - total += runtime; - } - 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/examples_thesis/ode_metapop_wang_nrw.cpp b/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp deleted file mode 100644 index 62f200fcb8..0000000000 --- a/cpp/examples/examples_thesis/ode_metapop_wang_nrw.cpp +++ /dev/null @@ -1,202 +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 "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" - -/** - * 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::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; - - 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::oseirmetapopwang::Parameters& params) -{ - //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(); -} - -template -mio::IOResult set_population_data(mio::oseirmetapopwang::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::oseirmetapopwang::Region(region_idx), mio::AgeGroup(age), - mio::oseirmetapopwang::InfectionState::Susceptible}] = - entry.population[mio::AgeGroup(age)]; - } - } - } - - printf("Setting population data successful.\n"); - return mio::success(); -} - -template -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>() - .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::oseirmetapopwang::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(); - } -} - -template -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::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)) - - BOOST_OUTCOME_TRY(set_covid_parameters(parameters)); - - return mio::success(); -} - -int main() -{ - mio::set_log_level(mio::LogLevel::debug); - - ScalarType t0 = 0.; - ScalarType tmax = 100.; - ScalarType dt = 0.1; - - ScalarType number_regions = 53; - ScalarType number_age_groups = 6; - - mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - - 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); - - model.check_constraints(); - - auto result_from_sim = simulate(t0, tmax, dt, model); - - 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_wang_nrw.h5"); -} diff --git a/cpp/examples/ode_seir_metapop.cpp b/cpp/examples/ode_seir_metapop.cpp index 0c7519b1b0..7bd6d031c5 100644 --- a/cpp/examples/ode_seir_metapop.cpp +++ b/cpp/examples/ode_seir_metapop.cpp @@ -1,9 +1,9 @@ #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 "models/ode_seir_metapop/infection_state.h" +#include "models/ode_seir_metapop/model.h" +#include "models/ode_seir_metapop/parameters.h" +#include "models/ode_seir_metapop/regions.h" #include diff --git a/cpp/models/ode_metapop/CMakeLists.txt b/cpp/models/ode_metapop/CMakeLists.txt deleted file mode 100644 index 5b8a8c87f2..0000000000 --- a/cpp/models/ode_metapop/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -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_metapop_wang/infection_state.h b/cpp/models/ode_metapop_wang/infection_state.h deleted file mode 100644 index 9caf8c4d17..0000000000 --- a/cpp/models/ode_metapop_wang/infection_state.h +++ /dev/null @@ -1,26 +0,0 @@ - -#ifndef ODESEIRMOBILITY_INFECTIONSTATE_H -#define ODESEIRMOBILITY_INFECTIONSTATE_H - -namespace mio -{ -namespace oseirmetapopwang -{ - -/** - * @brief The InfectionState enum describes the possible - * categories for the infectious state of persons - */ -enum class InfectionState -{ - Susceptible, - Exposed, - Infected, - Recovered, - Count -}; - -} // 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 deleted file mode 100644 index 3e93120de1..0000000000 --- a/cpp/models/ode_metapop_wang/model.cpp +++ /dev/null @@ -1,10 +0,0 @@ - -#include "ode_metapop_wang/model.h" - -namespace mio -{ -namespace oseirmetapopwang -{ - -} // namespace oseirmetapopwang -} // namespace mio diff --git a/cpp/models/ode_metapop_wang/model.h b/cpp/models/ode_metapop_wang/model.h deleted file mode 100644 index a1bf45d44b..0000000000 --- a/cpp/models/ode_metapop_wang/model.h +++ /dev/null @@ -1,216 +0,0 @@ - -#ifndef ODESEIRMOBILITY_MODEL_H -#define ODESEIRMOBILITY_MODEL_H - -#include "memilio/compartments/flow_model.h" -#include "memilio/epidemiology/populations.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" - -GCC_CLANG_DIAGNOSTIC(push) -GCC_CLANG_DIAGNOSTIC(ignored "-Wshadow") -#include -GCC_CLANG_DIAGNOSTIC(pop) - -namespace mio -{ -namespace oseirmetapopwang -{ - -/******************** - * 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))) - { - } - - 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>().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 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 Sjn = population.get_flat_index({region_n, age_j, InfectionState::Susceptible}); - const size_t Ejn = population.get_flat_index({region_n, age_j, InfectionState::Exposed}); - const size_t Ijn = population.get_flat_index({region_n, age_j, InfectionState::Infected}); - const size_t Rjn = population.get_flat_index({region_n, age_j, InfectionState::Recovered}); - - const double Njn_inv = 1.0 / (pop[Sjn] + pop[Ejn] + pop[Ijn] + pop[Rjn]); - - 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_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})] * Njn_inv; - continue; - } - 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_i, InfectionState::Susceptible})]; - } - flows[Base::template get_flat_flow_index( - {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_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++) { - auto const population_region_n = pop.template slice({(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_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()) * - 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()) / Njm + - commuting_strengths.get_matrix_at(y.get_time(t_idx))(m.get(), n.get())) / - 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]; - } - } - } - - 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 oseirmetapopwang -} // namespace mio - -#endif // ODESEIRMOBILITY_MODEL_H diff --git a/cpp/models/ode_metapop_wang/parameters.h b/cpp/models/ode_metapop_wang/parameters.h deleted file mode 100644 index 6e1d7b45a1..0000000000 --- a/cpp/models/ode_metapop_wang/parameters.h +++ /dev/null @@ -1,244 +0,0 @@ - -#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_metapop_wang/regions.h" - -#include - -namespace mio -{ -namespace oseirmetapopwang -{ - -/**************************************************** - * 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 contact patterns between different Region%s are modelled using a ContactMatrix. - */ -template -struct CommutingStrengths { - using Type = UncertainContactMatrix; - static Type get_default(Region size, AgeGroup) - { - return Type(1, static_cast((size_t)size)); - } - static std::string name() - { - return "CommutingStrengths"; - } -}; - -template -using ParametersBase = ParameterSet, TimeExposed, TimeInfected, - ContactPatterns, CommutingStrengths>; - -/** - * @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; - } - } - 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; - } - } - 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 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 deleted file mode 100644 index 361217436d..0000000000 --- a/cpp/models/ode_metapop_wang/regions.h +++ /dev/null @@ -1,26 +0,0 @@ - -#ifndef ODESEIRMOBILITY_REGIONS_H -#define ODESEIRMOBILITY_REGIONS_H - -#include "memilio/utils/index.h" - -namespace mio -{ -namespace oseirmetapopwang -{ - -/** - * @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 oseirmetapopwang -} // namespace mio - -#endif diff --git a/cpp/models/ode_metapop_wang/CMakeLists.txt b/cpp/models/ode_seir_metapop/CMakeLists.txt similarity index 52% rename from cpp/models/ode_metapop_wang/CMakeLists.txt rename to cpp/models/ode_seir_metapop/CMakeLists.txt index fefa3afae1..45e42593e6 100644 --- a/cpp/models/ode_metapop_wang/CMakeLists.txt +++ b/cpp/models/ode_seir_metapop/CMakeLists.txt @@ -1,13 +1,13 @@ -add_library(ode_metapop_wang +add_library(ode_seir_metapop infection_state.h model.h model.cpp parameters.h regions.h ) -target_link_libraries(ode_metapop_wang PUBLIC memilio) -target_include_directories(ode_metapop_wang PUBLIC +target_link_libraries(ode_seir_metapop PUBLIC memilio) +target_include_directories(ode_seir_metapop PUBLIC $ $ ) -target_compile_options(ode_metapop_wang PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +target_compile_options(ode_seir_metapop PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/ode_metapop/infection_state.h b/cpp/models/ode_seir_metapop/infection_state.h similarity index 78% rename from cpp/models/ode_metapop/infection_state.h rename to cpp/models/ode_seir_metapop/infection_state.h index 03a2b70080..bb4cca92d4 100644 --- a/cpp/models/ode_metapop/infection_state.h +++ b/cpp/models/ode_seir_metapop/infection_state.h @@ -1,6 +1,6 @@ -#ifndef ODESEIRMOBILITYIMPROVED_INFECTIONSTATE_H -#define ODESEIRMOBILITYIMPROVED_INFECTIONSTATE_H +#ifndef ODESEIRMETAPOP_INFECTIONSTATE_H +#define ODESEIRMETAPOP_INFECTIONSTATE_H namespace mio { diff --git a/cpp/models/ode_metapop/model.cpp b/cpp/models/ode_seir_metapop/model.cpp similarity index 100% rename from cpp/models/ode_metapop/model.cpp rename to cpp/models/ode_seir_metapop/model.cpp diff --git a/cpp/models/ode_metapop/model.h b/cpp/models/ode_seir_metapop/model.h similarity index 98% rename from cpp/models/ode_metapop/model.h rename to cpp/models/ode_seir_metapop/model.h index 47906d1232..4158da7979 100644 --- a/cpp/models/ode_metapop/model.h +++ b/cpp/models/ode_seir_metapop/model.h @@ -1,12 +1,12 @@ -#ifndef ODESEIRMOBILITYIMPROVED_MODEL_H -#define ODESEIRMOBILITYIMPROVED_MODEL_H +#ifndef ODESEIRMETAPOP_MODEL_H +#define ODESEIRMETAPOP_MODEL_H #include "memilio/compartments/flow_model.h" #include "memilio/epidemiology/populations.h" -#include "models/ode_metapop/infection_state.h" -#include "models/ode_metapop/parameters.h" -#include "models/ode_metapop/regions.h" +#include "models/ode_seir_metapop/infection_state.h" +#include "models/ode_seir_metapop/parameters.h" +#include "models/ode_seir_metapop/regions.h" #include "memilio/epidemiology/age_group.h" #include "memilio/utils/time_series.h" diff --git a/cpp/models/ode_metapop/parameters.h b/cpp/models/ode_seir_metapop/parameters.h similarity index 99% rename from cpp/models/ode_metapop/parameters.h rename to cpp/models/ode_seir_metapop/parameters.h index 70bc13043b..92df16b263 100644 --- a/cpp/models/ode_metapop/parameters.h +++ b/cpp/models/ode_seir_metapop/parameters.h @@ -1,6 +1,6 @@ -#ifndef SEIRMOBILITY_PARAMETERS_H -#define SEIRMOBILITY_PARAMETERS_H +#ifndef ODESEIRMETAPOP_PARAMETERS_H +#define ODESEIRMETAPOP_PARAMETERS_H #include "memilio/epidemiology/uncertain_matrix.h" #include "memilio/utils/uncertain_value.h" diff --git a/cpp/models/ode_metapop/regions.h b/cpp/models/ode_seir_metapop/regions.h similarity index 80% rename from cpp/models/ode_metapop/regions.h rename to cpp/models/ode_seir_metapop/regions.h index 41f37337e2..e482e76722 100644 --- a/cpp/models/ode_metapop/regions.h +++ b/cpp/models/ode_seir_metapop/regions.h @@ -1,6 +1,6 @@ -#ifndef ODESEIRMOBILITYIMPROVED_REGIONS_H -#define ODESEIRMOBILITYIMPROVED_REGIONS_H +#ifndef ODESEIRMETAPOP_REGIONS_H +#define ODESEIRMETAPOP_REGIONS_H #include "memilio/utils/index.h" diff --git a/cpp/tests/data/seir-compare.csv b/cpp/tests/data/seir-compare.csv index 677c4dcb36..2a457c2ce5 100644 --- a/cpp/tests/data/seir-compare.csv +++ b/cpp/tests/data/seir-compare.csv @@ -29,4 +29,4 @@ 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 +50.00000000000000 1046491.42674924037419 2.96615872057889 1.71632120750472 14503.89077083145639 diff --git a/docs/source/cpp/deterministic_metapop.rst b/docs/source/cpp/deterministic_metapop.rst new file mode 100644 index 0000000000..d7cda25343 --- /dev/null +++ b/docs/source/cpp/deterministic_metapop.rst @@ -0,0 +1,48 @@ +Deterministic metapopulation model +================================================= + +Introduction +---------------- + +This metapopulation model incorporates the effects of spatial heterogeneity and population dynamics into a system of ordinary differential equations (ODEs). A population is divided into several subpopulations, each representing spatially seperated regions which interact on some level. Each subpopulation is further divided into epidemiological compartments and eventually into age groups. +Commuting between regions is governed by a commuting matrix, which describes the fraction of individuals that commute from one region to another. Commuting is not performed explicitly, i.e., individuals are not exchanged between subpopulations, but rather their theoretical impact to transmission dynamics in other locations is considered, leading to a large system of ODEs which can be solved using standard numerical integration methods. + +Simulation +---------- + +The simulation runs in discrete time steps using standard numerical integration schemes. Several schemes including adaptive step size methods are available, see here. + +How to: Set up and run a simulation of the deterministic metapopulation model +---------------------------------------------------------------------------- + +To set up a simulation with the deterministic SEIR metapopulation model you need to initialize the model with the desired number of regions and age groups, e.g., 3 regions and 1 age group: +.. code-block:: cpp + + mio::oseirmetapop::Model model(3, 1) + +Set a population with the number of individuals in each region, age group and epidemiological compartment, e.g.: + +.. code-block:: cpp + + model.populations[{mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible}] = 900; + model.populations[{mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed}] = 100; + model.populations[{mio::oseirmetapop::Region(1), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible}] = 1000; + model.populations[{mio::oseirmetapop::Region(2), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible}] = 1000; + +and the epidemiological parameters, e.g.: + +.. code-block:: cpp + + 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); + +Construct an ``Eigen::MatrixXd`` of size :math:`n_{regions} \times n_{regions}` satisfying the sum of each row equal to 1.0, e.g.: +.. code-block:: cpp + 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; \ No newline at end of file diff --git a/shellscripts/likwid_equationbased.sh b/shellscripts/likwid_equationbased.sh deleted file mode 100644 index e4980ff289..0000000000 --- a/shellscripts/likwid_equationbased.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/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_metapop_timing - -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 deleted file mode 100644 index 4963e4e860..0000000000 --- a/shellscripts/likwid_graphbased.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/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=1 -regions=80 - -module purge -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/ -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 diff --git a/shellscripts/likwid_test.sh b/shellscripts/likwid_test.sh deleted file mode 100644 index d1e7a8c057..0000000000 --- a/shellscripts/likwid_test.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh -#SBATCH -N 1 -#SBATCH -n 1 -#SBATCH -c 1 -#SBATCH --exclusive -#SBATCH -t 5-0:00:00 -#SBATCH --output=likwid_test-%A.out -#SBATCH --error=likwid_test-%A.err -#SBATCH --exclude="be-cpu05, be-gpu01" -#SBATCH --job-name=likwid_test - - -cd ../cpp/examples -g++ -O3 -o likwid_test likwid_test.cpp - -srun --cpu-bind=cores --cpus-per-task=1 --cpu-freq=2200000-2200000 likwid-perfctr -C S0:1 -g MEM_DP ./likwid_test \ No newline at end of file diff --git a/shellscripts/steps_mobilitymodels.sh b/shellscripts/steps_mobilitymodels.sh deleted file mode 100644 index c2c6d80d1f..0000000000 --- a/shellscripts/steps_mobilitymodels.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/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 deleted file mode 100644 index a0d28bb84e..0000000000 --- a/shellscripts/timing_mobilitymodels.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/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 diff --git a/tools/basic_reproduction_numbers.py b/tools/basic_reproduction_numbers.py deleted file mode 100644 index d1ddfb0fc2..0000000000 --- a/tools/basic_reproduction_numbers.py +++ /dev/null @@ -1,40 +0,0 @@ -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 deleted file mode 100644 index dce00b1ff0..0000000000 --- a/tools/plot_mobility_runtimes.py +++ /dev/null @@ -1,236 +0,0 @@ -import matplotlib.pyplot as plt -import pandas as pd -import numpy as np - -import os - -colors = ['#1f77b4', '#2ca02c', '#ff7f0e'] -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 - - def flops_graph_based(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.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 FLOP', 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() - 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]) - - 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)*200 - - def flops_graph_based(x): - 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.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) - 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.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.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(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() - - 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') - - 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') - - 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') - 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 deleted file mode 100644 index 3e8cc74d7c..0000000000 --- a/tools/plot_results_mobility.py +++ /dev/null @@ -1,475 +0,0 @@ -import datetime as dt -import os.path -import h5py - -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 -from matplotlib.ticker import FormatStrFormatter - -compartments = {'Susceptible': 0, - 'Exposed': 1, - 'Infected': 2, - 'Recovered': 3} - - -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): - """! 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] - # 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. - 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]) - else: - 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) - - 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) - 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) - - 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) - - 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 = {} - 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) - 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=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): - plot_map_nrw( - 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, - fontsize=13) - - -def plot_difference(files, output_dir, name='difference2D'): - 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'] = ( - 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') - plt.xlim(left=0., right=101.) - plt.tight_layout() - plt.legend() - plt.grid(linestyle='--') - plt.savefig(os.path.join(output_dir, name)) - 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) - 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_dif2['Region'] = dfs_all['Region'] - - 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_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='', plot_colorbar=False, - output_path=output_dir, - fig_name="difference60-100", 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 - - i = 0 - for file in files.values(): - model_type = os.path.basename(file).split('_')[0] - if model_type == 'ode': - 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(r'(\d+)') - df['Group'] = df['Group'].apply(pd.to_numeric, errors='coerce') - 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')] - - 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 - - return dfs_all - - -def plot_total_compartment( - files, output_dir, legend, compartment='Infected', name='', ax=None, - print_legend=True): - - colors = ['#2ca02c', '#ff7f0e', '#9C180D'] - 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. - h5file = h5py.File(file + '.h5', 'r') - 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]) - 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.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) - - file_idx = file_idx+1 - ax.tick_params(labelsize=7, ) - 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__': - - 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 (ODE)', - 'Model C (ODE)', - '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) - # 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 5800934f4ec055c11671c5dc309df417f0aacd1a Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Mon, 12 May 2025 15:29:44 +0200 Subject: [PATCH 089/105] remove timing artifacts --- cpp/memilio/compartments/simulation.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/cpp/memilio/compartments/simulation.h b/cpp/memilio/compartments/simulation.h index f7b79c0b90..a72bee0386 100644 --- a/cpp/memilio/compartments/simulation.h +++ b/cpp/memilio/compartments/simulation.h @@ -26,8 +26,6 @@ #include "memilio/math/stepper_wrapper.h" #include "memilio/utils/time_series.h" -#include - namespace mio { @@ -227,22 +225,6 @@ TimeSeries simulate(FP t0, FP tmax, FP dt, Model const& model, 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); - if (integrator) { - sim.set_integrator(integrator); - } - double start_time = omp_get_wtime(); - sim.advance(tmax); - double end_time = omp_get_wtime(); - return end_time - start_time; -} - } // namespace mio #endif // SIMULATION_H From ceea756eecb11e570db67b96e11f4cbd769ed72f Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Mon, 12 May 2025 15:33:06 +0200 Subject: [PATCH 090/105] renamed model --- cpp/models/ode_seir_metapop/model.cpp | 2 +- cpp/models/ode_seir_metapop/parameters.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/models/ode_seir_metapop/model.cpp b/cpp/models/ode_seir_metapop/model.cpp index 04ea73c6f3..25e3f0b743 100644 --- a/cpp/models/ode_seir_metapop/model.cpp +++ b/cpp/models/ode_seir_metapop/model.cpp @@ -1,5 +1,5 @@ -#include "ode_metapop/model.h" +#include "ode_seir_metapop/model.h" namespace mio { diff --git a/cpp/models/ode_seir_metapop/parameters.h b/cpp/models/ode_seir_metapop/parameters.h index 92df16b263..5dd9604cd8 100644 --- a/cpp/models/ode_seir_metapop/parameters.h +++ b/cpp/models/ode_seir_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_metapop/regions.h" +#include "models/ode_seir_metapop/regions.h" #include "Eigen/Sparse" #include From 99fe446dfd7e76e6be5f8217b5f0023e2d30df35 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Mon, 12 May 2025 15:36:07 +0200 Subject: [PATCH 091/105] renamed model 2 --- cpp/tests/test_odemetapop.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/tests/test_odemetapop.cpp b/cpp/tests/test_odemetapop.cpp index bfedc322b5..607ba7a7c7 100644 --- a/cpp/tests/test_odemetapop.cpp +++ b/cpp/tests/test_odemetapop.cpp @@ -2,9 +2,9 @@ #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 "ode_seir_metapop/model.h" +#include "ode_seir_metapop/infection_state.h" +#include "ode_seir_metapop/parameters.h" #include "memilio/math/euler.h" #include "memilio/compartments/simulation.h" #include From 22a94f4ebf80a5a0420ab0c2742dcdf12face5b3 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Mon, 12 May 2025 15:40:32 +0200 Subject: [PATCH 092/105] remove superfluous include omp --- cpp/examples/ode_seir_metapop.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/cpp/examples/ode_seir_metapop.cpp b/cpp/examples/ode_seir_metapop.cpp index 7bd6d031c5..711e27195a 100644 --- a/cpp/examples/ode_seir_metapop.cpp +++ b/cpp/examples/ode_seir_metapop.cpp @@ -5,8 +5,6 @@ #include "models/ode_seir_metapop/parameters.h" #include "models/ode_seir_metapop/regions.h" -#include - int main() { const ScalarType t0 = 0.; From fd323b0776a9959be5f4cd5f0675353946d4c00d Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Tue, 13 May 2025 08:59:49 +0200 Subject: [PATCH 093/105] correct setting of population after commuting --- cpp/models/ode_seir_metapop/model.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cpp/models/ode_seir_metapop/model.h b/cpp/models/ode_seir_metapop/model.h index 4158da7979..cfad5089f2 100644 --- a/cpp/models/ode_seir_metapop/model.h +++ b/cpp/models/ode_seir_metapop/model.h @@ -212,10 +212,11 @@ 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& population_after_commuting = this->parameters.template get>(); + 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; + mio::Populations population_after_commuting( + {Region(number_regions), AgeGroup(number_age_groups)}, 0.); for (size_t region_n = 0; region_n < number_regions; ++region_n) { for (size_t age = 0; age < number_age_groups; ++age) { @@ -233,6 +234,7 @@ class Model : public FlowModelparameters.template get>() = population_after_commuting; } void set_commuting_strengths() From b2d266a54eca562fbb7b93659d7425ebfc7dfa0c Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Tue, 13 May 2025 09:00:50 +0200 Subject: [PATCH 094/105] comment in tests --- cpp/tests/test_odemetapop.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/tests/test_odemetapop.cpp b/cpp/tests/test_odemetapop.cpp index 607ba7a7c7..520d3631a8 100644 --- a/cpp/tests/test_odemetapop.cpp +++ b/cpp/tests/test_odemetapop.cpp @@ -128,7 +128,7 @@ TEST_F(ModelTestOdeMetapop, check_constraints_parameters) {mio::oseirmetapop::Region(4), mio::AgeGroup(1)}, 0.)); ASSERT_EQ(model.parameters.check_constraints(), 1); - // Nobody commutes to region 2 + // Nobody commutes to region 2 but everybody originating fron there commutes to other regions. 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); @@ -213,6 +213,7 @@ TEST_F(ModelTestOdeMetapop, apply_constraints_parameters) mio::oseirmetapop::Region(3), mio::AgeGroup(0)}]), 1.0, tol_times); + // Nobody commutes to region 2 but everybody originating fron there commutes to other regions. 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); From baf54e748e644140ef2226c3691183171d2a47d2 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Tue, 13 May 2025 12:37:43 +0200 Subject: [PATCH 095/105] correct test and add compare files --- cpp/tests/data/ode-seir-compare-euler.csv | 502 ++++++++++++++++++++ cpp/tests/data/ode-seir-metapop-compare.csv | 26 + cpp/tests/data/seir-compare.csv | 68 +-- cpp/tests/test_odemetapop.cpp | 97 ++-- 4 files changed, 614 insertions(+), 79 deletions(-) create mode 100644 cpp/tests/data/ode-seir-compare-euler.csv create mode 100644 cpp/tests/data/ode-seir-metapop-compare.csv diff --git a/cpp/tests/data/ode-seir-compare-euler.csv b/cpp/tests/data/ode-seir-compare-euler.csv new file mode 100644 index 0000000000..66722c7ad1 --- /dev/null +++ b/cpp/tests/data/ode-seir-compare-euler.csv @@ -0,0 +1,502 @@ + # t S E I R +0.00000000000000 1049000.00000000000000 10000.00000000000000 1000.00000000000000 1000.00000000000000 +0.10000000000000 1048973.30537229031324 9834.38693540201530 1175.64102564102564 1016.66666666666663 +0.20000000000000 1048941.92287142318673 9676.64661058845013 1345.16983422781641 1036.26068376068383 +0.30000000000000 1048906.01605155738071 9526.46407255830127 1508.83969488661796 1058.68018099781420 +0.40000000000000 1048865.74174628220499 9383.53714566897543 1666.89359880309030 1083.82750924592460 +0.50000000000000 1048821.25033727660775 9247.57591725778730 1819.56467623974982 1111.60906922597610 +0.60000000000000 1048772.68601242476143 9118.30224370071664 1967.07659671122428 1141.93514716330537 +0.70000000000000 1048720.18701378209516 8995.44927611847015 2109.64395299105081 1174.71975710849256 +0.80000000000000 1048663.88587577571161 8878.76100496862091 2247.47262959732416 1209.88048965834332 +0.90000000000000 1048603.90965401218273 8767.99182279047091 2380.76015637907312 1247.33836681829871 +1.00000000000000 1048540.38014504511375 8662.90610439617012 2509.69604780077725 1287.01770275795002 +1.10000000000000 1048473.41409745207056 8563.27780382778474 2634.46212849889571 1328.84597022129628 +1.20000000000000 1048403.12341455032583 8468.89006742519268 2755.23284566162783 1372.75367236294460 +1.30000000000000 1048329.61534907401074 8379.53486237413017 2872.17556876134176 1418.67421979063829 +1.40000000000000 1048252.99269012128934 8295.01262012730876 2985.45087714815509 1466.54381260332730 +1.50000000000000 1048173.35394267027732 8215.13189411430903 3095.21283599300568 1516.30132722246321 +1.60000000000000 1048090.79349995055236 8139.70903117802754 3201.60926104916689 1567.88820782234666 +1.70000000000000 1048005.40180894767400 8068.56785619668608 3304.78197268254007 1621.24836217316602 +1.80000000000000 1047917.26552930800244 8001.53936937099570 3404.86703960315208 1676.32806171787502 +1.90000000000000 1047826.46768589981366 7938.46145567586791 3501.99501271305462 1733.07584571126085 +2.00000000000000 1047733.08781527902465 7879.17860599520827 3596.29114946929622 1791.44242925647836 +2.10000000000000 1047637.20210629759822 7823.54164947676873 3687.87562914471573 1851.38061508096666 +2.20000000000000 1047538.88353508408181 7771.40749666184274 3776.86375935403657 1912.84520890004524 +2.30000000000000 1047438.20199461758602 7722.63889296173602 3863.36617419804315 1975.79293822261252 +2.40000000000000 1047335.22441910672933 7677.10418206948179 3947.48902436451954 2040.18237445924660 +2.50000000000000 1047230.01490337902214 7634.67707891121063 4029.33415951106235 2105.97385819865531 +2.60000000000000 1047122.63481747731566 7595.23645175693855 4108.99930324186244 2173.12942752383969 +2.70000000000000 1047013.14291665202472 7558.66611312532677 4186.57822097802909 2241.61274924453755 +2.80000000000000 1046901.59544693224598 7524.85461913120889 4262.16088100901015 2311.38905292750451 +2.90000000000000 1046788.04624644946307 7493.69507693841297 4335.83360900112712 2382.42506761098821 +3.00000000000000 1046672.54684268392157 7465.08495999359275 4407.67923622812941 2454.68896109434036 +3.10000000000000 1046555.14654579432681 7438.92593072951149 4477.77724177804976 2528.15028169814241 +3.20000000000000 1046435.89253818674479 7415.12367043845279 4546.20388898039346 2602.77990239444307 +3.30000000000000 1046314.82996047323104 7393.58771602820434 4613.03235628787024 2678.54996721078305 +3.40000000000000 1046192.00199396267999 7374.23130338440114 4678.33286283746111 2755.43383981558100 +3.50000000000000 1046067.44993982347660 7356.97121707389397 4742.17278890653688 2833.40605419620533 +3.60000000000000 1045941.21329505008180 7341.72764613432537 4804.61679147105406 2912.44226734464746 +3.70000000000000 1045813.32982536125928 7328.42404570514464 4865.72691506450428 2992.51921386916501 +3.80000000000000 1045683.83563515322749 7316.98700426501910 4925.56269812827213 3073.61466245357360 +3.90000000000000 1045552.76523462473415 7307.34611624991157 4984.18127503635878 3155.70737408904461 +4.00000000000000 1045420.15160418860614 7299.43385983506141 5041.63747397004590 3238.77706200631746 +4.10000000000000 1045286.02625627722591 7293.18547967273389 5097.98391081096270 3322.80435323915162 +4.20000000000000 1045150.41929464729037 7288.53887438587572 5153.27107921422976 3407.77075175266782 +4.30000000000000 1045013.35947128455155 7285.43448862579680 5207.54743701679763 3493.65860307290495 +4.40000000000000 1044874.87424100411590 7283.81520950963841 5260.85948912983440 3580.45106035651816 +4.50000000000000 1044734.98981383931823 7283.62626726075268 5313.25186705798387 3668.13205184201524 +4.60000000000000 1044593.73120530904271 7284.81513988219194 5364.76740518254519 3756.68624962631475 +4.70000000000000 1044451.12228464707732 7287.33146170028613 5415.44721394005774 3846.09903971269068 +4.80000000000000 1044307.18582107743714 7291.12693562182631 5465.33075002247278 3936.35649327835836 +4.90000000000000 1044161.94352821342181 7296.15524895464205 5514.45588371995382 4027.44533911206645 +5.00000000000000 1044015.41610665619373 7302.37199264736955 5562.85896352246709 4119.35293717406603 +5.10000000000000 1043867.62328486575279 7309.73458381001910 5610.57487809159375 4212.06725323277351 +5.20000000000000 1043718.58385837392416 7318.20219138248194 5657.63711570949090 4305.57683453430036 +5.30000000000000 1043568.31572740629781 7327.73566482348087 5704.07782130758551 4399.87078646279224 +5.40000000000000 1043416.83593297796324 7338.29746569757208 5749.92785117342373 4494.93875015125195 +5.50000000000000 1043264.16069152322598 7349.85160204274962 5795.21682543010229 4590.77088100414221 +5.60000000000000 1043110.30542812077329 7362.36356540592442 5839.97317837888386 4687.35782809464399 +5.70000000000000 1042955.28480836923700 7375.80027043808968 5884.22420679191418 4784.69071440095831 +5.80000000000000 1042799.11276896891650 7390.12999694534756 5927.99611623842247 4882.76111784748991 +5.90000000000000 1042641.80254706146661 7405.32233429615735 5971.31406552442331 4981.56105311813008 +5.99999999999999 1042483.36670837807469 7421.34812808919378 6014.20220932266056 5081.08295421020375 +6.09999999999999 1042323.81717424478848 7438.17942899004629 6056.68373906643410 5181.31965769891485 +6.19999999999999 1042163.16524749016389 7455.78944364871586 6098.78092217795620 5282.26438668335504 +6.29999999999999 1042001.42163730144966 7474.15248761340627 6140.51513969900407 5383.91073538632099 +6.39999999999999 1041838.59648307040334 7493.24394015953840 6181.90692238889369 5486.25265438130464 +6.49999999999999 1041674.69937727064826 7513.04020095617489 6222.97598535214638 5589.28443642111961 +6.59999999999999 1041509.73938740557060 7533.51864849521189 6263.74126125569092 5693.00070284365574 +6.69999999999999 1041343.72507706412580 7554.65760021169444 6304.22093219300405 5797.39639053125029 +6.79999999999999 1041176.66452612215653 7576.43627422652935 6344.43246025026838 5902.46673940113396 +6.89999999999999 1041008.56535012181848 7598.83475264564095 6384.39261682737651 6008.20728040530503 +6.99999999999999 1040839.43471886427142 7621.83394635228979 6424.11751076446490 6114.61382401909486 +7.09999999999999 1040669.27937424718402 7645.41556123183727 6463.62261532260163 6221.68244919850258 +7.19999999999999 1040498.10564737697132 7669.56206577071134 6502.92279406527268 6329.40949278721291 +7.29999999999999 1040325.91947498614900 7694.25665997366468 6542.03232568541625 6437.79153935496743 +7.39999999999999 1040152.72641518386081 7719.48324554571263 6580.96492782092173 6546.82541144972402 +7.49999999999999 1039978.53166256635450 7745.22639728729064 6619.73377989978508 6656.50816024673895 +7.59999999999999 1039803.34006271406543 7771.47133565327385 6658.35154505441642 6766.83705657840164 +7.69999999999999 1039627.15612609940581 7798.20390042849249 6696.83039114299572 6877.80958232930880 +7.79999999999999 1039449.98404142993968 7825.41052547430809 6735.18201091423725 6989.42342218169233 +7.89999999999999 1039271.82768845011014 7853.07821450265783 6773.41764135042922 7101.67645569692922 +7.99999999999999 1039092.69065022270661 7881.19451783574004 6811.54808222220436 7214.56674971943630 +8.09999999999999 1038912.57622491195798 7909.74751011121953 6849.58371388713658 7328.09255108980597 +8.19999999999999 1038731.48743708815891 7938.72576889445736 6887.53451436295109 7442.25227965459180 +8.29999999999999 1038549.42704857385252 7968.11835416083159 6925.41007570487182 7557.04452156064144 +8.39999999999999 1038366.39756884961389 7997.91478861272299 6963.21961971544806 7672.46802282238968 +8.49999999999999 1038182.40126503794454 8028.10503879717271 7000.97201301402492 7788.52168315098061 +8.59999999999999 1037997.44017148204148 8058.67949699160363 7038.67578149194196 7905.20455003454754 +8.69999999999999 1037811.51609893597197 8089.62896382632698 7076.33912417845295 8022.51581305941363 +8.79999999999998 1037624.63064338255208 8120.94463161381373 7113.96992654136920 8140.45479846238777 +8.89999999999998 1037436.78519449394662 8152.61806835595416 7151.57577324543217 8259.02096390474435 +8.99999999999998 1037247.98094374907669 8184.64120240166994 7189.16396039049505 8378.21389345883472 +9.09999999999998 1037058.21889222227037 8217.00630772839759 7226.74150725068557 8498.03329279867648 +9.19999999999998 1036867.49985805689357 8249.70598982201773 7264.31516753487449 8618.47898458618874 +9.29999999999998 1036675.82448363606818 8282.73317213084374 7301.89144018792194 8739.55090404510338 +9.39999999999998 1036483.19324246328324 8316.08108307028670 7339.47657975140828 8861.24909471490173 +9.49999999999998 1036289.60644576488994 8349.74324355574026 7377.07660630177452 8983.57370437742429 +9.59999999999998 1036095.06424882542342 8383.71345504218698 7414.69731498307374 9106.52498114912123 +9.69999999999998 1035899.56665706692729 8417.98578804984027 7452.34428515083346 9230.10326973217161 +9.79999999999998 1035703.11353188287467 8452.55457115603895 7490.02288914286783 9354.30900781801938 +9.89999999999998 1035505.70459623611532 8487.41438043438211 7527.73830069220548 9479.14272263706698 +9.99999999999998 1035307.33944003155921 8522.56002932286719 7565.49550299671409 9604.60502764860394 +10.09999999999998 1035108.01752527162898 8557.98655890355622 7603.29929645938773 9730.69661936521516 +10.19999999999998 1034907.73819100391120 8593.68922857697908 7641.15430611269676 9857.41827430620469 +10.29999999999998 1034706.50065806997009 8629.66350711520136 7679.06498873986311 9984.77084607474899 +10.39999999999998 1034504.30403366254177 8665.90506407809880 7717.03563970538835 10112.75526255374643 +10.49999999999998 1034301.14731569960713 8702.40976157803925 7755.07039950667240 10241.37252321550295 +10.59999999999998 1034097.02939702232834 8739.17364637876926 7793.17326005806171 10370.62369654061331 +10.69999999999998 1033891.94906942511443 8776.19294231487220 7831.34807071822433 10500.50991754158167 +10.79999999999998 1033685.90502752293833 8813.46404301872462 7869.59854407128387 10631.03238538688493 +10.89999999999998 1033478.89587246428709 8850.98350494242368 7907.92826147173764 10762.19236112140607 +10.99999999999998 1033270.92011549521703 8888.74804066263641 7946.34067836276790 10893.99116547926860 +11.09999999999998 1033061.97618138056714 8926.75451245685144 7984.83912937715741 11026.43017678531396 +11.19999999999998 1032852.06241168873385 8964.99992613994982 8023.42683322965695 11159.51082894160027 +11.29999999999998 1032641.17706794477999 9003.48142515049040 8062.10689740928956 11293.23460949542823 +11.39999999999998 1032429.31833465816453 9042.19628487650698 8100.88232267972126 11427.60305778558359 +11.49999999999998 1032216.48432222986594 9081.14190721106388 8139.75600739550464 11562.61776316357827 +11.59999999999997 1032002.67306974332314 9120.31581532819291 8178.73075164168949 11698.28036328683629 +11.69999999999997 1031791.03632657043636 9156.56186974472439 8217.80926120397271 11834.59254248086472 +11.79999999999997 1031587.62644657120109 9183.88402147963097 8256.93350178156106 11971.55603016759778 +11.89999999999997 1031397.67450624494813 9197.22280754671010 8295.93109767775786 12109.17158853062392 +11.99999999999997 1031225.07032349496149 9192.95732092076469 8334.53524875902622 12247.43710682525307 +12.09999999999997 1031071.96818014676683 9169.27182348207680 8372.41396873331360 12386.34602763790281 +12.19999999999997 1030938.55839373019990 9126.34945944704668 8409.20588637267065 12525.88626045012461 +12.29999999999997 1030823.02987110440154 9066.37126169881230 8444.55917530710758 12666.03969188966948 +12.39999999999997 1030721.73071303451434 8993.31712627448724 8478.16981587952978 12806.78234481145410 +12.49999999999997 1030629.51430479332339 8912.58512824118043 8509.81539188938041 12948.08517507611214 +12.59999999999997 1030540.23905261140317 8830.46451257228910 8539.38100320868216 13089.91543160760193 +12.69999999999997 1030450.66139191738330 8750.22554802458217 8566.87461173031261 13232.23844832774739 +12.79999999999997 1030360.80313613510225 8671.81023557558910 8592.36693643271610 13375.01969185658527 +12.89999999999997 1030270.68534965766594 8595.16244059968813 8615.92640227888114 13518.22580746379754 +12.99999999999997 1030180.32837217091583 8520.22783269034517 8637.61921430371513 13661.82458083511301 +13.09999999999997 1030089.75184219516814 8446.95382742206675 8657.50942930936435 13805.78490107350808 +13.19999999999997 1029998.97471986932214 8375.28952998984460 8675.65902524565900 13950.07672489533070 +13.29999999999997 1029908.01530900120270 8305.18568066581793 8692.12796835034351 14094.67104198275774 +13.39999999999997 1029816.89127840858418 8236.59460201480942 8706.97427812141177 14239.53984145526374 +13.49999999999997 1029725.61968257243279 8169.47014781224516 8720.25409019146718 14384.65607942395400 +13.59999999999997 1029634.21698162471876 8103.76765360976515 8732.02171717184501 14529.99364759381206 +13.69999999999997 1029542.69906069256831 8039.44388889557194 8742.32970753198970 14675.52734288001011 +13.79999999999997 1029451.08124861877877 7976.45701079825085 8751.22890257752442 14821.23283800554418 +13.89999999999997 1029359.37833607883658 7914.76651928443425 8758.76849158837831 14967.08665304850365 +13.99999999999997 1029267.60459311318118 7854.33321380225789 8764.99606517635038 15113.06612790831059 +14.09999999999997 1029175.77378609508742 7795.11915132409922 8769.95766691960853 15259.14939566125031 +14.19999999999997 1029083.89919415011536 7737.08760574356620 8773.69784332974450 15405.31535677657666 +14.29999999999997 1028991.99362504621968 7680.20302858315245 8776.25969220521438 15551.54365416540531 +14.39999999999996 1028900.06943057093304 7624.43101097035560 8777.68490942326571 15697.81464903549204 +14.49999999999996 1028808.13852141203824 7569.73824684141709 8778.01383422077015 15844.10939752587910 +14.59999999999996 1028716.21238155802712 7516.09249733314300 8777.28549301275962 15990.40962809622579 +14.69999999999996 1028624.30208223336376 7463.46255632453358 8775.53764179587597 16136.69771964643769 +14.79999999999996 1028532.41829538356978 7411.81821709116957 8772.80680718244184 16282.95668034303526 +14.89999999999996 1028440.57130672491621 7361.13024003650116 8769.12832610935948 16429.17012712940777 +14.99999999999996 1028348.77102837234270 7311.37032146532511 8764.53638426464931 16575.32226589789570 +15.09999999999996 1028257.02701105899177 7262.51106336585144 8759.06405327303401 16721.39787230230650 +15.19999999999996 1028165.34845596156083 7214.52594416784177 8752.74332668064744 16867.38227319018915 +15.29999999999996 1028073.74422614241485 7167.38929044534143 8745.60515477765875 17013.26132863486782 +15.39999999999996 1027982.22285762254614 7121.07624953354389 8737.67947829633886 17159.02141454782759 +15.49999999999996 1027890.79257009632420 7075.56276303029063 8728.99526102089112 17304.64940585276781 +15.59999999999996 1027799.46127729932778 7030.82554115367839 8719.58052134420177 17450.13266020311494 +15.69999999999996 1027708.23659704113379 6986.84203792814151 8709.46236280552330 17595.45900222551791 +15.79999999999996 1027617.12586091377307 6943.59042717227931 8698.66700364199824 17740.61670827227499 +15.89999999999996 1027526.13612368551549 6901.04957926255156 8687.21980538589378 17885.59449166630657 +15.99999999999996 1027435.27417239139322 6859.19903864779553 8675.14530053835733 18030.38148842273949 +16.09999999999996 1027344.54653512872756 6818.01900209033647 8662.46721934953530 18174.96724343171081 +16.19999999999996 1027253.95948956860229 6777.49029761022393 8649.20851573390792 18319.34169708753689 +16.29999999999996 1027163.51907119178213 6737.59436410989656 8635.39139234879622 18463.49517234976884 +16.39999999999996 1027073.23108125769068 6698.31323165730373 8621.03732486304580 18607.41836222224811 +16.49999999999996 1026983.10109451541211 6659.62950240622013 8606.16708544207177 18751.10231763663251 +16.59999999999997 1026893.13446666521486 6621.52633213316858 8590.80076547456702 18894.53843572733240 +16.69999999999997 1026803.33634157862980 6583.98741237104878 8574.95779756537195 19037.71844848524051 +16.79999999999997 1026713.71165828395169 6546.99695312017957 8558.65697681821257 19180.63441177799541 +16.89999999999997 1026624.26515772601124 6510.53966611811575 8541.91648143124621 19323.27869472496604 +16.99999999999997 1026535.00138930708636 6474.60074865018305 8524.75389262761200 19465.64396941548694 +17.09999999999997 1026445.92471721535549 6439.16586788325912 8507.18621394247566 19607.72320095928080 +17.19999999999997 1026357.03932654880919 6404.22114570589747 8489.22988988734323 19749.50963785832209 +17.29999999999998 1026268.34922924044076 6369.75314405843164 8470.90082401177096 19890.99680268977681 +17.39999999999998 1026179.85826979123522 6335.74885073722544 8452.21439638192896 20032.17848308997418 +17.49999999999998 1026091.57013081805781 6302.19566565775040 8433.18548049486890 20173.04872302967124 +17.59999999999998 1026003.48833842074964 6269.08138756165772 8413.82845964670560 20313.60181437125357 +17.69999999999998 1025915.61626737576444 6236.39420115349640 8394.15724277236950 20453.83228869869708 +17.79999999999998 1025827.95714616158511 6204.12266465319226 8374.18527977398662 20593.73490941157070 +17.89999999999998 1025740.51406182057690 6172.25569775085205 8353.92557635441699 20733.30466407446875 +17.99999999999999 1025653.28996466379613 6140.78256995088032 8333.39070837192412 20872.53675701370958 +18.09999999999999 1025566.28767282282934 6109.69288929283175 8312.59283573144785 21011.42660215324213 +18.19999999999999 1025479.50987665401772 6078.97659143681904 8291.54371582745262 21149.96981608209899 +18.29999999999999 1025392.95914299995638 6048.62392910169092 8270.25471655283218 21288.16221134589068 +18.39999999999999 1025306.63791931280866 6018.62546184457460 8248.73682888788244 21425.99978995510537 +18.49999999999999 1025220.54853764350992 5988.97204617074931 8227.00067908291567 21563.47873710323620 +18.59999999999999 1025134.69321850163396 5959.65482596317088 8205.05654044763833 21700.59541508795155 +18.70000000000000 1025049.07407459034584 5930.66522322131277 8182.91434475998267 21837.34635742874525 +18.80000000000000 1024963.69311441958416 5901.99492909932178 8160.58369330670030 21973.72826317474392 +18.90000000000000 1024878.55224580236245 5873.63589523381324 8138.07386756760116 22109.73799139652328 +19.00000000000000 1024793.65327923744917 5845.58032535193888 8115.39383955494486 22245.37255585598177 +19.10000000000000 1024708.99793118191883 5817.82066715066867 8092.55228181913026 22380.62911984856328 +19.20000000000000 1024624.58782721811440 5790.34960443851378 8069.55757713145249 22515.50499121221583 +19.30000000000000 1024540.42450511700008 5763.16004953120864 8046.41782785436135 22649.99761749773825 +19.40000000000001 1024456.50941780256107 5736.24513589313483 8023.14086500931171 22784.10458129531253 +19.50000000000001 1024372.84393621969502 5709.59821101655052 7999.73425705197315 22917.82359571213601 +19.60000000000001 1024289.42935210885480 5683.21282953092395 7976.20531836424561 23051.15249999633670 +19.70000000000001 1024206.26688069081865 5657.08274653494482 7952.56111747223076 23184.08925530240595 +19.80000000000001 1024123.35766326379962 5631.20191114399677 7928.80848499900640 23316.63194059360831 +19.90000000000001 1024040.70276971661951 5605.56446024614161 7904.95402136076609 23448.77874867692663 +20.00000000000001 1023958.30320095969364 5580.16471245985758 7881.00410421461493 23580.52798236627132 +20.10000000000002 1023876.15989127755165 5554.99716228701982 7856.96489566603486 23711.87805076984660 +20.20000000000002 1023794.27371060429141 5530.05647445480008 7832.84234924378688 23842.82746569761366 +20.30000000000002 1023712.64546672534198 5505.33747844038680 7808.64221664975230 23973.37483818500914 +20.40000000000002 1023631.27590740774758 5480.83516317260455 7784.37005429098190 24103.51887512917165 +20.50000000000002 1023550.16572246071883 5456.54467190472133 7760.03122960098972 24233.25837603402033 +20.60000000000002 1023469.31554572971072 5432.46129725290120 7735.63092715708990 24362.59222986070381 +20.70000000000002 1023388.72595702507533 5408.58047639494816 7711.17415460036045 24491.51941197998894 +20.80000000000003 1023308.39748398831580 5384.89778642416695 7686.66574836461587 24620.03898122332976 +20.90000000000003 1023228.33060389722232 5361.40893985330786 7662.11037922054220 24748.15007702940784 +21.00000000000003 1023148.52574541268405 5338.10978026376051 7637.51255764096823 24875.85191668308471 +21.10000000000003 1023068.98329026834108 5314.99627809528829 7612.87663899304971 25003.14379264376839 +21.20000000000003 1022989.70357490540482 5292.06452657176578 7588.20682856294661 25130.02506996032025 +21.30000000000003 1022910.68689205381088 5269.31073775851746 7563.50718641840558 25256.49518376970445 +21.40000000000003 1022831.93349226226564 5246.73123874700559 7538.78163211448100 25382.55363687667705 +21.50000000000004 1022753.44358537835069 5224.32246796275012 7514.03394924745135 25508.19999741191714 +21.60000000000004 1022675.21734198008198 5202.08097159249337 7489.26778986184127 25633.43389656604268 +21.70000000000004 1022597.25489476136863 5180.00340012675588 7464.48667871528141 25758.25502639707338 +21.80000000000004 1022519.55633987160400 5158.08650501405464 7439.69401740579724 25882.66313770899433 +21.90000000000004 1022442.12173821218312 5136.32713542316924 7414.89308836597047 26006.65803799909190 +22.00000000000004 1022364.95111669029575 5114.72223510996901 7390.08705872826522 26130.23958947185747 +22.10000000000004 1022288.04446943197399 5093.26883938541141 7365.27898406567783 26253.40770711732694 +22.20000000000005 1022211.40175895544235 5071.96407218145123 7340.47181201173862 26376.16235685175343 +22.30000000000005 1022135.02291730628349 5050.80514321168994 7315.66838576374994 26498.50355371861588 +22.40000000000005 1022058.90784715558402 5029.78934522370218 7290.87144747304046 26620.43136014801348 +22.50000000000005 1021983.05642286187503 5008.91405134007437 7266.08364152586910 26741.94588427256531 +22.60000000000005 1021907.46849149861373 4988.17671248529496 7241.30751771851646 26863.04727829799594 +22.70000000000005 1021832.14387384813745 4967.57485489571354 7216.54553432997636 26983.73573692663922 +22.80000000000005 1021757.08236536290497 4947.10607770988463 7191.80006109554779 27104.01149583213919 +22.90000000000006 1021682.28373709553853 4926.76805063670326 7167.07338208452984 27223.87483018373314 +23.00000000000006 1021607.74773659813218 4906.55851169880953 7142.36769848510903 27343.32605321847586 +23.10000000000006 1021533.47408879233990 4886.47526504883626 7117.68513129943676 27462.36551485989548 +23.20000000000006 1021459.46249681105837 4866.51617885614087 7093.02772395179545 27580.99360038155282 +23.30000000000006 1021385.71264281205367 4846.67918326174913 7068.39744481265279 27699.21072911408191 +23.40000000000006 1021312.22418876562733 4826.96226839929386 7043.79618964132169 27817.01735319429281 +23.50000000000006 1021238.99677721585613 4807.36348247983096 7019.22578394984976 27934.41395635497975 +23.60000000000007 1021166.03003201726824 4787.88092993845839 6994.68798529068226 28051.40105275414317 +23.70000000000007 1021093.32355904695578 4768.51276964074168 6970.18448547055141 28167.97918584231957 +23.80000000000007 1021020.87694689375348 4749.25721314701786 6945.71691269297935 28284.14892726682956 +23.90000000000007 1020948.68976752448361 4730.11252303269976 6921.28683363169330 28399.91087581171087 +24.00000000000007 1020876.76157692843117 4711.07701126278062 6896.89575543717820 28515.26565637223757 +24.10000000000007 1020805.09191574051511 4692.14903761877667 6872.54512767853521 28630.21391896285786 +24.20000000000007 1020733.68030984408688 4673.32700817642308 6848.23634422271516 28744.75633775749884 +24.30000000000008 1020662.52627095382195 4654.60937383247528 6823.97074505316505 28858.89361016121256 +24.40000000000008 1020591.62929717975203 4635.99462887903337 6799.74961802982671 28972.62645591209730 +24.50000000000008 1020520.98887357185595 4617.48130962385585 6775.57420059238757 29085.95561621259549 +24.60000000000008 1020450.60447264777031 4599.06799305516870 6751.44568140861429 29198.88185288913519 +24.70000000000008 1020380.47555490233935 4580.75329554953896 6727.36520196953188 29311.40594757927829 +24.80000000000008 1020310.60156930063386 4562.53587162142321 6703.33385813317182 29423.52870094543687 +24.90000000000008 1020240.98195375478826 4544.41441271303393 6679.35270161854351 29535.25093191432461 +25.00000000000009 1020171.61613558477256 4526.38764602323317 6655.42274145143347 29646.57347694129930 +25.10000000000009 1020102.50353196414653 4508.45433337418672 6631.54494536358743 29757.49718929882147 +25.20000000000009 1020033.64355035114568 4490.61327011455796 6607.72024114677515 29868.02293838821424 +25.30000000000009 1019965.03558890544809 4472.86328405806125 6583.94951796319856 29978.15160907399331 +25.40000000000009 1019896.67903689073864 4455.20323445623762 6560.23362761364660 30087.88410104004652 +25.50000000000009 1019828.57327506458387 4437.63201100434071 6536.57338576475740 30197.22132816693920 +25.60000000000009 1019760.71767605491914 4420.14853287926690 6512.96957313671010 30306.16421792968686 +25.70000000000010 1019693.11160472419579 4402.75174780849193 6489.42293665262241 30414.71371081530015 +25.80000000000010 1019625.75441852118820 4385.44063116901725 6465.93419055088270 30522.87075975950938 +25.90000000000010 1019558.64546782162506 4368.21418511535103 6442.50401746161879 30630.63632960202449 +26.00000000000010 1019491.78409625682980 4351.07143773558710 6419.13306944845135 30738.01139655971929 +26.10000000000010 1019425.16964103200007 4334.01144223468236 6395.82196901666157 30844.99694771719442 +26.20000000000010 1019358.80143323354423 4317.03327614403952 6372.57131008884608 30951.59398053414043 +26.30000000000010 1019292.67879812594038 4300.13604055655833 6349.38165894910981 31057.80350236895538 +26.40000000000011 1019226.80105543928221 4283.31885938632604 6326.25355515681531 31163.62653001810759 +26.50000000000011 1019161.16751964681316 4266.58087865215566 6303.18751243086172 31269.06408927071971 +26.60000000000011 1019095.77750023303088 4249.92126578419538 6280.18401950545285 31374.11721447790114 +26.70000000000011 1019030.63030195317697 4233.33920895287247 6257.24354095826311 31478.78694813632683 +26.80000000000011 1018965.72522508364636 4216.83391641944399 6234.36651801189873 31583.07434048563300 +26.90000000000011 1018901.06156566448044 4200.40461590745781 6211.55336930951034 31686.98044911916440 +27.00000000000011 1018836.63861573312897 4184.05055399445155 6188.80449166539256 31790.50633860765447 +27.10000000000012 1018772.45566355064511 4167.77099552323216 6166.12026079137559 31893.65308013540925 +27.20000000000012 1018708.51199382019695 4151.56522303210750 6143.50103199978639 31996.42175114859856 +27.30000000000012 1018644.80688789824490 4135.43253620345331 6120.94714088374076 32098.81343501526135 +27.40000000000012 1018581.33962399850134 4119.37225133002994 6098.45890397548828 32200.82922069665801 +27.50000000000012 1018518.10947738913819 4103.38370079846936 6076.03661938352525 32302.47020242958388 +27.60000000000012 1018455.11572058289312 4087.46623258938280 6053.68056740915472 32403.73747941930924 +27.70000000000012 1018392.35762352123857 4071.61920979354818 6031.39101114315690 32504.63215554279668 +27.80000000000013 1018329.83445375203155 4055.84201014366272 6009.16819704321097 32605.15533906185010 +27.90000000000013 1018267.54547660099342 4040.13402556115580 5987.01235549268949 32705.30814234590434 +28.00000000000013 1018205.48995533760171 4024.49466171757422 5964.92370134142311 32805.09168160411355 +28.10000000000013 1018143.66715133516118 4008.92333761007330 5942.90243442901919 32904.50707662646892 +28.20000000000013 1018082.07632422528695 3993.41948515055583 5920.94874009129308 33003.55545053361857 +28.30000000000013 1018020.71673204726540 3977.98254876801866 5899.06278965035926 33102.23792953514203 +28.40000000000013 1017959.58763139217626 3962.61198502368143 5877.24474088890474 33200.55564269598108 +28.50000000000014 1017898.68827754235826 3947.30726223848387 5855.49473850916002 33298.50972171079775 +28.60000000000014 1017838.01792460528668 3932.06786013255305 5833.81291457705538 33396.10130068595026 +28.70000000000014 1017777.57582564360928 3916.89326947625341 5812.19938895203813 33493.33151592889772 +28.80000000000014 1017717.36123280052561 3901.78299175244774 5790.65426970302178 33590.20150574476429 +28.90000000000014 1017657.37339742039330 3886.73653882960571 5769.17765351090293 33686.71241023981565 +29.00000000000014 1017597.61157016560901 3871.75343264540788 5747.76962605808512 33782.86537113166560 +29.10000000000014 1017538.07500112883281 3856.83320490051210 5726.43026240542622 33878.66153156596556 +29.20000000000014 1017478.76293994218577 3841.97539676214819 5705.15962735701214 33974.10203593938786 +29.30000000000015 1017419.67463588167448 3827.17955857722700 5683.95777581315451 34069.18802972866979 +29.40000000000015 1017360.80933796847239 3812.44524959465753 5662.82475311198414 34163.92065932555852 +29.50000000000015 1017302.16629506670870 3797.77203769657262 5641.76059536001503 34258.30107187742396 +29.60000000000015 1017243.74475597706623 3783.15949913817622 5620.76532975202554 34352.33041513342323 +29.70000000000015 1017185.54396952816751 3768.60721829593604 5599.83897488061029 34446.00983729595464 +29.80000000000015 1017127.56318466376979 3754.11478742385043 5578.98154103572688 34539.34048687729955 +29.90000000000015 1017069.80165052728262 3739.68180641752861 5558.19303049456448 34632.32351256122638 +30.00000000000016 1017012.25861654325854 3725.30788258583425 5537.47343780204301 34724.96006306946947 +30.10000000000016 1016954.93333249562420 3710.99263042984603 5516.82275004224903 34817.25128703283553 +30.20000000000016 1016897.82504860369954 3696.73567142890124 5496.24094710109330 34909.19833286687208 +30.30000000000016 1016840.93301559472457 3682.53663383349249 5475.72800192047725 35000.80234865188686 +30.40000000000016 1016784.25648477429058 3668.39515246479641 5455.28388074424129 35092.06448201723106 +30.50000000000016 1016727.79470809409395 3654.31086852062026 5434.90854335616041 35182.98588002963515 +30.60000000000016 1016671.54693821712863 3640.28342938756214 5414.60194331023649 35273.56768908556842 +30.70000000000017 1016615.51242858031765 3626.31248845918071 5394.36402815354450 35363.81105480740371 +30.80000000000017 1016559.69043345528189 3612.39770495998209 5374.19473964186727 35453.71712194329302 +30.90000000000017 1016504.08020800643135 3598.53874377503553 5354.09401394834822 35543.28703427065921 +31.00000000000017 1016448.68100834696088 3584.73527528503882 5334.06178186539546 35632.52193450312916 +31.10000000000017 1016393.49209159298334 3570.98697520665519 5314.09796900004312 35721.42296420088678 +31.20000000000017 1016338.51271591545083 3557.29352443795187 5294.20249596299072 35809.99126368422003 +31.30000000000017 1016283.74214059009682 3543.65460890877648 5274.37527855151711 35898.22797195026942 +31.40000000000018 1016229.17962604551576 3530.06991943591220 5254.61622792646813 35986.13422659279604 +31.50000000000018 1016174.82443390937988 3516.53915158285645 5234.92525078351264 36073.71116372490360 +31.60000000000018 1016120.67582705314271 3503.06200552407608 5215.30224951884247 36160.95991790462722 +31.70000000000018 1016066.73306963429786 3489.63818591359177 5195.74712238950451 36247.88162206327252 +31.80000000000018 1016012.99542713793926 3476.26740175775467 5176.25976366853047 36334.47740743643226 +31.90000000000018 1015959.46216641599312 3462.94936629207859 5156.84006379503717 36420.74840349757142 +32.00000000000018 1015906.13255572505295 3449.68379686199842 5137.48790951945466 36506.69573789415881 +32.10000000000019 1015853.00586476305034 3436.47041480742564 5118.20318404404043 36592.32053638614889 +32.20000000000019 1015800.08136470394675 3423.30894535098150 5098.98576715883428 36677.62392278688640 +32.30000000000019 1015747.35832823149394 3410.19911748978757 5079.83553537319312 36762.60701890620112 +32.40000000000019 1015694.83602957113180 3397.14066389069831 5060.75236204305929 36847.27094449575088 +32.50000000000019 1015642.51374452118762 3384.13332078886651 5041.73611749408610 36931.61681719646731 +32.60000000000019 1015590.39075048232917 3371.17682788953425 5022.78666914076530 37015.64575248803885 +32.70000000000019 1015538.46632648562081 3358.27092827294200 5003.90388160167913 37099.35886364038743 +32.80000000000020 1015486.73975322023034 3345.41536830226096 4985.08761681100259 37182.75726166708046 +32.90000000000020 1015435.21031305915676 3332.60989753444483 4966.33773412637584 37265.84205528059829 +33.00000000000020 1015383.87729008402675 3319.85426863391285 4947.65409043326508 37348.61435084936966 +33.10000000000020 1015332.73997010907624 3307.14823728896863 4929.03654024592652 37431.07525235658977 +33.20000000000020 1015281.79764070396777 3294.49156213086872 4910.48493580507693 37513.22586136069003 +33.30000000000020 1015231.04959121532738 3281.88400465545374 4891.99912717238112 37595.06727695744485 +33.40000000000020 1015180.49511278781574 3269.32532914726289 4873.57896232185612 37676.60059574365005 +33.50000000000021 1015130.13349838391878 3256.81530260604859 4855.22428722829864 37757.82691178235109 +33.60000000000021 1015079.96404280269053 3244.35369467561304 4836.93494595281481 37838.74731656949007 +33.70000000000021 1015029.98604269814678 3231.94027757489675 4818.71078072556793 37919.36289900203701 +33.80000000000021 1014980.19879659614526 3219.57482603124208 4800.55163202581298 37999.67474534745998 +33.90000000000021 1014930.60160491103306 3207.25711721576317 4782.45733865931652 38079.68393921455572 +34.00000000000021 1014881.19376996112987 3194.98693068075363 4764.42773783324628 38159.39156152554642 +34.10000000000021 1014831.97459598351270 3182.76404829906869 4746.46266522860424 38238.79869048943510 +34.20000000000022 1014782.94338914833497 3170.58825420541552 4728.56195507028951 38317.90640157657617 +34.30000000000022 1014734.09945757186506 3158.45933473949117 4710.72544019486304 38396.71576749441738 +34.40000000000022 1014685.44211132929195 3146.37707839090945 4692.95295211609300 38475.22785816433316 +34.50000000000022 1014636.97066246683244 3134.34127574585773 4675.24432108834208 38553.44374069960031 +34.60000000000022 1014588.68442501290701 3122.35171943542991 4657.59937616788011 38631.36447938440688 +34.70000000000022 1014540.58271498896647 3110.40820408557875 4640.01794527217407 38708.99113565387233 +34.80000000000022 1014492.66485041962005 3098.51052626863702 4622.49985523723262 38786.32476807507192 +34.90000000000023 1014444.93015134206507 3086.65848445635902 4605.04493187305980 38863.36643232902861 +35.00000000000023 1014397.37793981516734 3074.85187897442893 4587.65300001728519 38940.11718119357829 +35.10000000000023 1014350.00753992784303 3063.09051195839311 4570.32388358701792 39016.57806452720251 +35.20000000000023 1014302.81827780685853 3051.37418731096659 4553.05740562899791 39092.75012925365445 +35.30000000000023 1014255.80948162428103 3039.70271066067380 4535.85338836808478 39168.63441934747243 +35.40000000000023 1014208.98048160434701 3028.07588932177669 4518.71165325414222 39244.23197582027205 +35.50000000000023 1014162.33061002986506 3016.49353225545201 4501.63202100737635 39319.54383670783864 +35.60000000000024 1014115.85920124826953 3004.95545003217421 4484.61431166216607 39394.57103705796180 +35.70000000000024 1014069.56559167685919 2993.46145479526831 4467.65834460944097 39469.31460891899769 +35.80000000000024 1014023.44911980815232 2982.01136022559285 4450.76393863765406 39543.77558132915146 +35.90000000000024 1013977.50912621442694 2970.60498150731746 4433.93091197239028 39617.95498030644376 +36.00000000000024 1013931.74495355179533 2959.24213529476174 4417.15908231465801 39691.85382883931743 +36.10000000000024 1013886.15594656451140 2947.92263968025554 4400.44826687790282 39765.47314687789185 +36.20000000000024 1013840.74145208788104 2936.64631416299517 4383.79828242378881 39838.81395132585749 +36.30000000000025 1013795.50081905198749 2925.41297961885857 4367.20894529678299 39911.87725603292347 +36.40000000000025 1013750.43339848390315 2914.22245827114966 4350.68007145758384 39984.66407178786903 +36.50000000000025 1013705.53854351071641 2903.07457366224253 4334.21147651542833 40057.17540631216252 +36.60000000000025 1013660.81560936104506 2891.96915062609605 4317.80297575931672 40129.41226425408968 +36.70000000000025 1013616.26395336736459 2880.90601526161163 4301.45438418818867 40201.37564718341309 +36.80000000000025 1013571.88293496717233 2869.88499490680670 4285.16551654008344 40273.06655358654825 +36.90000000000025 1013527.67191570426803 2858.90591811377681 4268.93618732031518 40344.48597886221978 +37.00000000000026 1013483.63025922991801 2847.96861462442166 4252.76621082870315 40415.63491531756154 +37.10000000000026 1013439.75733130308799 2837.07291534691103 4236.65540118587433 40486.51435216470418 +37.20000000000026 1013396.05249979125801 2826.21865233286644 4220.60357235867832 40557.12527551779931 +37.30000000000026 1013352.51513467018958 2815.40565875523544 4204.61053818474284 40627.46866839044378 +37.40000000000026 1013309.14460802404210 2804.63376888683570 4188.67611239618782 40697.54551069352601 +37.50000000000026 1013265.94029404502362 2793.90281807954761 4172.80010864253654 40767.35677923346520 +37.60000000000026 1013222.90156903269235 2783.21264274413716 4156.98234051284453 40836.90344771084347 +37.70000000000027 1013180.02781139337458 2772.56308033068399 4141.22262155706903 40906.18648671939445 +37.80000000000027 1013137.31840163888410 2761.95396930959851 4125.52076530670820 40975.20686374534853 +37.90000000000027 1013094.77272238547448 2751.38514915321002 4109.87658529472992 41043.96554316712718 +38.00000000000027 1013052.39015835244209 2740.85646031790384 4094.28989507481538 41112.46348625537212 +38.10000000000027 1013010.17009636049625 2730.36774422679264 4078.76050823993819 41180.70165117328725 +38.20000000000027 1012968.11192533001304 2719.91884325290448 4063.28823844030057 41248.68099297728622 +38.30000000000027 1012926.21503627905622 2709.50960070287101 4047.87289940064647 41316.40246361796017 +38.40000000000028 1012884.47882232116535 2699.13986080109726 4032.51430493697308 41383.86701194130728 +38.50000000000028 1012842.90267866326030 2688.80946867440252 4017.21226897266024 41451.07558369025355 +38.60000000000028 1012801.48600260296371 2678.51827033711197 4001.96660555403378 41518.02912150646443 +38.70000000000028 1012760.22819352627266 2668.26611267658882 3986.77712886538529 41584.72856493236759 +38.80000000000028 1012719.12865290453192 2658.05284343918947 3971.64365324346090 41651.17485041345935 +38.90000000000028 1012678.18678429175634 2647.87831121663066 3956.56599319143879 41717.36891130085132 +39.00000000000028 1012637.40199332148768 2637.74236543275401 3941.54396339241430 41783.31167785404250 +39.10000000000029 1012596.77368770365138 2627.64485633067579 3926.57737872240159 41849.00407724391698 +39.20000000000029 1012556.30127722152974 2617.58563496030956 3911.66605426287470 41914.44703355595993 +39.30000000000029 1012515.98417372792028 2607.56455316624897 3896.80980531285832 41979.64146779367729 +39.40000000000029 1012475.82179114187602 2597.58146357600071 3882.00844740058483 42044.58829788222647 +39.50000000000029 1012435.81354544521309 2587.63621958855401 3867.26179629472881 42109.28843867223623 +39.60000000000029 1012395.95885467843618 2577.72867536327931 3852.56966801523777 42173.74280194381572 +39.70000000000029 1012356.25713893712964 2567.85868580914257 3837.93187884376493 42237.95229641073820 +39.80000000000030 1012316.70782036799937 2558.02610657422611 3823.34824533372421 42301.91782772479928 +39.90000000000030 1012277.31032316491473 2548.23079403554675 3808.81858431997398 42365.64029848036444 +40.00000000000030 1012238.06407356448472 2538.47260528916013 3794.34271292814537 42429.12060821903287 +40.10000000000030 1012198.96849984209985 2528.75139814054546 3779.92044858362169 42492.35965343450516 +40.20000000000030 1012160.02303230774123 2519.06703109525733 3765.55160902018724 42555.35832757756725 +40.30000000000030 1012121.22710330132395 2509.41936334983848 3751.23601228834923 42618.11752106123458 +40.40000000000030 1012082.58014718838967 2499.80825478298675 3736.97347676334812 42680.63812126604171 +40.50000000000031 1012044.08160035556648 2490.23356594696361 3722.76382115286242 42742.92101254543377 +40.60000000000031 1012005.73090120579582 2480.69515805924084 3708.60686450442290 42804.96707623131806 +40.70000000000031 1011967.52749015414156 2471.19289299437651 3694.50242621253983 42866.77719063972472 +40.80000000000031 1011929.47080962255131 2461.72663327611099 3680.45032602555602 42928.35223107659840 +40.90000000000031 1011891.56030403519981 2452.29624206967810 3666.45038405223477 42989.69306984369177 +41.00000000000031 1011853.79541981383227 2442.90158317432588 3652.50242076808854 43050.80057624456094 +41.10000000000031 1011816.17560537264217 2433.54252101603515 3638.60625702145990 43111.67561659069906 +41.20000000000032 1011778.70031111326534 2424.21892064043550 3624.76171403935950 43172.31905420772091 +41.30000000000032 1011741.36898942012340 2414.93064770590809 3610.96861343307091 43232.73174944170751 +41.40000000000032 1011704.18109465483576 2405.67756847687178 3597.22677720353067 43292.91455966559442 +41.50000000000032 1011667.13608315144666 2396.45954981724663 3583.53602774648880 43352.86833928565466 +41.60000000000032 1011630.23341321118642 2387.27645918408643 3569.89618785745597 43412.59393974809791 +41.70000000000032 1011593.47254509723280 2378.12816462137926 3556.30708073644882 43472.09220954572083 +41.80000000000032 1011556.85294102958869 2369.01453475400604 3542.76852999253470 43531.36399422465911 +41.90000000000033 1011520.37406517949421 2359.93543878185665 3529.28035964818491 43590.41013639119774 +42.00000000000033 1011484.03538366453722 2350.89074647409552 3515.84239414344302 43649.23147571866866 +42.10000000000033 1011447.83636454283260 2341.88032816357190 3502.45445833991289 43707.82884895439202 +42.20000000000033 1011411.77647780801635 2332.90405474137287 3489.11637752457273 43766.20308992672653 +42.30000000000033 1011375.85519538365770 2323.96179765151101 3475.82797741342029 43824.35502955213451 +42.40000000000033 1011340.07199111767113 2315.05342888574569 3462.58908415495625 43882.28549584235589 +42.50000000000033 1011304.42634077707771 2306.17882097853226 3449.39952433350982 43939.99531391160417 +42.60000000000034 1011268.91772204241715 2297.33784700209435 3436.25912497241006 43997.48530598382786 +42.70000000000034 1011233.54561450204346 2288.53038056161677 3423.16771353701279 44054.75629140003730 +42.80000000000034 1011198.30949964688625 2279.75629579055521 3410.12511793758085 44111.80908662565344 +42.90000000000034 1011163.20886086462997 2271.01546734605699 3397.13116653202906 44168.64450525794382 +43.00000000000034 1011128.24318343412597 2262.30777040449357 3384.18568812853482 44225.26335803348047 +43.10000000000034 1011093.41195451992098 2253.63308065709543 3371.28851198801749 44281.66645283561957 +43.20000000000034 1011058.71466316643637 2244.99127430569115 3358.43946782649482 44337.85459470208298 +43.30000000000035 1011024.15080029226374 2236.38222805854548 3345.63838581731670 44393.82858583252528 +43.40000000000035 1010989.71985868492629 2227.80581912629350 3332.88509659328201 44449.58922559614439 +43.50000000000035 1010955.42133299470879 2219.26192521796656 3320.17943124864314 44505.13731053936499 +43.60000000000035 1010921.25471972906962 2210.75042453710967 3307.52122134099864 44560.47363439350738 +43.70000000000035 1010887.21951724705286 2202.27119577798476 3294.91029889308038 44615.59898808252183 +43.80000000000035 1010853.31522575358395 2193.82411812186047 3282.34649639443887 44670.51415973073745 +43.90000000000035 1010819.54134729353245 2185.40907123338138 3269.82964680302894 44725.21993467064749 +44.00000000000036 1010785.89738574612420 2177.02593525701832 3257.35958354669719 44779.71709545069461 +44.10000000000036 1010752.38284681923687 2168.67459081359357 3244.93614052457951 44834.00642184313620 +44.20000000000036 1010718.99723804334644 2160.35491899688350 3232.55915210840567 44888.08869085188053 +44.30000000000036 1010685.74006876617204 2152.06680137029070 3220.22845314371853 44941.96467672035214 +44.40000000000036 1010652.61085014650598 2143.81011996358575 3207.94387895100817 44995.63515093941533 +44.50000000000036 1010619.60909514874220 2135.58475726971983 3195.70526532676558 45049.10088225526852 +44.60000000000036 1010586.73431853693910 2127.39059624169931 3183.51244854445531 45102.36263667738240 +44.70000000000037 1010553.98603686911520 2119.22752028952618 3171.36526535541361 45155.42117748645978 +44.80000000000037 1010521.36376849131193 2111.09541327719853 3159.26355298967337 45208.27726524238096 +44.90000000000037 1010488.86703353188932 2102.99415951977244 3147.20714915671488 45260.93165779220726 +45.00000000000037 1010456.49535389582161 2094.92364378047978 3135.19589204614977 45313.38511027815548 +45.10000000000037 1010424.24825325876009 2086.88375126790379 3123.22962032833857 45365.63837514559418 +45.20000000000037 1010392.12525706132874 2078.87436763320829 3111.30817315494141 45417.69220215106907 +45.30000000000037 1010360.12589250341989 2070.89537896741922 3099.43139015940778 45469.54733837032109 +45.40000000000038 1010328.24968853814062 2062.94667179875705 3087.59911145740625 45521.20452820631181 +45.50000000000038 1010296.49617586610839 2055.02813309002067 3075.81117764719465 45572.66451339727064 +45.60000000000038 1010264.86488692986313 2047.13965023601622 3064.06742980993431 45623.92803302472748 +45.70000000000038 1010233.35535590804648 2039.28111106103484 3052.36770950994833 45674.99582352155994 +45.80000000000038 1010201.96711870923173 2031.45240381637450 3040.71185879493078 45725.86861868006235 +45.90000000000038 1010170.69971296656877 2023.65341717790579 3029.09972019609950 45776.54714965997846 +46.00000000000038 1010139.55267803196330 2015.88404024367969 3017.53113672830386 45827.03214499657770 +46.10000000000039 1010108.52555497013964 2008.14416253157719 3006.00595189008254 45877.32433060871699 +46.20000000000039 1010077.61788655293640 2000.43367397699808 2994.52400966367577 45927.42442980688793 +46.30000000000039 1010046.82921725360211 1992.75246493058899 2983.08515451499261 45977.33316330128582 +46.40000000000039 1010016.15909324109089 1985.10042615600855 2971.68923139353592 46027.05124920987146 +46.50000000000039 1009985.60706237400882 1977.47744882772918 2960.33608573228503 46076.57940306643286 +46.60000000000039 1009955.17267419537529 1969.88342452887355 2949.02556344753657 46125.91833782863978 +46.70000000000039 1009924.85547992656939 1962.31824524908643 2937.75751093870986 46175.06876388609817 +46.80000000000040 1009894.65503246150911 1954.78180338243851 2926.53177508811132 46224.03138906841195 +46.90000000000040 1009864.57088636117987 1947.27399172536366 2915.34820326066392 46272.80691865321569 +47.00000000000040 1009834.60259784793016 1939.79470347462620 2904.20664330360205 46321.39605537422904 +47.10000000000040 1009804.74972479965072 1932.34383222531937 2893.10694354613088 46369.79949942928943 +47.20000000000040 1009775.01182674407028 1924.92127196889305 2882.04895279905395 46418.01794848839199 +47.30000000000040 1009745.38846485316753 1917.52691709121018 2871.03252035436890 46466.05209770170768 +47.40000000000040 1009715.87920193735044 1910.16066237063046 2860.05749598483226 46513.90263970761589 +47.50000000000041 1009686.48360244010109 1902.82240297612157 2849.12372994349471 46561.57026464069349 +47.60000000000041 1009657.20123243203852 1895.51203446539625 2838.23107296320813 46609.05566013975476 +47.70000000000041 1009628.03165960544720 1888.22945278307475 2827.37937625610448 46656.35951135581126 +47.80000000000041 1009598.97445326845627 1880.97455425887188 2816.56849151304914 46703.48250096008269 +47.90000000000041 1009570.02918433956802 1873.74723560580810 2805.79827090306617 46750.42530915196403 +48.00000000000041 1009541.19542534218635 1866.54739391844441 2795.06856707274210 46797.18861366701458 +48.10000000000041 1009512.47275039879605 1859.37492667113861 2784.37923314560248 46843.77308978489600 +48.20000000000041 1009483.86073522537481 1852.22973171632430 2773.73012272146707 46890.17941033732495 +48.30000000000042 1009455.35895712592173 1845.11170728281149 2763.12108987578222 46936.40824571601843 +48.40000000000042 1009426.96699498686939 1838.02075197410727 2752.55198915893243 46982.46026388061728 +48.50000000000042 1009398.68442927161232 1830.95676476675681 2742.02267559552911 47028.33613036660245 +48.60000000000042 1009370.51084201491904 1823.91964500870381 2731.53300468368207 47074.03650829319668 +48.70000000000042 1009342.44581681734417 1816.90929241767094 2721.08283239424964 47119.56205837125890 +48.80000000000042 1009314.48893883975688 1809.92560707955704 2710.67201517006970 47164.91343891116412 +48.90000000000042 1009286.63979479786940 1802.96848944685371 2700.30040992517525 47210.09130583066872 +49.00000000000043 1009258.89797295676544 1796.03784033707893 2689.96787404398992 47255.09631266275392 +49.10000000000043 1009231.26306312531233 1789.13356093122729 2679.67426538050813 47299.92911056348385 +49.20000000000043 1009203.73465665103868 1782.25555277223748 2669.41944225745920 47344.59034831982717 +49.30000000000043 1009176.31234641419724 1775.40371776347524 2659.20326346545471 47389.08067235744966 +49.40000000000043 1009148.99572682264261 1768.57795816723274 2649.02558826212316 47433.40072674854309 +49.50000000000043 1009121.78439380647615 1761.77817660324195 2638.88627637122681 47477.55115321958147 +49.60000000000043 1009094.67794481245801 1755.00427604720403 2628.78518798176856 47521.53259115909896 +49.70000000000044 1009067.67597879865207 1748.25615982933255 2618.72218374708291 47565.34567762546067 +49.80000000000044 1009040.77809622907080 1741.53373163291076 2608.69712478391375 47608.99104735457513 +49.90000000000044 1009013.98389906843659 1734.83689549286328 2598.70987267148121 47652.46933276764321 +50.00000000000000 1008987.29299077682663 1728.16555579436863 2588.76028945058079 47695.78116397864505 \ No newline at end of file diff --git a/cpp/tests/data/ode-seir-metapop-compare.csv b/cpp/tests/data/ode-seir-metapop-compare.csv new file mode 100644 index 0000000000..6b6ed790b5 --- /dev/null +++ b/cpp/tests/data/ode-seir-metapop-compare.csv @@ -0,0 +1,26 @@ + # t S_0 E_0 I_0 R_0 S_1 E_1 I_1 R_1 S_2 E_2 I_2 R_2 S_3 E_3 I_3 R_3 +0.000000000000000000 1049000.000000000000000000 10000.000000000000000000 1000.000000000000000000 1000.000000000000000000 1049000.000000000000000000 10000.000000000000000000 1000.000000000000000000 1000.000000000000000000 1049000.000000000000000000 10000.000000000000000000 1000.000000000000000000 1000.000000000000000000 1049000.000000000000000000 10000.000000000000000000 1000.000000000000000000 1000.000000000000000000 +0.100000000000000006 1048970.988352040527388453 9838.271405749961559195 1172.626704245788005210 1018.113537963836847666 1048970.988352040527388453 9838.271405749961559195 1172.626704245788005210 1018.113537963836847666 1048970.988352040527388453 9838.271405749961559195 1172.626704245788005210 1018.113537963836847666 1048970.988352040527388453 9838.271405749961559195 1172.626704245788005210 1018.113537963836847666 +0.550000000000000044 1048786.562808100134134293 9199.938732493899806286 1880.226382551424649137 1133.272076854476154040 1048786.562808100134134293 9199.938732493899806286 1880.226382551424649137 1133.272076854476154040 1048786.562808100134134293 9199.938732493899806286 1880.226382551424649137 1133.272076854476154040 1048786.562808100134134293 9199.938732493899806286 1880.226382551424649137 1133.272076854476154040 +1.571335751995554197 1048092.401353218709118664 8194.697825347475372837 3146.000554222973278229 1566.900267210686934050 1048092.401353218709118664 8194.697825347475372837 3146.000554222973278229 1566.900267210686934050 1048092.401353218709118664 8194.697825347475372837 3146.000554222973278229 1566.900267210686934050 1048092.401353218709118664 8194.697825347475372837 3146.000554222973278229 1566.900267210686934050 +2.721576076432889124 1046961.386030971654690802 7588.350638500698551070 4176.225815231045999099 2274.037515296420224331 1046961.386030971654690802 7588.350638500698551070 4176.225815231045999099 2274.037515296420224331 1046961.386030971654690802 7588.350638500698551070 4176.225815231045999099 2274.037515296420224331 1046961.386030971654690802 7588.350638500698551070 4176.225815231045999099 2274.037515296420224331 +4.029943604597698403 1045349.619403100456111133 7330.778352213967991702 5036.529414663581519562 3283.072830021797926747 1045349.619403100456111133 7330.778352213967991702 5036.529414663581519562 3283.072830021797926747 1045349.619403100456111133 7330.778352213967991702 5036.529414663581519562 3283.072830021797926747 1045349.619403100456111133 7330.778352213967991702 5036.529414663581519562 3283.072830021797926747 +5.507034559643384952 1043220.440254993853159249 7377.465553596446625306 5783.675800650045857765 4618.418390759416979563 1043220.440254993853159249 7377.465553596446625306 5783.675800650045857765 4618.418390759416979563 1043220.440254993853159249 7377.465553596446625306 5783.675800650045857765 4618.418390759416979563 1043220.440254993853159249 7377.465553596446625306 5783.675800650045857765 4618.418390759416979563 +7.181045772330549859 1040493.505196049343794584 7685.356236648490266816 6488.497226337810388941 6332.641340964195478591 1040493.505196049343794584 7685.356236648490266816 6488.497226337810388941 6332.641340964195478591 1040493.505196049343794584 7685.356236648490266816 6488.497226337810388941 6332.641340964195478591 1040493.505196049343794584 7685.356236648490266816 6488.497226337810388941 6332.641340964195478591 +9.068602661997122283 1037073.405391793348826468 8222.868082855427928735 7214.758721446800336707 8488.967803904286483885 1037073.405391793348826468 8222.868082855427928735 7214.758721446800336707 8488.967803904286483885 1037073.405391793348826468 8222.868082855427928735 7214.758721446800336707 8488.967803904286483885 1037073.405391793348826468 8222.868082855427928735 7214.758721446800336707 8488.967803904286483885 +11.248067398941367756 1032694.429363684146665037 8997.711351056386774871 8047.601685562283819309 11260.257599697049954557 1032694.429363684146665037 8997.711351056386774871 8047.601685562283819309 11260.257599697049954557 1032694.429363684146665037 8997.711351056386774871 8047.601685562283819309 11260.257599697049954557 1032694.429363684146665037 8997.711351056386774871 8047.601685562283819309 11260.257599697049954557 +11.624942631692711359 1031892.499271133681759238 9142.254586236071190797 8194.879248038520017872 11770.366894591707023210 1031892.499271133681759238 9142.254586236071190797 8194.879248038520017872 11770.366894591707023210 1031892.499271133681759238 9142.254586236071190797 8194.879248038520017872 11770.366894591707023210 1031892.499271133681759238 9142.254586236071190797 8194.879248038520017872 11770.366894591707023210 +12.001817864444054962 1031192.262633586768060923 9177.270036856716615148 8340.744771348789072363 12289.722558207797192154 1031192.262633586768060923 9177.270036856716615148 8340.744771348789072363 12289.722558207797192154 1031192.262633586768060923 9177.270036856716615148 8340.744771348789072363 12289.722558207797192154 1031192.262633586768060923 9177.270036856716615148 8340.744771348789072363 12289.722558207797192154 +12.529611483968700725 1030606.423360764631070197 8845.787659644680388737 8516.279530909305321984 13031.509448681445064722 1030606.423360764631070197 8845.787659644680388737 8516.279530909305321984 13031.509448681445064722 1030606.423360764631070197 8845.787659644680388737 8516.279530909305321984 13031.509448681445064722 1030606.423360764631070197 8845.787659644680388737 8516.279530909305321984 13031.509448681445064722 +13.057405103493346488 1030131.377186079975217581 8443.798219163865724113 8638.425499267183113261 13786.399095489065075526 1030131.377186079975217581 8443.798219163865724113 8638.425499267183113261 13786.399095489065075526 1030131.377186079975217581 8443.798219163865724113 8638.425499267183113261 13786.399095489065075526 1030131.377186079975217581 8443.798219163865724113 8638.425499267183113261 13786.399095489065075526 +15.002878194169083415 1028352.653943004552274942 7292.666872994709592604 8738.639010714050527895 16616.040173286801291397 1028352.653943004552274942 7292.666872994709592604 8738.639010714050527895 16616.040173286801291397 1028352.653943004552274942 7292.666872994709592604 8738.639010714050527895 16616.040173286801291397 1028352.653943004552274942 7292.666872994709592604 8738.639010714050527895 16616.040173286801291397 +16.948351284844822118 1026594.450561258592642844 6481.962568733895750483 8505.735030830541290925 19417.851839176964858780 1026594.450561258592642844 6481.962568733895750483 8505.735030830541290925 19417.851839176964858780 1026594.450561258592642844 6481.962568733895750483 8505.735030830541290925 19417.851839176964858780 1026594.450561258592642844 6481.962568733895750483 8505.735030830541290925 19417.851839176964858780 +19.121289365575044883 1024712.823017425718717277 5803.026431943653733470 8062.481969843786828278 22421.668580786674283445 1024712.823017425718717277 5803.026431943653733470 8062.481969843786828278 22421.668580786674283445 1024712.823017425718717277 5803.026431943653733470 8062.481969843786828278 22421.668580786674283445 1024712.823017425718717277 5803.026431943653733470 8062.481969843786828278 22421.668580786674283445 +21.568220941483573938 1022730.819907458848319948 5201.036499887130958086 7476.448597236990281090 25591.694995416903111618 1022730.819907458848319948 5201.036499887130958086 7476.448597236990281090 25591.694995416903111618 1022730.819907458848319948 5201.036499887130958086 7476.448597236990281090 25591.694995416903111618 1022730.819907458848319948 5201.036499887130958086 7476.448597236990281090 25591.694995416903111618 +24.302867828470034794 1020699.985484831035137177 4646.677304804762570711 6807.136086702391366998 28846.201123661736346548 1020699.985484831035137177 4646.677304804762570711 6807.136086702391366998 28846.201123661736346548 1020699.985484831035137177 4646.677304804762570711 6807.136086702391366998 28846.201123661736346548 1020699.985484831035137177 4646.677304804762570711 6807.136086702391366998 28846.201123661736346548 +27.405783498438019308 1018625.438826579484157264 4112.061390983284582035 6085.048903788306233764 32177.450878648814978078 1018625.438826579484157264 4112.061390983284582035 6085.048903788306233764 32177.450878648814978078 1018625.438826579484157264 4112.061390983285491529 6085.048903788305324269 32177.450878648814978078 1018625.438826579484157264 4112.061390983284582035 6085.048903788306233764 32177.450878648814978078 +30.982097872048104392 1016514.052626653225161135 3582.158500640592137643 5328.958786543431415339 35574.830086162648512982 1016514.052626653225161135 3582.158500640592592390 5328.958786543431415339 35574.830086162648512982 1016514.052626653225161135 3582.158500640593047137 5328.958786543431415339 35574.830086162648512982 1016514.052626653225161135 3582.158500640592137643 5328.958786543431415339 35574.830086162648512982 +35.174157269526475034 1014377.523218245478346944 3050.869285028250033065 4551.750098480431915959 39019.857398245752847288 1014377.523218245478346944 3050.869285028250487812 4551.750098480431915959 39019.857398245752847288 1014377.523218245478346944 3050.869285028250487812 4551.750098480432825454 39019.857398245752847288 1014377.523218245478346944 3050.869285028250033065 4551.750098480431915959 39019.857398245752847288 +40.165160093022812760 1012242.354254877660423517 2520.413323501484228473 3767.284556028632778180 42469.947865592235757504 1012242.354254877660423517 2520.413323501484228473 3767.284556028634142422 42469.947865592235757504 1012242.354254877660423517 2520.413323501484683220 3767.284556028633687674 42469.947865592235757504 1012242.354254877660423517 2520.413323501484228473 3767.284556028632778180 42469.947865592235757504 +46.138354563962117538 1010170.613532148068770766 2004.483312102868012516 3000.391258669248145452 45824.511897079959453549 1010170.613532148068770766 2004.483312102867785143 3000.391258669249054947 45824.511897079959453549 1010170.613532148068770766 2004.483312102868694637 3000.391258669249054947 45824.511897079959453549 1010170.613532148068770766 2004.483312102868012516 3000.391258669248145452 45824.511897079959453549 +50.000000000000000000 1009063.586620887159369886 1728.076734493041385576 2588.504609791979419242 47619.832034827901225071 1009063.586620887159369886 1728.076734493041385576 2588.504609791979873989 47619.832034827901225071 1009063.586620887159369886 1728.076734493041840324 2588.504609791979873989 47619.832034827901225071 1009063.586620887159369886 1728.076734493041385576 2588.504609791979419242 47619.832034827901225071 \ No newline at end of file diff --git a/cpp/tests/data/seir-compare.csv b/cpp/tests/data/seir-compare.csv index 2a457c2ce5..239da95a90 100644 --- a/cpp/tests/data/seir-compare.csv +++ b/cpp/tests/data/seir-compare.csv @@ -1,32 +1,38 @@ # t S E I R -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 +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 diff --git a/cpp/tests/test_odemetapop.cpp b/cpp/tests/test_odemetapop.cpp index 520d3631a8..500722714d 100644 --- a/cpp/tests/test_odemetapop.cpp +++ b/cpp/tests/test_odemetapop.cpp @@ -71,6 +71,54 @@ TEST_F(ModelTestOdeMetapop, checkPopulationConservation) EXPECT_NEAR(num_persons, total_population_per_region * (size_t)model.parameters.get_num_regions(), 1e-9); } +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.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"); + auto result = mio::simulate>(t0, tmax, dt, model); + + result.print_table({"S", "E", "I", "R"}, 16, 18); + + 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_F(ModelTestOdeMetapop, check_constraints_parameters) { model.parameters.set>(5.2); @@ -266,7 +314,7 @@ TEST(TestOdeMetapop, compareSEIR) 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"); + std::vector> refData = load_test_data_csv("ode-seir-compare-euler.csv"); ASSERT_EQ(refData.size(), static_cast(result.get_num_time_points())); @@ -296,50 +344,3 @@ TEST(TestOdeMetapop, compareSEIR) } } } - -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.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 13ec735c85ec17644091958bfe781af61445e50a Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Tue, 13 May 2025 14:12:12 +0200 Subject: [PATCH 096/105] remove debugging artifact --- cpp/examples/ode_seir_metapop.cpp | 7 ++----- cpp/tests/test_odemetapop.cpp | 2 -- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/cpp/examples/ode_seir_metapop.cpp b/cpp/examples/ode_seir_metapop.cpp index 711e27195a..27b6d4d6ab 100644 --- a/cpp/examples/ode_seir_metapop.cpp +++ b/cpp/examples/ode_seir_metapop.cpp @@ -11,12 +11,9 @@ int main() const ScalarType tmax = 10; ScalarType dt = 0.1; - size_t number_regions = 3; - size_t number_age_groups = 1; + mio::oseirmetapop::Model model(3, 1); - mio::oseirmetapop::Model model(number_regions, number_age_groups); - - for (size_t i = 0; i < number_regions; i++) { + for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { model.populations[{mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible}] = 10000; } diff --git a/cpp/tests/test_odemetapop.cpp b/cpp/tests/test_odemetapop.cpp index 500722714d..c34ef37ab2 100644 --- a/cpp/tests/test_odemetapop.cpp +++ b/cpp/tests/test_odemetapop.cpp @@ -88,8 +88,6 @@ TEST_F(ModelTestOdeMetapop, compareWithPreviousRun) std::vector> refData = load_test_data_csv("ode-seir-metapop-compare.csv"); auto result = mio::simulate>(t0, tmax, dt, model); - result.print_table({"S", "E", "I", "R"}, 16, 18); - ASSERT_EQ(refData.size(), static_cast(result.get_num_time_points())); for (Eigen::Index irow = 0; irow < result.get_num_time_points(); ++irow) { From fc94b55f87f2b1dc44231b2690d5196202dfb0f1 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Wed, 14 May 2025 09:37:36 +0200 Subject: [PATCH 097/105] add documentation --- cpp/models/ode_seir_metapop/infection_state.h | 26 +++++++-- cpp/models/ode_seir_metapop/model.cpp | 20 ++++++- cpp/models/ode_seir_metapop/model.h | 56 ++++++++++++++++--- cpp/models/ode_seir_metapop/parameters.h | 47 ++++++++++++---- cpp/models/ode_seir_metapop/regions.h | 20 ++++++- docs/source/cpp/deterministic_metapop.rst | 13 ++++- 6 files changed, 156 insertions(+), 26 deletions(-) diff --git a/cpp/models/ode_seir_metapop/infection_state.h b/cpp/models/ode_seir_metapop/infection_state.h index bb4cca92d4..a0c2faf8c2 100644 --- a/cpp/models/ode_seir_metapop/infection_state.h +++ b/cpp/models/ode_seir_metapop/infection_state.h @@ -1,4 +1,22 @@ - +/* +* Copyright (C) 2020-2025 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. +*/ #ifndef ODESEIRMETAPOP_INFECTIONSTATE_H #define ODESEIRMETAPOP_INFECTIONSTATE_H @@ -8,9 +26,9 @@ namespace oseirmetapop { /** - * @brief The InfectionState enum describes the possible - * categories for the infectious state of persons - */ + * @brief The InfectionState enum describes the possible + * categories for the infectious state of persons + */ enum class InfectionState { Susceptible, diff --git a/cpp/models/ode_seir_metapop/model.cpp b/cpp/models/ode_seir_metapop/model.cpp index 25e3f0b743..bf0a8cd4eb 100644 --- a/cpp/models/ode_seir_metapop/model.cpp +++ b/cpp/models/ode_seir_metapop/model.cpp @@ -1,4 +1,22 @@ - +/* +* Copyright (C) 2020-2025 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 "ode_seir_metapop/model.h" namespace mio diff --git a/cpp/models/ode_seir_metapop/model.h b/cpp/models/ode_seir_metapop/model.h index cfad5089f2..71b48b0412 100644 --- a/cpp/models/ode_seir_metapop/model.h +++ b/cpp/models/ode_seir_metapop/model.h @@ -1,4 +1,22 @@ - +/* +* Copyright (C) 2020-2025 MEmilio +* +* Authors: Carlotta Gerstein, Martin J. Kuehn, Henrik Zunker +* +* 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. +*/ #ifndef ODESEIRMETAPOP_MODEL_H #define ODESEIRMETAPOP_MODEL_H @@ -21,13 +39,16 @@ namespace oseirmetapop { /******************** - * define the model * - ********************/ +* define the model * +********************/ using Flows = TypeList, Flow, Flow>; +/** + * @brief The Model holds the Parameters and the initial Populations and defines the ordinary differential equations. + */ template class Model : public FlowModel, Parameters, Flows> @@ -40,12 +61,24 @@ class Model : public FlowModel> pop, Eigen::Ref> y, FP t, Eigen::Ref> flows) const override { @@ -110,8 +143,8 @@ class Model : public FlowModel get_reproduction_number(size_t t_idx, const mio::TimeSeries& y) @@ -193,8 +226,8 @@ class Model : public FlowModel& y) { @@ -206,6 +239,10 @@ class Model : public FlowModelparameters.template get>() = population_after_commuting; } + /** + * @brief Set the CommutingStrengths matrix without data. + * This function sets the CommutingStrengths matrix to the identity matrix, which corresponds to no commuting between Region%s. + * This prevents division by zero but does not produce meaningful results. + */ void set_commuting_strengths() { auto number_regions = (size_t)this->parameters.get_num_regions(); diff --git a/cpp/models/ode_seir_metapop/parameters.h b/cpp/models/ode_seir_metapop/parameters.h index 5dd9604cd8..e76dfe1c4f 100644 --- a/cpp/models/ode_seir_metapop/parameters.h +++ b/cpp/models/ode_seir_metapop/parameters.h @@ -1,4 +1,22 @@ - +/* +* Copyright (C) 2020-2025 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. +*/ #ifndef ODESEIRMETAPOP_PARAMETERS_H #define ODESEIRMETAPOP_PARAMETERS_H @@ -18,8 +36,8 @@ namespace oseirmetapop { /**************************************************** - * Define Parameters of the SEIR model with mobility * - ****************************************************/ +* Define Parameters of the SEIR model with mobility * +****************************************************/ /** * @brief Probability of getting infected from a contact. @@ -38,7 +56,7 @@ struct TransmissionProbabilityOnContact { }; /** - * @brief the latent time in day unit + * @brief The latent time in day unit. */ template struct TimeExposed { @@ -70,8 +88,9 @@ 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. + */ template struct ContactPatterns { using Type = UncertainContactMatrix; @@ -86,7 +105,9 @@ struct ContactPatterns { }; /** - * @brief The contact patterns between different Region%s are modelled using a ContactMatrix. + * @brief The commuting patterns between different Region%s are modelled using a ContactMatrix of size n_regions x n_regions. + * Each entry of the matrix represents the fraction of individuals commuting from one Region to another. The diagonal corresponds + * to the fraction of individuals staying in their Region. */ template struct CommutingStrengths { @@ -101,6 +122,11 @@ struct CommutingStrengths { } }; +/** + * @brief The number of individuals in each Region and AgeGroup if commuting was applied. + * Computed as the sum of the number of individuals staying in their Region and the number of individuals commuting to this Region + * minus the number of individuals commuting from this Region. + */ template struct PopulationAfterCommuting { using Type = Populations; @@ -119,7 +145,7 @@ using ParametersBase = ParameterSet, TimeEx ContactPatterns, CommutingStrengths, PopulationAfterCommuting>; /** - * @brief Parameters of SEIR model. + * @brief Parameters of the SEIR metapopulation model. */ template class Parameters : public ParametersBase @@ -144,7 +170,6 @@ class Parameters : public 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() @@ -153,7 +178,7 @@ class Parameters : public ParametersBase * (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. + * @return Returns true if one ore more constraints were corrected, false otherwise. */ bool apply_constraints() { @@ -279,7 +304,7 @@ class Parameters : public ParametersBase public: /** - * deserialize an object of this class. + * @brief Deserialize an object of this class. * @see mio::deserialize */ template diff --git a/cpp/models/ode_seir_metapop/regions.h b/cpp/models/ode_seir_metapop/regions.h index e482e76722..a1eb3692c8 100644 --- a/cpp/models/ode_seir_metapop/regions.h +++ b/cpp/models/ode_seir_metapop/regions.h @@ -1,4 +1,22 @@ - +/* +* Copyright (C) 2020-2025 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. +*/ #ifndef ODESEIRMETAPOP_REGIONS_H #define ODESEIRMETAPOP_REGIONS_H diff --git a/docs/source/cpp/deterministic_metapop.rst b/docs/source/cpp/deterministic_metapop.rst index d7cda25343..e8d40add30 100644 --- a/docs/source/cpp/deterministic_metapop.rst +++ b/docs/source/cpp/deterministic_metapop.rst @@ -42,7 +42,16 @@ and the epidemiological parameters, e.g.: model.parameters.set>(8.097612257); model.parameters.set>(0.07333); -Construct an ``Eigen::MatrixXd`` of size :math:`n_{regions} \times n_{regions}` satisfying the sum of each row equal to 1.0, e.g.: +Construct an ``Eigen::MatrixXd`` of size :math:`n_{regions} \times n_{regions}` which describes the fraction of individuals commuting from one region to another. The matrix should satify the sum of each row equal to 1.0, e.g.: .. code-block:: cpp 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; \ No newline at end of file + mobility_data_commuter << 0.4, 0.3, 0.3, 0.2, 0.7, 0.1, 0.4, 0.1, 0.5; + +Set the commuting strengths matrix via the ``set_commuting_strengths`` method to ensure that the population after commuting is correctly updated: +.. code-block:: cpp + + model.set_commuting_strengths(mobility_data_commuter); + +Finally, to run the simulation from `t0` to `tmax` with a time step of `dt`, use the following command: +.. code-block:: cpp + simulate(t0, tmax, dt, model); \ No newline at end of file From 172c6749316061d86322b8f91f7f8ec0ad603654 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Wed, 14 May 2025 10:43:50 +0200 Subject: [PATCH 098/105] change error handling to include --- cpp/models/ode_seir_metapop/model.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cpp/models/ode_seir_metapop/model.h b/cpp/models/ode_seir_metapop/model.h index 71b48b0412..86b8a71397 100644 --- a/cpp/models/ode_seir_metapop/model.h +++ b/cpp/models/ode_seir_metapop/model.h @@ -27,11 +27,7 @@ #include "models/ode_seir_metapop/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) +#include "memilio/compartments/simulation.h" namespace mio { From 8b856834cd7358351952874109e8a5a02c3462ce Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Wed, 11 Jun 2025 07:48:56 +0200 Subject: [PATCH 099/105] correct docu for contact matrix --- cpp/memilio/epidemiology/contact_matrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/memilio/epidemiology/contact_matrix.h b/cpp/memilio/epidemiology/contact_matrix.h index 83ce44517f..ce0b0704c0 100644 --- a/cpp/memilio/epidemiology/contact_matrix.h +++ b/cpp/memilio/epidemiology/contact_matrix.h @@ -31,7 +31,7 @@ namespace mio { /** - * represents the coefficient wise matrix (or vector) expression B - D * M + * Represents the coefficient wise matrix (or vector) expression B - D * (B - M) * where B is a baseline, M is a minimum and D is some time dependent complex damping factor. * Base class for e.g. time dependent contact matrices. * Coefficient wise expression, so B, D, M matrices must have the same shape. From 4619fac6ac7a8adc07134875ef2d7aa776e3863a Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Fri, 11 Jul 2025 10:01:50 +0200 Subject: [PATCH 100/105] use existing region struct --- cpp/examples/ode_seir_metapop.cpp | 11 +++--- cpp/models/ode_seir_metapop/CMakeLists.txt | 1 - cpp/models/ode_seir_metapop/model.h | 8 ++-- cpp/models/ode_seir_metapop/parameters.h | 4 +- cpp/models/ode_seir_metapop/regions.h | 44 ---------------------- 5 files changed, 12 insertions(+), 56 deletions(-) delete mode 100644 cpp/models/ode_seir_metapop/regions.h diff --git a/cpp/examples/ode_seir_metapop.cpp b/cpp/examples/ode_seir_metapop.cpp index 27b6d4d6ab..5b09e10353 100644 --- a/cpp/examples/ode_seir_metapop.cpp +++ b/cpp/examples/ode_seir_metapop.cpp @@ -3,7 +3,7 @@ #include "models/ode_seir_metapop/infection_state.h" #include "models/ode_seir_metapop/model.h" #include "models/ode_seir_metapop/parameters.h" -#include "models/ode_seir_metapop/regions.h" +#include "memilio/geography/regions.h" int main() { @@ -14,14 +14,13 @@ int main() mio::oseirmetapop::Model model(3, 1); for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { - model.populations[{mio::oseirmetapop::Region(i), mio::AgeGroup(0), - mio::oseirmetapop::InfectionState::Susceptible}] = 10000; + model.populations[{mio::regions::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible}] = + 10000; } - model.populations[{mio::oseirmetapop::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed}] += + model.populations[{mio::regions::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed}] += 100; + model.populations[{mio::regions::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible}] -= 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; diff --git a/cpp/models/ode_seir_metapop/CMakeLists.txt b/cpp/models/ode_seir_metapop/CMakeLists.txt index 45e42593e6..66a792cff9 100644 --- a/cpp/models/ode_seir_metapop/CMakeLists.txt +++ b/cpp/models/ode_seir_metapop/CMakeLists.txt @@ -3,7 +3,6 @@ add_library(ode_seir_metapop model.h model.cpp parameters.h - regions.h ) target_link_libraries(ode_seir_metapop PUBLIC memilio) target_include_directories(ode_seir_metapop PUBLIC diff --git a/cpp/models/ode_seir_metapop/model.h b/cpp/models/ode_seir_metapop/model.h index 86b8a71397..de338366ba 100644 --- a/cpp/models/ode_seir_metapop/model.h +++ b/cpp/models/ode_seir_metapop/model.h @@ -24,7 +24,7 @@ #include "memilio/epidemiology/populations.h" #include "models/ode_seir_metapop/infection_state.h" #include "models/ode_seir_metapop/parameters.h" -#include "models/ode_seir_metapop/regions.h" +#include "memilio/geography/regions.h" #include "memilio/epidemiology/age_group.h" #include "memilio/utils/time_series.h" #include "memilio/compartments/simulation.h" @@ -46,12 +46,12 @@ using Flows = TypeList -class Model : public FlowModel, +class Model : public FlowModel, Parameters, Flows> { - using Base = - FlowModel, Parameters, Flows>; + using Base = FlowModel, + Parameters, Flows>; public: using typename Base::ParameterSet; diff --git a/cpp/models/ode_seir_metapop/parameters.h b/cpp/models/ode_seir_metapop/parameters.h index e76dfe1c4f..ee506f61be 100644 --- a/cpp/models/ode_seir_metapop/parameters.h +++ b/cpp/models/ode_seir_metapop/parameters.h @@ -25,7 +25,7 @@ #include "memilio/epidemiology/age_group.h" #include "memilio/utils/parameter_set.h" #include "memilio/utils/custom_index_array.h" -#include "models/ode_seir_metapop/regions.h" +#include "memilio/geography/regions.h" #include "Eigen/Sparse" #include @@ -35,6 +35,8 @@ namespace mio namespace oseirmetapop { +using Region = mio::regions::Region; + /**************************************************** * Define Parameters of the SEIR model with mobility * ****************************************************/ diff --git a/cpp/models/ode_seir_metapop/regions.h b/cpp/models/ode_seir_metapop/regions.h deleted file mode 100644 index a1eb3692c8..0000000000 --- a/cpp/models/ode_seir_metapop/regions.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (C) 2020-2025 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. -*/ -#ifndef ODESEIRMETAPOP_REGIONS_H -#define ODESEIRMETAPOP_REGIONS_H - -#include "memilio/utils/index.h" - -namespace mio -{ -namespace oseirmetapop -{ - -/** - * @brief The Region struct is used as a dynamically - * sized tag for all region dependent categories - */ -struct Region : public Index { - Region(size_t val) - : Index(val) - { - } -}; - -} // namespace oseirmetapop -} // namespace mio - -#endif From e7c4def8f61d3d79c9ba073f89fae37444093caa Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Fri, 11 Jul 2025 10:05:07 +0200 Subject: [PATCH 101/105] adjust to new data structure --- pycode/examples/plot/plotResultsMapGermany.py | 4 ++-- pycode/memilio-plot/memilio/plot/createGIF.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pycode/examples/plot/plotResultsMapGermany.py b/pycode/examples/plot/plotResultsMapGermany.py index 68c8940282..1633efe88c 100755 --- a/pycode/examples/plot/plotResultsMapGermany.py +++ b/pycode/examples/plot/plotResultsMapGermany.py @@ -68,13 +68,13 @@ try: population = pd.read_json( - 'data/pydata/Germany/county_current_population.json') + 'data/Germany/pydata/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, + out_folder='data/Germany/pydata/', no_raw=True, merge_eisenach=True) # For fitting of different age groups we need format ">X". diff --git a/pycode/memilio-plot/memilio/plot/createGIF.py b/pycode/memilio-plot/memilio/plot/createGIF.py index 9ea23f9700..7806d30953 100644 --- a/pycode/memilio-plot/memilio/plot/createGIF.py +++ b/pycode/memilio-plot/memilio/plot/createGIF.py @@ -71,14 +71,14 @@ def create_plot_map(day, filename, files_input, output_path, compartments, file try: population = pd.read_json( - 'data/pydata/Germany/county_current_population.json') + 'data/Germany/pydata/county_current_population.json') # pandas>1.5 raise FileNotFoundError instead of ValueError except (ValueError, FileNotFoundError): print( "Population data was not found. Downloading 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) + out_folder='data/Germany/pydata/', no_raw=True, merge_eisenach=True) # For fitting of different age groups we need format ">X". age_group_values = list(age_groups.values()) From 6c75e60bb7e912070e022f0bdcb3035b2ae41137 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Wed, 5 Nov 2025 14:29:06 +0100 Subject: [PATCH 102/105] simplify metapop --- cpp/examples/ode_seir_metapop.cpp | 21 +-- cpp/models/ode_seir_metapop/infection_state.h | 44 ------- cpp/models/ode_seir_metapop/model.h | 112 +++++++++------- cpp/models/ode_seir_metapop/parameters.h | 121 +----------------- 4 files changed, 77 insertions(+), 221 deletions(-) delete mode 100644 cpp/models/ode_seir_metapop/infection_state.h diff --git a/cpp/examples/ode_seir_metapop.cpp b/cpp/examples/ode_seir_metapop.cpp index 5b09e10353..b794ac2ef2 100644 --- a/cpp/examples/ode_seir_metapop.cpp +++ b/cpp/examples/ode_seir_metapop.cpp @@ -1,6 +1,5 @@ #include "memilio/compartments/simulation.h" #include "memilio/utils/custom_index_array.h" -#include "models/ode_seir_metapop/infection_state.h" #include "models/ode_seir_metapop/model.h" #include "models/ode_seir_metapop/parameters.h" #include "memilio/geography/regions.h" @@ -14,12 +13,12 @@ int main() mio::oseirmetapop::Model model(3, 1); for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { - model.populations[{mio::regions::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible}] = + model.populations[{mio::regions::Region(i), mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 10000; } - model.populations[{mio::regions::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed}] += 100; - model.populations[{mio::regions::Region(0), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Susceptible}] -= + model.populations[{mio::regions::Region(0), mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; + model.populations[{mio::regions::Region(0), mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= 100; Eigen::MatrixXd mobility_data_commuter(3, 3); @@ -27,15 +26,21 @@ int main() model.set_commuting_strengths(mobility_data_commuter); - model.parameters.template get>() + mio::oseir::Parameters local_params(1); + + local_params.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); + local_params.set>(3.335); + local_params.set>(8.097612257); + local_params.set>(0.07333); + + model.set_local_parameters(local_params); auto result = simulate(t0, tmax, dt, model); + + result.print_table(); return 0; } diff --git a/cpp/models/ode_seir_metapop/infection_state.h b/cpp/models/ode_seir_metapop/infection_state.h deleted file mode 100644 index a0c2faf8c2..0000000000 --- a/cpp/models/ode_seir_metapop/infection_state.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (C) 2020-2025 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. -*/ -#ifndef ODESEIRMETAPOP_INFECTIONSTATE_H -#define ODESEIRMETAPOP_INFECTIONSTATE_H - -namespace mio -{ -namespace oseirmetapop -{ - -/** - * @brief The InfectionState enum describes the possible - * categories for the infectious state of persons - */ -enum class InfectionState -{ - Susceptible, - Exposed, - Infected, - Recovered, - Count -}; - -} // namespace oseirmetapop -} // namespace mio - -#endif // ODESEIR_INFECTIONSTATE_H diff --git a/cpp/models/ode_seir_metapop/model.h b/cpp/models/ode_seir_metapop/model.h index de338366ba..af4c251a7e 100644 --- a/cpp/models/ode_seir_metapop/model.h +++ b/cpp/models/ode_seir_metapop/model.h @@ -17,17 +17,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef ODESEIRMETAPOP_MODEL_H -#define ODESEIRMETAPOP_MODEL_H +#ifndef ODESEIRMETAPOPADVANCED_MODEL_H +#define ODESEIRMETAPOPADVANCED_MODEL_H #include "memilio/compartments/flow_model.h" #include "memilio/epidemiology/populations.h" -#include "models/ode_seir_metapop/infection_state.h" +#include "models/ode_seir/model.h" +#include "models/ode_seir/infection_state.h" #include "models/ode_seir_metapop/parameters.h" +#include "models/ode_seir/parameters.h" #include "memilio/geography/regions.h" #include "memilio/epidemiology/age_group.h" #include "memilio/utils/time_series.h" #include "memilio/compartments/simulation.h" +#include "memilio/utils/logging.h" namespace mio { @@ -38,19 +41,19 @@ namespace oseirmetapop * define the model * ********************/ -using Flows = TypeList, - Flow, - Flow>; +using Flows = TypeList, + Flow, + Flow>; /** * @brief The Model holds the Parameters and the initial Populations and defines the ordinary differential equations. */ template -class Model : public FlowModel, +class Model : public FlowModel, Parameters, Flows> { - using Base = FlowModel, + using Base = FlowModel, Parameters, Flows>; public: @@ -63,40 +66,42 @@ class Model : public FlowModel> pop, Eigen::Ref> y, FP t, Eigen::Ref> flows) const override { - const auto& params = this->parameters; + const auto& metapop_params = this->parameters; + const auto& local_params = this->local_model.parameters; const auto& population = this->populations; const Eigen::MatrixXd commuting_strengths = - params.template get>().get_cont_freq_mat().get_matrix_at(t); - const size_t n_age_groups = (size_t)params.get_num_agegroups(); - const size_t n_regions = (size_t)params.get_num_regions(); + metapop_params.template get>().get_cont_freq_mat().get_matrix_at(t); + const size_t n_age_groups = (size_t)metapop_params.get_num_agegroups(); + const size_t n_regions = (size_t)metapop_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})]; + pop[population.get_flat_index({Region(region_n), AgeGroup(age_i), mio::oseir::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) /= - params.template get>()[{Region(region_n), AgeGroup(age_i)}]; + metapop_params.template get>()[{Region(region_n), AgeGroup(age_i)}]; } } Eigen::MatrixXd infections_due_commuting = commuting_strengths * infectious_share_per_region; @@ -104,35 +109,35 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t)(age_i, age_j) * - params.template get>()[AgeGroup(age_i)]; + local_params.template get>().get_cont_freq_mat().get_matrix_at(t)(age_i, age_j) * + local_params.template get>()[AgeGroup(age_i)]; - flows[Base::template get_flat_flow_index( + flows[Base::template get_flat_flow_index( {Region(region_n), AgeGroup(age_i)})] += (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})]; + y[population.get_flat_index({Region(region_n), AgeGroup(age_i), mio::oseir::InfectionState::Susceptible})]; } } for (size_t region = 0; region < n_regions; region++) { - flows[Base::template get_flat_flow_index( + flows[Base::template get_flat_flow_index( {Region(region), AgeGroup(age_i)})] = - 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( + y[population.get_flat_index({Region(region), AgeGroup(age_i), mio::oseir::InfectionState::Exposed})] / + local_params.template get>()[AgeGroup(age_i)]; + flows[Base::template get_flat_flow_index( {Region(region), AgeGroup(age_i)})] = - y[population.get_flat_index({Region(region), AgeGroup(age_i), InfectionState::Infected})] / - params.template get>()[AgeGroup(age_i)]; + y[population.get_flat_index({Region(region), AgeGroup(age_i), mio::oseir::InfectionState::Infected})] / + local_params.template get>()[AgeGroup(age_i)]; } } } @@ -149,24 +154,25 @@ class Model : public FlowModelparameters; + auto const& metapop_params = this->parameters; + auto const& local_params = this->local_model.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(); + const size_t num_age_groups = (size_t)local_params.get_num_agegroups(); + const size_t num_regions = (size_t)local_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>(); - Populations const& population_after_commuting = params.template get>(); + ContactMatrixGroup const& contact_matrix = local_params.template get>(); + ContactMatrixGroup const& commuting_strengths = metapop_params.template get>(); + Populations const& population_after_commuting = metapop_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}); + size_t Si = pop.get_flat_index({n, i, mio::oseir::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({m.get(), 1}); @@ -174,7 +180,7 @@ class Model : public FlowModel>()[i]; + local_params.template get>()[i]; if (n == 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] / Njm; @@ -190,8 +196,8 @@ class Model : public FlowModel>()[i]; - double T_Ii = params.template get>()[i]; + double T_Ei = local_params.template get>()[i]; + double T_Ii = local_params.template get>()[i]; 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; @@ -254,15 +260,15 @@ class Model : public FlowModelparameters.get_num_regions(); set_commuting_strengths(Eigen::MatrixXd::Identity(number_regions, number_regions)); } -}; // namespace oseirmetapop + + void set_local_parameters(const mio::oseir::Parameters& params) + { + local_model.parameters = params; + } + +private: +mio::oseir::Model local_model; +}; } // namespace oseirmetapop } // namespace mio diff --git a/cpp/models/ode_seir_metapop/parameters.h b/cpp/models/ode_seir_metapop/parameters.h index ee506f61be..52a48666ed 100644 --- a/cpp/models/ode_seir_metapop/parameters.h +++ b/cpp/models/ode_seir_metapop/parameters.h @@ -41,71 +41,6 @@ using Region = mio::regions::Region; * 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 commuting patterns between different Region%s are modelled using a ContactMatrix of size n_regions x n_regions. * Each entry of the matrix represents the fraction of individuals commuting from one Region to another. The diagonal corresponds @@ -143,8 +78,7 @@ struct PopulationAfterCommuting { }; template -using ParametersBase = ParameterSet, TimeExposed, TimeInfected, - ContactPatterns, CommutingStrengths, PopulationAfterCommuting>; +using ParametersBase = ParameterSet, PopulationAfterCommuting>; /** * @brief Parameters of the SEIR metapopulation model. @@ -184,37 +118,9 @@ class Parameters : public ParametersBase */ 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; - } for (auto j = Region(0); j < Region(m_num_regions); j++) { if (this->template get>()[{j, i}] <= 0.0) { log_warning( @@ -248,32 +154,7 @@ class Parameters : public ParametersBase */ bool check_constraints() const { - 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; - } 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}", From 371f12abfcca59989208c9e9fd24f3db8b187088 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Wed, 5 Nov 2025 14:53:22 +0100 Subject: [PATCH 103/105] adjust test --- cpp/tests/test_odemetapop.cpp | 137 +++++++++++++--------------------- 1 file changed, 51 insertions(+), 86 deletions(-) diff --git a/cpp/tests/test_odemetapop.cpp b/cpp/tests/test_odemetapop.cpp index c34ef37ab2..deac64403a 100644 --- a/cpp/tests/test_odemetapop.cpp +++ b/cpp/tests/test_odemetapop.cpp @@ -3,7 +3,6 @@ #include "memilio/config.h" #include "memilio/utils/time_series.h" #include "ode_seir_metapop/model.h" -#include "ode_seir_metapop/infection_state.h" #include "ode_seir_metapop/parameters.h" #include "memilio/math/euler.h" #include "memilio/compartments/simulation.h" @@ -34,24 +33,24 @@ class ModelTestOdeMetapop : public testing::Test total_population_per_region = 1061000; for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { - model.populations[{mio::Index( - mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed)}] = 10000; - model.populations[{mio::Index( - mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index( - 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)}] = + model.populations[{mio::Index( + mio::regions::Region(i), mio::AgeGroup(0), mio::oseir::InfectionState::Exposed)}] = 10000; + model.populations[{mio::Index( + mio::regions::Region(i), mio::AgeGroup(0), mio::oseir::InfectionState::Infected)}] = 1000; + model.populations[{mio::Index( + mio::regions::Region(i), mio::AgeGroup(0), mio::oseir::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index( + mio::regions::Region(i), mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible)}] = total_population_per_region - model.populations[{ - mio::Index( - mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Exposed)}] - + mio::Index( + mio::regions::Region(i), mio::AgeGroup(0), mio::oseir::InfectionState::Exposed)}] - model.populations[{ - mio::Index( - mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Infected)}] - + mio::Index( + mio::regions::Region(i), mio::AgeGroup(0), mio::oseir::InfectionState::Infected)}] - model.populations[{ - mio::Index( - mio::oseirmetapop::Region(i), mio::AgeGroup(0), mio::oseirmetapop::InfectionState::Recovered)}]; + mio::Index( + mio::regions::Region(i), mio::AgeGroup(0), mio::oseir::InfectionState::Recovered)}]; } model.set_commuting_strengths(); } @@ -73,13 +72,17 @@ TEST_F(ModelTestOdeMetapop, checkPopulationConservation) 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>(); + mio::oseir::Parameters local_params(1); + + local_params.set>(5.2); + local_params.set>(6); + local_params.set>(0.1); + mio::ContactMatrixGroup& contact_matrix = local_params.get>(); contact_matrix[0].get_baseline().setConstant(2.7); contact_matrix[0].add_damping(0.6, mio::SimulationTime(12.5)); + model.set_local_parameters(local_params); + 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.5, 0.5, 0., 0., 0., 0., 1.; @@ -119,13 +122,6 @@ TEST_F(ModelTestOdeMetapop, compareWithPreviousRun) 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; - 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.5, 0.5, 0., 0., 0., 0., 1.; @@ -136,18 +132,7 @@ TEST_F(ModelTestOdeMetapop, check_constraints_parameters) 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); - 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); @@ -170,8 +155,8 @@ TEST_F(ModelTestOdeMetapop, check_constraints_parameters) 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.)); + mio::Populations( + {mio::regions::Region(4), mio::AgeGroup(1)}, 0.)); ASSERT_EQ(model.parameters.check_constraints(), 1); // Nobody commutes to region 2 but everybody originating fron there commutes to other regions. @@ -185,13 +170,6 @@ TEST_F(ModelTestOdeMetapop, check_constraints_parameters) TEST_F(ModelTestOdeMetapop, apply_constraints_parameters) { 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(); - 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.5, 0.5, 0., 0., 0., 0., 1.; @@ -199,22 +177,6 @@ TEST_F(ModelTestOdeMetapop, apply_constraints_parameters) 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); - - model.parameters.set>(0.04); mobility_data_commuter(0, 1) += 0.5; model.set_commuting_strengths(mobility_data_commuter); EXPECT_EQ(model.parameters.apply_constraints(), 1); @@ -252,11 +214,11 @@ TEST_F(ModelTestOdeMetapop, apply_constraints_parameters) 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.)); + mio::Populations( + {mio::regions::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)}]), + mio::regions::Region(3), mio::AgeGroup(0)}]), 1.0, tol_times); // Nobody commutes to region 2 but everybody originating fron there commutes to other regions. @@ -264,7 +226,7 @@ TEST_F(ModelTestOdeMetapop, apply_constraints_parameters) 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)}]), + mio::regions::Region(1), mio::AgeGroup(0)}]), 1.0, tol_times); mio::set_log_level(mio::LogLevel::warn); @@ -280,30 +242,33 @@ TEST(TestOdeMetapop, compareSEIR) 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)}] = + model.populations[{mio::Index( + mio::regions::Region(0), mio::AgeGroup(0), mio::oseir::InfectionState::Exposed)}] = 10000; + model.populations[{mio::Index( + mio::regions::Region(0), mio::AgeGroup(0), mio::oseir::InfectionState::Infected)}] = 1000; + model.populations[{mio::Index( + mio::regions::Region(0), mio::AgeGroup(0), mio::oseir::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index( + mio::regions::Region(0), mio::AgeGroup(0), mio::oseir::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>(); + model.populations[{mio::Index( + mio::regions::Region(0), mio::AgeGroup(0), mio::oseir::InfectionState::Exposed)}] - + model.populations[{mio::Index( + mio::regions::Region(0), mio::AgeGroup(0), mio::oseir::InfectionState::Infected)}] - + model.populations[{mio::Index( + mio::regions::Region(0), mio::AgeGroup(0), mio::oseir::InfectionState::Recovered)}]; + + mio::oseir::Parameters local_params(1); + + local_params.set>(5.2); + local_params.set>(6); + local_params.set>(0.1); + mio::ContactMatrixGroup& contact_matrix = local_params.get>(); contact_matrix[0].get_baseline().setConstant(2.7); contact_matrix[0].add_damping(0.6, mio::SimulationTime(12.5)); + model.set_local_parameters(local_params); + model.set_commuting_strengths(); model.check_constraints(); From 6649d490dff761e0473871b9c01fbb87ec9c6295 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Wed, 5 Nov 2025 14:56:41 +0100 Subject: [PATCH 104/105] fix bug --- cpp/models/ode_seir_metapop/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/models/ode_seir_metapop/CMakeLists.txt b/cpp/models/ode_seir_metapop/CMakeLists.txt index 66a792cff9..108b9d7b87 100644 --- a/cpp/models/ode_seir_metapop/CMakeLists.txt +++ b/cpp/models/ode_seir_metapop/CMakeLists.txt @@ -1,5 +1,4 @@ add_library(ode_seir_metapop - infection_state.h model.h model.cpp parameters.h From 58856cd646570a21c81a4886db3dfc6c7dd53fd3 Mon Sep 17 00:00:00 2001 From: Carlotta Gerstein Date: Thu, 6 Nov 2025 10:14:52 +0100 Subject: [PATCH 105/105] go back to previous version --- cpp/examples/ode_seir_metapop.cpp | 22 ++-- cpp/models/ode_seir_metapop/infection_state.h | 36 ++++++ cpp/models/ode_seir_metapop/model.h | 107 +++++++--------- cpp/models/ode_seir_metapop/parameters.h | 120 +++++++++++++++++- 4 files changed, 211 insertions(+), 74 deletions(-) create mode 100644 cpp/models/ode_seir_metapop/infection_state.h diff --git a/cpp/examples/ode_seir_metapop.cpp b/cpp/examples/ode_seir_metapop.cpp index b794ac2ef2..66b9f92c96 100644 --- a/cpp/examples/ode_seir_metapop.cpp +++ b/cpp/examples/ode_seir_metapop.cpp @@ -10,15 +10,17 @@ int main() const ScalarType tmax = 10; ScalarType dt = 0.1; - mio::oseirmetapop::Model model(3, 1); + using namespace mio::oseirmetapop; + + Model model(3, 1); for (size_t i = 0; i < (size_t)model.parameters.get_num_regions(); i++) { - model.populations[{mio::regions::Region(i), mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = + model.populations[{mio::regions::Region(i), mio::AgeGroup(0), InfectionState::Susceptible}] = 10000; } - model.populations[{mio::regions::Region(0), mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] += 100; - model.populations[{mio::regions::Region(0), mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] -= + model.populations[{mio::regions::Region(0), mio::AgeGroup(0), InfectionState::Exposed}] += 100; + model.populations[{mio::regions::Region(0), mio::AgeGroup(0), InfectionState::Susceptible}] -= 100; Eigen::MatrixXd mobility_data_commuter(3, 3); @@ -26,18 +28,14 @@ int main() model.set_commuting_strengths(mobility_data_commuter); - mio::oseir::Parameters local_params(1); - - local_params.template get>() + model.parameters.template get>() .get_cont_freq_mat()[0] .get_baseline() .setConstant(2.7); - local_params.set>(3.335); - local_params.set>(8.097612257); - local_params.set>(0.07333); - - model.set_local_parameters(local_params); + model.parameters.set>(3.335); + model.parameters.set>(8.097612257); + model.parameters.set>(0.07333); auto result = simulate(t0, tmax, dt, model); diff --git a/cpp/models/ode_seir_metapop/infection_state.h b/cpp/models/ode_seir_metapop/infection_state.h new file mode 100644 index 0000000000..6127c8e868 --- /dev/null +++ b/cpp/models/ode_seir_metapop/infection_state.h @@ -0,0 +1,36 @@ +/* +* Copyright (C) 2020-2025 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. +*/ + +#ifndef SEIRMETAPOP_INFECTIONSTATE_H +#define SEIRMETAPOP_INFECTIONSTATE_H + +#include "models/ode_seir/infection_state.h" + +namespace mio +{ +namespace oseirmetapop +{ + +using mio::oseir::InfectionState; + +} // namespace oseirmetapop +} // namespace mio + +#endif // SEIRMETAPOP_INFECTIONSTATE_H diff --git a/cpp/models/ode_seir_metapop/model.h b/cpp/models/ode_seir_metapop/model.h index af4c251a7e..79a56ac627 100644 --- a/cpp/models/ode_seir_metapop/model.h +++ b/cpp/models/ode_seir_metapop/model.h @@ -17,20 +17,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef ODESEIRMETAPOPADVANCED_MODEL_H -#define ODESEIRMETAPOPADVANCED_MODEL_H +#ifndef ODESEIRMETAPOP_MODEL_H +#define ODESEIRMETAPOP_MODEL_H + +#include #include "memilio/compartments/flow_model.h" #include "memilio/epidemiology/populations.h" -#include "models/ode_seir/model.h" -#include "models/ode_seir/infection_state.h" #include "models/ode_seir_metapop/parameters.h" -#include "models/ode_seir/parameters.h" +#include "models/ode_seir_metapop/infection_state.h" #include "memilio/geography/regions.h" -#include "memilio/epidemiology/age_group.h" #include "memilio/utils/time_series.h" -#include "memilio/compartments/simulation.h" -#include "memilio/utils/logging.h" namespace mio { @@ -41,19 +38,19 @@ namespace oseirmetapop * define the model * ********************/ -using Flows = TypeList, - Flow, - Flow>; +using Flows = TypeList, + Flow, + Flow>; /** * @brief The Model holds the Parameters and the initial Populations and defines the ordinary differential equations. */ template -class Model : public FlowModel, +class Model : public FlowModel, Parameters, Flows> { - using Base = FlowModel, + using Base = FlowModel, Parameters, Flows>; public: @@ -66,42 +63,41 @@ class Model : public FlowModel> pop, Eigen::Ref> y, FP t, Eigen::Ref> flows) const override { - const auto& metapop_params = this->parameters; - const auto& local_params = this->local_model.parameters; + using enum InfectionState; + const auto& params = this->parameters; const auto& population = this->populations; const Eigen::MatrixXd commuting_strengths = - metapop_params.template get>().get_cont_freq_mat().get_matrix_at(t); - const size_t n_age_groups = (size_t)metapop_params.get_num_agegroups(); - const size_t n_regions = (size_t)metapop_params.get_num_regions(); + params.template get>().get_cont_freq_mat().get_matrix_at(t); + 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), mio::oseir::InfectionState::Infected})]; + pop[population.get_flat_index({Region(region_n), AgeGroup(age_i), 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) /= - metapop_params.template get>()[{Region(region_n), AgeGroup(age_i)}]; + params.template get>()[{Region(region_n), AgeGroup(age_i)}]; } } Eigen::MatrixXd infections_due_commuting = commuting_strengths * infectious_share_per_region; @@ -109,35 +105,35 @@ class Model : public FlowModel>().get_cont_freq_mat().get_matrix_at(t)(age_i, age_j) * - local_params.template get>()[AgeGroup(age_i)]; + params.template get>().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( + flows[Base::template get_flat_flow_index( {Region(region_n), AgeGroup(age_i)})] += (pop[Ijn] * Nj_inv + infections_due_commuting(region_n, age_j)) * coeffStoE * - y[population.get_flat_index({Region(region_n), AgeGroup(age_i), mio::oseir::InfectionState::Susceptible})]; + y[population.get_flat_index({Region(region_n), AgeGroup(age_i), Susceptible})]; } } for (size_t region = 0; region < n_regions; region++) { - flows[Base::template get_flat_flow_index( + flows[Base::template get_flat_flow_index( {Region(region), AgeGroup(age_i)})] = - y[population.get_flat_index({Region(region), AgeGroup(age_i), mio::oseir::InfectionState::Exposed})] / - local_params.template get>()[AgeGroup(age_i)]; - flows[Base::template get_flat_flow_index( + y[population.get_flat_index({Region(region), AgeGroup(age_i), Exposed})] / + params.template get>()[AgeGroup(age_i)]; + flows[Base::template get_flat_flow_index( {Region(region), AgeGroup(age_i)})] = - y[population.get_flat_index({Region(region), AgeGroup(age_i), mio::oseir::InfectionState::Infected})] / - local_params.template get>()[AgeGroup(age_i)]; + y[population.get_flat_index({Region(region), AgeGroup(age_i), Infected})] / + params.template get>()[AgeGroup(age_i)]; } } } @@ -154,25 +150,24 @@ class Model : public FlowModelparameters; - auto const& local_params = this->local_model.parameters; + auto const& params = this->parameters; auto const& pop = this->populations; - const size_t num_age_groups = (size_t)local_params.get_num_agegroups(); - const size_t num_regions = (size_t)local_params.get_num_regions(); + 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 = local_params.template get>(); - ContactMatrixGroup const& commuting_strengths = metapop_params.template get>(); - Populations const& population_after_commuting = metapop_params.template get>(); + ContactMatrixGroup const& contact_matrix = params.template get>(); + 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); 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, mio::oseir::InfectionState::Susceptible}); + 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({m.get(), 1}); @@ -180,7 +175,7 @@ class Model : public FlowModel>()[i]; + params.template get>()[i]; if (n == 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] / Njm; @@ -196,8 +191,8 @@ class Model : public FlowModel>()[i]; - double T_Ii = local_params.template get>()[i]; + double T_Ei = params.template get>()[i]; + double T_Ii = params.template get>()[i]; 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; @@ -260,9 +255,9 @@ class Model : public FlowModelparameters.get_num_regions(); set_commuting_strengths(Eigen::MatrixXd::Identity(number_regions, number_regions)); } - - void set_local_parameters(const mio::oseir::Parameters& params) - { - local_model.parameters = params; - } - -private: -mio::oseir::Model local_model; }; } // namespace oseirmetapop diff --git a/cpp/models/ode_seir_metapop/parameters.h b/cpp/models/ode_seir_metapop/parameters.h index 52a48666ed..e293186888 100644 --- a/cpp/models/ode_seir_metapop/parameters.h +++ b/cpp/models/ode_seir_metapop/parameters.h @@ -26,7 +26,6 @@ #include "memilio/utils/parameter_set.h" #include "memilio/utils/custom_index_array.h" #include "memilio/geography/regions.h" -#include "Eigen/Sparse" #include @@ -41,6 +40,71 @@ using Region = mio::regions::Region; * 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 commuting patterns between different Region%s are modelled using a ContactMatrix of size n_regions x n_regions. * Each entry of the matrix represents the fraction of individuals commuting from one Region to another. The diagonal corresponds @@ -78,7 +142,8 @@ struct PopulationAfterCommuting { }; template -using ParametersBase = ParameterSet, PopulationAfterCommuting>; +using ParametersBase = ParameterSet, TimeExposed, TimeInfected, + ContactPatterns, CommutingStrengths, PopulationAfterCommuting>; /** * @brief Parameters of the SEIR metapopulation model. @@ -118,9 +183,36 @@ class Parameters : public ParametersBase */ 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; + } for (auto j = Region(0); j < Region(m_num_regions); j++) { if (this->template get>()[{j, i}] <= 0.0) { log_warning( @@ -154,7 +246,31 @@ class Parameters : public ParametersBase */ bool check_constraints() const { + 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; + } 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}",