-
Notifications
You must be signed in to change notification settings - Fork 23
946 implement generalized linear chain trick #1058
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
annawendler
merged 34 commits into
main
from
946-implement-generalized-linear-chain-trick
Nov 26, 2024
Merged
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
913de3a
Not working: first ideas to make derived of CompartmentalModel
lenaploetzke 2606932
implemented glct model
lenaploetzke 6d8f910
Merge branch 'main' into 946-implement-generalized-linear-chain-trick
lenaploetzke 427157a
some adaptions to the glct model
lenaploetzke 0bf1529
add constraints to check_constraints functions
lenaploetzke f38904f
correct signs
lenaploetzke 8e66b49
Merge branch 'main' into 946-implement-generalized-linear-chain-trick
lenaploetzke 8d2011f
Merge branch 'main' into 914-make-the-lct-secir-model-a-derived-class…
lenaploetzke be02fef
add ScalarType as template argument
lenaploetzke f9a3447
make LCT model a derived class of CompartmentalModel
lenaploetzke deaaeed
added test; changed int to size_t in LctInfectionState
lenaploetzke dd6bb88
fix bug
lenaploetzke 99a6867
rly fix bug
lenaploetzke 1edf777
add explicit conversion
lenaploetzke ff06d05
Merge branch '914-make-the-lct-secir-model-a-derived-class-of-flowmod…
lenaploetzke ff78759
fix error
lenaploetzke 3614f55
make dimensions in parameters of size_t
lenaploetzke 3e4b68a
added test
lenaploetzke 7470dd1
added README
lenaploetzke 34d9e6e
update README
lenaploetzke f8c9f89
Merge branch 'main' into 946-implement-generalized-linear-chain-trick
lenaploetzke 6c06904
cleanup
lenaploetzke 6e65611
Merge branch 'main' into 946-implement-generalized-linear-chain-trick
lenaploetzke a6674fc
[ci skip] adapt comments
lenaploetzke 411e1f7
Merge branch 'main' into 946-implement-generalized-linear-chain-trick
lenaploetzke a2c3938
Merge branch 'main' into 946-implement-generalized-linear-chain-trick
lenaploetzke 17ff131
use calculate_compartments function of ict_infection_state for LCT an…
lenaploetzke 60da5ce
Apply suggestions from code review
lenaploetzke 74dbc56
[ci skip] reviewer suggestions
lenaploetzke 5262748
Include tikz picture in README
lenaploetzke cfcb46a
mainly documentation
lenaploetzke c09e34e
use version that is rendered correctly in github
lenaploetzke 5828c41
Update README.md
lenaploetzke 6a612dc
Typos
lenaploetzke File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,211 @@ | ||
| /* | ||
| * Copyright (C) 2020-2024 MEmilio | ||
| * | ||
| * Authors: Lena Ploetzke | ||
| * | ||
| * Contact: Martin J. Kuehn <[email protected]> | ||
| * | ||
| * 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 "glct_secir/model.h" | ||
| #include "glct_secir/parameters.h" | ||
| #include "memilio/config.h" | ||
| #include "memilio/utils/time_series.h" | ||
| #include "memilio/epidemiology/uncertain_matrix.h" | ||
| #include "memilio/math/eigen.h" | ||
| #include "memilio/utils/logging.h" | ||
| #include "memilio/compartments/simulation.h" | ||
| #include "memilio/data/analyze_result.h" | ||
|
|
||
| #include <vector> | ||
|
|
||
| int main() | ||
| { | ||
| // Simple example to demonstrate how to run a simulation using an GLCT SECIR model. | ||
| // This example recreates the lct_secir.cpp example using the GLCT model. | ||
| // This means, that we use the corresponding initial numbers, parameters and numbers of subcompartments that are | ||
| // equivalent to the choices in the LCT example. | ||
| // Parameters, initial values and the number of subcompartments are not meant to represent a realistic scenario. | ||
| // We need to double the choices of the number of subcompartments for some compartments, | ||
| // as we define different strains for different transition possibilities. For both strains, the same number of | ||
| // subcompartments is chosen. The transition probabilities are defined in the StartingProbabilities. | ||
| constexpr size_t NumExposed = 2, NumInfectedNoSymptoms = 6, NumInfectedSymptoms = 2, NumInfectedSevere = 2, | ||
| NumInfectedCritical = 10; | ||
| using Model = mio::glsecir::Model<NumExposed, NumInfectedNoSymptoms, NumInfectedSymptoms, NumInfectedSevere, | ||
| NumInfectedCritical>; | ||
| using LctState = Model::LctState; | ||
| using InfectionState = LctState::InfectionState; | ||
|
|
||
| Model model; | ||
|
|
||
| const ScalarType tmax = 10; | ||
| const ScalarType t0 = 0; | ||
| const ScalarType dt_init = 10; ///< Initially used step size for adaptive method. | ||
|
|
||
| // Define some epidemiological parameters needed throughput the model definition and initialization. | ||
| const ScalarType timeExposed = 3.2; | ||
| const ScalarType timeInfectedNoSymptoms = 2.; | ||
| const ScalarType timeInfectedSymptoms = 5.8; | ||
| const ScalarType timeInfectedSevere = 9.5; | ||
| const ScalarType timeInfectedCritical = 7.1; | ||
| const ScalarType recoveredPerInfectedNoSymptoms = 0.09; | ||
| const ScalarType severePerInfectedSymptoms = 0.2; | ||
| const ScalarType criticalPerSevere = 0.25; | ||
| const ScalarType deathsPerCritical = 0.3; | ||
|
|
||
| // Define the initial values with the distribution of the population into subcompartments. | ||
| // This method of defining the initial values using a vector of vectors is not necessary, but should remind you | ||
| // how the entries of the initial value vector relate to the defined template parameters of the model or the number | ||
| // of subcompartments. It is also possible to define the initial values directly. | ||
| // Split the initial population defined in the lct_secir.cpp example according to the transition probabilities in | ||
| // the two strains per compartment. | ||
| std::vector<std::vector<ScalarType>> initial_populations = { | ||
| {750}, | ||
| {30, 20}, | ||
| {20 * (1 - recoveredPerInfectedNoSymptoms), 10 * (1 - recoveredPerInfectedNoSymptoms), | ||
| 10 * (1 - recoveredPerInfectedNoSymptoms), 20 * recoveredPerInfectedNoSymptoms, | ||
| 10 * recoveredPerInfectedNoSymptoms, 10 * recoveredPerInfectedNoSymptoms}, | ||
| {50 * severePerInfectedSymptoms, 50 * (1 - severePerInfectedSymptoms)}, | ||
| {50 * criticalPerSevere, 50 * (1 - criticalPerSevere)}, | ||
| {10 * deathsPerCritical, 10 * deathsPerCritical, 5 * deathsPerCritical, 3 * deathsPerCritical, | ||
| 2 * deathsPerCritical, 10 * (1 - deathsPerCritical), 10 * (1 - deathsPerCritical), 5 * (1 - deathsPerCritical), | ||
| 3 * (1 - deathsPerCritical), 2 * (1 - deathsPerCritical)}, | ||
| {20}, | ||
| {10}}; | ||
|
annawendler marked this conversation as resolved.
|
||
|
|
||
| // Assert that initial_populations has the right shape. | ||
| if (initial_populations.size() != (size_t)InfectionState::Count) { | ||
| mio::log_error("The number of vectors in initial_populations does not match the number of InfectionStates."); | ||
| return 1; | ||
| } | ||
| if ((initial_populations[(size_t)InfectionState::Susceptible].size() != | ||
| LctState::get_num_subcompartments<InfectionState::Susceptible>()) || | ||
| (initial_populations[(size_t)InfectionState::Exposed].size() != NumExposed) || | ||
| (initial_populations[(size_t)InfectionState::InfectedNoSymptoms].size() != NumInfectedNoSymptoms) || | ||
| (initial_populations[(size_t)InfectionState::InfectedSymptoms].size() != NumInfectedSymptoms) || | ||
| (initial_populations[(size_t)InfectionState::InfectedSevere].size() != NumInfectedSevere) || | ||
| (initial_populations[(size_t)InfectionState::InfectedCritical].size() != NumInfectedCritical) || | ||
| (initial_populations[(size_t)InfectionState::Recovered].size() != | ||
| LctState::get_num_subcompartments<InfectionState::Recovered>()) || | ||
| (initial_populations[(size_t)InfectionState::Dead].size() != | ||
| LctState::get_num_subcompartments<InfectionState::Dead>())) { | ||
| mio::log_error("The length of at least one vector in initial_populations does not match the related number of " | ||
| "subcompartments."); | ||
|
annawendler marked this conversation as resolved.
|
||
| return 1; | ||
| } | ||
|
|
||
| // Transfer the initial values in initial_populations to the model. | ||
| std::vector<ScalarType> flat_initial_populations; | ||
| for (auto&& vec : initial_populations) { | ||
| flat_initial_populations.insert(flat_initial_populations.end(), vec.begin(), vec.end()); | ||
| } | ||
| for (size_t i = 0; i < LctState::Count; i++) { | ||
| model.populations[mio::Index<LctState>(i)] = flat_initial_populations[i]; | ||
| } | ||
|
|
||
| // Set Parameters according to the LCT model definitions, e.g. use Erlang-distributions. | ||
| // Exposed. | ||
| // The get_default of the StartingProbabilities returns the first unit vector of the defined size. | ||
| // It is necessary to set it although the default method is used to define the length of the vector. | ||
| model.parameters.get<mio::glsecir::StartingProbabilitiesExposed>() = | ||
| mio::glsecir::StartingProbabilitiesExposed().get_default( | ||
| LctState::get_num_subcompartments<InfectionState::Exposed>()); | ||
| // The get_default function returns the TransitionMatrix that is required to have an Erlang-distributed | ||
| // stay time with an average of timeExposed. | ||
| model.parameters.get<mio::glsecir::TransitionMatrixExposedToInfectedNoSymptoms>() = | ||
| mio::glsecir::TransitionMatrixExposedToInfectedNoSymptoms().get_default( | ||
| LctState::get_num_subcompartments<InfectionState::Exposed>(), timeExposed); | ||
| // This definition of the StartingProbability and the TransitionMatrix lead to an Erlang-distributed latent stage. | ||
|
|
||
| // InfectedNoSymptoms. | ||
| // For InfectedNoSymptoms, two strains has to be defined, one for the Transition | ||
| // InfectedNoSymptomsToInfectedSymptoms and one for InfectedNoSymptomsToRecovered. | ||
| // The strains have a length of NumInfectedNoSymptoms/2. each. | ||
| // The transition probability is included in the StartingProbability vector. | ||
| mio::Vector<ScalarType> StartingProbabilitiesInfectedNoSymptoms = | ||
| mio::Vector<ScalarType>::Zero(LctState::get_num_subcompartments<InfectionState::InfectedNoSymptoms>()); | ||
| StartingProbabilitiesInfectedNoSymptoms[0] = 1 - recoveredPerInfectedNoSymptoms; | ||
| StartingProbabilitiesInfectedNoSymptoms[(Eigen::Index)( | ||
| LctState::get_num_subcompartments<InfectionState::InfectedNoSymptoms>() / 2.)] = recoveredPerInfectedNoSymptoms; | ||
| model.parameters.get<mio::glsecir::StartingProbabilitiesInfectedNoSymptoms>() = | ||
| StartingProbabilitiesInfectedNoSymptoms; | ||
| // Define equal TransitionMatrices for the strains. | ||
| // They follow the same Erlang-distribution such that we get the same result as with one strain in the LCT model. | ||
| model.parameters.get<mio::glsecir::TransitionMatrixInfectedNoSymptomsToInfectedSymptoms>() = | ||
| mio::glsecir::TransitionMatrixInfectedNoSymptomsToInfectedSymptoms().get_default( | ||
| (size_t)(LctState::get_num_subcompartments<InfectionState::InfectedNoSymptoms>() / 2.), | ||
| timeInfectedNoSymptoms); | ||
| model.parameters.get<mio::glsecir::TransitionMatrixInfectedNoSymptomsToRecovered>() = | ||
| mio::glsecir::TransitionMatrixInfectedNoSymptomsToRecovered().get_default( | ||
| (size_t)(LctState::get_num_subcompartments<InfectionState::InfectedNoSymptoms>() / 2.), | ||
| timeInfectedNoSymptoms); | ||
| // Do the same for all compartments. | ||
| // InfectedSymptoms. | ||
| mio::Vector<ScalarType> StartingProbabilitiesInfectedSymptoms = | ||
| mio::Vector<ScalarType>::Zero(LctState::get_num_subcompartments<InfectionState::InfectedSymptoms>()); | ||
| StartingProbabilitiesInfectedSymptoms[0] = severePerInfectedSymptoms; | ||
| StartingProbabilitiesInfectedSymptoms[(Eigen::Index)( | ||
| LctState::get_num_subcompartments<InfectionState::InfectedSymptoms>() / 2.)] = 1 - severePerInfectedSymptoms; | ||
| model.parameters.get<mio::glsecir::StartingProbabilitiesInfectedSymptoms>() = StartingProbabilitiesInfectedSymptoms; | ||
| model.parameters.get<mio::glsecir::TransitionMatrixInfectedSymptomsToInfectedSevere>() = | ||
| mio::glsecir::TransitionMatrixInfectedSymptomsToInfectedSevere().get_default( | ||
| (size_t)(LctState::get_num_subcompartments<InfectionState::InfectedSymptoms>() / 2.), timeInfectedSymptoms); | ||
| model.parameters.get<mio::glsecir::TransitionMatrixInfectedSymptomsToRecovered>() = | ||
| mio::glsecir::TransitionMatrixInfectedSymptomsToRecovered().get_default( | ||
| (size_t)(LctState::get_num_subcompartments<InfectionState::InfectedSymptoms>() / 2.), timeInfectedSymptoms); | ||
| // InfectedSevere. | ||
| mio::Vector<ScalarType> StartingProbabilitiesInfectedSevere = | ||
| mio::Vector<ScalarType>::Zero(LctState::get_num_subcompartments<InfectionState::InfectedSevere>()); | ||
| StartingProbabilitiesInfectedSevere[0] = criticalPerSevere; | ||
| StartingProbabilitiesInfectedSevere[(Eigen::Index)( | ||
| LctState::get_num_subcompartments<InfectionState::InfectedSevere>() / 2.)] = 1 - criticalPerSevere; | ||
| model.parameters.get<mio::glsecir::StartingProbabilitiesInfectedSevere>() = StartingProbabilitiesInfectedSevere; | ||
| model.parameters.get<mio::glsecir::TransitionMatrixInfectedSevereToInfectedCritical>() = | ||
| mio::glsecir::TransitionMatrixInfectedSevereToInfectedCritical().get_default( | ||
| (size_t)(LctState::get_num_subcompartments<InfectionState::InfectedSevere>() / 2.), timeInfectedSevere); | ||
| model.parameters.get<mio::glsecir::TransitionMatrixInfectedSevereToRecovered>() = | ||
| mio::glsecir::TransitionMatrixInfectedSevereToRecovered().get_default( | ||
| (size_t)(LctState::get_num_subcompartments<InfectionState::InfectedSevere>() / 2.), timeInfectedSevere); | ||
| // InfectedCritical. | ||
| mio::Vector<ScalarType> StartingProbabilitiesInfectedCritical = | ||
| mio::Vector<ScalarType>::Zero(LctState::get_num_subcompartments<InfectionState::InfectedCritical>()); | ||
| StartingProbabilitiesInfectedCritical[0] = deathsPerCritical; | ||
| StartingProbabilitiesInfectedCritical[(Eigen::Index)( | ||
| LctState::get_num_subcompartments<InfectionState::InfectedCritical>() / 2.)] = 1 - deathsPerCritical; | ||
| model.parameters.get<mio::glsecir::StartingProbabilitiesInfectedCritical>() = StartingProbabilitiesInfectedCritical; | ||
| model.parameters.get<mio::glsecir::TransitionMatrixInfectedCriticalToDead>() = | ||
| mio::glsecir::TransitionMatrixInfectedCriticalToDead().get_default( | ||
| (size_t)(LctState::get_num_subcompartments<InfectionState::InfectedCritical>() / 2.), timeInfectedCritical); | ||
| model.parameters.get<mio::glsecir::TransitionMatrixInfectedCriticalToRecovered>() = | ||
| mio::glsecir::TransitionMatrixInfectedCriticalToRecovered().get_default( | ||
| (size_t)(LctState::get_num_subcompartments<InfectionState::InfectedCritical>() / 2.), timeInfectedCritical); | ||
|
|
||
| model.parameters.get<mio::glsecir::TransmissionProbabilityOnContact>() = 0.05; | ||
|
|
||
| mio::ContactMatrixGroup& contact_matrix = model.parameters.get<mio::glsecir::ContactPatterns>(); | ||
| contact_matrix[0] = mio::ContactMatrix(Eigen::MatrixXd::Constant(1, 1, 10)); | ||
| // From SimulationTime 5, the contact pattern is reduced to 30% of the initial value. | ||
| contact_matrix[0].add_damping(0.7, mio::SimulationTime(5.)); | ||
|
|
||
| model.parameters.get<mio::glsecir::RelativeTransmissionNoSymptoms>() = 0.7; | ||
| model.parameters.get<mio::glsecir::RiskOfInfectionFromSymptomatic>() = 0.25; | ||
|
|
||
| // Perform a simulation. | ||
| mio::TimeSeries<ScalarType> result = mio::simulate<ScalarType, Model>(t0, tmax, dt_init, model); | ||
| // The simulation result is divided by subcompartments as in the LCT model. | ||
| // We call the function calculate_compartments to get a result according to the InfectionStates. | ||
| mio::TimeSeries<ScalarType> population_no_subcompartments = model.calculate_compartments(result); | ||
| auto interpolated_result = mio::interpolate_simulation_result(population_no_subcompartments, 0.1); | ||
| interpolated_result.print_table({"S", "E", "C", "I", "H", "U", "R", "D "}, 10, 4); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| add_library(glct_secir | ||
| infection_state.h | ||
| model.h | ||
| model.cpp | ||
| parameters.h | ||
| ) | ||
| target_link_libraries(glct_secir PUBLIC memilio) | ||
| target_include_directories(glct_secir PUBLIC | ||
| $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..> | ||
| $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> | ||
| ) | ||
| target_compile_options(glct_secir PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.