Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
8 changes: 4 additions & 4 deletions .github/actions/build-py/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ runs:
cd pycode/memilio-${{ inputs.package }}/
# else stay in root directory
fi
/opt/python/cp38-cp38/bin/python -m pip install --upgrade pip setuptools wheel
/opt/python/cp39-cp39/bin/python -m pip install --upgrade pip setuptools wheel
/opt/python/cp312-cp312/bin/python -m pip install --upgrade pip setuptools wheel
/opt/python/cp38-cp38/bin/python -m pip install scikit-build scikit-build-core
/opt/python/cp39-cp39/bin/python -m pip install scikit-build scikit-build-core
/opt/python/cp312-cp312/bin/python -m pip install scikit-build scikit-build-core
# Install setuptools-scm only for memilio-simulation
if [ "${{ inputs.package }}" == "simulation" ]; then
/opt/python/cp38-cp38/bin/python -m pip install setuptools-scm
/opt/python/cp39-cp39/bin/python -m pip install setuptools-scm
/opt/python/cp312-cp312/bin/python -m pip install setuptools-scm
fi
/opt/python/cp38-cp38/bin/python -m build --no-isolation --wheel
/opt/python/cp39-cp39/bin/python -m build --no-isolation --wheel
/opt/python/cp312-cp312/bin/python -m build --no-isolation --wheel
# Exclude memilio-generation, because its a pure python package, cmake is only used in the build process to retrieve data from cpp
if [[ -f "CMakeLists.txt" ]] && [ "${{ inputs.package }}" != "generation" ]; then
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/test-py/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ inputs:
version:
description: "Python version to use for the test."
required: false
default: "3.8"
default: "3.9"
coverage:
description: "Generate coverage report from running the tests, ON or OFF, default OFF."
required: false
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ jobs:
if: github.event.pull_request.draft == false
strategy:
matrix:
version: ["3.8", "3.12"]
version: ["3.9", "3.12"]
needs: build-py-generation
runs-on: ubuntu-latest
steps:
Expand All @@ -353,7 +353,7 @@ jobs:
needs: build-py-simulation
strategy:
matrix:
version: ["3.8", "3.12"]
version: ["3.9", "3.12"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
Expand All @@ -366,7 +366,7 @@ jobs:
needs: [build-py-surrogatemodel, build-py-simulation]
strategy:
matrix:
version: ["3.8", "3.12"]
version: ["3.9", "3.12"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
Expand Down
41 changes: 22 additions & 19 deletions cpp/examples/glct_secir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ int main()
// 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,
constexpr size_t NumExposed = 2, NumInfectedNoSymptoms = 6, NumInfectedSymptoms = 2, NumInfectedSevere = 3,
NumInfectedCritical = 10;
using Model = mio::glsecir::Model<ScalarType, NumExposed, NumInfectedNoSymptoms, NumInfectedSymptoms,
NumInfectedSevere, NumInfectedCritical>;
Expand All @@ -62,6 +62,7 @@ int main()
const ScalarType recoveredPerInfectedNoSymptoms = 0.09;
const ScalarType severePerInfectedSymptoms = 0.2;
const ScalarType criticalPerSevere = 0.25;
const ScalarType deathsPerSevere = 0.;
const ScalarType deathsPerCritical = 0.3;

// Define the initial values with the distribution of the population into subcompartments.
Expand All @@ -77,7 +78,7 @@ int main()
10 * (1 - recoveredPerInfectedNoSymptoms), 20 * recoveredPerInfectedNoSymptoms,
10 * recoveredPerInfectedNoSymptoms, 10 * recoveredPerInfectedNoSymptoms},
{50 * severePerInfectedSymptoms, 50 * (1 - severePerInfectedSymptoms)},
{50 * criticalPerSevere, 50 * (1 - criticalPerSevere)},
{50 * criticalPerSevere, 50 * deathsPerSevere, 50 * (1 - criticalPerSevere - deathsPerSevere)},
{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)},
Expand Down Expand Up @@ -136,9 +137,8 @@ int main()
Eigen::VectorX<ScalarType> StartingProbabilitiesInfectedNoSymptoms =
Eigen::VectorX<ScalarType>::Zero(LctState::get_num_subcompartments<InfectionState::InfectedNoSymptoms>());
StartingProbabilitiesInfectedNoSymptoms[0] = 1 - recoveredPerInfectedNoSymptoms;
StartingProbabilitiesInfectedNoSymptoms[(
Eigen::Index)(LctState::get_num_subcompartments<InfectionState::InfectedNoSymptoms>() / 2.)] =
recoveredPerInfectedNoSymptoms;
StartingProbabilitiesInfectedNoSymptoms[(Eigen::Index)(
LctState::get_num_subcompartments<InfectionState::InfectedNoSymptoms>() / 2.)] = recoveredPerInfectedNoSymptoms;
model.parameters.get<mio::glsecir::StartingProbabilitiesInfectedNoSymptoms<ScalarType>>() =
StartingProbabilitiesInfectedNoSymptoms;
// Define equal TransitionMatrices for the strains.
Expand All @@ -155,10 +155,9 @@ int main()
// InfectedSymptoms.
Eigen::VectorX<ScalarType> StartingProbabilitiesInfectedSymptoms =
Eigen::VectorX<ScalarType>::Zero(LctState::get_num_subcompartments<InfectionState::InfectedSymptoms>());
StartingProbabilitiesInfectedSymptoms[0] = severePerInfectedSymptoms;
StartingProbabilitiesInfectedSymptoms[(
Eigen::Index)(LctState::get_num_subcompartments<InfectionState::InfectedSymptoms>() / 2.)] =
1 - severePerInfectedSymptoms;
StartingProbabilitiesInfectedSymptoms[0] = severePerInfectedSymptoms;
StartingProbabilitiesInfectedSymptoms[(Eigen::Index)(
LctState::get_num_subcompartments<InfectionState::InfectedSymptoms>() / 2.)] = 1 - severePerInfectedSymptoms;
model.parameters.get<mio::glsecir::StartingProbabilitiesInfectedSymptoms<ScalarType>>() =
StartingProbabilitiesInfectedSymptoms;
model.parameters.get<mio::glsecir::TransitionMatrixInfectedSymptomsToInfectedSevere<ScalarType>>() =
Expand All @@ -170,25 +169,29 @@ int main()
// InfectedSevere.
Eigen::VectorX<ScalarType> StartingProbabilitiesInfectedSevere =
Eigen::VectorX<ScalarType>::Zero(LctState::get_num_subcompartments<InfectionState::InfectedSevere>());
StartingProbabilitiesInfectedSevere[0] = criticalPerSevere;
StartingProbabilitiesInfectedSevere[(
Eigen::Index)(LctState::get_num_subcompartments<InfectionState::InfectedSevere>() / 2.)] =
1 - criticalPerSevere;
StartingProbabilitiesInfectedSevere[0] = criticalPerSevere;
StartingProbabilitiesInfectedSevere[(Eigen::Index)(
LctState::get_num_subcompartments<InfectionState::InfectedSevere>() / 3.)] = deathsPerSevere;
StartingProbabilitiesInfectedSevere[2 * (Eigen::Index)(
LctState::get_num_subcompartments<InfectionState::InfectedSevere>() /
3.)] = 1 - criticalPerSevere - deathsPerSevere;
model.parameters.get<mio::glsecir::StartingProbabilitiesInfectedSevere<ScalarType>>() =
StartingProbabilitiesInfectedSevere;
model.parameters.get<mio::glsecir::TransitionMatrixInfectedSevereToInfectedCritical<ScalarType>>() =
mio::glsecir::TransitionMatrixInfectedSevereToInfectedCritical<ScalarType>().get_default(
(size_t)(LctState::get_num_subcompartments<InfectionState::InfectedSevere>() / 2.), timeInfectedSevere);
(size_t)(LctState::get_num_subcompartments<InfectionState::InfectedSevere>() / 3.), timeInfectedSevere);
model.parameters.get<mio::glsecir::TransitionMatrixInfectedSevereToDead<ScalarType>>() =
mio::glsecir::TransitionMatrixInfectedSevereToDead<ScalarType>().get_default(
(size_t)(LctState::get_num_subcompartments<InfectionState::InfectedSevere>() / 3.), timeInfectedSevere);
model.parameters.get<mio::glsecir::TransitionMatrixInfectedSevereToRecovered<ScalarType>>() =
mio::glsecir::TransitionMatrixInfectedSevereToRecovered<ScalarType>().get_default(
(size_t)(LctState::get_num_subcompartments<InfectionState::InfectedSevere>() / 2.), timeInfectedSevere);
(size_t)(LctState::get_num_subcompartments<InfectionState::InfectedSevere>() / 3.), timeInfectedSevere);
// InfectedCritical.
Eigen::VectorX<ScalarType> StartingProbabilitiesInfectedCritical =
Eigen::VectorX<ScalarType>::Zero(LctState::get_num_subcompartments<InfectionState::InfectedCritical>());
StartingProbabilitiesInfectedCritical[0] = deathsPerCritical;
StartingProbabilitiesInfectedCritical[(
Eigen::Index)(LctState::get_num_subcompartments<InfectionState::InfectedCritical>() / 2.)] =
1 - deathsPerCritical;
StartingProbabilitiesInfectedCritical[0] = deathsPerCritical;
StartingProbabilitiesInfectedCritical[(Eigen::Index)(
LctState::get_num_subcompartments<InfectionState::InfectedCritical>() / 2.)] = 1 - deathsPerCritical;
model.parameters.get<mio::glsecir::StartingProbabilitiesInfectedCritical<ScalarType>>() =
StartingProbabilitiesInfectedCritical;
model.parameters.get<mio::glsecir::TransitionMatrixInfectedCriticalToDead<ScalarType>>() =
Expand Down
24 changes: 20 additions & 4 deletions cpp/models/glct_secir/model.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,23 +268,32 @@ class Model
params.template get<TransitionMatrixInfectedSevereToInfectedCritical<FP>>().transpose() *
y.segment(LctState::template get_first_index<InfectionState::InfectedSevere>(),
dimensionInfectedSevereToInfectedCritical);
// Flow from InfectedSevere To Dead.
size_t dimensionInfectedSevereToDead = params.template get<TransitionMatrixInfectedSevereToDead<FP>>().rows();
dydt.segment(LctState::template get_first_index<InfectionState::InfectedSevere>() +
dimensionInfectedSevereToInfectedCritical,
dimensionInfectedSevereToDead) +=
params.template get<TransitionMatrixInfectedSevereToDead<FP>>().transpose() *
y.segment(LctState::template get_first_index<InfectionState::InfectedSevere>() +
dimensionInfectedSevereToInfectedCritical,
dimensionInfectedSevereToDead);
// Flow from InfectedSevere To Recovered.
size_t dimensionInfectedSevereToRecovered =
params.template get<TransitionMatrixInfectedSevereToRecovered<FP>>().rows();
dydt.segment(LctState::template get_first_index<InfectionState::InfectedSevere>() +
dimensionInfectedSevereToInfectedCritical,
dimensionInfectedSevereToInfectedCritical + dimensionInfectedSevereToDead,
dimensionInfectedSevereToRecovered) +=
params.template get<TransitionMatrixInfectedSevereToRecovered<FP>>().transpose() *
y.segment(LctState::template get_first_index<InfectionState::InfectedSevere>() +
dimensionInfectedSevereToInfectedCritical,
dimensionInfectedSevereToInfectedCritical + dimensionInfectedSevereToDead,
dimensionInfectedSevereToRecovered);
// Add flow directly to Recovered compartment.
dydt[LctState::template get_first_index<InfectionState::Recovered>()] +=
-(params.template get<TransitionMatrixInfectedSevereToRecovered<FP>>() *
Eigen::VectorX<FP>::Ones(dimensionInfectedSevereToRecovered))
.transpose() *
y.segment(LctState::template get_first_index<InfectionState::InfectedSevere>() +
dimensionInfectedSevereToInfectedCritical,
dimensionInfectedSevereToInfectedCritical + dimensionInfectedSevereToDead,
dimensionInfectedSevereToRecovered);

