@@ -29,14 +29,14 @@ namespace abm
2929{
3030
3131void Infection::initialize_viral_load (PersonalRandomNumberGenerator& rng, VirusVariant virus, AgeGroup age,
32- const Parameters& params, TimePoint init_date, ProtectionEvent latest_protection)
32+ const Parameters& params, ProtectionEvent latest_protection)
3333{
3434 auto & vl_params = params.get <ViralLoadDistributions>()[{virus, age}];
3535 ScalarType high_viral_load_factor = 1 ;
3636
3737 if (latest_protection.type != ProtectionType::NoProtection) {
3838 high_viral_load_factor -= params.get <HighViralLoadProtectionFactor>()[{latest_protection.type , age, virus}](
39- init_date .days () - latest_protection.time .days ());
39+ m_viral_load. start_date .days () - latest_protection.time .days ());
4040 }
4141
4242 m_viral_load.peak = vl_params.viral_load_peak .get (rng) * high_viral_load_factor;
@@ -57,15 +57,56 @@ void Infection::initialize_viral_shed(PersonalRandomNumberGenerator& rng, VirusV
5757 m_individual_viral_shed_factor = shedfactor_param.get (rng);
5858}
5959
60+ TimePoint Infection::shift_init_date (const InitialInfectionStateDistribution& init_state_dist,
61+ PersonalRandomNumberGenerator& rng, VirusVariant virus, AgeGroup age,
62+ TimePoint init_date)
63+ {
64+ auto dist = init_state_dist[{virus, age}];
65+ TimeSpan time_in_state = days (dist.get (rng));
66+ return init_date - time_in_state;
67+ }
68+
6069Infection::Infection (PersonalRandomNumberGenerator& rng, VirusVariant virus, AgeGroup age, const Parameters& params,
6170 TimePoint init_date, InfectionState init_state, ProtectionEvent latest_protection, bool detected)
6271 : m_virus_variant(virus)
6372 , m_detected(detected)
6473{
6574 assert (age.get () < params.get_num_groups ());
66- m_viral_load.start_date = draw_infection_course (rng, age, params, init_date, init_state, latest_protection);
75+ assert (init_state != InfectionState::Susceptible &&
76+ " Initializatin of an Infection must happen with an InfectionState that is not Suscpetible." );
77+
78+ draw_infection_course_forward (rng, age, params, init_date, init_state, latest_protection);
79+ m_viral_load.start_date = draw_infection_course_backward (rng, age, params, init_date, init_state);
80+
81+ initialize_viral_load (rng, virus, age, params, latest_protection);
82+ initialize_viral_shed (rng, virus, age, params);
83+ }
84+
85+ Infection::Infection (PersonalRandomNumberGenerator& rng, VirusVariant virus, AgeGroup age, const Parameters& params,
86+ TimePoint init_date, InfectionState init_state,
87+ const InitialInfectionStateDistribution& init_state_dist, ProtectionEvent latest_protection,
88+ bool detected)
89+ : m_virus_variant(virus)
90+ , m_detected(detected)
91+ {
92+ assert (age.get () < params.get_num_groups ());
93+ assert (init_state != InfectionState::Susceptible &&
94+ " Initializatin of an Infection must happen with an InfectionState that is not Suscpetible." );
95+
96+ // Draw the first transition and time that the agent has already spent in that state
97+ StateTransition first_transition =
98+ get_forward_transition (rng, age, params, init_state, init_date, latest_protection);
99+ ScalarType relative_time_in_first_state = init_state_dist[{virus, age}].get (rng);
100+
101+ init_date -= first_transition.duration .multiply (relative_time_in_first_state);
102+ m_infection_course.push_back ({init_date, first_transition.from_state });
67103
68- initialize_viral_load (rng, virus, age, params, init_date, latest_protection);
104+ // Draw the rest of the infection course
105+ draw_infection_course_forward (rng, age, params, init_date + first_transition.duration , first_transition.to_state ,
106+ latest_protection);
107+ m_viral_load.start_date = draw_infection_course_backward (rng, age, params, init_date, init_state);
108+
109+ initialize_viral_load (rng, virus, age, params, latest_protection);
69110 initialize_viral_shed (rng, virus, age, params);
70111}
71112
@@ -131,9 +172,8 @@ TimePoint Infection::draw_infection_course(PersonalRandomNumberGenerator& rng, A
131172 TimePoint init_date, InfectionState init_state,
132173 ProtectionEvent latest_protection)
133174{
134- TimePoint start_of_init_state =
135- draw_infection_course_forward (rng, age, params, init_date, init_state, latest_protection);
136- TimePoint start_date = draw_infection_course_backward (rng, age, params, start_of_init_state, init_state);
175+ draw_infection_course_forward (rng, age, params, init_date, init_state, latest_protection);
176+ TimePoint start_date = draw_infection_course_backward (rng, age, params, init_date, init_state);
137177 return start_date;
138178}
139179
@@ -145,10 +185,6 @@ StateTransition Infection::get_forward_transition(PersonalRandomNumberGenerator&
145185 StateTransition transition{current_state, current_state, TimeSpan{}};
146186
147187 switch (current_state) {
148- case InfectionState::Susceptible:
149- transition.to_state = InfectionState::Exposed;
150- transition.duration = mio::abm::hours (0 );
151- break ;
152188
153189 case InfectionState::Exposed:
154190 transition.to_state = InfectionState::InfectedNoSymptoms;
@@ -192,14 +228,14 @@ StateTransition Infection::get_forward_transition(PersonalRandomNumberGenerator&
192228 ScalarType critical_prob = params.get <CriticalPerInfectedSevere>()[{m_virus_variant, age}];
193229 ScalarType death_prob = params.get <DeathsPerInfectedSevere>()[{m_virus_variant, age}];
194230
195- if (p < critical_prob) {
196- transition.to_state = InfectionState::InfectedCritical;
197- transition.duration = days (params.get <TimeInfectedSevereToCritical>()[{m_virus_variant, age}].get (rng));
198- }
199- else if (p < critical_prob + death_prob) {
231+ if (p < death_prob) {
200232 transition.to_state = InfectionState::Dead;
201233 transition.duration = days (params.get <TimeInfectedSevereToDead>()[{m_virus_variant, age}].get (rng));
202234 }
235+ else if (p < critical_prob + death_prob) {
236+ transition.to_state = InfectionState::InfectedCritical;
237+ transition.duration = days (params.get <TimeInfectedSevereToCritical>()[{m_virus_variant, age}].get (rng));
238+ }
203239 else {
204240 transition.to_state = InfectionState::Recovered;
205241 transition.duration = days (params.get <TimeInfectedSevereToRecovered>()[{m_virus_variant, age}].get (rng));
@@ -276,7 +312,7 @@ StateTransition Infection::get_recovered_backward_transition(PersonalRandomNumbe
276312
277313 // Compute death probability to factor it out
278314 ScalarType p_death = calculate_death_probability (age, params);
279- assert (p_death == 1 && " Trying to create a recovered agent although the chance to die is 100%." );
315+ assert (p_death < 1 && " Trying to create a recovered agent although the chance to die is 100%." );
280316 ScalarType inv_death = 1 / (1 - p_death);
281317
282318 ScalarType symptoms_prob = params.get <SymptomsPerInfectedNoSymptoms>()[{m_virus_variant, age}];
@@ -343,40 +379,29 @@ ScalarType Infection::get_severity_protection_factor(const Parameters& params, P
343379 current_time.days () - latest_protection.time .days ());
344380}
345381
346- TimePoint Infection::draw_infection_course_forward (PersonalRandomNumberGenerator& rng, AgeGroup age,
347- const Parameters& params, TimePoint init_date,
348- InfectionState start_state, ProtectionEvent latest_protection)
382+ void Infection::draw_infection_course_forward (PersonalRandomNumberGenerator& rng, AgeGroup age,
383+ const Parameters& params, TimePoint init_date, InfectionState start_state ,
384+ ProtectionEvent latest_protection)
349385{
350- TimePoint start_of_init_state = init_date; // since there is no state transition from Recovered or Dead
351- bool init = true ; // the random start time of the first state cannot be drawn
352- // thus, just use the init_date as the start for this
353- auto & init_state_dist = params.get <InitialInfectionStateDistributions>()[{m_virus_variant, age, start_state}];
354-
355386 TimePoint current_time = init_date;
356387 InfectionState current_state = start_state;
357388 m_infection_course.push_back ({current_time, current_state});
358389
359390 while (current_state != InfectionState::Recovered && current_state != InfectionState::Dead) {
360391 StateTransition transition =
361392 get_forward_transition (rng, age, params, current_state, current_time, latest_protection);
362- if (init && current_state != InfectionState::Susceptible) { // random init within first time period
363- ScalarType p = init_state_dist.get (rng);
364- start_of_init_state -= transition.duration .multiply (1 - p);
365- transition.duration = transition.duration .multiply (p);
366- init = false ;
367- }
393+
368394 current_time += transition.duration ;
369395 current_state = transition.to_state ;
370396 m_infection_course.push_back ({current_time, current_state});
371397 }
372- return start_of_init_state;
373398}
374399
375400TimePoint Infection::draw_infection_course_backward (PersonalRandomNumberGenerator& rng, AgeGroup age,
376- const Parameters& params, TimePoint start_of_init_state ,
401+ const Parameters& params, TimePoint init_date ,
377402 InfectionState init_state)
378403{
379- TimePoint current_time = start_of_init_state ;
404+ TimePoint current_time = init_date ;
380405 InfectionState current_state = init_state;
381406
382407 while (current_state != InfectionState::Exposed) {
0 commit comments