Skip to content

Commit f9b7610

Browse files
HenrZureneSchmmknaranja
authored
323 SECIRTS model with waning and temporary immunity (#963)
- Add new ODE model including waning immunity and temporary immunity states build upon the secirvvs model - New initialization method - Allow to read booster vaccinations as optional args from vaccination data in cpp Co-authored-by: reneSchm <[email protected]> Co-authored-by: Martin J. Kühn <[email protected]>
1 parent 3a06d82 commit f9b7610

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+24661
-17865
lines changed

cpp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ add_subdirectory(memilio)
150150
if(MEMILIO_BUILD_MODELS)
151151
add_subdirectory(models/abm)
152152
add_subdirectory(models/ode_secir)
153+
add_subdirectory(models/ode_secirts)
153154
add_subdirectory(models/ode_secirvvs)
154155
add_subdirectory(models/lct_secir)
155156
add_subdirectory(models/glct_secir)

cpp/benchmarks/flow_simulation_ode_secirvvs.h

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -486,15 +486,17 @@ class Simulation : public Base
486486
double first_vacc;
487487
double full_vacc;
488488
if (t_idx == SimulationDay(0)) {
489-
first_vacc = params.template get<osecirvvs::DailyFirstVaccination<ScalarType>>()[{(AgeGroup)i, t_idx}];
490-
full_vacc = params.template get<osecirvvs::DailyFullVaccination<ScalarType>>()[{(AgeGroup)i, t_idx}];
489+
first_vacc =
490+
params.template get<osecirvvs::DailyPartialVaccinations<ScalarType>>()[{(AgeGroup)i, t_idx}];
491+
full_vacc = params.template get<osecirvvs::DailyFullVaccinations<ScalarType>>()[{(AgeGroup)i, t_idx}];
491492
}
492493
else {
493-
first_vacc = params.template get<osecirvvs::DailyFirstVaccination<ScalarType>>()[{(AgeGroup)i, t_idx}] -
494-
params.template get<osecirvvs::DailyFirstVaccination<ScalarType>>()[{
495-
(AgeGroup)i, t_idx - SimulationDay(1)}];
496-
full_vacc = params.template get<osecirvvs::DailyFullVaccination<ScalarType>>()[{(AgeGroup)i, t_idx}] -
497-
params.template get<osecirvvs::DailyFullVaccination<ScalarType>>()[{
494+
first_vacc =
495+
params.template get<osecirvvs::DailyPartialVaccinations<ScalarType>>()[{(AgeGroup)i, t_idx}] -
496+
params.template get<osecirvvs::DailyPartialVaccinations<ScalarType>>()[{(AgeGroup)i,
497+
t_idx - SimulationDay(1)}];
498+
full_vacc = params.template get<osecirvvs::DailyFullVaccinations<ScalarType>>()[{(AgeGroup)i, t_idx}] -
499+
params.template get<osecirvvs::DailyFullVaccinations<ScalarType>>()[{
498500
(AgeGroup)i, t_idx - SimulationDay(1)}];
499501
}
500502

@@ -665,10 +667,11 @@ void setup_model(Model& model)
665667

666668
model.parameters.template get<osecirvvs::ICUCapacity<ScalarType>>() = 100;
667669
model.parameters.template get<osecirvvs::TestAndTraceCapacity<ScalarType>>() = 0.0143;
668-
model.parameters.template get<osecirvvs::DailyFirstVaccination<ScalarType>>().resize(SimulationDay(size_t(1000)));
669-
model.parameters.template get<osecirvvs::DailyFirstVaccination<ScalarType>>().array().setConstant(5);
670-
model.parameters.template get<osecirvvs::DailyFullVaccination<ScalarType>>().resize(SimulationDay(size_t(1000)));
671-
model.parameters.template get<osecirvvs::DailyFullVaccination<ScalarType>>().array().setConstant(3);
670+
model.parameters.template get<osecirvvs::DailyPartialVaccinations<ScalarType>>().resize(
671+
SimulationDay(size_t(1000)));
672+
model.parameters.template get<osecirvvs::DailyPartialVaccinations<ScalarType>>().array().setConstant(5);
673+
model.parameters.template get<osecirvvs::DailyFullVaccinations<ScalarType>>().resize(SimulationDay(size_t(1000)));
674+
model.parameters.template get<osecirvvs::DailyFullVaccinations<ScalarType>>().array().setConstant(3);
672675

673676
auto& contacts = model.parameters.template get<osecirvvs::ContactPatterns<ScalarType>>();
674677
auto& contact_matrix = contacts.get_cont_freq_mat();

cpp/benchmarks/graph_simulation.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ mio::osecirvvs::Model<ScalarType> create_model(size_t num_agegroups, const Scala
6969
const size_t vacc_full = 5;
7070
model.parameters.get<mio::osecirvvs::ICUCapacity<ScalarType>>() = 100;
7171
model.parameters.get<mio::osecirvvs::TestAndTraceCapacity<ScalarType>>() = 0.0143;
72-
model.parameters.get<mio::osecirvvs::DailyFirstVaccination<ScalarType>>().resize(mio::SimulationDay(tmax));
73-
model.parameters.get<mio::osecirvvs::DailyFirstVaccination<ScalarType>>().array().setConstant(vacc_first);
74-
model.parameters.get<mio::osecirvvs::DailyFullVaccination<ScalarType>>().resize(mio::SimulationDay(tmax));
75-
model.parameters.get<mio::osecirvvs::DailyFullVaccination<ScalarType>>().array().setConstant(vacc_full);
72+
model.parameters.get<mio::osecirvvs::DailyPartialVaccinations<ScalarType>>().resize(mio::SimulationDay(tmax));
73+
model.parameters.get<mio::osecirvvs::DailyPartialVaccinations<ScalarType>>().array().setConstant(vacc_first);
74+
model.parameters.get<mio::osecirvvs::DailyFullVaccinations<ScalarType>>().resize(mio::SimulationDay(tmax));
75+
model.parameters.get<mio::osecirvvs::DailyFullVaccinations<ScalarType>>().array().setConstant(vacc_full);
7676

7777
auto& contacts = model.parameters.get<mio::osecirvvs::ContactPatterns<ScalarType>>();
7878
auto& contact_matrix = contacts.get_cont_freq_mat();

cpp/examples/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ add_executable(ode_secirvvs_example ode_secirvvs.cpp)
7676
target_link_libraries(ode_secirvvs_example PRIVATE memilio ode_secirvvs)
7777
target_compile_options(ode_secirvvs_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS})
7878

79+
add_executable(ode_secirts_example ode_secirts.cpp)
80+
target_link_libraries(ode_secirts_example PRIVATE memilio ode_secirts)
81+
target_compile_options(ode_secirts_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS})
82+
7983
add_executable(ode_secir_ageres_example ode_secir_ageres.cpp)
8084
target_link_libraries(ode_secir_ageres_example PRIVATE memilio ode_secir)
8185
target_compile_options(ode_secir_ageres_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS})

cpp/examples/ode_secirts.cpp

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright (C) 2020-2024 MEmilio
3+
*
4+
* Authors: Henrik Zunker
5+
*
6+
* Contact: Martin J. Kuehn <[email protected]>
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
#include "ode_secirts/analyze_result.h"
21+
#include "ode_secirts/model.h"
22+
#include "ode_secirts/parameters.h"
23+
#include "memilio/compartments/simulation.h"
24+
#include "memilio/utils/logging.h"
25+
26+
int main()
27+
{
28+
// This example demonstrates how to simulate a SECIRTS model.
29+
// The SECIRTS model is an extension of the SECIRVVS model that includes waning and temporary immunity.
30+
// After the simulation, the aggregated size of the temporary immunity states are printed.
31+
mio::set_log_level(mio::LogLevel::debug);
32+
33+
double t0 = 0;
34+
double tmax = 100;
35+
double dt = 0.1;
36+
37+
mio::log_info("Simulating SECIRTS; t={} ... {} with dt = {}.", t0, tmax, dt);
38+
39+
mio::osecirts::Model<double> model(3);
40+
auto nb_groups = model.parameters.get_num_groups();
41+
42+
for (mio::AgeGroup i = 0; i < nb_groups; i++) {
43+
// population
44+
model.populations[{i, mio::osecirts::InfectionState::ExposedNaive}] = 20;
45+
model.populations[{i, mio::osecirts::InfectionState::ExposedImprovedImmunity}] = 20;
46+
model.populations[{i, mio::osecirts::InfectionState::ExposedPartialImmunity}] = 20;
47+
model.populations[{i, mio::osecirts::InfectionState::InfectedNoSymptomsNaive}] = 30;
48+
model.populations[{i, mio::osecirts::InfectionState::InfectedNoSymptomsNaiveConfirmed}] = 0;
49+
model.populations[{i, mio::osecirts::InfectionState::InfectedNoSymptomsPartialImmunity}] = 30;
50+
model.populations[{i, mio::osecirts::InfectionState::InfectedNoSymptomsPartialImmunityConfirmed}] = 0;
51+
model.populations[{i, mio::osecirts::InfectionState::InfectedNoSymptomsImprovedImmunity}] = 30;
52+
model.populations[{i, mio::osecirts::InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed}] = 0;
53+
model.populations[{i, mio::osecirts::InfectionState::InfectedSymptomsNaive}] = 40;
54+
model.populations[{i, mio::osecirts::InfectionState::InfectedSymptomsNaiveConfirmed}] = 0;
55+
model.populations[{i, mio::osecirts::InfectionState::InfectedSymptomsPartialImmunity}] = 40;
56+
model.populations[{i, mio::osecirts::InfectionState::InfectedSymptomsPartialImmunityConfirmed}] = 0;
57+
model.populations[{i, mio::osecirts::InfectionState::InfectedSymptomsImprovedImmunity}] = 40;
58+
model.populations[{i, mio::osecirts::InfectionState::InfectedSymptomsImprovedImmunityConfirmed}] = 0;
59+
model.populations[{i, mio::osecirts::InfectionState::InfectedSevereNaive}] = 30;
60+
model.populations[{i, mio::osecirts::InfectionState::InfectedSevereImprovedImmunity}] = 30;
61+
model.populations[{i, mio::osecirts::InfectionState::InfectedSeverePartialImmunity}] = 30;
62+
model.populations[{i, mio::osecirts::InfectionState::InfectedCriticalNaive}] = 20;
63+
model.populations[{i, mio::osecirts::InfectionState::InfectedCriticalPartialImmunity}] = 20;
64+
model.populations[{i, mio::osecirts::InfectionState::InfectedCriticalImprovedImmunity}] = 20;
65+
model.populations[{i, mio::osecirts::InfectionState::SusceptibleNaive}] = 1000;
66+
model.populations[{i, mio::osecirts::InfectionState::SusceptiblePartialImmunity}] = 1200;
67+
model.populations[{i, mio::osecirts::InfectionState::SusceptibleImprovedImmunity}] = 1000;
68+
model.populations[{i, mio::osecirts::InfectionState::TemporaryImmunePartialImmunity}] = 60;
69+
model.populations[{i, mio::osecirts::InfectionState::TemporaryImmuneImprovedImmunity}] = 70;
70+
model.populations[{i, mio::osecirts::InfectionState::DeadNaive}] = 0;
71+
model.populations[{i, mio::osecirts::InfectionState::DeadPartialImmunity}] = 0;
72+
model.populations[{i, mio::osecirts::InfectionState::DeadImprovedImmunity}] = 0;
73+
74+
// parameters
75+
//times
76+
model.parameters.get<mio::osecirts::TimeExposed<double>>()[i] = 3.33;
77+
model.parameters.get<mio::osecirts::TimeInfectedNoSymptoms<double>>()[i] = 1.87;
78+
model.parameters.get<mio::osecirts::TimeInfectedSymptoms<double>>()[i] = 7;
79+
model.parameters.get<mio::osecirts::TimeInfectedSevere<double>>()[i] = 6;
80+
model.parameters.get<mio::osecirts::TimeInfectedCritical<double>>()[i] = 7;
81+
model.parameters.get<mio::osecirts::TimeTemporaryImmunityPI<double>>()[i] = 60;
82+
model.parameters.get<mio::osecirts::TimeTemporaryImmunityII<double>>()[i] = 60;
83+
model.parameters.get<mio::osecirts::TimeWaningPartialImmunity<double>>()[i] = 180;
84+
model.parameters.get<mio::osecirts::TimeWaningImprovedImmunity<double>>()[i] = 180;
85+
86+
//probabilities
87+
model.parameters.get<mio::osecirts::TransmissionProbabilityOnContact<double>>()[i] = 0.15;
88+
model.parameters.get<mio::osecirts::RelativeTransmissionNoSymptoms<double>>()[i] = 0.5;
89+
model.parameters.get<mio::osecirts::RiskOfInfectionFromSymptomatic<double>>()[i] = 0.0;
90+
model.parameters.get<mio::osecirts::MaxRiskOfInfectionFromSymptomatic<double>>()[i] = 0.4;
91+
model.parameters.get<mio::osecirts::RecoveredPerInfectedNoSymptoms<double>>()[i] = 0.2;
92+
model.parameters.get<mio::osecirts::SeverePerInfectedSymptoms<double>>()[i] = 0.1;
93+
model.parameters.get<mio::osecirts::CriticalPerSevere<double>>()[i] = 0.1;
94+
model.parameters.get<mio::osecirts::DeathsPerCritical<double>>()[i] = 0.1;
95+
96+
model.parameters.get<mio::osecirts::ReducExposedPartialImmunity<double>>()[i] = 0.8;
97+
model.parameters.get<mio::osecirts::ReducExposedImprovedImmunity<double>>()[i] = 0.331;
98+
model.parameters.get<mio::osecirts::ReducInfectedSymptomsPartialImmunity<double>>()[i] = 0.65;
99+
model.parameters.get<mio::osecirts::ReducInfectedSymptomsImprovedImmunity<double>>()[i] = 0.243;
100+
model.parameters.get<mio::osecirts::ReducInfectedSevereCriticalDeadPartialImmunity<double>>()[i] = 0.1;
101+
model.parameters.get<mio::osecirts::ReducInfectedSevereCriticalDeadImprovedImmunity<double>>()[i] = 0.091;
102+
model.parameters.get<mio::osecirts::ReducTimeInfectedMild<double>>()[i] = 0.9;
103+
}
104+
105+
model.parameters.get<mio::osecirts::ICUCapacity<double>>() = 100;
106+
model.parameters.get<mio::osecirts::TestAndTraceCapacity<double>>() = 0.0143;
107+
const size_t daily_vaccinations = 10;
108+
const size_t num_days = 300;
109+
model.parameters.get<mio::osecirts::DailyPartialVaccinations<double>>().resize(mio::SimulationDay(num_days));
110+
model.parameters.get<mio::osecirts::DailyFullVaccinations<double>>().resize(mio::SimulationDay(num_days));
111+
model.parameters.get<mio::osecirts::DailyBoosterVaccinations<double>>().resize(mio::SimulationDay(num_days));
112+
for (size_t i = 0; i < num_days; ++i) {
113+
for (mio::AgeGroup j = 0; j < nb_groups; ++j) {
114+
auto num_vaccinations = static_cast<double>(i * daily_vaccinations);
115+
model.parameters.get<mio::osecirts::DailyPartialVaccinations<double>>()[{j, mio::SimulationDay(i)}] =
116+
num_vaccinations;
117+
model.parameters.get<mio::osecirts::DailyFullVaccinations<double>>()[{j, mio::SimulationDay(i)}] =
118+
num_vaccinations;
119+
model.parameters.get<mio::osecirts::DailyBoosterVaccinations<double>>()[{j, mio::SimulationDay(i)}] =
120+
num_vaccinations;
121+
}
122+
}
123+
124+
mio::ContactMatrixGroup& contact_matrix = model.parameters.get<mio::osecirts::ContactPatterns<double>>();
125+
const double cont_freq = 10;
126+
const double fact = 1.0 / (double)(size_t)nb_groups;
127+
contact_matrix[0] =
128+
mio::ContactMatrix(Eigen::MatrixXd::Constant((size_t)nb_groups, (size_t)nb_groups, fact * cont_freq));
129+
contact_matrix.add_damping(Eigen::MatrixXd::Constant((size_t)nb_groups, (size_t)nb_groups, 0.7),
130+
mio::SimulationTime(30.));
131+
132+
model.parameters.get<mio::osecirts::Seasonality<double>>() = 0.2;
133+
134+
model.apply_constraints();
135+
136+
mio::TimeSeries<double> result = simulate(t0, tmax, dt, model);
137+
138+
bool print_to_terminal = true;
139+
140+
if (print_to_terminal) {
141+
auto result_interpolated = mio::interpolate_simulation_result(result);
142+
for (auto t_indx = 0; t_indx < result_interpolated.get_num_time_points(); t_indx++) {
143+
double timm_pi = 0.0;
144+
double timm_ii = 0.0;
145+
for (mio::AgeGroup i = 0; i < nb_groups; i++) {
146+
timm_pi += result_interpolated.get_value(t_indx)[model.populations.get_flat_index(
147+
{i, mio::osecirts::InfectionState::TemporaryImmunePartialImmunity})];
148+
timm_ii += result_interpolated.get_value(t_indx)[model.populations.get_flat_index(
149+
{i, mio::osecirts::InfectionState::TemporaryImmuneImprovedImmunity})];
150+
}
151+
printf("t=%i, timm_pi=%f, timm_ii=%f\n", int(result_interpolated.get_time(t_indx)), timm_pi, timm_ii);
152+
}
153+
}
154+
}

cpp/examples/ode_secirvvs.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,16 @@ int main()
6767
model.parameters.get<mio::osecirvvs::ICUCapacity<double>>() = 100;
6868
model.parameters.get<mio::osecirvvs::TestAndTraceCapacity<double>>() = 0.0143;
6969
const size_t daily_vaccinations = 10;
70-
model.parameters.get<mio::osecirvvs::DailyFirstVaccination<double>>().resize(mio::SimulationDay((size_t)tmax + 1));
71-
model.parameters.get<mio::osecirvvs::DailyFullVaccination<double>>().resize(mio::SimulationDay((size_t)tmax + 1));
70+
model.parameters.get<mio::osecirvvs::DailyPartialVaccinations<double>>().resize(
71+
mio::SimulationDay((size_t)tmax + 1));
72+
model.parameters.get<mio::osecirvvs::DailyFullVaccinations<double>>().resize(mio::SimulationDay((size_t)tmax + 1));
7273
for (size_t i = 0; i < tmax + 1; ++i) {
7374
auto num_vaccinations = static_cast<double>(i * daily_vaccinations);
7475
model.parameters
75-
.get<mio::osecirvvs::DailyFirstVaccination<double>>()[{(mio::AgeGroup)0, mio::SimulationDay(i)}] =
76+
.get<mio::osecirvvs::DailyPartialVaccinations<double>>()[{(mio::AgeGroup)0, mio::SimulationDay(i)}] =
7677
num_vaccinations;
7778
model.parameters
78-
.get<mio::osecirvvs::DailyFullVaccination<double>>()[{(mio::AgeGroup)0, mio::SimulationDay(i)}] =
79+
.get<mio::osecirvvs::DailyFullVaccinations<double>>()[{(mio::AgeGroup)0, mio::SimulationDay(i)}] =
7980
num_vaccinations;
8081
}
8182
model.parameters.get<mio::osecirvvs::DynamicNPIsImplementationDelay<double>>() = 7;

0 commit comments

Comments
 (0)