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

          Line data    Source code
       1             : /* 
       2             : * Copyright (C) 2020-2024 MEmilio
       3             : *
       4             : * Authors: Lena Ploetzke
       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             : 
      21             : #ifndef LCTSECIR_PARAMETERS_IO_H
      22             : #define LCTSECIR_PARAMETERS_IO_H
      23             : 
      24             : #include "memilio/config.h"
      25             : 
      26             : #ifdef MEMILIO_HAS_JSONCPP
      27             : 
      28             : #include "lct_secir/model.h"
      29             : #include "lct_secir/infection_state.h"
      30             : #include "lct_secir/parameters.h"
      31             : #include "memilio/io/epi_data.h"
      32             : #include "memilio/io/io.h"
      33             : #include "memilio/utils/date.h"
      34             : #include "memilio/utils/logging.h"
      35             : #include "memilio/utils/metaprogramming.h"
      36             : #include "memilio/math/eigen.h"
      37             : #include "memilio/math/floating_point.h"
      38             : #include "memilio/epidemiology/lct_populations.h"
      39             : 
      40             : #include <string>
      41             : namespace mio
      42             : {
      43             : namespace lsecir
      44             : {
      45             : 
      46             : namespace details
      47             : { // Use namespace to hide functions that are not intended to be used outside this file.
      48             : 
      49             : /**
      50             : * @brief Processes one entry of an RKI data set for the definition of an initial value vector for an LCT population.
      51             : *   
      52             : * Takes one entry of an RKI data vector and changes the value in populations accordingly.
      53             : * @param[out] populations The populations for which the inital data should be computed and set.
      54             : * @param[in] entry The entry of the RKI data set.
      55             : * @param[in] offset The offset between the date of the entry and the date for which the 
      56             : *   initial value vector is calculated.
      57             : * @param[in] staytimes A vector of the average time spent in each compartment defined in InfectionState
      58             : *    (for the group under consideration) for which the initial value vector is calculated.
      59             : * @param[in] inv_prob_SymptomsPerNoSymptoms The inverse of the probability InfectedSymptomsPerInfectedNoSymptoms
      60             : *    (for the group under consideration) for which the initial value vector is calculated.
      61             : * @param[in] severePerInfectedSymptoms Probability (for the group under consideration)
      62             : *    for which the initial value vector is calculated.
      63             : * @param[in] criticalPerSevere Probability (for the group under consideration)
      64             : *    for which the initial value vector is calculated.
      65             : * @param[in] scale_confirmed_cases Factor by which to scale the confirmed cases of RKI data to consider unreported cases.
      66             : * @tparam Populations is expected to be an LctPopulations defined in epidemiology/lct_populations. 
      67             : *   This defined the number of age groups and the number of subcompartments used.
      68             : * @tparam EntryType The type of the data entry of the RKI data.
      69             : * @tparam Group The age group of the entry the should be processed.
      70             : */
      71             : template <class Populations, class EntryType, size_t Group>
      72         194 : void process_entry(Populations& populations, const EntryType& entry, int offset,
      73             :                    const std::vector<ScalarType> staytimes, ScalarType inv_prob_SymptomsPerNoSymptoms,
      74             :                    ScalarType severePerInfectedSymptoms, ScalarType criticalPerSevere, ScalarType scale_confirmed_cases)
      75             : {
      76             :     using LctStateGroup      = type_at_index_t<Group, typename Populations::LctStatesGroups>;
      77         194 :     size_t first_index_group = populations.template get_first_index_of_group<Group>();
      78             : 
      79             :     // Add confirmed cases at date to compartment Recovered.
      80         194 :     if (offset == 0) {
      81          36 :         populations[first_index_group + LctStateGroup::template get_first_index<InfectionState::Recovered>()] +=
      82          18 :             scale_confirmed_cases * entry.num_confirmed;
      83             :     }
      84             : 
      85             :     // Compute initial values for compartment InfectedNoSymptoms.
      86         194 :     if (offset >= 0 && offset <= std::ceil(staytimes[(size_t)InfectionState::InfectedNoSymptoms])) {
      87             :         // Mean stay time in each subcompartment.
      88          54 :         ScalarType time_INS_per_subcomp =
      89          54 :             staytimes[(size_t)InfectionState::InfectedNoSymptoms] /
      90             :             (ScalarType)LctStateGroup::template get_num_subcompartments<InfectionState::InfectedNoSymptoms>();
      91             :         // Index of the last subcompartment of InfectedNoSymptoms.
      92          54 :         size_t last_index_INS =
      93          54 :             first_index_group + LctStateGroup::template get_first_index<InfectionState::InfectedNoSymptoms>() +
      94          54 :             LctStateGroup::template get_num_subcompartments<InfectionState::InfectedNoSymptoms>() - 1;
      95         198 :         for (int i = 0; i < (int)LctStateGroup::template get_num_subcompartments<InfectionState::InfectedNoSymptoms>();
      96             :              i++) {
      97         144 :             if (offset == std::floor(i * time_INS_per_subcomp)) {
      98          96 :                 populations[last_index_INS - i] -=
      99          48 :                     (1 - (i * time_INS_per_subcomp - std::floor(i * time_INS_per_subcomp))) *
     100          48 :                     inv_prob_SymptomsPerNoSymptoms * scale_confirmed_cases * entry.num_confirmed;
     101             :             }
     102         144 :             if (offset == std::ceil(i * time_INS_per_subcomp)) {
     103          96 :                 populations[last_index_INS - i] -= (i * time_INS_per_subcomp - std::floor(i * time_INS_per_subcomp)) *
     104          96 :                                                    inv_prob_SymptomsPerNoSymptoms * scale_confirmed_cases *
     105          48 :                                                    entry.num_confirmed;
     106             :             }
     107         144 :             if (offset == std::floor((i + 1) * time_INS_per_subcomp)) {
     108          96 :                 populations[last_index_INS - i] +=
     109          48 :                     (1 - ((i + 1) * time_INS_per_subcomp - std::floor((i + 1) * time_INS_per_subcomp))) *
     110          48 :                     inv_prob_SymptomsPerNoSymptoms * scale_confirmed_cases * entry.num_confirmed;
     111             :             }
     112         144 :             if (offset == std::ceil((i + 1) * time_INS_per_subcomp)) {
     113          96 :                 populations[last_index_INS - i] +=
     114          48 :                     ((i + 1) * time_INS_per_subcomp - std::floor((i + 1) * time_INS_per_subcomp)) *
     115          48 :                     inv_prob_SymptomsPerNoSymptoms * scale_confirmed_cases * entry.num_confirmed;
     116             :             }
     117             :         }
     118             :     }
     119             : 
     120             :     // Compute initial values for compartment Exposed.
     121         262 :     if (offset >= std::floor(staytimes[(size_t)InfectionState::InfectedNoSymptoms]) &&
     122          68 :         offset <= std::ceil(staytimes[(size_t)InfectionState::Exposed] +
     123             :                             staytimes[(size_t)InfectionState::InfectedNoSymptoms])) {
     124             :         // Mean stay time in each subcompartment.
     125          68 :         ScalarType time_Exposed_per_subcomp =
     126          68 :             staytimes[(size_t)InfectionState::Exposed] /
     127             :             (ScalarType)LctStateGroup::template get_num_subcompartments<InfectionState::Exposed>();
     128             :         // Index of the last subcompartment of Exposed.
     129         136 :         size_t last_index_Exposed = first_index_group +
     130          68 :                                     LctStateGroup::template get_first_index<InfectionState::Exposed>() +
     131          68 :                                     LctStateGroup::template get_num_subcompartments<InfectionState::Exposed>() - 1;
     132         192 :         for (int i = 0; i < (int)LctStateGroup::template get_num_subcompartments<InfectionState::Exposed>(); i++) {
     133         248 :             if (offset ==
     134         124 :                 std::floor(staytimes[(size_t)InfectionState::InfectedNoSymptoms] + i * time_Exposed_per_subcomp)) {
     135          33 :                 populations[last_index_Exposed - i] -=
     136          33 :                     (1 - (staytimes[(size_t)InfectionState::InfectedNoSymptoms] + i * time_Exposed_per_subcomp -
     137          33 :                           std::floor(staytimes[(size_t)InfectionState::InfectedNoSymptoms] +
     138          33 :                                      i * time_Exposed_per_subcomp))) *
     139          33 :                     inv_prob_SymptomsPerNoSymptoms * scale_confirmed_cases * entry.num_confirmed;
     140             :             }
     141         248 :             if (offset ==
     142         124 :                 std::ceil(staytimes[(size_t)InfectionState::InfectedNoSymptoms] + i * time_Exposed_per_subcomp)) {
     143          31 :                 populations[last_index_Exposed - i] -=
     144          31 :                     (staytimes[(size_t)InfectionState::InfectedNoSymptoms] + i * time_Exposed_per_subcomp -
     145          31 :                      std::floor(staytimes[(size_t)InfectionState::InfectedNoSymptoms] + i * time_Exposed_per_subcomp)) *
     146          31 :                     inv_prob_SymptomsPerNoSymptoms * scale_confirmed_cases * entry.num_confirmed;
     147             :             }
     148         124 :             if (offset == std::floor(staytimes[(size_t)InfectionState::InfectedNoSymptoms] +
     149         124 :                                      (i + 1) * time_Exposed_per_subcomp)) {
     150          31 :                 populations[last_index_Exposed - i] +=
     151          31 :                     (1 - (staytimes[(size_t)InfectionState::InfectedNoSymptoms] + (i + 1) * time_Exposed_per_subcomp -
     152          31 :                           std::floor(staytimes[(size_t)InfectionState::InfectedNoSymptoms] +
     153          31 :                                      (i + 1) * time_Exposed_per_subcomp))) *
     154          31 :                     inv_prob_SymptomsPerNoSymptoms * scale_confirmed_cases * entry.num_confirmed;
     155             :             }
     156         248 :             if (offset ==
     157         124 :                 std::ceil(staytimes[(size_t)InfectionState::InfectedNoSymptoms] + (i + 1) * time_Exposed_per_subcomp)) {
     158          29 :                 populations[last_index_Exposed - i] +=
     159          29 :                     (staytimes[(size_t)InfectionState::InfectedNoSymptoms] + (i + 1) * time_Exposed_per_subcomp -
     160          29 :                      std::floor(staytimes[(size_t)InfectionState::InfectedNoSymptoms] +
     161          29 :                                 (i + 1) * time_Exposed_per_subcomp)) *
     162          29 :                     inv_prob_SymptomsPerNoSymptoms * scale_confirmed_cases * entry.num_confirmed;
     163             :             }
     164             :         }
     165             :     }
     166             : 
     167             :     // Compute initial values for compartment InfectedSymptoms.
     168         194 :     if (offset >= std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms]) && offset <= 0) {
     169             :         // Mean stay time in each subcompartment.
     170          72 :         ScalarType time_IS_per_subcomp =
     171          72 :             staytimes[(size_t)InfectionState::InfectedSymptoms] /
     172             :             (ScalarType)LctStateGroup::template get_num_subcompartments<InfectionState::InfectedSymptoms>();
     173             :         // Index of the first subcompartment of InfectedSymptoms.
     174          72 :         size_t first_index_IS =
     175          72 :             first_index_group + LctStateGroup::template get_first_index<InfectionState::InfectedSymptoms>();
     176         204 :         for (int i = 0; i < (int)LctStateGroup::template get_num_subcompartments<InfectionState::InfectedSymptoms>();
     177             :              i++) {
     178         132 :             if (offset == std::floor(-time_IS_per_subcomp * (i + 1))) {
     179          66 :                 populations[first_index_IS + i] -=
     180          33 :                     (1 - (-(i + 1.) * time_IS_per_subcomp - std::floor(-(i + 1) * time_IS_per_subcomp))) *
     181          33 :                     scale_confirmed_cases * entry.num_confirmed;
     182             :             }
     183         132 :             if (offset == std::ceil(-time_IS_per_subcomp * (i + 1))) {
     184          66 :                 populations[first_index_IS + i] -=
     185          33 :                     (-(i + 1) * time_IS_per_subcomp - std::floor(-(i + 1) * time_IS_per_subcomp)) *
     186          33 :                     scale_confirmed_cases * entry.num_confirmed;
     187             :             }
     188         132 :             if (offset == std::floor(-time_IS_per_subcomp * i)) {
     189          66 :                 populations[first_index_IS + i] +=
     190          66 :                     (1 - (-i * time_IS_per_subcomp - std::floor(-i * time_IS_per_subcomp))) * scale_confirmed_cases *
     191          33 :                     entry.num_confirmed;
     192             :             }
     193         132 :             if (offset == std::ceil(-time_IS_per_subcomp * i)) {
     194          66 :                 populations[first_index_IS + i] += (-i * time_IS_per_subcomp - std::floor(-i * time_IS_per_subcomp)) *
     195          33 :                                                    scale_confirmed_cases * entry.num_confirmed;
     196             :             }
     197             :         }
     198             :     }
     199             : 
     200             :     // Compute initial values for compartment InfectedSevere.
     201         194 :     if (offset >= std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     202         370 :                              staytimes[(size_t)InfectionState::InfectedSevere]) &&
     203         176 :         offset <= std::ceil(-staytimes[(size_t)InfectionState::InfectedSymptoms])) {
     204             :         // Mean stay time in each subcompartment.
     205          72 :         ScalarType time_ISev_per_subcomp =
     206          72 :             staytimes[(size_t)InfectionState::InfectedSevere] /
     207             :             (ScalarType)LctStateGroup::template get_num_subcompartments<InfectionState::InfectedSevere>();
     208             :         // Index of the first subcompartment of InfectedSevere.
     209          72 :         size_t first_index_ISev =
     210          72 :             first_index_group + LctStateGroup::template get_first_index<InfectionState::InfectedSevere>();
     211         204 :         for (int i = 0; i < (int)LctStateGroup::template get_num_subcompartments<InfectionState::InfectedSevere>();
     212             :              i++) {
     213         264 :             if (offset ==
     214         132 :                 std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] - time_ISev_per_subcomp * (i + 1))) {
     215          33 :                 populations[first_index_ISev + i] -=
     216          33 :                     severePerInfectedSymptoms *
     217          33 :                     (1 - (-staytimes[(size_t)InfectionState::InfectedSymptoms] - (i + 1) * time_ISev_per_subcomp -
     218          33 :                           std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     219          33 :                                      (i + 1) * time_ISev_per_subcomp))) *
     220          33 :                     scale_confirmed_cases * entry.num_confirmed;
     221             :             }
     222         264 :             if (offset ==
     223         132 :                 std::ceil(-staytimes[(size_t)InfectionState::InfectedSymptoms] - time_ISev_per_subcomp * (i + 1))) {
     224          33 :                 populations[first_index_ISev + i] -=
     225          33 :                     severePerInfectedSymptoms *
     226          33 :                     (-staytimes[(size_t)InfectionState::InfectedSymptoms] - (i + 1) * time_ISev_per_subcomp -
     227          33 :                      std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     228          33 :                                 (i + 1) * time_ISev_per_subcomp)) *
     229          33 :                     scale_confirmed_cases * entry.num_confirmed;
     230             :             }
     231         264 :             if (offset ==
     232         132 :                 std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] - time_ISev_per_subcomp * i)) {
     233          33 :                 populations[first_index_ISev + i] +=
     234          33 :                     severePerInfectedSymptoms *
     235          33 :                     (1 -
     236          33 :                      (-staytimes[(size_t)InfectionState::InfectedSymptoms] - i * time_ISev_per_subcomp -
     237          33 :                       std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] - i * time_ISev_per_subcomp))) *
     238          33 :                     scale_confirmed_cases * entry.num_confirmed;
     239             :             }
     240         132 :             if (offset == std::ceil(-staytimes[(size_t)InfectionState::InfectedSymptoms] - time_ISev_per_subcomp * i)) {
     241          33 :                 populations[first_index_ISev + i] +=
     242          33 :                     severePerInfectedSymptoms *
     243          33 :                     (-staytimes[(size_t)InfectionState::InfectedSymptoms] - i * time_ISev_per_subcomp -
     244          33 :                      std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] - i * time_ISev_per_subcomp)) *
     245          33 :                     scale_confirmed_cases * entry.num_confirmed;
     246             :             }
     247             :         }
     248             :     }
     249             : 
     250             :     // Compute initial values for compartment InfectedCritical.
     251         388 :     if (offset >= std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     252         194 :                              staytimes[(size_t)InfectionState::InfectedSevere] -
     253         388 :                              staytimes[(size_t)InfectionState::InfectedCritical]) &&
     254         194 :         offset <= std::ceil(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     255             :                             staytimes[(size_t)InfectionState::InfectedSevere])) {
     256             :         // Mean stay time in each subcompartment.
     257          54 :         ScalarType time_ICri_per_subcomp =
     258          54 :             staytimes[(size_t)InfectionState::InfectedCritical] /
     259             :             (ScalarType)LctStateGroup::template get_num_subcompartments<InfectionState::InfectedCritical>();
     260             :         // Index of the first subcompartment of InfectedCritical.
     261          54 :         size_t first_index_ICri =
     262          54 :             first_index_group + LctStateGroup::template get_first_index<InfectionState::InfectedCritical>();
     263         141 :         for (int i = 0; i < (int)LctStateGroup::template get_num_subcompartments<InfectionState::InfectedCritical>();
     264             :              i++) {
     265         174 :             if (offset ==
     266          87 :                 std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     267          87 :                            staytimes[(size_t)InfectionState::InfectedSevere] - time_ICri_per_subcomp * (i + 1))) {
     268          29 :                 populations[first_index_ICri + i] -=
     269          58 :                     severePerInfectedSymptoms * criticalPerSevere *
     270          29 :                     (1 - (-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     271          58 :                           staytimes[(size_t)InfectionState::InfectedSevere] - (i + 1) * time_ICri_per_subcomp -
     272          29 :                           std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     273             :                                      staytimes[(size_t)InfectionState::InfectedSevere] -
     274          29 :                                      (i + 1) * time_ICri_per_subcomp))) *
     275          29 :                     scale_confirmed_cases * entry.num_confirmed;
     276             :             }
     277         174 :             if (offset ==
     278          87 :                 std::ceil(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     279          87 :                           staytimes[(size_t)InfectionState::InfectedSevere] - time_ICri_per_subcomp * (i + 1))) {
     280          29 :                 populations[first_index_ICri + i] -=
     281          58 :                     severePerInfectedSymptoms * criticalPerSevere *
     282          29 :                     (-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     283          58 :                      staytimes[(size_t)InfectionState::InfectedSevere] - (i + 1) * time_ICri_per_subcomp -
     284          29 :                      std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     285          29 :                                 staytimes[(size_t)InfectionState::InfectedSevere] - (i + 1) * time_ICri_per_subcomp)) *
     286          29 :                     scale_confirmed_cases * entry.num_confirmed;
     287             :             }
     288          87 :             if (offset == std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     289          87 :                                      staytimes[(size_t)InfectionState::InfectedSevere] - time_ICri_per_subcomp * i)) {
     290          29 :                 populations[first_index_ICri + i] +=
     291          58 :                     severePerInfectedSymptoms * criticalPerSevere *
     292          29 :                     (1 - (-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     293          58 :                           staytimes[(size_t)InfectionState::InfectedSevere] - i * time_ICri_per_subcomp -
     294          29 :                           std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     295          29 :                                      staytimes[(size_t)InfectionState::InfectedSevere] - i * time_ICri_per_subcomp))) *
     296          29 :                     scale_confirmed_cases * entry.num_confirmed;
     297             :             }
     298          87 :             if (offset == std::ceil(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     299          87 :                                     staytimes[(size_t)InfectionState::InfectedSevere] - time_ICri_per_subcomp * i)) {
     300          29 :                 populations[first_index_ICri + i] +=
     301          58 :                     severePerInfectedSymptoms * criticalPerSevere *
     302          29 :                     (-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     303          58 :                      staytimes[(size_t)InfectionState::InfectedSevere] - i * time_ICri_per_subcomp -
     304          29 :                      std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     305          29 :                                 staytimes[(size_t)InfectionState::InfectedSevere] - i * time_ICri_per_subcomp)) *
     306          29 :                     scale_confirmed_cases * entry.num_confirmed;
     307             :             }
     308             :         }
     309             :     }
     310             : 
     311             :     // Compute Dead.
     312         388 :     if (offset == std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     313         194 :                              staytimes[(size_t)InfectionState::InfectedSevere] -
     314             :                              staytimes[(size_t)InfectionState::InfectedCritical])) {
     315          18 :         populations[first_index_group + LctStateGroup::template get_first_index<InfectionState::Dead>()] +=
     316          18 :             (1 -
     317          18 :              (-staytimes[(size_t)InfectionState::InfectedSymptoms] - staytimes[(size_t)InfectionState::InfectedSevere] -
     318          18 :               staytimes[(size_t)InfectionState::InfectedCritical] -
     319          36 :               std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     320          18 :                          staytimes[(size_t)InfectionState::InfectedSevere] -
     321          18 :                          staytimes[(size_t)InfectionState::InfectedCritical]))) *
     322          18 :             entry.num_deaths;
     323             :     }
     324         388 :     if (offset == std::ceil(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     325         194 :                             staytimes[(size_t)InfectionState::InfectedSevere] -
     326             :                             staytimes[(size_t)InfectionState::InfectedCritical])) {
     327          18 :         populations[first_index_group + LctStateGroup::template get_first_index<InfectionState::Dead>()] +=
     328          18 :             (-staytimes[(size_t)InfectionState::InfectedSymptoms] - staytimes[(size_t)InfectionState::InfectedSevere] -
     329          18 :              staytimes[(size_t)InfectionState::InfectedCritical] -
     330          36 :              std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     331          18 :                         staytimes[(size_t)InfectionState::InfectedSevere] -
     332          18 :                         staytimes[(size_t)InfectionState::InfectedCritical])) *
     333          18 :             entry.num_deaths;
     334             :     }
     335         194 : }
     336             : 
     337             : /**
     338             : * @brief Computes an initialization vector for an LCT population with case data from RKI recursively for each age group
     339             : *    (or for one age group in the case without age resolution).
     340             : *   
     341             : * Please use the set_initial_data_from_confirmed_cases() function, which calls this function automatically!
     342             : * This function calculates a segment referring to the defined age group of the initial value vector with 
     343             : *   subcompartments using the rki_data and the parameters.
     344             : * The values for the whole initial value vector stored in populations are calculated recursively.
     345             : *
     346             : * @param[in] rki_data Vector with the RKI data.
     347             : * @param[out] populations The populations for which the inital data should be computed and set.
     348             : * @param[in] parameters The parameters that should be used to calculate the initial values. 
     349             : *   Probabilities and mean stay times are used.
     350             : * @param[in] date Date for which the initial values should be computed. date is the start date of the simulation.
     351             : * @param[in] total_population Total size of the population of Germany or of every age group. 
     352             : * @param[in] scale_confirmed_cases Factor(s for each age group) by which to scale the confirmed cases of the rki data 
     353             : *   to consider unreported cases.
     354             : * @tparam Populations is expected to be an LctPopulations defined in epidemiology/lct_populations. 
     355             : *   This defined the number of age groups and the number of subcompartments used.
     356             : * @tparam EntryType is expected to be ConfirmedCasesNoAgeEntry for data that is not age resolved and 
     357             : *   ConfirmedCasesDataEntry for age resolved data. See also epi_data.h.
     358             : * @tparam Group The age group for which the initial values should be calculated. The function is called recursively 
     359             : *   such that the initial values are calculated for every age group if Group is zero at the beginning.
     360             : * @returns Any io errors that happen during data processing.
     361             : */
     362             : template <class Populations, class EntryType, size_t Group = 0>
     363          18 : IOResult<void> set_initial_data_from_confirmed_cases_impl(Populations& populations,
     364             :                                                           const std::vector<EntryType>& rki_data,
     365             :                                                           const Parameters& parameters, Date date,
     366             :                                                           const std::vector<ScalarType>& total_population,
     367             :                                                           const std::vector<ScalarType>& scale_confirmed_cases)
     368             : {
     369             :     static_assert((Group < Populations::num_groups) && (Group >= 0), "The template parameter Group should be valid.");
     370             :     using LctStateGroup      = type_at_index_t<Group, typename Populations::LctStatesGroups>;
     371          18 :     size_t first_index_group = populations.template get_first_index_of_group<Group>();
     372             : 
     373             :     // Define variables for parameters.
     374          36 :     std::vector<ScalarType> staytimes((size_t)InfectionState::Count, -1.);
     375          18 :     staytimes[(size_t)InfectionState::Exposed]            = parameters.template get<TimeExposed>()[Group];
     376          18 :     staytimes[(size_t)InfectionState::InfectedNoSymptoms] = parameters.template get<TimeInfectedNoSymptoms>()[Group];
     377          18 :     staytimes[(size_t)InfectionState::InfectedSymptoms]   = parameters.template get<TimeInfectedSymptoms>()[Group];
     378          18 :     staytimes[(size_t)InfectionState::InfectedSevere]     = parameters.template get<TimeInfectedSevere>()[Group];
     379          18 :     staytimes[(size_t)InfectionState::InfectedCritical]   = parameters.template get<TimeInfectedCritical>()[Group];
     380          18 :     ScalarType inv_prob_SymptomsPerNoSymptoms =
     381          18 :         1 / (1 - parameters.template get<RecoveredPerInfectedNoSymptoms>()[Group]);
     382          18 :     ScalarType prob_SeverePerInfectedSymptoms = parameters.template get<SeverePerInfectedSymptoms>()[Group];
     383          18 :     ScalarType prob_CriticalPerSevere         = parameters.template get<CriticalPerSevere>()[Group];
     384             : 
     385          36 :     ScalarType min_offset_needed = std::floor(-staytimes[(size_t)InfectionState::InfectedSymptoms] -
     386          18 :                                               staytimes[(size_t)InfectionState::InfectedSevere] -
     387             :                                               staytimes[(size_t)InfectionState::InfectedCritical]);
     388             :     ScalarType max_offset_needed =
     389          18 :         std::ceil(staytimes[(size_t)InfectionState::Exposed] + staytimes[(size_t)InfectionState::InfectedNoSymptoms]);
     390             : 
     391          18 :     bool min_offset_needed_avail = false;
     392          18 :     bool max_offset_needed_avail = false;
     393             : 
     394             :     // Go through the entries of rki_data and check if the entry is age resolved and is referring to
     395             :     // the age_group Group in the case with age resolution. If the date is
     396             :     // needed for calculation, another function to handle the entry is called. Confirmed cases are scaled by scale_confirmed_cases.
     397         986 :     for (auto&& entry : rki_data) {
     398             :         if constexpr (std::is_same_v<EntryType, ConfirmedCasesDataEntry>) {
     399         924 :             if (!((size_t)entry.age_group == Group)) {
     400         770 :                 continue;
     401             :             }
     402             :         }
     403         198 :         int offset = get_offset_in_days(entry.date, date);
     404         198 :         if ((offset >= min_offset_needed) && (offset <= max_offset_needed)) {
     405         194 :             if (offset == max_offset_needed) {
     406          16 :                 max_offset_needed_avail = true;
     407             :             }
     408         194 :             if (offset == min_offset_needed) {
     409          18 :                 min_offset_needed_avail = true;
     410             :             }
     411         194 :             process_entry<Populations, EntryType, Group>(populations, entry, offset, staytimes,
     412             :                                                          inv_prob_SymptomsPerNoSymptoms, prob_SeverePerInfectedSymptoms,
     413             :                                                          prob_CriticalPerSevere, scale_confirmed_cases[Group]);
     414             :         }
     415             :     }
     416             : 
     417             :     // Compute Recovered.
     418          18 :     populations[first_index_group + LctStateGroup::template get_first_index<InfectionState::Recovered>()] -=
     419             :         populations.get_compartments()
     420          36 :             .segment(first_index_group + LctStateGroup::template get_first_index<InfectionState::InfectedSymptoms>(),
     421          18 :                      LctStateGroup::template get_num_subcompartments<InfectionState::InfectedSymptoms>() +
     422          18 :                          LctStateGroup::template get_num_subcompartments<InfectionState::InfectedSevere>() +
     423          18 :                          LctStateGroup::template get_num_subcompartments<InfectionState::InfectedCritical>())
     424          54 :             .sum();
     425          18 :     populations[first_index_group + LctStateGroup::template get_first_index<InfectionState::Recovered>()] -=
     426          18 :         populations[first_index_group + LctStateGroup::template get_first_index<InfectionState::Dead>()];
     427             : 
     428             :     // Compute Susceptibles.
     429          36 :     populations[first_index_group + LctStateGroup::template get_first_index<InfectionState::Susceptible>()] =
     430          18 :         total_population[Group] -
     431          36 :         populations.get_compartments().segment(first_index_group + 1, LctStateGroup::Count - 1).sum();
     432             : 
     433             :     // Check whether all necessary dates are available.
     434          18 :     if (!max_offset_needed_avail || !min_offset_needed_avail) {
     435           4 :         log_error(
     436             :             "Necessary range of dates needed to compute initial values does not exist in RKI data for group {:d}.",
     437             :             Group);
     438             :         return failure(StatusCode::OutOfRange,
     439           2 :                        "Necessary range of dates needed to compute initial values does not exist in RKI data.");
     440             :     }
     441             : 
     442             :     // Check if all values for populations are valid.
     443          70 :     for (size_t i = first_index_group; i < LctStateGroup::Count; i++) {
     444          56 :         if (floating_point_less((ScalarType)populations[i], 0., 1e-14)) {
     445           4 :             log_error("Something went wrong in the initialization of group {:d}. At least one entry is negative.",
     446             :                       Group);
     447             :             return failure(StatusCode::InvalidValue,
     448           2 :                            "Something went wrong in the initialization as at least one entry is negative.");
     449             :         }
     450             :     }
     451             : 
     452             :     if constexpr (Group + 1 < Populations::num_groups) {
     453             :         return set_initial_data_from_confirmed_cases_impl<Populations, EntryType, Group + 1>(
     454          10 :             populations, rki_data, parameters, date, total_population, scale_confirmed_cases);
     455             :     }
     456             :     else {
     457           8 :         return mio::success();
     458             :     }
     459          18 : }
     460             : } // namespace details
     461             : 
     462             : /**
     463             : * @brief Computes an initialization vector for an LCT population with case data from RKI.
     464             : *   
     465             : * Use just one group in the definition of the populations to not divide between age groups.
     466             : * Otherwise, the number of groups has to match the number of RKI age groups.
     467             : * The function calculates an initial value vector referring to an LCT population and updates the initial value vector
     468             : * in the populations class.
     469             : * For the computation expected stay times in the subcompartments defined in the parameters variable are used.
     470             : * To calculate the initial values, we assume for simplicity that individuals stay in the subcompartment 
     471             : * for exactly the expected time.
     472             : * The RKI data are linearly interpolated within one day to match the expected stay time in a subcompartment.
     473             : * The RKI data should contain data for each needed day with or without division of age groups, 
     474             : *   the completeness of the dates is not verified.
     475             : * Data can be downloaded e.g. with the file pycode/memilio-epidata/memilio/epidata/getCaseData.py, which creates files
     476             : * named e.g. cases_all_germany.json for no groups or cases_all_age.json with division in age groups or similar names.
     477             : * One should set impute_dates=True so that missing dates are imputed. 
     478             : * To read the data into a vector, use the functionality from epi_data.h.
     479             : * The data and the number of entries in the total_population and scale_confirmed_cases vectors have to match the 
     480             : *   number of groups used in Populations.
     481             : *
     482             : * @param[in] rki_data Vector with the RKI data.
     483             : * @param[out] populations The populations for which the inital data should be computed and set.
     484             : * @param[in] parameters The parameters that should be used to calculate the initial values. 
     485             : *   Probabilities and mean stay times are used.
     486             : * @param[in] date Date for which the initial values should be computed. date is the start date of the simulation.
     487             : * @param[in] total_population Total size of the population of Germany or of every age group. 
     488             : * @param[in] scale_confirmed_cases Factor(s for each age group) by which to scale the confirmed cases of the rki data 
     489             : *   to consider unreported cases.
     490             : * @tparam Populations is expected to be an LctPopulations defined in epidemiology/lct_populations. 
     491             : *   This defined the number of age groups and the number of subcompartments used.
     492             : * @tparam EntryType is expected to be ConfirmedCasesNoAgeEntry for data that is not age resolved and 
     493             : *   ConfirmedCasesDataEntry for age resolved data. See also epi_data.h.
     494             : * @returns Any io errors that happen during data processing.
     495             : */
     496             : template <class Populations, class EntryType>
     497          12 : IOResult<void> set_initial_data_from_confirmed_cases(const std::vector<EntryType>& rki_data, Populations& populations,
     498             :                                                      const Parameters& parameters, const Date date,
     499             :                                                      const std::vector<ScalarType>& total_population,
     500             :                                                      const std::vector<ScalarType>& scale_confirmed_cases)
     501             : { // Check if the inputs are matching.
     502          12 :     assert(total_population.size() == Populations::num_groups);
     503          12 :     assert(scale_confirmed_cases.size() == Populations::num_groups);
     504             :     if constexpr (Populations::num_groups > 1) {
     505             :         static_assert(std::is_same_v<EntryType, ConfirmedCasesDataEntry>);
     506           6 :         assert(ConfirmedCasesDataEntry::age_group_names.size() == Populations::num_groups);
     507             :     }
     508             :     else {
     509             :         static_assert(std::is_same_v<EntryType, ConfirmedCasesNoAgeEntry>);
     510             :     }
     511             :     // Check if RKI data vector is valid.
     512         387 :     auto max_date_entry = std::max_element(rki_data.begin(), rki_data.end(), [](auto&& a, auto&& b) {
     513         375 :         return a.date < b.date;
     514             :     });
     515          12 :     if (max_date_entry == rki_data.end()) {
     516           4 :         log_error("RKI data file is empty.");
     517           2 :         return failure(StatusCode::InvalidFileFormat, "RKI data is empty.");
     518             :     }
     519          10 :     auto max_date = max_date_entry->date;
     520          10 :     if (max_date < date) {
     521           4 :         log_error("Specified date does not exist in RKI data.");
     522           2 :         return failure(StatusCode::OutOfRange, "Specified date does not exist in RKI data.");
     523             :     }
     524             :     // Initially set populations to zero.
     525         378 :     for (size_t i = 0; i < populations.get_num_compartments(); i++) {
     526         370 :         populations[i] = 0;
     527             :     }
     528             :     return details::set_initial_data_from_confirmed_cases_impl<Populations, EntryType>(
     529           8 :         populations, rki_data, parameters, date, total_population, scale_confirmed_cases);
     530             : }
     531             : 
     532             : } // namespace lsecir
     533             : } // namespace mio
     534             : #endif // MEMILIO_HAS_JSONCPP
     535             : 
     536             : #endif // LCTSECIR_PARAMETERS_IO_H

Generated by: LCOV version 1.14