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