// --- InfectedCritical. ---
Expand Down Expand Up @@ -325,7 +334,14 @@ class Model
dimensionInfectedCriticalToRecovered);

// --- Dead. ---
dydt[LctState::template get_first_index<InfectionState::Dead>()] =
dydt[LctState::template get_first_index<InfectionState::Dead>()] +=
-(params.template get<TransitionMatrixInfectedSevereToDead<FP>>() *
Eigen::VectorX<FP>::Ones(dimensionInfectedSevereToDead))
.transpose() *
y.segment(LctState::template get_first_index<InfectionState::InfectedSevere>() +
dimensionInfectedSevereToInfectedCritical,
dimensionInfectedSevereToDead);
dydt[LctState::template get_first_index<InfectionState::Dead>()] +=
-(params.template get<TransitionMatrixInfectedCriticalToDead<FP>>() *
Eigen::VectorX<FP>::Ones(dimensionInfectedCriticalToDead))
.transpose() *
Expand Down
45 changes: 41 additions & 4 deletions cpp/models/glct_secir/parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,31 @@ struct TransitionMatrixInfectedSevereToInfectedCritical {
}
};

/**
* @brief Transition matrix of the phase-type distribution describing the stay time in the InfectedSevere
* compartment before dying.
*/
template <typename FP>
struct TransitionMatrixInfectedSevereToDead {
using Type = Eigen::MatrixX<FP>;
/**
* @brief Default parameters can be used to get an Erlang distributed stay time in InfectedSevere compartment
* before dying.
* @param[in] dimension Number of rows/columns of the transition matrix.
* @param[in] time Average time spent in InfectedSevere before dying in day unit.
*/
static Type get_default(size_t dimension, FP time = 1.)
{
Eigen::MatrixX<FP> def = Eigen::VectorX<FP>::Constant(dimension, -(FP)dimension / time).asDiagonal();
def.diagonal(1).setConstant((FP)dimension / time);
return def;
}
static std::string name()
{
return "TransitionMatrixInfectedSevereToDead";
}
};

