From dbf58b723850c11fff846f5bdff7419efeee3a86 Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Thu, 18 Jan 2024 15:36:17 +0100 Subject: [PATCH 01/34] modified parameters.h to account for AgeGroups --- .gitignore | 3 +- cpp/models/ode_sir/model.h | 18 +++++--- cpp/models/ode_sir/parameters.h | 74 ++++++++++++++++++++------------- 3 files changed, 61 insertions(+), 34 deletions(-) diff --git a/.gitignore b/.gitignore index f4ff6a4b0f..e3a0627b25 100644 --- a/.gitignore +++ b/.gitignore @@ -278,4 +278,5 @@ pycode/memilio-epidata/memilio/epidata/CredentialsRegio.ini docs/html docs/xml -# End of https://www.gitignore.io/api/c++,node,python \ No newline at end of file +# End of https://www.gitignore.io/api/c++,node,python +.vscode/settings.json diff --git a/cpp/models/ode_sir/model.h b/cpp/models/ode_sir/model.h index eafe9609cd..83a4cfcb2e 100644 --- a/cpp/models/ode_sir/model.h +++ b/cpp/models/ode_sir/model.h @@ -22,6 +22,7 @@ #define ODESIR_MODEL_H #include "memilio/compartments/compartmentalmodel.h" +#include "memilio/epidemiology/age_group.h" #include "memilio/epidemiology/populations.h" #include "memilio/epidemiology/contact_matrix.h" #include "ode_sir/infection_state.h" @@ -36,20 +37,27 @@ namespace osir * define the model * ********************/ -class Model : public CompartmentalModel, Parameters> +class Model : public CompartmentalModel, Parameters> { - using Base = CompartmentalModel, Parameters>; + using Base = CompartmentalModel, Parameters>; public: - Model() - : Base(Populations({InfectionState::Count}, 0.), ParameterSet()) + Model(const Populations& pop, const ParameterSet& params) + : Base(pop,params) + { + } + + Model(int num_agegroups) + : Model(Populations({AgeGroup(num_agegroups), InfectionState::Count}), ParameterSet(AgeGroup(num_agegroups))) { } void get_derivatives(Eigen::Ref pop, Eigen::Ref y, double t, Eigen::Ref dydt) const override { - auto& params = this->parameters; + auto const& params = this->parameters; + AgeGroup n_agegroups = params.get_num_groups(); + double coeffStoI = params.get().get_matrix_at(t)(0, 0) * params.get() / populations.get_total(); diff --git a/cpp/models/ode_sir/parameters.h b/cpp/models/ode_sir/parameters.h index 54f489cebb..e055769528 100644 --- a/cpp/models/ode_sir/parameters.h +++ b/cpp/models/ode_sir/parameters.h @@ -21,9 +21,12 @@ #ifndef SIR_PARAMETERS_H #define SIR_PARAMETERS_H +#include "memilio/epidemiology/age_group.h" +#include "memilio/epidemiology/uncertain_matrix.h" #include "memilio/utils/uncertain_value.h" #include "memilio/epidemiology/contact_matrix.h" #include "memilio/utils/parameter_set.h" +#include "tests/abm_helpers.h" #include @@ -40,10 +43,10 @@ namespace osir * @brief probability of getting infected from a contact */ struct TransmissionProbabilityOnContact { - using Type = UncertainValue; - static Type get_default() + using Type = CustomIndexArray; + static Type get_default(AgeGroup size) { - return Type(1.0); + return Type(size,1.0); } static std::string name() { @@ -55,10 +58,10 @@ struct TransmissionProbabilityOnContact { * @brief the infectious time in day unit */ struct TimeInfected { - using Type = UncertainValue; - static Type get_default() + using Type = CustomIndexArray; + static Type get_default(AgeGroup size) { - return Type(6.0); + return Type(size,6.0); } static std::string name() { @@ -70,10 +73,10 @@ struct TimeInfected { * @brief the contact patterns within the society are modelled using a ContactMatrix */ struct ContactPatterns { - using Type = ContactMatrix; - static Type get_default() + using Type = UncertainContactMatrix; + static Type get_default(AgeGroup size) { - return Type{1}; + return Type(1, static_cast((size_t)size)); } static std::string name() { @@ -89,11 +92,17 @@ using ParametersBase = ParameterSetget() < 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_groups);i++){ + if (this->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->get(), tol_times); + this->get() = tol_times; + corrected = true; + } + if (this->get()[i] < 0.0 || + this->get()[i] > 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; } @@ -139,26 +151,30 @@ class Parameters : public ParametersBase { double tol_times = 1e-1; - if (this->get() < tol_times) { + for(auto i = AgeGroup(0); i < AgeGroup(m_num_groups);i++){ + + if (this->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->get(), 0.0); return true; } - if (this->get() < 0.0 || - this->get() > 1.0) { + if (this->get()[i] < 0.0 || + this->get()[i] > 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)) + , m_num_groups(get().get_cont_freq_mat().get_num_groups()) { } @@ -173,6 +189,8 @@ class Parameters : public ParametersBase BOOST_OUTCOME_TRY(base, ParametersBase::deserialize(io)); return success(Parameters(std::move(base))); } +private: + AgeGroup m_num_groups; }; } // namespace osir From 1ed2b679720f59a57b4ae41cf51d0d55766202f1 Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 22 Jan 2024 10:51:41 +0100 Subject: [PATCH 02/34] modified sir model.h --- cpp/models/ode_sir/model.h | 44 ++++++++++++++++++++++----------- cpp/models/ode_sir/parameters.h | 1 - 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/cpp/models/ode_sir/model.h b/cpp/models/ode_sir/model.h index 83a4cfcb2e..fb10054db8 100644 --- a/cpp/models/ode_sir/model.h +++ b/cpp/models/ode_sir/model.h @@ -42,32 +42,46 @@ class Model : public CompartmentalModel, Parameters>; public: - Model(const Populations& pop, const ParameterSet& params) - : Base(pop,params) - { - } Model(int num_agegroups) - : Model(Populations({AgeGroup(num_agegroups), InfectionState::Count}), ParameterSet(AgeGroup(num_agegroups))) + : Base(Populations({AgeGroup(num_agegroups), InfectionState::Count}), ParameterSet(AgeGroup(num_agegroups))) { } void get_derivatives(Eigen::Ref pop, Eigen::Ref y, double t, Eigen::Ref dydt) const override { - auto const& params = this->parameters; + auto params = this->parameters; AgeGroup n_agegroups = params.get_num_groups(); + ContactMatrixGroup const& contact_matrix = params.get(); + + for (auto i = AgeGroup(0); i < n_agegroups; i++) { + + double Si = this->populations.get_flat_index({i, InfectionState::Susceptible}); + double Ii = this->populations.get_flat_index({i, InfectionState::Infected}); + double Ri = this->populations.get_flat_index({i, InfectionState::Recovered}); + + for (auto j = AgeGroup(0); j < n_agegroups; j++){ + + double Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); + double Ij = this->populations.get_flat_index({j, InfectionState::Infected}); + double Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); + + double Nj = pop[Sj] + pop[Ij] + pop[Rj]; - double coeffStoI = params.get().get_matrix_at(t)(0, 0) * - params.get() / populations.get_total(); + double coeffStoI = contact_matrix.get_matrix_at(t)(static_cast((size_t)i), + static_cast((size_t)j))* + params.get()[i] / Nj; - 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]; + dydt[Si] += + -coeffStoI * y[Si] * pop[Ij]; + dydt[Ii] += + coeffStoI * y[Si] * pop[Ij]; + } + dydt[Ii]-=(1.0 / params.get()[i]) * y[Ii]; + dydt[Ri] = + (1.0 / params.get()[i]) * y[Ii]; + } } }; diff --git a/cpp/models/ode_sir/parameters.h b/cpp/models/ode_sir/parameters.h index e055769528..f4ec6162d6 100644 --- a/cpp/models/ode_sir/parameters.h +++ b/cpp/models/ode_sir/parameters.h @@ -26,7 +26,6 @@ #include "memilio/utils/uncertain_value.h" #include "memilio/epidemiology/contact_matrix.h" #include "memilio/utils/parameter_set.h" -#include "tests/abm_helpers.h" #include From 1e0c1953c55b51f3800b3a85e81abbecf8b09b20 Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 22 Jan 2024 12:17:41 +0100 Subject: [PATCH 03/34] added agegroups to sir model --- cpp/examples/ode_sir.cpp | 16 +++++------ cpp/models/ode_sir/parameters.h | 13 ++++----- cpp/tests/test_odesir.cpp | 47 +++++++++++++++++---------------- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/cpp/examples/ode_sir.cpp b/cpp/examples/ode_sir.cpp index 71c9e6ce8b..270d85e4a5 100644 --- a/cpp/examples/ode_sir.cpp +++ b/cpp/examples/ode_sir.cpp @@ -36,18 +36,18 @@ int main() mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); - mio::osir::Model model; + mio::osir::Model model(1); - model.populations[{mio::Index(mio::osir::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index(mio::osir::InfectionState::Recovered)}] = 1000; - model.populations[{mio::Index(mio::osir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] = 1000; + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::osir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::osir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Recovered)}]; model.parameters.set(2); model.parameters.set(1); - model.parameters.get().get_baseline()(0, 0) = 2.7; - model.parameters.get().add_damping(0.6, mio::SimulationTime(12.5)); + 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)); auto integrator = std::make_shared(); diff --git a/cpp/models/ode_sir/parameters.h b/cpp/models/ode_sir/parameters.h index f4ec6162d6..c7217895f4 100644 --- a/cpp/models/ode_sir/parameters.h +++ b/cpp/models/ode_sir/parameters.h @@ -26,6 +26,7 @@ #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 @@ -126,14 +127,14 @@ class Parameters : public ParametersBase 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; + this->get()[i], tol_times); + this->get()[i] = tol_times; corrected = true; } if (this->get()[i] < 0.0 || this->get()[i] > 1.0) { log_warning("Constraint check: Parameter TransmissionProbabilityOnContact changed from {:0.4f} to {:d} ", - this->get(), 0.0); + this->get()[i], 0.0); this->get() = 0.0; corrected = true; } @@ -156,18 +157,18 @@ class Parameters : public ParametersBase 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); + this->get()[i], 0.0); return true; } if (this->get()[i] < 0.0 || this->get()[i] > 1.0) { log_error( "Constraint check: Parameter TransmissionProbabilityOnContact {:.4f} smaller {:.4f} or greater {:.4f}", - this->get(), 0.0, 1.0); + this->get()[i], 0.0, 1.0); return true; } - return false; } + return false; } private: diff --git a/cpp/tests/test_odesir.cpp b/cpp/tests/test_odesir.cpp index 3720cd9b9f..3804146f3b 100644 --- a/cpp/tests/test_odesir.cpp +++ b/cpp/tests/test_odesir.cpp @@ -35,7 +35,7 @@ TEST(Testsir, simulateDefault) double tmax = 1; double dt = 0.1; - mio::osir::Model model; + mio::osir::Model model(1); mio::TimeSeries result = simulate(t0, tmax, dt, model); EXPECT_NEAR(result.get_last_time(), tmax, 1e-10); @@ -50,19 +50,19 @@ TEST(Testsir, ComparesirWithJS) double total_population = 1061000; - mio::osir::Model model; + mio::osir::Model model(1); - model.populations[{mio::Index(mio::osir::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index(mio::osir::InfectionState::Recovered)}] = 1000; - model.populations[{mio::Index(mio::osir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] = 1000; + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::osir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::osir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::osir::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.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)); std::vector> refData = load_test_data_csv("ode-sir-js-compare.csv"); auto integrator = std::make_shared(); @@ -105,19 +105,20 @@ TEST(Testsir, checkPopulationConservation) double total_population = 1061000; - mio::osir::Model model; + mio::osir::Model model(1); - model.populations[{mio::Index(mio::osir::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index(mio::osir::InfectionState::Recovered)}] = 1000; - model.populations[{mio::Index(mio::osir::InfectionState::Susceptible)}] = + + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] = 1000; + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::osir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::osir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::osir::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.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)); auto result = mio::simulate(t0, tmax, dt, model); double num_persons = 0.0; for (auto i = 0; i < result.get_last_value().size(); i++) { @@ -128,10 +129,10 @@ TEST(Testsir, checkPopulationConservation) TEST(Testsir, check_constraints_parameters) { - mio::osir::Model model; + mio::osir::Model model(1); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 10; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(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 @@ -151,10 +152,10 @@ TEST(Testsir, check_constraints_parameters) TEST(Testsir, apply_constraints_parameters) { const double tol_times = 1e-1; - mio::osir::Model model; + mio::osir::Model model(1); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 10; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); EXPECT_EQ(model.parameters.apply_constraints(), 0); @@ -162,10 +163,10 @@ TEST(Testsir, apply_constraints_parameters) model.parameters.set(-2.5); EXPECT_EQ(model.parameters.apply_constraints(), 1); - EXPECT_EQ(model.parameters.get(), tol_times); + 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(), 0.0, 1e-14); + EXPECT_NEAR(model.parameters.get()[(mio::AgeGroup)0], 0.0, 1e-14); mio::set_log_level(mio::LogLevel::warn); } \ No newline at end of file From c4e6fdc8a0dd5bef9bb81353916375227d1ed95a Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 22 Jan 2024 15:59:54 +0100 Subject: [PATCH 04/34] finished --- cpp/examples/graph.cpp | 12 +-- cpp/examples/ode_seir.cpp | 18 ++--- cpp/examples/ode_seir_flows.cpp | 18 ++--- cpp/models/ode_seir/model.h | 112 +++++++++++++++++++++------- cpp/models/ode_seir/parameters.h | 106 +++++++++++++++----------- cpp/tests/test_flows.cpp | 40 +++++----- cpp/tests/test_graph_simulation.cpp | 30 ++++---- cpp/tests/test_mobility.cpp | 10 +-- cpp/tests/test_odeseir.cpp | 102 ++++++++++++------------- 9 files changed, 264 insertions(+), 184 deletions(-) diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index 49d0c48463..fd4e1a84f0 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -31,20 +31,20 @@ int main() const auto tmax = 10.; const auto dt = 0.5; //time step of migration, daily migration every second step - mio::oseir::Model model; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = 10000; + mio::oseir::Model model(1); + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 10000; model.parameters.set(1); - model.parameters.get().get_baseline()(0, 0) = 2.7; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(2.7); model.parameters.set(1); //two mostly identical groups auto model_group1 = model; auto model_group2 = model; //some contact restrictions in group 1 - model_group1.parameters.get().add_damping(0.5, mio::SimulationTime(5)); + model_group1.parameters.get().get_cont_freq_mat()[0].add_damping(0.5, mio::SimulationTime(5)); //infection starts in group 1 - model_group1.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = 9990; - model_group1.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 10; + model_group1.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 9990; + model_group1.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 10; mio::Graph>, mio::MigrationEdge> g; g.add_node(1001, model_group1, t0); diff --git a/cpp/examples/ode_seir.cpp b/cpp/examples/ode_seir.cpp index ff823c1723..bb632be36e 100644 --- a/cpp/examples/ode_seir.cpp +++ b/cpp/examples/ode_seir.cpp @@ -33,23 +33,23 @@ int main() mio::log_info("Simulating SEIR; t={} ... {} with dt = {}.", t0, tmax, dt); - mio::oseir::Model model; + mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; // suscetible now set with every other update // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 10; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); model.check_constraints(); // print_seir_params(model); diff --git a/cpp/examples/ode_seir_flows.cpp b/cpp/examples/ode_seir_flows.cpp index 97c71315bf..4a7ba18e89 100644 --- a/cpp/examples/ode_seir_flows.cpp +++ b/cpp/examples/ode_seir_flows.cpp @@ -38,23 +38,23 @@ int main() mio::log_info("Simulating SEIR; t={} ... {} with dt = {}.", t0, tmax, dt); - mio::oseir::Model model; + mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; // suscetible now set with every other update // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 10; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); model.check_constraints(); auto seir = simulate_flows(t0, tmax, dt, model); diff --git a/cpp/models/ode_seir/model.h b/cpp/models/ode_seir/model.h index 95e5459ca5..6e15d454e8 100644 --- a/cpp/models/ode_seir/model.h +++ b/cpp/models/ode_seir/model.h @@ -20,13 +20,10 @@ #ifndef SEIR_MODEL_H #define SEIR_MODEL_H -#include "memilio/compartments/flow_model.h" #include "memilio/epidemiology/populations.h" #include "memilio/epidemiology/contact_matrix.h" #include "memilio/utils/type_list.h" #include "memilio/compartments/compartmentalmodel.h" -#include "memilio/epidemiology/populations.h" -#include "memilio/epidemiology/contact_matrix.h" #include "memilio/io/io.h" #include "memilio/math/interpolation.h" #include "memilio/utils/time_series.h" @@ -34,6 +31,9 @@ #include "ode_seir/parameters.h" #include #include +#include "memilio/epidemiology/age_group.h" +#include "memilio/compartments/flow_simulation.h" + namespace mio { @@ -50,13 +50,13 @@ using Flows = TypeList>; // clang-format on -class Model : public FlowModel, Parameters, Flows> +class Model : public FlowModel, Parameters, Flows> { - using Base = FlowModel, Parameters, Flows>; + using Base = FlowModel, Parameters, Flows>; public: - Model() - : Base(Populations({InfectionState::Count}, 0.), ParameterSet()) + Model(int num_agegroups) + : Base(Populations({AgeGroup(num_agegroups), InfectionState::Count}), ParameterSet(AgeGroup(num_agegroups))) { } @@ -64,15 +64,34 @@ class Model : public FlowModel, Para Eigen::Ref flows) const override { auto& params = this->parameters; - double coeffStoE = params.get().get_matrix_at(t)(0, 0) * - params.get() / populations.get_total(); - - flows[get_flat_flow_index()] = - coeffStoE * y[(size_t)InfectionState::Susceptible] * pop[(size_t)InfectionState::Infected]; - flows[get_flat_flow_index()] = - (1.0 / params.get()) * y[(size_t)InfectionState::Exposed]; - flows[get_flat_flow_index()] = - (1.0 / params.get()) * y[(size_t)InfectionState::Infected]; + AgeGroup n_agegroups = params.get_num_groups(); + ContactMatrixGroup const& contact_matrix = params.get(); + + for(auto i = AgeGroup(0); i < n_agegroups; i++){ + double Si = this->populations.get_flat_index({i, InfectionState::Susceptible}); + double Ei = this->populations.get_flat_index({i, InfectionState::Exposed}); + double Ii = this->populations.get_flat_index({i, InfectionState::Infected}); + + for(auto j = AgeGroup(0); j < n_agegroups; j++){ + + double Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); + double Ij = this->populations.get_flat_index({j, InfectionState::Infected}); + double Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); + + double Nj = pop[Sj] + pop[Ij] + pop[Rj]; + double divNj = 1.0/Nj; + + double coeffStoE = contact_matrix.get_matrix_at(t)(static_cast((size_t)i), + static_cast((size_t)j)) * + params.get()[i]*divNj; + + double dummy_S = y[Si] *y[Ij]*coeffStoE; + + flows[get_flat_flow_index({i})]+=dummy_S; + } + flows[get_flat_flow_index({i})] = (1.0 / params.get()[i]) * y[Ei]; + flows[get_flat_flow_index({i})] = (1.0 / params.get()[i]) * y[Ii]; + } } /** @@ -87,18 +106,61 @@ class Model : public FlowModel, Para return mio::failure(mio::StatusCode::OutOfRange, "t_idx is not a valid index for the TimeSeries"); } - ScalarType TimeInfected = this->parameters.get(); + auto const& params = this->parameters; + + const size_t num_groups = (size_t)params.get_num_groups(); + const size_t num_infected_compartments = 2; + const size_t total_infected_compartments = num_infected_compartments*num_groups; + + ContactMatrixGroup const& contact_matrix = params.get(); - ScalarType coeffStoE = this->parameters.get().get_matrix_at( - y.get_time(static_cast(t_idx)))(0, 0) * - this->parameters.get() / - this->populations.get_total(); + Eigen::MatrixXd F(total_infected_compartments,total_infected_compartments); + Eigen::MatrixXd V(total_infected_compartments,total_infected_compartments); - ScalarType result = - y.get_value(static_cast(t_idx))[(Eigen::Index)mio::oseir::InfectionState::Susceptible] * - TimeInfected * coeffStoE; + for(auto i = AgeGroup(0); i < AgeGroup(num_groups); i++){ + double Si = this->populations.get_flat_index({i, InfectionState::Susceptible}); + for(auto j = AgeGroup(0); j < AgeGroup(num_groups); j++){ - return mio::success(result); + double Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); + double Ej = this->populations.get_flat_index({j, InfectionState::Susceptible}); + double Ij = this->populations.get_flat_index({j, InfectionState::Infected}); + double Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); + + double Nj = y.get_value(t_idx)[Sj]+y.get_value(t_idx)[Ej] + y.get_value(t_idx)[Ej] + y.get_value(t_idx)[Ij] + y.get_value(t_idx)[Rj]; + double divNj = 1.0/Nj; + + double coeffStoI = contact_matrix.get_matrix_at(y.get_time(t_idx))(static_cast((size_t)i), + static_cast((size_t)j))* + params.get()[i]*divNj; + + F((size_t)i,(size_t)j) = coeffStoI*y.get_value(t_idx)[Si]*y.get_value(t_idx)[Ij]; + } + + double T_Ei = params.get()[i]; + double T_Ii = params.get()[i]; + V((size_t)i,(size_t)i) = 1/T_Ei; + V((size_t)i+num_groups,(size_t)i) = - 1/T_Ei; + V((size_t)i+num_groups,(size_t)i+num_groups) = 1/T_Ii; + } + + V = V.inverse(); + + Eigen::MatrixXd NextGenMatrix(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()); } /** diff --git a/cpp/models/ode_seir/parameters.h b/cpp/models/ode_seir/parameters.h index 6cf4f71458..a0e3e2effa 100644 --- a/cpp/models/ode_seir/parameters.h +++ b/cpp/models/ode_seir/parameters.h @@ -23,6 +23,9 @@ #include "memilio/utils/uncertain_value.h" #include "memilio/epidemiology/contact_matrix.h" #include "memilio/utils/parameter_set.h" +#include "memilio/epidemiology/age_group.h" +#include "memilio/utils/custom_index_array.h" +#include "memilio/epidemiology/uncertain_matrix.h" #include @@ -39,10 +42,10 @@ namespace oseir * @brief probability of getting infected from a contact */ struct TransmissionProbabilityOnContact { - using Type = UncertainValue; - static Type get_default() + using Type = CustomIndexArray; + static Type get_default(AgeGroup size) { - return Type(1.0); + return Type(size, 1.); } static std::string name() { @@ -54,10 +57,10 @@ struct TransmissionProbabilityOnContact { * @brief the latent time in day unit */ struct TimeExposed { - using Type = UncertainValue; - static Type get_default() + using Type = CustomIndexArray; + static Type get_default(AgeGroup size) { - return Type(5.2); + return Type(size,5.2); } static std::string name() { @@ -69,10 +72,10 @@ struct TimeExposed { * @brief the infectious time in day unit */ struct TimeInfected { - using Type = UncertainValue; - static Type get_default() + using Type = CustomIndexArray; + static Type get_default(AgeGroup size) { - return Type(6.0); + return Type(size,6.0); } static std::string name() { @@ -84,10 +87,10 @@ struct TimeInfected { * @brief the contact patterns within the society are modelled using a ContactMatrix */ struct ContactPatterns { - using Type = ContactMatrix; - static Type get_default() + using Type = UncertainContactMatrix; + static Type get_default(AgeGroup size) { - return Type{1}; + return Type(1, static_cast((size_t)size)); } static std::string name() { @@ -103,11 +106,17 @@ using ParametersBase = ParameterSetget() < 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_groups);++i){ + if (this->get()[i] < 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()[i], tol_times); + this->get()[i] = tol_times; + corrected = true; + } + if (this->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->get()[i], tol_times); + this->get()[i] = tol_times; + corrected = true; + } + if (this->get()[i] < 0.0 || + this->get()[i] > 1.0) { + log_warning("Constraint check: Parameter TransmissionProbabilityOnContact changed from {:0.4f} to {:d} ", + this->get()[i], 0.0); + this->get()[i] = 0.0; + corrected = true; + } } return corrected; } @@ -161,33 +173,36 @@ class Parameters : public ParametersBase { const double tol_times = 1e-1; - if (this->get() < tol_times) { + for(auto i = AgeGroup(0); i < m_num_groups; i++){ + if (this->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->get(), 0.0); + this->get()[i], 0.0); return true; } - if (this->get() < tol_times) { + if (this->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->get(), 0.0); + this->get()[i], 0.0); return true; } - if (this->get() < 0.0 || - this->get() > 1.0) { + if (this->get()[i] < 0.0 || + this->get()[i] > 1.0) { log_error( "Constraint check: Parameter TransmissionProbabilityOnContact {:.4f} smaller {:.4f} or greater {:.4f}", - this->get(), 0.0, 1.0); + this->get()[i], 0.0, 1.0); return true; } - return false; + } + return false; } private: Parameters(ParametersBase&& base) : ParametersBase(std::move(base)) + , m_num_groups(get().get_cont_freq_mat().get_num_groups()) { } @@ -202,8 +217,9 @@ class Parameters : public ParametersBase BOOST_OUTCOME_TRY(base, ParametersBase::deserialize(io)); return success(Parameters(std::move(base))); } +private: + AgeGroup m_num_groups; }; - } // namespace oseir } // namespace mio diff --git a/cpp/tests/test_flows.cpp b/cpp/tests/test_flows.cpp index 68eef35b7d..bbdca5918c 100644 --- a/cpp/tests/test_flows.cpp +++ b/cpp/tests/test_flows.cpp @@ -59,7 +59,7 @@ class TestModel : public mio::FlowModel public: TestModel(Populations::Index dimensions) - : Base(Populations(dimensions, 0.), mio::oseir::Parameters{}) + : Base(Populations(dimensions, 0.), mio::oseir::Parameters(mio::AgeGroup(1))) { } void get_flows(Eigen::Ref /*pop*/, Eigen::Ref /*y*/, double /*t*/, @@ -103,23 +103,23 @@ TEST(TestFlows, FlowSimulation) double tmax = 1; double dt = 0.001; - mio::oseir::Model model; + mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; // suscetible now set with every other update // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 10; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); model.check_constraints(); auto IC = std::make_shared(); @@ -145,23 +145,23 @@ TEST(TestFlows, CompareSimulations) double tmax = 1; double dt = 0.001; - mio::oseir::Model model; + mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; // suscetible now set with every other update // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 10; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); model.check_constraints(); auto seir_sim_flows = simulate_flows(t0, tmax, dt, model); @@ -177,7 +177,7 @@ TEST(TestFlows, CompareSimulations) TEST(TestFlows, GetInitialFlows) { - mio::oseir::Model m; + mio::oseir::Model m(1); EXPECT_EQ(m.get_initial_flows().size(), 3); // 3 == Flows().size() EXPECT_EQ(m.get_initial_flows().norm(), 0); } diff --git a/cpp/tests/test_graph_simulation.cpp b/cpp/tests/test_graph_simulation.cpp index 6ae43c8864..abcd3da060 100644 --- a/cpp/tests/test_graph_simulation.cpp +++ b/cpp/tests/test_graph_simulation.cpp @@ -137,9 +137,9 @@ TEST(TestGraphSimulation, stopsAtTmaxStochastic) const auto tmax = 5.; const auto dt = 0.076; - mio::oseir::Model model; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = 0.9; - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 0.1; + mio::oseir::Model model(1); + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 0.9; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 0.1; model.populations.set_total(1000); mio::Graph>, mio::MigrationEdgeStochastic> g; @@ -193,9 +193,9 @@ TEST(TestGraphSimulation, consistencyStochasticMobility) const auto tmax = 10.; const auto dt = 0.076; - mio::oseir::Model model; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = 0.7; - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 0.3; + mio::oseir::Model model(1); + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 0.7; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 0.3; model.populations.set_total(1000); mio::Graph>, mio::MigrationEdgeStochastic> g; @@ -275,20 +275,20 @@ TEST(TestGraphSimulation, consistencyFlowMobility) double tmax = 1; double dt = 0.001; - mio::oseir::Model model; + mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 10; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); model.check_constraints(); diff --git a/cpp/tests/test_mobility.cpp b/cpp/tests/test_mobility.cpp index 188f3dafcf..66baac23b3 100644 --- a/cpp/tests/test_mobility.cpp +++ b/cpp/tests/test_mobility.cpp @@ -38,17 +38,17 @@ TEST(TestMobility, compareNoMigrationWithSingleIntegration) auto tmax = 5; auto dt = 0.5; - mio::oseir::Model model1; - model1.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = 0.9; - model1.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 0.1; + mio::oseir::Model model1(1); + model1.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 0.9; + model1.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 0.1; model1.populations.set_total(1000); - model1.parameters.get().get_baseline()(0, 0) = 10; + model1.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); model1.parameters.set(0.4); model1.parameters.set(4); model1.parameters.set(10); auto model2 = model1; - model2.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = 1.; + model2.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 1.; model2.populations.set_total(500); auto graph_sim = mio::make_migration_sim( diff --git a/cpp/tests/test_odeseir.cpp b/cpp/tests/test_odeseir.cpp index cba961dbee..68390f66d5 100644 --- a/cpp/tests/test_odeseir.cpp +++ b/cpp/tests/test_odeseir.cpp @@ -35,7 +35,7 @@ TEST(TestSeir, simulateDefault) double tmax = 1; double dt = 0.1; - mio::oseir::Model model; + mio::oseir::Model model(1); mio::TimeSeries result = simulate(t0, tmax, dt, model); EXPECT_NEAR(result.get_last_time(), tmax, 1e-10); @@ -50,22 +50,22 @@ TEST(TestSeir, CompareSeirWithJS) double total_population = 1061000; - mio::oseir::Model model; + mio::oseir::Model model(1); - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 10000; - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}] = 1000; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 10000; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 1000; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; model.parameters.set(1.0); model.parameters.set(5.2); 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.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)); std::vector> refData = load_test_data_csv("seir-js-compare.csv"); auto integrator = std::make_shared(); @@ -107,22 +107,22 @@ TEST(TestSeir, checkPopulationConservation) double total_population = 1061000; - mio::oseir::Model model; + mio::oseir::Model model(1); - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 10000; - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}] = 1000; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 10000; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 1000; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; model.parameters.set(1.0); model.parameters.set(5.2); 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.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)); auto result = mio::simulate(t0, tmax, dt, model); double num_persons = 0.0; for (auto i = 0; i < result.get_last_value().size(); i++) { @@ -133,11 +133,11 @@ TEST(TestSeir, checkPopulationConservation) TEST(TestSeir, check_constraints_parameters) { - mio::oseir::Model model; + mio::oseir::Model model(1); model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 10; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(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 @@ -160,46 +160,46 @@ TEST(TestSeir, check_constraints_parameters) TEST(TestSeir, apply_constraints_parameters) { const double tol_times = 1e-1; - mio::oseir::Model model; + mio::oseir::Model model(1); model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 10; + model.parameters.get().get_cont_freq_mat()[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(), tol_times); + 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(), tol_times); + 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(), 0.0, 1e-14); + EXPECT_NEAR(model.parameters.get()[(mio::AgeGroup)0], 0.0, 1e-14); mio::set_log_level(mio::LogLevel::warn); } TEST(TestSeir, get_reproduction_numbers) { - mio::oseir::Model model; + mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 10; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); model.apply_constraints(); @@ -246,7 +246,7 @@ TEST(TestSeir, get_reproduction_numbers) EXPECT_NEAR(reproduction_numbers[i], checkReproductionNumbers[i], 1e-12); } - model.parameters.get().get_baseline()(0, 0) = 9; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(9); auto reproduction_numbers2 = model.get_reproduction_numbers(result); @@ -254,7 +254,7 @@ TEST(TestSeir, get_reproduction_numbers) EXPECT_NEAR(reproduction_numbers2[i], checkReproductionNumbers2[i], 1e-12); } - model.parameters.get().get_baseline()(0, 0) = 8; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(8); auto reproduction_numbers3 = model.get_reproduction_numbers(result); @@ -268,21 +268,21 @@ TEST(TestSeir, get_reproduction_numbers) TEST(TestSeir, get_reproduction_number) { - mio::oseir::Model model; + mio::oseir::Model model(1); double total_population = 10000; //Initialize compartments to get total population of 10000 - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(mio::oseir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - + model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_baseline()(0, 0) = 10; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); model.apply_constraints(); @@ -325,11 +325,13 @@ TEST(TestSeir, get_reproduction_number) EXPECT_NEAR(model.get_reproduction_number(0.7, result).value(), 2.3242860858116172196, 1e-12); EXPECT_NEAR(model.get_reproduction_number(0.0, result).value(), 2.3280000000000002913, 1e-12); - model.parameters.get().get_baseline()(0, 0) = 9; + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(9); + EXPECT_NEAR(model.get_reproduction_number(0.1, result).value(), 2.0946073086586665113, 1e-12); EXPECT_NEAR(model.get_reproduction_number(0.3, result).value(), 2.0936545545126947765, 1e-12); + + model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(8); - model.parameters.get().get_baseline()(0, 0) = 8; EXPECT_NEAR(model.get_reproduction_number(0.2, result).value(), 1.8614409729718137676, 1e-12); EXPECT_NEAR(model.get_reproduction_number(0.9, result).value(), 1.858670429549998504, 1e-12); } From a97113111bd1531bc5d9216f40d947456560e3c0 Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 29 Jan 2024 09:41:37 +0100 Subject: [PATCH 05/34] agegroup extension finished --- cpp/models/ode_seir/model.h | 26 ++++++++++----------- cpp/tests/test_odeseir.cpp | 45 +++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/cpp/models/ode_seir/model.h b/cpp/models/ode_seir/model.h index 6e15d454e8..7cfd16f600 100644 --- a/cpp/models/ode_seir/model.h +++ b/cpp/models/ode_seir/model.h @@ -75,10 +75,11 @@ class Model : public FlowModelpopulations.get_flat_index({j, InfectionState::Susceptible}); + double Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); double Ij = this->populations.get_flat_index({j, InfectionState::Infected}); double Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); - double Nj = pop[Sj] + pop[Ij] + pop[Rj]; + double Nj = pop[Sj] + pop[Ej] + pop[Ij] + pop[Rj]; double divNj = 1.0/Nj; double coeffStoE = contact_matrix.get_matrix_at(t)(static_cast((size_t)i), @@ -113,39 +114,38 @@ class Model : public FlowModel(); - - Eigen::MatrixXd F(total_infected_compartments,total_infected_compartments); - Eigen::MatrixXd V(total_infected_compartments,total_infected_compartments); + + 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_groups); i++){ double Si = this->populations.get_flat_index({i, InfectionState::Susceptible}); for(auto j = AgeGroup(0); j < AgeGroup(num_groups); j++){ double Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); - double Ej = this->populations.get_flat_index({j, InfectionState::Susceptible}); + double Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); double Ij = this->populations.get_flat_index({j, InfectionState::Infected}); double Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); - double Nj = y.get_value(t_idx)[Sj]+y.get_value(t_idx)[Ej] + y.get_value(t_idx)[Ej] + y.get_value(t_idx)[Ij] + y.get_value(t_idx)[Rj]; + double Nj = y.get_value(t_idx)[Sj]+y.get_value(t_idx)[Ej] + y.get_value(t_idx)[Ij] + y.get_value(t_idx)[Rj]; double divNj = 1.0/Nj; - double coeffStoI = contact_matrix.get_matrix_at(y.get_time(t_idx))(static_cast((size_t)i), + double coeffStoE = contact_matrix.get_matrix_at(y.get_time(t_idx))(static_cast((size_t)i), static_cast((size_t)j))* params.get()[i]*divNj; - - F((size_t)i,(size_t)j) = coeffStoI*y.get_value(t_idx)[Si]*y.get_value(t_idx)[Ij]; + F((size_t)i,(size_t)j+num_groups) = coeffStoE*y.get_value(t_idx)[Si]; } double T_Ei = params.get()[i]; double T_Ii = params.get()[i]; - V((size_t)i,(size_t)i) = 1/T_Ei; - V((size_t)i+num_groups,(size_t)i) = - 1/T_Ei; - V((size_t)i+num_groups,(size_t)i+num_groups) = 1/T_Ii; + V((size_t)i,(size_t)i) = 1.0/T_Ei; + V((size_t)i+num_groups,(size_t)i) = - 1.0/T_Ei; + V((size_t)i+num_groups,(size_t)i+num_groups) = 1.0/T_Ii; } V = V.inverse(); - Eigen::MatrixXd NextGenMatrix(total_infected_compartments, total_infected_compartments); + Eigen::MatrixXd NextGenMatrix = Eigen::MatrixXd::Zero(total_infected_compartments, total_infected_compartments); NextGenMatrix = F * V; //Compute the largest eigenvalue in absolute value diff --git a/cpp/tests/test_odeseir.cpp b/cpp/tests/test_odeseir.cpp index 68390f66d5..2598e70340 100644 --- a/cpp/tests/test_odeseir.cpp +++ b/cpp/tests/test_odeseir.cpp @@ -225,12 +225,33 @@ TEST(TestSeir, get_reproduction_numbers) mio::TimeSeries::Vector result_6(4); result_0[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9700; + result_0[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100; + result_0[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100; + result_0[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100; result_1[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.9611995799496071; + result_1[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.012933473350130966666666666666666666667; + result_1[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.012933473350130966666666666666666666667; + result_1[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.012933473350130966666666666666666666667; result_2[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.7865872644051706; + result_2[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.0711375785316098; + result_2[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.0711375785316098; + result_2[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.0711375785316098; result_3[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.0006179798110679; + result_3[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.33312734006297736666666666666666666666667; + result_3[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.33312734006297736666666666666666666666667; + result_3[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.33312734006297736666666666666666666666667; result_4[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9695.4591772453732119; + result_4[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 101.513607584875596033333333333333333333333333; + result_4[(Eigen::Index)mio::oseir::InfectionState::Infected] = 101.513607584875596033333333333333333333333333; + result_4[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 101.513607584875596033333333333333333333333333; result_5[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9679.4083551723888377; + result_5[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 106.863881609203720766666666666666666666667; + result_5[(Eigen::Index)mio::oseir::InfectionState::Infected] = 106.863881609203720766666666666666666666667; + result_5[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 106.863881609203720766666666666666666666667; result_6[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9660.5835936179428245; + result_6[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 113.1388021273523918333333333333333333333333; + result_6[(Eigen::Index)mio::oseir::InfectionState::Infected] = 113.1388021273523918333333333333333333333333; + result_6[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 113.1388021273523918333333333333333333333333; result.add_time_point(0, result_0); result.add_time_point(0.0010000000000000000208, result_1); @@ -297,13 +318,37 @@ TEST(TestSeir, get_reproduction_number) mio::TimeSeries::Vector result_7(4); result_0[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9700; + result_0[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.0; + result_0[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.0; + result_0[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.0; result_1[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.9709149074315; + result_1[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.009695030856166666666666666666666666666667; + result_1[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.009695030856166666666666666666666666666667; + result_1[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.009695030856166666666666666666666666666667; result_2[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.8404009584538; + result_2[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.0531996805154; + result_2[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.0531996805154; + result_2[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.0531996805154; result_3[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.260556488618; + result_3[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.24648117046066666666666666666666666667; + result_3[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.24648117046066666666666666666666666667; + result_3[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.24648117046066666666666666666666666667; result_4[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9696.800490904101; + result_4[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 101.06650303196633333333333333333333333333333; + result_4[(Eigen::Index)mio::oseir::InfectionState::Infected] = 101.06650303196633333333333333333333333333333; + result_4[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 101.06650303196633333333333333333333333333333; result_5[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9687.9435082620021; + result_5[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 104.018830579332633333333333333333333333333333; + result_5[(Eigen::Index)mio::oseir::InfectionState::Infected] = 104.018830579332633333333333333333333333333333; + result_5[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 104.018830579332633333333333333333333333333333; result_6[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9679.5436372291661; + result_6[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 106.8187875902779666666666666666666666666667; + result_6[(Eigen::Index)mio::oseir::InfectionState::Infected] = 106.8187875902779666666666666666666666666667; + result_6[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 106.8187875902779666666666666666666666666667; result_7[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9678.5949381732935; + result_7[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 107.135020608902166666666666666666666666667; + result_7[(Eigen::Index)mio::oseir::InfectionState::Infected] = 107.135020608902166666666666666666666666667; + result_7[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 107.135020608902166666666666666666666666667; result.add_time_point(0, result_0); result.add_time_point(0.001, result_1); From 2514ded5ef9197f06c72a4eea622c2d7a3b92c68 Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 29 Jan 2024 10:51:15 +0100 Subject: [PATCH 06/34] try to fix CI --- cpp/models/ode_seir/model.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/models/ode_seir/model.h b/cpp/models/ode_seir/model.h index 7cfd16f600..e1554d6cad 100644 --- a/cpp/models/ode_seir/model.h +++ b/cpp/models/ode_seir/model.h @@ -122,10 +122,10 @@ class Model : public FlowModelpopulations.get_flat_index({i, InfectionState::Susceptible}); for(auto j = AgeGroup(0); j < AgeGroup(num_groups); j++){ - double Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); - double Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); - double Ij = this->populations.get_flat_index({j, InfectionState::Infected}); - double Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); + auto Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); + auto Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); + auto Ij = this->populations.get_flat_index({j, InfectionState::Infected}); + auto Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); double Nj = y.get_value(t_idx)[Sj]+y.get_value(t_idx)[Ej] + y.get_value(t_idx)[Ij] + y.get_value(t_idx)[Rj]; double divNj = 1.0/Nj; From f14ed43d59baf03df3be98a4b9df81e133da2bdf Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 29 Jan 2024 11:05:33 +0100 Subject: [PATCH 07/34] hope to fix CI --- cpp/models/ode_seir/model.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cpp/models/ode_seir/model.h b/cpp/models/ode_seir/model.h index e1554d6cad..af3c90d1dc 100644 --- a/cpp/models/ode_seir/model.h +++ b/cpp/models/ode_seir/model.h @@ -68,16 +68,16 @@ class Model : public FlowModel(); for(auto i = AgeGroup(0); i < n_agegroups; i++){ - double Si = this->populations.get_flat_index({i, InfectionState::Susceptible}); - double Ei = this->populations.get_flat_index({i, InfectionState::Exposed}); - double Ii = this->populations.get_flat_index({i, InfectionState::Infected}); + size_t Si = this->populations.get_flat_index({i, InfectionState::Susceptible}); + size_t Ei = this->populations.get_flat_index({i, InfectionState::Exposed}); + size_t Ii = this->populations.get_flat_index({i, InfectionState::Infected}); for(auto j = AgeGroup(0); j < n_agegroups; j++){ - double Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); - double Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); - double Ij = this->populations.get_flat_index({j, InfectionState::Infected}); - double Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); + size_t Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); + size_t Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); + size_t Ij = this->populations.get_flat_index({j, InfectionState::Infected}); + size_t Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); double Nj = pop[Sj] + pop[Ej] + pop[Ij] + pop[Rj]; double divNj = 1.0/Nj; @@ -119,13 +119,13 @@ class Model : public FlowModelpopulations.get_flat_index({i, InfectionState::Susceptible}); + size_t Si = this->populations.get_flat_index({i, InfectionState::Susceptible}); for(auto j = AgeGroup(0); j < AgeGroup(num_groups); j++){ - auto Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); - auto Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); - auto Ij = this->populations.get_flat_index({j, InfectionState::Infected}); - auto Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); + size_t Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); + size_t Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); + size_t Ij = this->populations.get_flat_index({j, InfectionState::Infected}); + size_t Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); double Nj = y.get_value(t_idx)[Sj]+y.get_value(t_idx)[Ej] + y.get_value(t_idx)[Ij] + y.get_value(t_idx)[Rj]; double divNj = 1.0/Nj; From d018c3081d64d38f1af39f92cdf1089d1e723578 Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 29 Jan 2024 11:15:33 +0100 Subject: [PATCH 08/34] get ci to work --- cpp/models/ode_sir/model.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/models/ode_sir/model.h b/cpp/models/ode_sir/model.h index fb10054db8..c441424f7b 100644 --- a/cpp/models/ode_sir/model.h +++ b/cpp/models/ode_sir/model.h @@ -57,15 +57,15 @@ class Model : public CompartmentalModelpopulations.get_flat_index({i, InfectionState::Susceptible}); - double Ii = this->populations.get_flat_index({i, InfectionState::Infected}); - double Ri = this->populations.get_flat_index({i, InfectionState::Recovered}); + size_t Si = this->populations.get_flat_index({i, InfectionState::Susceptible}); + size_t Ii = this->populations.get_flat_index({i, InfectionState::Infected}); + size_t Ri = this->populations.get_flat_index({i, InfectionState::Recovered}); for (auto j = AgeGroup(0); j < n_agegroups; j++){ - double Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); - double Ij = this->populations.get_flat_index({j, InfectionState::Infected}); - double Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); + size_t Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); + size_t Ij = this->populations.get_flat_index({j, InfectionState::Infected}); + size_t Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); double Nj = pop[Sj] + pop[Ij] + pop[Rj]; From f66bdfe9e4b68c71db287cfe88611a3c0ca03f14 Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 5 Feb 2024 10:12:49 +0100 Subject: [PATCH 09/34] easier indexing --- cpp/examples/graph.cpp | 6 +++--- cpp/examples/ode_seir.cpp | 15 ++++++++------- cpp/examples/ode_seir_flows.cpp | 14 +++++++------- cpp/examples/ode_sir.cpp | 10 +++++----- cpp/tests/test_flows.cpp | 28 ++++++++++++++-------------- cpp/tests/test_graph_simulation.cpp | 22 +++++++++++----------- cpp/tests/test_mobility.cpp | 6 +++--- 7 files changed, 51 insertions(+), 50 deletions(-) diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index fd4e1a84f0..11c216a2e3 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -32,7 +32,7 @@ int main() const auto dt = 0.5; //time step of migration, daily migration every second step mio::oseir::Model model(1); - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 10000; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 10000; model.parameters.set(1); model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(2.7); model.parameters.set(1); @@ -43,8 +43,8 @@ int main() //some contact restrictions in group 1 model_group1.parameters.get().get_cont_freq_mat()[0].add_damping(0.5, mio::SimulationTime(5)); //infection starts in group 1 - model_group1.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 9990; - model_group1.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 10; + model_group1.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 9990; + model_group1.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] = 10; mio::Graph>, mio::MigrationEdge> g; g.add_node(1001, model_group1, t0); diff --git a/cpp/examples/ode_seir.cpp b/cpp/examples/ode_seir.cpp index bb632be36e..4883205850 100644 --- a/cpp/examples/ode_seir.cpp +++ b/cpp/examples/ode_seir.cpp @@ -36,14 +36,15 @@ int main() mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = + //model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; + 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::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; + 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}]; // suscetible now set with every other update // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; model.parameters.set(5.2); diff --git a/cpp/examples/ode_seir_flows.cpp b/cpp/examples/ode_seir_flows.cpp index 4a7ba18e89..8d74a45d32 100644 --- a/cpp/examples/ode_seir_flows.cpp +++ b/cpp/examples/ode_seir_flows.cpp @@ -41,14 +41,14 @@ int main() mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = + 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::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; + 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}]; // suscetible now set with every other update // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; model.parameters.set(5.2); diff --git a/cpp/examples/ode_sir.cpp b/cpp/examples/ode_sir.cpp index 270d85e4a5..0d88e1be11 100644 --- a/cpp/examples/ode_sir.cpp +++ b/cpp/examples/ode_sir.cpp @@ -38,12 +38,12 @@ int main() mio::osir::Model model(1); - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Recovered)}] = 1000; - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Susceptible)}] = + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] = 1000; + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}] = 1000; + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Susceptible}] = total_population - - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Recovered)}]; + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] - + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}]; model.parameters.set(2); model.parameters.set(1); model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(2.7); diff --git a/cpp/tests/test_flows.cpp b/cpp/tests/test_flows.cpp index bbdca5918c..b4b2c33018 100644 --- a/cpp/tests/test_flows.cpp +++ b/cpp/tests/test_flows.cpp @@ -106,14 +106,14 @@ TEST(TestFlows, FlowSimulation) mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = + 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::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; + 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}]; // suscetible now set with every other update // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; model.parameters.set(5.2); @@ -148,14 +148,14 @@ TEST(TestFlows, CompareSimulations) mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = + 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::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; + 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}]; // suscetible now set with every other update // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; model.parameters.set(5.2); diff --git a/cpp/tests/test_graph_simulation.cpp b/cpp/tests/test_graph_simulation.cpp index abcd3da060..d75bac788e 100644 --- a/cpp/tests/test_graph_simulation.cpp +++ b/cpp/tests/test_graph_simulation.cpp @@ -138,8 +138,8 @@ TEST(TestGraphSimulation, stopsAtTmaxStochastic) const auto dt = 0.076; mio::oseir::Model model(1); - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 0.9; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 0.1; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 0.9; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] = 0.1; model.populations.set_total(1000); mio::Graph>, mio::MigrationEdgeStochastic> g; @@ -194,8 +194,8 @@ TEST(TestGraphSimulation, consistencyStochasticMobility) const auto dt = 0.076; mio::oseir::Model model(1); - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 0.7; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 0.3; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 0.7; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] = 0.3; model.populations.set_total(1000); mio::Graph>, mio::MigrationEdgeStochastic> g; @@ -277,14 +277,14 @@ TEST(TestGraphSimulation, consistencyFlowMobility) mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = + 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::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; + 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}]; model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); diff --git a/cpp/tests/test_mobility.cpp b/cpp/tests/test_mobility.cpp index 66baac23b3..c00bfdcc68 100644 --- a/cpp/tests/test_mobility.cpp +++ b/cpp/tests/test_mobility.cpp @@ -39,8 +39,8 @@ TEST(TestMobility, compareNoMigrationWithSingleIntegration) auto dt = 0.5; mio::oseir::Model model1(1); - model1.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 0.9; - model1.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 0.1; + model1.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 0.9; + model1.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] = 0.1; model1.populations.set_total(1000); model1.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); model1.parameters.set(0.4); @@ -48,7 +48,7 @@ TEST(TestMobility, compareNoMigrationWithSingleIntegration) model1.parameters.set(10); auto model2 = model1; - model2.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = 1.; + model2.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 1.; model2.populations.set_total(500); auto graph_sim = mio::make_migration_sim( From f9fd94a91d21538a03fbc28ab0c2c5b888785d41 Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 5 Feb 2024 10:13:59 +0100 Subject: [PATCH 10/34] gitignore changed --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index e3a0627b25..412c0bd65d 100644 --- a/.gitignore +++ b/.gitignore @@ -279,4 +279,3 @@ docs/html docs/xml # End of https://www.gitignore.io/api/c++,node,python -.vscode/settings.json From df3dcecc07f85079ace4138c8f8e3e4d4acc01e8 Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 5 Feb 2024 10:44:02 +0100 Subject: [PATCH 11/34] added contact matrices --- cpp/examples/graph.cpp | 6 ++++-- cpp/examples/ode_seir.cpp | 3 ++- cpp/examples/ode_seir_flows.cpp | 3 ++- cpp/examples/ode_sir.cpp | 5 +++-- cpp/tests/test_flows.cpp | 3 ++- cpp/tests/test_graph_simulation.cpp | 3 ++- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index 11c216a2e3..bf45c36359 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -34,14 +34,16 @@ int main() mio::oseir::Model model(1); model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 10000; model.parameters.set(1); - model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(2.7); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(2.7); model.parameters.set(1); //two mostly identical groups auto model_group1 = model; auto model_group2 = model; //some contact restrictions in group 1 - model_group1.parameters.get().get_cont_freq_mat()[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; model_group1.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] = 10; diff --git a/cpp/examples/ode_seir.cpp b/cpp/examples/ode_seir.cpp index 4883205850..3814ff1ccb 100644 --- a/cpp/examples/ode_seir.cpp +++ b/cpp/examples/ode_seir.cpp @@ -50,7 +50,8 @@ int main() model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(10); model.check_constraints(); // print_seir_params(model); diff --git a/cpp/examples/ode_seir_flows.cpp b/cpp/examples/ode_seir_flows.cpp index 8d74a45d32..188cb60202 100644 --- a/cpp/examples/ode_seir_flows.cpp +++ b/cpp/examples/ode_seir_flows.cpp @@ -54,7 +54,8 @@ int main() model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(10); model.check_constraints(); auto seir = simulate_flows(t0, tmax, dt, model); diff --git a/cpp/examples/ode_sir.cpp b/cpp/examples/ode_sir.cpp index 0d88e1be11..e74175bc86 100644 --- a/cpp/examples/ode_sir.cpp +++ b/cpp/examples/ode_sir.cpp @@ -46,8 +46,9 @@ int main() model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}]; model.parameters.set(2); model.parameters.set(1); - 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)); + 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.6, mio::SimulationTime(12.5)); auto integrator = std::make_shared(); diff --git a/cpp/tests/test_flows.cpp b/cpp/tests/test_flows.cpp index b4b2c33018..b3e1ead5ee 100644 --- a/cpp/tests/test_flows.cpp +++ b/cpp/tests/test_flows.cpp @@ -161,7 +161,8 @@ TEST(TestFlows, CompareSimulations) model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(10); model.check_constraints(); auto seir_sim_flows = simulate_flows(t0, tmax, dt, model); diff --git a/cpp/tests/test_graph_simulation.cpp b/cpp/tests/test_graph_simulation.cpp index d75bac788e..97081da299 100644 --- a/cpp/tests/test_graph_simulation.cpp +++ b/cpp/tests/test_graph_simulation.cpp @@ -288,7 +288,8 @@ TEST(TestGraphSimulation, consistencyFlowMobility) model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(10); model.check_constraints(); From 8120e44c057cdefb3cbae274480caa6ba2593fe4 Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 26 Feb 2024 16:00:02 +0100 Subject: [PATCH 12/34] added ageres examples --- cpp/examples/CMakeLists.txt | 7 +++ cpp/examples/ode_seir_ageres.cpp | 74 ++++++++++++++++++++++++++++++++ cpp/examples/ode_sir_ageres.cpp | 68 +++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 cpp/examples/ode_seir_ageres.cpp create mode 100644 cpp/examples/ode_sir_ageres.cpp diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 3c5e4e7369..f251e480bc 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -18,9 +18,16 @@ add_executable(ode_seir_example ode_seir.cpp) target_link_libraries(ode_seir_example PRIVATE memilio ode_seir) target_compile_options(ode_seir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(ode_seir_ageres_example ode_seir_ageres.cpp) +target_link_libraries(ode_seir_ageres_example PRIVATE memilio ode_seir) +target_compile_options(ode_seir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) + add_executable(ode_sir_example ode_sir.cpp) target_link_libraries(ode_sir_example PRIVATE memilio ode_sir) +add_executable(ode_sir_ageres_example ode_sir_ageres.cpp) +target_link_libraries(ode_sir_ageres_example PRIVATE memilio ode_sir) +target_compile_options(ode_sir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) add_executable(seir_flows_example ode_seir_flows.cpp) target_link_libraries(seir_flows_example PRIVATE memilio ode_seir) diff --git a/cpp/examples/ode_seir_ageres.cpp b/cpp/examples/ode_seir_ageres.cpp new file mode 100644 index 0000000000..d0a9ee7738 --- /dev/null +++ b/cpp/examples/ode_seir_ageres.cpp @@ -0,0 +1,74 @@ +#include "ode_seir/model.h" +#include "ode_seir/infection_state.h" +#include "ode_seir/parameters.h" +#include "memilio/compartments/simulation.h" +#include "memilio/utils/logging.h" + +int main() +{ + mio::set_log_level(mio::LogLevel::debug); + + double t0 = 0; + double tmax = 1; + double dt = 0.001; + + mio::log_info("Simulating SEIR; t={} ... {} with dt = {}.", t0, tmax, dt); + + double cont_freq = 10; // see Polymod study + + double nb_total_t0 = 10000, nb_exp_t0 = 100, nb_inf_t0 = 50, nb_rec_t0 = 10; + + // alpha = alpha_in; // percentage of asymptomatic cases + // beta = beta_in; // risk of infection from the infected symptomatic patients + // rho = rho_in; // hospitalized per infected + // theta = theta_in; // icu per hospitalized + // delta = delta_in; // deaths per ICUs + + mio::oseir::Model model(3); + + auto nb_groups = model.parameters.get_num_groups(); + + double fact = 1.0 / (double)(size_t)nb_groups; + + auto& params = model.parameters; + + for (auto i = mio::AgeGroup(0); i < nb_groups; i++) { + model.populations[{i, mio::oseir::InfectionState::Exposed}] = fact*nb_exp_t0; + model.populations[{i, mio::oseir::InfectionState::Infected}] = fact*nb_inf_t0; + model.populations[{i, mio::oseir::InfectionState::Recovered}] = fact*nb_rec_t0; + model.populations.set_difference_from_group_total({i, mio::oseir::InfectionState::Susceptible}, + fact * nb_total_t0); + + model.parameters.get()[i] = 5.2; + model.parameters.get()[i] = 6; + model.parameters.get()[i] = 0.04; + + } + + mio::ContactMatrixGroup& contact_matrix = params.get(); + contact_matrix[0] = + mio::ContactMatrix(Eigen::MatrixXd::Constant((size_t)nb_groups, (size_t)nb_groups, fact * cont_freq)); + contact_matrix.add_damping(Eigen::MatrixXd::Constant((size_t)nb_groups, (size_t)nb_groups, 0.7), + mio::SimulationTime(30.)); + + model.apply_constraints(); + + mio::TimeSeries seir = simulate(t0, tmax, dt, model); + + std::vector vars = {"S", "E", "I", "R"}; + printf("Number of time points :%d\n", static_cast(seir.get_num_time_points())); + printf("People in\n"); + + for (size_t k = 0; k < (size_t)mio::oseir::InfectionState::Count; k++) { + double dummy = 0; + + for (size_t i = 0; i < (size_t)params.get_num_groups(); i++) { + printf("\t %s[%d]: %.0f", vars[k].c_str(), (int)i, + seir.get_last_value()[k + (size_t)mio::oseir::InfectionState::Count * (int)i]); + dummy += seir.get_last_value()[k + (size_t)mio::oseir::InfectionState::Count * (int)i]; + } + + printf("\t %s_otal: %.0f\n", vars[k].c_str(), dummy); + +} +} diff --git a/cpp/examples/ode_sir_ageres.cpp b/cpp/examples/ode_sir_ageres.cpp new file mode 100644 index 0000000000..e85414e138 --- /dev/null +++ b/cpp/examples/ode_sir_ageres.cpp @@ -0,0 +1,68 @@ +#include "memilio/utils/time_series.h" +#include "memilio/utils/logging.h" +#include "memilio/compartments/simulation.h" +#include "ode_sir/model.h" + +int main(){ + mio::set_log_level(mio::LogLevel::debug); + + double t0 = 0; + double tmax = 50; + double dt = 0.1; + + mio::log_info("Simulating SIR; t={} ... {} with dt = {}.", t0, tmax, dt); + + double cont_freq = 10; // see Polymod study + + double nb_total_t0 = 10000, nb_inf_t0 = 50, nb_rec_t0 = 10; + + // alpha = alpha_in; // percentage of asymptomatic cases + // beta = beta_in; // risk of infection from the infected symptomatic patients + // rho = rho_in; // hospitalized per infected + // theta = theta_in; // icu per hospitalized + // delta = delta_in; // deaths per ICUs + + mio::osir::Model model(3); + auto nb_groups = model.parameters.get_num_groups(); + + double fact = 1.0 / (double)(size_t)nb_groups; + + auto& params = model.parameters; + + for (auto i = mio::AgeGroup(0); i < nb_groups; i++) { + model.populations[{i, mio::osir::InfectionState::Infected}] = fact*nb_inf_t0; + model.populations[{i, mio::osir::InfectionState::Recovered}] = fact*nb_rec_t0; + model.populations.set_difference_from_group_total({i, mio::osir::InfectionState::Susceptible}, + fact * nb_total_t0); + + model.parameters.get()[i] = 2.0; + model.parameters.get()[i] = 0.3; + + } + + mio::ContactMatrixGroup& contact_matrix = params.get(); + contact_matrix[0] = + mio::ContactMatrix(Eigen::MatrixXd::Constant((size_t)nb_groups, (size_t)nb_groups, fact * cont_freq)); + contact_matrix.add_damping(Eigen::MatrixXd::Constant((size_t)nb_groups, (size_t)nb_groups, 0.7), + mio::SimulationTime(30.)); + + model.apply_constraints(); + + mio::TimeSeries sir = simulate(t0, tmax, dt, model); + + 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::osir::InfectionState::Count; k++) { + double dummy = 0; + + for (size_t i = 0; i < (size_t)params.get_num_groups(); i++) { + printf("\t %s[%d]: %.0f", vars[k].c_str(), (int)i, + sir.get_last_value()[k + (size_t)mio::osir::InfectionState::Count * (int)i]); + dummy += sir.get_last_value()[k + (size_t)mio::osir::InfectionState::Count * (int)i]; + } + + printf("\t %s_otal: %.0f\n", vars[k].c_str(), dummy); + } +} \ No newline at end of file From 5a47464106af0a1db0458a4da36872e475c0ef30 Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Fri, 1 Mar 2024 12:18:34 +0100 Subject: [PATCH 13/34] first try to implement agegroup test --- .vscode/settings.json | 3 + cpp/examples/ode_sir.cpp | 30 ++ cpp/examples/sir_example_pre_agegroups.txt | 499 ++++++++++++++++++++ cpp/tests/sir_example_pre_agegroups.txt | 501 +++++++++++++++++++++ cpp/tests/test_odesir.cpp | 53 +++ 5 files changed, 1086 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 cpp/examples/sir_example_pre_agegroups.txt create mode 100644 cpp/tests/sir_example_pre_agegroups.txt diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..e5e80475e7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.sourceDirectory": "/home/joha_pu/Documents/coding/memilio1/memilio/cpp/CMakeLists.txt" +} \ No newline at end of file diff --git a/cpp/examples/ode_sir.cpp b/cpp/examples/ode_sir.cpp index e74175bc86..42b021136d 100644 --- a/cpp/examples/ode_sir.cpp +++ b/cpp/examples/ode_sir.cpp @@ -23,6 +23,8 @@ #include "ode_sir/parameters.h" #include "memilio/compartments/simulation.h" #include "memilio/utils/logging.h" +#include +#include int main() { @@ -77,4 +79,32 @@ int main() Eigen::VectorXd res_j = sir.get_last_value(); printf("number total: %f", res_j[0] + res_j[1] + res_j[2]); } + + // Print the resulting table into a string + std::ostringstream ostream; + sir.print_table({"S","I", "R"}, 16, 5,ostream); + std::string result_1 = ostream.rdbuf()->str(); + + // Extract existing table from implementation without agegroups into string + std::string path = "sir_example_pre_agegroups.txt"; + constexpr auto read_size = std::size_t(40000); + auto istream = std::ifstream(path); + istream.exceptions(std::ios_base::badbit); + + if (!istream.is_open()) { + throw std::ios_base::failure("file does not exist"); + } + + auto result_2 = std::string(); + auto buf = std::string(read_size, '\0'); + while (istream.read(& buf[0], read_size)) { + result_2.append(buf, 0, istream.gcount()); + } + result_2.append(buf, 0, istream.gcount()); + + std::cout< #include #include +#include TEST(Testsir, simulateDefault) { @@ -169,4 +170,56 @@ TEST(Testsir, apply_constraints_parameters) 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(Testsir, test_age_groups) +{ + double t0 = 0.; + double tmax = 50.; + double dt = 0.1002004008016032; + + double total_population = 1061000; + + mio::osir::Model model(1); + + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] = 1000; + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}] = 1000; + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Susceptible}] = + total_population - + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] - + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}]; + model.parameters.set(2); + model.parameters.set(1); + 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.6, mio::SimulationTime(12.5)); + + auto integrator = std::make_shared(); + + model.check_constraints(); + + auto sir = simulate(t0, tmax, dt, model, integrator); + + // Convert the table from the simulation into a string + std::ostringstream ostream; + sir.print_table({"S","I", "R"}, 16, 5,ostream); + std::string result_1 = ostream.rdbuf()->str(); + + // Extract existing table from implementation without agegroups into a string + std::string path = "sir_example_pre_agegroups.txt"; + constexpr auto read_size = std::size_t(40000); + auto istream = std::ifstream(path); + istream.exceptions(std::ios_base::badbit); + + if (!istream.is_open()) { + throw std::ios_base::failure("file does not exist"); + } + + auto result_2 = std::string(); + auto buf = std::string(read_size, '\0'); + while (istream.read(& buf[0], read_size)) { + result_2.append(buf, 0, istream.gcount()); + } + result_2.append(buf, 0, istream.gcount()); + EXPECT_EQ(result_1,result_2); } \ No newline at end of file From 851c0e2b7f1450d128f62421e1e972169e359b3b Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 4 Mar 2024 13:31:32 +0100 Subject: [PATCH 14/34] push --- cpp/examples/ode_sir.cpp | 2 +- cpp/tests/test_odesir.cpp | 30 +++++++++--------------------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/cpp/examples/ode_sir.cpp b/cpp/examples/ode_sir.cpp index 42b021136d..2106bd9b01 100644 --- a/cpp/examples/ode_sir.cpp +++ b/cpp/examples/ode_sir.cpp @@ -82,7 +82,7 @@ int main() // Print the resulting table into a string std::ostringstream ostream; - sir.print_table({"S","I", "R"}, 16, 5,ostream); + sir.print_table({"S","I", "R"}, 16, 1,ostream); std::string result_1 = ostream.rdbuf()->str(); // Extract existing table from implementation without agegroups into string diff --git a/cpp/tests/test_odesir.cpp b/cpp/tests/test_odesir.cpp index df00b6f10b..416640bdb5 100644 --- a/cpp/tests/test_odesir.cpp +++ b/cpp/tests/test_odesir.cpp @@ -200,26 +200,14 @@ TEST(Testsir, test_age_groups) auto sir = simulate(t0, tmax, dt, model, integrator); - // Convert the table from the simulation into a string - std::ostringstream ostream; - sir.print_table({"S","I", "R"}, 16, 5,ostream); - std::string result_1 = ostream.rdbuf()->str(); - - // Extract existing table from implementation without agegroups into a string - std::string path = "sir_example_pre_agegroups.txt"; - constexpr auto read_size = std::size_t(40000); - auto istream = std::ifstream(path); - istream.exceptions(std::ios_base::badbit); - - if (!istream.is_open()) { - throw std::ios_base::failure("file does not exist"); - } - - auto result_2 = std::string(); - auto buf = std::string(read_size, '\0'); - while (istream.read(& buf[0], read_size)) { - result_2.append(buf, 0, istream.gcount()); + const auto compare = load_test_data_csv("sir-agegrp-compare.csv"); + + ASSERT_EQ(compare.size(), static_cast(sir.get_num_time_points())); + for (size_t i = 0; i < compare.size(); i++) { + ASSERT_EQ(compare[i].size(), static_cast(sir.get_num_elements()) + 1) << "at row " << i; + EXPECT_NEAR(sir.get_time(i), compare[i][0], 1e-10) << "at row " << i; + for (size_t j = 1; j < compare[i].size(); j++) { + EXPECT_NEAR(sir.get_value(i)[j - 1], compare[i][j], 1e-10) << " at row " << i; + } } - result_2.append(buf, 0, istream.gcount()); - EXPECT_EQ(result_1,result_2); } \ No newline at end of file From 0bfd71c6b7c7639d27ac57d7784bbfc0b27860ca Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 11 Mar 2024 09:43:29 +0100 Subject: [PATCH 15/34] test agegroup --- cpp/tests/test_odesir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/tests/test_odesir.cpp b/cpp/tests/test_odesir.cpp index 416640bdb5..816fe73a48 100644 --- a/cpp/tests/test_odesir.cpp +++ b/cpp/tests/test_odesir.cpp @@ -207,7 +207,7 @@ TEST(Testsir, test_age_groups) ASSERT_EQ(compare[i].size(), static_cast(sir.get_num_elements()) + 1) << "at row " << i; EXPECT_NEAR(sir.get_time(i), compare[i][0], 1e-10) << "at row " << i; for (size_t j = 1; j < compare[i].size(); j++) { - EXPECT_NEAR(sir.get_value(i)[j - 1], compare[i][j], 1e-10) << " at row " << i; + EXPECT_NEAR(sir.get_value(i)[j - 1], compare[i][j], 1e-9) << " at row " << i; } } } \ No newline at end of file From 832b3644521378d34765cefb9bd7ce82e681676e Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 11 Mar 2024 12:59:16 +0100 Subject: [PATCH 16/34] new tests added --- cpp/examples/ode_sir.cpp | 28 -------------------------- cpp/tests/test_odesir.cpp | 41 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/cpp/examples/ode_sir.cpp b/cpp/examples/ode_sir.cpp index 2106bd9b01..8b6ef38d90 100644 --- a/cpp/examples/ode_sir.cpp +++ b/cpp/examples/ode_sir.cpp @@ -79,32 +79,4 @@ int main() Eigen::VectorXd res_j = sir.get_last_value(); printf("number total: %f", res_j[0] + res_j[1] + res_j[2]); } - - // Print the resulting table into a string - std::ostringstream ostream; - sir.print_table({"S","I", "R"}, 16, 1,ostream); - std::string result_1 = ostream.rdbuf()->str(); - - // Extract existing table from implementation without agegroups into string - std::string path = "sir_example_pre_agegroups.txt"; - constexpr auto read_size = std::size_t(40000); - auto istream = std::ifstream(path); - istream.exceptions(std::ios_base::badbit); - - if (!istream.is_open()) { - throw std::ios_base::failure("file does not exist"); - } - - auto result_2 = std::string(); - auto buf = std::string(read_size, '\0'); - while (istream.read(& buf[0], read_size)) { - result_2.append(buf, 0, istream.gcount()); - } - result_2.append(buf, 0, istream.gcount()); - - std::cout<(2); + model.parameters.set(1); + 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.6, mio::SimulationTime(12.5)); + + auto integrator = std::make_shared(); + + model.check_constraints(); + + auto sir = simulate(t0, tmax, dt, model, integrator); + + auto dydt_default = Eigen::VectorXd(Eigen::Index(mio::osir::InfectionState::Count)); + Eigen::VectorXd y0 = sir.get_value(0); + model.get_derivatives(y0, y0, 0, dydt_default); + + EXPECT_NEAR(dydt_default[0],-2694.9104618284641,1e-12); + EXPECT_NEAR(dydt_default[1],2194.9104618284641,1e-12); + EXPECT_NEAR(dydt_default[2],500,1e-10); } \ No newline at end of file From f918c6b28ea850ed7f2afa4dc449266452a854ce Mon Sep 17 00:00:00 2001 From: Paul Johannssen Date: Mon, 11 Mar 2024 14:29:35 +0100 Subject: [PATCH 17/34] seir tests changed --- cpp/tests/test_odeseir.cpp | 177 +++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 87 deletions(-) diff --git a/cpp/tests/test_odeseir.cpp b/cpp/tests/test_odeseir.cpp index 2598e70340..f2f38f4fbd 100644 --- a/cpp/tests/test_odeseir.cpp +++ b/cpp/tests/test_odeseir.cpp @@ -52,20 +52,21 @@ TEST(TestSeir, CompareSeirWithJS) mio::oseir::Model model(1); - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 10000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 1000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = + model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Exposed}] = 10000; + model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Infected}] = 1000; + model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Recovered}] = 1000; + model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Susceptible}] = total_population - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; + 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}]; model.parameters.set(1.0); model.parameters.set(5.2); 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)); + 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.6, mio::SimulationTime(12.5)); std::vector> refData = load_test_data_csv("seir-js-compare.csv"); auto integrator = std::make_shared(); @@ -109,20 +110,22 @@ TEST(TestSeir, checkPopulationConservation) mio::oseir::Model model(1); - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 10000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 1000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = + model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Exposed}] = 10000; + model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Infected}] = 1000; + model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Recovered}] = 1000; + model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Susceptible}] = total_population - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; + 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}]; model.parameters.set(1.0); model.parameters.set(5.2); 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)); + 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.6, mio::SimulationTime(12.5)); + auto result = mio::simulate(t0, tmax, dt, model); double num_persons = 0.0; for (auto i = 0; i < result.get_last_value().size(); i++) { @@ -137,7 +140,8 @@ TEST(TestSeir, 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().setConstant(10); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(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 @@ -164,7 +168,8 @@ TEST(TestSeir, apply_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().setConstant(10); + 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); @@ -188,18 +193,19 @@ TEST(TestSeir, get_reproduction_numbers) mio::oseir::Model model(1); double total_population = 10000; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = + 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::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; + 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}]; model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(10); model.apply_constraints(); @@ -225,33 +231,12 @@ TEST(TestSeir, get_reproduction_numbers) mio::TimeSeries::Vector result_6(4); result_0[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9700; - result_0[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100; - result_0[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100; - result_0[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100; result_1[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.9611995799496071; - result_1[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.012933473350130966666666666666666666667; - result_1[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.012933473350130966666666666666666666667; - result_1[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.012933473350130966666666666666666666667; result_2[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.7865872644051706; - result_2[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.0711375785316098; - result_2[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.0711375785316098; - result_2[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.0711375785316098; result_3[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.0006179798110679; - result_3[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.33312734006297736666666666666666666666667; - result_3[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.33312734006297736666666666666666666666667; - result_3[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.33312734006297736666666666666666666666667; result_4[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9695.4591772453732119; - result_4[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 101.513607584875596033333333333333333333333333; - result_4[(Eigen::Index)mio::oseir::InfectionState::Infected] = 101.513607584875596033333333333333333333333333; - result_4[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 101.513607584875596033333333333333333333333333; result_5[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9679.4083551723888377; - result_5[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 106.863881609203720766666666666666666666667; - result_5[(Eigen::Index)mio::oseir::InfectionState::Infected] = 106.863881609203720766666666666666666666667; - result_5[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 106.863881609203720766666666666666666666667; result_6[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9660.5835936179428245; - result_6[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 113.1388021273523918333333333333333333333333; - result_6[(Eigen::Index)mio::oseir::InfectionState::Infected] = 113.1388021273523918333333333333333333333333; - result_6[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 113.1388021273523918333333333333333333333333; result.add_time_point(0, result_0); result.add_time_point(0.0010000000000000000208, result_1); @@ -267,7 +252,7 @@ TEST(TestSeir, get_reproduction_numbers) EXPECT_NEAR(reproduction_numbers[i], checkReproductionNumbers[i], 1e-12); } - model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(9); + contact_matrix[0].get_baseline().setConstant(9); auto reproduction_numbers2 = model.get_reproduction_numbers(result); @@ -275,7 +260,7 @@ TEST(TestSeir, get_reproduction_numbers) EXPECT_NEAR(reproduction_numbers2[i], checkReproductionNumbers2[i], 1e-12); } - model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(8); + contact_matrix[0].get_baseline().setConstant(8); auto reproduction_numbers3 = model.get_reproduction_numbers(result); @@ -292,18 +277,20 @@ TEST(TestSeir, get_reproduction_number) mio::oseir::Model model(1); double total_population = 10000; //Initialize compartments to get total population of 10000 - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}] = 100; - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Susceptible)}] = + 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::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Recovered)}]; + 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}]; model.parameters.set(6); model.parameters.set(0.04); - model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(10); + + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(10); model.apply_constraints(); @@ -318,37 +305,13 @@ TEST(TestSeir, get_reproduction_number) mio::TimeSeries::Vector result_7(4); result_0[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9700; - result_0[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.0; - result_0[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.0; - result_0[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.0; result_1[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.9709149074315; - result_1[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.009695030856166666666666666666666666666667; - result_1[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.009695030856166666666666666666666666666667; - result_1[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.009695030856166666666666666666666666666667; result_2[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.8404009584538; - result_2[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.0531996805154; - result_2[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.0531996805154; - result_2[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.0531996805154; result_3[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.260556488618; - result_3[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 100.24648117046066666666666666666666666667; - result_3[(Eigen::Index)mio::oseir::InfectionState::Infected] = 100.24648117046066666666666666666666666667; - result_3[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 100.24648117046066666666666666666666666667; result_4[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9696.800490904101; - result_4[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 101.06650303196633333333333333333333333333333; - result_4[(Eigen::Index)mio::oseir::InfectionState::Infected] = 101.06650303196633333333333333333333333333333; - result_4[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 101.06650303196633333333333333333333333333333; result_5[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9687.9435082620021; - result_5[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 104.018830579332633333333333333333333333333333; - result_5[(Eigen::Index)mio::oseir::InfectionState::Infected] = 104.018830579332633333333333333333333333333333; - result_5[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 104.018830579332633333333333333333333333333333; result_6[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9679.5436372291661; - result_6[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 106.8187875902779666666666666666666666666667; - result_6[(Eigen::Index)mio::oseir::InfectionState::Infected] = 106.8187875902779666666666666666666666666667; - result_6[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 106.8187875902779666666666666666666666666667; result_7[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9678.5949381732935; - result_7[(Eigen::Index)mio::oseir::InfectionState::Exposed] = 107.135020608902166666666666666666666666667; - result_7[(Eigen::Index)mio::oseir::InfectionState::Infected] = 107.135020608902166666666666666666666666667; - result_7[(Eigen::Index)mio::oseir::InfectionState::Recovered] = 107.135020608902166666666666666666666666667; result.add_time_point(0, result_0); result.add_time_point(0.001, result_1); @@ -370,13 +333,53 @@ TEST(TestSeir, get_reproduction_number) EXPECT_NEAR(model.get_reproduction_number(0.7, result).value(), 2.3242860858116172196, 1e-12); EXPECT_NEAR(model.get_reproduction_number(0.0, result).value(), 2.3280000000000002913, 1e-12); - model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(9); - + contact_matrix[0].get_baseline().setConstant(9); EXPECT_NEAR(model.get_reproduction_number(0.1, result).value(), 2.0946073086586665113, 1e-12); EXPECT_NEAR(model.get_reproduction_number(0.3, result).value(), 2.0936545545126947765, 1e-12); - - model.parameters.get().get_cont_freq_mat()[0].get_baseline().setConstant(8); + contact_matrix[0].get_baseline().setConstant(8); EXPECT_NEAR(model.get_reproduction_number(0.2, result).value(), 1.8614409729718137676, 1e-12); EXPECT_NEAR(model.get_reproduction_number(0.9, result).value(), 1.858670429549998504, 1e-12); } + +TEST(TestSeir,test_age_groups){ + double t0 = 0; + double tmax = 1; + double dt = 0.001; + + mio::oseir::Model model(1); + + double total_population = 10000; + //model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; + 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}]; + // suscetible now set with every other update + // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; + model.parameters.set(5.2); + model.parameters.set(6); + model.parameters.set(0.04); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(10); + + model.check_constraints(); + // print_seir_params(model); + + auto seir = simulate(t0, tmax, dt, model); + + const auto compare = load_test_data_csv("seir-agegrp-compare.csv"); + + ASSERT_EQ(compare.size(), static_cast(seir.get_num_time_points())); + for (size_t i = 0; i < compare.size(); i++) { + ASSERT_EQ(compare[i].size(), static_cast(seir.get_num_elements()) + 1) << "at row " << i; + EXPECT_NEAR(seir.get_time(i), compare[i][0], 1e-10) << "at row " << i; + for (size_t j = 1; j < compare[i].size(); j++) { + EXPECT_NEAR(seir.get_value(i)[j - 1], compare[i][j], 1e-9) << " at row " << i; + } + } +} From cf70d1ce3a94dabeb6e9f4f10b88035e932cb23b Mon Sep 17 00:00:00 2001 From: HenrZu Date: Wed, 27 Mar 2024 12:16:08 +0100 Subject: [PATCH 18/34] remove vscode folder --- .vscode/settings.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e5e80475e7..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "cmake.sourceDirectory": "/home/joha_pu/Documents/coding/memilio1/memilio/cpp/CMakeLists.txt" -} \ No newline at end of file From 6d3ae4fecb15b52278442fe6d67ec6d6dc9c8441 Mon Sep 17 00:00:00 2001 From: HenrZu Date: Wed, 27 Mar 2024 13:51:05 +0100 Subject: [PATCH 19/34] cleanup examples --- cpp/examples/graph.cpp | 10 +- cpp/examples/ode_seir.cpp | 19 +- cpp/examples/ode_seir_ageres.cpp | 38 +- cpp/examples/ode_seir_flows.cpp | 7 +- cpp/examples/ode_sir.cpp | 10 +- cpp/examples/ode_sir_ageres.cpp | 31 +- cpp/examples/sir_example_pre_agegroups.txt | 499 --------------------- 7 files changed, 52 insertions(+), 562 deletions(-) delete mode 100644 cpp/examples/sir_example_pre_agegroups.txt diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index bf45c36359..6ecbf8a5d3 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -32,18 +32,26 @@ int main() const auto dt = 0.5; //time step of migration, daily migration every second step mio::oseir::Model model(1); + + // set population model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 10000; + + // set transition times model.parameters.set(1); + model.parameters.set(1); + + // set contact matrix mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(2.7); - model.parameters.set(1); //two mostly identical groups 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)); + //infection starts in group 1 model_group1.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}] = 9990; model_group1.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] = 10; diff --git a/cpp/examples/ode_seir.cpp b/cpp/examples/ode_seir.cpp index b5e4b5d008..4af8579b27 100644 --- a/cpp/examples/ode_seir.cpp +++ b/cpp/examples/ode_seir.cpp @@ -23,6 +23,8 @@ #include "memilio/compartments/simulation.h" #include "memilio/utils/logging.h" +#include "memilio/utils/time_series.h" + int main() { mio::set_log_level(mio::LogLevel::debug); @@ -35,23 +37,22 @@ int main() mio::oseir::Model model(1); - double total_population = 10000; - //model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; + double 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}] - + 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}]; - // suscetible now set with every other update - // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; + model.parameters.set(5.2); model.parameters.set(6); - model.parameters.set(0.04); - mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(10); + model.parameters.set(0.1); + + mio::ContactMatrixGroup& contact_matrix = model.parameters.get(); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 2.7)); + contact_matrix.add_damping(Eigen::MatrixXd::Constant(1, 1, 0.7), mio::SimulationTime(30.)); model.check_constraints(); diff --git a/cpp/examples/ode_seir_ageres.cpp b/cpp/examples/ode_seir_ageres.cpp index d0a9ee7738..520555516d 100644 --- a/cpp/examples/ode_seir_ageres.cpp +++ b/cpp/examples/ode_seir_ageres.cpp @@ -14,42 +14,31 @@ int main() mio::log_info("Simulating SEIR; t={} ... {} with dt = {}.", t0, tmax, dt); - double cont_freq = 10; // see Polymod study + double cont_freq = 10; double nb_total_t0 = 10000, nb_exp_t0 = 100, nb_inf_t0 = 50, nb_rec_t0 = 10; + const size_t num_groups = 3; - // alpha = alpha_in; // percentage of asymptomatic cases - // beta = beta_in; // risk of infection from the infected symptomatic patients - // rho = rho_in; // hospitalized per infected - // theta = theta_in; // icu per hospitalized - // delta = delta_in; // deaths per ICUs - - mio::oseir::Model model(3); - - auto nb_groups = model.parameters.get_num_groups(); - - double fact = 1.0 / (double)(size_t)nb_groups; + mio::oseir::Model model(num_groups); + double fact = 1.0 / num_groups; auto& params = model.parameters; - for (auto i = mio::AgeGroup(0); i < nb_groups; i++) { - model.populations[{i, mio::oseir::InfectionState::Exposed}] = fact*nb_exp_t0; - model.populations[{i, mio::oseir::InfectionState::Infected}] = fact*nb_inf_t0; - model.populations[{i, mio::oseir::InfectionState::Recovered}] = fact*nb_rec_t0; + for (auto i = mio::AgeGroup(0); i < mio::AgeGroup(num_groups); i++) { + model.populations[{i, mio::oseir::InfectionState::Exposed}] = fact * nb_exp_t0; + model.populations[{i, mio::oseir::InfectionState::Infected}] = fact * nb_inf_t0; + model.populations[{i, mio::oseir::InfectionState::Recovered}] = fact * nb_rec_t0; model.populations.set_difference_from_group_total({i, mio::oseir::InfectionState::Susceptible}, fact * nb_total_t0); - model.parameters.get()[i] = 5.2; - model.parameters.get()[i] = 6; + model.parameters.get()[i] = 5.2; + model.parameters.get()[i] = 6; model.parameters.get()[i] = 0.04; - } mio::ContactMatrixGroup& contact_matrix = params.get(); - contact_matrix[0] = - mio::ContactMatrix(Eigen::MatrixXd::Constant((size_t)nb_groups, (size_t)nb_groups, fact * cont_freq)); - contact_matrix.add_damping(Eigen::MatrixXd::Constant((size_t)nb_groups, (size_t)nb_groups, 0.7), - mio::SimulationTime(30.)); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(num_groups, num_groups, fact * cont_freq)); + contact_matrix.add_damping(Eigen::MatrixXd::Constant(num_groups, num_groups, 0.7), mio::SimulationTime(30.)); model.apply_constraints(); @@ -69,6 +58,5 @@ int main() } printf("\t %s_otal: %.0f\n", vars[k].c_str(), dummy); - -} + } } diff --git a/cpp/examples/ode_seir_flows.cpp b/cpp/examples/ode_seir_flows.cpp index 188cb60202..c4df2330fa 100644 --- a/cpp/examples/ode_seir_flows.cpp +++ b/cpp/examples/ode_seir_flows.cpp @@ -40,13 +40,12 @@ int main() mio::oseir::Model model(1); - double total_population = 10000; + double 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}] - + 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}]; // suscetible now set with every other update @@ -54,10 +53,12 @@ int main() model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(10); model.check_constraints(); + auto seir = simulate_flows(t0, tmax, dt, model); printf("Compartments: \n"); diff --git a/cpp/examples/ode_sir.cpp b/cpp/examples/ode_sir.cpp index 48e3da0076..abf14ea8bb 100644 --- a/cpp/examples/ode_sir.cpp +++ b/cpp/examples/ode_sir.cpp @@ -43,20 +43,18 @@ int main() model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] = 1000; model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}] = 1000; model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Susceptible}] = - total_population - - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] - + total_population - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}]; model.parameters.set(2); model.parameters.set(1); + 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.6, mio::SimulationTime(12.5)); - - auto integrator = std::make_shared(); - model.check_constraints(); - auto sir = simulate(t0, tmax, dt, model, integrator); + auto integrator = std::make_shared(); + auto sir = simulate(t0, tmax, dt, model, integrator); bool print_to_terminal = true; diff --git a/cpp/examples/ode_sir_ageres.cpp b/cpp/examples/ode_sir_ageres.cpp index e85414e138..60e6b88e24 100644 --- a/cpp/examples/ode_sir_ageres.cpp +++ b/cpp/examples/ode_sir_ageres.cpp @@ -1,9 +1,11 @@ +#include "memilio/epidemiology/age_group.h" #include "memilio/utils/time_series.h" #include "memilio/utils/logging.h" #include "memilio/compartments/simulation.h" #include "ode_sir/model.h" -int main(){ +int main() +{ mio::set_log_level(mio::LogLevel::debug); double t0 = 0; @@ -16,35 +18,26 @@ int main(){ double nb_total_t0 = 10000, nb_inf_t0 = 50, nb_rec_t0 = 10; - // alpha = alpha_in; // percentage of asymptomatic cases - // beta = beta_in; // risk of infection from the infected symptomatic patients - // rho = rho_in; // hospitalized per infected - // theta = theta_in; // icu per hospitalized - // delta = delta_in; // deaths per ICUs + const size_t num_groups = 3; + mio::osir::Model model(num_groups); - mio::osir::Model model(3); - auto nb_groups = model.parameters.get_num_groups(); - - double fact = 1.0 / (double)(size_t)nb_groups; + double fact = 1.0 / num_groups; auto& params = model.parameters; - for (auto i = mio::AgeGroup(0); i < nb_groups; i++) { - model.populations[{i, mio::osir::InfectionState::Infected}] = fact*nb_inf_t0; - model.populations[{i, mio::osir::InfectionState::Recovered}] = fact*nb_rec_t0; + for (auto i = mio::AgeGroup(0); i < mio::AgeGroup(num_groups); i++) { + model.populations[{i, mio::osir::InfectionState::Infected}] = fact * nb_inf_t0; + model.populations[{i, mio::osir::InfectionState::Recovered}] = fact * nb_rec_t0; model.populations.set_difference_from_group_total({i, mio::osir::InfectionState::Susceptible}, fact * nb_total_t0); - model.parameters.get()[i] = 2.0; + model.parameters.get()[i] = 2.0; model.parameters.get()[i] = 0.3; - } mio::ContactMatrixGroup& contact_matrix = params.get(); - contact_matrix[0] = - mio::ContactMatrix(Eigen::MatrixXd::Constant((size_t)nb_groups, (size_t)nb_groups, fact * cont_freq)); - contact_matrix.add_damping(Eigen::MatrixXd::Constant((size_t)nb_groups, (size_t)nb_groups, 0.7), - mio::SimulationTime(30.)); + contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(num_groups, num_groups, fact * cont_freq)); + contact_matrix.add_damping(Eigen::MatrixXd::Constant(num_groups, num_groups, 0.7), mio::SimulationTime(30.)); model.apply_constraints(); diff --git a/cpp/examples/sir_example_pre_agegroups.txt b/cpp/examples/sir_example_pre_agegroups.txt deleted file mode 100644 index e6556bbae0..0000000000 --- a/cpp/examples/sir_example_pre_agegroups.txt +++ /dev/null @@ -1,499 +0,0 @@ -0.00000000000000 1059000.00000000000000 1000.00000000000000 1000.00000000000000 -0.10020040080160 1058729.96889160037972 1219.93090799884408 1050.10020040080167 -0.20040080160321 1058400.63359394157305 1488.14742269180306 1111.21898336667573 -0.30060120240481 1057999.01493035070598 1815.20960217982019 1185.77546746947155 -0.40080160320641 1057509.31518007768318 2213.96698761413700 1276.71783230813980 -0.50100200400802 1056912.31676053931005 2700.04521739217944 1387.63802206836704 -0.60120240480962 1056184.65787779795937 3292.43129365104414 1522.91082855094123 -0.70140280561122 1055297.96256138081662 4014.17514245041275 1687.86229616872902 -0.80160320641283 1054217.79966321703978 4893.22706153360286 1888.97327524941102 -0.90180360721443 1052902.44292916753329 5963.43213919364280 2134.12493163886984 -1.00200400801603 1051301.40266555664130 7265.70325755438716 2432.89407688905249 -1.10220440881764 1049353.69963742210530 8849.39309643268098 2796.90726614528421 -1.20240480961924 1046985.85488663148135 10773.88147966651013 3240.26363370203171 -1.30260521042084 1044109.57696973485872 13110.38577533738135 3780.03725492780859 -1.40280561122244 1040619.14329997752793 15943.98649041852150 4436.87020960402970 -1.50300601202405 1036388.49846472707577 19375.83440731135124 5235.66712796167121 -1.60320641282565 1031268.13443739665672 23525.46524790269177 6206.40031470071699 -1.70340681362725 1025081.88170794758480 28533.08745390980039 7385.03083814273577 -1.80360721442886 1017623.83388363581616 34561.62187872713548 8814.54423763721388 -1.90380761523046 1008655.75905008928385 41798.15252997267817 10546.08841993817259 -2.00400801603206 997905.52553679223638 50454.29022513484233 12640.18423807307590 -2.10420841683367 985067.28916704165749 60764.75654352594574 15167.95428943253683 -2.20440881763527 969804.44398430001456 72983.27524613103014 18212.28076956910809 -2.30460921843687 951756.59875476337038 87374.64375992969144 21868.75748530713463 -2.40480961923848 930552.04420189023949 104201.71115048164211 26246.24464762826028 -2.50501002004008 905827.21175045368727 123706.01699117259705 31466.77125837383210 -2.60521042084168 877254.33117221482098 146081.20132736873347 37664.46750041654741 -2.70541082164328 844577.66873030539136 171439.16630798709230 44983.16496170756727 -2.80561122244489 807657.17677508865017 199770.52167462737998 53572.30155028407171 -2.90581162324649 766516.03889572352637 230903.11638392097666 63580.84472035558429 -3.00601202404809 721385.67035694385413 264465.19251869659638 75149.13712435963680 -3.10621242484970 672738.91591344983317 299862.18781796738040 88398.89626858291740 -3.20641282565130 621300.67652029450983 336277.27150881977286 103422.05197088589193 -3.30661322645290 568026.44663031317759 372703.94270597450668 120269.61066371253401 -3.40681362725451 514044.27117714169435 408013.57593940774677 138942.15288345073350 -3.50701402805611 460564.07691111566965 441052.20828462176723 159383.71480426273774 -3.60721442885771 408767.87672741338611 470751.60444604844088 181480.51882653837674 -3.70741482965932 359701.22681102331262 496233.50464069261216 205065.26854828427895 -3.80761523046092 314187.13915495952824 516886.19426866556751 229926.66657637507888 -3.90781563126252 272777.52581479097717 532399.70569156634156 255822.76849364288501 -4.00801603206413 235746.62886062962934 542757.27069725247566 282496.10044211812783 -4.10821643286573 203120.24210856959689 548191.40941838803701 309688.34847304259893 -4.20841683366733 174727.76593399303965 549119.38612310541794 337152.84794290171703 -4.30861723446894 150262.69161622395040 546073.46915214171167 364663.83923163445434 -4.40881763527054 129339.87830850327737 539637.89222177909687 392022.22946971771307 -4.50901803607214 111542.63555356080178 530399.16843254421838 419058.19601389503805 -4.60921843687375 96457.07073075458175 518911.62862446147483 445631.30064478400163 -4.70941883767535 83694.28991028707242 505676.83286053710617 471628.87722917587962 -4.80961923847695 72902.66789944795892 491133.94420702068601 496963.38789353147149 -4.90981963927856 63772.86899556950084 475657.83408249128843 521569.29692193929804 -5.01002004008016 56038.08039885869948 459562.06986945803510 545399.84973168338183 -5.11022044088176 49471.40928160546900 443104.58918964420445 568424.00152875040658 -5.21042084168337 43881.83966988739849 426494.53008444624720 590623.63024566648528 -5.31062124248497 39109.66720139017707 409899.24112586700357 611991.09167274297215 -5.41082164328657 35021.96664970767597 393450.90755300706951 632527.12579728534911 -5.51102204408818 31508.39414002569902 377252.51074640610022 652239.09511356824078 -5.61122244488978 28477.46176093551912 361383.01673539576586 671139.52150366874412 -5.71142284569139 25853.32264308047525 345901.79429336125031 689244.88306355825625 -5.81162324649299 23573.04872438028906 330852.31899896718096 706574.63227665249724 -5.91182364729459 21584.35558332820074 316265.24465510109439 723150.39976157073397 -6.01202404809620 19843.71784715210015 302160.93025424808729 738995.35189859988168 -6.11222444889780 18314.81745826164843 288551.50748410809319 754133.67505763028748 -6.21242484969940 16967.27089439218616 275442.56569707032759 768590.16340853751171 -6.31262525050101 15775.58749973508202 262834.52135139325401 782389.89114887174219 -6.41282565130261 14718.31779805738915 250723.72886111738626 795557.95334082527552 -6.51302605210421 13777.35716742684235 239103.38043056969764 808119.26240200351458 -6.61322645290582 12937.37614839028174 227964.23417352561955 820098.38967808417510 -6.71342685370742 12185.35377906321082 217295.20272654379369 831519.44349439302459 -6.81362725450902 11510.19468771994616 207083.82861515440163 842405.97669712570496 -6.91382765531063 10902.41428271531731 197316.66770677454770 852780.91801051015500 -7.01402805611223 10353.87934745316670 187979.59804750891635 862666.52260503789876 -7.11422845691383 9857.59376870755477 179058.06809281220194 872084.33813848020509 -7.21442885771544 9407.52108989800399 170537.29567679148749 881055.18323331046849 -7.31462925851704 8998.43716754125671 162402.42690993021824 889599.13592252845410 -7.41482965931865 8625.80748849474730 154638.66245521267410 897735.53005629254039 -7.51503006012025 8285.68473610345609 147231.35722888589953 905482.95803501061164 -7.61523046092185 7974.62302313733835 140166.09843940282008 912859.27853745978791 -7.71543086172346 7689.60587778809804 133428.76596353948116 919881.62815867236350 -7.81563126252506 7427.98560782763343 127005.57831949496176 926566.43607267737389 -7.91583166332666 7187.43210296193683 120883.12689853426127 932929.44099850382190 -8.01603206412827 6965.88948701961363 115048.40063178449054 938985.70988119591493 -8.11623246492987 6761.53931636347625 109488.80287499651604 944749.65780864004046 -8.21643286573147 6572.76925197264791 104192.16197370615555 950235.06877432123292 -8.31663326653307 6398.14632053042442 99146.73671007291705 955455.11696939670946 -8.41683366733468 6236.39403297508670 94341.21761936809344 960422.38834765693173 -8.51703406813628 6086.37275404705269 89764.72498951015586 965148.90225644293241 -8.61723446893788 5947.06281877435504 85406.80421388555260 969646.13296734017786 -8.71743486973948 5817.54997588886727 81257.41905006334127 973925.03097404784057 -8.81763527054109 5697.01280731648967 77306.94324017563486 977996.04395250789821 -8.91783567134269 5584.71182991577098 73546.15086887015786 981869.13730121403933 -9.01803607214429 5479.98003279034128 69966.20576875760162 985553.81419845204800 -9.11823647294590 5382.21464257788921 66558.65022867158405 989059.13512875058223 -9.21843687374750 5290.86994158328616 63315.39321480288345 992393.73684361390769 -9.31863727454910 5205.45099065983140 60228.69827720915782 995565.85073213104624 -9.41883767535070 5125.50813131193900 57291.17128298946045 998583.32058569858782 -9.51903807615231 5050.63216037751226 54495.74809144946630 1001453.61974817304872 -9.61923847695391 4980.45008648711428 51835.68226496664283 1004183.86764854623470 -9.71943887775551 4914.62139081177520 49304.53289125487208 1006780.84571793337818 -9.81963927855711 4852.83472582953618 46896.15257771733013 1009251.01269645313732 -9.91983967935872 4794.80499531386249 44604.67566606279433 1011600.51933862338774 -10.02004008016032 4740.27076676396518 42424.50670493018697 1013835.22252830583602 -10.12024048096192 4688.99197429637570 40350.30920957562194 1015960.69881612795871 -10.22044088176352 4640.74787579598069 38376.99473044196930 1017982.25739376200363 -10.32064128256513 4595.33523304660139 36499.71224641570006 1019904.95252053765580 -10.42084168336673 4552.56668776173865 34713.83789358354261 1021733.59541865473147 -10.52104208416833 4512.26931002828314 33014.96503616752307 1023472.76565380417742 -10.62124248496993 4474.28329875391955 31398.89468290443619 1025126.82201834162697 -10.72144288577154 4438.46081635146675 29861.62624932971448 1026699.91293431876693 -10.82164328657314 4404.66494216629235 28399.34866412963311 1028195.98639370407909 -10.92184368737474 4372.76873111163150 27008.43181585916318 1029618.79945302917622 -11.02204408817635 4342.65436566764038 25685.41833481722279 1030971.92729951511137 -11.12224448897795 4314.21239086248170 24427.01570366961460 1032258.77190546784550 -11.22244488977955 4287.34102312082268 23230.08868946389703 1033482.57028741517570 -11.32264529058115 4261.94552496480264 22091.65208894938041 1034646.40238608571235 -11.42284569138276 4237.93763850849155 21008.86377856454055 1035753.19858292688150 -11.52304609218436 4215.23507151932154 19979.01806005448452 1036805.74686842609663 -11.62324649298596 4193.77790810559327 18999.52241484824845 1037806.69967704603914 -11.72344689378756 4173.91181482437514 18067.50862762604811 1038758.57955754944123 -11.82364729458917 4156.04662311202719 17180.18801635111959 1039663.76536053675227 -11.92384769539077 4140.42845786313228 16335.07531905737414 1040524.49622307938989 -12.02404809619237 4127.13038021540888 15529.98284965813400 1041342.88677012640983 -12.12424849699397 4116.06020558210093 14762.99777130255825 1042120.94202311534900 -12.22444889779558 4106.98283038177124 14032.44599964404188 1042860.57116997416597 -12.32464929859718 4099.55353669199394 13336.84693663822509 1043563.59952666971367 -12.42484969939878 4093.35822928030166 12674.86353980952481 1044231.77823091007303 -12.52505010020039 4087.95636339231714 12045.25220230023842 1044866.79143430734985 -12.62525050100199 4082.93409429047688 11446.80492218863947 1045470.26098352076951 -12.72545090180359 4078.16721141119388 10878.08458451738989 1046043.74820407130755 -12.82565130260519 4073.64245410151534 10337.61512416587721 1046588.74242173251696 -12.92585170340680 4069.34727678444187 9823.99371209588207 1047106.65901111962739 -13.02605210420840 4065.26980785749993 9335.88712731060514 1047598.84306483180262 -13.12625250501000 4061.39881119181427 8872.02830797876595 1048066.57288082933519 -13.22645290581160 4057.72365004570338 8431.21307293355676 1048511.06327702070121 -13.32665330661321 4054.23425322195362 8012.29700518147729 1048933.46874159644358 -13.42685370741481 4050.92108331166855 7614.19248946142761 1049334.88642722670920 -13.52705410821641 4047.77510688010716 7235.86589628069305 1049716.35899683902971 -13.62725450901801 4044.78776646130336 6876.33490522250850 1050078.87732831598260 -13.72745490981962 4041.95095423865314 6534.66596067048431 1050423.38308509066701 -13.82765531062122 4039.25698729811893 6209.97185342913053 1050750.77115927264094 -13.92785571142282 4036.69858434934849 5901.40942203776376 1051061.89199361274950 -14.02805611222442 4034.26884381792070 5608.17736787792091 1051357.55378830409609 -14.12825651302603 4031.96122321914527 5329.51417846277218 1051638.52459831791930 -14.22845691382763 4029.76951973048563 5064.69615357153361 1051905.53432669793256 -14.32865731462923 4027.68785188572292 4813.03552915319324 1052159.27661896101199 -14.42885771543084 4025.71064231956143 4573.87869417260208 1052400.41066350787878 -14.52905811623244 4023.83260149647549 4346.60449580868408 1052629.56290269480087 -14.62925851703404 4022.04871236230429 4130.62262863981505 1052847.32865899777971 -14.72945891783564 4020.35421586140819 3925.37210366577028 1053054.27368047274649 -14.82965931863725 4018.74459726619125 3730.31979321961580 1053250.93560951412655 -14.92985971943885 4017.21557326944367 3544.95904801698407 1053437.82537871343084 -15.03006012024045 4015.76307979334524 3368.80838277479643 1053615.42853743163869 -15.13026052104205 4014.38326047208602 3201.41022700713802 1053784.20651252055541 -15.23046092184366 4013.07245576793503 3042.32973777305551 1053944.59780645882711 -15.33066132264526 4011.82719268325627 2891.15367130998584 1054097.01913600647822 -15.43086172344686 4010.64417503342975 2747.48931063766895 1054241.86651432863437 -15.53106212424846 4009.52027424791459 2610.96344636117692 1054379.51627939054742 -15.63126252505007 4008.45252066880676 2481.22140803842240 1054510.32607129239477 -15.73146292585167 4007.43809531820170 2357.92614360754351 1054634.63576107379049 -15.83166332665327 4006.47432210748730 2240.75734449323045 1054752.76833339873701 -15.93186372745487 4005.55866046338770 2129.41061412865110 1054865.03072540741414 -16.03206412825648 4004.68869834714087 2023.59667774145873 1054971.71462391084060 -16.13226452905808 4003.86214564465854 1923.04063135869796 1055073.09722299617715 -16.23246492985969 4003.07682790687295 1827.48122808652874 1055169.44194400613196 -16.33266533066129 4002.33068042074183 1736.67019981682165 1055260.99911976186559 -16.43286573146290 4001.62174259255971 1650.37161260408084 1055348.00664480286650 -16.53306613226450 4000.94815262632937 1568.36125404305290 1055430.69059333018959 -16.63326653306611 4000.30814248097022 1490.42605106000246 1055509.26580645865761 -16.73346693386771 3999.70003309110234 1416.36351660918899 1055583.93645029934123 -16.83366733466931 3999.12222983703623 1345.98122384075077 1055654.89654632192105 -16.93386773547092 3998.57321825044528 1279.09630637720375 1055722.33047537202947 -17.03406813627252 3998.05155994297411 1215.53498340325177 1055786.41345665347762 -17.13426853707413 3997.55588874577415 1155.13210833776361 1055847.31200291612186 -17.23446893787573 3997.08490704864562 1097.73073991776982 1055905.18435303331353 -17.33466933867734 3996.63738232810829 1043.18173458230672 1055960.18088308931328 -17.43486973947894 3996.21214385433177 991.34335909905360 1056012.44449704629369 -17.53507014028055 3995.80807956741774 942.08092242910129 1056062.11099800304510 -17.63527054108215 3995.42413311406199 895.26642587498702 1056109.30944101046771 -17.73547094188375 3995.05930103612764 850.77823060447497 1056154.16246835887432 -17.83567134268536 3994.71263010312487 808.50074168755395 1056196.78662820882164 -17.93587174348696 3994.38321478103808 768.32410782689772 1056237.29267739155330 -18.03607214428857 3994.07019483035447 730.14393600268670 1056275.78586916648783 -18.13627254509017 3993.77275302654471 693.86102029133156 1056312.36622668174095 -18.23647294589178 3993.49011299660697 659.38108415436898 1056347.12880284874700 -18.33667334669338 3993.22153716563389 626.61453552871012 1056380.16392730548978 -18.43687374749499 3992.96632480769676 595.47623408260358 1056411.55744110955857 -18.53707414829659 3992.72381019563500 565.88527003321235 1056441.39091977104545 -18.63727454909819 3992.49336084464085 537.76475395168086 1056469.74188520363532 -18.73747494989980 3992.27437584479776 511.04161701005677 1056496.68400714499876 -18.83767535070140 3992.06628427798978 485.64642115151128 1056522.28729457035661 -18.93787575150301 3991.86854371483923 461.51317869103889 1056546.61827759398147 -19.03807615230461 3991.68063878756993 438.57918087827602 1056569.74018033407629 -19.13827655310622 3991.50207983489736 416.78483497732736 1056591.71308518759906 -19.23847695390782 3991.33240161526237 396.07350944058339 1056612.59408894390799 -19.33867735470943 3991.17116208491188 376.39138677451177 1056632.43745114025660 -19.43887775551103 3991.01794123752097 357.68732371536402 1056651.29473504680209 -19.53907815631263 3990.87234000221270 339.91271835170596 1056669.21494164573960 -19.63927855711424 3990.73397919700756 323.02138384870938 1056686.24463695404120 -19.73947895791584 3990.60249853487903 306.96942844627347 1056702.42807301855646 -19.83967935871745 3990.47755567974536 291.71514141932931 1056717.80730290059000 -19.93987975951905 3990.35882534986376 277.21888470415445 1056732.42228994565085 -20.04008016032066 3990.24599846622050 263.44298990923278 1056746.31101162428968 -20.14028056112226 3990.13878134364222 250.35166044317211 1056759.50955821294338 -20.24048096192386 3990.03689492246303 237.91087850547484 1056772.05222657183185 -20.34068136272547 3989.94007403869955 226.08831669858313 1056783.97160926251672 -20.44088176352707 3989.84806673078765 214.85325403161627 1056795.29867923748679 -20.54108216432868 3989.76063358103420 204.17649609762148 1056806.06287032132968 -20.64128256513028 3989.67754709003657 194.03029921699493 1056816.29215369303711 -20.74148296593189 3989.59859108240380 184.38829835002863 1056826.01311056758277 -20.84168336673349 3989.52356014220732 175.22543859132594 1056835.25100126652978 -20.94188376753510 3989.45225907666008 166.51791006812928 1056844.02983085531741 -21.04208416833670 3989.38450240660950 158.24308607344389 1056852.37241151998751 -21.14228456913830 3989.32011388249157 150.37946427324104 1056860.30042184423655 -21.24248496993991 3989.25892602446993 142.90661083500822 1056867.83446314046159 -21.34268537074151 3989.20077968554415 135.80510733250071 1056874.99411298194900 -21.44288577154312 3989.14552363647499 129.05650028875903 1056881.79797607474029 -21.54308617234472 3989.09301417143206 122.64325322630899 1056888.26373260212131 -21.64328657314633 3989.04311473332336 116.54870109997317 1056894.40818416653201 -21.74348697394793 3988.99569555782364 110.75700699391095 1056900.24729744810611 -21.84368737474954 3988.95063333516100 105.25312097038548 1056905.79624569439329 -21.94388777555114 3988.90781088877520 100.02274096334503 1056911.06944814790040 -22.04408817635274 3988.86711687000161 95.05227561521770 1056916.08060751482844 -22.14428857715435 3988.82844546797878 90.32880896036596 1056920.84274557163008 -22.24448897795595 3988.79169613402019 85.84006686344472 1056925.36823700251989 -22.34468937875756 3988.75677331972292 81.57438512546500 1056929.66884155478328 -22.44488977955916 3988.72358622813226 77.52067917469780 1056933.75573459709994 -22.54509018036077 3988.69204857730165 73.66841526366962 1056937.63953615888022 -22.64529058116237 3988.66207837563843 70.00758309741366 1056941.33033852674998 -22.74549098196398 3988.63359770843681 66.52866982185910 1056944.83773246943019 -22.84569138276558 3988.60653253504825 63.22263530477395 1056948.17083215992898 -22.94589178356718 3988.58081249615088 60.08088864503529 1056951.33829885860905 -23.04609218436879 3988.55637073062007 57.09526584919175 1056954.34836341999471 -23.14629258517039 3988.53314370151475 54.25800861731541 1056957.20884768106043 -23.24649298597200 3988.51107103073173 51.56174418302270 1056959.92718478618190 -23.34669338677360 3988.49009534188781 48.99946615528233 1056962.51043850276619 -23.44689378757521 3988.47016211102709 46.56451631223102 1056964.96532157668844 -23.54709418837681 3988.45121952475756 44.25056729969132 1056967.29821317549795 -23.64729458917841 3988.43321834544895 42.05160618943629 1056969.51517546502873 -23.74749498998002 3988.41611178313951 39.96191885447944 1056971.62196936225519 -23.84769539078162 3988.39985537381790 37.97607512079124 1056973.62406950537115 -23.94789579158323 3988.38440686376089 36.08891465686067 1056975.52667847927660 -24.04809619238483 3988.36972609962777 34.29553356443753 1056977.33474033582024 -24.14829659318644 3988.35577492402172 32.59127163561281 1056979.05295344023034 -24.24849699398804 3988.34251707624753 30.97170024312592 1056980.68578268052079 -24.34869739478965 3988.32991809800660 29.43261083243271 1056982.23747106944211 -24.44889779559125 3988.31794524378347 27.97000398563197 1056983.71205077040941 -24.54909819639285 3988.30656739569031 26.58007902883361 1056985.11335357534699 -24.64929859719446 3988.29575498254599 25.25922415596408 1056986.44502086145803 -24.74949899799606 3988.28547990298148 24.00400704334624 1056987.71051305369474 -24.84969939879767 3988.27571545236788 22.81116593066615 1056988.91311861691065 -24.94989979959927 3988.26643625338056 21.67760114515109 1056990.05596260144375 -25.05010020040088 3988.25761819001627 20.60036704693470 1056991.14201476308517 -25.15030060120248 3988.24923834488982 19.57666437467959 1056992.17409728048369 -25.25050100200409 3988.24127493965125 18.60383297156768 1056993.15489208884537 -25.35070140280569 3988.23370727836345 17.67934487275696 1056994.08694784902036 -25.45090180360729 3988.22651569369782 16.80079773634258 1056994.97268657013774 -25.55110220440890 3988.21968149580380 15.96590860075269 1056995.81440990371630 -25.65130260521050 3988.21318692372006 15.17250795235772 1056996.61430512415245 -25.75150300601211 3988.20701509920400 14.41853408787778 1056997.37445081304759 -25.85170340681371 3988.20114998285453 13.70202775693893 1056998.09682226041332 -25.95190380761532 3988.19557633241629 13.02112707085704 1056998.78329659695737 -26.05210420841692 3988.19027966315934 12.37406266441964 1056999.43565767258406 -26.15230460921853 3988.18524621022561 11.75915309809365 1057000.05560069181956 -26.25250501002013 3988.18046289284939 11.17480048871150 1057000.64473661850207 -26.35270541082173 3988.17591728035541 10.61948635728213 1057001.20459636230953 -26.45290581162334 3988.17159755984721 10.09176768313698 1057001.73663475690410 -26.55310621242494 3988.16749250550265 9.59027315415804 1057002.24223434017040 -26.65330661322655 3988.16359144939543 9.11369960334367 1057002.72270894702524 -26.75350701402815 3988.15988425376599 8.66080862245285 1057003.17930712364614 -26.85370741482976 3988.15636128467304 8.23042334392814 1057003.61321537126787 -26.95390781563136 3988.15301338695190 7.82142538273511 1057004.02556123025715 -27.05410821643297 3988.14983186042036 7.43275193017163 1057004.41741620935500 -27.15430861723457 3988.14680843726592 7.06339299209504 1057004.78979857056402 -27.25450901803617 3988.14393526055665 6.71238876439074 1057005.14367597503588 -27.35470941883778 3988.14120486382126 6.37882713886219 1057005.47996799740940 -27.45490981963938 3988.13861015164275 6.06184133306142 1057005.79954851535149 -27.55511022044099 3988.13614438121931 5.76060763790083 1057006.10324798082002 -27.65531062124259 3988.13380114483743 5.47434327719362 1057006.39185557793826 -27.75551102204420 3988.13157435322046 5.20230437356059 1057006.66612127330154 -27.85571142284580 3988.12945821970197 4.94378401541774 1057006.92675776500255 -27.95591182364740 3988.12744724518734 4.69811042002160 1057007.17444233479910 -28.05611222444901 3988.12553620386188 4.46464518779882 1057007.40981860831380 -28.15631262525061 3988.12372012960941 4.24278164342402 1057007.63349822699092 -28.25651302605222 3988.12199430310602 4.03194325933482 1057007.84606243763119 -28.35671342685382 3988.12035423955558 3.83158215758774 1057008.04806360299699 -28.45691382765543 3988.11879567703409 3.64117768616182 1057008.24002663698047 -28.55711422845703 3988.11731456541384 3.46023506601042 1057008.42245036875829 -28.65731462925864 3988.11590705583785 3.28828410534555 1057008.59580883895978 -28.75751503006024 3988.11456949071726 3.12487797781371 1057008.76055253157392 -28.85771543086184 3988.11329839422615 2.96959206138824 1057008.91710954438895 -28.95791583166345 3988.11209046326940 2.82202283496099 1057009.06588670169003 -29.05811623246505 3988.11094255889702 2.68178682976605 1057009.20727061131038 -29.15831663326666 3988.10985169814876 2.54851963291075 1057009.34162866882980 -29.25851703406826 3988.10881504630061 2.42187494042461 1057009.46931001311168 -29.35871743486987 3988.10782990949883 2.30152365736532 1057009.59064643294550 -29.45891783567147 3988.10689372775914 2.18715304264369 1057009.70595322945155 -29.55911823647308 3988.10600406831418 2.07846589634493 1057009.81553003517911 -29.65931863727468 3988.10515861929116 1.97517978743485 1057009.91966159315780 -29.75951903807628 3988.10435518370423 1.87702631984380 1057010.01861849636771 -29.85971943887789 3988.10359167374463 1.78375043502148 1057010.11265789112076 -29.95991983967949 3988.10286610535650 1.69510974915011 1057010.20202414528467 -30.06012024048110 3988.10217659307909 1.61087392329376 1057010.28694948344491 -30.16032064128270 3988.10152134514829 1.53082406484702 1057010.36765458993614 -30.26052104208431 3988.10089865884038 1.45475215872782 1057010.44434918230399 -30.36072144288591 3988.10030691604652 1.38246052683612 1057010.51723255706020 -30.46092184368752 3988.09974457906810 1.31376131437396 1057010.58649410656653 -30.56112224448912 3988.09921018662089 1.24847600169203 1057010.65231381170452 -30.66132264529072 3988.09870235003837 1.18643494039424 1057010.71486270963214 -30.76152304609233 3988.09821974966144 1.12747691249478 1057010.77430333802477 -30.86172344689393 3988.09776113141061 1.07144871148224 1057010.83079015719704 -30.96192384769554 3988.09732530352630 1.01820474420203 1057010.88446995243430 -31.06212424849714 3988.09691113347208 0.96760665252265 1057010.93548221420497 -31.16232464929875 3988.09651754499146 0.91952295380259 1057010.98395950137638 -31.26252505010035 3988.09614351531172 0.87382869922376 1057011.03002778557129 -31.36272545090196 3988.09578807248499 0.83040514910340 1057011.07380677852780 -31.46292585170356 3988.09545029286346 0.78913946434088 1057011.11541024292819 -31.56312625250516 3988.09512929869925 0.74992441319761 1057011.15494628832676 -31.66332665330677 3988.09482425586202 0.71265809264796 1057011.19251765171066 -31.76352705410837 3988.09453437167394 0.67724366357729 1057011.22822196502239 -31.86372745490998 3988.09425889284694 0.64358909913886 1057011.26215200824663 -31.96392785571158 3988.09399710352727 0.61160694561574 1057011.29439595108852 -32.06412825651319 3988.09374832343474 0.58121409516633 1057011.32503758161329 -32.16432865731479 3988.09351190609459 0.55233156986291 1057011.35415652417578 -32.26452905811639 3988.09328723715771 0.52488431646204 1057011.38182844640687 -32.36472945891800 3988.09307373280399 0.49880101137358 1057011.40812525595538 -32.46492985971960 3988.09287083822619 0.47401387532143 1057011.43311528651975 -32.56513026052121 3988.09267802618706 0.45045849721435 1057011.45686347666197 -32.66533066132281 3988.09249479564915 0.42807366676939 1057011.47943153767847 -32.76553106212442 3988.09232067047424 0.40680121545269 1057011.50087811425328 -32.86573146292602 3988.09215519818508 0.38658586532454 1057011.52125893672928 -32.96593186372763 3988.09199794878896 0.36737508539585 1057011.54062696616165 -33.06613226452923 3988.09184851366126 0.34911895512275 1057011.55903253145516 -33.16633266533083 3988.09170650448414 0.33177003468463 1057011.57652346114628 -33.26653306613244 3988.09157155223556 0.31528324170843 1057011.59314520633779 -33.36673346693404 3988.09144330623212 0.29961573411905 1057011.60894095990807 -33.46693386773565 3988.09132143321722 0.28472679881120 1057011.62395176826976 -33.56713426853725 3988.09120561649479 0.27057774585364 1057011.63821663800627 -33.66733466933886 3988.09109555510668 0.25713180795065 1057011.65177263738587 -33.76753507014046 3988.09099096304999 0.24435404489974 1057011.66465499252081 -33.86773547094207 3988.09089156853452 0.23221125279706 1057011.67689717910253 -33.96793587174367 3988.09079711327649 0.22067187775479 1057011.68853100948036 -34.06813627254527 3988.09070735182695 0.20970593390618 1057011.69958671485074 -34.16833667334688 3988.09062205093414 0.19928492548519 1057011.71009302418679 -34.26853707414848 3988.09054098893739 0.18938177277826 1057011.72007723897696 -34.36873747495009 3988.09046395519135 0.17997074175583 1057011.72956530377269 -34.46893787575169 3988.09039074951806 0.17102737720066 1057011.73858187394217 -34.56913827655330 3988.09032118168761 0.16252843915924 1057011.74715037969872 -34.66933867735490 3988.09025507092292 0.15445184255120 1057011.75529308710247 -34.76953907815651 3988.09019224543044 0.14677659977968 1057011.76303115533665 -34.86973947895811 3988.09013254195361 0.13948276619360 1057011.77038469235413 -34.96993987975971 3988.09007580534853 0.13255138826010 1057011.77737280679867 -35.07014028056132 3988.09002188818113 0.12596445431248 1057011.78401365783066 -35.17034068136292 3988.08997065034373 0.11970484774565 1057011.79032450215891 -35.27054108216453 3988.08992195869087 0.11375630253741 1057011.79632173897699 -35.37074148296613 3988.08987568669409 0.10810336098009 1057011.80202095257118 -35.47094188376774 3988.08983171411228 0.10273133351263 1057011.80743695260026 -35.57114228456934 3988.08978992667971 0.09762626054870 1057011.81258381297812 -35.67134268537094 3988.08975021580864 0.09277487620181 1057011.81747490819544 -35.77154308617255 3988.08971247830777 0.08816457381290 1057011.82212294801138 -35.87174348697415 3988.08967661611314 0.08378337319116 1057011.82654001074843 -35.97194388777576 3988.08964253603472 0.07961988948257 1057011.83073757449165 -36.07214428857736 3988.08961014951274 0.07566330358567 1057011.83472654689103 -36.17234468937897 3988.08957937238847 0.07190333403729 1057011.83851729356684 -36.27254509018057 3988.08955012468550 0.06833021029550 1057011.84211966511793 -36.37274549098218 3988.08952233040145 0.06493464735016 1057011.84554302226752 -36.47294589178378 3988.08949591731107 0.06170782159521 1057011.84879626100883 -36.57314629258538 3988.08947081677843 0.05864134789985 1057011.85188783518970 -36.67334669338699 3988.08944696357730 0.05572725781927 1057011.85482577839866 -36.77354709418859 3988.08942429572380 0.05295797888806 1057011.85761772515252 -36.87374749499020 3988.08940275431405 0.05032631494263 1057011.86027093045413 -36.97394789579180 3988.08938228337092 0.04782542742147 1057011.86279228888452 -37.07414829659341 3988.08936282969944 0.04544881759471 1057011.86518835229799 -37.17434869739501 3988.08934434274806 0.04319030967667 1057011.86746534705162 -37.27454909819662 3988.08932677447683 0.04104403477772 1057011.86962919030339 -37.37474949899822 3988.08931007923366 0.03900441565348 1057011.87168550468050 -37.47494989979982 3988.08929421363428 0.03706615221202 1057011.87363963364623 -37.57515030060143 3988.08927913645130 0.03522420774121 1057011.87549665523693 -37.67535070140303 3988.08926480850550 0.03347379582042 1057011.87726139510050 -37.77555110220464 3988.08925119256446 0.03181036788272 1057011.87893843906932 -37.87575150300624 3988.08923825324655 0.03022960139511 1057011.88053214480169 -37.97595190380785 3988.08922595692775 0.02872738862610 1057011.88204665388912 -38.07615230460945 3988.08921427165524 0.02729982597148 1057011.88348590186797 -38.17635270541106 3988.08920316706417 0.02594320381057 1057011.88485362869687 -38.27655310621266 3988.08919261429855 0.02465399686646 1057011.88615338830277 -38.37675350701426 3988.08918258593576 0.02342885504539 1057011.88738855859265 -38.47695390781587 3988.08917305591694 0.02226459473125 1057011.88856234890409 -38.57715430861747 3988.08916399947748 0.02115819051277 1057011.88967780955136 -38.67735470941908 3988.08915539308373 0.02010676732174 1057011.89073783904314 -38.77755511022068 3988.08914721437122 0.01910759296199 1057011.89174519223161 -38.87775551102229 3988.08913944208689 0.01815807100956 1057011.89270248636603 -38.97795591182389 3988.08913205603449 0.01725573406571 1057011.89361220947467 -39.07815631262550 3988.08912503702004 0.01639823734522 1057011.89447672525421 -39.17835671342710 3988.08911836680454 0.01558335258333 1057011.89529828028753 -39.27855711422870 3988.08911202805530 0.01480896224538 1057011.89607900939882 -39.37875751503031 3988.08910600429999 0.01407305402430 1057011.89682094147429 -39.47895791583191 3988.08910027988577 0.01337371561147 1057011.89752600435168 -39.57915831663352 3988.08909483993739 0.01270912972746 1057011.89819603017531 -39.67935871743512 3988.08908967031903 0.01207756939970 1057011.89883276005276 -39.77955911823673 3988.08908475759654 0.01147739347481 1057011.89943784871139 -39.87975951903833 3988.08908008900426 0.01090704235397 1057011.90001286845654 -39.97995991983993 3988.08907565241043 0.01036503394018 1057011.90055931336246 -40.08016032064154 3988.08907143628630 0.00984995978694 1057011.90107860369608 -40.18036072144314 3988.08906742967565 0.00936048143829 1057011.90157208871096 -40.28056112224475 3988.08906362216749 0.00889532695074 1057011.90204105060548 -40.38076152304635 3988.08906000386742 0.00845328758806 1057011.90248670824803 -40.48096192384796 3988.08905656537308 0.00803321468027 1057011.90291021973826 -40.58116232464956 3988.08905329774916 0.00763401663873 1057011.90331268543378 -40.68136272545117 3988.08905019250460 0.00725465611961 1057011.90369515120983 -40.78156312625277 3988.08904724157037 0.00689414732827 1057011.90405861102045 -40.88176352705437 3988.08904443727852 0.00655155345755 1057011.90440400922671 -40.98196392785598 3988.08904177234126 0.00622598425351 1057011.90473224339075 -41.08216432865758 3988.08903923983416 0.00591659370195 1057011.90504416637123 -41.18236472945919 3988.08903683317612 0.00562257783004 1057011.90534058888443 -41.28256513026079 3988.08903454611300 0.00534317261711 1057011.90562228113413 -41.38276553106240 3988.08903237270169 0.00507765200932 1057011.90588997513987 -41.48296593186400 3988.08903030729471 0.00482532603292 1057011.90614436659962 -41.58316633266561 3988.08902834452510 0.00458553900133 1057011.90638611628674 -41.68336673346721 3988.08902647929199 0.00435766781132 1057011.90661585261114 -41.78356713426881 3988.08902470674911 0.00414112032376 1057011.90683417255059 -41.88376753507042 3988.08902302228989 0.00393533382496 1057011.90704164351337 -41.98396793587202 3988.08902142153738 0.00373977356442 1057011.90723880450241 -42.08416833667363 3988.08901990033155 0.00355393136522 1057011.90742616797797 -42.18436873747523 3988.08901845471974 0.00337732430350 1057011.90760422055610 -42.28456913827684 3988.08901708094527 0.00320949345354 1057011.90777342510410 -42.38476953907844 3988.08901577543838 0.00305000269522 1057011.90793422143906 -42.48496993988005 3988.08901453480667 0.00289843758074 1057011.90808702725917 -42.58517034068165 3988.08901335582595 0.00275440425760 1057011.90823223954067 -42.68537074148325 3988.08901223543307 0.00261752844523 1057011.90837023570202 -42.78557114228486 3988.08901117071628 0.00248745446231 1057011.90850137430243 -42.88577154308646 3988.08901015890888 0.00236384430257 1057011.90862599620596 -42.98597194388807 3988.08900919738153 0.00224637675642 1057011.90874442528002 -43.08617234468967 3988.08900828363585 0.00213474657629 1057011.90885696909390 -43.18637274549128 3988.08900741529760 0.00202866368339 1057011.90896392031573 -43.28657314629288 3988.08900659010988 0.00192785241397 1057011.90906555671245 -43.38677354709449 3988.08900580592854 0.00183205080294 1057011.90916214254685 -43.48697394789609 3988.08900506071586 0.00174100990316 1057011.90925392857753 -43.58717434869769 3988.08900435253554 0.00165449313853 1057011.90934115345590 -43.68737474949930 3988.08900367954720 0.00157227568923 1057011.90942404395901 -43.78757515030090 3988.08900304000190 0.00149414390750 1057011.90950281522237 -43.88777555110251 3988.08900243223752 0.00141989476249 1057011.90957767213695 -43.98797595190411 3988.08900185467519 0.00134933531263 1057011.90964880911633 -44.08817635270572 3988.08900130581378 0.00128228220430 1057011.90971641102806 -44.18837675350732 3988.08900078422721 0.00121856119532 1057011.90978065365925 -44.28857715430892 3988.08900028856033 0.00115800670225 1057011.90984170371667 -44.38877755511053 3988.08899981752484 0.00110046137002 1057011.90989971999079 -44.48897795591213 3988.08899936989656 0.00104577566308 1057011.90995485335588 -44.58917835671374 3988.08899894451270 0.00099380747684 1057011.91000724700280 -44.68937875751534 3988.08899854026731 0.00094442176834 1057011.91005703690462 -44.78957915831695 3988.08899815611039 0.00089749020541 1057011.91010435251519 -44.88977955911855 3988.08899779104377 0.00085289083310 1057011.91014931700192 -44.98997995992016 3988.08899744411838 0.00081050775686 1057011.91019204701297 -45.09018036072176 3988.08899711443291 0.00077023084131 1057011.91023265360855 -45.19038076152336 3988.08899680113063 0.00073195542410 1057011.91027124226093 -45.29058116232497 3988.08899650339754 0.00069558204390 1057011.91030791332014 -45.39078156312657 3988.08899622045965 0.00066101618195 1057011.91034276201390 -45.49098196392818 3988.08899595158209 0.00062816801645 1057011.91037587914616 -45.59118236472978 3988.08899569606592 0.00059695218917 1057011.91040735039860 -45.69138276553139 3988.08899545324721 0.00056728758361 1057011.91043725772761 -45.79158316633299 3988.08899522249476 0.00053909711424 1057011.91046567889862 -45.89178356713460 3988.08899500320922 0.00051230752616 1057011.91049268771894 -45.99198396793620 3988.08899479482079 0.00048684920477 1057011.91051835450344 -46.09218436873780 3988.08899459678787 0.00046265599485 1057011.91054274584167 -46.19238476953941 3988.08899440859614 0.00043966502867 1057011.91056592506357 -46.29258517034101 3988.08899422975628 0.00041781656259 1057011.91058795247227 -46.39278557114262 3988.08899405980355 0.00039705382188 1057011.91060888511129 -46.49298597194422 3988.08899389829639 0.00037732285309 1057011.91062877769582 -46.59318637274583 3988.08899374481507 0.00035857238395 1057011.91064768168144 -46.69338677354743 3988.08899359896077 0.00034075369004 1057011.91066564619541 -46.79358717434904 3988.08899346035423 0.00032382046827 1057011.91068271803670 -46.89378757515064 3988.08899332863575 0.00030772871647 1057011.91069894144312 -46.99398797595224 3988.08899320346291 0.00029243661912 1057011.91071435878985 -47.09418837675385 3988.08899308451009 0.00027790443863 1057011.91072900989093 -47.19438877755545 3988.08899297146854 0.00026409441213 1057011.91074293293059 -47.29458917835706 3988.08899286404449 0.00025097065329 1057011.91075616399758 -47.39478957915866 3988.08899276195871 0.00023849905913 1057011.91076873778366 -47.49498997996027 3988.08899266494564 0.00022664722134 1057011.91078068665229 -47.59519038076187 3988.08899257275380 0.00021538434210 1057011.91079204180278 -47.69539078156348 3988.08899248514308 0.00020468115403 1057011.91080283257179 -47.79559118236508 3988.08899240188612 0.00019450984415 1057011.91081308713183 -47.89579158316668 3988.08899232276644 0.00018484398161 1057011.91082283202559 -47.99599198396829 3988.08899224757852 0.00017565844899 1057011.91083209263161 -48.09619238476989 3988.08899217612679 0.00016692937705 1057011.91084089316428 -48.19639278557150 3988.08899210822574 0.00015863408270 1057011.91084925644100 -48.29659318637310 3988.08899204369891 0.00015075101002 1057011.91085720411502 -48.39679358717471 3988.08899198237896 0.00014325967432 1057011.91086475667544 -48.49699398797631 3988.08899192410627 0.00013614060882 1057011.91087193391286 -48.59719438877791 3988.08899186872895 0.00012937531416 1057011.91087875468656 -48.69739478957952 3988.08899181610377 0.00012294621023 1057011.91088523645885 -48.79759519038112 3988.08899176609384 0.00011683659057 1057011.91089139599353 -48.89779559118273 3988.08899171856910 0.00011103057891 1057011.91089724958874 -48.99799599198433 3988.08899167340587 0.00010551308791 1057011.91090281214565 -49.09819639278594 3988.08899163048682 0.00010026978000 1057011.91090809833258 -49.19839679358754 3988.08899158970053 0.00009528703008 1057011.91091312188655 -49.29859719438915 3988.08899155094105 0.00009055189013 1057011.91091789584607 -49.39879759519075 3988.08899151410787 0.00008605205555 1057011.91092243255116 -49.49899799599235 3988.08899147910506 0.00008177583321 1057011.91092674387619 -49.59919839679396 3988.08899144584166 0.00007771211106 1057011.91093084076419 -49.69939879759556 3988.08899141423126 0.00007385032922 1057011.91093473415822 -49.79959919839717 3988.08899138419156 0.00007018045259 1057011.91093843406998 -49.89979959919877 3988.08899135564479 0.00006669294475 1057011.91094195004553 \ No newline at end of file From 197f371d074fe832d8ca7d56ca4cc41a8f867318 Mon Sep 17 00:00:00 2001 From: HenrZu Date: Wed, 27 Mar 2024 15:41:10 +0100 Subject: [PATCH 20/34] [ci skip] fix bug. Tests still fail --- cpp/models/ode_seir/model.h | 73 +++++++------- cpp/tests/test_odeseir.cpp | 185 +++++++++++++++++------------------- 2 files changed, 123 insertions(+), 135 deletions(-) diff --git a/cpp/models/ode_seir/model.h b/cpp/models/ode_seir/model.h index af3c90d1dc..fe425c6202 100644 --- a/cpp/models/ode_seir/model.h +++ b/cpp/models/ode_seir/model.h @@ -34,7 +34,6 @@ #include "memilio/epidemiology/age_group.h" #include "memilio/compartments/flow_simulation.h" - namespace mio { namespace oseir @@ -50,9 +49,9 @@ using Flows = TypeList>; // clang-format on -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_agegroups) @@ -63,35 +62,37 @@ class Model : public FlowModel pop, Eigen::Ref y, double t, Eigen::Ref flows) const override { - auto& params = this->parameters; - AgeGroup n_agegroups = params.get_num_groups(); + auto& params = this->parameters; + AgeGroup n_agegroups = params.get_num_groups(); ContactMatrixGroup const& contact_matrix = params.get(); - for(auto i = AgeGroup(0); i < n_agegroups; i++){ + for (auto i = AgeGroup(0); i < n_agegroups; i++) { size_t Si = this->populations.get_flat_index({i, InfectionState::Susceptible}); size_t Ei = this->populations.get_flat_index({i, InfectionState::Exposed}); size_t Ii = this->populations.get_flat_index({i, InfectionState::Infected}); - for(auto j = AgeGroup(0); j < n_agegroups; j++){ + for (auto j = AgeGroup(0); j < n_agegroups; j++) { size_t Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); size_t Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); size_t Ij = this->populations.get_flat_index({j, InfectionState::Infected}); size_t Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); - double Nj = pop[Sj] + pop[Ej] + pop[Ij] + pop[Rj]; - double divNj = 1.0/Nj; + double Nj = pop[Sj] + pop[Ej] + pop[Ij] + pop[Rj]; + double divNj = 1.0 / Nj; double coeffStoE = contact_matrix.get_matrix_at(t)(static_cast((size_t)i), - static_cast((size_t)j)) * - params.get()[i]*divNj; + static_cast((size_t)j)) * + params.get()[i] * divNj; - double dummy_S = y[Si] *y[Ij]*coeffStoE; + double dummy_S = y[Si] * y[Ij] * coeffStoE; - flows[get_flat_flow_index({i})]+=dummy_S; + flows[get_flat_flow_index({i})] += dummy_S; } - flows[get_flat_flow_index({i})] = (1.0 / params.get()[i]) * y[Ei]; - flows[get_flat_flow_index({i})] = (1.0 / params.get()[i]) * y[Ii]; + flows[get_flat_flow_index({i})] = + (1.0 / params.get()[i]) * y[Ei]; + flows[get_flat_flow_index({i})] = + (1.0 / params.get()[i]) * y[Ii]; } } @@ -109,44 +110,46 @@ class Model : public FlowModelparameters; - const size_t num_groups = (size_t)params.get_num_groups(); - const size_t num_infected_compartments = 2; - const size_t total_infected_compartments = num_infected_compartments*num_groups; + const size_t num_groups = (size_t)params.get_num_groups(); + const size_t num_infected_compartments = 2; + const size_t total_infected_compartments = num_infected_compartments * num_groups; ContactMatrixGroup const& contact_matrix = params.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_groups); i++){ + 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_groups); i++) { size_t Si = this->populations.get_flat_index({i, InfectionState::Susceptible}); - for(auto j = AgeGroup(0); j < AgeGroup(num_groups); j++){ + for (auto j = AgeGroup(0); j < AgeGroup(num_groups); j++) { size_t Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); size_t Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); size_t Ij = this->populations.get_flat_index({j, InfectionState::Infected}); size_t Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); - double Nj = y.get_value(t_idx)[Sj]+y.get_value(t_idx)[Ej] + y.get_value(t_idx)[Ij] + y.get_value(t_idx)[Rj]; - double divNj = 1.0/Nj; + std::cout << " y = " << y.get_value(t_idx) << std::endl; + double Nj = + y.get_value(t_idx)[Sj] + y.get_value(t_idx)[Ej] + y.get_value(t_idx)[Ij] + y.get_value(t_idx)[Rj]; + double divNj = 1.0 / Nj; - double coeffStoE = contact_matrix.get_matrix_at(y.get_time(t_idx))(static_cast((size_t)i), - static_cast((size_t)j))* - params.get()[i]*divNj; - F((size_t)i,(size_t)j+num_groups) = coeffStoE*y.get_value(t_idx)[Si]; + double coeffStoE = contact_matrix.get_matrix_at(y.get_time(t_idx))( + static_cast((size_t)i), static_cast((size_t)j)) * + params.get()[i] * divNj; + F((size_t)i, (size_t)j + num_groups) = coeffStoE * y.get_value(t_idx)[Si]; } - double T_Ei = params.get()[i]; - double T_Ii = params.get()[i]; - V((size_t)i,(size_t)i) = 1.0/T_Ei; - V((size_t)i+num_groups,(size_t)i) = - 1.0/T_Ei; - V((size_t)i+num_groups,(size_t)i+num_groups) = 1.0/T_Ii; + double T_Ei = params.get()[i]; + double T_Ii = params.get()[i]; + V((size_t)i, (size_t)i) = 1.0 / T_Ei; + V((size_t)i + num_groups, (size_t)i) = -1.0 / T_Ei; + V((size_t)i + num_groups, (size_t)i + num_groups) = 1.0 / T_Ii; } V = V.inverse(); Eigen::MatrixXd NextGenMatrix = Eigen::MatrixXd::Zero(total_infected_compartments, total_infected_compartments); - NextGenMatrix = F * V; + NextGenMatrix = F * V; //Compute the largest eigenvalue in absolute value Eigen::ComplexEigenSolver ces; diff --git a/cpp/tests/test_odeseir.cpp b/cpp/tests/test_odeseir.cpp index a80aac3e57..b5b57c3d05 100644 --- a/cpp/tests/test_odeseir.cpp +++ b/cpp/tests/test_odeseir.cpp @@ -43,6 +43,18 @@ TEST(TestOdeSeir, simulateDefault) class ModelTestOdeSeir : public testing::Test { + +public: + ModelTestOdeSeir() + : model(1) + { + } + double t0; + double tmax; + double dt; + double total_population; + mio::oseir::Model model; + protected: void SetUp() override { @@ -52,82 +64,56 @@ class ModelTestOdeSeir : public testing::Test total_population = 1061000; - mio::oseir::Model model(1); - - model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Exposed}] = 10000; - model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Infected}] = 1000; - model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Recovered}] = 1000; - 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}]; - model.parameters.set(1.0); - model.parameters.set(5.2); - model.parameters.set(2); - - 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.6, mio::SimulationTime(12.5)); - - std::vector> refData = load_test_data_csv("seir-js-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; - } - - ASSERT_NEAR(t, result.get_times()[irow], 1e-12) << "at row " << irow; - for (size_t icol = 0; icol < 4; ++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; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Exposed}] = 10000; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Infected}] = 1000; + model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Recovered}] = 1000; + 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}]; + model.parameters.set(1.0); + model.parameters.set(5.2); + model.parameters.set(2); + + 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.6, mio::SimulationTime(12.5)); + + std::vector> refData = load_test_data_csv("seir-js-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; + } + + ASSERT_NEAR(t, result.get_times()[irow], 1e-12) << "at row " << irow; + for (size_t icol = 0; icol < 4; ++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(ModelTestOdeSeir, checkPopulationConservation) { - // initialization - double t0 = 0.; - double tmax = 50.; - double dt = 0.1002004008016032; - - double total_population = 1061000; - - mio::oseir::Model model(1); - - model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Exposed}] = 10000; - model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Infected}] = 1000; - model.populations[{mio::AgeGroup(0),mio::oseir::InfectionState::Recovered}] = 1000; - 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}]; - model.parameters.set(1.0); - model.parameters.set(5.2); - model.parameters.set(2); - - 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.6, mio::SimulationTime(12.5)); - auto result = mio::simulate(t0, tmax, dt, model); double num_persons = 0.0; for (auto i = 0; i < result.get_last_value().size(); i++) { @@ -138,13 +124,6 @@ TEST_F(ModelTestOdeSeir, checkPopulationConservation) TEST_F(ModelTestOdeSeir, check_constraints_parameters) { - mio::oseir::Model model(1); - model.parameters.set(5.2); - model.parameters.set(6); - model.parameters.set(0.04); - mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(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); @@ -194,15 +173,14 @@ TEST(TestOdeSeir, get_reproduction_numbers) { mio::oseir::Model model(1); - double 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}]; + double 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}]; model.parameters.set(6); model.parameters.set(0.04); @@ -232,6 +210,14 @@ TEST(TestOdeSeir, get_reproduction_numbers) mio::TimeSeries::Vector result_5(4); mio::TimeSeries::Vector result_6(4); + result_0.setZero(); + result_1.setZero(); + result_2.setZero(); + result_3.setZero(); + result_4.setZero(); + result_5.setZero(); + result_6.setZero(); + result_0[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9700; result_1[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.9611995799496071; result_2[(Eigen::Index)mio::oseir::InfectionState::Susceptible] = 9699.7865872644051706; @@ -279,14 +265,13 @@ TEST(TestOdeSeir, get_reproduction_number) mio::oseir::Model model(1); double total_population = 10000; //Initialize compartments to get total population of 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}]; + 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}]; model.parameters.set(6); model.parameters.set(0.04); @@ -344,21 +329,21 @@ TEST(TestOdeSeir, get_reproduction_number) EXPECT_NEAR(model.get_reproduction_number(0.9, result).value(), 1.858670429549998504, 1e-12); } -TEST(TestSeir,test_age_groups){ +TEST(TestSeir, test_age_groups) +{ double t0 = 0; double tmax = 1; double dt = 0.001; mio::oseir::Model model(1); - double total_population = 10000; + double total_population = 10000; //model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; 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}] - + 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}]; // suscetible now set with every other update @@ -374,7 +359,7 @@ TEST(TestSeir,test_age_groups){ auto seir = simulate(t0, tmax, dt, model); - const auto compare = load_test_data_csv("seir-agegrp-compare.csv"); + const auto compare = load_test_data_csv("seir-agegrp-compare.csv"); ASSERT_EQ(compare.size(), static_cast(seir.get_num_time_points())); for (size_t i = 0; i < compare.size(); i++) { From 3a3615c2c4625f10b6703636f905df19866664a7 Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Tue, 2 Apr 2024 20:21:07 +0200 Subject: [PATCH 21/34] fix tests --- cpp/models/ode_seir/model.h | 15 ++---- cpp/tests/test_odeseir.cpp | 61 ++++++------------------ cpp/tests/test_odesir.cpp | 92 ++++++++++++------------------------- 3 files changed, 48 insertions(+), 120 deletions(-) diff --git a/cpp/models/ode_seir/model.h b/cpp/models/ode_seir/model.h index fe425c6202..a0d68d4165 100644 --- a/cpp/models/ode_seir/model.h +++ b/cpp/models/ode_seir/model.h @@ -110,9 +110,9 @@ class Model : public FlowModelparameters; - const size_t num_groups = (size_t)params.get_num_groups(); - const size_t num_infected_compartments = 2; - const size_t total_infected_compartments = num_infected_compartments * num_groups; + const size_t num_groups = (size_t)params.get_num_groups(); + constexpr size_t num_infected_compartments = 2; + const size_t total_infected_compartments = num_infected_compartments * num_groups; ContactMatrixGroup const& contact_matrix = params.get(); @@ -123,14 +123,7 @@ class Model : public FlowModelpopulations.get_flat_index({i, InfectionState::Susceptible}); for (auto j = AgeGroup(0); j < AgeGroup(num_groups); j++) { - size_t Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); - size_t Ej = this->populations.get_flat_index({j, InfectionState::Exposed}); - size_t Ij = this->populations.get_flat_index({j, InfectionState::Infected}); - size_t Rj = this->populations.get_flat_index({j, InfectionState::Recovered}); - - std::cout << " y = " << y.get_value(t_idx) << std::endl; - double Nj = - y.get_value(t_idx)[Sj] + y.get_value(t_idx)[Ej] + y.get_value(t_idx)[Ij] + y.get_value(t_idx)[Rj]; + double Nj = this->populations.get_group_total(j); double divNj = 1.0 / Nj; double coeffStoE = contact_matrix.get_matrix_at(y.get_time(t_idx))( diff --git a/cpp/tests/test_odeseir.cpp b/cpp/tests/test_odeseir.cpp index b5b57c3d05..ddffd49f15 100644 --- a/cpp/tests/test_odeseir.cpp +++ b/cpp/tests/test_odeseir.cpp @@ -79,46 +79,13 @@ class ModelTestOdeSeir : public testing::Test model.parameters.get().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(2.7); contact_matrix[0].add_damping(0.6, mio::SimulationTime(12.5)); - - std::vector> refData = load_test_data_csv("seir-js-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; - } - - ASSERT_NEAR(t, result.get_times()[irow], 1e-12) << "at row " << irow; - for (size_t icol = 0; icol < 4; ++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(ModelTestOdeSeir, checkPopulationConservation) { 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]; - } + double num_persons = result.get_last_value().sum(); EXPECT_NEAR(num_persons, total_population, 1e-8); } @@ -329,8 +296,11 @@ TEST(TestOdeSeir, get_reproduction_number) EXPECT_NEAR(model.get_reproduction_number(0.9, result).value(), 1.858670429549998504, 1e-12); } -TEST(TestSeir, test_age_groups) +TEST(TestSeir, get_derivatives) { + + // Test, that in the case of one agegroup, the simulation is the same as before the implementation of agegroups + // This test is independent of the integrator used. double t0 = 0; double tmax = 1; double dt = 0.001; @@ -338,7 +308,7 @@ TEST(TestSeir, test_age_groups) mio::oseir::Model model(1); double total_population = 10000; - //model.populations[{mio::Index(0),mio::Index(mio::oseir::InfectionState::Exposed)}] = 100; + 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; @@ -346,8 +316,7 @@ TEST(TestSeir, test_age_groups) 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}]; - // suscetible now set with every other update - // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; + model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); @@ -359,14 +328,12 @@ TEST(TestSeir, test_age_groups) auto seir = simulate(t0, tmax, dt, model); - const auto compare = load_test_data_csv("seir-agegrp-compare.csv"); + auto dydt_default = Eigen::VectorXd(Eigen::Index(mio::oseir::InfectionState::Count)); + Eigen::VectorXd y0 = seir.get_value(0); + model.get_derivatives(y0, y0, 0, dydt_default); - ASSERT_EQ(compare.size(), static_cast(seir.get_num_time_points())); - for (size_t i = 0; i < compare.size(); i++) { - ASSERT_EQ(compare[i].size(), static_cast(seir.get_num_elements()) + 1) << "at row " << i; - EXPECT_NEAR(seir.get_time(i), compare[i][0], 1e-10) << "at row " << i; - for (size_t j = 1; j < compare[i].size(); j++) { - EXPECT_NEAR(seir.get_value(i)[j - 1], compare[i][j], 1e-9) << " at row " << i; - } - } + EXPECT_NEAR(dydt_default[0], -38.8, 1e-12); + EXPECT_NEAR(dydt_default[1], 19.56923076923077, 1e-12); + EXPECT_NEAR(dydt_default[2], 2.564102564102566, 1e-12); + EXPECT_NEAR(dydt_default[3], 16.66666666666666, 1e-12); } diff --git a/cpp/tests/test_odesir.cpp b/cpp/tests/test_odesir.cpp index dd562dd8af..04b061246e 100644 --- a/cpp/tests/test_odesir.cpp +++ b/cpp/tests/test_odesir.cpp @@ -53,17 +53,23 @@ TEST(TestOdeSir, compareWithPreviousRun) mio::osir::Model model(1); - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Recovered)}] = 1000; - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0), + mio::Index(mio::osir::InfectionState::Infected)}] = 1000; + model.populations[{mio::Index(0), + mio::Index(mio::osir::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index(0), + mio::Index(mio::osir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0), + mio::Index(mio::osir::InfectionState::Infected)}] - + model.populations[{mio::Index(0), + mio::Index(mio::osir::InfectionState::Recovered)}]; model.parameters.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)); + model.parameters.get().get_cont_freq_mat()[0].add_damping(0.6, + mio::SimulationTime(12.5)); std::vector> refData = load_test_data_csv("ode-sir-compare.csv"); auto integrator = std::make_shared(); @@ -108,18 +114,23 @@ TEST(TestOdeSir, checkPopulationConservation) mio::osir::Model model(1); - - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] = 1000; - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Recovered)}] = 1000; - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Susceptible)}] = + model.populations[{mio::Index(0), + mio::Index(mio::osir::InfectionState::Infected)}] = 1000; + model.populations[{mio::Index(0), + mio::Index(mio::osir::InfectionState::Recovered)}] = 1000; + model.populations[{mio::Index(0), + mio::Index(mio::osir::InfectionState::Susceptible)}] = total_population - - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Infected)}] - - model.populations[{mio::Index(0),mio::Index(mio::osir::InfectionState::Recovered)}]; + model.populations[{mio::Index(0), + mio::Index(mio::osir::InfectionState::Infected)}] - + model.populations[{mio::Index(0), + mio::Index(mio::osir::InfectionState::Recovered)}]; model.parameters.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)); + model.parameters.get().get_cont_freq_mat()[0].add_damping(0.6, + mio::SimulationTime(12.5)); auto result = mio::simulate(t0, tmax, dt, model); double num_persons = 0.0; for (auto i = 0; i < result.get_last_value().size(); i++) { @@ -172,52 +183,10 @@ TEST(TestOdeSir, apply_constraints_parameters) mio::set_log_level(mio::LogLevel::warn); } -TEST(Testsir, test_age_groups) -{ - // Test, that in the case of one agegroup, the simulation is the same as before the implementation of agegroups - double t0 = 0.; - double tmax = 50.; - double dt = 0.1002004008016032; - - double total_population = 1061000; - - mio::osir::Model model(1); - - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] = 1000; - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}] = 1000; - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Susceptible}] = - total_population - - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] - - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}]; - model.parameters.set(2); - model.parameters.set(1); - 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.6, mio::SimulationTime(12.5)); - - auto integrator = std::make_shared(); - - model.check_constraints(); - - auto sir = simulate(t0, tmax, dt, model, integrator); - - const auto compare = load_test_data_csv("sir-agegrp-compare.csv"); - - ASSERT_EQ(compare.size(), static_cast(sir.get_num_time_points())); - for (size_t i = 0; i < compare.size(); i++) { - ASSERT_EQ(compare[i].size(), static_cast(sir.get_num_elements()) + 1) << "at row " << i; - EXPECT_NEAR(sir.get_time(i), compare[i][0], 1e-10) << "at row " << i; - for (size_t j = 1; j < compare[i].size(); j++) { - EXPECT_NEAR(sir.get_value(i)[j - 1], compare[i][j], 1e-9) << " at row " << i; - } - } -} - TEST(Testsir, get_derivatives_agegrp_compare) { - // Test, that in the case of one agegroup, the simulation is the same as before the implementation of agegroups + // Test, that in the case of one age group, the simulation is the same as before the implementation of agegroups // This test is independent of the integrator used. - // Test, that in the case of one agegroup, the simulation is the same as before the implementation of agegroups double t0 = 0.; double tmax = 50.; double dt = 0.1002004008016032; @@ -229,8 +198,7 @@ TEST(Testsir, get_derivatives_agegrp_compare) model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] = 1000; model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}] = 1000; model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Susceptible}] = - total_population - - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] - + total_population - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}]; model.parameters.set(2); model.parameters.set(1); @@ -244,11 +212,11 @@ TEST(Testsir, get_derivatives_agegrp_compare) auto sir = simulate(t0, tmax, dt, model, integrator); - auto dydt_default = Eigen::VectorXd(Eigen::Index(mio::osir::InfectionState::Count)); + auto dydt_default = Eigen::VectorXd(Eigen::Index(mio::osir::InfectionState::Count)); Eigen::VectorXd y0 = sir.get_value(0); model.get_derivatives(y0, y0, 0, dydt_default); - EXPECT_NEAR(dydt_default[0],-2694.9104618284641,1e-12); - EXPECT_NEAR(dydt_default[1],2194.9104618284641,1e-12); - EXPECT_NEAR(dydt_default[2],500,1e-10); + EXPECT_NEAR(dydt_default[0], -2694.9104618284641, 1e-12); + EXPECT_NEAR(dydt_default[1], 2194.9104618284641, 1e-12); + EXPECT_NEAR(dydt_default[2], 500, 1e-12); } \ No newline at end of file From 7078c469432660527a0e9facf58058feecb0151b Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Wed, 3 Apr 2024 08:51:04 +0200 Subject: [PATCH 22/34] fix msvc --- cpp/models/ode_sir/model.h | 25 +++++++++++-------------- cpp/tests/test_odeseir.cpp | 1 + cpp/tests/test_odesir.cpp | 1 + 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/cpp/models/ode_sir/model.h b/cpp/models/ode_sir/model.h index c441424f7b..f3cf456b48 100644 --- a/cpp/models/ode_sir/model.h +++ b/cpp/models/ode_sir/model.h @@ -37,12 +37,11 @@ namespace osir * define the model * ********************/ -class Model : public CompartmentalModel, Parameters> +class Model : public CompartmentalModel, Parameters> { using Base = CompartmentalModel, Parameters>; public: - Model(int num_agegroups) : Base(Populations({AgeGroup(num_agegroups), InfectionState::Count}), ParameterSet(AgeGroup(num_agegroups))) { @@ -51,8 +50,8 @@ class Model : public CompartmentalModel pop, Eigen::Ref y, double t, Eigen::Ref dydt) const override { - auto params = this->parameters; - AgeGroup n_agegroups = params.get_num_groups(); + auto params = this->parameters; + AgeGroup n_agegroups = params.get_num_groups(); ContactMatrixGroup const& contact_matrix = params.get(); for (auto i = AgeGroup(0); i < n_agegroups; i++) { @@ -61,7 +60,7 @@ class Model : public CompartmentalModelpopulations.get_flat_index({i, InfectionState::Infected}); size_t Ri = this->populations.get_flat_index({i, InfectionState::Recovered}); - for (auto j = AgeGroup(0); j < n_agegroups; j++){ + for (auto j = AgeGroup(0); j < n_agegroups; j++) { size_t Sj = this->populations.get_flat_index({j, InfectionState::Susceptible}); size_t Ij = this->populations.get_flat_index({j, InfectionState::Infected}); @@ -70,17 +69,15 @@ class Model : public CompartmentalModel((size_t)i), - static_cast((size_t)j))* - params.get()[i] / Nj; + static_cast((size_t)j)) * + params.get()[i] / Nj; - dydt[Si] += - -coeffStoI * y[Si] * pop[Ij]; - dydt[Ii] += - coeffStoI * y[Si] * pop[Ij]; + dydt[Si] += -coeffStoI * y[Si] * pop[Ij]; + dydt[Ii] += coeffStoI * y[Si] * pop[Ij]; } - dydt[Ii]-=(1.0 / params.get()[i]) * y[Ii]; - dydt[Ri] = - (1.0 / params.get()[i]) * y[Ii]; + dydt[Ii] -= (1.0 / params.get()[i]) * y[Ii]; + dydt[Ri] = (1.0 / params.get()[i]) * y[Ii]; + } } }; diff --git a/cpp/tests/test_odeseir.cpp b/cpp/tests/test_odeseir.cpp index ddffd49f15..d3caab9c49 100644 --- a/cpp/tests/test_odeseir.cpp +++ b/cpp/tests/test_odeseir.cpp @@ -329,6 +329,7 @@ TEST(TestSeir, get_derivatives) auto seir = simulate(t0, tmax, dt, model); auto dydt_default = Eigen::VectorXd(Eigen::Index(mio::oseir::InfectionState::Count)); + dydt_default.setZero(); Eigen::VectorXd y0 = seir.get_value(0); model.get_derivatives(y0, y0, 0, dydt_default); diff --git a/cpp/tests/test_odesir.cpp b/cpp/tests/test_odesir.cpp index 04b061246e..b322443cea 100644 --- a/cpp/tests/test_odesir.cpp +++ b/cpp/tests/test_odesir.cpp @@ -213,6 +213,7 @@ TEST(Testsir, get_derivatives_agegrp_compare) auto sir = simulate(t0, tmax, dt, model, integrator); auto dydt_default = Eigen::VectorXd(Eigen::Index(mio::osir::InfectionState::Count)); + dydt_default.setZero(); Eigen::VectorXd y0 = sir.get_value(0); model.get_derivatives(y0, y0, 0, dydt_default); From f6e1683bc58827569b83302d360b38e83d6d0f2f Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Wed, 3 Apr 2024 09:51:55 +0200 Subject: [PATCH 23/34] adjust bindings + tests pycode --- pycode/examples/simulation/oseir_simple.py | 31 +++++----- pycode/examples/simulation/osir_simple.py | 27 +++++---- .../memilio/simulation/oseir.cpp | 19 +++++-- .../memilio/simulation/osir.cpp | 19 +++++-- .../memilio/simulation_test/test_oseir.py | 56 ++++++++++--------- .../memilio/simulation_test/test_osir.py | 44 ++++++++------- 6 files changed, 112 insertions(+), 84 deletions(-) diff --git a/pycode/examples/simulation/oseir_simple.py b/pycode/examples/simulation/oseir_simple.py index 96bfe779ab..e2eaf4b60f 100644 --- a/pycode/examples/simulation/oseir_simple.py +++ b/pycode/examples/simulation/oseir_simple.py @@ -21,7 +21,7 @@ import numpy as np -from memilio.simulation import Damping +from memilio.simulation import AgeGroup, Damping from memilio.simulation.oseir import Index_InfectionState from memilio.simulation.oseir import InfectionState as State from memilio.simulation.oseir import (Model, interpolate_simulation_result, @@ -40,26 +40,29 @@ def run_oseir_simulation(): dt = 0.1 # Initialize Parameters - model = Model() + num_groups = 1 + model = Model(num_groups) + A0 = AgeGroup(0) # Compartment transition duration - model.parameters.TimeExposed.value = 5.2 - model.parameters.TimeInfected.value = 6. + model.parameters.TimeExposed[A0] = 6. + model.parameters.TimeInfected[A0] = 6. # Compartment transition propabilities - model.parameters.TransmissionProbabilityOnContact.value = 1. + model.parameters.TransmissionProbabilityOnContact[A0] = 1. # Initial number of people in each compartment - model.populations[Index_InfectionState(State.Exposed)] = 100 - model.populations[Index_InfectionState(State.Infected)] = 50 - model.populations[Index_InfectionState(State.Recovered)] = 10 + model.populations[A0, State.Exposed] = 100 + model.populations[A0, State.Infected] = 50 + model.populations[A0, State.Recovered] = 10 model.populations.set_difference_from_total( - (Index_InfectionState(State.Susceptible)), populations[0]) - - # model.parameters.ContactPatterns = ContactMatrix(np.r_[0.5]) - model.parameters.ContactPatterns.baseline = np.ones((1, 1)) - model.parameters.ContactPatterns.minimum = np.zeros((1, 1)) - model.parameters.ContactPatterns.add_damping( + (A0, State.Susceptible), populations[0]) + + model.parameters.ContactPatterns.cont_freq_mat[0].baseline = np.ones( + (num_groups, num_groups)) + model.parameters.ContactPatterns.cont_freq_mat[0].minimum = np.zeros( + (num_groups, num_groups)) * 0 + model.parameters.ContactPatterns.cont_freq_mat.add_damping( Damping(coeffs=np.r_[0.9], t=30.0, level=0, type=0)) # Check logical constraints to parameters diff --git a/pycode/examples/simulation/osir_simple.py b/pycode/examples/simulation/osir_simple.py index 336603e7cc..7b429d01ea 100644 --- a/pycode/examples/simulation/osir_simple.py +++ b/pycode/examples/simulation/osir_simple.py @@ -21,7 +21,7 @@ import numpy as np -from memilio.simulation import Damping +from memilio.simulation import AgeGroup, Damping from memilio.simulation.osir import Index_InfectionState from memilio.simulation.osir import InfectionState as State from memilio.simulation.osir import (Model, interpolate_simulation_result, @@ -40,24 +40,27 @@ def run_osir_simulation(): dt = 0.1 # Initialize Parameters - model = Model() + num_groups = 1 + model = Model(num_groups) + A0 = AgeGroup(0) # Compartment transition duration - model.parameters.TimeInfected.value = 6. + model.parameters.TimeInfected[A0] = 6. # Compartment transition propabilities - model.parameters.TransmissionProbabilityOnContact.value = 1. + model.parameters.TransmissionProbabilityOnContact[A0] = 1. # Initial number of people in each compartment - model.populations[Index_InfectionState(State.Infected)] = 50 - model.populations[Index_InfectionState(State.Recovered)] = 10 + model.populations[A0, State.Infected] = 50 + model.populations[A0, State.Recovered] = 10 model.populations.set_difference_from_total( - (Index_InfectionState(State.Susceptible)), populations[0]) - - # model.parameters.ContactPatterns = ContactMatrix(np.r_[0.5]) - model.parameters.ContactPatterns.baseline = np.ones((1, 1)) - model.parameters.ContactPatterns.minimum = np.zeros((1, 1)) - model.parameters.ContactPatterns.add_damping( + (A0, State.Susceptible), populations[0]) + + model.parameters.ContactPatterns.cont_freq_mat[0].baseline = np.ones( + (num_groups, num_groups)) * 1 + model.parameters.ContactPatterns.cont_freq_mat[0].minimum = np.ones( + (num_groups, num_groups)) * 0 + model.parameters.ContactPatterns.cont_freq_mat.add_damping( Damping(coeffs=np.r_[0.9], t=30.0, level=0, type=0)) # Check logical constraints to parameters diff --git a/pycode/memilio-simulation/memilio/simulation/oseir.cpp b/pycode/memilio-simulation/memilio/simulation/oseir.cpp index 683c69112c..631402deb4 100755 --- a/pycode/memilio-simulation/memilio/simulation/oseir.cpp +++ b/pycode/memilio-simulation/memilio/simulation/oseir.cpp @@ -41,6 +41,12 @@ std::string pretty_name() return "InfectionState"; } +template <> +std::string pretty_name() +{ + return "AgeGroup"; +} + } // namespace pymio PYBIND11_MODULE(_simulation_oseir, m) @@ -66,15 +72,16 @@ PYBIND11_MODULE(_simulation_oseir, m) pymio::bind_ParameterSet(m, "ParametersBase"); py::class_(m, "Parameters") - .def(py::init<>()) + .def(py::init()) .def("check_constraints", &mio::oseir::Parameters::check_constraints); - using Populations = mio::Populations; - pymio::bind_Population(m, "Population", mio::Tag{}); - pymio::bind_CompartmentalModel(m, "ModelBase"); + using SeirPopulations = mio::Populations; + pymio::bind_Population(m, "SeirPopulations", mio::Tag{}); + + pymio::bind_CompartmentalModel(m, "ModelBase"); py::class_>(m, "Model") - .def(py::init<>()); + mio::CompartmentalModel>(m, "Model") + .def(py::init(), py::arg("num_agegroups")); m.def( "simulate", diff --git a/pycode/memilio-simulation/memilio/simulation/osir.cpp b/pycode/memilio-simulation/memilio/simulation/osir.cpp index 615196c954..1987f34563 100644 --- a/pycode/memilio-simulation/memilio/simulation/osir.cpp +++ b/pycode/memilio-simulation/memilio/simulation/osir.cpp @@ -40,6 +40,12 @@ std::string pretty_name() return "InfectionState"; } +template <> +std::string pretty_name() +{ + return "AgeGroup"; +} + } // namespace pymio PYBIND11_MODULE(_simulation_osir, m) @@ -64,15 +70,16 @@ PYBIND11_MODULE(_simulation_osir, m) pymio::bind_ParameterSet(m, "ParametersBase"); py::class_(m, "Parameters") - .def(py::init<>()) + .def(py::init()) .def("check_constraints", &mio::osir::Parameters::check_constraints); - using Populations = mio::Populations; - pymio::bind_Population(m, "Population", mio::Tag{}); - pymio::bind_CompartmentalModel(m, "ModelBase"); + using SirPopulations = mio::Populations; + pymio::bind_Population(m, "SirPopulations", mio::Tag{}); + + pymio::bind_CompartmentalModel(m, "ModelBase"); py::class_>(m, "Model") - .def(py::init<>()); + mio::CompartmentalModel>(m, "Model") + .def(py::init(), py::arg("num_agegroups")); m.def( "simulate", diff --git a/pycode/memilio-simulation/memilio/simulation_test/test_oseir.py b/pycode/memilio-simulation/memilio/simulation_test/test_oseir.py index 08928fab28..23091288dc 100644 --- a/pycode/memilio-simulation/memilio/simulation_test/test_oseir.py +++ b/pycode/memilio-simulation/memilio/simulation_test/test_oseir.py @@ -23,7 +23,7 @@ import numpy as np import pandas as pd -from memilio.simulation import Damping +from memilio.simulation import AgeGroup, Damping from memilio.simulation.oseir import Index_InfectionState from memilio.simulation.oseir import InfectionState as State from memilio.simulation.oseir import Model, simulate, simulate_flows @@ -35,27 +35,30 @@ class Test_oseir_integration(unittest.TestCase): def setUp(self): - model = Model() + model = Model(1) + A0 = AgeGroup(0) self.t0 = 0. self.tmax = 50. self.dt = 0.1002004008016032 total_population = 1061000 - model.populations[Index_InfectionState(State.Exposed)] = 10000 - model.populations[Index_InfectionState(State.Infected)] = 1000 - model.populations[Index_InfectionState(State.Recovered)] = 1000 + model.populations[A0, State.Exposed] = 10000 + model.populations[A0, State.Infected] = 1000 + model.populations[A0, State.Recovered] = 1000 model.populations.set_difference_from_total( - Index_InfectionState(State.Susceptible), total_population) + (A0, State.Susceptible), total_population) - model.parameters.TransmissionProbabilityOnContact.value = 1. - model.parameters.TimeExposed.value = 5.2 - model.parameters.TimeInfected.value = 2. + model.parameters.TransmissionProbabilityOnContact[A0] = 1. + model.parameters.TimeExposed[A0] = 5.2 + model.parameters.TimeInfected[A0] = 2. - model.parameters.ContactPatterns.baseline = [[2.7]] - model.parameters.ContactPatterns.minimum = np.zeros((1, 1)) - model.parameters.ContactPatterns.add_damping( - Damping(coeffs=[[0.6]], t=12.5, level=0, type=0)) + model.parameters.ContactPatterns.cont_freq_mat[0].baseline = np.ones( + (1, 1)) * 2.7 + model.parameters.ContactPatterns.cont_freq_mat[0].minimum = np.zeros( + (1, 1)) + model.parameters.ContactPatterns.cont_freq_mat.add_damping( + Damping(coeffs=np.r_[0.6], t=12.5, level=0, type=0)) model.check_constraints() @@ -97,7 +100,7 @@ def test_compare_with_cpp(self): self.assertAlmostEqual( t, result.get_time(index_timestep), - delta=1e-12) + delta=1e-10) for index_compartment in range(0, 4): ref = timestep[index_compartment+1] @@ -121,26 +124,27 @@ def test_flow_simulation_simple(self): def test_check_constraints_parameters(self): - model = Model() + model = Model(1) + A0 = AgeGroup(0) - model.parameters.TimeExposed.value = 5.2 - model.parameters.TimeInfected.value = 6. - model.parameters.TransmissionProbabilityOnContact.value = 1. + model.parameters.TimeExposed[A0] = 5.2 + model.parameters.TimeInfected[A0] = 6. + model.parameters.TransmissionProbabilityOnContact[A0] = 1. - model.parameters.TimeExposed.value = 5.2 - model.parameters.TimeInfected.value = 6. - model.parameters.TransmissionProbabilityOnContact.value = 1. + model.parameters.TimeExposed[A0] = 5.2 + model.parameters.TimeInfected[A0] = 6. + model.parameters.TransmissionProbabilityOnContact[A0] = 1. self.assertEqual(model.parameters.check_constraints(), 0) - model.parameters.TimeExposed.value = -1. + model.parameters.TimeExposed[A0] = -1. self.assertEqual(model.parameters.check_constraints(), 1) - model.parameters.TimeExposed.value = 5.2 - model.parameters.TimeInfected.value = 0 + model.parameters.TimeExposed[A0] = 5.2 + model.parameters.TimeInfected[A0] = 0 self.assertEqual(model.parameters.check_constraints(), 1) - model.parameters.TimeInfected.value = 6. - model.parameters.TransmissionProbabilityOnContact.value = -1. + model.parameters.TimeInfected[A0] = 6. + model.parameters.TransmissionProbabilityOnContact[A0] = -1. self.assertEqual(model.parameters.check_constraints(), 1) diff --git a/pycode/memilio-simulation/memilio/simulation_test/test_osir.py b/pycode/memilio-simulation/memilio/simulation_test/test_osir.py index d777ac9b7d..a326fd6f96 100644 --- a/pycode/memilio-simulation/memilio/simulation_test/test_osir.py +++ b/pycode/memilio-simulation/memilio/simulation_test/test_osir.py @@ -21,7 +21,7 @@ import numpy as np -from memilio.simulation import Damping +from memilio.simulation import AgeGroup, Damping from memilio.simulation.osir import Index_InfectionState from memilio.simulation.osir import InfectionState as State from memilio.simulation.osir import Model, simulate @@ -31,19 +31,22 @@ class Test_osir_integration(unittest.TestCase): def setUp(self): - model = Model() + model = Model(1) + A0 = AgeGroup(0) - model.parameters.TimeInfected.value = 6. - model.parameters.TransmissionProbabilityOnContact.value = 1. + model.parameters.TimeInfected[A0] = 6. + model.parameters.TransmissionProbabilityOnContact[A0] = 1. - model.populations[Index_InfectionState(State.Susceptible)] = 4800 - model.populations[Index_InfectionState(State.Infected)] = 50 - model.populations[Index_InfectionState(State.Recovered)] = 50 - - model.parameters.ContactPatterns.baseline = np.ones((1, 1)) - model.parameters.ContactPatterns.minimum = np.zeros((1, 1)) - model.parameters.ContactPatterns.add_damping( - Damping(coeffs=np.r_[0.9], t=30.0, level=0, type=0)) + model.populations[A0, State.Susceptible] = 4800 + model.populations[A0, State.Infected] = 50 + model.populations[A0, State.Recovered] = 50 + + model.parameters.ContactPatterns.cont_freq_mat[0].baseline = np.ones( + (1, 1)) + model.parameters.ContactPatterns.cont_freq_mat[0].minimum = np.zeros( + (1, 1)) + model.parameters.ContactPatterns.cont_freq_mat.add_damping( + Damping(coeffs=np.r_[0.9], t=30.0, level=0, type=0)) model.check_constraints() @@ -57,20 +60,21 @@ def test_simulate_simple(self): def test_check_constraints_parameters(self): - model = Model() + model = Model(1) + A0 = AgeGroup(0) - model.parameters.TimeInfected.value = 6. - model.parameters.TransmissionProbabilityOnContact.value = 1. + model.parameters.TimeInfected[A0] = 6. + model.parameters.TransmissionProbabilityOnContact[A0] = 1. - model.parameters.TimeInfected.value = 6. - model.parameters.TransmissionProbabilityOnContact.value = 1. + model.parameters.TimeInfected[A0] = 6. + model.parameters.TransmissionProbabilityOnContact[A0] = 1. self.assertEqual(model.parameters.check_constraints(), 0) - model.parameters.TimeInfected.value = 0 + model.parameters.TimeInfected[A0] = 0 self.assertEqual(model.parameters.check_constraints(), 1) - model.parameters.TimeInfected.value = 6. - model.parameters.TransmissionProbabilityOnContact.value = -1. + model.parameters.TimeInfected[A0] = 6. + model.parameters.TransmissionProbabilityOnContact[A0] = -1. self.assertEqual(model.parameters.check_constraints(), 1) From 1d1ceec28b3174e229e23c13801a52b793299122 Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Wed, 3 Apr 2024 10:01:48 +0200 Subject: [PATCH 24/34] some formating + print generation --- pycode/examples/simulation/oseir_simple.py | 6 ++--- pycode/examples/simulation/osir_simple.py | 4 +-- .../generation_test/test_oseir_generation.py | 1 + .../memilio/simulation_test/test_oseir.py | 26 +++++++++---------- .../memilio/simulation_test/test_osir.py | 6 ++--- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/pycode/examples/simulation/oseir_simple.py b/pycode/examples/simulation/oseir_simple.py index e2eaf4b60f..0565785e6c 100644 --- a/pycode/examples/simulation/oseir_simple.py +++ b/pycode/examples/simulation/oseir_simple.py @@ -54,12 +54,12 @@ def run_oseir_simulation(): # Initial number of people in each compartment model.populations[A0, State.Exposed] = 100 model.populations[A0, State.Infected] = 50 - model.populations[A0, State.Recovered] = 10 + model.populations[A0, State.Recovered] = 10 model.populations.set_difference_from_total( (A0, State.Susceptible), populations[0]) - + model.parameters.ContactPatterns.cont_freq_mat[0].baseline = np.ones( - (num_groups, num_groups)) + (num_groups, num_groups)) model.parameters.ContactPatterns.cont_freq_mat[0].minimum = np.zeros( (num_groups, num_groups)) * 0 model.parameters.ContactPatterns.cont_freq_mat.add_damping( diff --git a/pycode/examples/simulation/osir_simple.py b/pycode/examples/simulation/osir_simple.py index 7b429d01ea..1eec6cb1ff 100644 --- a/pycode/examples/simulation/osir_simple.py +++ b/pycode/examples/simulation/osir_simple.py @@ -52,10 +52,10 @@ def run_osir_simulation(): # Initial number of people in each compartment model.populations[A0, State.Infected] = 50 - model.populations[A0, State.Recovered] = 10 + model.populations[A0, State.Recovered] = 10 model.populations.set_difference_from_total( (A0, State.Susceptible), populations[0]) - + model.parameters.ContactPatterns.cont_freq_mat[0].baseline = np.ones( (num_groups, num_groups)) * 1 model.parameters.ContactPatterns.cont_freq_mat[0].minimum = np.ones( diff --git a/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py b/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py index 5913acf8de..48666f4add 100644 --- a/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py +++ b/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py @@ -82,6 +82,7 @@ def test_clean_oseir(self): with open(os.path.join(irdata.target_folder, "test_oseir.py")) as result: self.assertEqual(result.read(), self.expected_test_oseir_py) with open(os.path.join(irdata.target_folder, "test_oseir.cpp")) as result: + print(result.read()) self.assertEqual(result.read(), self.expected_test_oseir_cpp) def test_wrong_model_name(self): diff --git a/pycode/memilio-simulation/memilio/simulation_test/test_oseir.py b/pycode/memilio-simulation/memilio/simulation_test/test_oseir.py index 23091288dc..d97021fe7d 100644 --- a/pycode/memilio-simulation/memilio/simulation_test/test_oseir.py +++ b/pycode/memilio-simulation/memilio/simulation_test/test_oseir.py @@ -45,7 +45,7 @@ def setUp(self): model.populations[A0, State.Exposed] = 10000 model.populations[A0, State.Infected] = 1000 - model.populations[A0, State.Recovered] = 1000 + model.populations[A0, State.Recovered] = 1000 model.populations.set_difference_from_total( (A0, State.Susceptible), total_population) @@ -54,9 +54,9 @@ def setUp(self): model.parameters.TimeInfected[A0] = 2. model.parameters.ContactPatterns.cont_freq_mat[0].baseline = np.ones( - (1, 1)) * 2.7 + (1, 1)) * 2.7 model.parameters.ContactPatterns.cont_freq_mat[0].minimum = np.zeros( - (1, 1)) + (1, 1)) model.parameters.ContactPatterns.cont_freq_mat.add_damping( Damping(coeffs=np.r_[0.6], t=12.5, level=0, type=0)) @@ -128,23 +128,23 @@ def test_check_constraints_parameters(self): A0 = AgeGroup(0) model.parameters.TimeExposed[A0] = 5.2 - model.parameters.TimeInfected[A0] = 6. - model.parameters.TransmissionProbabilityOnContact[A0] = 1. + model.parameters.TimeInfected[A0] = 6. + model.parameters.TransmissionProbabilityOnContact[A0] = 1. - model.parameters.TimeExposed[A0] = 5.2 - model.parameters.TimeInfected[A0] = 6. - model.parameters.TransmissionProbabilityOnContact[A0] = 1. + model.parameters.TimeExposed[A0] = 5.2 + model.parameters.TimeInfected[A0] = 6. + model.parameters.TransmissionProbabilityOnContact[A0] = 1. self.assertEqual(model.parameters.check_constraints(), 0) - model.parameters.TimeExposed[A0] = -1. + model.parameters.TimeExposed[A0] = -1. self.assertEqual(model.parameters.check_constraints(), 1) - model.parameters.TimeExposed[A0] = 5.2 - model.parameters.TimeInfected[A0] = 0 + model.parameters.TimeExposed[A0] = 5.2 + model.parameters.TimeInfected[A0] = 0 self.assertEqual(model.parameters.check_constraints(), 1) - model.parameters.TimeInfected[A0] = 6. - model.parameters.TransmissionProbabilityOnContact[A0] = -1. + model.parameters.TimeInfected[A0] = 6. + model.parameters.TransmissionProbabilityOnContact[A0] = -1. self.assertEqual(model.parameters.check_constraints(), 1) diff --git a/pycode/memilio-simulation/memilio/simulation_test/test_osir.py b/pycode/memilio-simulation/memilio/simulation_test/test_osir.py index a326fd6f96..1e1bd1cc1a 100644 --- a/pycode/memilio-simulation/memilio/simulation_test/test_osir.py +++ b/pycode/memilio-simulation/memilio/simulation_test/test_osir.py @@ -39,14 +39,14 @@ def setUp(self): model.populations[A0, State.Susceptible] = 4800 model.populations[A0, State.Infected] = 50 - model.populations[A0, State.Recovered] = 50 - + model.populations[A0, State.Recovered] = 50 + model.parameters.ContactPatterns.cont_freq_mat[0].baseline = np.ones( (1, 1)) model.parameters.ContactPatterns.cont_freq_mat[0].minimum = np.zeros( (1, 1)) model.parameters.ContactPatterns.cont_freq_mat.add_damping( - Damping(coeffs=np.r_[0.9], t=30.0, level=0, type=0)) + Damping(coeffs=np.r_[0.9], t=30.0, level=0, type=0)) model.check_constraints() From 6f2aa0946a1f88182c77fb9ea744847ea2fcbd86 Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Wed, 3 Apr 2024 10:14:18 +0200 Subject: [PATCH 25/34] rm print, adjust tests --- .../generation_test/test_data/test_oseir.cpp.txt | 16 +++++++++++----- .../generation_test/test_oseir_generation.py | 1 - 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pycode/memilio-generation/memilio/generation_test/test_data/test_oseir.cpp.txt b/pycode/memilio-generation/memilio/generation_test/test_data/test_oseir.cpp.txt index 9d230ecb5f..f268ec74d1 100644 --- a/pycode/memilio-generation/memilio/generation_test/test_data/test_oseir.cpp.txt +++ b/pycode/memilio-generation/memilio/generation_test/test_data/test_oseir.cpp.txt @@ -36,6 +36,12 @@ namespace py = pybind11; namespace pymio{ //specialization of pretty_name +template <> +std::string pretty_name() +{ + return "AgeGroup"; +} + template <> std::string pretty_name() { @@ -65,12 +71,12 @@ PYBIND11_MODULE(_simulation_test_oseir, m) .def("check_constraints", &mio::oseir::Parameters::check_constraints) .def("apply_constraints", &mio::oseir::Parameters::apply_constraints); - using Populations = mio::Populations; + using Populations = mio::Populations; pymio::bind_Population(m, "Population", mio::Tag{}); - pymio::bind_CompartmentalModel, mio::oseir::Parameters>(m, "ModelBase"); - py::class_, mio::oseir::Parameters, mio::TypeList, mio::Flow, mio::Flow>>>(m, "Model") - .def(py::init<>()); + pymio::bind_CompartmentalModel, mio::oseir::Parameters>(m, "ModelBase"); + py::class_, mio::oseir::Parameters, mio::TypeList, mio::Flow, mio::Flow>>>(m, "Model") + .def(py::init(), py::arg("num_agegroups")); @@ -85,4 +91,4 @@ PYBIND11_MODULE(_simulation_test_oseir, m) m.attr("__version__") = "dev"; -} +} \ No newline at end of file diff --git a/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py b/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py index 48666f4add..5913acf8de 100644 --- a/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py +++ b/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py @@ -82,7 +82,6 @@ def test_clean_oseir(self): with open(os.path.join(irdata.target_folder, "test_oseir.py")) as result: self.assertEqual(result.read(), self.expected_test_oseir_py) with open(os.path.join(irdata.target_folder, "test_oseir.cpp")) as result: - print(result.read()) self.assertEqual(result.read(), self.expected_test_oseir_cpp) def test_wrong_model_name(self): From ac1c59f1fd50aebe9c3cb583578ba0c036622370 Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Wed, 3 Apr 2024 12:32:51 +0200 Subject: [PATCH 26/34] print results generation --- .../memilio/generation_test/test_oseir_generation.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py b/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py index 5913acf8de..c767af3698 100644 --- a/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py +++ b/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py @@ -82,6 +82,10 @@ def test_clean_oseir(self): with open(os.path.join(irdata.target_folder, "test_oseir.py")) as result: self.assertEqual(result.read(), self.expected_test_oseir_py) with open(os.path.join(irdata.target_folder, "test_oseir.cpp")) as result: + print("------- read -------------") + print(result.read()) + print("------- expected -------------") + print(self.expected_test_oseir_cpp) self.assertEqual(result.read(), self.expected_test_oseir_cpp) def test_wrong_model_name(self): From 83ea5456ea71f51b6b1b7ea922ee9ff865020530 Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Wed, 3 Apr 2024 12:50:51 +0200 Subject: [PATCH 27/34] add space --- .../memilio/generation_test/test_data/test_oseir.cpp.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycode/memilio-generation/memilio/generation_test/test_data/test_oseir.cpp.txt b/pycode/memilio-generation/memilio/generation_test/test_data/test_oseir.cpp.txt index f268ec74d1..432b7e149a 100644 --- a/pycode/memilio-generation/memilio/generation_test/test_data/test_oseir.cpp.txt +++ b/pycode/memilio-generation/memilio/generation_test/test_data/test_oseir.cpp.txt @@ -91,4 +91,4 @@ PYBIND11_MODULE(_simulation_test_oseir, m) m.attr("__version__") = "dev"; -} \ No newline at end of file +} From cca2bab851e2d07d0119689fef22f686e2a3e16d Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Thu, 4 Apr 2024 10:20:53 +0200 Subject: [PATCH 28/34] fix buffer --- .../memilio/generation_test/test_oseir_generation.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py b/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py index c767af3698..5913acf8de 100644 --- a/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py +++ b/pycode/memilio-generation/memilio/generation_test/test_oseir_generation.py @@ -82,10 +82,6 @@ def test_clean_oseir(self): with open(os.path.join(irdata.target_folder, "test_oseir.py")) as result: self.assertEqual(result.read(), self.expected_test_oseir_py) with open(os.path.join(irdata.target_folder, "test_oseir.cpp")) as result: - print("------- read -------------") - print(result.read()) - print("------- expected -------------") - print(self.expected_test_oseir_cpp) self.assertEqual(result.read(), self.expected_test_oseir_cpp) def test_wrong_model_name(self): From 92108611be7d2f2edb602325de680501852fc67b Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Thu, 4 Apr 2024 11:21:16 +0200 Subject: [PATCH 29/34] rm space gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 412c0bd65d..f4ff6a4b0f 100644 --- a/.gitignore +++ b/.gitignore @@ -278,4 +278,4 @@ pycode/memilio-epidata/memilio/epidata/CredentialsRegio.ini docs/html docs/xml -# End of https://www.gitignore.io/api/c++,node,python +# End of https://www.gitignore.io/api/c++,node,python \ No newline at end of file From 622b7ad67bffb23818766fd1bf47d4b3b2af58c0 Mon Sep 17 00:00:00 2001 From: Henrik Zunker <69154294+HenrZu@users.noreply.github.com> Date: Tue, 23 Apr 2024 08:16:20 +0200 Subject: [PATCH 30/34] Update cpp/examples/ode_seir.cpp Co-authored-by: jubicker <113909589+jubicker@users.noreply.github.com> --- cpp/examples/ode_seir.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/examples/ode_seir.cpp b/cpp/examples/ode_seir.cpp index 4af8579b27..b81c9565e9 100644 --- a/cpp/examples/ode_seir.cpp +++ b/cpp/examples/ode_seir.cpp @@ -51,7 +51,8 @@ int main() model.parameters.set(0.1); mio::ContactMatrixGroup& contact_matrix = model.parameters.get(); - contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 2.7)); + contact_matrix[0].get_baseline().setConstant(2.7); + contact_matrix[0].add_damping(0.7, mio::SimulationTime(30.)); contact_matrix.add_damping(Eigen::MatrixXd::Constant(1, 1, 0.7), mio::SimulationTime(30.)); model.check_constraints(); From 99aec4c7aa80d35c88b0902f8afdd6f528084090 Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Tue, 23 Apr 2024 08:23:04 +0200 Subject: [PATCH 31/34] fixes from review --- cpp/examples/ode_seir_ageres.cpp | 2 +- cpp/examples/ode_seir_flows.cpp | 11 ++++------- cpp/examples/ode_sir.cpp | 2 +- cpp/tests/test_odeseir.cpp | 3 +-- pycode/examples/simulation/oseir_simple.py | 4 ++-- pycode/examples/simulation/osir_simple.py | 6 +++--- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/cpp/examples/ode_seir_ageres.cpp b/cpp/examples/ode_seir_ageres.cpp index 520555516d..03925413e5 100644 --- a/cpp/examples/ode_seir_ageres.cpp +++ b/cpp/examples/ode_seir_ageres.cpp @@ -9,7 +9,7 @@ int main() mio::set_log_level(mio::LogLevel::debug); double t0 = 0; - double tmax = 1; + double tmax = 50; double dt = 0.001; mio::log_info("Simulating SEIR; t={} ... {} with dt = {}.", t0, tmax, dt); diff --git a/cpp/examples/ode_seir_flows.cpp b/cpp/examples/ode_seir_flows.cpp index c4df2330fa..9e3adf5a28 100644 --- a/cpp/examples/ode_seir_flows.cpp +++ b/cpp/examples/ode_seir_flows.cpp @@ -40,16 +40,13 @@ int main() mio::oseir::Model model(1); - double total_population = 10000; + constexpr double 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}]; - // suscetible now set with every other update - // params.nb_sus_t0 = params.nb_total_t0 - params.nb_exp_t0 - params.nb_inf_t0 - params.nb_rec_t0; + model.populations.set_difference_from_group_total( + {mio::AgeGroup(0), mio::oseir::InfectionState::Susceptible}, total_population); + model.parameters.set(5.2); model.parameters.set(6); model.parameters.set(0.04); diff --git a/cpp/examples/ode_sir.cpp b/cpp/examples/ode_sir.cpp index 6440bd52f3..4b6769c5a5 100644 --- a/cpp/examples/ode_sir.cpp +++ b/cpp/examples/ode_sir.cpp @@ -47,7 +47,7 @@ int main() total_population - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}]; model.parameters.set(2); - model.parameters.set(1); + model.parameters.set(0.5); mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); contact_matrix[0].get_baseline().setConstant(2.7); diff --git a/cpp/tests/test_odeseir.cpp b/cpp/tests/test_odeseir.cpp index d3caab9c49..7bfd4cd014 100644 --- a/cpp/tests/test_odeseir.cpp +++ b/cpp/tests/test_odeseir.cpp @@ -324,11 +324,10 @@ TEST(TestSeir, get_derivatives) contact_matrix[0].get_baseline().setConstant(10); model.check_constraints(); - // print_seir_params(model); auto seir = simulate(t0, tmax, dt, model); - auto dydt_default = Eigen::VectorXd(Eigen::Index(mio::oseir::InfectionState::Count)); + auto dydt_default = Eigen::VectorXd(Eigen::Index(mio::oseir::InfectionState::Count)); dydt_default.setZero(); Eigen::VectorXd y0 = seir.get_value(0); model.get_derivatives(y0, y0, 0, dydt_default); diff --git a/pycode/examples/simulation/oseir_simple.py b/pycode/examples/simulation/oseir_simple.py index 0565785e6c..4d01d40e29 100644 --- a/pycode/examples/simulation/oseir_simple.py +++ b/pycode/examples/simulation/oseir_simple.py @@ -45,7 +45,7 @@ def run_oseir_simulation(): A0 = AgeGroup(0) # Compartment transition duration - model.parameters.TimeExposed[A0] = 6. + model.parameters.TimeExposed[A0] = 5.2 model.parameters.TimeInfected[A0] = 6. # Compartment transition propabilities @@ -61,7 +61,7 @@ def run_oseir_simulation(): model.parameters.ContactPatterns.cont_freq_mat[0].baseline = np.ones( (num_groups, num_groups)) model.parameters.ContactPatterns.cont_freq_mat[0].minimum = np.zeros( - (num_groups, num_groups)) * 0 + (num_groups, num_groups)) model.parameters.ContactPatterns.cont_freq_mat.add_damping( Damping(coeffs=np.r_[0.9], t=30.0, level=0, type=0)) diff --git a/pycode/examples/simulation/osir_simple.py b/pycode/examples/simulation/osir_simple.py index 1eec6cb1ff..1f28c6f809 100644 --- a/pycode/examples/simulation/osir_simple.py +++ b/pycode/examples/simulation/osir_simple.py @@ -57,9 +57,9 @@ def run_osir_simulation(): (A0, State.Susceptible), populations[0]) model.parameters.ContactPatterns.cont_freq_mat[0].baseline = np.ones( - (num_groups, num_groups)) * 1 - model.parameters.ContactPatterns.cont_freq_mat[0].minimum = np.ones( - (num_groups, num_groups)) * 0 + (num_groups, num_groups)) + model.parameters.ContactPatterns.cont_freq_mat[0].minimum = np.zeros( + (num_groups, num_groups)) model.parameters.ContactPatterns.cont_freq_mat.add_damping( Damping(coeffs=np.r_[0.9], t=30.0, level=0, type=0)) From 266ac20c9bf21c1be2f22b071f16a0baf02fe61f Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Thu, 25 Apr 2024 09:29:08 +0200 Subject: [PATCH 32/34] more extensive testing of simulation and get_flows --- cpp/tests/test_odeseir.cpp | 111 ++++++++++++++++++++++++++++++------- cpp/tests/test_odesir.cpp | 66 ++++++++++++++-------- 2 files changed, 135 insertions(+), 42 deletions(-) diff --git a/cpp/tests/test_odeseir.cpp b/cpp/tests/test_odeseir.cpp index 7bfd4cd014..21ff5ac666 100644 --- a/cpp/tests/test_odeseir.cpp +++ b/cpp/tests/test_odeseir.cpp @@ -296,19 +296,46 @@ TEST(TestOdeSeir, get_reproduction_number) EXPECT_NEAR(model.get_reproduction_number(0.9, result).value(), 1.858670429549998504, 1e-12); } -TEST(TestSeir, get_derivatives) +TEST(TestSeir, get_flows) { + mio::oseir::Model model(1); + + constexpr double total_population = 400; + + 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}]; - // Test, that in the case of one agegroup, the simulation is the same as before the implementation of agegroups - // This test is independent of the integrator used. + model.parameters.set(2); + model.parameters.set(4); + model.parameters.set(1); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(1); + model.check_constraints(); + + auto dydt_default = Eigen::VectorXd(3); + dydt_default.setZero(); + auto y0 = model.get_initial_values(); + model.get_flows(y0, y0, 0, dydt_default); + + EXPECT_NEAR(dydt_default[0], 25, 1e-12); + EXPECT_NEAR(dydt_default[1], 50, 1e-12); + EXPECT_NEAR(dydt_default[2], 25, 1e-12); +} + +TEST(TestSeir, Simulation) +{ double t0 = 0; double tmax = 1; - double dt = 0.001; + double dt = 1; mio::oseir::Model model(1); - double total_population = 10000; - + constexpr double total_population = 400; 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; @@ -317,23 +344,69 @@ TEST(TestSeir, get_derivatives) model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Infected}] - model.populations[{mio::AgeGroup(0), mio::oseir::InfectionState::Recovered}]; - model.parameters.set(5.2); - model.parameters.set(6); - model.parameters.set(0.04); + model.parameters.set(2); + model.parameters.set(4); + model.parameters.set(1); mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); - contact_matrix[0].get_baseline().setConstant(10); + contact_matrix[0].get_baseline().setConstant(1); model.check_constraints(); - auto seir = simulate(t0, tmax, dt, model); + auto integrator = std::make_shared(); - auto dydt_default = Eigen::VectorXd(Eigen::Index(mio::oseir::InfectionState::Count)); - dydt_default.setZero(); - Eigen::VectorXd y0 = seir.get_value(0); - model.get_derivatives(y0, y0, 0, dydt_default); + auto sim = simulate(t0, tmax, dt, model, integrator); + + EXPECT_EQ(sim.get_num_time_points(), 2); + + const auto& results_t1 = sim.get_last_value(); + EXPECT_NEAR(results_t1[0], 75, 1e-12); + EXPECT_NEAR(results_t1[1], 75, 1e-12); + EXPECT_NEAR(results_t1[2], 125, 1e-12); + EXPECT_NEAR(results_t1[3], 125, 1e-12); +} + +TEST(TestSeir, FlowSimulation) +{ + double t0 = 0; + double tmax = 1; + double dt = 1; + + mio::oseir::Model model(1); + + constexpr double total_population = 400; + 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}]; + + model.parameters.set(2); + model.parameters.set(4); + model.parameters.set(1); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(1); + + model.check_constraints(); - EXPECT_NEAR(dydt_default[0], -38.8, 1e-12); - EXPECT_NEAR(dydt_default[1], 19.56923076923077, 1e-12); - EXPECT_NEAR(dydt_default[2], 2.564102564102566, 1e-12); - EXPECT_NEAR(dydt_default[3], 16.66666666666666, 1e-12); + auto integrator = std::make_shared(); + + auto sim = simulate_flows(t0, tmax, dt, model, integrator); + + // results + EXPECT_EQ(sim[0].get_num_time_points(), 2); + const auto& results_t1 = sim[0].get_last_value(); + EXPECT_NEAR(results_t1[0], 75, 1e-12); + EXPECT_NEAR(results_t1[1], 75, 1e-12); + EXPECT_NEAR(results_t1[2], 125, 1e-12); + EXPECT_NEAR(results_t1[3], 125, 1e-12); + + // flows + EXPECT_EQ(sim[1].get_num_time_points(), 2); + sim[1].print_table(); + const auto& flows_t1 = sim[1].get_last_value(); + EXPECT_NEAR(flows_t1[0], 25, 1e-12); + EXPECT_NEAR(flows_t1[1], 50, 1e-12); + EXPECT_NEAR(flows_t1[2], 25, 1e-12); } diff --git a/cpp/tests/test_odesir.cpp b/cpp/tests/test_odesir.cpp index b322443cea..f920d5e062 100644 --- a/cpp/tests/test_odesir.cpp +++ b/cpp/tests/test_odesir.cpp @@ -183,41 +183,61 @@ TEST(TestOdeSir, apply_constraints_parameters) mio::set_log_level(mio::LogLevel::warn); } -TEST(Testsir, get_derivatives_agegrp_compare) +TEST(Testsir, get_flows) { - // Test, that in the case of one age group, the simulation is the same as before the implementation of agegroups - // This test is independent of the integrator used. - double t0 = 0.; - double tmax = 50.; - double dt = 0.1002004008016032; - - double total_population = 1061000; - mio::osir::Model model(1); - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] = 1000; - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}] = 1000; + constexpr auto total_population = 400; + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] = 100; + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}] = 100; model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Susceptible}] = total_population - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}]; - model.parameters.set(2); + + model.parameters.set(4); model.parameters.set(1); 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.6, mio::SimulationTime(12.5)); + contact_matrix[0].get_baseline().setConstant(1); + model.check_constraints(); - auto integrator = std::make_shared(); + auto dydt_default = Eigen::VectorXd(Eigen::Index(mio::osir::InfectionState::Count)); + dydt_default.setZero(); + auto y0 = model.get_initial_values(); + model.get_derivatives(y0, y0, 0, dydt_default); + EXPECT_NEAR(dydt_default[0], -50, 1e-12); + EXPECT_NEAR(dydt_default[1], 25, 1e-12); + EXPECT_NEAR(dydt_default[2], 25, 1e-12); +} + +TEST(Testsir, Simulation) +{ + double t0 = 0; + double tmax = 1; + double dt = 1; + + mio::osir::Model model(1); + + constexpr auto total_population = 400; + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] = 100; + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}] = 100; + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Susceptible}] = + total_population - model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Infected}] - + model.populations[{mio::AgeGroup(0), mio::osir::InfectionState::Recovered}]; + + model.parameters.set(4); + model.parameters.set(1); + mio::ContactMatrixGroup& contact_matrix = model.parameters.get().get_cont_freq_mat(); + contact_matrix[0].get_baseline().setConstant(1); model.check_constraints(); - auto sir = simulate(t0, tmax, dt, model, integrator); + auto integrator = std::make_shared(); + auto sim = simulate(t0, tmax, dt, model, integrator); - auto dydt_default = Eigen::VectorXd(Eigen::Index(mio::osir::InfectionState::Count)); - dydt_default.setZero(); - Eigen::VectorXd y0 = sir.get_value(0); - model.get_derivatives(y0, y0, 0, dydt_default); + EXPECT_EQ(sim.get_num_time_points(), 2); - EXPECT_NEAR(dydt_default[0], -2694.9104618284641, 1e-12); - EXPECT_NEAR(dydt_default[1], 2194.9104618284641, 1e-12); - EXPECT_NEAR(dydt_default[2], 500, 1e-12); + const auto& results_t1 = sim.get_last_value(); + EXPECT_NEAR(results_t1[0], 150, 1e-12); + EXPECT_NEAR(results_t1[1], 125, 1e-12); + EXPECT_NEAR(results_t1[2], 125, 1e-12); } \ No newline at end of file From 140942d13d3a588d22f6c64b40c7cf36cdbbc9f8 Mon Sep 17 00:00:00 2001 From: Henrik Zunker <69154294+HenrZu@users.noreply.github.com> Date: Mon, 29 Apr 2024 15:59:57 +0200 Subject: [PATCH 33/34] Update cpp/examples/ode_seir.cpp Co-authored-by: jubicker <113909589+jubicker@users.noreply.github.com> --- cpp/examples/ode_seir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/examples/ode_seir.cpp b/cpp/examples/ode_seir.cpp index f8a03eaaee..ad21bc76fb 100644 --- a/cpp/examples/ode_seir.cpp +++ b/cpp/examples/ode_seir.cpp @@ -53,7 +53,7 @@ int main() 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.add_damping(Eigen::MatrixXd::Constant(1, 1, 0.7), mio::SimulationTime(30.)); + model.check_constraints(); From 4e874c9e58c8fb1e621ba697a25e9be5a599a396 Mon Sep 17 00:00:00 2001 From: HenrZu <69154294+HenrZu@users.noreply.github.com> Date: Mon, 29 Apr 2024 16:06:09 +0200 Subject: [PATCH 34/34] naming --- cpp/tests/test_odesir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/tests/test_odesir.cpp b/cpp/tests/test_odesir.cpp index f920d5e062..bd9233b0b1 100644 --- a/cpp/tests/test_odesir.cpp +++ b/cpp/tests/test_odesir.cpp @@ -183,7 +183,7 @@ TEST(TestOdeSir, apply_constraints_parameters) mio::set_log_level(mio::LogLevel::warn); } -TEST(Testsir, get_flows) +TEST(Testsir, get_derivatives) { mio::osir::Model model(1);