LCOV - code coverage report
Current view: top level - models/abm - person.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 119 121 98.3 %
Date: 2024-11-18 12:45:26 Functions: 26 27 96.3 %

          Line data    Source code
       1             : /* 
       2             : * Copyright (C) 2020-2024 MEmilio
       3             : *
       4             : * Authors: Daniel Abele, Elisabeth Kluth, David Kerkmann, Khoa Nguyen
       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 "abm/person.h"
      21             : #include "abm/location_type.h"
      22             : #include "abm/mask_type.h"
      23             : #include "abm/parameters.h"
      24             : #include "abm/infection.h"
      25             : #include "abm/location.h"
      26             : #include "memilio/utils/random_number_generator.h"
      27             : #include <vector>
      28             : 
      29             : namespace mio
      30             : {
      31             : namespace abm
      32             : {
      33             : 
      34        1935 : Person::Person(mio::RandomNumberGenerator& rng, LocationType location_type, LocationId location_id, AgeGroup age,
      35        1935 :                PersonId person_id)
      36        1935 :     : m_location(location_id)
      37        1935 :     , m_location_type(location_type)
      38        1935 :     , m_assigned_locations((uint32_t)LocationType::Count, LocationId::invalid_id())
      39        1935 :     , m_home_isolation_start(TimePoint(-(std::numeric_limits<int>::max() / 2)))
      40        1935 :     , m_age(age)
      41        1935 :     , m_time_at_location(0)
      42        1935 :     , m_mask(Mask(MaskType::None, TimePoint(-(std::numeric_limits<int>::max() / 2))))
      43        1935 :     , m_compliance((uint32_t)InterventionType::Count, 1.)
      44        1935 :     , m_person_id(person_id)
      45        1935 :     , m_cells{0}
      46        1935 :     , m_last_transport_mode(TransportMode::Unknown)
      47        3870 :     , m_test_results({TestType::Count}, TestResult())
      48             : {
      49        1935 :     m_random_workgroup        = UniformDistribution<double>::get_instance()(rng);
      50        1935 :     m_random_schoolgroup      = UniformDistribution<double>::get_instance()(rng);
      51        1935 :     m_random_goto_work_hour   = UniformDistribution<double>::get_instance()(rng);
      52        1935 :     m_random_goto_school_hour = UniformDistribution<double>::get_instance()(rng);
      53        1935 : }
      54             : 
      55        1305 : Person::Person(const Person& other, PersonId id)
      56        1305 :     : Person(other)
      57             : {
      58        1305 :     m_person_id = id;
      59        1305 : }
      60             : 
      61        3051 : bool Person::is_infected(TimePoint t) const
      62             : {
      63        3051 :     if (m_infections.empty()) {
      64        2016 :         return false;
      65             :     }
      66             :     // subject to change if Recovered is removed
      67        4140 :     if (m_infections.back().get_infection_state(t) == InfectionState::Susceptible ||
      68        3105 :         m_infections.back().get_infection_state(t) == InfectionState::Recovered) {
      69          81 :         return false;
      70             :     }
      71         954 :     return true;
      72             : }
      73             : 
      74       29115 : InfectionState Person::get_infection_state(TimePoint t) const
      75             : {
      76       29115 :     if (m_infections.empty()) {
      77       18855 :         return InfectionState::Susceptible;
      78             :     }
      79             :     else {
      80       10260 :         return m_infections.back().get_infection_state(t);
      81             :     }
      82             : }
      83             : 
      84         441 : void Person::add_new_infection(Infection&& inf)
      85             : {
      86         441 :     m_infections.push_back(std::move(inf));
      87         441 : }
      88             : 
      89      124218 : LocationId Person::get_location() const
      90             : {
      91      124218 :     return m_location;
      92             : }
      93             : 
      94         351 : void Person::set_location(LocationType type, LocationId id)
      95             : {
      96         351 :     m_location         = id;
      97         351 :     m_location_type    = type;
      98         351 :     m_time_at_location = TimeSpan(0);
      99         351 : }
     100             : 
     101         846 : const Infection& Person::get_infection() const
     102             : {
     103         846 :     return m_infections.back();
     104             : }
     105             : 
     106           0 : Infection& Person::get_infection()
     107             : {
     108           0 :     return m_infections.back();
     109             : }
     110             : 
     111        3096 : void Person::set_assigned_location(LocationType type, LocationId id)
     112             : {
     113        3096 :     m_assigned_locations[static_cast<uint32_t>(type)] = id;
     114        3096 : }
     115             : 
     116        8928 : LocationId Person::get_assigned_location(LocationType type) const
     117             : {
     118        8928 :     return m_assigned_locations[static_cast<uint32_t>(type)];
     119             : }
     120             : 
     121          99 : bool Person::goes_to_work(TimePoint t, const Parameters& params) const
     122             : {
     123          99 :     return m_random_workgroup < params.get<WorkRatio>().get_matrix_at(t.days())[0];
     124             : }
     125             : 
     126         306 : TimeSpan Person::get_go_to_work_time(const Parameters& params) const
     127             : {
     128         306 :     TimeSpan minimum_goto_work_time = params.get<GotoWorkTimeMinimum>()[m_age];
     129         306 :     TimeSpan maximum_goto_work_time = params.get<GotoWorkTimeMaximum>()[m_age];
     130         306 :     int timeSlots                   = (maximum_goto_work_time.seconds() - minimum_goto_work_time.seconds());
     131         306 :     int seconds_after_minimum       = int(timeSlots * m_random_goto_work_hour);
     132         612 :     return minimum_goto_work_time + seconds(seconds_after_minimum);
     133             : }
     134             : 
     135         855 : TimeSpan Person::get_go_to_school_time(const Parameters& params) const
     136             : {
     137         855 :     TimeSpan minimum_goto_school_time = params.get<GotoSchoolTimeMinimum>()[m_age];
     138         855 :     TimeSpan maximum_goto_school_time = params.get<GotoSchoolTimeMaximum>()[m_age];
     139         855 :     int timeSlots                     = (maximum_goto_school_time.seconds() - minimum_goto_school_time.seconds());
     140         855 :     int seconds_after_minimum         = int(timeSlots * m_random_goto_school_hour);
     141        1710 :     return minimum_goto_school_time + seconds(seconds_after_minimum);
     142             : }
     143             : 
     144          90 : bool Person::goes_to_school(TimePoint t, const Parameters& params) const
     145             : {
     146          90 :     return m_random_schoolgroup < params.get<SchoolRatio>().get_matrix_at(t.days())[0];
     147             : }
     148             : 
     149          18 : void Person::remove_quarantine()
     150             : {
     151          18 :     m_home_isolation_start = TimePoint(-(std::numeric_limits<int>::max() / 2));
     152          18 : }
     153             : 
     154         162 : bool Person::get_tested(PersonalRandomNumberGenerator& rng, TimePoint t, const TestParameters& params)
     155             : {
     156         162 :     ScalarType random = UniformDistribution<double>::get_instance()(rng);
     157         162 :     if (is_infected(t)) {
     158             :         // true positive
     159         108 :         if (random < params.sensitivity) {
     160             :             // If the Person complies to isolation, start the quarantine.
     161          90 :             if (is_compliant(rng, InterventionType::Isolation)) {
     162          72 :                 m_home_isolation_start = t;
     163             :             }
     164          90 :             m_infections.back().set_detected();
     165          90 :             return true;
     166             :         }
     167             :         // false negative
     168             :         else {
     169          18 :             return false;
     170             :         }
     171             :     }
     172             :     else {
     173             :         // true negative
     174          54 :         if (random < params.specificity) {
     175          36 :             return false;
     176             :         }
     177             :         // false positive
     178             :         else {
     179             :             // If the Person complies to isolation, start the quarantine.
     180          18 :             if (is_compliant(rng, InterventionType::Isolation)) {
     181          18 :                 m_home_isolation_start = t;
     182             :             }
     183          18 :             return true;
     184             :         }
     185             :     }
     186             : }
     187             : 
     188       11169 : PersonId Person::get_id() const
     189             : {
     190       11169 :     return m_person_id;
     191             : }
     192             : 
     193        9999 : std::vector<uint32_t>& Person::get_cells()
     194             : {
     195        9999 :     return m_cells;
     196             : }
     197             : 
     198         846 : const std::vector<uint32_t>& Person::get_cells() const
     199             : {
     200         846 :     return m_cells;
     201             : }
     202             : 
     203        2016 : ScalarType Person::get_mask_protective_factor(const Parameters& params) const
     204             : {
     205        2016 :     return params.get<MaskProtection>()[m_mask.get_type()];
     206             : }
     207             : 
     208         666 : bool Person::is_compliant(PersonalRandomNumberGenerator& rng, InterventionType intervention) const
     209             : {
     210         666 :     ScalarType compliance_check = UniformDistribution<double>::get_instance()(rng);
     211         666 :     return compliance_check <= get_compliance(intervention);
     212             : }
     213             : 
     214        2070 : ProtectionEvent Person::get_latest_protection() const
     215             : {
     216        2070 :     ProtectionType latest_protection_type = ProtectionType::NoProtection;
     217        2070 :     TimePoint infection_time          = TimePoint(0);
     218        2070 :     if (!m_infections.empty()) {
     219           9 :         latest_protection_type = ProtectionType::NaturalInfection;
     220           9 :         infection_time       = m_infections.back().get_start_date();
     221             :     }
     222        2070 :     if (!m_vaccinations.empty() && infection_time.days() <= m_vaccinations.back().time.days()) {
     223          54 :         latest_protection_type = m_vaccinations.back().type;
     224          54 :         infection_time       = m_vaccinations.back().time;
     225             :     }
     226        4140 :     return ProtectionEvent{latest_protection_type, infection_time};
     227             : }
     228             : 
     229        2016 : ScalarType Person::get_protection_factor(TimePoint t, VirusVariant virus, const Parameters& params) const
     230             : {
     231        2016 :     auto latest_protection = get_latest_protection();
     232             :     // If there is no previous protection or vaccination, return 0.
     233        2016 :     if (latest_protection.type == ProtectionType::NoProtection) {
     234        1980 :         return 0;
     235             :     }
     236         108 :     return params.get<InfectionProtectionFactor>()[{latest_protection.type, m_age, virus}](
     237          72 :         t.days() - latest_protection.time.days());
     238             : }
     239             : 
     240         360 : void Person::set_mask(MaskType type, TimePoint t)
     241             : {
     242         360 :     m_mask.change_mask(type, t);
     243         360 : } 
     244             : 
     245          72 : void Person::add_test_result(TimePoint t, TestType type, bool result)
     246             : {
     247             :     // Remove outdated test results or replace the old result of the same type
     248          72 :     m_test_results[{type}] = {t, result};
     249          72 : }
     250             : 
     251         171 : TestResult Person::get_test_result(TestType type) const
     252             : {
     253         171 :     return m_test_results[{type}];
     254             : }
     255             : 
     256             : } // namespace abm
     257             : } // namespace mio

Generated by: LCOV version 1.14