Line data Source code
1 : /*
2 : * Copyright (C) 2020-2025 MEmilio
3 : *
4 : * Authors: Daniel Abele, Majid Abedi, Elisabeth Kluth, David Kerkmann, Sascha Korf, Martin J. Kuehn, 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 : #ifndef MIO_ABM_MODEL_H
21 : #define MIO_ABM_MODEL_H
22 :
23 : #include "abm/model_functions.h"
24 : #include "abm/location_type.h"
25 : #include "abm/mobility_data.h"
26 : #include "abm/parameters.h"
27 : #include "abm/location.h"
28 : #include "abm/person.h"
29 : #include "abm/person_id.h"
30 : #include "abm/time.h"
31 : #include "abm/trip_list.h"
32 : #include "abm/random_events.h"
33 : #include "abm/testing_strategy.h"
34 : #include "memilio/epidemiology/age_group.h"
35 : #include "memilio/utils/logging.h"
36 : #include "memilio/utils/random_number_generator.h"
37 : #include "memilio/utils/stl_util.h"
38 :
39 : #include <bitset>
40 : #include <cstdint>
41 : #include <vector>
42 :
43 : namespace mio
44 : {
45 : namespace abm
46 : {
47 :
48 : /**
49 : * @brief The Model of the Simulation.
50 : * It consists of Location%s and Person%s (Agents).
51 : */
52 : class Model
53 : {
54 : public:
55 : using LocationIterator = std::vector<Location>::iterator;
56 : using ConstLocationIterator = std::vector<Location>::const_iterator;
57 : using PersonIterator = std::vector<Person>::iterator;
58 : using ConstPersonIterator = std::vector<Person>::const_iterator;
59 : using ActivenessIterator = std::vector<bool>::iterator;
60 : using ConstActivenessIterator = std::vector<bool>::const_iterator;
61 : using MobilityRuleType = LocationType (*)(PersonalRandomNumberGenerator&, const Person&, TimePoint, TimeSpan,
62 : const Parameters&);
63 :
64 : /**
65 : * @brief Create a Model.
66 : * @param[in] num_agegroups The number of AgeGroup%s in the simulated Model. Must be less than MAX_NUM_AGE_GROUPS.
67 : */
68 216 : Model(size_t num_agegroups, int id = 0)
69 216 : : parameters(num_agegroups)
70 216 : , m_id(id)
71 216 : , m_trip_list()
72 216 : , m_use_mobility_rules(true)
73 216 : , m_cemetery_id(add_location(LocationType::Cemetery))
74 864 : , m_person_ids_equal_index(true)
75 : {
76 216 : assert(num_agegroups < MAX_NUM_AGE_GROUPS && "MAX_NUM_AGE_GROUPS exceeded.");
77 216 : }
78 :
79 : /**
80 : * @brief Create a Model.
81 : * @param[in] params Initial simulation parameters.
82 : */
83 9 : Model(const Parameters& params, int id = 0)
84 9 : : parameters(params.get_num_groups())
85 9 : , m_id(id)
86 9 : , m_trip_list()
87 9 : , m_use_mobility_rules(true)
88 9 : , m_cemetery_id(add_location(LocationType::Cemetery))
89 36 : , m_person_ids_equal_index(true)
90 : {
91 9 : parameters = params;
92 9 : }
93 :
94 141 : Model(const Model& other, int id = 0)
95 141 : : parameters(other.parameters)
96 141 : , m_local_population_cache()
97 141 : , m_air_exposure_rates_cache()
98 141 : , m_contact_exposure_rates_cache()
99 141 : , m_is_local_population_cache_valid(false)
100 141 : , m_are_exposure_caches_valid(false)
101 141 : , m_exposure_caches_need_rebuild(true)
102 141 : , m_id(id)
103 141 : , m_persons(other.m_persons)
104 141 : , m_locations(other.m_locations)
105 141 : , m_activeness_statuses(other.m_activeness_statuses)
106 141 : , m_has_locations(other.m_has_locations)
107 141 : , m_testing_strategy(other.m_testing_strategy)
108 141 : , m_trip_list(other.m_trip_list)
109 141 : , m_use_mobility_rules(other.m_use_mobility_rules)
110 141 : , m_mobility_rules(other.m_mobility_rules)
111 141 : , m_cemetery_id(other.m_cemetery_id)
112 141 : , m_rng(other.m_rng)
113 141 : , m_person_ids_equal_index(true)
114 : {
115 141 : }
116 : Model& operator=(const Model&) = default;
117 78 : Model(Model&&) = default;
118 : Model& operator=(Model&&) = default;
119 :
120 : /**
121 : * serialize this.
122 : * @see mio::serialize
123 : */
124 : template <class IOContext>
125 9 : void serialize(IOContext& io) const
126 : {
127 27 : auto obj = io.create_object("Model");
128 9 : obj.add_element("parameters", parameters);
129 : // skip caches, they are rebuild by the deserialized model
130 9 : obj.add_list("persons", get_persons().begin(), get_persons().end());
131 9 : obj.add_list("locations", get_locations().begin(), get_locations().end());
132 9 : obj.add_element("location_types", m_has_locations.to_ulong());
133 9 : obj.add_element("testing_strategy", m_testing_strategy);
134 9 : obj.add_element("trip_list", m_trip_list);
135 9 : obj.add_element("use_mobility_rules", m_use_mobility_rules);
136 9 : obj.add_element("cemetery_id", m_cemetery_id);
137 9 : obj.add_element("rng", m_rng);
138 18 : }
139 :
140 : /**
141 : * deserialize an object of this class.
142 : * @see mio::deserialize
143 : */
144 : template <class IOContext>
145 9 : static IOResult<Model> deserialize(IOContext& io)
146 : {
147 27 : auto obj = io.expect_object("Model");
148 27 : auto params = obj.expect_element("parameters", Tag<Parameters>{});
149 27 : auto persons = obj.expect_list("persons", Tag<Person>{});
150 27 : auto locations = obj.expect_list("locations", Tag<Location>{});
151 27 : auto location_types = obj.expect_element("location_types", Tag<unsigned long>{});
152 27 : auto trip_list = obj.expect_element("trip_list", Tag<TripList>{});
153 27 : auto use_mobility_rules = obj.expect_element("use_mobility_rules", Tag<bool>{});
154 27 : auto cemetery_id = obj.expect_element("cemetery_id", Tag<LocationId>{});
155 27 : auto rng = obj.expect_element("rng", Tag<RandomNumberGenerator>{});
156 : return apply(
157 : io,
158 9 : [](auto&& params_, auto&& persons_, auto&& locations_, auto&& location_types_, auto&& trip_list_,
159 : auto&& use_mobility_rules_, auto&& cemetery_id_, auto&& rng_) {
160 9 : Model model{params_};
161 9 : model.m_persons.assign(persons_.cbegin(), persons_.cend());
162 9 : model.m_locations.assign(locations_.cbegin(), locations_.cend());
163 9 : model.m_has_locations = location_types_;
164 9 : model.m_trip_list = trip_list_;
165 9 : model.m_use_mobility_rules = use_mobility_rules_;
166 9 : model.m_cemetery_id = cemetery_id_;
167 9 : model.m_rng = rng_;
168 18 : return model;
169 9 : },
170 18 : params, persons, locations, location_types, trip_list, use_mobility_rules, cemetery_id, rng);
171 9 : }
172 :
173 : /**
174 : * @brief Prepare the Model for the next Simulation step.
175 : * @param[in] t Current time.
176 : * @param[in] dt Length of the time step.
177 : */
178 : void begin_step(TimePoint t, TimeSpan dt);
179 :
180 : /**
181 : * @brief Evolve the Model one time step.
182 : * @param[in] t Current time.
183 : * @param[in] dt Length of the time step.
184 : */
185 : void evolve(TimePoint t, TimeSpan dt);
186 :
187 : /**
188 : * @brief Add a Location to the Model.
189 : * @param[in] type Type of Location to add.
190 : * @param[in] num_cells [Default: 1] Number of Cell%s that the Location is divided into.
191 : * @return ID of the newly created Location.
192 : */
193 : LocationId add_location(LocationType type, uint32_t num_cells = 1);
194 :
195 : /**
196 : * @brief Add a Person to the Model.
197 : * @param[in] id The LocationID of the initial Location of the Person.
198 : * @param[in] age AgeGroup of the person.
199 : * @return Id of the newly created Person.
200 : */
201 : PersonId add_person(const LocationId id, AgeGroup age);
202 :
203 : /**
204 : * @brief Adds a copy of a given Person to the Model.
205 : * @param[in] person The Person to copy from.
206 : * @return Id of the newly created Person.
207 : */
208 : PersonId add_person(Person&& person);
209 :
210 : /**
211 : * @brief Get a range of all Location%s in the Model.
212 : * @return A range of all Location%s.
213 : * @{
214 : */
215 : Range<std::pair<ConstLocationIterator, ConstLocationIterator>> get_locations() const;
216 : Range<std::pair<LocationIterator, LocationIterator>> get_locations();
217 : /** @} */
218 :
219 : /**
220 : * @brief Get a range of all Person%s in the Model.
221 : * @return A range of all Person%s.
222 : * @{
223 : */
224 : Range<std::pair<ConstPersonIterator, ConstPersonIterator>> get_persons() const;
225 : Range<std::pair<PersonIterator, PersonIterator>> get_persons();
226 : /** @} */
227 :
228 : /**
229 : * @brief Get a range of all Person%s activeness statuses in the Model.
230 : * @return A range of all Person%s activeness statuses.
231 : * @{
232 : */
233 : Range<std::pair<ConstActivenessIterator, ConstActivenessIterator>> get_activeness_statuses() const;
234 : Range<std::pair<ActivenessIterator, ActivenessIterator>> get_activeness_statuses();
235 : /** @} */
236 :
237 : /**
238 : * @brief Find an assigned Location of a Person.
239 : * @param[in] type The #LocationType that specifies the assigned Location.
240 : * @param[in] person Id of the Person.
241 : * @return ID of the Location of LocationType type assigend to person.
242 : */
243 : LocationId find_location(LocationType type, const PersonId person) const;
244 :
245 : /**
246 : * @brief Assign a Location to a Person.
247 : * A Person can have at most one assigned Location of a certain LocationType.
248 : * Assigning another Location of an already assigned LocationType will replace the prior assignment.
249 : * @param[in] person The Id of the person this location will be assigned to.
250 : * @param[in] location The LocationId of the Location.
251 : */
252 1098 : void assign_location(PersonId person, LocationId location)
253 : {
254 1098 : assign_location(get_person(person), location);
255 1098 : }
256 :
257 : /**
258 : * @brief Get the number of Persons in one #InfectionState at all Location%s.
259 : * @param[in] t Specified #TimePoint.
260 : * @param[in] s Specified #InfectionState.
261 : */
262 : size_t get_subpopulation_combined(TimePoint t, InfectionState s) const;
263 :
264 : /**
265 : * @brief Get the number of Persons in one #InfectionState at all Location%s of a type.
266 : * @param[in] t Specified #TimePoint.
267 : * @param[in] s Specified #InfectionState.
268 : * @param[in] type Specified #LocationType.
269 : */
270 : size_t get_subpopulation_combined_per_location_type(TimePoint t, InfectionState s, LocationType type) const;
271 :
272 : /**
273 : * @brief Get the mobility data.
274 : * @return Reference to the list of Trip%s that the Person%s make.
275 : */
276 : TripList& get_trip_list();
277 :
278 : const TripList& get_trip_list() const;
279 :
280 : /**
281 : * @brief Decide if mobility rules (like go to school/work) are used or not;
282 : * The mobility rules regarding hospitalization/ICU/quarantine are always used.
283 : * @param[in] param If true uses the mobility rules for changing location to school/work etc., else only the rules
284 : * regarding hospitalization/ICU/quarantine.
285 : */
286 : void use_mobility_rules(bool param);
287 : bool use_mobility_rules() const;
288 :
289 : /**
290 : * @brief Check if at least one Location with a specified LocationType exists.
291 : * @return True if there is at least one Location of LocationType `type`. False otherwise.
292 : */
293 28980 : bool has_location(LocationType type) const
294 : {
295 28980 : return m_has_locations[size_t(type)];
296 : }
297 :
298 : /**
299 : * @brief Check if at least one Location of every specified LocationType exists.
300 : * @tparam C A type of container of LocationType.
301 : * @param location_types A container of LocationType%s.
302 : * @return True if there is at least one Location of every LocationType in `location_types`. False otherwise.
303 : */
304 : template <class C = std::initializer_list<LocationType>>
305 24219 : bool has_locations(const C& location_types) const
306 : {
307 82179 : return std::all_of(location_types.begin(), location_types.end(), [&](auto loc) {
308 57960 : return has_location(loc);
309 24219 : });
310 : }
311 :
312 : /**
313 : * @brief Get the TestingStrategy.
314 : * @return Reference to the list of TestingScheme%s that are checked for testing.
315 : */
316 : TestingStrategy& get_testing_strategy();
317 :
318 : const TestingStrategy& get_testing_strategy() const;
319 :
320 : /**
321 : * @brief The simulation parameters of the Model.
322 : */
323 : Parameters parameters;
324 :
325 : /**
326 : * Get the RandomNumberGenerator used by this Model for random events.
327 : * Persons use their own generators with the same key as the global one.
328 : * @return The random number generator.
329 : */
330 1296 : RandomNumberGenerator& get_rng()
331 : {
332 1296 : return m_rng;
333 : }
334 :
335 : /**
336 : * Get the model id. Is only relevant for graph abm or hybrid model.
337 : * @return The model id
338 : */
339 550 : int get_id() const
340 : {
341 550 : return m_id;
342 : }
343 :
344 : /**
345 : * @brief Add a TestingScheme to the set of schemes that are checked for testing at all Locations that have
346 : * the LocationType.
347 : * @param[in] loc_type LocationId key for TestingScheme to be added.
348 : * @param[in] scheme TestingScheme to be added.
349 : */
350 : void add_testing_scheme(const LocationType& loc_type, const TestingScheme& scheme);
351 :
352 : /**
353 : * @brief Remove a TestingScheme from the set of schemes that are checked for testing at all Locations that have
354 : * the LocationType.
355 : * @param[in] loc_type LocationId key for TestingScheme to be added.
356 : * @param[in] scheme TestingScheme to be added.
357 : */
358 : void remove_testing_scheme(const LocationType& loc_type, const TestingScheme& scheme);
359 :
360 : /**
361 : * @brief Get a reference to a Person from this Model.
362 : * @param[in] person_id A Person's PersonId.
363 : * @return A reference to the Person.
364 : */
365 81 : const Person& get_person(PersonId person_id) const
366 : {
367 81 : return get_person_impl(*this, person_id);
368 : }
369 :
370 1643 : Person& get_person(PersonId person_id)
371 : {
372 1643 : return get_person_impl(*this, person_id);
373 : }
374 :
375 : /**
376 : * @brief Get the number of Person%s of a particular #InfectionState for all Cell%s.
377 : * @param[in] location A LocationId from the Model.
378 : * @param[in] t TimePoint of querry.
379 : * @param[in] state #InfectionState of interest.
380 : * @return Amount of Person%s of the #InfectionState in all Cell%s of the Location.
381 : */
382 27315 : size_t get_subpopulation(LocationId location, TimePoint t, InfectionState state) const
383 : {
384 27315 : return std::count_if(m_persons.begin(), m_persons.end(), [&](auto&& p) {
385 320238 : return p.get_location_model_id() == m_id && p.get_location() == location &&
386 226980 : p.get_infection_state(t) == state;
387 27315 : });
388 : }
389 :
390 : /**
391 : * @brief Get the total number of Person%s at the Location.
392 : * @param[in] location A LocationId from the Model.
393 : * @return Number of Person%s in the location.
394 : */
395 290 : size_t get_number_persons(LocationId location) const
396 : {
397 290 : if (!m_is_local_population_cache_valid) {
398 0 : build_compute_local_population_cache();
399 : }
400 290 : return m_local_population_cache[location.get()];
401 : }
402 :
403 : // Change the Location of a Person. this requires that Location is part of this Model.
404 : /**
405 : * @brief Let a Person change to another Location.
406 : * @param[in] person Id of a person from this Model.
407 : * @param[in] destination LocationId of the Location in this Model, which the Person should change to.
408 : * @param[in] mode The transport mode the person uses to change the Location.
409 : * @param[in] cells The cells within the destination the person should be in.
410 : */
411 36 : inline void change_location(PersonId person, LocationId destination, TransportMode mode = TransportMode::Unknown,
412 : const std::vector<uint32_t>& cells = {0})
413 : {
414 36 : change_location(get_person(person), destination, mode, cells);
415 36 : }
416 :
417 : /**
418 : * @brief Let a person interact with the population at its current location.
419 : * @param[in] person Id of a person from this Model.
420 : * @param[in] t Time step of the simulation.
421 : * @param[in] dt Step size of the simulation.
422 : */
423 : inline void interact(PersonId person, TimePoint t, TimeSpan dt)
424 : {
425 : interact(get_person(person), t, dt);
426 : }
427 :
428 : /**
429 : * @brief Get a reference to a location in this Model.
430 : * @param[in] id LocationId of the Location.
431 : * @return Reference to the Location.
432 : * @{
433 : */
434 : const Location& get_location(LocationId id) const
435 : {
436 : assert(id != LocationId::invalid_id() && "Given LocationId must be valid.");
437 : assert(id < LocationId((uint32_t)m_locations.size()) && "Given LocationId is not in this Model.");
438 : return m_locations[id.get()];
439 : }
440 :
441 : /**
442 : * @brief Assign a Location to a Person.
443 : * A Person can have at most one assigned Location of a certain LocationType.
444 : * Assigning another Location of an already assigned LocationType will replace the prior assignment.
445 : * @param[in] person reference to the Person the location will be assigned to.
446 : * @param[in] location The LocationId of the Location.
447 : */
448 1098 : void assign_location(Person& person, LocationId location)
449 : {
450 1098 : person.set_assigned_location(get_location(location).get_type(), location, m_id);
451 1098 : }
452 :
453 18296 : Location& get_location(LocationId id)
454 : {
455 18296 : assert(id != LocationId::invalid_id() && "Given LocationId must be valid.");
456 18296 : assert(id < LocationId((uint32_t)m_locations.size()) && "Given LocationId is not in this Model.");
457 18296 : return m_locations[id.get()];
458 : }
459 : /** @} */
460 :
461 : /**
462 : * @brief Get a reference to the location of a person.
463 : * @param[in] id Id of a person.
464 : * @return Reference to the Location.
465 : * @{
466 : */
467 63 : inline Location& get_location(PersonId id)
468 : {
469 63 : return get_location(get_person(id).get_location());
470 : }
471 :
472 : inline const Location& get_location(PersonId id) const
473 : {
474 : return get_location(get_person(id).get_location());
475 : }
476 : /** @} */
477 :
478 : /**
479 : * @brief Get index of person in m_persons.
480 : * @param[in] person_id A person's unique PersonId.
481 : * First 32 bit are the Person's individual id and second 32 bit the Persons's home model id.
482 : * @return Index of Person in m_persons vector.
483 : * @{
484 : */
485 10 : uint32_t get_person_index(PersonId person_id) const
486 : {
487 10 : mio::log_debug("get_person_index is used leading to a search in m_persons.");
488 10 : auto it = std::find_if(m_persons.begin(), m_persons.end(), [person_id](auto& person) {
489 25 : return person.get_id() == person_id;
490 : });
491 10 : if (it == m_persons.end()) {
492 1 : log_error("Given PersonId is not in this Model.");
493 1 : return std::numeric_limits<uint32_t>::max();
494 : }
495 : else {
496 9 : return static_cast<uint32_t>(std::distance(m_persons.begin(), it));
497 : }
498 : }
499 :
500 : protected:
501 : /**
502 : * @brief Person%s interact at their Location and may become infected.
503 : * @param[in] t The current TimePoint.
504 : * @param[in] dt The length of the time step of the Simulation.
505 : */
506 : void interaction(TimePoint t, TimeSpan dt);
507 : /**
508 : * @brief Person%s change location in the Model according to rules.
509 : * @param[in] t The current TimePoint.
510 : * @param[in] dt The length of the time step of the Simulation.
511 : */
512 : void perform_mobility(TimePoint t, TimeSpan dt);
513 :
514 : /// @brief Shape the cache and store how many Person%s are at any Location. Use from single thread!
515 : void build_compute_local_population_cache() const;
516 :
517 : /// @brief Shape the air and contact exposure cache according to the current Location%s.
518 : void build_exposure_caches();
519 :
520 : /**
521 : * @brief Store all air/contact exposures for the current simulation step.
522 : * @param[in] t Current TimePoint of the simulation.
523 : * @param[in] dt The duration of the simulation step.
524 : */
525 : void compute_exposure_caches(TimePoint t, TimeSpan dt);
526 :
527 : // Change the Location of a Person. this requires that Location is part of this Model.
528 : /**
529 : * @brief Let a Person change to another Location.
530 : * @param[in] person Reference to Person.
531 : * @param[in] destination LocationId of the Location in this Model, which the Person should change to.
532 : * @param[in] mode The transport mode the person uses to change the Location.
533 : * @param[in] cells The cells within the destination the person should be in.
534 : */
535 337 : inline void change_location(Person& person, LocationId destination, TransportMode mode = TransportMode::Unknown,
536 : const std::vector<uint32_t>& cells = {0})
537 : {
538 337 : LocationId origin = get_location(person).get_id();
539 337 : const bool has_changed_location = mio::abm::change_location(person, get_location(destination), mode, cells);
540 : // if the person has changed location, invalidate exposure caches but keep population caches valid
541 337 : if (has_changed_location) {
542 328 : m_are_exposure_caches_valid = false;
543 328 : if (m_is_local_population_cache_valid) {
544 328 : --m_local_population_cache[origin.get()];
545 328 : ++m_local_population_cache[destination.get()];
546 : }
547 : }
548 337 : }
549 :
550 : /**
551 : * @brief Get a reference to the location of a person.
552 : * @param[in] person Reference to a Person.
553 : * @return Reference to the Location.
554 : * @{
555 : */
556 337 : inline Location& get_location(Person& person)
557 : {
558 337 : return get_location(person.get_location());
559 : }
560 :
561 : inline const Location& get_location(Person& person) const
562 : {
563 : return get_location(person.get_location());
564 : }
565 :
566 : /**
567 : * @brief Find an assigned Location of a Person.
568 : * @param[in] type The #LocationType that specifies the assigned Location.
569 : * @param[in] person Reference to Person.
570 : * @return ID of the Location of LocationType type assigend to person.
571 : */
572 9094 : LocationId find_location(LocationType type, const Person& person) const
573 : {
574 9094 : auto location_id = person.get_assigned_location(type);
575 9094 : assert(location_id != LocationId::invalid_id() && "The person has no assigned location of that type.");
576 18188 : return location_id;
577 : }
578 :
579 : /**
580 : * @brief Let a person interact with the population at its current location.
581 : * @param[in] person Reference to Person.
582 : * @param[in] t Time step of the simulation.
583 : * @param[in] dt Step size of the simulation.
584 : */
585 2853 : inline void interact(Person& person, TimePoint t, TimeSpan dt)
586 : {
587 2853 : if (!m_are_exposure_caches_valid) {
588 : // checking caches is only needed for external calls
589 : // during simulation (i.e. in evolve()), the caches are computed in begin_step
590 0 : compute_exposure_caches(t, dt);
591 0 : m_are_exposure_caches_valid = true;
592 : }
593 2853 : auto personal_rng = PersonalRandomNumberGenerator(person);
594 8559 : mio::abm::interact(personal_rng, person, get_location(person.get_location()),
595 5706 : m_air_exposure_rates_cache[person.get_location().get()],
596 8559 : m_contact_exposure_rates_cache[person.get_location().get()], t, dt, parameters);
597 2853 : }
598 :
599 : /**
600 : * @brief Implementation of Model::get_person.
601 : * This function needs to use a template to deduce whether the model and returned person should be const.
602 : * @param[in] m A reference to `*this`, so we can access m_persons.
603 : * @param[in] person_id A Person's PersonId.
604 : * @return A reference to the Person with matching ID.
605 : */
606 : template <class M>
607 1724 : static std::conditional_t<std::is_const_v<M>, const Person&, Person&> get_person_impl(M& m, PersonId person_id)
608 : {
609 1724 : if (m.m_person_ids_equal_index) {
610 1723 : assert(static_cast<uint32_t>(person_id.get()) < m.m_persons.size() &&
611 : "Given PersonId is not in this Model.");
612 1723 : return m.m_persons[static_cast<uint32_t>(person_id.get())];
613 : }
614 : else {
615 1 : mio::log_warning("get_person is accessed by PersonId which does not align with the index of the person due "
616 : "to former removal of persons. Therefore m_persons is searched.");
617 1 : auto it = std::find_if(m.m_persons.begin(), m.m_persons.end(), [person_id](auto& person) {
618 1 : return person.get_id() == person_id;
619 : });
620 1 : assert(it != m.m_persons.end() && "Given PersonId is not in this Model.");
621 1 : return *it;
622 : };
623 : }
624 :
625 : mutable Eigen::Matrix<std::atomic_int_fast32_t, Eigen::Dynamic, 1>
626 : m_local_population_cache; ///< Current number of Persons in a given location.
627 : Eigen::Matrix<AirExposureRates, Eigen::Dynamic, 1>
628 : m_air_exposure_rates_cache; ///< Cache for local exposure through droplets in #transmissions/day.
629 : Eigen::Matrix<ContactExposureRates, Eigen::Dynamic, 1>
630 : m_contact_exposure_rates_cache; ///< Cache for local exposure through contacts in #transmissions/day.
631 : bool m_is_local_population_cache_valid = false;
632 : bool m_are_exposure_caches_valid = false;
633 : bool m_exposure_caches_need_rebuild = true;
634 :
635 : int m_id; ///< Model id. Is only used for abm graph model or hybrid model.
636 : std::vector<Person> m_persons; ///< Vector of every Person.
637 : std::vector<Location> m_locations; ///< Vector of every Location.
638 : std::vector<bool>
639 : m_activeness_statuses; ///< Vector with activeness status for every person. Is only used for abm graph model or hybrid model.
640 : std::bitset<size_t(LocationType::Count)>
641 : m_has_locations; ///< Flags for each LocationType, set if a Location of that type exists.
642 : TestingStrategy m_testing_strategy; ///< List of TestingScheme%s that are checked for testing.
643 : TripList m_trip_list; ///< List of all Trip%s the Person%s do.
644 : bool m_use_mobility_rules; ///< Whether mobility rules are considered.
645 : std::vector<MobilityRuleType> m_mobility_rules; ///< Rules that govern the mobility between Location%s.
646 : LocationId m_cemetery_id; // Central cemetery for all dead persons.
647 : RandomNumberGenerator m_rng; ///< Global random number generator
648 : bool m_person_ids_equal_index;
649 : };
650 :
651 : } // namespace abm
652 : } // namespace mio
653 :
654 : #endif
|