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*
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"
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