LCOV - code coverage report
Current view: top level - models/abm - person.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 128 130 98.5 %
Date: 2025-02-17 13:46:44 Functions: 27 28 96.4 %

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

Generated by: LCOV version 1.14