|
| 1 | +/* |
| 2 | +* Copyright (C) 2020-2026 MEmilio |
| 3 | +* |
| 4 | +* Authors: Annika Jungklaus, Lena Ploetzke |
| 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 | + |
| 21 | +#include "lct_secir_2_diseases/model.h" |
| 22 | +#include "lct_secir_2_diseases/infection_state.h" |
| 23 | +#include "memilio/config.h" |
| 24 | +#include "memilio/utils/time_series.h" |
| 25 | +#include "memilio/epidemiology/lct_infection_state.h" |
| 26 | +#include "memilio/utils/logging.h" |
| 27 | +#include "memilio/compartments/simulation.h" |
| 28 | +#include "memilio/data/analyze_result.h" |
| 29 | +#include <vector> |
| 30 | + |
| 31 | +int main() |
| 32 | +{ |
| 33 | + // Simple example to demonstrate how to run a simulation using an LCT-SECIR-2-DISEASE model. |
| 34 | + // One single AgeGroup/Category member is used here. |
| 35 | + // Parameters, initial values and the number of subcompartments are not meant to represent a realistic scenario. |
| 36 | + // The number of subcompartments can be chosen for most of the compartments: |
| 37 | + constexpr size_t NumExposed_1a = 2, NumInfectedNoSymptoms_1a = 3, NumInfectedSymptoms_1a = 3, |
| 38 | + NumInfectedSevere_1a = 3, NumInfectedCritical_1a = 2, NumExposed_2a = 1, |
| 39 | + NumInfectedNoSymptoms_2a = 2, NumInfectedSymptoms_2a = 2, NumInfectedSevere_2a = 2, |
| 40 | + NumInfectedCritical_2a = 1, NumExposed_1b = 2, NumInfectedNoSymptoms_1b = 3, |
| 41 | + NumInfectedSymptoms_1b = 3, NumInfectedSevere_1b = 3, NumInfectedCritical_1b = 2, |
| 42 | + NumExposed_2b = 1, NumInfectedNoSymptoms_2b = 2, NumInfectedSymptoms_2b = 2, |
| 43 | + NumInfectedSevere_2b = 2, NumInfectedCritical_2b = 1; |
| 44 | + // The compartment for Susceptible people and all compartments for Dead and Recovered people must have exactly one subcompartment: |
| 45 | + constexpr size_t NumSusceptible = 1, NumDead_a = 1, NumDead_b = 1, NumRecovered_1a = 1, NumRecovered_1b = 1, |
| 46 | + NumRecovered_2ab = 1; |
| 47 | + using InfState = mio::lsecir2d::InfectionState; |
| 48 | + using LctState = |
| 49 | + mio::LctInfectionState<ScalarType, InfState, NumSusceptible, NumExposed_1a, NumInfectedNoSymptoms_1a, |
| 50 | + NumInfectedSymptoms_1a, NumInfectedSevere_1a, NumInfectedCritical_1a, NumRecovered_1a, |
| 51 | + NumDead_a, NumExposed_2a, NumInfectedNoSymptoms_2a, NumInfectedSymptoms_2a, |
| 52 | + NumInfectedSevere_2a, NumInfectedCritical_2a, NumExposed_1b, NumInfectedNoSymptoms_1b, |
| 53 | + NumInfectedSymptoms_1b, NumInfectedSevere_1b, NumInfectedCritical_1b, NumRecovered_1b, |
| 54 | + NumDead_b, NumExposed_2b, NumInfectedNoSymptoms_2b, NumInfectedSymptoms_2b, |
| 55 | + NumInfectedSevere_2b, NumInfectedCritical_2b, NumRecovered_2ab>; |
| 56 | + using Model = mio::lsecir2d::Model<ScalarType, LctState>; |
| 57 | + Model model; |
| 58 | + |
| 59 | + ScalarType tmax = 5; |
| 60 | + |
| 61 | + // Set Parameters. |
| 62 | + model.parameters.get<mio::lsecir2d::TimeExposed_a<ScalarType>>()[0] = 3.; |
| 63 | + model.parameters.get<mio::lsecir2d::TimeExposed_b<ScalarType>>()[0] = 3.; |
| 64 | + model.parameters.get<mio::lsecir2d::TimeInfectedNoSymptoms_a<ScalarType>>()[0] = 3.; |
| 65 | + model.parameters.get<mio::lsecir2d::TimeInfectedNoSymptoms_b<ScalarType>>()[0] = 3.; |
| 66 | + model.parameters.get<mio::lsecir2d::TimeInfectedSymptoms_a<ScalarType>>()[0] = 3.; |
| 67 | + model.parameters.get<mio::lsecir2d::TimeInfectedSymptoms_b<ScalarType>>()[0] = 3.; |
| 68 | + model.parameters.get<mio::lsecir2d::TimeInfectedSevere_a<ScalarType>>()[0] = 3.; |
| 69 | + model.parameters.get<mio::lsecir2d::TimeInfectedSevere_b<ScalarType>>()[0] = 3.; |
| 70 | + model.parameters.get<mio::lsecir2d::TimeInfectedCritical_a<ScalarType>>()[0] = 3.; |
| 71 | + model.parameters.get<mio::lsecir2d::TimeInfectedCritical_b<ScalarType>>()[0] = 3.; |
| 72 | + |
| 73 | + model.parameters.get<mio::lsecir2d::TransmissionProbabilityOnContact_a<ScalarType>>()[0] = 0.1; |
| 74 | + model.parameters.get<mio::lsecir2d::TransmissionProbabilityOnContact_b<ScalarType>>()[0] = 0.1; |
| 75 | + |
| 76 | + mio::ContactMatrixGroup<ScalarType>& contact_matrix = |
| 77 | + model.parameters.get<mio::lsecir2d::ContactPatterns<ScalarType>>(); |
| 78 | + contact_matrix[0] = mio::ContactMatrix<ScalarType>(Eigen::MatrixX<ScalarType>::Constant(1, 1, 10)); |
| 79 | + // From SimulationTime 5, the contact pattern is reduced to 30% of the initial value. |
| 80 | + contact_matrix[0].add_damping(0.7, mio::SimulationTime<ScalarType>(5.)); |
| 81 | + |
| 82 | + model.parameters.get<mio::lsecir2d::RelativeTransmissionNoSymptoms_a<ScalarType>>()[0] = 0.7; |
| 83 | + model.parameters.get<mio::lsecir2d::RelativeTransmissionNoSymptoms_b<ScalarType>>()[0] = 0.7; |
| 84 | + model.parameters.get<mio::lsecir2d::RiskOfInfectionFromSymptomatic_a<ScalarType>>()[0] = 0.25; |
| 85 | + model.parameters.get<mio::lsecir2d::RiskOfInfectionFromSymptomatic_b<ScalarType>>()[0] = 0.25; |
| 86 | + model.parameters.get<mio::lsecir2d::RecoveredPerInfectedNoSymptoms_a<ScalarType>>()[0] = 0.09; |
| 87 | + model.parameters.get<mio::lsecir2d::RecoveredPerInfectedNoSymptoms_b<ScalarType>>()[0] = 0.09; |
| 88 | + model.parameters.get<mio::lsecir2d::SeverePerInfectedSymptoms_a<ScalarType>>()[0] = 0.2; |
| 89 | + model.parameters.get<mio::lsecir2d::SeverePerInfectedSymptoms_b<ScalarType>>()[0] = 0.2; |
| 90 | + model.parameters.get<mio::lsecir2d::CriticalPerSevere_a<ScalarType>>()[0] = 0.25; |
| 91 | + model.parameters.get<mio::lsecir2d::CriticalPerSevere_b<ScalarType>>()[0] = 0.25; |
| 92 | + model.parameters.get<mio::lsecir2d::DeathsPerCritical_a<ScalarType>>()[0] = 0.3; |
| 93 | + model.parameters.get<mio::lsecir2d::DeathsPerCritical_b<ScalarType>>()[0] = 0.3; |
| 94 | + |
| 95 | + // Simple example how to initialize model without flows. |
| 96 | + // Define the initial values with the distribution of the population into subcompartments. |
| 97 | + // This method of defining the initial values using a vector of vectors is not necessary, but should remind you |
| 98 | + // how the entries of the initial value vector relate to the defined template parameters of the model or the number |
| 99 | + // of subcompartments. It is also possible to define the initial values directly. |
| 100 | + std::vector<std::vector<ScalarType>> initial_populations = { |
| 101 | + {200}, {0, 0}, {30, 10, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0}, {0}, {0}, {0}, |
| 102 | + {0, 0}, {10, 0}, {0, 0}, {0}, {10, 0}, {30, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0}, |
| 103 | + {0}, {0}, {100}, {0, 0}, {0, 0}, {0, 0}, {0}, {0}}; |
| 104 | + |
| 105 | + // Assert that initial_populations has the right shape. |
| 106 | + if (initial_populations.size() != (size_t)InfState::Count) { |
| 107 | + mio::log_error("The number of vectors in initial_populations does not match the number of InfectionStates."); |
| 108 | + return 1; |
| 109 | + } |
| 110 | + if ((initial_populations[(size_t)InfState::Susceptible].size() != |
| 111 | + LctState::get_num_subcompartments<InfState::Susceptible>()) || |
| 112 | + (initial_populations[(size_t)InfState::Exposed_1a].size() != NumExposed_1a) || |
| 113 | + (initial_populations[(size_t)InfState::InfectedNoSymptoms_1a].size() != NumInfectedNoSymptoms_1a) || |
| 114 | + (initial_populations[(size_t)InfState::InfectedSymptoms_1a].size() != NumInfectedSymptoms_1a) || |
| 115 | + (initial_populations[(size_t)InfState::InfectedSevere_1a].size() != NumInfectedSevere_1a) || |
| 116 | + (initial_populations[(size_t)InfState::InfectedCritical_1a].size() != NumInfectedCritical_1a) || |
| 117 | + (initial_populations[(size_t)InfState::Exposed_2a].size() != NumExposed_2a) || |
| 118 | + (initial_populations[(size_t)InfState::InfectedNoSymptoms_2a].size() != NumInfectedNoSymptoms_2a) || |
| 119 | + (initial_populations[(size_t)InfState::InfectedSymptoms_2a].size() != NumInfectedSymptoms_2a) || |
| 120 | + (initial_populations[(size_t)InfState::InfectedSevere_2a].size() != NumInfectedSevere_2a) || |
| 121 | + (initial_populations[(size_t)InfState::InfectedCritical_2a].size() != NumInfectedCritical_2a) || |
| 122 | + (initial_populations[(size_t)InfState::Recovered_1a].size() != |
| 123 | + LctState::get_num_subcompartments<InfState::Recovered_1a>()) || |
| 124 | + (initial_populations[(size_t)InfState::Dead_a].size() != |
| 125 | + LctState::get_num_subcompartments<InfState::Dead_a>()) || |
| 126 | + (initial_populations[(size_t)InfState::Exposed_1b].size() != NumExposed_1b) || |
| 127 | + (initial_populations[(size_t)InfState::InfectedNoSymptoms_1b].size() != NumInfectedNoSymptoms_1b) || |
| 128 | + (initial_populations[(size_t)InfState::InfectedSymptoms_1b].size() != NumInfectedSymptoms_1b) || |
| 129 | + (initial_populations[(size_t)InfState::InfectedSevere_1b].size() != NumInfectedSevere_1b) || |
| 130 | + (initial_populations[(size_t)InfState::InfectedCritical_1b].size() != NumInfectedCritical_1b) || |
| 131 | + (initial_populations[(size_t)InfState::Recovered_1b].size() != |
| 132 | + LctState::get_num_subcompartments<InfState::Recovered_1b>()) || |
| 133 | + (initial_populations[(size_t)InfState::Dead_b].size() != |
| 134 | + LctState::get_num_subcompartments<InfState::Dead_b>()) || |
| 135 | + (initial_populations[(size_t)InfState::Exposed_2b].size() != NumExposed_2b) || |
| 136 | + (initial_populations[(size_t)InfState::InfectedNoSymptoms_2b].size() != NumInfectedNoSymptoms_2b) || |
| 137 | + (initial_populations[(size_t)InfState::InfectedSymptoms_2b].size() != NumInfectedSymptoms_2b) || |
| 138 | + (initial_populations[(size_t)InfState::InfectedSevere_2b].size() != NumInfectedSevere_2b) || |
| 139 | + (initial_populations[(size_t)InfState::InfectedCritical_2b].size() != NumInfectedCritical_2b) || |
| 140 | + (initial_populations[(size_t)InfState::Recovered_2ab].size() != |
| 141 | + LctState::get_num_subcompartments<InfState::Recovered_2ab>())) { |
| 142 | + mio::log_error("The length of at least one vector in initial_populations does not match the related number of " |
| 143 | + "subcompartments."); |
| 144 | + return 1; |
| 145 | + } |
| 146 | + // Transfer the initial values in initial_populations to the model. |
| 147 | + std::vector<ScalarType> flat_initial_populations; |
| 148 | + for (auto&& vec : initial_populations) { |
| 149 | + flat_initial_populations.insert(flat_initial_populations.end(), vec.begin(), vec.end()); |
| 150 | + } |
| 151 | + for (size_t i = 0; i < LctState::Count; i++) { |
| 152 | + model.populations[i] = flat_initial_populations[i]; |
| 153 | + } |
| 154 | + |
| 155 | + // Perform a simulation. |
| 156 | + mio::TimeSeries<ScalarType> result = mio::simulate<ScalarType, Model>(0, tmax, 0.1, model); |
| 157 | + // The simulation result is divided by subcompartments. |
| 158 | + // We call the function calculate_compartments to get a result according to the InfectionStates. |
| 159 | + mio::TimeSeries<ScalarType> population_no_subcompartments = model.calculate_compartments(result); |
| 160 | + auto interpolated_results = mio::interpolate_simulation_result(population_no_subcompartments); |
| 161 | + |
| 162 | + interpolated_results.print_table({" S", " E1a", " C1a", " I1a", " H1a", " U1a", " Ra", |
| 163 | + " Da", " E2a", " C2a", " I2a", " H2a", " U2a", " E1b", |
| 164 | + " C1b", " I1b", " H1b", " U1b", " Rb", " Db", " E2b", |
| 165 | + " C2b", " I2b", " H2b", " U2b", " Rab"}, |
| 166 | + 6, 2); |
| 167 | +} |
0 commit comments