Skip to content

Commit fe3f18e

Browse files
committed
update abm tutorials
1 parent 2e78be0 commit fe3f18e

8 files changed

Lines changed: 774 additions & 410 deletions

cpp-tutorials/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,11 @@ target_link_libraries(tutorial11 PRIVATE memilio ode_secir Boost::filesystem)
7979
add_executable(tutorial12_ensemble_sims tutorial12_ensemble_sims.cpp)
8080
target_link_libraries(tutorial12_ensemble_sims PRIVATE memilio ode_secir)
8181

82-
add_executable(tutorial_abm_household abm/tutorial_abm_household1.cpp abm/parameter_setter.cpp)
82+
add_executable(tutorial_abm_household abm/tutorial_abm_households.cpp abm/parameter_setter.cpp)
8383
target_link_libraries(tutorial_abm_household PRIVATE memilio abm)
8484

85-
add_executable(tutorial_abm_tests abm/tutorial_abm_testing2.cpp abm/parameter_setter.cpp)
85+
add_executable(tutorial_abm_tests abm/tutorial_abm_testing.cpp abm/parameter_setter.cpp)
8686
target_link_libraries(tutorial_abm_tests PRIVATE memilio abm)
8787

88-
add_executable(tutorial_abm_vaccination abm/tutorial_abm_vacc3.cpp abm/parameter_setter.cpp)
88+
add_executable(tutorial_abm_vaccination abm/tutorial_abm_vaccination.cpp abm/parameter_setter.cpp)
8989
target_link_libraries(tutorial_abm_vaccination PRIVATE memilio abm)

cpp-tutorials/abm/parameter_setter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ void set_world_parameters(mio::abm::Parameters& params)
8686
params.get<mio::abm::DeathsPerInfectedCritical>()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.48;
8787

8888
// Set infection parameters
89-
params.get<mio::abm::InfectionRateFromViralShed>()[{mio::abm::VirusVariant::Wildtype}] = 100.0;
89+
params.get<mio::abm::InfectionRateFromViralShed>()[{mio::abm::VirusVariant::Wildtype}] = 5.0;
9090
params.get<mio::abm::AerosolTransmissionRates>() = 0.0;
9191
}
9292

cpp-tutorials/abm/tutorial_abm_household1.cpp renamed to cpp-tutorials/abm/tutorial_abm_households.cpp

Lines changed: 72 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* Copyright (C) 2020-2026 MEmilio
33
*
4-
* Authors: Khoa Nguyen
4+
* Authors: Sascha Korf
55
*
66
* Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
77
*
@@ -19,24 +19,27 @@
1919
*/
2020

2121
/**
22-
* @file tutorial_abm_household1.cpp
23-
* @brief Tutorial 1: Setting up an ABM model with household data.
22+
* @file tutorial_abm_households.cpp
23+
* @brief ABM Tutorial 1: Setting up an agent-based model with households.
24+
*
25+
* MEmilio provides an agent-based model (ABM) where each individual ("agent")
26+
* has an age, a home, and assigned locations they visit during the day.
27+
* Agents transition between infection states (Susceptible, Exposed, ..., Dead)
28+
* based on stochastic contact events at their current location.
2429
*
2530
* This tutorial demonstrates how to:
26-
* 1. Define age groups and model parameters.
31+
* 1. Define age groups and configure model parameters.
2732
* 2. Create HouseholdMember types with weighted age distributions.
28-
* 3. Compose Household templates from HouseholdMember types.
29-
* 4. Group Household templates into HouseholdGroups and add them to the model.
30-
* 5. Add and configure locations (school, work, shop, etc.).
31-
* 6. Assign initial infection states and locations to persons.
32-
* 7. Run a short simulation and write the results to a file.
33+
* 3. Compose Household templates and add them to the model.
34+
* 4. Add locations (school, work, shop, hospital, etc.).
35+
* 5. Assign initial infection states and locations to persons.
36+
* 6. Run a 30-day simulation and write the results.
3337
*
34-
* Key concept HouseholdMember age weights:
38+
* Key concept -- HouseholdMember age weights:
3539
* Each HouseholdMember carries an integer weight for every AgeGroup.
3640
* When a person is created for that member slot, the model draws its age
3741
* from a discrete distribution proportional to these weights.
38-
* Example: weights {1, 1, 0, 0} give a 50 / 50 chance of AgeGroup 0 or 1.
39-
* Weights {0, 0, 1, 2} give a 1/3 chance of AgeGroup 2 and 2/3 of AgeGroup 3.
42+
* Example: weights {1, 1, 0, 0} give a 50/50 chance of AgeGroup 0 or 1.
4043
*/
4144

4245
#include "abm/household.h"
@@ -45,19 +48,27 @@
4548
#include "abm/common_abm_loggers.h"
4649
#include "parameter_setter.h"
4750

51+
#include <cstdlib>
4852
#include <fstream>
4953
#include <iostream>
5054

