|
1 | 1 | # Agent-Based Model |
2 | 2 |
|
3 | | -This module models and simulates the epidemic using an agent-based model (*ABM*) approach. Unlike compartmental models like the [SECIR](../ode_secir/README.md) model that uses a system of ODEs, this model simulates the spread of COVID-19 in a population with discrete persons (the agents) moving throughout locations in the model and interacting with (infecting) each other. |
| 3 | +This directory contains the agent based model. |
| 4 | +To get started, check out the [official documentation](https://memilio.readthedocs.io/en/latest/cpp/mobility_based_abm.html) |
| 5 | +or the code examples |
4 | 6 |
|
5 | | -## Structure |
6 | | - |
7 | | -The model consists of the following major classes: |
8 | | - |
9 | | -1. Person: represents an agent of the model. A person has an ID, i.e. a unique number, an age, a location and a list with their assigned locations, i.e. the locations it can visit during the simulation. They can perform tests and wear masks. Every person has lists with past and current infections and vaccinations. |
10 | | -2. Infection: collection of all information about a persons' infection, i.e. infectiousness, infection course, virus variant. The infection course is drawn stochastically from the infection states that are similar to the compartments of the SECIR model. |
11 | | -3. Location: represents places in the model where people meet and interact, e.g. home, school, work, social event sites. A location can be split into cells to model parts of a location, like classrooms in a school. Some infection parameters are location-specific and one can activate NPIs like mandatory masks or tests to enter the location. |
12 | | -4. Model: collection of all persons and locations. It also holds information about the testing strategy of the simulation and holds the rules for the mobility phase. |
13 | | -5. Simulation: runs the simulation and stores results. |
14 | | - |
15 | | -## Simulation |
16 | | - |
17 | | -The simulation runs in discrete time steps. Each step has two phases, an interaction phase and a mobility phase. |
18 | | - |
19 | | -### Interaction Phase |
20 | | - |
21 | | -In this phase, each person interacts with the other persons at the same location. This interaction determines the transmission of the disease. A susceptible person can become infected by contact with an infected person. The probability of infection depends on a multitude of factors, such as the viral load and infectiousness of the infected and the immunity level of the susceptible person at the time of transmission. |
22 | | - |
23 | | -### Mobility Phase |
24 | | - |
25 | | -During the mobility phase, each person may change their location. Mobility follows complex [rules](../abm/mobility_rules.cpp), considering the current location, time of day, and properties of the person (e.g. age). Some location changes are deterministic and regular (e.g. going to work), others are random (e.g. going to shopping or to a social event in the evening/on the weekend). When agents are tested positive, they are quarantined and cannot leave their home, unless their infection becomes worse and they have to go to the hospital or the ICU. In general, if an agent suffers from severe or critical symptoms, it will move to the hospital or ICU with highest priority. Some mobility rules can be restricted by allowing only a proportion of people to enter specific locations. |
26 | | - |
27 | | -Another way of mobility we use in the simulation of Braunschweig (simulations/abm_braunschweig.cpp) is using trips. A trip consists of the ID of the person that performs this trip, a time point when this trip is performed and where the person is heading to. At the beginning of the simulation, a list with all trips is initialized and followed during the simulation. There can be different trips on the weekend than during the week, but other than that, the agents do the same trips every day. As before, agents that are in quarantine or in the hospital cannot change their location. |
28 | | - |
29 | | -## Get Started |
30 | | - |
31 | | -This section gives an introduction to how to use the ABM and set up your own simulation. For a quick overview, can find a full example in the [ABM minimal example](../../examples/abm_minimal.cpp) and a more detailed Doxygen documentation [here](https://scicompmod.github.io/memilio/documentation/index.html ). For a guide on installation and running the simulations and examples, see this [README](../../README.md). |
32 | | - |
33 | | -Every person in the ABM belongs to an AgeGroup, which we can define as follows: |
34 | | - |
35 | | -```cpp |
36 | | -size_t num_age_groups = 4; |
37 | | -const auto age_group_0_to_4 = mio::AgeGroup(0); |
38 | | -const auto age_group_5_to_14 = mio::AgeGroup(1); |
39 | | -... = ... |
40 | | -``` |
41 | | - |
42 | | -Note that every age group has to have values strictly smaller than the number of age groups `num_age_groups`. |
43 | | -With this number we create an empty model: |
44 | | - |
45 | | -```cpp |
46 | | -auto model = mio::abm::Model(num_age_groups); |
47 | | -``` |
48 | | - |
49 | | -We can set several general parameters, which you can find [here](../abm/parameters.h). Here is an example where we set the time to go from Exposed to InfectedNoSymptoms to 4 days: |
50 | | - |
51 | | -```cpp |
52 | | -model.parameters.get<mio::abm::TimeExposedToNoSymptoms>() = mio::ParameterDistributionConstant(4.); |
53 | | -``` |
54 | | - |
55 | | -To add a location to the model, we have to specify the kind of location. |
56 | | - |
57 | | -```cpp |
58 | | -auto home = model.add_location(mio::abm::LocationType::Home); |
59 | | -``` |
60 | | - |
61 | | -People are added with an age. Then we have to assign them, so the model knows they can travel to this location. |
62 | | - |
63 | | -```cpp |
64 | | -auto person = model.add_person(home, age_group_0_to_4); |
65 | | -person.set_assigned_location(home); |
66 | | -``` |
67 | | - |
68 | | -For adding more people to the model, we create households. A Household holds a vector of HouseholdMembers, which in turn hold a weighted distribution, such that we can randomly draw the age of each Person belonging to the Household. To manage multiple Households of the same type, we can use a HouseholdGroup. |
69 | | -In our example, we categorize individuals into two groups: children and parents. |
70 | | - |
71 | | -- Children: They can either belong to AgeGroup(0) or AgeGroup(1). The probability of a child belonging to either group is 0.5. |
72 | | -- Parents: They can either belong to AgeGroup(2) or AgeGroup(3). The probability of a parent belonging to either group is also 0.5. |
73 | | - |
74 | | -We then form households in two ways: |
75 | | - |
76 | | -1. Households with one parent and one child. |
77 | | -2. Households with two parents and one child. |
78 | | - |
79 | | -```cpp |
80 | | -auto child = mio::abm::HouseholdMember(num_age_groups); |
81 | | -child.set_age_weight(age_group_0_to_4, 1); |
82 | | -child.set_age_weight(age_group_0_to_4, 1); |
83 | | - |
84 | | -auto parent = mio::abm::HouseholdMember(num_age_groups); |
85 | | -parent.set_age_weight(age_groups_15_to_34, 1); |
86 | | -parent.set_age_weight(age_groups_35_to_59, 1); |
87 | | - |
88 | | -// Two-person household with one parent and one child. |
89 | | -auto twoPersonHousehold_group = mio::abm::HouseholdGroup(); |
90 | | -auto twoPersonHousehold_full = mio::abm::Household(); |
91 | | -twoPersonHousehold_full.add_members(child, 1); |
92 | | -twoPersonHousehold_full.add_members(parent, 1); |
93 | | -twoPersonHousehold_group.add_households(twoPersonHousehold_full, n_households); |
94 | | -add_household_group_to_model(model, twoPersonHousehold_group); |
95 | | - |
96 | | -``` |
97 | | -
|
98 | | -During the simulation, people can get tested, and we have to specify the scheme for that: |
99 | | -
|
100 | | -```cpp |
101 | | -auto probability = 0.5; |
102 | | -auto start_date = mio::abm::TimePoint(0); |
103 | | -auto end_date = mio::abm::TimePoint(0) + mio::abm::days(30); |
104 | | -auto test_type = mio::abm::AntigenTest(); |
105 | | -auto test_at_work = std::vector<mio::abm::LocationType>{mio::abm::LocationType::Work}; |
106 | | -auto testing_criteria_work = |
107 | | - std::vector<mio::abm::TestingCriteria>{mio::abm::TestingCriteria({}, test_at_work, {})}; |
108 | | -auto testing_scheme_work = |
109 | | - mio::abm::TestingScheme(testing_criteria_work, start_date, end_date, test_type, probability); |
110 | | -model.get_testing_strategy().add_testing_scheme(testing_scheme_work); |
111 | | -``` |
112 | | - |
113 | | -For some infections to happen during the simulation, we have to initialize people with infections. |
114 | | - |
115 | | -```cpp |
116 | | -person.add_new_infection(mio::abm::Infection(rng, mio::abm::VirusVariant::Wildtype, person.get_age(), model.parameters, start_date, infection_state)); |
117 | | -``` |
118 | | - |
119 | | -We can add restrictions for people after a specific date. For example, only 10% of the people go to social events after day 10. |
120 | | - |
121 | | -```cpp |
122 | | -auto t_lockdown = mio::abm::TimePoint(0) + mio::abm::days(10); |
123 | | -mio::abm::close_social_events(t_lockdown, 0.9, model.parameters); |
124 | | -``` |
125 | | -
|
126 | | -Then we run the simulation. |
127 | | -
|
128 | | -```cpp |
129 | | -sim.advance(mio::abm::TimePoint(0) + mio::abm::days(30)); |
130 | | -``` |
131 | | - |
132 | | -Alternitavely, if we want to track things in the simulation, we need to set up a [history](../../memilio/io/README.md#the-history-object), for example, to track all the Infection states of each simulation step. |
133 | | - |
134 | | -```cpp |
135 | | - mio::History<mio::abm::TimeSeriesWriter, mio::abm::LogInfectionState> history; |
136 | | -``` |
137 | | - |
138 | | -Then we can run the simulation with the history object and one can access the data it through get_log. |
139 | | - |
140 | | -```cpp |
141 | | - sim.advance(tmax, history); |
142 | | - auto log = history.get_log(); |
143 | | -``` |
144 | | - |
145 | | -Finally we can print the data to a text file. |
146 | | - |
147 | | -```cpp |
148 | | - std::ofstream outfile("abm_minimal.txt"); |
149 | | - std::get<0>(log).print_table({"S", "E", "I_NS", "I_Sy", "I_Sev", "I_Crit", "R", "D"}, 7, 4, outfile); |
150 | | - std::cout << "Results written to abm_minimal.txt" << std::endl; |
151 | | -``` |
152 | | -
|
153 | | -## Current Limitations |
154 | | -
|
155 | | -Currently, a few things are not yet implemented, such as: |
156 | | -
|
157 | | -- Different trips for each day. |
158 | | -- Test and Trace functionality |
| 7 | +- [examples/abm.cpp](../../examples/abm_minimal.cpp) |
| 8 | +- [examples/abm_minimal.cpp](../../examples/abm_history_object.cpp) |
0 commit comments