Skip to content

Commit bc69d42

Browse files
1279 minor additions to how infections work (#1320)
Co-authored-by: Sascha <[email protected]> - Add InfectionRateFromViralShed parameter - Rename infectivity functionality to viral shed functionality - Removed distributions from viral shed parameters; this is not required to have - Rework infection setup, initial stay duration is now drawn randomly when initialized somewhere in the middle of the infection
1 parent 3586d84 commit bc69d42

14 files changed

Lines changed: 650 additions & 397 deletions

cpp/models/abm/analyze_result.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,6 @@ std::vector<Model> ensemble_params_percentile(const std::vector<std::vector<Mode
169169
return model.parameters.template get<DeathsPerInfectedCritical>()[{virus_variant, age_group}];
170170
});
171171

172-
param_percentile(node, [age_group, virus_variant](auto&& model) -> auto& {
173-
return model.parameters.template get<DetectInfection>()[{virus_variant, age_group}];
174-
});
175-
176172
param_percentile(node, [virus_variant](auto&& model) -> auto& {
177173
return model.parameters.template get<AerosolTransmissionRates>()[{virus_variant}];
178174
});
@@ -187,17 +183,17 @@ std::vector<Model> ensemble_params_percentile(const std::vector<std::vector<Mode
187183
return dist1.viral_load_peak < dist2.viral_load_peak;
188184
});
189185
param_percentile_dist(
190-
node, std::vector<InfectivityDistributionsParameters>(num_runs),
186+
node, std::vector<ViralShedTuple>(num_runs),
191187
[age_group, virus_variant](auto&& model) -> auto& {
192-
return model.parameters.template get<InfectivityDistributions>()[{virus_variant, age_group}];
188+
return model.parameters.template get<ViralShedParameters>()[{virus_variant, age_group}];
193189
},
194190
[](auto& dist1, auto& dist2) {
195-
return dist1.infectivity_alpha < dist2.infectivity_alpha;
191+
return dist1.viral_shed_alpha < dist2.viral_shed_alpha;
196192
});
197193
param_percentile_dist(
198194
node, std::vector<mio::AbstractParameterDistribution>(num_runs),
199195
[age_group, virus_variant](auto&& model) -> auto& {
200-
return model.parameters.template get<VirusShedFactor>()[{virus_variant, age_group}];
196+
return model.parameters.template get<ViralShedFactor>()[{virus_variant, age_group}];
201197
},
202198
[](auto& dist1, auto& dist2) {
203199
return dist1 < dist2;

cpp/models/abm/infection.cpp

Lines changed: 307 additions & 232 deletions
Large diffs are not rendered by default.

cpp/models/abm/infection.h

Lines changed: 127 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ namespace mio
3434
namespace abm
3535
{
3636

37+
/**
38+
* @brief Represents a transition period between two infection states.
39+
*/
40+
struct StateTransition {
41+
InfectionState from_state;
42+
InfectionState to_state;
43+
TimeSpan duration; // Duration that the infection stays in from_state before transitioning to to_state.
44+
};
45+
3746
/**
3847
* @brief Models the ViralLoad for an Infection, modelled on a log_10 scale.
3948
* Based on https://www.science.org/doi/full/10.1126/science.abi5273
@@ -58,6 +67,13 @@ struct ViralLoad {
5867
}
5968
};
6069

70+
/**
71+
* @brief Distributions of the relative time that people have been in their initial infection state at the beginning of the simulation.
72+
* Values have to be within [0, 1].
73+
* This makes it possible to draw from a user-defined distribution instead of drawing from a uniform distribution.
74+
*/
75+
using InitialInfectionStateDistribution = CustomIndexArray<AbstractParameterDistribution, VirusVariant, AgeGroup>;
76+
6177
class Infection
6278
{
6379
public:
@@ -77,24 +93,43 @@ class Infection
7793
TimePoint start_date, InfectionState start_state = InfectionState::Exposed,
7894
ProtectionEvent latest_protection = {ProtectionType::NoProtection, TimePoint(0)}, bool detected = false);
7995

96+
/**
97+
* @brief Create an Infection for a single Person with a time spent in the given initial state that is drawn from the given distribution.
98+
* @param[inout] rng PersonalRandomNumberGenerator of the Person.
99+
* @param[in] virus Virus type of the Infection.
100+
* @param[in] age AgeGroup to determine the ViralLoad course.
101+
* @param[in] params Parameters of the Model.
102+
* @param[in] init_date Date of initializing the Infection.
103+
* @param[in] init_state #InfectionState at time of initializing the Infection.
104+
* @param[in] init_state_dist Distribution to draw the relative time spent in the initial state from. Values have to be within [0, 1].
105+
* @param[in] latest_protection The pair value of last ProtectionType (previous Infection/Vaccination) and TimePoint of that protection.
106+
* @param[in] detected If the Infection is detected.
107+
*/
108+
Infection(PersonalRandomNumberGenerator& rng, VirusVariant virus, AgeGroup age, const Parameters& params,
109+
TimePoint init_date, InfectionState init_state, const InitialInfectionStateDistribution& init_state_dist,
110+
ProtectionEvent latest_protection = {ProtectionType::NoProtection, TimePoint(0)}, bool detected = false);
111+
80112
/**
81113
* @brief Gets the ViralLoad of the Infection at a given TimePoint.
82114
* @param[in] t TimePoint of querry.
83115
*/
84116
ScalarType get_viral_load(TimePoint t) const;
85117

86118
/**
87-
* @brief Get infectivity at a given time.
119+
* @brief Get viral shed at a specific time.
88120
* Computed depending on current ViralLoad and individual invlogit function of each Person
89121
* corresponding to https://www.science.org/doi/full/10.1126/science.abi5273
90122
* The mapping corresponds to Fig. 2 C.
91123
* Formula of invlogit function can be found here:
92124
* https://github.com/VirologyCharite/SARS-CoV-2-VL-paper/tree/main
93125
* in ExtendedMethods.html, Section 3.1.2.1.
126+
* * Also in accordance to Fig. 3d of another publication:
127+
* https://www.nature.com/articles/s41564-022-01105-z/figures/3
128+
* The result is in arbitrary units and has to be scaled to the rate "infections per day".
94129
* @param[in] t TimePoint of the querry.
95-
* @return Infectivity at given TimePoint.
130+
* @return Viral shed at given TimePoint.
96131
*/
97-
ScalarType get_infectivity(TimePoint t) const;
132+
ScalarType get_viral_shed(TimePoint t) const;
98133

99134
/**
100135
* @brief: Get VirusVariant.
@@ -133,29 +168,14 @@ class Infection
133168
.add("viral_load", m_viral_load)
134169
.add("log_norm_alpha", m_log_norm_alpha)
135170
.add("log_norm_beta", m_log_norm_beta)
136-
.add("individual_virus_shed_factor", m_individual_virus_shed_factor)
171+
.add("individual_viral_shed_factor", m_individual_viral_shed_factor)
137172
.add("detected", m_detected);
138173
}
139174

140175
private:
141176
friend DefaultFactory<Infection>;
142177
Infection() = default;
143178

144-
/**
145-
* @brief Determine Infection course based on #InfectionState init_state.
146-
* Calls draw_infection_course_backward for all #InfectionState%s prior and draw_infection_course_forward for all
147-
* subsequent #InfectionState%s.
148-
* @param[inout] rng PersonalRandomNumberGenerator of the Person.
149-
* @param[in] age AgeGroup of the Person.
150-
* @param[in] params Parameters of the Model.
151-
* @param[in] init_date Date of initializing the Infection.
152-
* @param[in] init_state #InfectionState at time of initializing the Infection.
153-
* @param[in] latest_protection Latest protection against Infection, has an influence on transition probabilities.
154-
* @return The starting date of the Infection.
155-
*/
156-
TimePoint draw_infection_course(PersonalRandomNumberGenerator& rng, AgeGroup age, const Parameters& params,
157-
TimePoint init_date, InfectionState start_state, ProtectionEvent latest_protection);
158-
159179
/**
160180
* @brief Determine Infection course subsequent to the given #InfectionState start_state.
161181
* From the start_state, a random path through the #InfectionState tree is chosen, that is
@@ -164,8 +184,7 @@ class Infection
164184
* InfectedSymptoms -> Infected_Severe or InfectedSymptoms -> Recovered,
165185
* InfectedSevere -> InfectedCritical or InfectedSevere -> Recovered or InfectedSevere -> Dead,
166186
* InfectedCritical -> Recovered or InfectedCritical -> Dead,
167-
* with artifical, hardcoded probabilites, until either Recoverd or Dead is reached.
168-
* This is subject to change when parameter distributions for these transitions are implemented.
187+
* until either Recoverd or Dead is reached.
169188
* The duration in each #InfectionState is taken from the respective parameter.
170189
* @param[inout] rng PersonalRandomNumberGenerator of the Person.
171190
* @param[in] age AgeGroup of the Person.
@@ -192,12 +211,97 @@ class Infection
192211
TimePoint draw_infection_course_backward(PersonalRandomNumberGenerator& rng, AgeGroup age, const Parameters& params,
193212
TimePoint init_date, InfectionState init_state);
194213

214+
/**
215+
* @brief Initialize the viral load parameters for the infection.
216+
* @param[inout] rng PersonalRandomNumberGenerator of the Person.
217+
* @param[in] virus Virus type of the Infection.
218+
* @param[in] age AgeGroup of the Person.
219+
* @param[in] params Parameters of the Model.
220+
* @param[in] latest_protection Latest protection against Infection.
221+
*/
222+
void initialize_viral_load(PersonalRandomNumberGenerator& rng, VirusVariant virus, AgeGroup age,
223+
const Parameters& params, ProtectionEvent latest_protection);
224+
225+
/**
226+
* @brief Initialize the viral shed parameters and individual factor for the infection.
227+
* @param[inout] rng PersonalRandomNumberGenerator of the Person.
228+
* @param[in] virus Virus type of the Infection.
229+
* @param[in] age AgeGroup of the Person.
230+
* @param[in] params Parameters of the Model.
231+
*/
232+
void initialize_viral_shed(PersonalRandomNumberGenerator& rng, VirusVariant virus, AgeGroup age,
233+
const Parameters& params);
234+
235+
/**
236+
* @brief Get the forward transition from a given infection state.
237+
* @param[inout] rng PersonalRandomNumberGenerator of the Person.
238+
* @param[in] age AgeGroup of the Person.
239+
* @param[in] params Parameters of the Model.
240+
* @param[in] current_state Current infection state.
241+
* @param[in] current_time Current time point.
242+
* @param[in] latest_protection Latest protection against Infection.
243+
* @return StateTransition representing the next transition.
244+
*/
245+
StateTransition get_forward_transition(PersonalRandomNumberGenerator& rng, AgeGroup age, const Parameters& params,
246+
InfectionState current_state, TimePoint current_time,
247+
ProtectionEvent latest_protection) const;
248+
249+
/**
250+
* @brief Get the backward transition from a given infection state.
251+
* @param[inout] rng PersonalRandomNumberGenerator of the Person.
252+
* @param[in] age AgeGroup of the Person.
253+
* @param[in] params Parameters of the Model.
254+
* @param[in] current_state Current infection state.
255+
* @return StateTransition representing the previous transition.
256+
*/
257+
StateTransition get_backward_transition(PersonalRandomNumberGenerator& rng, AgeGroup age, const Parameters& params,
258+
InfectionState current_state) const;
259+
260+
/**
261+
* @brief Get the backward transition from recovered state.
262+
* @param[inout] rng PersonalRandomNumberGenerator of the Person.
263+
* @param[in] age AgeGroup of the Person.
264+
* @param[in] params Parameters of the Model.
265+
* @return StateTransition representing the transition that led to recovery.
266+
*/
267+
StateTransition get_recovered_backward_transition(PersonalRandomNumberGenerator& rng, AgeGroup age,
268+
const Parameters& params) const;
269+
270+
/**
271+
* @brief Get the backward transition from dead state.
272+
* @param[inout] rng PersonalRandomNumberGenerator of the Person.
273+
* @param[in] age AgeGroup of the Person.
274+
* @param[in] params Parameters of the Model.
275+
* @return StateTransition representing the transition that led to death.
276+
*/
277+
StateTransition get_dead_backward_transition(PersonalRandomNumberGenerator& rng, AgeGroup age,
278+
const Parameters& params) const;
279+
280+
/**
281+
* @brief Calculate the overall death probability for the infection.
282+
* @param[in] age AgeGroup of the Person.
283+
* @param[in] params Parameters of the Model.
284+
* @return The probability of death for this infection.
285+
*/
286+
ScalarType calculate_death_probability(AgeGroup age, const Parameters& params) const;
287+
288+
/**
289+
* @brief Get the severity protection factor based on latest protection.
290+
* @param[in] params Parameters of the Model.
291+
* @param[in] latest_protection Latest protection against Infection.
292+
* @param[in] age AgeGroup of the Person.
293+
* @param[in] current_time Current time point.
294+
* @return The protection factor against severe outcomes.
295+
*/
296+
ScalarType get_severity_protection_factor(const Parameters& params, ProtectionEvent latest_protection, AgeGroup age,
297+
TimePoint current_time) const;
298+
195299
std::vector<std::pair<TimePoint, InfectionState>> m_infection_course; ///< Start date of each #InfectionState.
196300
VirusVariant m_virus_variant; ///< Variant of the Infection.
197301
ViralLoad m_viral_load; ///< ViralLoad of the Infection.
198302
ScalarType m_log_norm_alpha,
199-
m_log_norm_beta; ///< Parameters for the infectivity mapping, which is modelled through an invlogit function.
200-
ScalarType m_individual_virus_shed_factor; ///< Individual virus shed factor.
303+
m_log_norm_beta; ///< Parameters for the viral shed mapping, which is modelled through an invlogit function.
304+
ScalarType m_individual_viral_shed_factor; ///< Individual viral shed factor.
201305
bool m_detected; ///< Whether an Infection is detected or not.
202306
};
203307

0 commit comments

Comments
 (0)