LCOV - code coverage report
Current view: top level - models/graph_abm - graph_abmodel.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 83 86 96.5 %
Date: 2025-02-17 13:46:44 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             : * Copyright (C) 2020-2024 MEmilio
       3             : *
       4             : * Authors: Julia Bicker
       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             : #ifndef MIO_ABM_GRAPH_ABMODEL_H
      22             : #define MIO_ABM_GRAPH_ABMODEL_H
      23             : 
      24             : #include "abm/location_type.h"
      25             : #include "abm/model.h"
      26             : #include "abm/person_id.h"
      27             : #include "abm/time.h"
      28             : #include "abm/location_id.h"
      29             : #include "memilio/utils/compiler_diagnostics.h"
      30             : #include "memilio/utils/logging.h"
      31             : #include "memilio/utils/mioomp.h"
      32             : #include "abm/mobility_rules.h"
      33             : #include "abm/mobility_rules.h"
      34             : #include <cstddef>
      35             : #include <cstdint>
      36             : #include <list>
      37             : #include <vector>
      38             : 
      39             : namespace mio
      40             : {
      41             : using namespace abm;
      42             : class GraphABModel : public abm::Model
      43             : {
      44             :     using Base = Model;
      45             : 
      46             : public:
      47           8 :     GraphABModel(size_t num_agegroups, int id,
      48             :                  std::vector<Base::MobilityRuleType> mobility_rules =
      49             :                      std::vector<Base::MobilityRuleType>{&get_buried, &return_home_when_recovered, &go_to_hospital,
      50             :                                                          &go_to_icu, &go_to_school, &go_to_work, &go_to_shop,
      51             :                                                          &go_to_event, &go_to_quarantine})
      52           8 :         : Base(num_agegroups, id)
      53             :     {
      54           8 :         Base::m_mobility_rules = mobility_rules;
      55           8 :     }
      56             : 
      57             :     /**
      58             :      * @brief Get person buffer. 
      59             :      */
      60          25 :     std::vector<size_t>& get_person_buffer()
      61             :     {
      62          25 :         return m_person_buffer;
      63             :     }
      64             : 
      65             :     /** 
      66             :     * @brief Removes person from the model.
      67             :     * @param[in] pos Index of person in m_persons vector.
      68             :     */
      69           4 :     void remove_person(size_t pos)
      70             :     {
      71           4 :         Base::m_persons.erase(Base::m_persons.begin() + pos);
      72           4 :         Base::m_activeness_statuses.erase(Base::m_activeness_statuses.begin() + pos);
      73           4 :         Base::m_person_ids_equal_index = false;
      74           4 :     }
      75             : 
      76             :     /** 
      77             :      * @brief Evolve the Graph Model one time step.
      78             :      * @param[in] t Current time.
      79             :      * @param[in] dt Length of the time step.
      80             :      */
      81         289 :     void evolve(TimePoint t, TimeSpan dt)
      82             :     {
      83         289 :         Base::begin_step(t, dt);
      84         289 :         log_info("Graph ABM Model interaction.");
      85         289 :         Base::interaction(t, dt);
      86         289 :         log_info("Graph ABM Model mobility.");
      87         289 :         perform_mobility(t, dt);
      88         289 :     }
      89             : 
      90             : private:
      91         289 :     void perform_mobility(TimePoint t, TimeSpan dt)
      92             :     {
      93         289 :         const uint32_t num_persons = static_cast<uint32_t>(Base::m_persons.size());
      94         365 :         for (uint32_t person_index = 0; person_index < num_persons; ++person_index) {
      95          76 :             if (Base::m_activeness_statuses[person_index]) {
      96          63 :                 Person& person    = Base::m_persons[person_index];
      97          63 :                 auto personal_rng = PersonalRandomNumberGenerator(person);
      98             : 
      99          63 :                 auto try_mobility_rule = [&](auto rule) -> bool {
     100             :                     //run mobility rule and check if change of location can actually happen
     101        1146 :                     auto target_type = rule(personal_rng, person, t, dt, parameters);
     102         372 :                     if (person.get_assigned_location_model_id(target_type) == Base::m_id) {
     103         484 :                         const Location& target_location = Base::get_location(Base::find_location(target_type, person));
     104         363 :                         const LocationId current_location = person.get_location();
     105             :                         // the Person cannot move if they do not wear mask as required at targeted location
     106         123 :                         if (target_location.is_mask_required() &&
     107           4 :                             !person.is_compliant(personal_rng, InterventionType::Mask)) {
     108           1 :                             return false;
     109             :                         }
     110             :                         // the Person cannot move if the capacity of targeted Location is reached
     111         122 :                         if (target_location.get_id() == current_location ||
     112           2 :                             get_number_persons(target_location.get_id()) >= target_location.get_capacity().persons) {
     113         118 :                             return false;
     114             :                         }
     115             :                         // the Person cannot move if the performed TestingStrategy is positive
     116           8 :                         if (!m_testing_strategy.run_strategy(personal_rng, person, target_location, t)) {
     117           0 :                             return false;
     118             :                         }
     119             :                         // update worn mask to target location's requirements
     120           2 :                         if (target_location.is_mask_required()) {
     121             :                             // if the current MaskProtection level is lower than required, the Person changes mask
     122           5 :                             if (parameters.get<MaskProtection>()[person.get_mask().get_type()] <
     123           2 :                                 parameters.get<MaskProtection>()[target_location.get_required_mask()]) {
     124           4 :                                 person.set_mask(target_location.get_required_mask(), t);
     125             :                             }
     126             :                         }
     127             :                         else {
     128           4 :                             person.set_mask(MaskType::None, t);
     129             :                         }
     130           4 :                         Base::change_location(person, target_location.get_id());
     131           2 :                         return true;
     132             :                     }
     133             :                     else { //person moves to other world
     134           9 :                         Base::m_activeness_statuses[person_index] = false;
     135           6 :                         person.set_location(target_type, abm::LocationId::invalid_id(),
     136             :                                             std::numeric_limits<int>::max());
     137           6 :                         m_person_buffer.push_back(person_index);
     138           3 :                         m_are_exposure_caches_valid       = false;
     139           3 :                         m_is_local_population_cache_valid = false;
     140           3 :                         return true;
     141             :                     }
     142          63 :                 };
     143             : 
     144         182 :                 for (auto rule : Base::m_mobility_rules) {
     145         124 :                     bool applied = try_mobility_rule(rule);
     146             :                     //only use one mobility rule per person
     147         124 :                     if (applied) {
     148           5 :                         break;
     149             :                     }
     150             :                 }
     151             :             }
     152             :         }
     153             : 
     154             :         // check if a person makes a trip
     155         289 :         bool weekend     = t.is_weekend();
     156         289 :         size_t num_trips = Base::m_trip_list.num_trips(weekend);
     157             : 
     158         598 :         for (; Base::m_trip_list.get_current_index() < num_trips &&
     159         317 :                Base::m_trip_list.get_next_trip_time(weekend).seconds() < (t + dt).time_since_midnight().seconds();
     160           4 :              Base::m_trip_list.increase_index()) {
     161           4 :             auto& trip        = Base::m_trip_list.get_next_trip(weekend);
     162           4 :             auto& person      = get_person(trip.person_id);
     163           4 :             auto person_index = Base::get_person_index(trip.person_id);
     164           4 :             auto personal_rng = PersonalRandomNumberGenerator(person);
     165             :             // skip the trip if the person is in quarantine or is dead
     166           4 :             if (person.is_in_quarantine(t, parameters) || person.get_infection_state(t) == InfectionState::Dead) {
     167           0 :                 continue;
     168             :             }
     169           4 :             if (trip.destination_model_id == Base::m_id) {
     170           3 :                 auto& target_location = get_location(trip.destination);
     171             :                 // skip the trip if the Person wears mask as required at targeted location
     172           3 :                 if (target_location.is_mask_required() && !person.is_compliant(personal_rng, InterventionType::Mask)) {
     173           1 :                     continue;
     174             :                 }
     175             :                 // skip the trip if the performed TestingStrategy is positive
     176           2 :                 if (!Base::m_testing_strategy.run_strategy(personal_rng, person, target_location, t)) {
     177           0 :                     continue;
     178             :                 }
     179             :                 // all requirements are met, move to target location
     180           2 :                 change_location(person, target_location.get_id(), trip.trip_mode);
     181             :                 // update worn mask to target location's requirements
     182           2 :                 if (target_location.is_mask_required()) {
     183             :                     // if the current MaskProtection level is lower than required, the Person changes mask
     184           4 :                     if (parameters.get<MaskProtection>()[person.get_mask().get_type()] <
     185           3 :                         parameters.get<MaskProtection>()[target_location.get_required_mask()]) {
     186           1 :                         person.set_mask(target_location.get_required_mask(), t);
     187             :                     }
     188             :                 }
     189             :                 else {
     190           1 :                     person.set_mask(MaskType::None, t);
     191             :                 }
     192             :             }
     193             :             else { //person moves to other world
     194           1 :                 Base::m_activeness_statuses[person_index] = false;
     195           1 :                 person.set_location(trip.destination_type, abm::LocationId::invalid_id(),
     196             :                                     std::numeric_limits<int>::max());
     197           1 :                 m_person_buffer.push_back(person_index);
     198           1 :                 m_are_exposure_caches_valid       = false;
     199           1 :                 m_is_local_population_cache_valid = false;
     200             :             }
     201             :         }
     202         289 :         if (((t).days() < std::floor((t + dt).days()))) {
     203          11 :             Base::m_trip_list.reset_index();
     204             :         }
     205         289 :     }
     206             : 
     207             :     std::vector<size_t> m_person_buffer; ///< List with indices of persons that are subject to move to another node.
     208             : };
     209             : } // namespace mio
     210             : 
     211             : #endif //MIO_ABM_GRAPH_ABMODEL_H

Generated by: LCOV version 1.14