51-
int main()
55+
int main(int argc, char* argv[])
5256
{
57+
// Usage: tutorial_abm_household [n_households] [infected_frac] [sim_days]
58+
// n_households : number of each household type (default: 125)
59+
// infected_frac : fraction initially infected (default: 0.2)
60+
// sim_days : simulation duration in days (default: 30)
61+
int arg_n_households = (argc > 1) ? std::atoi(argv[1]) : 125;
62+
double arg_infected_frac = (argc > 2) ? std::atof(argv[2]) : 0.2;
63+
int arg_sim_days = (argc > 3) ? std::atoi(argv[3]) : 30;
64+
65+
// Suppress verbose log output; only warnings and errors are shown.
5366
mio::set_log_level(mio::LogLevel::warn);
5467

55-
// -------------------------------------------------------------------------
56-
// 1. Age groups
57-
// -------------------------------------------------------------------------
58-
// We use six age groups covering children and adults younger than 60.
59-
// The index passed to mio::AgeGroup must match the order in which the model
60-
// was constructed (0-based).
68+
// *** Define age groups. ***
69+
// The ABM supports multiple age groups. Each person is assigned to exactly
70+
// one group when created. The number and meaning of groups must be
71+
// consistent throughout the entire setup.
6172
size_t num_age_groups = 6;
6273
const auto age_group_0_to_4 = mio::AgeGroup(0); // toddlers / kindergarten
6374
const auto age_group_5_to_14 = mio::AgeGroup(1); // school children
@@ -66,9 +77,11 @@ int main()
6677
const auto age_group_60_to_79 = mio::AgeGroup(4); // seniors
6778
const auto age_group_80_plus = mio::AgeGroup(5); // elderly
6879

69-
// -------------------------------------------------------------------------
70-
// 2. Model and global infection parameters
71-
// -------------------------------------------------------------------------
80+
// *** Create the model and set infection parameters. ***
81+
// The Model holds all persons, locations, and parameters. We pass in the
82+
// number of age groups so that all parameter arrays are sized correctly.
83+
// `set_local_parameters` and `set_world_parameters` fill in realistic
84+
// epidemiological values (see parameter_setter.h).
7285
auto model = mio::abm::Model(num_age_groups);
7386
set_local_parameters(model);
7487
set_world_parameters(model.parameters);
@@ -83,13 +96,10 @@ int main()
8396
{age_group_15_to_34, age_group_35_to_59}, true);
8497

8598

86-
// -------------------------------------------------------------------------
87-
// 3. HouseholdMember types
88-
// -------------------------------------------------------------------------
99+
// *** Define HouseholdMember types. ***
89100
// A HouseholdMember is not a person itself; it is a *template* that
90-
// describes the age distribution of whoever fills that role in a household.
91-
// The weights are integers; the probability of each age group is
92-
// P(AgeGroup i) = weight_i / sum_of_all_weights.
101+
// describes the age distribution of whoever fills that role.
102+
// The probability of each age group is P(i) = weight_i / sum_of_weights.
93103

94104
// child: equally likely to be 0-4 or 5-14 years old (weights 1 and 1).
95105
auto child = mio::abm::HouseholdMember(num_age_groups);
@@ -106,17 +116,21 @@ int main()
106116
auto single_adult = mio::abm::HouseholdMember(num_age_groups);
107117
single_adult.set_age_weight(age_group_35_to_59, 1);
108118

119+
// senior: equally likely to be 60-79 or 80+ years old.
109120
auto senior_adult = mio::abm::HouseholdMember(num_age_groups);
110121
senior_adult.set_age_weight(age_group_60_to_79, 1);
111122
senior_adult.set_age_weight(age_group_80_plus, 1);
112123

113-
// -------------------------------------------------------------------------
114-
// 4. Household templates and HouseholdGroups
115-
// -------------------------------------------------------------------------
116-
// A Household collects one or more (member_type, count) pairs.
117-
// set_space_per_member sets the volume per person in m³, which affects
118-
// aerosol transmission when UseLocationCapacityForTransmissions is true.
119-
int n_households = 125; // number of each household type to add to the model
124+
// *** Compose households and add them to the model. ***
125+
// A Household collects (member_type, count) pairs. A HouseholdGroup bundles
126+
// many copies of a Household template. `add_household_group_to_model`
127+
// creates the actual persons and their home locations.
128+
//
129+
// CLI parameters (see usage at top of main):
130+
// argv[1] = n_households (population size: 50, 125, 500)
131+
// argv[2] = infected_frac (initial infected fraction: 0.05, 0.2, 0.5)
132+
// argv[3] = sim_days (simulation duration: 15, 30, 90)
133+
int n_households = arg_n_households;
120134

121135
// --- Type A: two-person household (1 parent + 1 child) -------------------
122136
auto twoPersonHousehold = mio::abm::Household();
@@ -150,14 +164,10 @@ int main()
150164
seniorAdultGroup.add_households(seniorAdultHousehold, n_households);
151165
add_household_group_to_model(model, seniorAdultGroup);
152166

