LCOV - code coverage report
Current view: top level - models/abm - model_functions.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 61 66 92.4 %
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, Elisabeth Kluth, Khoa Nguyen, David Kerkmann, Rene Schmieding
       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             : #include "abm/model_functions.h"
      22             : #include "abm/location.h"
      23             : #include "abm/person.h"
      24             : #include "abm/random_events.h"
      25             : #include "abm/infection.h"
      26             : #include "abm/virus_variant.h"
      27             : #include "memilio/epidemiology/age_group.h"
      28             : #include "memilio/utils/logging.h"
      29             : 
      30             : namespace mio
      31             : {
      32             : namespace abm
      33             : {
      34             : 
      35        1980 : ScalarType daily_transmissions_by_contacts(const ContactExposureRates& rates, const CellIndex cell_index,
      36             :                                            const VirusVariant virus, const AgeGroup age_receiver,
      37             :                                            const LocalInfectionParameters& params)
      38             : {
      39        1980 :     assert(age_receiver < rates.size<AgeGroup>());
      40        1980 :     ScalarType prob = 0;
      41       13860 :     for (AgeGroup age_transmitter(0); age_transmitter < rates.size<AgeGroup>(); ++age_transmitter) {
      42       11880 :         prob +=
      43       23760 :             rates[{cell_index, virus, age_transmitter}] * params.get<ContactRates>()[{age_receiver, age_transmitter}];
      44             :     }
      45        1980 :     return prob;
      46             : }
      47             : 
      48        1980 : ScalarType daily_transmissions_by_air(const AirExposureRates& rates, const CellIndex cell_index,
      49             :                                       const VirusVariant virus, const Parameters& global_params)
      50             : {
      51        3960 :     return rates[{cell_index, virus}] * global_params.get<AerosolTransmissionRates>()[{virus}];
      52             : }
      53             : 
      54        2817 : void interact(PersonalRandomNumberGenerator& personal_rng, Person& person, const Location& location,
      55             :               const AirExposureRates& local_air_exposure, const ContactExposureRates& local_contact_exposure,
      56             :               const TimePoint t, const TimeSpan dt, const Parameters& global_parameters)
      57             : {
      58             :     // make sure all dimensions are set correctly and all indices are valid
      59        2817 :     assert(location.get_cells().size() == local_air_exposure.size<CellIndex>().get());
      60        2817 :     assert(location.get_cells().size() == local_contact_exposure.size<CellIndex>().get());
      61        2817 :     assert(local_contact_exposure.size<VirusVariant>() == local_air_exposure.size<VirusVariant>());
      62        2817 :     assert(local_contact_exposure.size<VirusVariant>() == VirusVariant::Count);
      63        2817 :     assert(local_contact_exposure.size<AgeGroup>().get() == global_parameters.get_num_groups());
      64        2817 :     assert(person.get_age() < local_contact_exposure.size<AgeGroup>());
      65        5634 :     assert(std::all_of(person.get_cells().begin(), person.get_cells().end(), [&](const auto& cell) {
      66             :         return cell < location.get_cells().size();
      67             :     }));
      68             : 
      69        2817 :     if (person.get_infection_state(t) == InfectionState::Susceptible) {
      70        1980 :         auto& local_parameters = location.get_infection_parameters();
      71             :         // TODO: we need to define what a cell is used for, as the loop may lead to incorrect results for multiple cells
      72        1980 :         auto age_receiver          = person.get_age();
      73        1980 :         ScalarType mask_protection = person.get_mask_protective_factor(global_parameters);
      74        1980 :         assert(person.get_cells().size() && "Person is in multiple cells. Interact logic is incorrect at the moment.");
      75        3960 :         for (auto cell_index : person.get_cells()) {
      76        1980 :             std::pair<VirusVariant, ScalarType> local_indiv_trans_prob[static_cast<uint32_t>(VirusVariant::Count)];
      77        3960 :             for (uint32_t v = 0; v != static_cast<uint32_t>(VirusVariant::Count); ++v) {
      78        1980 :                 VirusVariant virus = static_cast<VirusVariant>(v);
      79        1980 :                 ScalarType local_indiv_trans_prob_v =
      80        1980 :                     (std::min(local_parameters.get<MaximumContacts>(),
      81        3960 :                               daily_transmissions_by_contacts(local_contact_exposure, cell_index, virus, age_receiver,
      82        1980 :                                                               local_parameters)) +
      83        3960 :                      daily_transmissions_by_air(local_air_exposure, cell_index, virus, global_parameters)) *
      84        3960 :                     dt.days() * (1 - mask_protection) * (1 - person.get_protection_factor(t, virus, global_parameters));
      85             : 
      86        1980 :                 local_indiv_trans_prob[v] = std::make_pair(virus, local_indiv_trans_prob_v);
      87             :             }
      88             :             VirusVariant virus =
      89        1980 :                 random_transition(personal_rng, VirusVariant::Count, dt,
      90        1980 :                                   local_indiv_trans_prob); // use VirusVariant::Count for no virus submission
      91        1980 :             if (virus != VirusVariant::Count) {
      92          54 :                 person.add_new_infection(Infection(personal_rng, virus, age_receiver, global_parameters, t + dt / 2,
      93          27 :                                                    mio::abm::InfectionState::Exposed, person.get_latest_protection(),
      94             :                                                    false)); // Starting time in first approximation
      95             :             }
      96             :         }
      97             :     }
      98        2817 :     person.add_time_at_location(dt);
      99        2817 : }
     100             : 
     101        2889 : void add_exposure_contribution(AirExposureRates& local_air_exposure, ContactExposureRates& local_contact_exposure,
     102             :                                const Person& person, const Location& location, const TimePoint t, const TimeSpan dt)
     103             : {
     104        2889 :     if (person.get_location() != location.get_id()) {
     105           0 :         mio::log_debug("In add_exposure_contribution: Person {} is not at Location {}", person.get_id().get(),
     106           0 :                        location.get_id().get());
     107             :     }
     108             : 
     109        2889 :     if (person.is_infected(t)) {
     110         846 :         auto& infection = person.get_infection();
     111         846 :         auto virus      = infection.get_virus_variant();
     112         846 :         auto age        = person.get_age();
     113             :         // average infectivity over the time step to second order accuracy using midpoint rule
     114        1692 :         for (CellIndex cell : person.get_cells()) {
     115         846 :             if (location.get_infection_parameters().get<UseLocationCapacityForTransmissions>()) {
     116           0 :                 local_air_exposure[{cell, virus}] +=
     117           0 :                     infection.get_infectivity(t + dt / 2) *
     118           0 :                     location.get_cells()[cell.get()].compute_space_per_person_relative();
     119             :             }
     120             :             else {
     121        1692 :                 local_air_exposure[{cell, virus}] += infection.get_infectivity(t + dt / 2);
     122             :             }
     123        1692 :             local_contact_exposure[{cell, virus, age}] += infection.get_infectivity(t + dt / 2);
     124             :         }
     125             :     }
     126        2889 : }
     127             : 
     128         360 : bool change_location(Person& person, const Location& destination, const TransportMode mode,
     129             :                      const std::vector<uint32_t>& cells)
     130             : {
     131         738 :     assert(std::all_of(cells.begin(), cells.end(), [&](const auto& cell) {
     132             :         return cell < destination.get_cells().size();
     133             :     })); // make sure cell indices are valid
     134             : 
     135         360 :     if (person.get_location() != destination.get_id()) {
     136         351 :         person.set_location(destination.get_type(), destination.get_id());
     137         351 :         person.get_cells() = cells;
     138         351 :         person.set_last_transport_mode(mode);
     139             : 
     140         351 :         return true;
     141             :     }
     142             :     else {
     143          18 :         mio::log_debug("In change_location: Person {} already is at Location {}", person.get_id().get(),
     144          18 :                        destination.get_id().get());
     145           9 :         return false;
     146             :     }
     147             : }
     148             : 
     149             : } // namespace abm
     150             : } // namespace mio

Generated by: LCOV version 1.14