Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ if(MEMILIO_BUILD_MODELS)
add_subdirectory(models/ide_secir)
add_subdirectory(models/ide_seir)
add_subdirectory(models/ode_seir)
add_subdirectory(models/ode_seirv)
add_subdirectory(models/ode_seair)
add_subdirectory(models/ode_sir)
add_subdirectory(models/sde_sir)
Expand Down
4 changes: 4 additions & 0 deletions cpp/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ add_executable(seir_flows_example ode_seir_flows.cpp)
target_link_libraries(seir_flows_example PRIVATE memilio ode_seir)
target_compile_options(seir_flows_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS})

add_executable(ode_seirv_example ode_seirv_example.cpp)
target_link_libraries(ode_seirv_example PRIVATE memilio ode_seirv)
target_compile_options(ode_seirv_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS})

add_executable(ode_secir_example ode_secir.cpp)
target_link_libraries(ode_secir_example PRIVATE memilio ode_secir)
target_compile_options(ode_secir_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS})
Expand Down
120 changes: 120 additions & 0 deletions cpp/examples/ode_seirv_example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright (C) 2020-2025 MEmilio
*
* Authors: Henrik Zunker
*
* Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "ode_seirv/model.h"
#include "memilio/compartments/simulation.h"
#include "memilio/utils/logging.h"

/**
* @brief set_initial_population sets the initial population of the model
*
* We assume that no one is initially infected or exposed at the beginning of the season.
* Infections are seeded later via the OutsideFoI parameter.
* The destinction into the 2 layers of susceptibility is done via the parameters.
* @tparam FP floating point type
* @param[in, out] model SEIRV model
* @param[in] total_pop total population size
*/
template <class FP>
void set_initial_population(mio::oseirv::Model<FP>& model, const FP total_pop)
{
auto& params = model.parameters;
auto& pop = model.populations;
const size_t num_groups = (size_t)params.get_num_groups();

for (size_t i = 0; i < num_groups; ++i) {
pop.template set_difference_from_group_total<mio::AgeGroup>(
{mio::AgeGroup(i), mio::oseirv::InfectionState::Susceptible}, total_pop / num_groups);

// Total population N_i as currently stored in group totals
FP Ni = pop.get_group_total(mio::AgeGroup(i));

FP s_age = params.template get<mio::oseirv::SusceptibilityByAge<FP>>()[mio::AgeGroup(i)];
FP s_frac = params.template get<mio::oseirv::SusceptibleFraction<FP>>();
FP vc = params.template get<mio::oseirv::VaccineCoverage<FP>>()[mio::AgeGroup(i)];
FP ve = params.template get<mio::oseirv::VaccineEffectiveness<FP>>()[mio::AgeGroup(i)];

pop[{mio::AgeGroup(i), mio::oseirv::InfectionState::Exposed}] = 0;
pop[{mio::AgeGroup(i), mio::oseirv::InfectionState::ExposedVaccinated}] = 0;
pop[{mio::AgeGroup(i), mio::oseirv::InfectionState::Infected}] = 0;
pop[{mio::AgeGroup(i), mio::oseirv::InfectionState::InfectedVaccinated}] = 0;

pop[{mio::AgeGroup(i), mio::oseirv::InfectionState::Susceptible}] = s_frac * s_age * (FP(1) - vc) * Ni;
pop[{mio::AgeGroup(i), mio::oseirv::InfectionState::SusceptibleVaccinated}] =
s_frac * s_age * (FP(1) - ve) * vc * Ni;

pop[{mio::AgeGroup(i), mio::oseirv::InfectionState::Recovered}] = (FP(1) - s_frac * s_age) * (FP(1) - vc) * Ni;
pop[{mio::AgeGroup(i), mio::oseirv::InfectionState::RecoveredVaccinated}] =
(FP(1) - s_frac * s_age * (FP(1) - ve)) * vc * Ni;
}
}

