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

          Line data    Source code
       1             : /* 
       2             : * Copyright (C) 2020-2024 MEmilio
       3             : *
       4             : * Authors: Daniel Abele, Martin J. Kuehn
       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 ODESECIR_PARAMETER_SPACE_H
      21             : #define ODESECIR_PARAMETER_SPACE_H
      22             : 
      23             : #include "memilio/mobility/metapopulation_mobility_instant.h"
      24             : #include "memilio/utils/memory.h"
      25             : #include "memilio/utils/logging.h"
      26             : #include "memilio/utils/parameter_distributions.h"
      27             : #include "ode_secir/model.h"
      28             : 
      29             : #include <assert.h>
      30             : #include <string>
      31             : #include <vector>
      32             : #include <random>
      33             : #include <memory>
      34             : 
      35             : namespace mio
      36             : {
      37             : namespace osecir
      38             : {
      39             : /** Sets alls SecirParams parameters normally distributed, 
      40             :  *  using the current value and a given standard deviation
      41             :  * @param[inout] params SecirParams including contact patterns for alle age groups
      42             :  * @param[in] t0 start time
      43             :  * @param[in] tmax end time
      44             :  * @param[in] dev_rel maximum relative deviation from particular value(s) given in params
      45             :  */
      46             : template <typename FP = double>
      47          41 : void set_params_distributions_normal(Model<FP>& model, double t0, double tmax, double dev_rel)
      48             : {
      49        6137 :     auto set_distribution = [dev_rel](UncertainValue<FP>& v, double min_val = 0.001) {
      50       10160 :         v.set_distribution(ParameterDistributionNormal(
      51             :             //add add limits for nonsense big values. Also mscv has a problem with a few doubles so this fixes it
      52        6096 :             std::min(std::max(min_val, (1 - dev_rel * 2.6) * v), 0.1 * std::numeric_limits<double>::max()),
      53        6096 :             std::min(std::max(min_val, (1 + dev_rel * 2.6) * v), 0.5 * std::numeric_limits<double>::max()),
      54        4064 :             std::min(std::max(min_val, double(v)), 0.3 * std::numeric_limits<double>::max()),
      55        4064 :             std::min(std::max(min_val, dev_rel * v), std::numeric_limits<double>::max())));
      56             :     };
      57             : 
      58          41 :     set_distribution(model.parameters.template get<Seasonality<FP>>(), 0.0);
      59          41 :     set_distribution(model.parameters.template get<ICUCapacity<FP>>());
      60          41 :     set_distribution(model.parameters.template get<TestAndTraceCapacity<FP>>());
      61          41 :     set_distribution(model.parameters.template get<DynamicNPIsImplementationDelay<FP>>());
      62             : 
      63             :     // populations
      64         128 :     for (auto i = AgeGroup(0); i < model.parameters.get_num_groups(); i++) {
      65         957 :         for (auto j = Index<InfectionState>(0); j < Index<InfectionState>(InfectionState::Count); j++) {
      66             : 
      67             :             // don't touch S and D
      68         870 :             if (j == InfectionState::Susceptible || j == InfectionState::Dead) {
      69         174 :                 continue;
      70             :             }
      71             : 
      72             :             // variably sized groups
      73         696 :             set_distribution(model.populations[{i, j}], 0.0);
      74             :         }
      75             :     }
      76             : 
      77             :     // times
      78         128 :     for (auto i = AgeGroup(0); i < model.parameters.get_num_groups(); i++) {
      79             : 
      80          87 :         set_distribution(model.parameters.template get<TimeExposed<FP>>()[i]);
      81          87 :         set_distribution(model.parameters.template get<TimeInfectedNoSymptoms<FP>>()[i]);
      82          87 :         set_distribution(model.parameters.template get<TimeInfectedSymptoms<FP>>()[i]);
      83          87 :         set_distribution(model.parameters.template get<TimeInfectedSevere<FP>>()[i]);
      84          87 :         set_distribution(model.parameters.template get<TimeInfectedCritical<FP>>()[i]);
      85             : 
      86          87 :         set_distribution(model.parameters.template get<TransmissionProbabilityOnContact<FP>>()[i]);
      87          87 :         set_distribution(model.parameters.template get<RelativeTransmissionNoSymptoms<FP>>()[i]);
      88          87 :         set_distribution(model.parameters.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i]);
      89          87 :         set_distribution(model.parameters.template get<RiskOfInfectionFromSymptomatic<FP>>()[i]);
      90          87 :         set_distribution(model.parameters.template get<MaxRiskOfInfectionFromSymptomatic<FP>>()[i]);
      91          87 :         set_distribution(model.parameters.template get<DeathsPerCritical<FP>>()[i]);
      92          87 :         set_distribution(model.parameters.template get<SeverePerInfectedSymptoms<FP>>()[i]);
      93          87 :         set_distribution(model.parameters.template get<CriticalPerSevere<FP>>()[i]);
      94             :     }
      95             : 
      96             :     // dampings
      97          41 :     auto matrices = std::vector<size_t>();
      98          82 :     for (size_t i = 0; i < model.parameters.template get<ContactPatterns<FP>>().get_cont_freq_mat().get_num_matrices();
      99             :          ++i) {
     100          41 :         matrices.push_back(i);
     101             :     }
     102          41 :     auto groups = Eigen::VectorXd::Constant(Eigen::Index(model.parameters.get_num_groups().get()), 1.0);
     103          82 :     model.parameters.template get<ContactPatterns<FP>>().get_dampings().emplace_back(
     104          82 :         mio::UncertainValue(0.5), mio::DampingLevel(0), mio::DampingType(0), mio::SimulationTime(t0 + (tmax - t0) / 2),
     105             :         matrices, groups);
     106          41 :     set_distribution(model.parameters.template get<ContactPatterns<FP>>().get_dampings()[0].get_value(), 0.0);
     107          82 : }
     108             : 
     109             : /**
     110             :  * draws a sample from the specified distributions for all parameters related to the demographics, e.g. population.
     111             :  * @param[inout] model Model including contact patterns for alle age groups
     112             :  */
     113             : template <typename FP = double>
     114         138 : void draw_sample_demographics(Model<FP>& model)
     115             : {
     116         138 :     model.parameters.template get<ICUCapacity<FP>>().draw_sample();
     117         138 :     model.parameters.template get<TestAndTraceCapacity<FP>>().draw_sample();
     118             : 
     119         354 :     for (auto i = AgeGroup(0); i < model.parameters.get_num_groups(); i++) {
     120         216 :         double group_total = model.populations.get_group_total(i);
     121             : 
     122         216 :         model.populations[{i, InfectionState::Exposed}].draw_sample();
     123         216 :         model.populations[{i, InfectionState::InfectedNoSymptoms}].draw_sample();
     124         216 :         model.populations[{i, InfectionState::InfectedSymptoms}].draw_sample();
     125         216 :         model.populations[{i, InfectionState::InfectedSevere}].draw_sample();
     126         216 :         model.populations[{i, InfectionState::InfectedCritical}].draw_sample();
     127         216 :         model.populations[{i, InfectionState::Recovered}].draw_sample();
     128             : 
     129             :         // no sampling for dead and total numbers
     130             :         // [...]
     131             : 
     132         216 :         model.populations.template set_difference_from_group_total<AgeGroup>({i, InfectionState::Susceptible},
     133             :                                                                              group_total);
     134         432 :         model.populations.template set_difference_from_group_total<AgeGroup>({i, InfectionState::Susceptible},
     135         216 :                                                                              model.populations.get_group_total(i));
     136             :     }
     137         138 : }
     138             : 
     139             : /**
     140             :  * draws a sample from the specified distributions for all parameters related to the infection.
     141             :  * @param[inout] model Model including contact patterns for alle age groups
     142             :  */
     143             : template <typename FP = double>
     144         123 : void draw_sample_infection(Model<FP>& model)
     145             : {
     146         123 :     model.parameters.template get<Seasonality<FP>>().draw_sample();
     147             : 
     148             :     //not age dependent
     149         123 :     model.parameters.template get<TimeExposed<FP>>()[AgeGroup(0)].draw_sample();
     150         123 :     model.parameters.template get<TimeInfectedNoSymptoms<FP>>()[AgeGroup(0)].draw_sample();
     151         123 :     model.parameters.template get<TimeInfectedSymptoms<FP>>()[AgeGroup(0)].draw_sample();
     152         123 :     model.parameters.template get<RelativeTransmissionNoSymptoms<FP>>()[AgeGroup(0)].draw_sample();
     153         123 :     model.parameters.template get<RiskOfInfectionFromSymptomatic<FP>>()[AgeGroup(0)].draw_sample();
     154         123 :     model.parameters.template get<MaxRiskOfInfectionFromSymptomatic<FP>>()[AgeGroup(0)].draw_sample();
     155             : 
     156         294 :     for (auto i = AgeGroup(0); i < model.parameters.get_num_groups(); i++) {
     157             :         //not age dependent
     158         171 :         model.parameters.template get<TimeExposed<FP>>()[i] =
     159         342 :             model.parameters.template get<TimeExposed<FP>>()[AgeGroup(0)];
     160         171 :         model.parameters.template get<TimeInfectedNoSymptoms<FP>>()[i] =
     161         342 :             model.parameters.template get<TimeInfectedNoSymptoms<FP>>()[AgeGroup(0)];
     162         171 :         model.parameters.template get<RelativeTransmissionNoSymptoms<FP>>()[i] =
     163         342 :             model.parameters.template get<RelativeTransmissionNoSymptoms<FP>>()[AgeGroup(0)];
     164         171 :         model.parameters.template get<RiskOfInfectionFromSymptomatic<FP>>()[i] =
     165         342 :             model.parameters.template get<RiskOfInfectionFromSymptomatic<FP>>()[AgeGroup(0)];
     166         171 :         model.parameters.template get<MaxRiskOfInfectionFromSymptomatic<FP>>()[i] =
     167         342 :             model.parameters.template get<MaxRiskOfInfectionFromSymptomatic<FP>>()[AgeGroup(0)];
     168             : 
     169             :         //age dependent
     170         171 :         model.parameters.template get<TimeInfectedSymptoms<FP>>()[i].draw_sample();
     171         171 :         model.parameters.template get<TimeInfectedSevere<FP>>()[i].draw_sample();
     172         171 :         model.parameters.template get<TimeInfectedCritical<FP>>()[i].draw_sample();
     173             : 
     174         171 :         model.parameters.template get<TransmissionProbabilityOnContact<FP>>()[i].draw_sample();
     175         171 :         model.parameters.template get<RecoveredPerInfectedNoSymptoms<FP>>()[i].draw_sample();
     176         171 :         model.parameters.template get<DeathsPerCritical<FP>>()[i].draw_sample();
     177         171 :         model.parameters.template get<SeverePerInfectedSymptoms<FP>>()[i].draw_sample();
     178         171 :         model.parameters.template get<CriticalPerSevere<FP>>()[i].draw_sample();
     179             :     }
     180         123 : }
     181             : 
     182             : /** Draws a sample from Model parameter distributions and stores sample values
     183             :  * as SecirParams parameter values (cf. UncertainValue and SecirParams classes).
     184             :  * @param[inout] model Model including contact patterns for alle age groups.
     185             :  */
     186             : template <typename FP = double>
     187          99 : void draw_sample(Model<FP>& model)
     188             : {
     189          99 :     draw_sample_infection(model);
     190          99 :     draw_sample_demographics(model);
     191          99 :     model.parameters.template get<ContactPatterns<FP>>().draw_sample();
     192          99 :     model.apply_constraints();
     193          99 : }
     194             : 
     195             : template <typename FP = double>
     196          24 : Graph<Model<FP>, MobilityParameters<FP>> draw_sample(Graph<Model<FP>, MobilityParameters<FP>>& graph)
     197             : {
     198          24 :     Graph<Model<FP>, MobilityParameters<FP>> sampled_graph;
     199             : 
     200             :     //sample global parameters
     201          24 :     auto& shared_params_model = graph.nodes()[0].property;
     202          24 :     draw_sample_infection(shared_params_model);
     203          24 :     auto& shared_contacts = shared_params_model.parameters.template get<ContactPatterns<FP>>();
     204          24 :     shared_contacts.draw_sample_dampings();
     205          24 :     auto& shared_dynamic_npis = shared_params_model.parameters.template get<DynamicNPIsInfectedSymptoms<FP>>();
     206          24 :     shared_dynamic_npis.draw_sample();
     207          24 :     auto& shared_dynamic_npis_delay = shared_params_model.parameters.template get<DynamicNPIsImplementationDelay<FP>>();
     208          24 :     shared_dynamic_npis_delay.draw_sample();
     209             : 
     210         102 :     for (auto& params_node : graph.nodes()) {
     211          39 :         auto& node_model = params_node.property;
     212             : 
     213             :         //sample local parameters
     214          39 :         draw_sample_demographics(params_node.property);
     215             : 
     216             :         //copy global parameters
     217             :         //save demographic parameters so they aren't overwritten
     218          39 :         auto local_icu_capacity = node_model.parameters.template get<ICUCapacity<FP>>();
     219          39 :         auto local_tnt_capacity = node_model.parameters.template get<TestAndTraceCapacity<FP>>();
     220          39 :         auto local_holidays     = node_model.parameters.template get<ContactPatterns<FP>>().get_school_holidays();
     221          39 :         node_model.parameters   = shared_params_model.parameters;
     222          39 :         node_model.parameters.template get<ICUCapacity<FP>>()                           = local_icu_capacity;
     223          39 :         node_model.parameters.template get<TestAndTraceCapacity<FP>>()                  = local_tnt_capacity;
     224          39 :         node_model.parameters.template get<ContactPatterns<FP>>().get_school_holidays() = local_holidays;
     225             : 
     226          39 :         node_model.parameters.template get<ContactPatterns<FP>>().make_matrix();
     227          39 :         node_model.apply_constraints();
     228             : 
     229          39 :         sampled_graph.add_node(params_node.id, node_model);
     230             :     }
     231             : 
     232          54 :     for (auto& edge : graph.edges()) {
     233          15 :         auto edge_params = edge.property;
     234          45 :         apply_dampings(edge_params.get_coefficients(), shared_contacts.get_dampings(), [&edge_params](auto& v) {
     235          30 :             return make_mobility_damping_vector(edge_params.get_coefficients().get_shape(), v);
     236             :         });
     237          15 :         edge_params.set_dynamic_npis_infected(shared_dynamic_npis);
     238          15 :         sampled_graph.add_edge(edge.start_node_idx, edge.end_node_idx, edge_params);
     239             :     }
     240             : 
     241          48 :     return sampled_graph;
     242          24 : }
     243             : 
     244             : } // namespace osecir
     245             : } // namespace mio
     246             : 
     247             : #endif // ODESECIR_PARAMETER_SPACE_H

Generated by: LCOV version 1.14