/**
* @brief Transition matrix of the phase-type distribution describing the stay time in the InfectedSevere
* compartment before recovery.
Expand Down Expand Up @@ -461,10 +486,11 @@ using ParametersBase =
TransitionMatrixInfectedNoSymptomsToRecovered<FP>, StartingProbabilitiesInfectedSymptoms<FP>,
TransitionMatrixInfectedSymptomsToInfectedSevere<FP>, TransitionMatrixInfectedSymptomsToRecovered<FP>,
StartingProbabilitiesInfectedSevere<FP>, TransitionMatrixInfectedSevereToInfectedCritical<FP>,
TransitionMatrixInfectedSevereToRecovered<FP>, StartingProbabilitiesInfectedCritical<FP>,
TransitionMatrixInfectedCriticalToDead<FP>, TransitionMatrixInfectedCriticalToRecovered<FP>,
TransmissionProbabilityOnContact<FP>, ContactPatterns<FP>, RelativeTransmissionNoSymptoms<FP>,
RiskOfInfectionFromSymptomatic<FP>, StartDay<FP>, Seasonality<FP>>;
TransitionMatrixInfectedSevereToDead<FP>, TransitionMatrixInfectedSevereToRecovered<FP>,
StartingProbabilitiesInfectedCritical<FP>, TransitionMatrixInfectedCriticalToDead<FP>,
TransitionMatrixInfectedCriticalToRecovered<FP>, TransmissionProbabilityOnContact<FP>,
ContactPatterns<FP>, RelativeTransmissionNoSymptoms<FP>, RiskOfInfectionFromSymptomatic<FP>,
StartDay<FP>, Seasonality<FP>>;

/// @brief Parameters of an GLCT-SECIR model.
template <typename FP>
Expand Down Expand Up @@ -523,6 +549,8 @@ class Parameters : public ParametersBase<FP>
this->template get<TransitionMatrixInfectedSymptomsToRecovered<FP>>().rows()) ||
(this->template get<TransitionMatrixInfectedSevereToInfectedCritical<FP>>().cols() !=
this->template get<TransitionMatrixInfectedSevereToInfectedCritical<FP>>().rows()) ||
(this->template get<TransitionMatrixInfectedSevereToDead<FP>>().cols() !=
this->template get<TransitionMatrixInfectedSevereToDead<FP>>().rows()) ||
(this->template get<TransitionMatrixInfectedSevereToRecovered<FP>>().cols() !=
this->template get<TransitionMatrixInfectedSevereToRecovered<FP>>().rows()) ||
(this->template get<TransitionMatrixInfectedCriticalToDead<FP>>().cols() !=
Expand Down Expand Up @@ -559,6 +587,7 @@ class Parameters : public ParametersBase<FP>

if (this->template get<StartingProbabilitiesInfectedSevere<FP>>().rows() !=
this->template get<TransitionMatrixInfectedSevereToInfectedCritical<FP>>().rows() +
this->template get<TransitionMatrixInfectedSevereToDead<FP>>().rows() +
this->template get<TransitionMatrixInfectedSevereToRecovered<FP>>().rows()) {
log_error("Constraint check: Dimensions of StartingProbabilitiesInfectedSevere and "
"TransitionMatrices of InfectedSevere compartment are not matching.");
Expand Down Expand Up @@ -653,6 +682,14 @@ class Parameters : public ParametersBase<FP>
"flow InfectedSevereToInfectedCritical.");
return true;
}
if (((this->template get<TransitionMatrixInfectedSevereToDead<FP>>() *
Eigen::VectorX<FP>::Ones(this->template get<TransitionMatrixInfectedSevereToDead<FP>>().rows()))
.array() > 1e-10)
.any()) {
log_warning("Constraint check: The entries of TransitionMatrixInfectedSevereToDead lead to a negative "
"flow InfectedSevereToDead.");
return true;
}
if (((this->template get<TransitionMatrixInfectedSevereToRecovered<FP>>() *
Eigen::VectorX<FP>::Ones(this->template get<TransitionMatrixInfectedSevereToRecovered<FP>>().rows()))
.array() > 1e-10)
Expand Down
3 changes: 0 additions & 3 deletions cpp/models/ide_secir/parameters_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ namespace isecir
* using the means of the respective TransitionDistribution.
* The flow InfectedNoSymptomsToInfectedSymptoms is calculated with the standard formula from the IDE model
* using the results for ExposedToInfectedNoSymptoms.
* Throughout this RKI-based initialization, we assume that individuals can only die from InfectedCritical and not from
* InfectedSevere, i.e. this initialization routine assumes that the probability from transitioning from InfectedSevere
* to Dead is 0.
*
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When thinking about the initialization again with regard to the LCT model, I noticed that the new transition doesn't actually affect the initialization based on RKI data which is why I removed this comment here for the IDE-SECIR model again.

* The number of deaths used in the model is computed by shifting the reported RKI data according to the mean values of the transitions
* InfectedSymptomsToInfectedSevere, InfectedSevereToInfectedCritical and InfectedCriticalToDead.
Expand Down
9 changes: 5 additions & 4 deletions cpp/models/lct_secir/infection_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ enum class InfectionTransition
InfectedSymptomsToInfectedSevere = 4,
InfectedSymptomsToRecovered = 5,
InfectedSevereToInfectedCritical = 6,
InfectedSevereToRecovered = 7,
InfectedCriticalToDead = 8,
InfectedCriticalToRecovered = 9,
Count = 10
InfectedSevereToDead = 7,
InfectedSevereToRecovered = 8,
InfectedCriticalToDead = 9,
InfectedCriticalToRecovered = 10,
Count = 11
};

} // namespace lsecir
Expand Down
Loading
Loading