// Example usage of the SEIRV ODE model presented in https://doi.org/10.1186/s12879-017-2344-6
int main()
{
using FP = double;
mio::set_log_level(mio::LogLevel::debug);

const FP t0 = 0., tmax = 42.;
const FP dt = 0.1;

const size_t num_groups = 1;
const auto total_pop = 1e5;
mio::oseirv::Model<FP> model((int)num_groups);
auto& parameters = model.parameters;

FP cont_freq = 10.0;
FP cont_freq_group = FP(1) / FP(num_groups);

// Healthy contacts
mio::ContactMatrixGroup<ScalarType>& contacts_healthy = parameters.get<mio::oseirv::ContactPatternsHealthy<FP>>();
contacts_healthy[0] = mio::ContactMatrix<FP>(
Eigen::MatrixXd::Constant((Eigen::Index)num_groups, (Eigen::Index)num_groups, cont_freq_group * cont_freq));

// Sick contacts (here 20% reduced)
mio::ContactMatrixGroup<ScalarType>& contacts_sick = parameters.get<mio::oseirv::ContactPatternsSick<FP>>();
contacts_sick[0] = mio::ContactMatrix<FP>(Eigen::MatrixXd::Constant(
(Eigen::Index)num_groups, (Eigen::Index)num_groups, cont_freq_group * cont_freq * 0.8));

// Parameters
parameters.get<mio::oseirv::BaselineTransmissibility<FP>>() = 1.2;
parameters.get<mio::oseirv::RecoveryRate<FP>>() = 1.0 / 2.0;
parameters.get<mio::oseirv::SeasonalityAmplitude<FP>>() = 1.0;
parameters.get<mio::oseirv::SeasonalityShiftPerSubtype<FP>>() = 0.0;
parameters.get<mio::oseirv::SeasonalityShiftPerSeason<FP>>() = 0.0;
parameters.get<mio::oseirv::OutsideFoI<FP>>() = 1e-6;
parameters.get<mio::oseirv::ClusteringExponent<FP>>() = 0.9;
parameters.get<mio::oseirv::SickMixing<FP>>() = 2.0;

for (size_t i = 0; i < num_groups; ++i) {
parameters.get<mio::oseirv::SusceptibilityByAge<FP>>()[mio::AgeGroup(i)] = 1.0;
parameters.get<mio::oseirv::VaccineCoverage<FP>>()[mio::AgeGroup(i)] = 0.3;
parameters.get<mio::oseirv::VaccineEffectiveness<FP>>()[mio::AgeGroup(i)] = 0.5;
model.populations.set_difference_from_group_total<mio::AgeGroup>(
{mio::AgeGroup(i), mio::oseirv::InfectionState::Susceptible}, 1e5 / num_groups);
}

set_initial_population(model, total_pop);

auto seirv = mio::simulate<FP>(t0, tmax, dt, model);

std::vector<std::string> vars = {"S", "SV", "E", "EV", "I", "IV", "R", "RV"};
seirv.print_table(vars);
}
12 changes: 12 additions & 0 deletions cpp/models/ode_seirv/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
add_library(ode_seirv
infection_state.h
model.h
model.cpp
parameters.h
)
target_link_libraries(ode_seirv PUBLIC memilio)
target_include_directories(ode_seirv PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_compile_options(ode_seirv PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS})
23 changes: 23 additions & 0 deletions cpp/models/ode_seirv/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# ODE SEIRV (seasonal influenza)

A age‑structured **SEIRV** model implemented into the MEmilio ODE framework.
It extends the classic SEIR by a vaccinated layer (Sᵛ, Eᵛ, Iᵛ, Rᵛ) and follows the seasonal influenza
model structure from:

> **Weidemann, F., Remschmidt, C., Buda, S. et al.**
> *Is the impact of childhood influenza vaccination less than expected: a transmission modelling study.*
> **BMC Infectious Diseases** 17, 258 (2017).
> https://doi.org/10.1186/s12879-017-2344-6

## Get started

To get started, check out the
[official documentation](https://memilio.readthedocs.io/en/latest/cpp/models/oseirv.html)
or the [code example](../../examples/ode_seirv_example.cpp).

## Reference

Please cite the original study if you use this model:

> Weidemann, F., Remschmidt, C., Buda, S. et al. *Is the impact of childhood influenza vaccination less than expected: a transmission modelling study.* **BMC Infect Dis** 17, 258 (2017).
> https://doi.org/10.1186/s12879-017-2344-6
42 changes: 42 additions & 0 deletions cpp/models/ode_seirv/infection_state.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2020-2025 MEmilio
*
* Authors: Henrik Zunker
*
* Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SEIRV_INFECTIONSTATE_H
#define SEIRV_INFECTIONSTATE_H
namespace mio
{
namespace oseirv
{

enum class InfectionState
{
Susceptible,
SusceptibleVaccinated,
Exposed,
ExposedVaccinated,
Infected,
InfectedVaccinated,
Recovered,
RecoveredVaccinated,
Count
};

} // namespace oseirv
} // namespace mio
#endif
20 changes: 20 additions & 0 deletions cpp/models/ode_seirv/model.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2020-2025 MEmilio
*
* Authors: Henrik Zunker
*
* Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ode_seirv/model.h"
Loading