LCOV - code coverage report
Current view: top level - models/ode_secirvvs - parameters_io.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 155 186 83.3 %
Date: 2024-11-18 12:45:26 Functions: 18 19 94.7 %

          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             : #include "memilio/config.h"
      21             : 
      22             : #ifdef MEMILIO_HAS_JSONCPP
      23             : 
      24             : #include "ode_secirvvs/parameters_io.h"
      25             : 
      26             : namespace mio
      27             : {
      28             : namespace osecirvvs
      29             : {
      30             : namespace details
      31             : {
      32             : //gets the county or state id of the entry if available, 0 (for whole country) otherwise
      33             : //used for comparisons of entry to integer region id
      34             : template <class EpiDataEntry>
      35       72036 : int get_region_id(const EpiDataEntry& rki_entry)
      36             : {
      37      164772 :     return rki_entry.county_id ? rki_entry.county_id->get()
      38       62100 :                                : (rki_entry.state_id ? rki_entry.state_id->get()
      39      113436 :                                                      : (rki_entry.district_id ? rki_entry.district_id->get() : 0));
      40             : }
      41             : 
      42           9 : IOResult<void> read_confirmed_cases_data(
      43             :     std::string const& path, std::vector<int> const& vregion, Date date, std::vector<std::vector<double>>& vnum_Exposed,
      44             :     std::vector<std::vector<double>>& vnum_InfectedNoSymptoms, std::vector<std::vector<double>>& vnum_InfectedSymptoms,
      45             :     std::vector<std::vector<double>>& vnum_InfectedSevere, std::vector<std::vector<double>>& vnum_icu,
      46             :     std::vector<std::vector<double>>& vnum_death, std::vector<std::vector<double>>& vnum_rec,
      47             :     const std::vector<std::vector<int>>& vt_Exposed, const std::vector<std::vector<int>>& vt_InfectedNoSymptoms,
      48             :     const std::vector<std::vector<int>>& vt_InfectedSymptoms, const std::vector<std::vector<int>>& vt_InfectedSevere,
      49             :     const std::vector<std::vector<int>>& vt_InfectedCritical, const std::vector<std::vector<double>>& vmu_C_R,
      50             :     const std::vector<std::vector<double>>& vmu_I_H, const std::vector<std::vector<double>>& vmu_H_U,
      51             :     const std::vector<double>& scaling_factor_inf)
      52             : {
      53           9 :     BOOST_OUTCOME_TRY(auto&& rki_data, mio::read_confirmed_cases_data(path));
      54             :     return read_confirmed_cases_data(rki_data, vregion, date, vnum_Exposed, vnum_InfectedNoSymptoms,
      55             :                                      vnum_InfectedSymptoms, vnum_InfectedSevere, vnum_icu, vnum_death, vnum_rec,
      56             :                                      vt_Exposed, vt_InfectedNoSymptoms, vt_InfectedSymptoms, vt_InfectedSevere,
      57           9 :                                      vt_InfectedCritical, vmu_C_R, vmu_I_H, vmu_H_U, scaling_factor_inf);
      58           9 : }
      59             : 
      60         279 : IOResult<void> read_confirmed_cases_data(
      61             :     const std::vector<ConfirmedCasesDataEntry>& rki_data, std::vector<int> const& vregion, Date date,
      62             :     std::vector<std::vector<double>>& vnum_Exposed, std::vector<std::vector<double>>& vnum_InfectedNoSymptoms,
      63             :     std::vector<std::vector<double>>& vnum_InfectedSymptoms, std::vector<std::vector<double>>& vnum_InfectedSevere,
      64             :     std::vector<std::vector<double>>& vnum_icu, std::vector<std::vector<double>>& vnum_death,
      65             :     std::vector<std::vector<double>>& vnum_rec, const std::vector<std::vector<int>>& vt_Exposed,
      66             :     const std::vector<std::vector<int>>& vt_InfectedNoSymptoms,
      67             :     const std::vector<std::vector<int>>& vt_InfectedSymptoms, const std::vector<std::vector<int>>& vt_InfectedSevere,
      68             :     const std::vector<std::vector<int>>& vt_InfectedCritical, const std::vector<std::vector<double>>& vmu_C_R,
      69             :     const std::vector<std::vector<double>>& vmu_I_H, const std::vector<std::vector<double>>& vmu_H_U,
      70             :     const std::vector<double>& scaling_factor_inf)
      71             : {
      72         279 :     auto max_date_entry = std::max_element(rki_data.begin(), rki_data.end(), [](auto&& a, auto&& b) {
      73      153729 :         return a.date < b.date;
      74             :     });
      75         279 :     if (max_date_entry == rki_data.end()) {
      76           0 :         log_error("RKI data file is empty.");
      77           0 :         return failure(StatusCode::InvalidValue, "RKI data is empty.");
      78             :     }
      79         279 :     auto max_date = max_date_entry->date;
      80         279 :     if (max_date < date) {
      81           0 :         log_error("Specified date does not exist in RKI data");
      82           0 :         return failure(StatusCode::OutOfRange, "RKI data does not contain specified date.");
      83             :     }
      84             : 
      85             :     // shifts the initilization to the recent past if simulation starts
      86             :     // around current day and data of the future would be required.
      87             :     // Only needed for preinfection compartments, exposed and InfectedNoSymptoms.
      88         279 :     auto days_surplus = get_offset_in_days(max_date, date) - 6; // 6 > T_E + T_C
      89         279 :     if (days_surplus > 0) {
      90         279 :         days_surplus = 0;
      91             :     }
      92             : 
      93      154287 :     for (auto&& entry : rki_data) {
      94      203688 :         auto it = std::find_if(vregion.begin(), vregion.end(), [&entry](auto r) {
      95      203688 :             return r == 0 || get_region_id(entry) == r;
      96             :         });
      97      154008 :         if (it != vregion.end()) {
      98      154008 :             auto region_idx = size_t(it - vregion.begin());
      99             : 
     100      154008 :             auto& t_Exposed            = vt_Exposed[region_idx];
     101      154008 :             auto& t_InfectedNoSymptoms = vt_InfectedNoSymptoms[region_idx];
     102      154008 :             auto& t_InfectedSymptoms   = vt_InfectedSymptoms[region_idx];
     103      154008 :             auto& t_InfectedSevere     = vt_InfectedSevere[region_idx];
     104      154008 :             auto& t_InfectedCritical   = vt_InfectedCritical[region_idx];
     105             : 
     106      154008 :             auto& num_InfectedNoSymptoms = vnum_InfectedNoSymptoms[region_idx];
     107      154008 :             auto& num_InfectedSymptoms   = vnum_InfectedSymptoms[region_idx];
     108      154008 :             auto& num_rec                = vnum_rec[region_idx];
     109      154008 :             auto& num_Exposed            = vnum_Exposed[region_idx];
     110      154008 :             auto& num_InfectedSevere     = vnum_InfectedSevere[region_idx];
     111      154008 :             auto& num_death              = vnum_death[region_idx];
     112      154008 :             auto& num_icu                = vnum_icu[region_idx];
     113             : 
     114      154008 :             auto& mu_C_R = vmu_C_R[region_idx];
     115      154008 :             auto& mu_I_H = vmu_I_H[region_idx];
     116      154008 :             auto& mu_H_U = vmu_H_U[region_idx];
     117             : 
     118      154008 :             bool read_icu = false; // params.populations.get({age, SecirCompartments::U}) == 0;
     119             : 
     120      154008 :             auto age = (size_t)entry.age_group;
     121      154008 :             if (entry.date == offset_date_by_days(date, 0)) {
     122        1188 :                 num_InfectedSymptoms[age] += scaling_factor_inf[age] * entry.num_confirmed;
     123        1188 :                 num_rec[age] += entry.num_confirmed;
     124             :             }
     125      154008 :             if (entry.date == offset_date_by_days(date, t_InfectedNoSymptoms[age] + days_surplus)) {
     126        1188 :                 num_InfectedNoSymptoms[age] += 1 / (1 - mu_C_R[age]) * scaling_factor_inf[age] * entry.num_confirmed;
     127        1188 :                 num_Exposed[age] -= 1 / (1 - mu_C_R[age]) * scaling_factor_inf[age] * entry.num_confirmed;
     128             :             }
     129      154008 :             if (entry.date == offset_date_by_days(date, days_surplus)) {
     130        1188 :                 num_InfectedNoSymptoms[age] -= 1 / (1 - mu_C_R[age]) * scaling_factor_inf[age] * entry.num_confirmed;
     131             :             }
     132      154008 :             if (entry.date == offset_date_by_days(date, t_Exposed[age] + t_InfectedNoSymptoms[age] + days_surplus)) {
     133        1188 :                 num_Exposed[age] += 1 / (1 - mu_C_R[age]) * scaling_factor_inf[age] * entry.num_confirmed;
     134             :             }
     135      154008 :             if (entry.date == offset_date_by_days(date, -t_InfectedSymptoms[age])) {
     136        1188 :                 num_InfectedSymptoms[age] -= scaling_factor_inf[age] * entry.num_confirmed;
     137        1188 :                 num_InfectedSevere[age] += mu_I_H[age] * scaling_factor_inf[age] * entry.num_confirmed;
     138             :             }
     139      154008 :             if (entry.date == offset_date_by_days(date, -t_InfectedSymptoms[age] - t_InfectedSevere[age])) {
     140        1188 :                 num_InfectedSevere[age] -= mu_I_H[age] * scaling_factor_inf[age] * entry.num_confirmed;
     141        1188 :                 if (read_icu) {
     142           0 :                     num_icu[age] += mu_I_H[age] * mu_H_U[age] * scaling_factor_inf[age] * entry.num_confirmed;
     143             :                 }
     144             :             }
     145      308016 :             if (entry.date ==
     146      308016 :                 offset_date_by_days(date, -t_InfectedSymptoms[age] - t_InfectedSevere[age] - t_InfectedCritical[age])) {
     147        1188 :                 num_death[age] += entry.num_deaths;
     148        1188 :                 if (read_icu) {
     149           0 :                     num_icu[age] -= mu_I_H[age] * mu_H_U[age] * scaling_factor_inf[age] * entry.num_confirmed;
     150             :                 }
     151             :             }
     152             :         }
     153             :     }
     154             : 
     155         558 :     for (size_t region_idx = 0; region_idx < vregion.size(); ++region_idx) {
     156         279 :         auto region = vregion[region_idx];
     157             : 
     158         279 :         auto& num_InfectedNoSymptoms = vnum_InfectedNoSymptoms[region_idx];
     159         279 :         auto& num_InfectedSymptoms   = vnum_InfectedSymptoms[region_idx];
     160         279 :         auto& num_rec                = vnum_rec[region_idx];
     161         279 :         auto& num_Exposed            = vnum_Exposed[region_idx];
     162         279 :         auto& num_InfectedSevere     = vnum_InfectedSevere[region_idx];
     163         279 :         auto& num_death              = vnum_death[region_idx];
     164         279 :         auto& num_icu                = vnum_icu[region_idx];
     165             : 
     166         279 :         size_t num_groups = ConfirmedCasesDataEntry::age_group_names.size();
     167        1953 :         for (size_t i = 0; i < num_groups; i++) {
     168             :             // subtract infected confirmed cases which are not yet recovered
     169             :             // and remove dark figure scaling factor
     170        1674 :             num_rec[i] -= num_InfectedSymptoms[i] / scaling_factor_inf[i];
     171        1674 :             num_rec[i] -= num_InfectedSevere[i] / scaling_factor_inf[i];
     172        1674 :             num_rec[i] -=
     173        3348 :                 num_icu[i] /
     174        1674 :                 scaling_factor_inf[i]; // TODO: this has to be adapted for scaling_factor_inf != 1 or != ***_icu
     175        1674 :             num_rec[i] -= num_death[i] / scaling_factor_inf[i];
     176        1674 :             auto try_fix_constraints = [region, i](double& value, double error, auto str) {
     177       11718 :                 if (value < error) {
     178             :                     // this should probably return a failure
     179             :                     // but the algorithm is not robust enough to avoid large negative
     180             :                     // values and there are tests that rely on it
     181           0 :                     log_error("{:s} for age group {:s} is {:.4f} for region {:d}, "
     182             :                               "exceeds expected negative value.",
     183           0 :                               str, ConfirmedCasesDataEntry::age_group_names[i], value, region);
     184           0 :                     value = 0.0;
     185             :                 }
     186       11718 :                 else if (value < 0) {
     187           0 :                     log_info("{:s} for age group {:s} is {:.4f} for region {:d}, "
     188             :                              "automatically corrected",
     189           0 :                              str, ConfirmedCasesDataEntry::age_group_names[i], value, region);
     190           0 :                     value = 0.0;
     191             :                 }
     192       11718 :             };
     193             : 
     194        1674 :             try_fix_constraints(num_InfectedSymptoms[i], -5, "InfectedSymptoms");
     195        1674 :             try_fix_constraints(num_InfectedNoSymptoms[i], -5, "InfectedNoSymptoms");
     196        1674 :             try_fix_constraints(num_Exposed[i], -5, "Exposed");
     197        1674 :             try_fix_constraints(num_InfectedSevere[i], -5, "InfectedSevere");
     198        1674 :             try_fix_constraints(num_death[i], -5, "Dead");
     199        1674 :             try_fix_constraints(num_icu[i], -5, "InfectedCritical");
     200        1674 :             try_fix_constraints(num_rec[i], -20, "Recovered or vaccinated");
     201             :         }
     202             :     }
     203             : 
     204         558 :     return success();
     205             : }
     206             : 
     207           0 : IOResult<void> read_confirmed_cases_data_fix_recovered(std::string const& path, std::vector<int> const& vregion,
     208             :                                                        Date date, std::vector<std::vector<double>>& vnum_rec,
     209             :                                                        double delay)
     210             : {
     211           0 :     BOOST_OUTCOME_TRY(auto&& rki_data, mio::read_confirmed_cases_data(path));
     212           0 :     return read_confirmed_cases_data_fix_recovered(rki_data, vregion, date, vnum_rec, delay);
     213           0 : }
     214             : 
     215         108 : IOResult<void> read_confirmed_cases_data_fix_recovered(const std::vector<ConfirmedCasesDataEntry>& rki_data,
     216             :                                                        std::vector<int> const& vregion, Date date,
     217             :                                                        std::vector<std::vector<double>>& vnum_rec, double delay)
     218             : {
     219         108 :     auto max_date_entry = std::max_element(rki_data.begin(), rki_data.end(), [](auto&& a, auto&& b) {
     220       59508 :         return a.date < b.date;
     221             :     });
     222         108 :     if (max_date_entry == rki_data.end()) {
     223           0 :         log_error("RKI data is empty.");
     224           0 :         return failure(StatusCode::InvalidValue, "RKI data is empty.");
     225             :     }
     226         108 :     auto max_date = max_date_entry->date;
     227         108 :     if (max_date < date) {
     228           0 :         log_error("Specified date does not exist in RKI data");
     229           0 :         return failure(StatusCode::OutOfRange, "RKI data does not contain specified date.");
     230             :     }
     231             : 
     232             :     // shifts the initilization to the recent past if simulation starts
     233             :     // around current day and data of the future would be required.
     234             :     // Only needed for preinfection compartments, exposed and InfectedNoSymptoms.
     235         108 :     auto days_surplus = get_offset_in_days(max_date, date) - 6; // 6 > T_E^C + T_C^I
     236         108 :     if (days_surplus > 0) {
     237         108 :         days_surplus = 0;
     238             :     }
     239             : 
     240       59724 :     for (auto&& rki_entry : rki_data) {
     241       79488 :         auto it = std::find_if(vregion.begin(), vregion.end(), [&rki_entry](auto r) {
     242       79488 :             return r == 0 || get_region_id(rki_entry) == r;
     243             :         });
     244       59616 :         if (it != vregion.end()) {
     245       54648 :             auto region_idx = size_t(it - vregion.begin());
     246       54648 :             if (rki_entry.date == offset_date_by_days(date, int(-delay))) {
     247         378 :                 vnum_rec[region_idx][size_t(rki_entry.age_group)] = rki_entry.num_confirmed;
     248             :             }
     249             :         }
     250             :     }
     251             : 
     252         216 :     for (size_t region_idx = 0; region_idx < vregion.size(); ++region_idx) {
     253         108 :         auto region   = vregion[region_idx];
     254         108 :         auto& num_rec = vnum_rec[region_idx];
     255             : 
     256         108 :         size_t num_groups = ConfirmedCasesDataEntry::age_group_names.size();
     257         756 :         for (size_t i = 0; i < num_groups; i++) {
     258         648 :             auto try_fix_constraints = [region, i](double& value, double error, auto str) {
     259         648 :                 if (value < error) {
     260             :                     // this should probably return a failure
     261             :                     // but the algorithm is not robust enough to avoid large negative
     262             :                     // values and there are tests that rely on it
     263           0 :                     log_error("{:s} for age group {:s} is {:.4f} for region {:d}, "
     264             :                               "exceeds expected negative value.",
     265           0 :                               str, ConfirmedCasesDataEntry::age_group_names[i], value, region);
     266           0 :                     value = 0.0;
     267             :                 }
     268         648 :                 else if (value < 0) {
     269           0 :                     log_info("{:s} for age group {:s} is {:.4f} for region {:d}, "
     270             :                              "automatically corrected",
     271           0 :                              str, ConfirmedCasesDataEntry::age_group_names[i], value, region);
     272           0 :                     value = 0.0;
     273             :                 }
     274         648 :             };
     275         648 :             try_fix_constraints(num_rec[i], 0, "Recovered");
     276             :         }
     277             :     }
     278             : 
     279         216 :     return success();
     280             : }
     281             : 
     282          63 : IOResult<void> read_divi_data(const std::string& path, const std::vector<int>& vregion, Date date,
     283             :                               std::vector<double>& vnum_icu)
     284             : {
     285          63 :     BOOST_OUTCOME_TRY(auto&& divi_data, mio::read_divi_data(path));
     286          63 :     return read_divi_data(divi_data, vregion, date, vnum_icu);
     287          63 : }
     288             : 
     289          63 : IOResult<void> read_divi_data(const std::vector<DiviEntry>& divi_data, const std::vector<int>& vregion, Date date,
     290             :                               std::vector<double>& vnum_icu)
     291             : {
     292          63 :     auto max_date_entry = std::max_element(divi_data.begin(), divi_data.end(), [](auto&& a, auto&& b) {
     293        5733 :         return a.date < b.date;
     294             :     });
     295          63 :     if (max_date_entry == divi_data.end()) {
     296           0 :         log_error("DIVI data is empty.");
     297           0 :         return failure(StatusCode::InvalidValue, "DIVI data is empty.");
     298             :     }
     299          63 :     auto max_date = max_date_entry->date;
     300          63 :     if (max_date < date) {
     301           0 :         log_error("DIVI data does not contain the specified date.");
     302           0 :         return failure(StatusCode::OutOfRange, "DIVI data does not contain the specified date.");
     303             :     }
     304             : 
     305        5859 :     for (auto&& entry : divi_data) {
     306        8280 :         auto it      = std::find_if(vregion.begin(), vregion.end(), [&entry](auto r) {
     307        8280 :             return r == 0 || r == get_region_id(entry);
     308             :         });
     309        5796 :         auto date_df = entry.date;
     310        5796 :         if (it != vregion.end() && date_df == date) {
     311          63 :             auto region_idx      = size_t(it - vregion.begin());
     312          63 :             vnum_icu[region_idx] = entry.num_icu;
     313             :         }
     314             :     }
     315             : 
     316         126 :     return success();
     317             : }
     318             : 
     319         135 : IOResult<std::vector<std::vector<double>>> read_population_data(const std::string& path,
     320             :                                                                 const std::vector<int>& vregion)
     321             : {
     322         135 :     BOOST_OUTCOME_TRY(auto&& population_data, mio::read_population_data(path));
     323         135 :     return read_population_data(population_data, vregion);
     324         135 : }
     325             : 
     326         135 : IOResult<std::vector<std::vector<double>>> read_population_data(const std::vector<PopulationDataEntry>& population_data,
     327             :                                                                 const std::vector<int>& vregion)
     328             : {
     329         135 :     std::vector<std::vector<double>> vnum_population(
     330         540 :         vregion.size(), std::vector<double>(ConfirmedCasesDataEntry::age_group_names.size(), 0.0));
     331             : 
     332       54270 :     for (auto&& county_entry : population_data) {
     333             :         //accumulate population of states or country from population of counties
     334       54135 :         if (!county_entry.county_id && !county_entry.district_id) {
     335           0 :             return failure(StatusCode::InvalidFileFormat, "File with county population expected.");
     336             :         }
     337             :         //find region that this county belongs to
     338             :         //all counties belong to the country (id = 0)
     339      191241 :         auto it = std::find_if(vregion.begin(), vregion.end(), [&county_entry](auto r) {
     340       14436 :             return r == 0 ||
     341       54135 :                    (county_entry.county_id &&
     342       97443 :                     regions::StateId(r) == regions::get_state_id(int(*county_entry.county_id))) ||
     343      187650 :                    (county_entry.county_id && regions::CountyId(r) == *county_entry.county_id) ||
     344      158742 :                    (county_entry.district_id && regions::DistrictId(r) == *county_entry.district_id);
     345             :         });
     346       54135 :         if (it != vregion.end()) {
     347       39726 :             auto region_idx      = size_t(it - vregion.begin());
     348       39726 :             auto& num_population = vnum_population[region_idx];
     349      278082 :             for (size_t age = 0; age < num_population.size(); age++) {
     350      238356 :                 num_population[age] += county_entry.population[AgeGroup(age)];
     351             :             }
     352             :         }
     353             :     }
     354             : 
     355         135 :     return success(vnum_population);
     356         135 : }
     357             : 
     358             : } // namespace details
     359             : } // namespace osecirvvs
     360             : } // namespace mio
     361             : 
     362             : #endif // MEMILIO_HAS_JSONCPP

Generated by: LCOV version 1.14