LCOV - code coverage report
Current view: top level - models/ode_secirvvs - parameters_io.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 473 482 98.1 %
Date: 2024-11-18 12:45:26 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /* 
       2             : * Copyright (C) 2020-2024 MEmilio
       3             : *
       4             : * Authors: Wadim Koslow, Daniel Abele, Martin J. Kühn
       5             : *
       6             : * Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
       7             : *
       8             : * Licensed under the Apache License, Version 2.0 (the "License");
       9             : * you may not use this file except in compliance with the License.
      10             : * You may obtain a copy of the License at
      11             : *
      12             : *     http://www.apache.org/licenses/LICENSE-2.0
      13             : *
      14             : * Unless required by applicable law or agreed to in writing, software
      15             : * distributed under the License is distributed on an "AS IS" BASIS,
      16             : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      17             : * See the License for the specific language governing permissions and
      18             : * limitations under the License.
      19             : */
      20             : #ifndef ODESECIRVVS_PARAMETERS_IO_H
      21             : #define ODESECIRVVS_PARAMETERS_IO_H
      22             : 
      23             : #include "memilio/config.h"
      24             : 
      25             : #ifdef MEMILIO_HAS_JSONCPP
      26             : 
      27             : #include "ode_secirvvs/model.h"
      28             : #include "memilio/io/epi_data.h"
      29             : #include "memilio/io/io.h"
      30             : #include "memilio/io/result_io.h"
      31             : #include "memilio/utils/date.h"
      32             : #include "memilio/utils/logging.h"
      33             : 
      34             : namespace mio
      35             : {
      36             : namespace osecirvvs
      37             : {
      38             : 
      39             : namespace details
      40             : {
      41             : /**
      42             :         * @brief Reads subpopulations of infection states from transformed RKI cases file.
      43             :         * @param[in] path Path to transformed RKI cases file.
      44             :         * @param[in] vregion Vector of keys of the region of interest.
      45             :         * @param[in] date Date for which the arrays are initialized.
      46             :         * @param[in, out] num_* Output vector for number of people in the corresponding compartement.
      47             :         * @param[in] vt_* Average time it takes to get from one compartement to another (vector with one element per age group).
      48             :         * @param[in] vmu_* Probabilities to get from one compartement to another (vector with one element per age group).
      49             :         * @param[in] scaling_factor_inf Factor for scaling the confirmed cases to account for estimated undetected cases.
      50             :         * @see mio::read_confirmed_cases_data
      51             :         * @{
      52             :         */
      53             : IOResult<void> read_confirmed_cases_data(
      54             :     std::string const& path, std::vector<int> const& vregion, Date date, std::vector<std::vector<double>>& num_Exposed,
      55             :     std::vector<std::vector<double>>& num_InfectedNoSymptoms, std::vector<std::vector<double>>& num_InfectedSymptoms,
      56             :     std::vector<std::vector<double>>& num_InfectedSevere, std::vector<std::vector<double>>& num_icu,
      57             :     std::vector<std::vector<double>>& num_death, std::vector<std::vector<double>>& num_rec,
      58             :     const std::vector<std::vector<int>>& t_Exposed, const std::vector<std::vector<int>>& t_InfectedNoSymptoms,
      59             :     const std::vector<std::vector<int>>& t_InfectedSymptoms, const std::vector<std::vector<int>>& t_InfectedSevere,
      60             :     const std::vector<std::vector<int>>& t_InfectedCritical, const std::vector<std::vector<double>>& mu_C_R,
      61             :     const std::vector<std::vector<double>>& mu_I_H, const std::vector<std::vector<double>>& mu_H_U,
      62             :     const std::vector<double>& scaling_factor_inf);
      63             : 
      64             : IOResult<void> read_confirmed_cases_data(
      65             :     const std::vector<ConfirmedCasesDataEntry>& rki_data, std::vector<int> const& vregion, Date date,
      66             :     std::vector<std::vector<double>>& num_Exposed, std::vector<std::vector<double>>& num_InfectedNoSymptoms,
      67             :     std::vector<std::vector<double>>& num_InfectedSymptoms, std::vector<std::vector<double>>& num_InfectedSevere,
      68             :     std::vector<std::vector<double>>& num_icu, std::vector<std::vector<double>>& num_death,
      69             :     std::vector<std::vector<double>>& num_rec, const std::vector<std::vector<int>>& t_Exposed,
      70             :     const std::vector<std::vector<int>>& t_InfectedNoSymptoms, const std::vector<std::vector<int>>& t_InfectedSymptoms,
      71             :     const std::vector<std::vector<int>>& t_InfectedSevere, const std::vector<std::vector<int>>& t_InfectedCritical,
      72             :     const std::vector<std::vector<double>>& mu_C_R, const std::vector<std::vector<double>>& mu_I_H,
      73             :     const std::vector<std::vector<double>>& mu_H_U, const std::vector<double>& scaling_factor_inf);
      74             : /**@}*/
      75             : 
      76             : /**
      77             :         * @brief Reads confirmed cases data and translates data of day t0-delay to recovered compartment.
      78             :         * @param[in] path Path to RKI confirmed cases file.
      79             :         * @param[in] vregion Vector of keys of the region of interest.
      80             :         * @param[in] date Date for which the arrays are initialized.
      81             :         * @param[in, out] num_rec Output vector for number of people in the compartement recovered.
      82             :         * @param[in] delay Number of days in the past the are used to set recovered compartment.
      83             :         * @see mio::read_confirmed_cases_data
      84             :         * @{
      85             :         */
      86             : IOResult<void> read_confirmed_cases_data_fix_recovered(const std::vector<ConfirmedCasesDataEntry>& rki_data,
      87             :                                                        std::vector<int> const& vregion, Date date,
      88             :                                                        std::vector<std::vector<double>>& vnum_rec, double delay = 14.);
      89             : IOResult<void> read_confirmed_cases_data_fix_recovered(std::string const& path, std::vector<int> const& vregion,
      90             :                                                        Date date, std::vector<std::vector<double>>& vnum_rec,
      91             :                                                        double delay = 14.);
      92             : /**@}*/
      93             : 
      94             : /**
      95             :         * @brief Sets the confirmed cases data for a vector of models based on input data.
      96             :         * @param[in, out] model Vector of objects in which the data is set.
      97             :         * @param[in] case_data Vector of case data. Each inner vector represents a different region.
      98             :         * @param[in] region Vector of keys of the region of interest.
      99             :         * @param[in] date Date for which the arrays are initialized.
     100             :         * @param[in] scaling_factor_inf Factors by which to scale the confirmed cases of RKI data.
     101             :         * @param[in] set_death If true, set the number of deaths.
     102             :         */
     103             : template <class Model>
     104          90 : IOResult<void> set_confirmed_cases_data(std::vector<Model>& model,
     105             :                                         const std::vector<ConfirmedCasesDataEntry>& case_data,
     106             :                                         std::vector<int> const& region, Date date,
     107             :                                         const std::vector<double>& scaling_factor_inf, bool set_death = false)
     108             : {
     109          90 :     auto num_age_groups = (size_t)model[0].parameters.get_num_groups();
     110          90 :     assert(scaling_factor_inf.size() == num_age_groups); //TODO: allow vector or scalar valued scaling factors
     111          90 :     assert(ConfirmedCasesDataEntry::age_group_names.size() == num_age_groups);
     112             : 
     113         180 :     std::vector<std::vector<int>> t_Exposed{model.size()};
     114         180 :     std::vector<std::vector<int>> t_InfectedNoSymptoms{model.size()};
     115         180 :     std::vector<std::vector<int>> t_InfectedSymptoms{model.size()};
     116         180 :     std::vector<std::vector<int>> t_InfectedSevere{model.size()};
     117         180 :     std::vector<std::vector<int>> t_InfectedCritical{model.size()};
     118             : 
     119         180 :     std::vector<std::vector<double>> mu_C_R{model.size()};
     120         180 :     std::vector<std::vector<double>> mu_I_H{model.size()};
     121         180 :     std::vector<std::vector<double>> mu_H_U{model.size()};
     122             : 
     123         180 :     std::vector<std::vector<double>> num_InfectedSymptoms(model.size());
     124         180 :     std::vector<std::vector<double>> num_death(model.size());
     125         180 :     std::vector<std::vector<double>> num_rec(model.size());
     126         180 :     std::vector<std::vector<double>> num_Exposed(model.size());
     127         180 :     std::vector<std::vector<double>> num_InfectedNoSymptoms(model.size());
     128         180 :     std::vector<std::vector<double>> num_InfectedSevere(model.size());
     129         180 :     std::vector<std::vector<double>> num_icu(model.size());
     130             : 
     131             :     /*----------- UNVACCINATED -----------*/
     132         180 :     for (size_t county = 0; county < model.size(); county++) {
     133          90 :         num_InfectedSymptoms[county]   = std::vector<double>(num_age_groups, 0.0);
     134          90 :         num_death[county]              = std::vector<double>(num_age_groups, 0.0);
     135          90 :         num_rec[county]                = std::vector<double>(num_age_groups, 0.0);
     136          90 :         num_Exposed[county]            = std::vector<double>(num_age_groups, 0.0);
     137          90 :         num_InfectedNoSymptoms[county] = std::vector<double>(num_age_groups, 0.0);
     138          90 :         num_InfectedSevere[county]     = std::vector<double>(num_age_groups, 0.0);
     139          90 :         num_icu[county]                = std::vector<double>(num_age_groups, 0.0);
     140         630 :         for (size_t group = 0; group < num_age_groups; group++) {
     141             : 
     142        1080 :             t_Exposed[county].push_back(static_cast<int>(
     143        1080 :                 std::round(model[county].parameters.template get<TimeExposed<double>>()[(AgeGroup)group])));
     144        1080 :             t_InfectedNoSymptoms[county].push_back(static_cast<int>(
     145        1080 :                 std::round(model[county].parameters.template get<TimeInfectedNoSymptoms<double>>()[(AgeGroup)group])));
     146        1080 :             t_InfectedSymptoms[county].push_back(static_cast<int>(
     147        1080 :                 std::round(model[county].parameters.template get<TimeInfectedSymptoms<double>>()[(AgeGroup)group])));
     148        1080 :             t_InfectedSevere[county].push_back(static_cast<int>(
     149        1080 :                 std::round(model[county].parameters.template get<TimeInfectedSevere<double>>()[(AgeGroup)group])));
     150        1080 :             t_InfectedCritical[county].push_back(static_cast<int>(
     151        1080 :                 std::round(model[county].parameters.template get<TimeInfectedCritical<double>>()[(AgeGroup)group])));
     152             : 
     153        1080 :             mu_C_R[county].push_back(
     154        1080 :                 model[county].parameters.template get<RecoveredPerInfectedNoSymptoms<double>>()[(AgeGroup)group]);
     155        1080 :             mu_I_H[county].push_back(
     156        1080 :                 model[county].parameters.template get<SeverePerInfectedSymptoms<double>>()[(AgeGroup)group]);
     157        1080 :             mu_H_U[county].push_back(
     158        1080 :                 model[county].parameters.template get<CriticalPerSevere<double>>()[(AgeGroup)group]);
     159             :         }
     160             :     }
     161             : 
     162          90 :     BOOST_OUTCOME_TRY(read_confirmed_cases_data(case_data, region, date, num_Exposed, num_InfectedNoSymptoms,
     163             :                                                 num_InfectedSymptoms, num_InfectedSevere, num_icu, num_death, num_rec,
     164             :                                                 t_Exposed, t_InfectedNoSymptoms, t_InfectedSymptoms, t_InfectedSevere,
     165             :                                                 t_InfectedCritical, mu_C_R, mu_I_H, mu_H_U, scaling_factor_inf));
     166             : 
     167         180 :     for (size_t county = 0; county < model.size(); county++) {
     168             :         // if (std::accumulate(num_InfectedSymptoms[county].begin(), num_InfectedSymptoms[county].end(), 0.0) > 0) {
     169          90 :         size_t num_groups = (size_t)model[county].parameters.get_num_groups();
     170         630 :         for (size_t i = 0; i < num_groups; i++) {
     171         540 :             model[county].populations[{AgeGroup(i), InfectionState::ExposedNaive}] = num_Exposed[county][i];
     172         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedNoSymptomsNaive}] =
     173             :                 num_InfectedNoSymptoms[county][i];
     174         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedNoSymptomsNaiveConfirmed}] = 0;
     175         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedSymptomsNaive}] =
     176             :                 num_InfectedSymptoms[county][i];
     177         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedSymptomsNaiveConfirmed}] = 0;
     178         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedSevereNaive}] =
     179             :                 num_InfectedSevere[county][i];
     180         540 :             model[county].populations[{AgeGroup(i), InfectionState::SusceptibleImprovedImmunity}] = num_rec[county][i];
     181         540 :             if (set_death) {
     182             :                 // in set_confirmed_cases_data initilization, deaths are now set to 0. In order to visualize
     183             :                 // the extrapolated real number of deaths, they have to be set here. In the comparison of data
     184             :                 // it has to be paid attention to the fact, the the simulation starts with deaths=0
     185             :                 // while this method starts with deaths=number of reported deaths so far...
     186             :                 // Additionally, we set the number of reported deaths to DeadNaive since no information on that is
     187             :                 // available here.
     188             :                 // Do only add deaths after substraction.
     189         216 :                 model[county].populations[{AgeGroup(i), InfectionState::DeadNaive}] = num_death[county][i];
     190             :             }
     191             :         }
     192             : 
     193             :         // }
     194          90 :         if (std::accumulate(num_InfectedSymptoms[county].begin(), num_InfectedSymptoms[county].end(), 0.0) == 0) {
     195          54 :             log_warning("No infections for unvaccinated reported on date " + std::to_string(date.year) + "-" +
     196             :                         std::to_string(date.month) + "-" + std::to_string(date.day) + " for region " +
     197          27 :                         std::to_string(region[county]) + ". Population data has not been set.");
     198             :         }
     199             :     }
     200             : 
     201             :     /*----------- PARTIALLY VACCINATED -----------*/
     202         180 :     for (size_t county = 0; county < model.size(); county++) {
     203          90 :         t_InfectedNoSymptoms[county].clear();
     204          90 :         t_Exposed[county].clear();
     205          90 :         t_InfectedSymptoms[county].clear();
     206          90 :         t_InfectedSevere[county].clear();
     207          90 :         t_InfectedCritical[county].clear();
     208             : 
     209          90 :         mu_C_R[county].clear();
     210          90 :         mu_I_H[county].clear();
     211          90 :         mu_H_U[county].clear();
     212             : 
     213          90 :         num_InfectedSymptoms[county]   = std::vector<double>(num_age_groups, 0.0);
     214          90 :         num_death[county]              = std::vector<double>(num_age_groups, 0.0);
     215          90 :         num_rec[county]                = std::vector<double>(num_age_groups, 0.0);
     216          90 :         num_Exposed[county]            = std::vector<double>(num_age_groups, 0.0);
     217          90 :         num_InfectedNoSymptoms[county] = std::vector<double>(num_age_groups, 0.0);
     218          90 :         num_InfectedSevere[county]     = std::vector<double>(num_age_groups, 0.0);
     219          90 :         num_icu[county]                = std::vector<double>(num_age_groups, 0.0);
     220         630 :         for (size_t group = 0; group < num_age_groups; group++) {
     221         540 :             double reduc_t = model[0].parameters.template get<ReducTimeInfectedMild<double>>()[(AgeGroup)group];
     222        1080 :             t_Exposed[county].push_back(static_cast<int>(
     223        1080 :                 std::round(model[county].parameters.template get<TimeExposed<double>>()[(AgeGroup)group])));
     224        1080 :             t_InfectedNoSymptoms[county].push_back(static_cast<int>(std::round(
     225        1080 :                 model[county].parameters.template get<TimeInfectedNoSymptoms<double>>()[(AgeGroup)group] * reduc_t)));
     226        1080 :             t_InfectedSymptoms[county].push_back(static_cast<int>(std::round(
     227        1080 :                 model[county].parameters.template get<TimeInfectedSymptoms<double>>()[(AgeGroup)group] * reduc_t)));
     228        1080 :             t_InfectedSevere[county].push_back(static_cast<int>(
     229        1080 :                 std::round(model[county].parameters.template get<TimeInfectedSevere<double>>()[(AgeGroup)group])));
     230        1080 :             t_InfectedCritical[county].push_back(static_cast<int>(
     231        1080 :                 std::round(model[county].parameters.template get<TimeInfectedCritical<double>>()[(AgeGroup)group])));
     232             : 
     233         540 :             double exp_fac_part_immune =
     234        1080 :                 model[county].parameters.template get<ReducExposedPartialImmunity<double>>()[(AgeGroup)group];
     235         540 :             double inf_fac_part_immune =
     236        1080 :                 model[county].parameters.template get<ReducInfectedSymptomsPartialImmunity<double>>()[(AgeGroup)group];
     237         540 :             double hosp_fac_part_immune =
     238         540 :                 model[county]
     239        1080 :                     .parameters.template get<ReducInfectedSevereCriticalDeadPartialImmunity<double>>()[(AgeGroup)group];
     240         540 :             double icu_fac_part_immune =
     241         540 :                 model[county]
     242        1080 :                     .parameters.template get<ReducInfectedSevereCriticalDeadPartialImmunity<double>>()[(AgeGroup)group];
     243        1080 :             mu_C_R[county].push_back((
     244        1080 :                 1 - inf_fac_part_immune / exp_fac_part_immune *
     245        1080 :                         (1 - model[county]
     246        1080 :                                  .parameters.template get<RecoveredPerInfectedNoSymptoms<double>>()[(AgeGroup)group])));
     247        1080 :             mu_I_H[county].push_back(
     248        1620 :                 hosp_fac_part_immune / inf_fac_part_immune *
     249        1080 :                 model[county].parameters.template get<SeverePerInfectedSymptoms<double>>()[(AgeGroup)group]);
     250             :             // transfer from H to U, D unchanged.
     251        1080 :             mu_H_U[county].push_back(
     252        1620 :                 icu_fac_part_immune / hosp_fac_part_immune *
     253        1080 :                 model[county].parameters.template get<CriticalPerSevere<double>>()[(AgeGroup)group]);
     254             :         }
     255             :     }
     256             : 
     257          90 :     BOOST_OUTCOME_TRY(read_confirmed_cases_data(case_data, region, date, num_Exposed, num_InfectedNoSymptoms,
     258             :                                                 num_InfectedSymptoms, num_InfectedSevere, num_icu, num_death, num_rec,
     259             :                                                 t_Exposed, t_InfectedNoSymptoms, t_InfectedSymptoms, t_InfectedSevere,
     260             :                                                 t_InfectedCritical, mu_C_R, mu_I_H, mu_H_U, scaling_factor_inf));
     261             : 
     262         180 :     for (size_t county = 0; county < model.size(); county++) {
     263             :         // if (std::accumulate(num_InfectedSymptoms[county].begin(), num_InfectedSymptoms[county].end(), 0.0) > 0) {
     264          90 :         size_t num_groups = (size_t)model[county].parameters.get_num_groups();
     265         630 :         for (size_t i = 0; i < num_groups; i++) {
     266         540 :             model[county].populations[{AgeGroup(i), InfectionState::ExposedPartialImmunity}] = num_Exposed[county][i];
     267         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedNoSymptomsPartialImmunity}] =
     268             :                 num_InfectedNoSymptoms[county][i];
     269         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedNoSymptomsPartialImmunityConfirmed}] = 0;
     270         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedSymptomsPartialImmunity}] =
     271             :                 num_InfectedSymptoms[county][i];
     272         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedSymptomsPartialImmunityConfirmed}] = 0;
     273         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedSeverePartialImmunity}] =
     274             :                 num_InfectedSevere[county][i];
     275             :         }
     276             :         // }
     277          90 :         if (std::accumulate(num_InfectedSymptoms[county].begin(), num_InfectedSymptoms[county].end(), 0.0) == 0) {
     278          54 :             log_warning("No infections for partially vaccinated reported on date " + std::to_string(date.year) + "-" +
     279             :                         std::to_string(date.month) + "-" + std::to_string(date.day) + " for region " +
     280          27 :                         std::to_string(region[county]) + ". Population data has not been set.");
     281             :         }
     282             :     }
     283             : 
     284             :     /*----------- FULLY VACCINATED -----------*/
     285         180 :     for (size_t county = 0; county < model.size(); county++) {
     286          90 :         t_InfectedNoSymptoms[county].clear();
     287          90 :         t_Exposed[county].clear();
     288          90 :         t_InfectedSymptoms[county].clear();
     289          90 :         t_InfectedSevere[county].clear();
     290          90 :         t_InfectedCritical[county].clear();
     291             : 
     292          90 :         mu_C_R[county].clear();
     293          90 :         mu_I_H[county].clear();
     294          90 :         mu_H_U[county].clear();
     295             : 
     296          90 :         num_InfectedSymptoms[county]   = std::vector<double>(num_age_groups, 0.0);
     297          90 :         num_death[county]              = std::vector<double>(num_age_groups, 0.0);
     298          90 :         num_rec[county]                = std::vector<double>(num_age_groups, 0.0);
     299          90 :         num_Exposed[county]            = std::vector<double>(num_age_groups, 0.0);
     300          90 :         num_InfectedNoSymptoms[county] = std::vector<double>(num_age_groups, 0.0);
     301          90 :         num_InfectedSevere[county]     = std::vector<double>(num_age_groups, 0.0);
     302          90 :         num_icu[county]                = std::vector<double>(num_age_groups, 0.0);
     303         630 :         for (size_t group = 0; group < num_age_groups; group++) {
     304         540 :             double reduc_t = model[0].parameters.template get<ReducTimeInfectedMild<double>>()[(AgeGroup)group];
     305        1080 :             t_Exposed[county].push_back(static_cast<int>(
     306        1080 :                 std::round(model[county].parameters.template get<TimeExposed<double>>()[(AgeGroup)group])));
     307        1080 :             t_InfectedNoSymptoms[county].push_back(static_cast<int>(std::round(
     308        1080 :                 model[county].parameters.template get<TimeInfectedNoSymptoms<double>>()[(AgeGroup)group] * reduc_t)));
     309        1080 :             t_InfectedSymptoms[county].push_back(static_cast<int>(std::round(
     310        1080 :                 model[county].parameters.template get<TimeInfectedSymptoms<double>>()[(AgeGroup)group] * reduc_t)));
     311        1080 :             t_InfectedSevere[county].push_back(static_cast<int>(
     312        1080 :                 std::round(model[county].parameters.template get<TimeInfectedSevere<double>>()[(AgeGroup)group])));
     313        1080 :             t_InfectedCritical[county].push_back(static_cast<int>(
     314        1080 :                 std::round(model[county].parameters.template get<TimeInfectedCritical<double>>()[(AgeGroup)group])));
     315             : 
     316         540 :             double reduc_immune_exp =
     317        1080 :                 model[county].parameters.template get<ReducExposedImprovedImmunity<double>>()[(AgeGroup)group];
     318         540 :             double reduc_immune_inf =
     319        1080 :                 model[county].parameters.template get<ReducInfectedSymptomsImprovedImmunity<double>>()[(AgeGroup)group];
     320         540 :             double reduc_immune_hosp =
     321        1080 :                 model[county].parameters.template get<ReducInfectedSevereCriticalDeadImprovedImmunity<double>>()[(
     322             :                     AgeGroup)group];
     323         540 :             double reduc_immune_icu =
     324        1080 :                 model[county].parameters.template get<ReducInfectedSevereCriticalDeadImprovedImmunity<double>>()[(
     325             :                     AgeGroup)group];
     326        1080 :             mu_C_R[county].push_back((
     327        1080 :                 1 - reduc_immune_inf / reduc_immune_exp *
     328        1080 :                         (1 - model[county]
     329        1080 :                                  .parameters.template get<RecoveredPerInfectedNoSymptoms<double>>()[(AgeGroup)group])));
     330        1080 :             mu_I_H[county].push_back(
     331        1620 :                 reduc_immune_hosp / reduc_immune_inf *
     332        1080 :                 model[county].parameters.template get<SeverePerInfectedSymptoms<double>>()[(AgeGroup)group]);
     333             :             // transfer from H to U, D unchanged.
     334        1080 :             mu_H_U[county].push_back(
     335        1620 :                 reduc_immune_icu / reduc_immune_hosp *
     336        1080 :                 model[county].parameters.template get<CriticalPerSevere<double>>()[(AgeGroup)group]);
     337             :         }
     338             :     }
     339             : 
     340          90 :     BOOST_OUTCOME_TRY(read_confirmed_cases_data(case_data, region, date, num_Exposed, num_InfectedNoSymptoms,
     341             :                                                 num_InfectedSymptoms, num_InfectedSevere, num_icu, num_death, num_rec,
     342             :                                                 t_Exposed, t_InfectedNoSymptoms, t_InfectedSymptoms, t_InfectedSevere,
     343             :                                                 t_InfectedCritical, mu_C_R, mu_I_H, mu_H_U, scaling_factor_inf));
     344             : 
     345         180 :     for (size_t county = 0; county < model.size(); county++) {
     346             :         // if (std::accumulate(num_InfectedSymptoms[county].begin(), num_InfectedSymptoms[county].end(), 0.0) > 0) {
     347          90 :         size_t num_groups = (size_t)model[county].parameters.get_num_groups();
     348         630 :         for (size_t i = 0; i < num_groups; i++) {
     349         540 :             model[county].populations[{AgeGroup(i), InfectionState::ExposedImprovedImmunity}] = num_Exposed[county][i];
     350         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedNoSymptomsImprovedImmunity}] =
     351             :                 num_InfectedNoSymptoms[county][i];
     352         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed}] = 0;
     353         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedSymptomsImprovedImmunity}] =
     354             :                 num_InfectedSymptoms[county][i];
     355         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedSymptomsImprovedImmunityConfirmed}] = 0;
     356         540 :             model[county].populations[{AgeGroup(i), InfectionState::InfectedSevereImprovedImmunity}] =
     357             :                 num_InfectedSevere[county][i];
     358             :         }
     359             :         // }
     360          90 :         if (std::accumulate(num_InfectedSymptoms[county].begin(), num_InfectedSymptoms[county].end(), 0.0) == 0) {
     361          54 :             log_warning("No infections for vaccinated reported on date " + std::to_string(date.year) + "-" +
     362             :                         std::to_string(date.month) + "-" + std::to_string(date.day) + " for region " +
     363          27 :                         std::to_string(region[county]) + ". Population data has not been set.");
     364             :         }
     365             :     }
     366             : 
     367         180 :     return success();
     368          90 : }
     369             : 
     370             : /**
     371             :         * @brief sets populations data from a transformed RKI cases file into a Model.
     372             :         * @param[in, out] model vector of objects in which the data is set
     373             :         * @param[in] path Path to transformed RKI cases file
     374             :         * @param[in] region vector of keys of the region of interest
     375             :         * @param[in] date Date for which the arrays are initialized
     376             :         * @param[in] scaling_factor_inf factors by which to scale the confirmed cases of
     377             :         * rki data
     378             :         * @param set_death[in] If true, set the number of deaths.
     379             :         */
     380             : template <class Model>
     381          54 : IOResult<void> set_confirmed_cases_data(std::vector<Model>& model, const std::string& path,
     382             :                                         std::vector<int> const& region, Date date,
     383             :                                         const std::vector<double>& scaling_factor_inf, bool set_death = false)
     384             : {
     385          54 :     BOOST_OUTCOME_TRY(auto&& case_data, mio::read_confirmed_cases_data(path));
     386          54 :     BOOST_OUTCOME_TRY(set_confirmed_cases_data(model, case_data, region, date, scaling_factor_inf, set_death));
     387         108 :     return success();
     388          54 : }
     389             : 
     390             : /**
     391             :         * @brief reads number of ICU patients from DIVI register into Parameters
     392             :         * @param[in] path Path to transformed DIVI file
     393             :         * @param[in] vregion Keys of the region of interest
     394             :         * @param[in] date Date for which the arrays are initialized
     395             :         * @param[in, out] vnum_icu number of ICU patients
     396             :         * @see mio::read_divi_data
     397             :         * @{
     398             :         */
     399             : IOResult<void> read_divi_data(const std::string& path, const std::vector<int>& vregion, Date date,
     400             :                               std::vector<double>& vnum_icu);
     401             : IOResult<void> read_divi_data(const std::vector<DiviEntry>& divi_data, const std::vector<int>& vregion, Date date,
     402             :                               std::vector<double>& vnum_icu);
     403             : /**@}*/
     404             : 
     405             : /**
     406             :         * @brief sets populations data from DIVI register into Model
     407             :         * @param[in, out] model vector of objects in which the data is set
     408             :         * @param[in] path Path to transformed DIVI file
     409             :         * @param[in] vregion vector of keys of the regions of interest
     410             :         * @param[in] date Date for which the arrays are initialized
     411             :         * @param[in] scaling_factor_icu factor by which to scale the icu cases of divi data
     412             :         */
     413             : template <class Model>
     414          63 : IOResult<void> set_divi_data(std::vector<Model>& model, const std::string& path, const std::vector<int>& vregion,
     415             :                              Date date, double scaling_factor_icu)
     416             : {
     417         126 :     std::vector<double> sum_mu_I_U(vregion.size(), 0);
     418         126 :     std::vector<std::vector<double>> mu_I_U{model.size()};
     419         126 :     for (size_t region = 0; region < vregion.size(); region++) {
     420          63 :         auto num_groups = model[region].parameters.get_num_groups();
     421         441 :         for (auto i = AgeGroup(0); i < num_groups; i++) {
     422         756 :             sum_mu_I_U[region] += model[region].parameters.template get<CriticalPerSevere<double>>()[i] *
     423         378 :                                   model[region].parameters.template get<SeverePerInfectedSymptoms<double>>()[i];
     424         756 :             mu_I_U[region].push_back(model[region].parameters.template get<CriticalPerSevere<double>>()[i] *
     425         378 :                                      model[region].parameters.template get<SeverePerInfectedSymptoms<double>>()[i]);
     426             :         }
     427             :     }
     428         126 :     std::vector<double> num_icu(model.size(), 0.0);
     429          63 :     BOOST_OUTCOME_TRY(read_divi_data(path, vregion, date, num_icu));
     430             : 
     431         126 :     for (size_t region = 0; region < vregion.size(); region++) {
     432          63 :         auto num_groups = model[region].parameters.get_num_groups();
     433         441 :         for (auto i = AgeGroup(0); i < num_groups; i++) {
     434         378 :             model[region].populations[{i, InfectionState::InfectedCriticalNaive}] =
     435         378 :                 scaling_factor_icu * num_icu[region] * mu_I_U[region][(size_t)i] / sum_mu_I_U[region];
     436             :         }
     437             :     }
     438             : 
     439         126 :     return success();
     440          63 : }
     441             : 
     442             : /**
     443             :         * @brief reads population data from census data.
     444             :         * @param[in] path Path to population data file.
     445             :         * @param[in] vregion vector of keys of the regions of interest
     446             :         * @see mio::read_population_data
     447             :         * @{
     448             :         */
     449             : IOResult<std::vector<std::vector<double>>> read_population_data(const std::string& path,
     450             :                                                                 const std::vector<int>& vregion);
     451             : IOResult<std::vector<std::vector<double>>> read_population_data(const std::vector<PopulationDataEntry>& population_data,
     452             :                                                                 const std::vector<int>& vregion);
     453             : /**@}*/
     454             : 
     455             : /**
     456             : * @brief sets population data from census data which has been read into num_population
     457             : * @param[in, out] model vector of objects in which the data is set
     458             : * @param[in] num_population vector of population data
     459             : * @param[in] case_data vector of case data. Each inner vector represents a different region
     460             : * @param[in] vregion vector of keys of the regions of interest
     461             : * @param[in] date Date for which the arrays are initialized
     462             : */
     463             : template <class Model>
     464         108 : IOResult<void> set_population_data(std::vector<Model>& model, const std::vector<std::vector<double>>& num_population,
     465             :                                    const std::vector<ConfirmedCasesDataEntry>& case_data,
     466             :                                    const std::vector<int>& vregion, Date date)
     467             : {
     468         108 :     auto num_age_groups = ConfirmedCasesDataEntry::age_group_names.size();
     469         432 :     std::vector<std::vector<double>> vnum_rec(model.size(), std::vector<double>(num_age_groups, 0.0));
     470             : 
     471         108 :     BOOST_OUTCOME_TRY(read_confirmed_cases_data_fix_recovered(case_data, vregion, date, vnum_rec, 14.));
     472             : 
     473         216 :     for (size_t region = 0; region < vregion.size(); region++) {
     474         108 :         if (std::accumulate(num_population[region].begin(), num_population[region].end(), 0.0) > 0) {
     475          99 :             auto num_groups = model[region].parameters.get_num_groups();
     476         693 :             for (auto i = AgeGroup(0); i < num_groups; i++) {
     477             : 
     478        1188 :                 double S_v = std::min(
     479        1188 :                     model[region].parameters.template get<DailyFullVaccination<double>>()[{i, SimulationDay(0)}] +
     480             :                         vnum_rec[region][size_t(i)],
     481             :                     num_population[region][size_t(i)]);
     482         594 :                 double S_pv = std::max(
     483        2376 :                     model[region].parameters.template get<DailyFirstVaccination<double>>()[{i, SimulationDay(0)}] -
     484        1188 :                         model[region].parameters.template get<DailyFullVaccination<double>>()[{i, SimulationDay(0)}],
     485        1188 :                     0.0); // use std::max with 0
     486             :                 double S;
     487         594 :                 if (num_population[region][size_t(i)] - S_pv - S_v < 0.0) {
     488          18 :                     log_warning("Number of vaccinated persons greater than population in county {}, age group {}.",
     489          18 :                                 region, size_t(i));
     490           9 :                     S   = 0.0;
     491           9 :                     S_v = num_population[region][size_t(i)] - S_pv;
     492             :                 }
     493             :                 else {
     494         585 :                     S = num_population[region][size_t(i)] - S_pv - S_v;
     495             :                 }
     496             : 
     497         594 :                 double denom_E =
     498         594 :                     1 / (S + S_pv * model[region].parameters.template get<ReducExposedPartialImmunity<double>>()[i] +
     499         594 :                          S_v * model[region].parameters.template get<ReducExposedImprovedImmunity<double>>()[i]);
     500         594 :                 double denom_C =
     501         594 :                     1 / (S + S_pv * model[region].parameters.template get<ReducExposedPartialImmunity<double>>()[i] +
     502         594 :                          S_v * model[region].parameters.template get<ReducExposedImprovedImmunity<double>>()[i]);
     503         594 :                 double denom_I =
     504             :                     1 /
     505         594 :                     (S +
     506         594 :                      S_pv * model[region].parameters.template get<ReducInfectedSymptomsPartialImmunity<double>>()[i] +
     507         594 :                      S_v * model[region].parameters.template get<ReducInfectedSymptomsImprovedImmunity<double>>()[i]);
     508         594 :                 double denom_HU =
     509             :                     1 /
     510         594 :                     (S +
     511        1188 :                      S_pv * model[region]
     512         594 :                                 .parameters.template get<ReducInfectedSevereCriticalDeadPartialImmunity<double>>()[i] +
     513        1188 :                      S_v * model[region]
     514         594 :                                .parameters.template get<ReducInfectedSevereCriticalDeadImprovedImmunity<double>>()[i]);
     515             : 
     516         594 :                 model[region].populations[{i, InfectionState::ExposedNaive}] =
     517        1188 :                     S * model[region].populations[{i, InfectionState::ExposedNaive}] * denom_E;
     518         594 :                 model[region].populations[{i, InfectionState::ExposedPartialImmunity}] =
     519        1188 :                     S_pv * model[region].parameters.template get<ReducExposedPartialImmunity<double>>()[i] *
     520        1188 :                     model[region].populations[{i, InfectionState::ExposedPartialImmunity}] * denom_E;
     521         594 :                 model[region].populations[{i, InfectionState::ExposedImprovedImmunity}] =
     522        1188 :                     S_v * model[region].parameters.template get<ReducExposedImprovedImmunity<double>>()[i] *
     523        1188 :                     model[region].populations[{i, InfectionState::ExposedImprovedImmunity}] * denom_E;
     524             : 
     525         594 :                 model[region].populations[{i, InfectionState::InfectedNoSymptomsNaive}] =
     526        1188 :                     S * model[region].populations[{i, InfectionState::InfectedNoSymptomsNaive}] * denom_C;
     527         594 :                 model[region].populations[{i, InfectionState::InfectedNoSymptomsPartialImmunity}] =
     528        1188 :                     S_pv * model[region].populations[{i, InfectionState::InfectedNoSymptomsPartialImmunity}] * denom_C;
     529         594 :                 model[region].populations[{i, InfectionState::InfectedNoSymptomsImprovedImmunity}] =
     530        1188 :                     S_v * model[region].populations[{i, InfectionState::InfectedNoSymptomsImprovedImmunity}] * denom_C;
     531             : 
     532         594 :                 model[region].populations[{i, InfectionState::InfectedNoSymptomsNaiveConfirmed}] =
     533        1188 :                     S * model[region].populations[{i, InfectionState::InfectedNoSymptomsNaiveConfirmed}] * denom_C;
     534         594 :                 model[region].populations[{i, InfectionState::InfectedNoSymptomsPartialImmunityConfirmed}] =
     535        1188 :                     S_pv * model[region].populations[{i, InfectionState::InfectedNoSymptomsPartialImmunityConfirmed}] *
     536             :                     denom_C;
     537         594 :                 model[region].populations[{i, InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed}] =
     538        1188 :                     S_v * model[region].populations[{i, InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed}] *
     539             :                     denom_C;
     540             : 
     541         594 :                 model[region].populations[{i, InfectionState::InfectedSymptomsNaive}] =
     542        1188 :                     S * model[region].populations[{i, InfectionState::InfectedSymptomsNaive}] * denom_I;
     543         594 :                 model[region].populations[{i, InfectionState::InfectedSymptomsPartialImmunity}] =
     544        1188 :                     S_pv * model[region].parameters.template get<ReducInfectedSymptomsPartialImmunity<double>>()[i] *
     545        1188 :                     model[region].populations[{i, InfectionState::InfectedSymptomsPartialImmunity}] * denom_I;
     546         594 :                 model[region].populations[{i, InfectionState::InfectedSymptomsImprovedImmunity}] =
     547        1188 :                     S_v * model[region].parameters.template get<ReducInfectedSymptomsImprovedImmunity<double>>()[i] *
     548        1188 :                     model[region].populations[{i, InfectionState::InfectedSymptomsImprovedImmunity}] * denom_I;
     549             : 
     550         594 :                 model[region].populations[{i, InfectionState::InfectedSymptomsNaiveConfirmed}] =
     551        1188 :                     S * model[region].populations[{i, InfectionState::InfectedSymptomsNaiveConfirmed}] * denom_I;
     552         594 :                 model[region].populations[{i, InfectionState::InfectedSymptomsPartialImmunityConfirmed}] =
     553        1188 :                     S_pv * model[region].parameters.template get<ReducInfectedSymptomsPartialImmunity<double>>()[i] *
     554        1188 :                     model[region].populations[{i, InfectionState::InfectedSymptomsPartialImmunityConfirmed}] * denom_I;
     555         594 :                 model[region].populations[{i, InfectionState::InfectedSymptomsImprovedImmunityConfirmed}] =
     556        1188 :                     S_v * model[region].parameters.template get<ReducInfectedSymptomsImprovedImmunity<double>>()[i] *
     557        1188 :                     model[region].populations[{i, InfectionState::InfectedSymptomsImprovedImmunityConfirmed}] * denom_I;
     558             : 
     559         594 :                 model[region].populations[{i, InfectionState::InfectedSevereNaive}] =
     560        1188 :                     S * model[region].populations[{i, InfectionState::InfectedSevereNaive}] * denom_HU;
     561         594 :                 model[region].populations[{i, InfectionState::InfectedSeverePartialImmunity}] =
     562         594 :                     S_pv *
     563        1188 :                     model[region].parameters.template get<ReducInfectedSevereCriticalDeadPartialImmunity<double>>()[i] *
     564        1188 :                     model[region].populations[{i, InfectionState::InfectedSeverePartialImmunity}] * denom_HU;
     565         594 :                 model[region].populations[{i, InfectionState::InfectedSevereImprovedImmunity}] =
     566         594 :                     S_v *
     567         594 :                     model[region]
     568        1188 :                         .parameters.template get<ReducInfectedSevereCriticalDeadImprovedImmunity<double>>()[i] *
     569        1188 :                     model[region].populations[{i, InfectionState::InfectedSevereImprovedImmunity}] * denom_HU;
     570             : 
     571         594 :                 model[region].populations[{i, InfectionState::InfectedCriticalPartialImmunity}] =
     572         594 :                     S_pv *
     573        1188 :                     model[region].parameters.template get<ReducInfectedSevereCriticalDeadPartialImmunity<double>>()[i] *
     574        1188 :                     model[region].populations[{i, InfectionState::InfectedCriticalNaive}] * denom_HU;
     575         594 :                 model[region].populations[{i, InfectionState::InfectedCriticalImprovedImmunity}] =
     576         594 :                     S_v *
     577         594 :                     model[region]
     578        1188 :                         .parameters.template get<ReducInfectedSevereCriticalDeadImprovedImmunity<double>>()[i] *
     579        1188 :                     model[region].populations[{i, InfectionState::InfectedCriticalNaive}] * denom_HU;
     580         594 :                 model[region].populations[{i, InfectionState::InfectedCriticalNaive}] =
     581        1188 :                     S * model[region].populations[{i, InfectionState::InfectedCriticalNaive}] * denom_HU;
     582             : 
     583         594 :                 model[region].populations[{i, InfectionState::SusceptibleImprovedImmunity}] =
     584        1782 :                     model[region].parameters.template get<DailyFullVaccination<double>>()[{i, SimulationDay(0)}] +
     585        1188 :                     model[region].populations[{i, InfectionState::SusceptibleImprovedImmunity}] -
     586        1782 :                     (model[region].populations[{i, InfectionState::InfectedSymptomsNaive}] +
     587        1782 :                      model[region].populations[{i, InfectionState::InfectedSymptomsPartialImmunity}] +
     588        1782 :                      model[region].populations[{i, InfectionState::InfectedSymptomsImprovedImmunity}] +
     589        1782 :                      model[region].populations[{i, InfectionState::InfectedSymptomsNaiveConfirmed}] +
     590        1782 :                      model[region].populations[{i, InfectionState::InfectedSymptomsPartialImmunityConfirmed}] +
     591        1782 :                      model[region].populations[{i, InfectionState::InfectedSymptomsImprovedImmunityConfirmed}] +
     592        1782 :                      model[region].populations[{i, InfectionState::InfectedSevereNaive}] +
     593        1782 :                      model[region].populations[{i, InfectionState::InfectedSeverePartialImmunity}] +
     594        1782 :                      model[region].populations[{i, InfectionState::InfectedSevereImprovedImmunity}] +
     595        1782 :                      model[region].populations[{i, InfectionState::InfectedCriticalNaive}] +
     596        1782 :                      model[region].populations[{i, InfectionState::InfectedCriticalPartialImmunity}] +
     597        1782 :                      model[region].populations[{i, InfectionState::InfectedCriticalImprovedImmunity}] +
     598        1782 :                      model[region].populations[{i, InfectionState::DeadNaive}] +
     599        1782 :                      model[region].populations[{i, InfectionState::DeadPartialImmunity}] +
     600        1188 :                      model[region].populations[{i, InfectionState::DeadImprovedImmunity}]);
     601             : 
     602        1188 :                 model[region].populations[{i, InfectionState::SusceptibleImprovedImmunity}] = std::min(
     603        1782 :                     S_v - model[region].populations[{i, InfectionState::ExposedImprovedImmunity}] -
     604        1782 :                         model[region].populations[{i, InfectionState::InfectedNoSymptomsImprovedImmunity}] -
     605        1782 :                         model[region].populations[{i, InfectionState::InfectedNoSymptomsImprovedImmunityConfirmed}] -
     606        1782 :                         model[region].populations[{i, InfectionState::InfectedSymptomsImprovedImmunity}] -
     607        1782 :                         model[region].populations[{i, InfectionState::InfectedSymptomsImprovedImmunityConfirmed}] -
     608        1782 :                         model[region].populations[{i, InfectionState::InfectedSevereImprovedImmunity}] -
     609        2970 :                         model[region].populations[{i, InfectionState::InfectedCriticalImprovedImmunity}] -
     610        1188 :                         model[region].populations[{i, InfectionState::DeadImprovedImmunity}],
     611        1188 :                     std::max(0.0, double(model[region].populations[{i, InfectionState::SusceptibleImprovedImmunity}])));
     612             : 
     613         594 :                 model[region].populations[{i, InfectionState::SusceptiblePartialImmunity}] = std::max(
     614        1188 :                     0.0,
     615        1782 :                     S_pv - model[region].populations[{i, InfectionState::ExposedPartialImmunity}] -
     616        1782 :                         model[region].populations[{i, InfectionState::InfectedNoSymptomsPartialImmunity}] -
     617        1782 :                         model[region].populations[{i, InfectionState::InfectedNoSymptomsPartialImmunityConfirmed}] -
     618        1782 :                         model[region].populations[{i, InfectionState::InfectedSymptomsPartialImmunity}] -
     619        1782 :                         model[region].populations[{i, InfectionState::InfectedSymptomsPartialImmunityConfirmed}] -
     620        1782 :                         model[region].populations[{i, InfectionState::InfectedSeverePartialImmunity}] -
     621        2970 :                         model[region].populations[{i, InfectionState::InfectedCriticalPartialImmunity}] -
     622        1188 :                         model[region].populations[{i, InfectionState::DeadPartialImmunity}]);
     623             : 
     624         594 :                 model[region].populations.template set_difference_from_group_total<AgeGroup>(
     625             :                     {i, InfectionState::SusceptibleNaive}, num_population[region][size_t(i)]);
     626             :             }
     627             : 
     628         693 :             for (auto i = AgeGroup(0); i < AgeGroup(6); i++) {
     629       16632 :                 for (auto j = Index<InfectionState>(0); j < InfectionState::Count; ++j) {
     630       16038 :                     if (model[region].populations[{i, j}] < 0) {
     631           0 :                         log_warning("Compartment at age group {}, infection state {}, is negative: {}", size_t(i),
     632           0 :                                     size_t(j), model[region].populations[{i, j}] / num_population[region][size_t(i)]);
     633             :                     }
     634             :                 }
     635             :             }
     636             :         }
     637             :         else {
     638           9 :             log_warning("No population data available for region " + std::to_string(region) +
     639             :                         ". Population data has not been set.");
     640             :         }
     641             :     }
     642             : 
     643         216 :     return success();
     644         108 : }
     645             : 
     646             : /**
     647             : * @brief Sets population data from census data which has been read into num_population.
     648             : * @param[in, out] model Vector of objects in which the data is set.
     649             : * @param[in] path Path to population data file.
     650             : * @param[in] path_rki Path to RKI cases data file.
     651             : * @param[in] vregion Vector of keys of the regions of interest.
     652             : * @param[in] date Date for which the arrays are initialized.
     653             : */
     654             : template <class Model>
     655          72 : IOResult<void> set_population_data(std::vector<Model>& model, const std::string& path, const std::string& path_rki,
     656             :                                    const std::vector<int>& vregion, Date date)
     657             : {
     658          72 :     BOOST_OUTCOME_TRY(auto&& num_population, details::read_population_data(path, vregion));
     659          72 :     BOOST_OUTCOME_TRY(auto&& rki_data, mio::read_confirmed_cases_data(path_rki));
     660             : 
     661          72 :     BOOST_OUTCOME_TRY(set_population_data(model, num_population, rki_data, vregion, date));
     662         144 :     return success();
     663          72 : }
     664             : 
     665             : /**
     666             :  * @brief Sets vaccination data for models stored in a vector.
     667             :  * 
     668             :  * @tparam FP Floating point type used in the Model objects.
     669             :  * @param[in, out] model Vector of Model objects in which the vaccination data is set.
     670             :  * @param[in] vacc_data Vector of VaccinationDataEntry objects containing the vaccination data.
     671             :  * @param[in] date Start date for the simulation.
     672             :  * @param[in] vregion Vector of region identifiers.
     673             :  * @param[in] num_days Number of days for which the simulation is run.
     674             :  */
     675             : template <typename FP = double>
     676          91 : IOResult<void> set_vaccination_data(std::vector<Model<FP>>& model, const std::vector<VaccinationDataEntry>& vacc_data,
     677             :                                     Date date, const std::vector<int>& vregion, int num_days)
     678             : {
     679          91 :     auto num_groups = model[0].parameters.get_num_groups();
     680             : 
     681             :     // type conversion from UncertainValue -> FP -> int
     682          91 :     auto days_until_effective1 = static_cast<int>(
     683          91 :         static_cast<FP>(model[0].parameters.template get<DaysUntilEffectivePartialImmunity<FP>>()[AgeGroup(0)]));
     684          91 :     auto days_until_effective2 = static_cast<int>(
     685          91 :         static_cast<FP>(model[0].parameters.template get<DaysUntilEffectiveImprovedImmunity<FP>>()[AgeGroup(0)]));
     686          91 :     auto vaccination_distance =
     687          91 :         static_cast<int>(static_cast<FP>(model[0].parameters.template get<VaccinationGap<FP>>()[AgeGroup(0)]));
     688             : 
     689             :     // iterate over regions (e.g., counties)
     690         182 :     for (size_t i = 0; i < model.size(); ++i) {
     691             :         // iterate over age groups in region
     692         632 :         for (auto g = AgeGroup(0); g < num_groups; ++g) {
     693             : 
     694         541 :             model[i].parameters.template get<DailyFirstVaccination<FP>>().resize(SimulationDay(num_days + 1));
     695         541 :             model[i].parameters.template get<DailyFullVaccination<FP>>().resize(SimulationDay(num_days + 1));
     696        3144 :             for (auto d = SimulationDay(0); d < SimulationDay(num_days + 1); ++d) {
     697        2603 :                 model[i].parameters.template get<DailyFirstVaccination<FP>>()[{g, d}] = 0.0;
     698        2603 :                 model[i].parameters.template get<DailyFullVaccination<FP>>()[{g, d}]  = 0.0;
     699             :             }
     700             :         }
     701             :     }
     702             : 
     703          91 :     auto max_date_entry = std::max_element(vacc_data.begin(), vacc_data.end(), [](auto&& a, auto&& b) {
     704       49600 :         return a.date < b.date;
     705             :     });
     706          91 :     if (max_date_entry == vacc_data.end()) {
     707           0 :         return failure(StatusCode::InvalidFileFormat, "Vaccination data file is empty.");
     708             :     }
     709          91 :     auto max_date = max_date_entry->date;
     710             : 
     711       49782 :     for (auto&& vacc_data_entry : vacc_data) {
     712      129223 :         auto it      = std::find_if(vregion.begin(), vregion.end(), [&vacc_data_entry](auto&& r) {
     713      124277 :             return r == 0 || (vacc_data_entry.county_id && vacc_data_entry.county_id == regions::CountyId(r)) ||
     714      129201 :                    (vacc_data_entry.state_id && vacc_data_entry.state_id == regions::StateId(r)) ||
     715      124222 :                    (vacc_data_entry.district_id && vacc_data_entry.district_id == regions::DistrictId(r));
     716             :         });
     717       49691 :         auto date_df = vacc_data_entry.date;
     718       49691 :         if (it != vregion.end()) {
     719       49691 :             auto region_idx = size_t(it - vregion.begin());
     720       49691 :             auto age        = vacc_data_entry.age_group;
     721             : 
     722      288276 :             for (size_t d = 0; d < (size_t)num_days + 1; ++d) {
     723             :                 int days_plus;
     724             :                 // In the following, second dose means previous 'full immunization', now 'Grundimmunisierung'.
     725             :                 // ---
     726             :                 // date: start_date of the simulation (Input from IO call read_input_data_county_vaccmodel())
     727             :                 // d: day of simulation, counted from 0 to num_days (for which we need (approximated) vaccination numbers)
     728             :                 // root[i]["Vacc_completed"]: accumulated number of total second doses up to day date_df;
     729             :                 //                               taken from input dataframe, single value, per county and age group
     730             :                 // ----
     731             :                 // An averaged distance between first and second doses (vaccination_distance) is assumed in the following
     732             :                 // and the first doses are computed based on the second doses given 'vaccination_distance' days later.
     733             :                 // ----
     734             :                 // a person whose second dose is reported at start_date + simulation_day - days_until_effective1 + vaccination_distance
     735             :                 // had the first dose on start_date + simulation_day - days_until_effective1. Furthermore, he/she has the full protection
     736             :                 // of the first dose at day X = start_date + simulation_day
     737             :                 // Storing its value in get<DailyFirstVaccination>() will eventually (in the simulation)
     738             :                 // transfer the difference (between get<DailyFirstVaccination>() at d and d-1) of
     739             :                 // N susceptible individuals to 'Susceptible Partially Vaccinated' state at day d; see secir_vaccinated.h
     740      238585 :                 auto offset_first_date =
     741      238585 :                     offset_date_by_days(date, (int)d - days_until_effective1 + vaccination_distance);
     742      238585 :                 if (max_date >= offset_first_date) {
     743             :                     // Option 1: considered offset_first_date is available in input data frame
     744       14970 :                     if (date_df == offset_first_date) {
     745           6 :                         model[region_idx]
     746           6 :                             .parameters.template get<DailyFirstVaccination<FP>>()[{age, SimulationDay(d)}] =
     747           6 :                             vacc_data_entry.num_vaccinations_completed;
     748             :                     }
     749             :                 }
     750             :                 else { // offset_first_date > max_date
     751             :                     // Option 2: considered offset_first_date is NOT available in input data frame
     752             :                     // Here, a constant number of first and second doses is assumed, i.e.,
     753             :                     // the the number of vaccinationes at day d (N days after max_date) will be:
     754             :                     // total number of vaccinations up to day max_date + N * number of vaccinations ON max_date
     755             :                     // (where the latter is computed as the difference between the total number at max_date and max_date-1)
     756      223615 :                     days_plus = get_offset_in_days(offset_first_date, max_date);
     757      223615 :                     if (date_df == offset_date_by_days(max_date, -1)) {
     758        2435 :                         model[region_idx]
     759        4870 :                             .parameters.template get<DailyFirstVaccination<FP>>()[{age, SimulationDay(d)}] -=
     760        2435 :                             days_plus * vacc_data_entry.num_vaccinations_completed;
     761             :                     }
     762      221180 :                     else if (date_df == max_date) {
     763        2435 :                         model[region_idx]
     764        4870 :                             .parameters.template get<DailyFirstVaccination<FP>>()[{age, SimulationDay(d)}] +=
     765        2435 :                             (days_plus + 1) * vacc_data_entry.num_vaccinations_completed;
     766             :                     }
     767             :                 }
     768             : 
     769             :                 // a person whose second dose is reported at start_date + simulation_day - days_until_effective2
     770             :                 // has the full protection of the second dose at day X = start_date + simulation_day
     771             :                 // Storing its value in get<DailyFullVaccination>() will eventually (in the simulation)
     772             :                 // transfer the difference (between get<DailyFullVaccination>() at d and d-1) of
     773             :                 // N susceptible, partially vaccinated individuals to 'SusceptibleImprovedImmunity' state at day d; see secir_vaccinated.h
     774      238585 :                 auto offset_full_date = offset_date_by_days(date, (int)d - days_until_effective2);
     775      238585 :                 if (max_date >= offset_full_date) {
     776             :                     // Option 1: considered offset_full_date is available in input data frame
     777      238574 :                     if (date_df == offset_full_date) {
     778        2440 :                         model[region_idx].parameters.template get<DailyFullVaccination<FP>>()[{age, SimulationDay(d)}] =
     779        2440 :                             vacc_data_entry.num_vaccinations_completed;
     780             :                     }
     781             :                 }
     782             :                 else { // offset_full_date > max_full_date
     783             :                     // Option 2: considered offset_full_date is NOT available in input data frame
     784          11 :                     days_plus = get_offset_in_days(offset_full_date, max_date);
     785          11 :                     if (date_df == offset_date_by_days(max_date, -1)) {
     786           1 :                         model[region_idx]
     787           2 :                             .parameters.template get<DailyFullVaccination<FP>>()[{age, SimulationDay(d)}] -=
     788           1 :                             days_plus * vacc_data_entry.num_vaccinations_completed;
     789             :                     }
     790          10 :                     else if (date_df == max_date) {
     791           1 :                         model[region_idx]
     792           2 :                             .parameters.template get<DailyFullVaccination<FP>>()[{age, SimulationDay(d)}] +=
     793           1 :                             (days_plus + 1) * vacc_data_entry.num_vaccinations_completed;
     794             :                     }
     795             :                 }
     796             :             }
     797             :         }
     798             :     }
     799         182 :     return success();
     800             : }
     801             : 
     802             : /**
     803             :  * @brief Reads vaccination data from a file and sets it for each model.
     804             :  * 
     805             :  * @tparam FP Floating point type used in the Model objects.
     806             :  * @param[in, out] model Vector of Model objects in which the vaccination data is set.
     807             :  * @param[in] path Path to vaccination data file.
     808             :  * @param[in] date Start date for the simulation.
     809             :  * @param[in] vregion Vector of region identifiers.
     810             :  * @param[in] num_days Number of days for which the simulation is run.
     811             :  */
     812             : template <typename FP = double>
     813          55 : IOResult<void> set_vaccination_data(std::vector<Model<FP>>& model, const std::string& path, Date date,
     814             :                                     const std::vector<int>& vregion, int num_days)
     815             : {
     816          55 :     BOOST_OUTCOME_TRY(auto&& vacc_data, read_vaccination_data(path));
     817          55 :     BOOST_OUTCOME_TRY(set_vaccination_data(model, vacc_data, date, vregion, num_days));
     818         110 :     return success();
     819          55 : }
     820             : 
     821             : } // namespace details
     822             : 
     823             : #ifdef MEMILIO_HAS_HDF5
     824             : 
     825             : /**
     826             : * @brief Uses the initialisation method, which uses the reported data to set the initial conditions for the model for a given day. 
     827             : * The initialisation is applied for a predefined number of days and finally saved in a timeseries for each region. In the end,
     828             : * we save the files "Results_rki.h5" and "Results_rki_sum.h5" in the results_dir.
     829             : * Results_rki.h5 contains a time series for each region and Results_rki_sum.h5 contains the sum of all regions.
     830             : * @param[in] models Vector of models in which the data is set. Copy is made to avoid changing the original model.
     831             : * @param[in] results_dir Path to result files.
     832             : * @param[in] counties Vector of keys of the counties of interest.
     833             : * @param[in] date Date for which the data should be read.
     834             : * @param[in] scaling_factor_inf Factors by which to scale the confirmed cases of rki data.
     835             : * @param[in] scaling_factor_icu Factor by which to scale the icu cases of divi data.
     836             : * @param[in] num_days Number of days to be simulated/initialized.
     837             : * @param[in] divi_data_path Path to DIVI file.
     838             : * @param[in] confirmed_cases_path Path to confirmed cases file.
     839             : * @param[in] population_data_path Path to population data file.
     840             : * @param[in] vaccination_data_path Path to vaccination data file.
     841             : */
     842             : template <class Model>
     843          18 : IOResult<void> export_input_data_county_timeseries(
     844             :     std::vector<Model> models, const std::string& results_dir, const std::vector<int>& counties, Date date,
     845             :     const std::vector<double>& scaling_factor_inf, const double scaling_factor_icu, const int num_days,
     846             :     const std::string& divi_data_path, const std::string& confirmed_cases_path, const std::string& population_data_path,
     847             :     const std::string& vaccination_data_path = "")
     848             : {
     849          18 :     const auto num_groups = (size_t)models[0].parameters.get_num_groups();
     850          18 :     assert(scaling_factor_inf.size() == num_groups);
     851          18 :     assert(num_groups == ConfirmedCasesDataEntry::age_group_names.size());
     852          18 :     assert(models.size() == counties.size());
     853          72 :     std::vector<TimeSeries<double>> extrapolated_data(
     854          18 :         models.size(), TimeSeries<double>::zero(num_days + 1, (size_t)InfectionState::Count * num_groups));
     855             : 
     856          18 :     BOOST_OUTCOME_TRY(auto&& case_data, read_confirmed_cases_data(confirmed_cases_path));
     857          18 :     BOOST_OUTCOME_TRY(auto&& population_data, details::read_population_data(population_data_path, counties));
     858             : 
     859             :     // empty vector if set_vaccination_data is not set
     860          18 :     std::vector<VaccinationDataEntry> vacc_data;
     861          18 :     if (!vaccination_data_path.empty()) {
     862          18 :         BOOST_OUTCOME_TRY(vacc_data, read_vaccination_data(vaccination_data_path));
     863          18 :     }
     864             : 
     865          90 :     for (int t = 0; t <= num_days; ++t) {
     866          36 :         auto offset_day = offset_date_by_days(date, t);
     867             : 
     868          36 :         if (!vaccination_data_path.empty()) {
     869          36 :             BOOST_OUTCOME_TRY(details::set_vaccination_data(models, vacc_data, offset_day, counties, num_days));
     870          36 :         }
     871             : 
     872             :         // TODO: Reuse more code, e.g., set_divi_data (in secir) and a set_divi_data (here) only need a different ModelType.
     873             :         // TODO: add option to set ICU data from confirmed cases if DIVI or other data is not available.
     874          36 :         if (offset_day > Date(2020, 4, 23)) {
     875          27 :             BOOST_OUTCOME_TRY(details::set_divi_data(models, divi_data_path, counties, offset_day, scaling_factor_icu));
     876          27 :         }
     877             :         else {
     878          18 :             log_warning("No DIVI data available for for date: {}-{}-{}", offset_day.day, offset_day.month,
     879             :                         offset_day.year);
     880             :         }
     881             : 
     882          36 :         BOOST_OUTCOME_TRY(
     883             :             details::set_confirmed_cases_data(models, case_data, counties, offset_day, scaling_factor_inf, true));
     884          36 :         BOOST_OUTCOME_TRY(details::set_population_data(models, population_data, case_data, counties, offset_day));
     885             : 
     886          72 :         for (size_t r = 0; r < counties.size(); r++) {
     887          36 :             extrapolated_data[r][t] = models[r].get_initial_values();
     888             :             // in set_population_data the number of death individuals is subtracted from the SusceptibleImprovedImmunity compartment.
     889             :             // Since we should be independent whether we consider them or not, we add them back here before we save the data.
     890         252 :             for (size_t age = 0; age < num_groups; age++) {
     891         216 :                 extrapolated_data[r][t][(size_t)InfectionState::SusceptibleImprovedImmunity +
     892         432 :                                         age * (size_t)InfectionState::Count] +=
     893         216 :                     extrapolated_data[r][t][(size_t)InfectionState::DeadNaive + age * (size_t)InfectionState::Count];
     894             :             }
     895             :         }
     896             :     }
     897          36 :     BOOST_OUTCOME_TRY(save_result(extrapolated_data, counties, static_cast<int>(num_groups),
     898             :                                   path_join(results_dir, "Results_rki.h5")));
     899             : 
     900          90 :     auto extrapolated_rki_data_sum = sum_nodes(std::vector<std::vector<TimeSeries<double>>>{extrapolated_data});
     901         144 :     BOOST_OUTCOME_TRY(save_result({extrapolated_rki_data_sum[0][0]}, {0}, static_cast<int>(num_groups),
     902             :                                   path_join(results_dir, "Results_rki_sum.h5")));
     903             : 
     904          36 :     return success();
     905          18 : }
     906             : #else
     907             : template <class Model>
     908             : IOResult<void> export_input_data_county_timeseries(std::vector<Model>, const std::string&, const std::vector<int>&,
     909             :                                                    Date, const std::vector<double>&, const double, const int,
     910             :                                                    const std::string&, const std::string&, const std::string&,
     911             :                                                    const std::string&)
     912             : {
     913             :     mio::log_warning("HDF5 not available. Cannot export time series of extrapolated real data.");
     914             :     return success();
     915             : }
     916             : 
     917             : #endif //MEMILIO_HAS_HDF5
     918             : 
     919             : /**
     920             :     * Reads compartments for German counties at a specified date from data files.
     921             :     * Estimates all compartments from available data using the model parameters, so the 
     922             :     * model parameters must be set before calling this function.
     923             :     * Uses data files that contain centered 7-day moving average.
     924             :     * @param[in, out] model Vector of SECIRVVS models, one per county.
     925             :     * @param[in] date Date for which the data should be read.
     926             :     * @param[in] county Ids of the counties.
     927             :     * @param[in] scaling_factor_inf Factor of confirmed cases to account for undetected cases in each county.
     928             :     * @param[in] scaling_factor_icu Factor of ICU cases to account for underreporting.
     929             :     * @param[in] dir Directory that contains the data files.
     930             :     * @param[in] num_days Number of days to be simulated; required to load data for vaccinations during the simulation.
     931             :     * @param[in] export_time_series If true, reads data for each day of simulation and writes it in the same directory as the input files.
     932             :     */
     933             : template <class Model>
     934          27 : IOResult<void> read_input_data_county(std::vector<Model>& model, Date date, const std::vector<int>& county,
     935             :                                       const std::vector<double>& scaling_factor_inf, double scaling_factor_icu,
     936             :                                       const std::string& dir, int num_days, bool export_time_series = false)
     937             : {
     938          54 :     BOOST_OUTCOME_TRY(details::set_vaccination_data(
     939             :         model, path_join(dir, "pydata/Germany", "all_county_ageinf_vacc_ma7.json"), date, county, num_days));
     940             : 
     941             :     // TODO: Reuse more code, e.g., set_divi_data (in secir) and a set_divi_data (here) only need a different ModelType.
     942             :     // TODO: add option to set ICU data from confirmed cases if DIVI or other data is not available.
     943          27 :     if (date > Date(2020, 4, 23)) {
     944          36 :         BOOST_OUTCOME_TRY(details::set_divi_data(model, path_join(dir, "pydata/Germany", "county_divi_ma7.json"),
     945             :                                                  county, date, scaling_factor_icu));
     946          18 :     }
     947             :     else {
     948          18 :         log_warning("No DIVI data available for this date");
     949             :     }
     950             : 
     951          54 :     BOOST_OUTCOME_TRY(details::set_confirmed_cases_data(
     952             :         model, path_join(dir, "pydata/Germany", "cases_all_county_age_ma7.json"), county, date, scaling_factor_inf));
     953          81 :     BOOST_OUTCOME_TRY(
     954             :         details::set_population_data(model, path_join(dir, "pydata/Germany", "county_current_population.json"),
     955             :                                      path_join(dir, "pydata/Germany", "cases_all_county_age_ma7.json"), county, date));
     956             : 
     957          27 :     if (export_time_series) {
     958             :         // Use only if extrapolated real data is needed for comparison. EXPENSIVE !
     959             :         // Run time equals run time of the previous functions times the num_days !
     960             :         // (This only represents the vectorization of the previous function over all simulation days...)
     961           0 :         log_warning("Exporting time series of extrapolated real data. This may take some minutes. "
     962             :                     "For simulation runs over the same time period, deactivate it.");
     963           0 :         BOOST_OUTCOME_TRY(
     964             :             export_input_data_county_timeseries(model, dir, county, date, scaling_factor_inf, scaling_factor_icu,
     965             :                                                 num_days, path_join(dir, "pydata/Germany", "county_divi_ma7.json"),
     966             :                                                 path_join(dir, "pydata/Germany", "cases_all_county_age_ma7.json"),
     967             :                                                 path_join(dir, "pydata/Germany", "county_current_population.json"),
     968             :                                                 path_join(dir, "pydata/Germany", "all_county_ageinf_vacc_ma7.json")));
     969           0 :     }
     970             : 
     971          54 :     return success();
     972          27 : }
     973             : 
     974             : /**
     975             :     * Reads compartments for German counties at a specified date from data files.
     976             :     * Estimates all compartments from available data using the model parameters, so the 
     977             :     * model parameters must be set before calling this function.
     978             :     * Uses data files that contain centered 7-day moving average.
     979             :     * @param[in, out] model Vector of SECIRVVS models, one per county.
     980             :     * @param[in] date Date for which the data should be read.
     981             :     * @param[in] node_ids Ids of the nodes.
     982             :     * @param[in] scaling_factor_inf Factor of confirmed cases to account for undetected cases in each county.
     983             :     * @param[in] scaling_factor_icu Factor of ICU cases to account for underreporting.
     984             :     * @param[in] dir Directory that contains the data files.
     985             :     * @param[in] num_days Number of days to be simulated; required to load data for vaccinations during the simulation.
     986             :     * @param[in] export_time_series If true, reads data for each day of simulation and writes it in the same directory as the input files.
     987             :     */
     988             : template <class Model>
     989          27 : IOResult<void> read_input_data(std::vector<Model>& model, Date date, const std::vector<int>& node_ids,
     990             :                                const std::vector<double>& scaling_factor_inf, double scaling_factor_icu,
     991             :                                const std::string& data_dir, int num_days, bool export_time_series = false)
     992             : {
     993             : 
     994          54 :     BOOST_OUTCOME_TRY(
     995             :         details::set_vaccination_data(model, path_join(data_dir, "vaccination_data.json"), date, node_ids, num_days));
     996             : 
     997             :     // TODO: Reuse more code, e.g., set_divi_data (in secir) and a set_divi_data (here) only need a different ModelType.
     998             :     // TODO: add option to set ICU data from confirmed cases if DIVI or other data is not available.
     999          27 :     if (date > Date(2020, 4, 23)) {
    1000          36 :         BOOST_OUTCOME_TRY(details::set_divi_data(model, path_join(data_dir, "critical_cases.json"), node_ids, date,
    1001             :                                                  scaling_factor_icu));
    1002          18 :     }
    1003             :     else {
    1004          18 :         log_warning("No DIVI data available for this date");
    1005             :     }
    1006             : 
    1007          54 :     BOOST_OUTCOME_TRY(details::set_confirmed_cases_data(model, path_join(data_dir, "confirmed_cases.json"), node_ids,
    1008             :                                                         date, scaling_factor_inf));
    1009          81 :     BOOST_OUTCOME_TRY(details::set_population_data(model, path_join(data_dir, "population_data.json"),
    1010             :                                                    path_join(data_dir, "confirmed_cases.json"), node_ids, date));
    1011             : 
    1012          27 :     if (export_time_series) {
    1013             :         // Use only if extrapolated real data is needed for comparison. EXPENSIVE !
    1014             :         // Run time equals run time of the previous functions times the num_days !
    1015             :         // (This only represents the vectorization of the previous function over all simulation days...)
    1016           0 :         log_warning("Exporting time series of extrapolated real data. This may take some minutes. "
    1017             :                     "For simulation runs over the same time period, deactivate it.");
    1018           0 :         BOOST_OUTCOME_TRY(export_input_data_county_timeseries(
    1019             :             model, data_dir, node_ids, date, scaling_factor_inf, scaling_factor_icu, num_days,
    1020             :             path_join(data_dir, "divi_data.json"), path_join(data_dir, "confirmed_cases.json"),
    1021             :             path_join(data_dir, "population_data.json"), path_join(data_dir, "vaccination_data.json")));
    1022           0 :     }
    1023             : 
    1024          54 :     return success();
    1025          27 : }
    1026             : 
    1027             : } // namespace osecirvvs
    1028             : } // namespace mio
    1029             : 
    1030             : #endif // MEMILIO_HAS_JSONCPP
    1031             : 
    1032             : #endif // ODESECIRVVS_PARAMETERS_IO_H

Generated by: LCOV version 1.14