@@ -56,6 +56,10 @@ IOResult<void> set_initial_flows(Model& model, ScalarType dt, std::string const&
5656 log_error (" Specified date does not exist in RKI data." );
5757 return failure (StatusCode::OutOfRange, path + " , specified date does not exist in RKI data." );
5858 }
59+ auto min_date_entry = std::min_element (rki_data.begin (), rki_data.end (), [](auto && a, auto && b) {
60+ return a.date < b.date ;
61+ });
62+ auto min_date = min_date_entry->date ;
5963
6064 // Get (global) support_max to determine how many flows in the past we have to compute.
6165 ScalarType global_support_max = model.get_global_support_max (dt);
@@ -71,17 +75,33 @@ IOResult<void> set_initial_flows(Model& model, ScalarType dt, std::string const&
7175 0 , TimeSeries<ScalarType>::Vector::Constant ((int )InfectionState::Count, 0 ));
7276 }
7377
74- // The first time we need is -4 * global_support_max .
75- Eigen::Index start_shift = 4 * global_support_max_index ;
76- // The last time needed is dependent on the mean stay time in the Exposed compartment and
77- // the mean stay time of asymptomatic individuals in InfectedNoSymptoms .
78+ // Set the Dead compartment to 0 so that RKI data can be added correctly .
79+ model. m_populations [ 0 ][ Eigen::Index (InfectionState::Dead)] = 0 ;
80+
81+ // Define variables for the mean of transitions used .
7882 ScalarType mean_ExposedToInfectedNoSymptoms =
7983 model.parameters .get <TransitionDistributions>()[Eigen::Index (InfectionTransition::ExposedToInfectedNoSymptoms)]
8084 .get_mean (dt);
8185 ScalarType mean_InfectedNoSymptomsToInfectedSymptoms =
8286 model.parameters
83- .get <TransitionDistributions>()[Eigen::Index ( InfectionTransition::InfectedNoSymptomsToInfectedSymptoms) ]
87+ .get <TransitionDistributions>()[( Eigen::Index) InfectionTransition::InfectedNoSymptomsToInfectedSymptoms]
8488 .get_mean (dt);
89+ ScalarType mean_InfectedSymptomsToInfectedSevere =
90+ model.parameters
91+ .get <TransitionDistributions>()[(Eigen::Index)InfectionTransition::InfectedSymptomsToInfectedSevere]
92+ .get_mean ();
93+ ScalarType mean_InfectedSevereToInfectedCritical =
94+ model.parameters
95+ .get <TransitionDistributions>()[(Eigen::Index)InfectionTransition::InfectedSevereToInfectedCritical]
96+ .get_mean ();
97+ ScalarType mean_InfectedCriticalToDead =
98+ model.parameters .get <TransitionDistributions>()[(Eigen::Index)InfectionTransition::InfectedCriticalToDead]
99+ .get_mean ();
100+
101+ // The first time we need is -4 * global_support_max.
102+ Eigen::Index start_shift = 4 * global_support_max_index;
103+ // The last time needed is dependent on the mean stay time in the Exposed compartment and
104+ // the mean stay time of asymptomatic individuals in InfectedNoSymptoms.
85105 Eigen::Index last_time_index_needed =
86106 Eigen::Index (std::ceil ((mean_ExposedToInfectedNoSymptoms + mean_InfectedNoSymptomsToInfectedSymptoms) / dt));
87107 // Create TimeSeries with zeros. The index of time zero is start_shift.
@@ -99,6 +119,7 @@ IOResult<void> set_initial_flows(Model& model, ScalarType dt, std::string const&
99119
100120 bool min_offset_needed_avail = false ;
101121 bool max_offset_needed_avail = false ;
122+
102123 // Go through the entries of rki_data and check if date is needed for calculation. Confirmed cases are scaled.
103124 // Define dummy variables to store the first and the last index of the TimeSeries where the considered entry of rki_data is potentially needed.
104125 Eigen::Index idx_needed_first = 0 ;
@@ -110,6 +131,9 @@ IOResult<void> set_initial_flows(Model& model, ScalarType dt, std::string const&
110131 if (offset == min_offset_needed) {
111132 min_offset_needed_avail = true ;
112133 }
134+ if (offset == max_offset_needed) {
135+ max_offset_needed_avail = true ;
136+ }
113137 // Smallest index for which the entry is needed.
114138 idx_needed_first =
115139 Eigen::Index (std::max (std::floor ((offset - model.m_transitions .get_time (0 ) - 1 ) / dt), 0 .));
@@ -137,21 +161,51 @@ IOResult<void> set_initial_flows(Model& model, ScalarType dt, std::string const&
137161 }
138162 }
139163
140- if (offset == max_offset_needed) {
141- max_offset_needed_avail = true ;
164+ // Compute Dead by shifting RKI data according to mean stay times.
165+ // This is done because the RKI reports death with the date of positive test instead of the date of deaths.
166+ if (offset == std::floor (-mean_InfectedSymptomsToInfectedSevere - mean_InfectedSevereToInfectedCritical -
167+ mean_InfectedCriticalToDead)) {
168+ model.m_populations [0 ][Eigen::Index (InfectionState::Dead)] +=
169+ (1 - (-mean_InfectedSymptomsToInfectedSevere - mean_InfectedSevereToInfectedCritical -
170+ mean_InfectedCriticalToDead -
171+ std::floor (-mean_InfectedSymptomsToInfectedSevere - mean_InfectedSevereToInfectedCritical -
172+ mean_InfectedCriticalToDead))) *
173+ entry.num_deaths ;
142174 }
175+ if (offset == std::ceil (-mean_InfectedSymptomsToInfectedSevere - mean_InfectedSevereToInfectedCritical -
176+ mean_InfectedCriticalToDead)) {
177+ model.m_populations [0 ][Eigen::Index (InfectionState::Dead)] +=
178+ (-mean_InfectedSymptomsToInfectedSevere - mean_InfectedSevereToInfectedCritical -
179+ mean_InfectedCriticalToDead -
180+ std::floor (-mean_InfectedSymptomsToInfectedSevere - mean_InfectedSevereToInfectedCritical -
181+ mean_InfectedCriticalToDead)) *
182+ entry.num_deaths ;
183+ }
184+
143185 if (offset == 0 ) {
144- model.m_populations [0 ][Eigen::Index (InfectionState::Dead)] = entry.num_deaths ;
145186 model.m_total_confirmed_cases = scale_confirmed_cases * entry.num_confirmed ;
146187 }
147188 }
148189 }
149190
150- if (!max_offset_needed_avail || !min_offset_needed_avail ) {
191+ if (!max_offset_needed_avail) {
151192 log_error (" Necessary range of dates needed to compute initial values does not exist in RKI data." );
152193 return failure (StatusCode::OutOfRange, path + " , necessary range of dates does not exist in RKI data." );
153194 }
154195
196+ if (!min_offset_needed_avail) {
197+ std::string min_date_string =
198+ std::to_string (min_date.day ) + " ." + std::to_string (min_date.month ) + " ." + std::to_string (min_date.year );
199+ // Get first date that is needed.
200+ mio::Date min_offset_date = offset_date_by_days (date, int (min_offset_needed));
201+ std::string min_offset_date_string = std::to_string (min_offset_date.day ) + " ." +
202+ std::to_string (min_offset_date.month ) + " ." +
203+ std::to_string (min_offset_date.year );
204+ log_warning (" RKI data is needed from " + min_offset_date_string +
205+ " to compute initial values. RKI data is only available from " + min_date_string +
206+ " . Missing dates were set to 0." );
207+ }
208+
155209 // --- Calculate the flows "after" InfectedNoSymptomsToInfectedSymptoms. ---
156210 // Compute flow InfectedSymptomsToInfectedSevere for -3 * global_support_max, ..., 0.
157211 for (Eigen::Index i = -3 * global_support_max_index; i <= 0 ; i++) {
@@ -183,10 +237,10 @@ IOResult<void> set_initial_flows(Model& model, ScalarType dt, std::string const&
183237 }
184238
185239 // --- Calculate the remaining flows. ---
186- // Compute flow ExposedToInfectedNoSymptoms for -global_support_max, ..., 0.
240+ // Compute flow ExposedToInfectedNoSymptoms for -2 * global_support_max, ..., 0.
187241 // Use mean value of the TransitionDistribution InfectedNoSymptomsToInfectedSymptoms for the calculation.
188242 Eigen::Index index_shift_mean = Eigen::Index (std::round (mean_InfectedNoSymptomsToInfectedSymptoms / dt));
189- for (Eigen::Index i = -global_support_max_index; i <= 0 ; i++) {
243+ for (Eigen::Index i = -2 * global_support_max_index; i <= 0 ; i++) {
190244 model.m_transitions [i + start_shift][Eigen::Index (InfectionTransition::ExposedToInfectedNoSymptoms)] =
191245 (1 / model.parameters .get <TransitionProbabilities>()[Eigen::Index (
192246 InfectionTransition::InfectedNoSymptomsToInfectedSymptoms)]) *
@@ -226,4 +280,4 @@ IOResult<void> set_initial_flows(Model& model, ScalarType dt, std::string const&
226280} // namespace isecir
227281} // namespace mio
228282
229- #endif // MEMILIO_HAS_JSONCPP
283+ #endif // MEMILIO_HAS_JSONCPP
0 commit comments