153-
// -------------------------------------------------------------------------
154-
// 5. Locations
155-
// -------------------------------------------------------------------------
156-
// Locations are added one at a time. The returned LocationId is used later
157-
// to assign persons and to read infection parameters.
158-
// MaximumContacts caps the total contact rate at a location: if the sum of
159-
// all ContactRates entries exceeds this value, every rate is scaled down
160-
// proportionally (see adjust_contact_rates in model_functions.cpp).
167+
// *** Add locations. ***
168+
// Besides their home (created automatically above), persons need places to
169+
// visit: a hospital, an ICU, a social event venue, a shop, a school, and
170+
// a workplace. The returned LocationId is used to assign persons later.
161171

162172

163173
// One hospital and one ICU shared by all persons.
@@ -177,13 +187,10 @@ int main()
177187
auto work = model.add_location(mio::abm::LocationType::Work);
178188

179189

180-
// -------------------------------------------------------------------------
181-
// 6. Initial infection states
182-
// -------------------------------------------------------------------------
183-
// We assign each person a random infection state drawn from the discrete
184-
// distribution below. Persons who are not Susceptible receive a full
185-
// Infection object so their viral-load course and state transitions are
186-
// properly initialised.
190+
// *** Assign initial infection states. ***
191+
// Each person draws a random infection state from the distribution below.
192+
// Persons who are not Susceptible receive a full Infection object so their
193+
// viral-load course and state transitions are properly initialised.
187194
//
188195
// Index | InfectionState | Probability
189196
// ------|-------------------------|------------
@@ -197,7 +204,11 @@ int main()
197204
// 7 | Dead | 0.06
198205
auto start_date = mio::abm::TimePoint(0); // t = 0 s from the simulation epoch
199206

200-
std::vector<ScalarType> infection_distribution{0.8, 0.05, 0.1, 0.05, 0.00, 0.00, 0.0, 0.00};
207+
// Build infection distribution from the infected fraction.
208+
// The non-susceptible portion is split: 25% Exposed, 50% I_NS, 25% I_Sy.
209+
const double f = arg_infected_frac;
210+
std::vector<ScalarType> infection_distribution{
211+
1.0 - f, f * 0.25, f * 0.50, f * 0.25, 0.0, 0.0, 0.0, 0.0};
201212

202213
for (auto& person : model.get_persons()) {
203214
// Draw an infection state from the distribution above.
@@ -215,13 +226,10 @@ int main()
215226
}
216227
}
217228

218-
// -------------------------------------------------------------------------
219-
// 7. Location assignment
220-
// -------------------------------------------------------------------------
221-
// Every person must be assigned to at least: their home (done automatically
222-
// by add_household_to_model), a shop, a social-event venue, a hospital, and
223-
// an ICU. School-age children also need a school; working adults need a
224-
// workplace. The model's mobility rules then move persons between their
229+
// *** Assign locations to persons. ***
230+
// Every person must be assigned to at least a shop, social event venue,
231+
// hospital, and ICU. School-age children get a school; working-age adults
232+
// get a workplace. The mobility rules then move persons between their
225233
// assigned locations according to the time of day.
226234
for (auto& person : model.get_persons()) {
227235
const auto id = person.get_id();
@@ -242,27 +250,20 @@ int main()
242250
}
243251
}
244252

245-
// -------------------------------------------------------------------------
246-
// 8. Run the simulation
247-
// -------------------------------------------------------------------------
253+
// *** Run the simulation. ***
254+
// We simulate 30 days. The Simulation object takes ownership of the model.
255+
// A History logger records the number of persons in each InfectionState
256+
// at every time step.
248257
auto t0 = mio::abm::TimePoint(0);
249-
auto tmax = t0 + mio::abm::days(30);
258+
auto tmax = t0 + mio::abm::days(arg_sim_days);
250259
auto sim = mio::abm::Simulation(t0, std::move(model));
251260

252-
// The History object accumulates one time-series entry per simulation step.
253-
// LogInfectionState counts persons in each InfectionState across all
254-
// locations at every logged time point.
255261
mio::History<mio::abm::TimeSeriesWriter, mio::abm::LogInfectionState> historyTimeSeries{
256262
Eigen::Index(mio::abm::InfectionState::Count)};
257263

258264
sim.advance(tmax, historyTimeSeries);
259265

260-
// -------------------------------------------------------------------------
261-
// 9. Write results
262-
// -------------------------------------------------------------------------
263-
// The output file contains a table with 9 columns:
264-
// Time S E I_NS I_Sy I_Sev I_Crit R D
265-
// where Time is in days and the remaining columns are person counts.
266+
// *** Write results to file. ***
266267
std::ofstream outfile("abm_household.txt");
267268
std::get<0>(historyTimeSeries.get_log())
268269
.print_table(outfile,

0 commit comments

Comments
 (0)