From c273e358ab99b42b5eeb57359c36ad67affda221 Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Thu, 23 Apr 2026 10:02:37 +0200 Subject: [PATCH 01/12] add ActivityType as input for corresponding fcts --- cpp/benchmarks/abm.cpp | 4 +- cpp/examples/abm_history_object.cpp | 14 +- cpp/examples/abm_minimal.cpp | 14 +- cpp/examples/abm_parameter_study.cpp | 2 +- cpp/examples/graph_abm.cpp | 33 +-- cpp/models/abm/CMakeLists.txt | 1 + cpp/models/abm/activity_type.h | 51 ++++ cpp/models/abm/common_abm_loggers.h | 20 +- cpp/models/abm/household.cpp | 5 +- cpp/models/abm/location_type.h | 5 +- cpp/models/abm/mobility_data.h | 28 +-- cpp/models/abm/mobility_rules.cpp | 100 ++++---- cpp/models/abm/mobility_rules.h | 25 +- cpp/models/abm/model.cpp | 31 +-- cpp/models/abm/model.h | 58 +++-- cpp/models/abm/model_functions.cpp | 5 +- cpp/models/abm/model_functions.h | 5 +- cpp/models/abm/person.cpp | 32 +-- cpp/models/abm/person.h | 68 +++--- cpp/models/abm/trip_list.h | 14 +- cpp/models/graph_abm/graph_abm_mobility.h | 15 +- cpp/models/graph_abm/graph_abmodel.h | 18 +- cpp/tests/abm_helpers.cpp | 14 +- cpp/tests/abm_helpers.h | 8 +- cpp/tests/test_abm_infection.cpp | 4 +- cpp/tests/test_abm_location.cpp | 13 +- cpp/tests/test_abm_lockdown_rules.cpp | 67 +++--- cpp/tests/test_abm_masks.cpp | 16 +- cpp/tests/test_abm_mobility_rules.cpp | 160 +++++++------ cpp/tests/test_abm_model.cpp | 280 ++++++++++++---------- cpp/tests/test_abm_person.cpp | 93 +++---- cpp/tests/test_abm_simulation.cpp | 83 ++++--- cpp/tests/test_abm_testing_strategy.cpp | 91 +++---- cpp/tests/test_graph_abm.cpp | 70 +++--- 34 files changed, 798 insertions(+), 649 deletions(-) create mode 100644 cpp/models/abm/activity_type.h diff --git a/cpp/benchmarks/abm.cpp b/cpp/benchmarks/abm.cpp index 0a16c654d3..70e4f9e494 100644 --- a/cpp/benchmarks/abm.cpp +++ b/cpp/benchmarks/abm.cpp @@ -51,7 +51,7 @@ mio::abm::Simulation<> make_simulation(size_t num_persons, std::initializer_list //create other locations for (auto loc_type : - {mio::abm::LocationType::School, mio::abm::LocationType::Work, mio::abm::LocationType::SocialEvent, + {mio::abm::LocationType::School, mio::abm::LocationType::Work, mio::abm::LocationType::Recreation, mio::abm::LocationType::BasicsShop, mio::abm::LocationType::Hospital, mio::abm::LocationType::ICU}) { const auto num_locs = std::max(size_t(1), num_persons / 2'000); @@ -112,7 +112,7 @@ mio::abm::Simulation<> make_simulation(size_t num_persons, std::initializer_list }; model.get_testing_strategy().add_scheme( - {mio::abm::LocationType::School, mio::abm::LocationType::Work, mio::abm::LocationType::SocialEvent, + {mio::abm::LocationType::School, mio::abm::LocationType::Work, mio::abm::LocationType::Recreation, mio::abm::LocationType::Home}, mio::abm::TestingScheme(random_criteria(), mio::abm::days(3), mio::abm::TimePoint(0), mio::abm::TimePoint(0) + mio::abm::days(10), {}, 0.5)); diff --git a/cpp/examples/abm_history_object.cpp b/cpp/examples/abm_history_object.cpp index f4240e44fa..8176d0349c 100644 --- a/cpp/examples/abm_history_object.cpp +++ b/cpp/examples/abm_history_object.cpp @@ -110,7 +110,7 @@ int main() // Add one social event with 5 maximum contacts. // Maximum contacs limit the number of people that a person can infect while being at this location. - auto event = model.add_location(mio::abm::LocationType::SocialEvent); + auto event = model.add_location(mio::abm::LocationType::Recreation); model.get_location(event).get_infection_parameters().set(5); // Add hospital and ICU with 5 maximum contacs. auto hospital = model.add_location(mio::abm::LocationType::Hospital); @@ -155,17 +155,17 @@ int main() for (auto& person : model.get_persons()) { const auto pid = person.get_id(); //assign shop and event - model.assign_location(pid, event); - model.assign_location(pid, shop); + model.assign_location(pid, event, mio::abm::ActivityType::Recreation); + model.assign_location(pid, shop, mio::abm::ActivityType::BasicsShop); //assign hospital and ICU - model.assign_location(pid, hospital); - model.assign_location(pid, icu); + model.assign_location(pid, hospital, mio::abm::ActivityType::Hospital); + model.assign_location(pid, icu, mio::abm::ActivityType::ICU); //assign work/school to people depending on their age if (person.get_age() == age_group_5_to_14) { - model.assign_location(pid, school); + model.assign_location(pid, school, mio::abm::ActivityType::School); } if (person.get_age() == age_group_15_to_34 || person.get_age() == age_group_35_to_59) { - model.assign_location(pid, work); + model.assign_location(pid, work, mio::abm::ActivityType::Work); } } diff --git a/cpp/examples/abm_minimal.cpp b/cpp/examples/abm_minimal.cpp index 426526c120..13f4c2bd8f 100644 --- a/cpp/examples/abm_minimal.cpp +++ b/cpp/examples/abm_minimal.cpp @@ -79,7 +79,7 @@ int main() // Add one social event with 5 maximum contacts. // Maximum contacs limit the number of people that a person can infect while being at this location. - auto event = model.add_location(mio::abm::LocationType::SocialEvent); + auto event = model.add_location(mio::abm::LocationType::Recreation); model.get_location(event).get_infection_parameters().set(5); // Add hospital and ICU with 5 maximum contacs. auto hospital = model.add_location(mio::abm::LocationType::Hospital); @@ -131,17 +131,17 @@ int main() for (auto& person : model.get_persons()) { const auto id = person.get_id(); //assign shop and event - model.assign_location(id, event); - model.assign_location(id, shop); + model.assign_location(id, event, mio::abm::ActivityType::Recreation); + model.assign_location(id, shop, mio::abm::ActivityType::BasicsShop); //assign hospital and ICU - model.assign_location(id, hospital); - model.assign_location(id, icu); + model.assign_location(id, hospital, mio::abm::ActivityType::Hospital); + model.assign_location(id, icu, mio::abm::ActivityType::ICU); //assign work/school to people depending on their age if (person.get_age() == age_group_5_to_14) { - model.assign_location(id, school); + model.assign_location(id, school, mio::abm::ActivityType::School); } if (person.get_age() == age_group_15_to_34 || person.get_age() == age_group_35_to_59) { - model.assign_location(id, work); + model.assign_location(id, work, mio::abm::ActivityType::Work); } } diff --git a/cpp/examples/abm_parameter_study.cpp b/cpp/examples/abm_parameter_study.cpp index e3cf55da0a..1f8627532a 100644 --- a/cpp/examples/abm_parameter_study.cpp +++ b/cpp/examples/abm_parameter_study.cpp @@ -91,7 +91,7 @@ mio::abm::Model make_model(const mio::RandomNumberGenerator& rng) // Add one social event with 5 maximum contacts. // Maximum contacts limit the number of people that a person can infect while being at this location. - auto event = model.add_location(mio::abm::LocationType::SocialEvent); + auto event = model.add_location(mio::abm::LocationType::Recreation); model.get_location(event).get_infection_parameters().set(5); // Add hospital and ICU with 5 maximum contacs. auto hospital = model.add_location(mio::abm::LocationType::Hospital); diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index 7050dc89a3..96b10f9316 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -18,6 +18,7 @@ * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/household.h" #include "abm/model.h" #include "abm/infection_state.h" @@ -167,7 +168,7 @@ int main() //Create locations for both models //model 1 - auto event_m1 = model1.add_location(mio::abm::LocationType::SocialEvent); + auto event_m1 = model1.add_location(mio::abm::LocationType::Recreation); model1.get_location(event_m1).get_infection_parameters().set(10); auto hospital_m1 = model1.add_location(mio::abm::LocationType::Hospital); model1.get_location(hospital_m1).get_infection_parameters().set(10); @@ -180,7 +181,7 @@ int main() auto work_m1 = model1.add_location(mio::abm::LocationType::Work); model1.get_location(work_m1).get_infection_parameters().set(10); //model 2 - auto event_m2 = model2.add_location(mio::abm::LocationType::SocialEvent); + auto event_m2 = model2.add_location(mio::abm::LocationType::Recreation); model2.get_location(event_m2).get_infection_parameters().set(10); auto hospital_m2 = model2.add_location(mio::abm::LocationType::Hospital); model2.get_location(hospital_m2).get_infection_parameters().set(10); @@ -206,22 +207,22 @@ int main() person.add_new_infection(mio::abm::Infection(rng, mio::abm::VirusVariant::Wildtype, person.get_age(), model1.parameters, start_date, infection_state)); } - person.set_assigned_location(mio::abm::LocationType::SocialEvent, event_m1, model1.get_id()); - person.set_assigned_location(mio::abm::LocationType::BasicsShop, shop_m1, model1.get_id()); - person.set_assigned_location(mio::abm::LocationType::Hospital, hospital_m1, model1.get_id()); - person.set_assigned_location(mio::abm::LocationType::ICU, icu_m1, model1.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Recreation, event_m1, model1.get_id()); + person.set_assigned_location(mio::abm::ActivityType::BasicsShop, shop_m1, model1.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Hospital, hospital_m1, model1.get_id()); + person.set_assigned_location(mio::abm::ActivityType::ICU, icu_m1, model1.get_id()); if (person.get_age() == age_group_children) { - person.set_assigned_location(mio::abm::LocationType::School, school_m1, model1.get_id()); + person.set_assigned_location(mio::abm::ActivityType::School, school_m1, model1.get_id()); } if (person.get_age() == age_group_adults) { //10% of adults in model 1 work in model 2 size_t work_model = mio::DiscreteDistribution::get_instance()(mio::thread_local_rng(), std::vector{0.9, 0.1}); if (work_model == 1) { //person works in other model - person.set_assigned_location(mio::abm::LocationType::Work, work_m2, model2.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Work, work_m2, model2.get_id()); } else { //person works in same model - person.set_assigned_location(mio::abm::LocationType::Work, work_m1, model1.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Work, work_m1, model1.get_id()); } } } @@ -236,22 +237,22 @@ int main() person.add_new_infection(mio::abm::Infection(rng, mio::abm::VirusVariant::Wildtype, person.get_age(), model2.parameters, start_date, infection_state)); } - person.set_assigned_location(mio::abm::LocationType::SocialEvent, event_m2, model2.get_id()); - person.set_assigned_location(mio::abm::LocationType::BasicsShop, shop_m2, model2.get_id()); - person.set_assigned_location(mio::abm::LocationType::Hospital, hospital_m2, model2.get_id()); - person.set_assigned_location(mio::abm::LocationType::ICU, icu_m2, model2.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Recreation, event_m2, model2.get_id()); + person.set_assigned_location(mio::abm::ActivityType::BasicsShop, shop_m2, model2.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Hospital, hospital_m2, model2.get_id()); + person.set_assigned_location(mio::abm::ActivityType::ICU, icu_m2, model2.get_id()); if (person.get_age() == age_group_children) { - person.set_assigned_location(mio::abm::LocationType::School, school_m2, model2.get_id()); + person.set_assigned_location(mio::abm::ActivityType::School, school_m2, model2.get_id()); } if (person.get_age() == age_group_adults) { //20% of adults in model 2 work in model 1 size_t work_model = mio::DiscreteDistribution::get_instance()(mio::thread_local_rng(), std::vector{0.2, 0.8}); if (work_model == 1) { //person works in same model - person.set_assigned_location(mio::abm::LocationType::Work, work_m2, model2.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Work, work_m2, model2.get_id()); } else { //person works in other model - person.set_assigned_location(mio::abm::LocationType::Work, work_m1, model1.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Work, work_m1, model1.get_id()); } } } diff --git a/cpp/models/abm/CMakeLists.txt b/cpp/models/abm/CMakeLists.txt index ae04b68b2d..28849159c2 100644 --- a/cpp/models/abm/CMakeLists.txt +++ b/cpp/models/abm/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(abm model.cpp model.h location_type.h + activity_type.h parameters.h parameters.cpp mobility_rules.cpp diff --git a/cpp/models/abm/activity_type.h b/cpp/models/abm/activity_type.h new file mode 100644 index 0000000000..891e50e51c --- /dev/null +++ b/cpp/models/abm/activity_type.h @@ -0,0 +1,51 @@ +/* +* Copyright (C) 2020-2026 MEmilio +* +* Authors: Julia Bicker +* +* Contact: Martin J. Kuehn +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MIO_ABM_ACTIVITY_TYPE_H +#define MIO_ABM_ACTIVITY_TYPE_H + +#include + +namespace mio +{ +namespace abm +{ + +/** + * @brief Type of an Activity. This is used to determine the type of an Activity that a Person does at a Location. It is similar to LocationType, but is not necessarily the same as Persons can do different activities at the same location e.g. "Work" and "School" at a Location of LocationType "School". + */ +enum class ActivityType : std::uint32_t +{ + Home = 0, + School, + Work, + Recreation, // TODO: differentiate different kinds + BasicsShop, // groceries and other necessities + Hospital, + ICU, + Cemetery, // Location for all the dead persons. It is created once for the Model. + + Count, //last! + Invalid +}; + +} // namespace abm +} // namespace mio + +#endif diff --git a/cpp/models/abm/common_abm_loggers.h b/cpp/models/abm/common_abm_loggers.h index 0d91c69c24..d7d75c92f5 100644 --- a/cpp/models/abm/common_abm_loggers.h +++ b/cpp/models/abm/common_abm_loggers.h @@ -57,21 +57,21 @@ constexpr mio::abm::ActivityType guess_activity_type(mio::abm::LocationType curr case mio::abm::LocationType::Home: return mio::abm::ActivityType::Home; case mio::abm::LocationType::Work: - return mio::abm::ActivityType::Workplace; + return mio::abm::ActivityType::Work; case mio::abm::LocationType::School: - return mio::abm::ActivityType::Education; - case mio::abm::LocationType::SocialEvent: - return mio::abm::ActivityType::Leisure; + return mio::abm::ActivityType::School; + case mio::abm::LocationType::Recreation: + return mio::abm::ActivityType::Recreation; case mio::abm::LocationType::BasicsShop: - return mio::abm::ActivityType::Shopping; + return mio::abm::ActivityType::BasicsShop; case mio::abm::LocationType::ICU: - return mio::abm::ActivityType::OtherActivity; + return mio::abm::ActivityType::ICU; case mio::abm::LocationType::Hospital: - return mio::abm::ActivityType::OtherActivity; + return mio::abm::ActivityType::Hospital; case mio::abm::LocationType::Cemetery: - return mio::abm::ActivityType::OtherActivity; + return mio::abm::ActivityType::Cemetery; default: - return mio::abm::ActivityType::UnknownActivity; + return mio::abm::ActivityType::Home; } } @@ -126,7 +126,7 @@ struct LogPersonInformation : mio::LogOnce { person_information.reserve(sim.get_model().get_persons().size()); for (auto& person : sim.get_model().get_persons()) { person_information.push_back(std::make_tuple( - person.get_id(), sim.get_model().find_location(mio::abm::LocationType::Home, person.get_id()), + person.get_id(), sim.get_model().find_locations(mio::abm::ActivityType::Home, person.get_id())[0], person.get_age())); } return person_information; diff --git a/cpp/models/abm/household.cpp b/cpp/models/abm/household.cpp index e234aaff58..984f483358 100755 --- a/cpp/models/abm/household.cpp +++ b/cpp/models/abm/household.cpp @@ -19,6 +19,7 @@ */ #include "abm/household.h" +#include "abm/activity_type.h" #include "abm/person_id.h" #include "abm/location.h" #include "memilio/utils/random_number_generator.h" @@ -69,8 +70,8 @@ void add_household_to_model(Model& model, const Household& household) std::tie(member, count) = memberTouple; for (int j = 0; j < count; j++) { auto age_group = pick_age_group_from_age_distribution(model.get_rng(), member.get_age_weights()); - auto person = model.add_person(home, age_group); - model.assign_location(person, home); + auto person = model.add_person(home, age_group, ActivityType::Home); + model.assign_location(person, home, ActivityType::Home); } } } diff --git a/cpp/models/abm/location_type.h b/cpp/models/abm/location_type.h index 93b601c438..8f146cadbd 100644 --- a/cpp/models/abm/location_type.h +++ b/cpp/models/abm/location_type.h @@ -34,8 +34,9 @@ enum class LocationType : std::uint32_t { Home = 0, School, - Work, - SocialEvent, // TODO: differentiate different kinds + Office, + Work, // other workplaces than offices, e.g. factories + Recreation, // TODO: differentiate different kinds BasicsShop, // groceries and other necessities Hospital, ICU, diff --git a/cpp/models/abm/mobility_data.h b/cpp/models/abm/mobility_data.h index a192589d2a..0d19d46a52 100644 --- a/cpp/models/abm/mobility_data.h +++ b/cpp/models/abm/mobility_data.h @@ -43,20 +43,20 @@ enum class TransportMode : uint32_t Count //last!! }; -/** - * @brief Type of the activity. - */ -enum class ActivityType : uint32_t -{ - Workplace, - Education, - Shopping, - Leisure, - PrivateMatters, - OtherActivity, - Home, - UnknownActivity -}; +// /** +// * @brief Type of the activity. +// */ +// enum class ActivityType : uint32_t +// { +// Workplace, +// Education, +// Shopping, +// Leisure, +// PrivateMatters, +// OtherActivity, +// Home, +// UnknownActivity +// }; } // namespace abm } // namespace mio diff --git a/cpp/models/abm/mobility_rules.cpp b/cpp/models/abm/mobility_rules.cpp index 60d1946c5d..29f223a618 100644 --- a/cpp/models/abm/mobility_rules.cpp +++ b/cpp/models/abm/mobility_rules.cpp @@ -18,6 +18,7 @@ * limitations under the License. */ #include "abm/mobility_rules.h" +#include "abm/activity_type.h" #include "abm/person.h" #include "abm/random_events.h" #include "abm/location_type.h" @@ -28,151 +29,150 @@ namespace mio namespace abm { -LocationType random_mobility(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, +ActivityType random_mobility(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, const Parameters& params) { - auto current_loc = person.get_location_type(); + auto current_loc = person.get_activity_type(); auto make_transition = [current_loc](auto l) { return std::make_pair(l, l == current_loc ? 0. : 1.); }; if (t < params.get()) { return random_transition(rng, current_loc, dt, - {make_transition(LocationType::Work), make_transition(LocationType::Home), - make_transition(LocationType::School), make_transition(LocationType::SocialEvent), - make_transition(LocationType::BasicsShop)}); + {make_transition(ActivityType::Work), make_transition(ActivityType::Home), + make_transition(ActivityType::School), make_transition(ActivityType::Recreation), + make_transition(ActivityType::BasicsShop)}); } return current_loc; } -LocationType go_to_school(PersonalRandomNumberGenerator& /*rng*/, const Person& person, TimePoint t, TimeSpan dt, +ActivityType go_to_school(PersonalRandomNumberGenerator& /*rng*/, const Person& person, TimePoint t, TimeSpan dt, const Parameters& params) { - auto current_loc = person.get_location_type(); + auto current_loc = person.get_activity_type(); - if (current_loc == LocationType::Home && t < params.get() && t.day_of_week() < 5 && + if (current_loc == ActivityType::Home && t < params.get() && t.day_of_week() < 5 && person.get_go_to_school_time(params) >= t.time_since_midnight() && person.get_go_to_school_time(params) < t.time_since_midnight() + dt && params.get()[person.get_age()] && person.goes_to_school(t, params) && !person.is_in_quarantine(t, params)) { - return LocationType::School; + return ActivityType::School; } //return home - if (current_loc == LocationType::School && t.hour_of_day() >= 15) { - return LocationType::Home; + if (current_loc == ActivityType::School && t.hour_of_day() >= 15) { + return ActivityType::Home; } return current_loc; } -LocationType go_to_work(PersonalRandomNumberGenerator& /*rng*/, const Person& person, TimePoint t, TimeSpan dt, +ActivityType go_to_work(PersonalRandomNumberGenerator& /*rng*/, const Person& person, TimePoint t, TimeSpan dt, const Parameters& params) { - auto current_loc = person.get_location_type(); + auto current_loc = person.get_activity_type(); - if (current_loc == LocationType::Home && t < params.get() && + if (current_loc == ActivityType::Home && t < params.get() && params.get()[person.get_age()] && t.day_of_week() < 5 && t.time_since_midnight() + dt > person.get_go_to_work_time(params) && t.time_since_midnight() <= person.get_go_to_work_time(params) && person.goes_to_work(t, params) && !person.is_in_quarantine(t, params)) { - return LocationType::Work; + return ActivityType::Work; } //return home - if (current_loc == LocationType::Work && t.hour_of_day() >= 17) { - return LocationType::Home; + if (current_loc == ActivityType::Work && t.hour_of_day() >= 17) { + return ActivityType::Home; } return current_loc; } -LocationType go_to_shop(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, +ActivityType go_to_shop(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, const Parameters& params) { - auto current_loc = person.get_location_type(); + auto current_loc = person.get_activity_type(); //leave - if (t.day_of_week() < 6 && t.hour_of_day() > 7 && t.hour_of_day() < 22 && current_loc == LocationType::Home && + if (t.day_of_week() < 6 && t.hour_of_day() > 7 && t.hour_of_day() < 22 && current_loc == ActivityType::Home && !person.is_in_quarantine(t, params)) { return random_transition(rng, current_loc, dt, - {{LocationType::BasicsShop, params.get()[person.get_age()]}}); + {{ActivityType::BasicsShop, params.get()[person.get_age()]}}); } //return home - if (current_loc == LocationType::BasicsShop && person.get_time_at_location() >= hours(1)) { - return LocationType::Home; + if (current_loc == ActivityType::BasicsShop && person.get_time_at_location() >= hours(1)) { + return ActivityType::Home; } return current_loc; } -LocationType go_to_event(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, - const Parameters& params) +ActivityType go_to_recreation(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, + const Parameters& params) { - auto current_loc = person.get_location_type(); + auto current_loc = person.get_activity_type(); //leave - if (current_loc == LocationType::Home && t < params.get() && + if (current_loc == ActivityType::Home && t < params.get() && ((t.day_of_week() <= 4 && t.hour_of_day() >= 19 && t.hour_of_day() < 22) || (t.day_of_week() >= 5 && t.hour_of_day() >= 10 && t.hour_of_day() < 22)) && !person.is_in_quarantine(t, params)) { return random_transition( rng, current_loc, dt, - {{LocationType::SocialEvent, params.get().get_matrix_at( - SimulationTime(t.days()))[(size_t)person.get_age()]}}); + {{ActivityType::Recreation, params.get().get_matrix_at( + SimulationTime(t.days()))[(size_t)person.get_age()]}}); } //return home - if (current_loc == LocationType::SocialEvent && t.hour_of_day() >= 20 && - person.get_time_at_location() >= hours(2)) { - return LocationType::Home; + if (current_loc == ActivityType::Recreation && t.hour_of_day() >= 20 && person.get_time_at_location() >= hours(2)) { + return ActivityType::Home; } return current_loc; } -LocationType go_to_quarantine(PersonalRandomNumberGenerator& /*rng*/, const Person& person, TimePoint t, +ActivityType go_to_quarantine(PersonalRandomNumberGenerator& /*rng*/, const Person& person, TimePoint t, TimeSpan /*dt*/, const Parameters& params) { - auto current_loc = person.get_location_type(); - if (person.is_in_quarantine(t, params) && current_loc != LocationType::Hospital && - current_loc != LocationType::ICU) { - return LocationType::Home; + auto current_loc = person.get_activity_type(); + if (person.is_in_quarantine(t, params) && current_loc != ActivityType::Hospital && + current_loc != ActivityType::ICU) { + return ActivityType::Home; } return current_loc; } -LocationType go_to_hospital(PersonalRandomNumberGenerator& /*rng*/, const Person& person, const TimePoint t, +ActivityType go_to_hospital(PersonalRandomNumberGenerator& /*rng*/, const Person& person, const TimePoint t, TimeSpan /*dt*/, const Parameters& /*params*/) { - auto current_loc = person.get_location_type(); + auto current_loc = person.get_activity_type(); if (person.get_infection_state(t) == InfectionState::InfectedSevere) { - return LocationType::Hospital; + return ActivityType::Hospital; } return current_loc; } -LocationType go_to_icu(PersonalRandomNumberGenerator& /*rng*/, const Person& person, const TimePoint t, TimeSpan /*dt*/, +ActivityType go_to_icu(PersonalRandomNumberGenerator& /*rng*/, const Person& person, const TimePoint t, TimeSpan /*dt*/, const Parameters& /*params*/) { - auto current_loc = person.get_location_type(); + auto current_loc = person.get_activity_type(); if (person.get_infection_state(t) == InfectionState::InfectedCritical) { - return LocationType::ICU; + return ActivityType::ICU; } return current_loc; } -LocationType return_home_when_recovered(PersonalRandomNumberGenerator& /*rng*/, const Person& person, const TimePoint t, +ActivityType return_home_when_recovered(PersonalRandomNumberGenerator& /*rng*/, const Person& person, const TimePoint t, TimeSpan /*dt*/, const Parameters& /*params*/) { - auto current_loc = person.get_location_type(); - if ((current_loc == LocationType::Hospital || current_loc == LocationType::ICU) && + auto current_loc = person.get_activity_type(); + if ((current_loc == ActivityType::Hospital || current_loc == ActivityType::ICU) && person.get_infection_state(t) == InfectionState::Recovered) { - return LocationType::Home; + return ActivityType::Home; } return current_loc; } -LocationType get_buried(PersonalRandomNumberGenerator& /*rng*/, const Person& person, const TimePoint t, +ActivityType get_buried(PersonalRandomNumberGenerator& /*rng*/, const Person& person, const TimePoint t, TimeSpan /*dt*/, const Parameters& /*params*/) { - auto current_loc = person.get_location_type(); + auto current_loc = person.get_activity_type(); if (person.get_infection_state(t) == InfectionState::Dead) { - return LocationType::Cemetery; + return ActivityType::Cemetery; } return current_loc; } diff --git a/cpp/models/abm/mobility_rules.h b/cpp/models/abm/mobility_rules.h index 98dd9e250e..a531d3de04 100644 --- a/cpp/models/abm/mobility_rules.h +++ b/cpp/models/abm/mobility_rules.h @@ -20,7 +20,8 @@ #ifndef MIO_ABM_MOBILITY_RULES_H #define MIO_ABM_MOBILITY_RULES_H -#include "abm/location_type.h" +#include "abm/activity_type.h" +#include "abm/activity_type.h" #include "abm/parameters.h" #include "abm/time.h" #include "abm/person.h" @@ -45,61 +46,61 @@ namespace abm /** * @brief Completely random mobility to any other Location. */ -LocationType random_mobility(PersonalRandomNumberGenerator& rng, const Person& p, TimePoint t, TimeSpan dt, +ActivityType random_mobility(PersonalRandomNumberGenerator& rng, const Person& p, TimePoint t, TimeSpan dt, const Parameters& params); /** * @brief School age children go to school in the morning and return later in the day. */ -LocationType go_to_school(PersonalRandomNumberGenerator& rng, const Person& p, TimePoint t, TimeSpan dt, +ActivityType go_to_school(PersonalRandomNumberGenerator& rng, const Person& p, TimePoint t, TimeSpan dt, const Parameters& params); /** * @brief Adults may go shopping in their free time. */ -LocationType go_to_shop(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, +ActivityType go_to_shop(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, const Parameters& params); /** * @brief Person%s might go to social events. */ -LocationType go_to_event(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, - const Parameters& params); +ActivityType go_to_recreation(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, + const Parameters& params); /** * @brief Adults go to work in the morning and return later in the day. */ -LocationType go_to_work(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, +ActivityType go_to_work(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, const Parameters& params); /** * @brief Person%s who are in quarantine should go home. */ -LocationType go_to_quarantine(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint /*t*/, +ActivityType go_to_quarantine(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint /*t*/, TimeSpan /*dt*/, const Parameters& /*params*/); /** * @brief Infected Person%s may be hospitalized. */ -LocationType go_to_hospital(PersonalRandomNumberGenerator& rng, const Person& p, TimePoint t, TimeSpan dt, +ActivityType go_to_hospital(PersonalRandomNumberGenerator& rng, const Person& p, TimePoint t, TimeSpan dt, const Parameters& params); /** * @brief Person%s in the hospital may be put in intensive care. */ -LocationType go_to_icu(PersonalRandomNumberGenerator& rng, const Person& p, TimePoint t, TimeSpan dt, +ActivityType go_to_icu(PersonalRandomNumberGenerator& rng, const Person& p, TimePoint t, TimeSpan dt, const Parameters& params); /** * @brief Person%s in the hospital/icu return home when they recover. */ -LocationType return_home_when_recovered(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, +ActivityType return_home_when_recovered(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, const Parameters& params); /** * @brief Person%s in the icu go to cemetery when they are dead. */ -LocationType get_buried(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, +ActivityType get_buried(PersonalRandomNumberGenerator& rng, const Person& person, TimePoint t, TimeSpan dt, const Parameters& params); /**@}*/ diff --git a/cpp/models/abm/model.cpp b/cpp/models/abm/model.cpp index a886edde98..bee1f134fd 100755 --- a/cpp/models/abm/model.cpp +++ b/cpp/models/abm/model.cpp @@ -18,6 +18,7 @@ * limitations under the License. */ #include "abm/model.h" +#include "abm/activity_type.h" #include "abm/location_id.h" #include "abm/location_type.h" #include "abm/intervention_type.h" @@ -52,10 +53,10 @@ LocationId Model::add_location(LocationType type, uint32_t num_cells) return id; } -PersonId Model::add_person(const LocationId id, AgeGroup age) +PersonId Model::add_person(const LocationId id, AgeGroup age, ActivityType activity_type) { PersonId person_id = (static_cast(m_id)) << 32 | static_cast(m_persons.size()); - return add_person(Person(m_rng, get_location(id).get_type(), id, m_id, age, person_id)); + return add_person(Person(m_rng, get_location(id).get_type(), activity_type, id, m_id, age, person_id)); } PersonId Model::add_person(Person&& person) @@ -65,7 +66,7 @@ PersonId Model::add_person(Person&& person) "Added Person's location is not in Model."); assert(person.get_id() != PersonId::invalid_ID() && "Added Person's unique id must be valid."); assert(person.get_age() < (AgeGroup)parameters.get_num_groups() && "Added Person's AgeGroup is too large."); - person.set_assigned_location(LocationType::Cemetery, m_cemetery_id, m_id); + person.set_assigned_location(ActivityType::Cemetery, m_cemetery_id, m_id); m_persons.emplace_back(person); m_activeness_statuses.push_back(true); auto& new_person = m_persons.back(); @@ -113,8 +114,9 @@ void Model::perform_mobility(TimePoint t, TimeSpan dt) auto try_mobility_rule = [&](auto rule) -> bool { // run mobility rule and check if change of location can actually happen auto target_type = rule(personal_rng, person, t, dt, parameters); - if (person.get_assigned_location_model_id(target_type) == m_id) { - const Location& target_location = get_location(find_location(target_type, person)); + auto target = person.get_assigned_location(target_type, personal_rng); + if (target.second == m_id) { + const Location& target_location = get_location(target.first); const LocationId current_location = person.get_location(); // the Person cannot move if they do not wear mask as required at targeted location @@ -127,11 +129,10 @@ void Model::perform_mobility(TimePoint t, TimeSpan dt) get_number_persons(target_location.get_id()) >= target_location.get_capacity().persons) { return false; } - // The person cannot move if he has a positive test result, except he want to go to a hospital, ICU or home. + // The person cannot move if he has a positive test result, except he want to go to a hospital, ICU (as a patient) or home. if (!m_testing_strategy.run_and_check(personal_rng, person, target_location, t) && - target_location.get_type() != LocationType::Hospital && - target_location.get_type() != LocationType::ICU && - target_location.get_type() != LocationType::Home) { + target_type != ActivityType::Hospital && target_type != ActivityType::ICU && + target_type != ActivityType::Home) { return false; } @@ -147,7 +148,7 @@ void Model::perform_mobility(TimePoint t, TimeSpan dt) person.set_mask(MaskType::None, t); } // all requirements are met, move to target location - change_location(person, target_location.get_id()); + change_location(person, target_location.get_id(), target_type); return true; } return false; @@ -163,8 +164,8 @@ void Model::perform_mobility(TimePoint t, TimeSpan dt) (has_locations({LocationType::School, LocationType::Home}) && try_mobility_rule(&go_to_school)) || (has_locations({LocationType::Work, LocationType::Home}) && try_mobility_rule(&go_to_work)) || (has_locations({LocationType::BasicsShop, LocationType::Home}) && try_mobility_rule(&go_to_shop)) || - (has_locations({LocationType::SocialEvent, LocationType::Home}) && - try_mobility_rule(&go_to_event)) || + (has_locations({LocationType::Recreation, LocationType::Home}) && + try_mobility_rule(&go_to_recreation)) || (has_locations({LocationType::Home}) && try_mobility_rule(&go_to_quarantine)); } else { @@ -203,7 +204,7 @@ void Model::perform_mobility(TimePoint t, TimeSpan dt) continue; } // all requirements are met, move to target location - change_location(person, target_location.get_id(), trip.trip_mode); + change_location(person, target_location.get_id(), trip.activity, trip.trip_mode); // update worn mask to target location's requirements if (target_location.is_mask_required()) { // if the current MaskProtection level is lower than required, the Person changes mask @@ -373,9 +374,9 @@ auto Model::get_activeness_statuses() -> Range return {m_activeness_statuses}; } -LocationId Model::find_location(LocationType type, const PersonId person) const +std::vector Model::find_locations(ActivityType type, const PersonId person) const { - return find_location(type, get_person(person)); + return find_locations(type, get_person(person)); } size_t Model::get_subpopulation_combined(TimePoint t, InfectionState s) const diff --git a/cpp/models/abm/model.h b/cpp/models/abm/model.h index 90fff62025..b2250aa3c5 100644 --- a/cpp/models/abm/model.h +++ b/cpp/models/abm/model.h @@ -20,6 +20,7 @@ #ifndef MIO_ABM_MODEL_H #define MIO_ABM_MODEL_H +#include "abm/activity_type.h" #include "abm/infection_state.h" #include "abm/model_functions.h" #include "abm/location_type.h" @@ -38,6 +39,7 @@ #include "memilio/utils/stl_util.h" #include +#include #include #include @@ -59,8 +61,8 @@ class Model using ConstPersonIterator = std::vector::const_iterator; using ActivenessIterator = std::vector::iterator; using ConstActivenessIterator = std::vector::const_iterator; - using MobilityRuleType = LocationType (*)(PersonalRandomNumberGenerator&, const Person&, TimePoint, TimeSpan, - const Parameters&); + using MobilityRuleType = ActivityType (*)(PersonalRandomNumberGenerator&, const Person&, TimePoint, TimeSpan, + const Parameters&); using Compartments = mio::abm::InfectionState; /** @@ -203,9 +205,10 @@ class Model * @brief Add a Person to the Model. * @param[in] id The LocationID of the initial Location of the Person. * @param[in] age AgeGroup of the person. + * @param[in] activity_type The ActivityType the Person does at its initial Location. * @return Id of the newly created Person. */ - PersonId add_person(const LocationId id, AgeGroup age); + PersonId add_person(const LocationId id, AgeGroup age, ActivityType activity_type); /** * @brief Adds a copy of a given Person to the Model. @@ -242,12 +245,12 @@ class Model /** @} */ /** - * @brief Find an assigned Location of a Person. - * @param[in] type The #LocationType that specifies the assigned Location. + * @brief Find an all assigned Locations of a Person for a certain ActivityType. + * @param[in] type The ActivityType that specifies the assigned Locations. * @param[in] person Id of the Person. - * @return ID of the Location of LocationType type assigend to person. + * @return IDs of the Locations of ActivityType type assigend to person. */ - LocationId find_location(LocationType type, const PersonId person) const; + std::vector find_locations(ActivityType type, const PersonId person) const; /** * @brief Assign a Location to a Person. @@ -255,10 +258,11 @@ class Model * Assigning another Location of an already assigned LocationType will replace the prior assignment. * @param[in] person The Id of the person this location will be assigned to. * @param[in] location The LocationId of the Location. + * @param[in] activity The ActivityType the person does at the Location. */ - void assign_location(PersonId person, LocationId location) + void assign_location(PersonId person, LocationId location, ActivityType activity) { - assign_location(get_person(person), location); + assign_location(get_person(person), location, activity); } /** @@ -445,10 +449,10 @@ class Model * @param[in] mode The transport mode the person uses to change the Location. * @param[in] cells The cells within the destination the person should be in. */ - inline void change_location(PersonId person, LocationId destination, TransportMode mode = TransportMode::Unknown, - const std::vector& cells = {0}) + inline void change_location(PersonId person, LocationId destination, ActivityType activity, + TransportMode mode = TransportMode::Unknown, const std::vector& cells = {0}) { - change_location(get_person(person), destination, mode, cells); + change_location(get_person(person), destination, activity, mode, cells); } /** @@ -481,10 +485,11 @@ class Model * Assigning another Location of an already assigned LocationType will replace the prior assignment. * @param[in] person reference to the Person the location will be assigned to. * @param[in] location The LocationId of the Location. + * @param[in] activity The ActivityType the person does at the Location. */ - void assign_location(Person& person, LocationId location) + void assign_location(Person& person, LocationId location, ActivityType activity) { - person.set_assigned_location(get_location(location).get_type(), location, m_id); + person.set_assigned_location(activity, location, m_id); } Location& get_location(LocationId id) @@ -570,12 +575,13 @@ class Model * @param[in] mode The transport mode the person uses to change the Location. * @param[in] cells The cells within the destination the person should be in. */ - inline void change_location(Person& person, LocationId destination, TransportMode mode = TransportMode::Unknown, - const std::vector& cells = {0}) + inline void change_location(Person& person, LocationId destination, ActivityType activity, + TransportMode mode = TransportMode::Unknown, const std::vector& cells = {0}) { - LocationId origin = get_location(person).get_id(); - auto old_cells = person.get_cells(); - const bool has_changed_location = mio::abm::change_location(person, get_location(destination), mode, cells); + LocationId origin = get_location(person).get_id(); + auto old_cells = person.get_cells(); + const bool has_changed_location = + mio::abm::change_location(person, get_location(destination), activity, mode, cells); // if the person has changed location, invalidate exposure caches but keep population caches valid if (has_changed_location) { m_are_exposure_caches_valid = false; @@ -611,16 +617,16 @@ class Model } /** - * @brief Find an assigned Location of a Person. - * @param[in] type The #LocationType that specifies the assigned Location. + * @brief Find an assigned Locations of a Person. + * @param[in] type The ActivityType that specifies the assigned Locations. * @param[in] person Reference to Person. - * @return ID of the Location of LocationType type assigend to person. + * @return IDs of the Locations of ActivityType type assigend to person. */ - LocationId find_location(LocationType type, const Person& person) const + std::vector find_locations(ActivityType type, const Person& person) const { - auto location_id = person.get_assigned_location(type); - assert(location_id != LocationId::invalid_id() && "The person has no assigned location of that type."); - return location_id; + auto location_ids = person.get_assigned_locations()[static_cast(type)]; + assert(!location_ids.empty() && "The person has no assigned location of that type."); + return location_ids; } /** diff --git a/cpp/models/abm/model_functions.cpp b/cpp/models/abm/model_functions.cpp index 7529590521..c56f30bf39 100644 --- a/cpp/models/abm/model_functions.cpp +++ b/cpp/models/abm/model_functions.cpp @@ -19,6 +19,7 @@ */ #include "abm/model_functions.h" +#include "abm/activity_type.h" #include "abm/location.h" #include "abm/person.h" #include "abm/random_events.h" @@ -159,7 +160,7 @@ void normalize_exposure_contribution(ContactExposureRates& local_contact_exposur } } -bool change_location(Person& person, const Location& destination, const TransportMode mode, +bool change_location(Person& person, const Location& destination, ActivityType activity, const TransportMode mode, const std::vector& cells) { assert(std::all_of(cells.begin(), cells.end(), [&](const auto& cell) { @@ -167,7 +168,7 @@ bool change_location(Person& person, const Location& destination, const Transpor })); // make sure cell indices are valid if (person.get_location() != destination.get_id()) { - person.set_location(destination.get_type(), destination.get_id(), destination.get_model_id()); + person.set_location(activity, destination.get_type(), destination.get_id(), destination.get_model_id()); person.get_cells() = cells; person.set_last_transport_mode(mode); diff --git a/cpp/models/abm/model_functions.h b/cpp/models/abm/model_functions.h index 3b0bdbf462..e8bc2d5710 100644 --- a/cpp/models/abm/model_functions.h +++ b/cpp/models/abm/model_functions.h @@ -101,12 +101,13 @@ void interact(PersonalRandomNumberGenerator& personal_rng, Person& person, const * If the person already is at the destination, neither mode nor cells are set. * @param[in, out] person The person to change location. * @param[in] destination The destination to change location to. + * @param[in] activity The ActivityType the person does at the destination. * @param[in] mode The transport mode the person uses to change location. * @param[in] cells The cells within the destination the person should be in. * @return Returns false if the person already is at the given destination, true otherwise. */ -bool change_location(Person& person, const Location& destination, const TransportMode mode = TransportMode::Unknown, - const std::vector& cells = {0}); +bool change_location(Person& person, const Location& destination, ActivityType activity, + const TransportMode mode = TransportMode::Unknown, const std::vector& cells = {0}); /** * @brief Adjust ContactRates of location by MaximumContacts. diff --git a/cpp/models/abm/person.cpp b/cpp/models/abm/person.cpp index 19a66aec99..765e0f3db0 100755 --- a/cpp/models/abm/person.cpp +++ b/cpp/models/abm/person.cpp @@ -18,6 +18,7 @@ * limitations under the License. */ #include "abm/person.h" +#include "abm/activity_type.h" #include "abm/location_type.h" #include "abm/mask_type.h" #include "abm/parameters.h" @@ -25,6 +26,7 @@ #include "abm/location.h" #include "abm/person_id.h" #include "memilio/utils/random_number_generator.h" +#include #include #include @@ -33,12 +35,13 @@ namespace mio namespace abm { -Person::Person(mio::RandomNumberGenerator& rng, LocationType location_type, LocationId location_id, - int location_model_id, AgeGroup age, PersonId person_id) +Person::Person(mio::RandomNumberGenerator& rng, LocationType location_type, ActivityType activity_type, + LocationId location_id, int location_model_id, AgeGroup age, PersonId person_id) : m_location(location_id) , m_location_type(location_type) + , m_activity_type(activity_type) , m_location_model_id(location_model_id) - , m_assigned_locations((uint32_t)LocationType::Count, LocationId::invalid_id()) + , m_assigned_locations((uint32_t)ActivityType::Count) , m_home_isolation_start(TimePoint(-(std::numeric_limits::max() / 2))) , m_age(age) , m_time_at_location(0) @@ -95,10 +98,11 @@ LocationId Person::get_location() const return m_location; } -void Person::set_location(LocationType type, LocationId id, int model_id) +void Person::set_location(ActivityType type, LocationType location_type, LocationId id, int model_id) { m_location = id; - m_location_type = type; + m_location_type = location_type; + m_activity_type = type; m_location_model_id = model_id; m_time_at_location = TimeSpan(0); } @@ -113,20 +117,18 @@ Infection& Person::get_infection() return m_infections.back(); } -void Person::set_assigned_location(LocationType type, LocationId id, int model_id = 0) +void Person::set_assigned_location(ActivityType type, LocationId id, int model_id = 0) { - m_assigned_locations[static_cast(type)] = id; - m_assigned_location_model_ids[static_cast(type)] = model_id; + m_assigned_locations[static_cast(type)].push_back(id); + m_assigned_location_model_ids[static_cast(type)].push_back(model_id); } -LocationId Person::get_assigned_location(LocationType type) const +std::pair Person::get_assigned_location(ActivityType type, PersonalRandomNumberGenerator& rng) const { - return m_assigned_locations[static_cast(type)]; -} - -int Person::get_assigned_location_model_id(LocationType type) const -{ - return m_assigned_location_model_ids[static_cast(type)]; + size_t index = UniformIntDistribution::get_instance()( + rng, size_t(0), m_assigned_locations[static_cast(type)].size() - 1); + return {m_assigned_locations[static_cast(type)][index], + m_assigned_location_model_ids[static_cast(type)][index]}; } bool Person::goes_to_work(TimePoint t, const Parameters& params) const diff --git a/cpp/models/abm/person.h b/cpp/models/abm/person.h index e1cea60230..c799974528 100755 --- a/cpp/models/abm/person.h +++ b/cpp/models/abm/person.h @@ -24,6 +24,7 @@ #include "abm/infection_state.h" #include "abm/location_id.h" #include "abm/location_type.h" +#include "abm/activity_type.h" #include "abm/parameters.h" #include "abm/person_id.h" #include "abm/personal_rng.h" @@ -57,8 +58,9 @@ class Person * @param[in] person_index Index of the Person. * */ - explicit Person(mio::RandomNumberGenerator& rng, LocationType location_type, LocationId location_id, - int location_model_id, AgeGroup age, PersonId person_id = PersonId::invalid_ID()); + explicit Person(mio::RandomNumberGenerator& rng, LocationType location_type, ActivityType activity_type, + LocationId location_id, int location_model_id, AgeGroup age, + PersonId person_id = PersonId::invalid_ID()); explicit Person(const Person& other, PersonId person_id); @@ -128,11 +130,27 @@ class Person */ LocationId get_location() const; + /** + * @brief Get the LocationType of the current Location of the Person. + * @return LocationType of the current Location of the Person. + */ LocationType get_location_type() const { return m_location_type; } + /** + * @brief Get the ActivityType the Person does at its current Location. + * @return ActivityType of the current Location of the Person. + */ + ActivityType get_activity_type() const + { + return m_activity_type; + } + + /** + * @brief Get the model id of the current Location of the Person. Only used for Graph ABM. + */ int get_location_model_id() const { return m_location_model_id; @@ -140,11 +158,12 @@ class Person /** * @brief Change the location of the person. - * @param[in] type The LocationType of the new Location. + * @param[in] type The ActivityType the Person does at the new Location. + * @param[in] location_type The LocationType of the new Location. * @param[in] id The LocationId of the new Location. * @param[in] model_id The model id of the new Location. */ - void set_location(LocationType type, LocationId id, int model_id); + void set_location(ActivityType type, LocationType location_type, LocationId id, int model_id); /** * @brief Get the time the Person has been at its current Location. @@ -170,44 +189,35 @@ class Person * Important: Setting incorrect values will cause issues during simulation. It is preferable to use * Model::assign_location with a valid LocationId, obtained e.g. through Model::add_location. * - * The assigned Location is saved by the index of its LocationId. Assume that a Person has at most one assigned - * Location of a certain #LocationType. - * @param[in] type The LocationType of the Location. + * The assigned Location is saved by the index of its LocationId. + * @param[in] type The ActivityType the Person does at the Location. * @param[in] id The LocationId of the Location. * @param[in] model_id The model id of the Location. */ - void set_assigned_location(LocationType type, LocationId id, int model_id); + void set_assigned_location(ActivityType type, LocationId id, int model_id); /** - * @brief Returns the index of an assigned Location of the Person. - * Assume that a Person has at most one assigned Location of a certain #LocationType. - * @param[in] type #LocationType of the assigned Location. - * @return The index in the LocationId of the assigned Location. + * @brief Returns the index of an assigned Location of the Person. The index is uniformly sampled from the LocationIds of the assigned ActivityType. + * @param[in] type #ActivityType of the assigned Location. + * @param[in] rng RandomNumberGenerator for sampling the index of the assigned LocationId. + * @return The index in the LocationId and the model id of the assigned Location. */ - LocationId get_assigned_location(LocationType type) const; + std::pair get_assigned_location(ActivityType type, PersonalRandomNumberGenerator& rng) const; /** * @brief Get the assigned Location%s of the Person. * @return A vector with the indices of the assigned Location%s of the Person. */ - const std::vector& get_assigned_locations() const + const std::vector>& get_assigned_locations() const { return m_assigned_locations; } - /** - * @brief Returns the model id of an assigned location of the Person. - * Assume that a Person has at most one assigned Location of a certain #LocationType. - * @param[in] type #LocationType of the assigned Location. - * @return The model id of the assigned Location. - */ - int get_assigned_location_model_id(LocationType type) const; - /** * @brief Get the assigned locations' model ids of the Person. * @return A vector with the model ids of the assigned locations of the Person */ - const std::vector& get_assigned_location_model_ids() const + const std::vector>& get_assigned_location_model_ids() const { return m_assigned_location_model_ids; } @@ -446,9 +456,11 @@ class Person private: LocationId m_location; ///< Current Location of the Person. - LocationType m_location_type; ///< Type of the current Location. + LocationType m_location_type; ///< LocationType of the current Location. + ActivityType m_activity_type; ///< ActivityType the Person does at the current Location. int m_location_model_id; ///< Model id of the current Location. Only used for Graph ABM. - std::vector m_assigned_locations; /**! Vector with the indices of the assigned Locations so that the + std::vector> + m_assigned_locations; /**! Vector with the indices of the assigned Locations so that the Person always visits the same Home or School etc. */ std::vector m_vaccinations; ///< Vector with all vaccinations the Person has received. std::vector m_infections; ///< Vector with all Infection%s the Person had. @@ -467,7 +479,7 @@ class Person std::vector m_cells; ///< Vector with all Cell%s the Person visits at its current Location. mio::abm::TransportMode m_last_transport_mode; ///< TransportMode the Person used to get to its current Location. CustomIndexArray m_test_results; ///< CustomIndexArray for TestResults. - std::vector + std::vector> m_assigned_location_model_ids; ///< Vector with model ids of the assigned locations. Only used in graph abm. PersonId m_person_id; ///< Unique identifier of a person. Counter m_rng_counter{0}; ///< counter for RandomNumberGenerator. @@ -480,8 +492,8 @@ template <> struct DefaultFactory { static abm::Person create() { - return abm::Person(thread_local_rng(), abm::LocationType::Count, abm::LocationId(), 0, AgeGroup(0), - abm::PersonId()); + return abm::Person(thread_local_rng(), abm::LocationType::Count, abm::ActivityType::Count, abm::LocationId(), 0, + AgeGroup(0), abm::PersonId()); } }; diff --git a/cpp/models/abm/trip_list.h b/cpp/models/abm/trip_list.h index 0ffc03d93d..f244db7c67 100644 --- a/cpp/models/abm/trip_list.h +++ b/cpp/models/abm/trip_list.h @@ -20,6 +20,7 @@ #ifndef MIO_ABM_TRIP_LIST_H #define MIO_ABM_TRIP_LIST_H +#include "abm/activity_type.h" #include "abm/location_id.h" #include "abm/mobility_data.h" #include "abm/person.h" @@ -44,6 +45,7 @@ struct Trip { Model, where all Person%s are saved.*/ TimePoint trip_time; ///< Daytime at which a Person changes the Location. LocationId destination; ///< Location where the Person changes to. + ActivityType activity; ///< Activity the person does at the destination location. int destination_model_id; ///< Model id of destination Location. TransportMode trip_mode; ///< Mode of transportation. See TransportMode for all possible modes of transportation. std::vector cells; /**< If destination consists of different Cell%s, this gives the index of the @@ -54,17 +56,19 @@ struct Trip { * @param[in] id ID of the Person that makes the Trip. * @param[in] time Time at which a Person changes the Location this currently cant be set for s specific day just a timepoint in a day. * @param[in] destination Location where the Person changes to. - * @param[in] destination_model_id Model the Person changes to. + * @param[in] actvty Activity the person does at the destination location. + * @param[in] dest_model_id Model the Person changes to. * @param[in] origin Location where the person starts the Trip. * @param[in] origin_model_id Model the Person starts the Trip. * @param[in] input_cells The index of the Cell%s the Person changes to. */ - Trip(PersonId id, const TimePoint time, const LocationId dest, const int dest_model_id = 0, + Trip(PersonId id, const TimePoint time, const LocationId dest, ActivityType actvty, const int dest_model_id = 0, const TransportMode mode_of_transport = mio::abm::TransportMode::Unknown, const std::vector& input_cells = {}) : person_id(id) , trip_time(mio::abm::TimePoint(time.time_since_midnight().seconds())) , destination(dest) + , activity(actvty) , destination_model_id(dest_model_id) , trip_mode(mode_of_transport) , cells(input_cells) @@ -78,7 +82,8 @@ struct Trip { bool operator==(const Trip& other) const { return (person_id == other.person_id) && (trip_time == other.trip_time) && (destination == other.destination) && - (destination_model_id == other.destination_model_id) && (trip_mode == other.trip_mode); + (activity == other.activity) && (destination_model_id == other.destination_model_id) && + (trip_mode == other.trip_mode); } auto default_serialize() @@ -87,6 +92,7 @@ struct Trip { .add("person_id", person_id) .add("trip_time", trip_time) .add("destination", destination) + .add("activity", activity) .add("model_id", destination_model_id) .add("trip_mode", trip_mode); } @@ -173,7 +179,7 @@ template <> struct DefaultFactory { static abm::Trip create() { - return abm::Trip{abm::PersonId{}, abm::TimePoint{}, abm::LocationId{}}; + return abm::Trip{abm::PersonId{}, abm::TimePoint{}, abm::LocationId{}, abm::ActivityType::Count}; } }; diff --git a/cpp/models/graph_abm/graph_abm_mobility.h b/cpp/models/graph_abm/graph_abm_mobility.h index 99e6e78050..f4b8e62218 100644 --- a/cpp/models/graph_abm/graph_abm_mobility.h +++ b/cpp/models/graph_abm/graph_abm_mobility.h @@ -123,15 +123,14 @@ class ABMMobilityEdge std::sort(persons_to_change.begin(), persons_to_change.end()); //iterate over all persons that change from node_from for (int i = int(persons_to_change.size()) - 1; i >= 0; --i) { - auto& person = model_from.get_persons()[persons_to_change[i]]; - auto target_type = person.get_location_type(); - if (target_type == abm::LocationType::Invalid) { - target_type = model_to.get_location(person.get_location()).get_type(); - } + auto& person = model_from.get_persons()[persons_to_change[i]]; //check if Person uses this edge - if (person.get_assigned_location_model_id(target_type) == model_to.get_id()) { - - auto target_id = person.get_assigned_location(target_type); + if (person.get_location_model_id() == model_to.get_id()) { + auto target_id = person.get_location(); + auto target_type = person.get_location_type(); + if (target_type == abm::LocationType::Invalid) { + target_type = model_to.get_location(target_id).get_type(); + } //set correct location for person person.set_location(target_type, target_id, model_to.get_id()); //add person to model_to diff --git a/cpp/models/graph_abm/graph_abmodel.h b/cpp/models/graph_abm/graph_abmodel.h index 7ea9b799a5..7835bcc369 100644 --- a/cpp/models/graph_abm/graph_abmodel.h +++ b/cpp/models/graph_abm/graph_abmodel.h @@ -21,6 +21,7 @@ #ifndef MIO_ABM_GRAPH_ABMODEL_H #define MIO_ABM_GRAPH_ABMODEL_H +#include "abm/activity_type.h" #include "abm/location_type.h" #include "abm/model.h" #include "abm/person_id.h" @@ -48,7 +49,7 @@ class GraphABModel : public abm::Model std::vector mobility_rules = std::vector{&get_buried, &return_home_when_recovered, &go_to_hospital, &go_to_icu, &go_to_school, &go_to_work, &go_to_shop, - &go_to_event, &go_to_quarantine}) + &go_to_recreation, &go_to_quarantine}) : Base(num_agegroups, id) { Base::m_mobility_rules = mobility_rules; @@ -99,8 +100,9 @@ class GraphABModel : public abm::Model auto try_mobility_rule = [&](auto rule) -> bool { //run mobility rule and check if change of location can actually happen auto target_type = rule(personal_rng, person, t, dt, parameters); - if (person.get_assigned_location_model_id(target_type) == Base::m_id) { - const Location& target_location = Base::get_location(Base::find_location(target_type, person)); + auto target = person.get_assigned_location(target_type, personal_rng); + if (target.second == Base::m_id) { + const Location& target_location = Base::get_location(target.first); const LocationId current_location = person.get_location(); // the Person cannot move if they do not wear mask as required at targeted location if (target_location.is_mask_required() && @@ -127,13 +129,12 @@ class GraphABModel : public abm::Model else { person.set_mask(MaskType::None, t); } - Base::change_location(person, target_location.get_id()); + Base::change_location(person, target_location.get_id(), target_type); return true; } else { //person moves to other world Base::m_activeness_statuses[person_index] = false; - person.set_location(target_type, abm::LocationId::invalid_id(), - std::numeric_limits::max()); + person.set_location(target_type, abm::LocationType::Invalid, target.first, target.second); m_person_buffer.push_back(person_index); m_are_exposure_caches_valid = false; m_is_local_population_cache_valid = false; @@ -176,7 +177,7 @@ class GraphABModel : public abm::Model continue; } // all requirements are met, move to target location - change_location(person, target_location.get_id(), trip.trip_mode); + change_location(person, target_location.get_id(), trip.activity, trip.trip_mode); // update worn mask to target location's requirements if (target_location.is_mask_required()) { // if the current MaskProtection level is lower than required, the Person changes mask @@ -191,7 +192,8 @@ class GraphABModel : public abm::Model } else { //person moves to other world Base::m_activeness_statuses[person_index] = false; - person.set_location(abm::LocationType::Invalid, trip.destination, std::numeric_limits::max()); + person.set_location(trip.activity, abm::LocationType::Invalid, trip.destination, + trip.destination_model_id); m_person_buffer.push_back(person_index); m_are_exposure_caches_valid = false; m_is_local_population_cache_valid = false; diff --git a/cpp/tests/abm_helpers.cpp b/cpp/tests/abm_helpers.cpp index bf9af22c29..2ca81defaa 100644 --- a/cpp/tests/abm_helpers.cpp +++ b/cpp/tests/abm_helpers.cpp @@ -18,16 +18,18 @@ * limitations under the License. */ #include "abm_helpers.h" +#include "abm/activity_type.h" #include "abm/person.h" #include "abm/person_id.h" #include "memilio/utils/random_number_generator.h" -mio::abm::Person make_test_person(mio::RandomNumberGenerator& rng, mio::abm::Location& location, mio::AgeGroup age, +mio::abm::Person make_test_person(mio::RandomNumberGenerator& rng, mio::abm::Location& location, + mio::abm::ActivityType actvty_type, mio::AgeGroup age, mio::abm::InfectionState infection_state, mio::abm::TimePoint t, mio::abm::Parameters params, mio::abm::PersonId id) { assert(age.get() < params.get_num_groups()); - mio::abm::Person p(rng, location.get_type(), location.get_id(), location.get_model_id(), age, id); + mio::abm::Person p(rng, location.get_type(), actvty_type, location.get_id(), location.get_model_id(), age, id); if (infection_state != mio::abm::InfectionState::Susceptible) { auto rng_p = mio::abm::PersonalRandomNumberGenerator(rng, p); p.add_new_infection( @@ -36,11 +38,13 @@ mio::abm::Person make_test_person(mio::RandomNumberGenerator& rng, mio::abm::Loc return p; } -mio::abm::PersonId add_test_person(mio::abm::Model& model, mio::abm::LocationId loc_id, mio::AgeGroup age, +mio::abm::PersonId add_test_person(mio::abm::Model& model, mio::abm::LocationId loc_id, + mio::abm::ActivityType actvty_type, mio::AgeGroup age, mio::abm::InfectionState infection_state, mio::abm::TimePoint t) { - return model.add_person(make_test_person(model.get_rng(), model.get_location(loc_id), age, infection_state, t, - model.parameters, static_cast(model.get_persons().size()))); + return model.add_person(make_test_person(model.get_rng(), model.get_location(loc_id), actvty_type, age, + infection_state, t, model.parameters, + static_cast(model.get_persons().size()))); } void interact_testing(mio::abm::PersonalRandomNumberGenerator& personal_rng, mio::abm::Person& person, diff --git a/cpp/tests/abm_helpers.h b/cpp/tests/abm_helpers.h index 808e8dc173..518102433e 100644 --- a/cpp/tests/abm_helpers.h +++ b/cpp/tests/abm_helpers.h @@ -20,6 +20,7 @@ #ifndef ABM_HELPERS_H #define ABM_HELPERS_H +#include "abm/activity_type.h" #include "abm/model.h" #include "abm/person_id.h" @@ -94,17 +95,18 @@ struct ScopedMockDistribution { * @brief Create a Person without a Model object. Intended for simple use in tests. */ mio::abm::Person make_test_person(mio::RandomNumberGenerator& rng, mio::abm::Location& location, - mio::AgeGroup age = age_group_15_to_34, + mio::abm::ActivityType actvty_type, mio::AgeGroup age = age_group_15_to_34, mio::abm::InfectionState infection_state = mio::abm::InfectionState::Susceptible, mio::abm::TimePoint t = mio::abm::TimePoint(0), mio::abm::Parameters params = mio::abm::Parameters(num_age_groups), - mio::abm::PersonId id = mio::abm::PersonId(0)); + + mio::abm::PersonId id = mio::abm::PersonId(0)); /** * @brief Add a Person to the Model. Intended for simple use in tests. */ mio::abm::PersonId add_test_person(mio::abm::Model& model, mio::abm::LocationId loc_id, - mio::AgeGroup age = age_group_15_to_34, + mio::abm::ActivityType actvty_type, mio::AgeGroup age = age_group_15_to_34, mio::abm::InfectionState infection_state = mio::abm::InfectionState::Susceptible, mio::abm::TimePoint t = mio::abm::TimePoint(0)); diff --git a/cpp/tests/test_abm_infection.cpp b/cpp/tests/test_abm_infection.cpp index f8c7650de5..2ca97c7b81 100644 --- a/cpp/tests/test_abm_infection.cpp +++ b/cpp/tests/test_abm_infection.cpp @@ -298,8 +298,8 @@ TEST_F(TestInfection, getPersonalProtectiveFactor) const ScalarType eps = 1e-4; auto location = mio::abm::Location(mio::abm::LocationType::School, 0, num_age_groups); - auto person = mio::abm::Person(this->get_rng(), location.get_type(), location.get_id(), location.get_model_id(), - age_group_15_to_34); + auto person = mio::abm::Person(this->get_rng(), location.get_type(), mio::abm::ActivityType::School, + location.get_id(), location.get_model_id(), age_group_15_to_34); auto t0 = mio::abm::TimePoint(0); person.add_new_vaccination(mio::abm::ProtectionType::GenericVaccine, t0); auto latest_protection = person.get_latest_protection(t0); diff --git a/cpp/tests/test_abm_location.cpp b/cpp/tests/test_abm_location.cpp index 5e04ddc931..13b41b74f2 100644 --- a/cpp/tests/test_abm_location.cpp +++ b/cpp/tests/test_abm_location.cpp @@ -18,6 +18,7 @@ * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/location_id.h" #include "abm/parameters.h" #include "abm/person.h" @@ -102,11 +103,11 @@ TEST_F(TestLocation, interact) // Setup location with some chance of exposure mio::abm::Location location(mio::abm::LocationType::Work, 0, num_age_groups); location.get_infection_parameters().get() = true; - auto infected1 = make_test_person(this->get_rng(), location, age_group_15_to_34, + auto infected1 = make_test_person(this->get_rng(), location, mio::abm::ActivityType::Work, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms, t, params); - auto infected2 = make_test_person(this->get_rng(), location, age_group_80_plus, + auto infected2 = make_test_person(this->get_rng(), location, mio::abm::ActivityType::Work, age_group_80_plus, mio::abm::InfectionState::InfectedSymptoms, t, params); - auto infected3 = make_test_person(this->get_rng(), location, age_group_5_to_14, + auto infected3 = make_test_person(this->get_rng(), location, mio::abm::ActivityType::Work, age_group_5_to_14, mio::abm::InfectionState::InfectedSymptoms, t, params); std::vector local_population{infected1, infected2, infected3}; @@ -115,8 +116,8 @@ TEST_F(TestLocation, interact) ScopedMockDistribution>>> mock_discrete_dist; // Create a susceptible person and test interaction. - auto susceptible = - make_test_person(this->get_rng(), location, age, mio::abm::InfectionState::Susceptible, t, params); + auto susceptible = make_test_person(this->get_rng(), location, mio::abm::ActivityType::Work, age, + mio::abm::InfectionState::Susceptible, t, params); EXPECT_CALL(mock_exponential_dist.get_mock(), invoke).Times(1).WillOnce(Return(0.5)); // Probability of no infection auto person_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), susceptible); interact_testing(person_rng, susceptible, location, local_population, t, dt, params); @@ -176,7 +177,7 @@ TEST_F(TestLocation, getGeographicalLocation) */ TEST_F(TestLocation, adjustContactRates) { - mio::abm::Location loc(mio::abm::LocationType::SocialEvent, mio::abm::LocationId(0)); + mio::abm::Location loc(mio::abm::LocationType::Recreation, mio::abm::LocationId(0)); //Set the maximum contacts smaller than the contact rates loc.get_infection_parameters().get() = 2; loc.get_infection_parameters().get().get_baseline()(0, 0) = 4; diff --git a/cpp/tests/test_abm_lockdown_rules.cpp b/cpp/tests/test_abm_lockdown_rules.cpp index a292fc9984..d0de9c3a22 100644 --- a/cpp/tests/test_abm_lockdown_rules.cpp +++ b/cpp/tests/test_abm_lockdown_rules.cpp @@ -17,6 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/lockdown_rules.h" #include "abm/mobility_rules.h" #include "abm/person.h" @@ -52,12 +53,14 @@ TEST_F(TestLockdownRules, school_closure) .WillRepeatedly(testing::Return(1.0)); // Set up two people with assigned locations (home and school) - auto p1 = mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_5_to_14); - p1.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p1.set_assigned_location(school.get_type(), school.get_id(), school.get_model_id()); - auto p2 = mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_5_to_14); - p2.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p2.set_assigned_location(school.get_type(), school.get_id(), school.get_model_id()); + auto p1 = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_5_to_14); + p1.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p1.set_assigned_location(mio::abm::ActivityType::School, school.get_id(), school.get_model_id()); + auto p2 = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_5_to_14); + p2.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p2.set_assigned_location(mio::abm::ActivityType::School, school.get_id(), school.get_model_id()); mio::abm::Parameters params = mio::abm::Parameters(num_age_groups); // Set the age group the can go to school is AgeGroup(1) (i.e. 5-14) params.get() = false; @@ -101,9 +104,10 @@ TEST_F(TestLockdownRules, school_opening) .WillRepeatedly(testing::Return(1.0)); // Set up one person with assigned locations (home and school) - auto p = mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_5_to_14); - p.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p.set_assigned_location(school.get_type(), school.get_id(), school.get_model_id()); + auto p = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_5_to_14); + p.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p.set_assigned_location(mio::abm::ActivityType::School, school.get_id(), school.get_model_id()); mio::abm::Parameters params = mio::abm::Parameters(num_age_groups); // Set the age group the can go to school is AgeGroup(1) (i.e. 5-14) @@ -157,14 +161,14 @@ TEST_F(TestLockdownRules, home_office) .WillOnce(testing::Return(0.7)) .WillRepeatedly(testing::Return(1.0)); - auto person1 = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_15_to_34); - auto person2 = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_15_to_34); - person1.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - person1.set_assigned_location(work.get_type(), work.get_id(), work.get_model_id()); - person2.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - person2.set_assigned_location(work.get_type(), work.get_id(), work.get_model_id()); + auto person1 = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_15_to_34); + auto person2 = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_15_to_34); + person1.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + person1.set_assigned_location(mio::abm::ActivityType::Work, work.get_id(), work.get_model_id()); + person2.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + person2.set_assigned_location(mio::abm::ActivityType::Work, work.get_id(), work.get_model_id()); // Check that person1 goes to work and person2 stays at home. auto p1_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person1); @@ -195,9 +199,10 @@ TEST_F(TestLockdownRules, no_home_office) .WillOnce(testing::Return(0.7)) .WillRepeatedly(testing::Return(1.0)); - auto p = mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_15_to_34); - p.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p.set_assigned_location(work.get_type(), work.get_id(), work.get_model_id()); + auto p = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_15_to_34); + p.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p.set_assigned_location(mio::abm::ActivityType::Work, work.get_id(), work.get_model_id()); mio::abm::Parameters params = mio::abm::Parameters(num_age_groups); // Set the age group the can go to school is AgeGroup(1) (i.e. 5-14) params.get() = false; @@ -226,10 +231,11 @@ TEST_F(TestLockdownRules, social_event_closure) auto t_evening = mio::abm::TimePoint(0) + mio::abm::hours(19); mio::abm::Location home(mio::abm::LocationType::Home, 0, num_age_groups); - mio::abm::Location event(mio::abm::LocationType::SocialEvent, 1, num_age_groups); - auto p = mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_5_to_14); - p.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p.set_assigned_location(event.get_type(), event.get_id(), event.get_model_id()); + mio::abm::Location event(mio::abm::LocationType::Recreation, 1, num_age_groups); + auto p = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_5_to_14); + p.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p.set_assigned_location(mio::abm::ActivityType::Recreation, event.get_id(), event.get_model_id()); mio::abm::Parameters params = mio::abm::Parameters(num_age_groups); // Close social events @@ -237,7 +243,7 @@ TEST_F(TestLockdownRules, social_event_closure) // Checks that p stays home instead of attending social events during a closure. auto p_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p); - EXPECT_EQ(mio::abm::go_to_event(p_rng, p, t_evening, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_recreation(p_rng, p, t_evening, dt, params), mio::abm::ActivityType::Home); } /** @@ -251,10 +257,11 @@ TEST_F(TestLockdownRules, social_events_opening) auto t_evening = mio::abm::TimePoint(0) + mio::abm::days(1) + mio::abm::hours(19); mio::abm::Location home(mio::abm::LocationType::Home, 0, num_age_groups); - mio::abm::Location event(mio::abm::LocationType::SocialEvent, 1, num_age_groups); - auto p = mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_5_to_14); - p.set_assigned_location(event.get_type(), event.get_id(), event.get_model_id()); - p.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); + mio::abm::Location event(mio::abm::LocationType::Recreation, 1, num_age_groups); + auto p = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_5_to_14); + p.set_assigned_location(mio::abm::ActivityType::Recreation, event.get_id(), event.get_model_id()); + p.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); mio::abm::Parameters params = mio::abm::Parameters(num_age_groups); // Close then open social events @@ -267,5 +274,5 @@ TEST_F(TestLockdownRules, social_events_opening) // Test that after reopening, p attends social events again. auto p_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p); - EXPECT_EQ(mio::abm::go_to_event(p_rng, p, t_evening, dt, params), mio::abm::LocationType::SocialEvent); + EXPECT_EQ(mio::abm::go_to_recreation(p_rng, p, t_evening, dt, params), mio::abm::ActivityType::Recreation); } diff --git a/cpp/tests/test_abm_masks.cpp b/cpp/tests/test_abm_masks.cpp index 5031dc7205..c3e68da12b 100644 --- a/cpp/tests/test_abm_masks.cpp +++ b/cpp/tests/test_abm_masks.cpp @@ -17,6 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/person.h" #include "abm_helpers.h" #include "random_number_test.h" @@ -79,13 +80,16 @@ TEST_F(TestMasks, maskProtection) auto t = mio::abm::TimePoint(0); mio::abm::Location infection_location(mio::abm::LocationType::School, 0, num_age_groups); // Two susceptible persons, one with a mask, one without - auto susc_person1 = mio::abm::Person(this->get_rng(), infection_location.get_type(), infection_location.get_id(), - infection_location.get_model_id(), age_group_15_to_34); - auto susc_person2 = mio::abm::Person(this->get_rng(), infection_location.get_type(), infection_location.get_id(), - infection_location.get_model_id(), age_group_15_to_34); + auto susc_person1 = + mio::abm::Person(this->get_rng(), infection_location.get_type(), mio::abm::ActivityType::School, + infection_location.get_id(), infection_location.get_model_id(), age_group_15_to_34); + auto susc_person2 = + mio::abm::Person(this->get_rng(), infection_location.get_type(), mio::abm::ActivityType::School, + infection_location.get_id(), infection_location.get_model_id(), age_group_15_to_34); // Infected person interacting with susceptible persons - auto infected1 = make_test_person(this->get_rng(), infection_location, age_group_15_to_34, - mio::abm::InfectionState::InfectedSymptoms, t, params); // infected 7 days prior + auto infected1 = + make_test_person(this->get_rng(), infection_location, mio::abm::ActivityType::School, age_group_15_to_34, + mio::abm::InfectionState::InfectedSymptoms, t, params); // infected 7 days prior // Cache precomputed results for 1-day intervals auto dt = mio::abm::days(1); diff --git a/cpp/tests/test_abm_mobility_rules.cpp b/cpp/tests/test_abm_mobility_rules.cpp index f5bd9fcc3a..2280df17e7 100644 --- a/cpp/tests/test_abm_mobility_rules.cpp +++ b/cpp/tests/test_abm_mobility_rules.cpp @@ -17,6 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/location_type.h" #include "abm/mobility_rules.h" #include "abm/person.h" @@ -32,9 +33,10 @@ TEST_F(TestMobilityRules, random_mobility) { int t = 0, dt = 1; auto default_type = mio::abm::LocationType::Cemetery; - auto person = mio::abm::Person(this->get_rng(), default_type, 0, 0, age_group_15_to_34); - auto p_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); - auto params = mio::abm::Parameters(num_age_groups); + auto person = + mio::abm::Person(this->get_rng(), default_type, mio::abm::ActivityType::Cemetery, 0, 0, age_group_15_to_34); + auto p_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); + auto params = mio::abm::Parameters(num_age_groups); ScopedMockDistribution>>> mock_exp_dist; EXPECT_CALL(mock_exp_dist.get_mock(), invoke) @@ -84,10 +86,10 @@ TEST_F(TestMobilityRules, student_goes_to_school) .WillRepeatedly(testing::Return(1.0)); mio::abm::Location home(mio::abm::LocationType::Home, 0, num_age_groups); - auto p_child = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_5_to_14); - auto p_adult = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_15_to_34); + auto p_child = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_5_to_14); + auto p_adult = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_15_to_34); auto t_morning = mio::abm::TimePoint(0) + mio::abm::hours(7); auto t_weekend = mio::abm::TimePoint(0) + mio::abm::days(5) + mio::abm::hours(7); @@ -134,12 +136,12 @@ TEST_F(TestMobilityRules, students_go_to_school_in_different_times) .WillRepeatedly(testing::Return(1.0)); mio::abm::Location home(mio::abm::LocationType::Home, 0, num_age_groups); - auto p_child_goes_to_school_at_6 = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_5_to_14); + auto p_child_goes_to_school_at_6 = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, + home.get_id(), home.get_model_id(), age_group_5_to_14); auto rng_child_goes_to_school_at_6 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_child_goes_to_school_at_6); - auto p_child_goes_to_school_at_8 = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_5_to_14); + auto p_child_goes_to_school_at_8 = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, + home.get_id(), home.get_model_id(), age_group_5_to_14); auto rng_child_goes_to_school_at_8 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_child_goes_to_school_at_8); @@ -200,14 +202,15 @@ TEST_F(TestMobilityRules, students_go_to_school_in_different_times_with_smaller_ mio::abm::Location home(mio::abm::LocationType::Home, 0, num_age_groups); // First student goes to school at 6:00 AM - auto p_child_goes_to_school_at_6 = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_5_to_14); + auto p_child_goes_to_school_at_6 = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, + home.get_id(), home.get_model_id(), age_group_5_to_14); auto rng_child_goes_to_school_at_6 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_child_goes_to_school_at_6); // Second student goes to school at 8:30 AM auto p_child_goes_to_school_at_8_30 = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_5_to_14); + mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_5_to_14); auto rng_child_goes_to_school_at_8_30 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_child_goes_to_school_at_8_30); @@ -245,8 +248,8 @@ TEST_F(TestMobilityRules, students_go_to_school_in_different_times_with_smaller_ TEST_F(TestMobilityRules, school_return) { mio::abm::Location school(mio::abm::LocationType::School, 0, num_age_groups); - auto p_child = - mio::abm::Person(this->get_rng(), school.get_type(), school.get_id(), school.get_model_id(), age_group_5_to_14); + auto p_child = mio::abm::Person(this->get_rng(), school.get_type(), mio::abm::ActivityType::School, school.get_id(), + school.get_model_id(), age_group_5_to_14); auto rng_child = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_child); // Simulate a time point after school hours @@ -278,12 +281,12 @@ TEST_F(TestMobilityRules, worker_goes_to_work) .WillOnce(testing::Return(0.)) .WillRepeatedly(testing::Return(1.0)); - auto p_retiree = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_60_to_79); + auto p_retiree = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_60_to_79); auto rng_retiree = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_retiree); - auto p_adult = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_15_to_34); - auto rng_adult = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_adult); + auto p_adult = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_15_to_34); + auto rng_adult = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_adult); auto t_morning = mio::abm::TimePoint(0) + mio::abm::hours(8); auto t_night = mio::abm::TimePoint(0) + mio::abm::days(1) + mio::abm::hours(4); @@ -328,12 +331,12 @@ TEST_F(TestMobilityRules, worker_goes_to_work_with_non_dividable_timespan) .WillRepeatedly(testing::Return(1.0)); // Set up two people: one retiree and one working adult. - auto p_retiree = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_60_to_79); + auto p_retiree = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_60_to_79); auto rng_retiree = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_retiree); - auto p_adult = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_15_to_34); - auto rng_adult = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_adult); + auto p_adult = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_15_to_34); + auto rng_adult = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_adult); auto t_morning = mio::abm::TimePoint(0) + mio::abm::hours(8); auto t_night = mio::abm::TimePoint(0) + mio::abm::days(1) + mio::abm::hours(4); @@ -383,12 +386,12 @@ TEST_F(TestMobilityRules, workers_go_to_work_in_different_times) .WillRepeatedly(testing::Return(1.0)); // Create two workers: one goes to work at 6 AM and the other at 8 AM. - auto p_adult_goes_to_work_at_6 = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_15_to_34); + auto p_adult_goes_to_work_at_6 = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, + home.get_id(), home.get_model_id(), age_group_15_to_34); auto rng_adult_goes_to_work_at_6 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_adult_goes_to_work_at_6); - auto p_adult_goes_to_work_at_8 = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_15_to_34); + auto p_adult_goes_to_work_at_8 = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, + home.get_id(), home.get_model_id(), age_group_15_to_34); auto rng_adult_goes_to_work_at_8 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_adult_goes_to_work_at_8); @@ -432,8 +435,8 @@ TEST_F(TestMobilityRules, work_return) { mio::abm::Location work(mio::abm::LocationType::Work, 0, num_age_groups); // Set up a random number generator and a worker who is currently at work - auto p_adult = - mio::abm::Person(this->get_rng(), work.get_type(), work.get_id(), work.get_model_id(), age_group_35_to_59); + auto p_adult = mio::abm::Person(this->get_rng(), work.get_type(), mio::abm::ActivityType::Work, work.get_id(), + work.get_model_id(), age_group_35_to_59); auto rng_adult = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_adult); // Set the time to 5 PM (17:00) when the worker should return home auto t = mio::abm::TimePoint(0) + mio::abm::hours(17); @@ -455,23 +458,23 @@ TEST_F(TestMobilityRules, quarantine) mio::abm::Location work(mio::abm::LocationType::Work, 0, num_age_groups); mio::abm::Location hospital(mio::abm::LocationType::Hospital, 0, num_age_groups); - auto p_inf1 = - make_test_person(this->get_rng(), work, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms, t); + auto p_inf1 = make_test_person(this->get_rng(), work, mio::abm::ActivityType::Work, age_group_15_to_34, + mio::abm::InfectionState::InfectedSymptoms, t); auto rng_inf1 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_inf1); p_inf1.get_tested(rng_inf1, t, test_params); // Check detected infected person quarantines at home EXPECT_EQ(mio::abm::go_to_quarantine(rng_inf1, p_inf1, t, dt, mio::abm::Parameters(num_age_groups)), mio::abm::LocationType::Home); - auto p_inf2 = - make_test_person(this->get_rng(), work, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms, t); + auto p_inf2 = make_test_person(this->get_rng(), work, mio::abm::ActivityType::Work, age_group_15_to_34, + mio::abm::InfectionState::InfectedSymptoms, t); auto rng_inf2 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_inf2); // Check that undetected infected person does not quaratine EXPECT_EQ(mio::abm::go_to_quarantine(rng_inf2, p_inf2, t, dt, mio::abm::Parameters(num_age_groups)), mio::abm::LocationType::Work); - auto p_inf3 = - make_test_person(this->get_rng(), hospital, age_group_15_to_34, mio::abm::InfectionState::InfectedSevere, t); + auto p_inf3 = make_test_person(this->get_rng(), hospital, mio::abm::ActivityType::Hospital, age_group_15_to_34, + mio::abm::InfectionState::InfectedSevere, t); auto rng_inf3 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_inf3); p_inf1.get_tested(rng_inf3, t, test_params); // Check that detected infected person does not leave hospital to quarantine @@ -485,18 +488,18 @@ TEST_F(TestMobilityRules, quarantine) TEST_F(TestMobilityRules, hospital) { mio::abm::Location home(mio::abm::LocationType::Home, 0, num_age_groups); - auto t = mio::abm::TimePoint(12346); - auto dt = mio::abm::hours(1); - auto p_inf = - make_test_person(this->get_rng(), home, age_group_15_to_34, mio::abm::InfectionState::InfectedSevere, t); + auto t = mio::abm::TimePoint(12346); + auto dt = mio::abm::hours(1); + auto p_inf = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedSevere, t); auto rng_inf = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_inf); // Ensure person goes to the hospital when severely infected EXPECT_EQ(mio::abm::go_to_hospital(rng_inf, p_inf, t, dt, mio::abm::Parameters(num_age_groups)), mio::abm::LocationType::Hospital); - auto p_car = - make_test_person(this->get_rng(), home, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms); + auto p_car = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedSymptoms); auto rng_car = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_car); // Ensure person has infection symptoms still stay at home EXPECT_EQ(mio::abm::go_to_hospital(rng_car, p_car, t, dt, mio::abm::Parameters(num_age_groups)), @@ -517,12 +520,12 @@ TEST_F(TestMobilityRules, go_shopping) auto dt = mio::abm::hours(1); // Create an infected child in the hospital - auto p_hosp = make_test_person(this->get_rng(), hospital, age_group_0_to_4, + auto p_hosp = make_test_person(this->get_rng(), hospital, mio::abm::ActivityType::Hospital, age_group_0_to_4, mio::abm::InfectionState::InfectedSymptoms, t_weekday); auto rng_hosp = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_hosp); // Create a healthy elderly person at home - auto p_home = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_60_to_79); + auto p_home = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_60_to_79); auto rng_home = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_home); // Check that an infected person stays in the hospital and doesn't go shopping @@ -555,8 +558,8 @@ TEST_F(TestMobilityRules, shop_return) // Create a person at a basic shop who is asymptomatically infected mio::abm::Location shop(mio::abm::LocationType::BasicsShop, 0, num_age_groups); - auto p = - make_test_person(this->get_rng(), shop, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms, t); + auto p = make_test_person(this->get_rng(), shop, mio::abm::ActivityType::BasicsShop, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms, t); auto rng_p = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p); // Simulate the person spending 1 hour at the shop p.add_time_at_location(dt); @@ -573,12 +576,12 @@ TEST_F(TestMobilityRules, go_event) { // Initialize two people, one at work and one at home mio::abm::Location work(mio::abm::LocationType::Work, 0, num_age_groups); - auto p_work = - mio::abm::Person(this->get_rng(), work.get_type(), work.get_id(), work.get_model_id(), age_group_35_to_59); + auto p_work = mio::abm::Person(this->get_rng(), work.get_type(), mio::abm::ActivityType::Work, work.get_id(), + work.get_model_id(), age_group_35_to_59); auto rng_work = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_work); mio::abm::Location home(mio::abm::LocationType::Home, 1, num_age_groups); - auto p_home = - mio::abm::Person(this->get_rng(), home.get_type(), home.get_id(), home.get_model_id(), age_group_60_to_79); + auto p_home = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_60_to_79); auto rng_home = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_home); auto t_weekday = mio::abm::TimePoint(0) + mio::abm::days(4) + mio::abm::hours(20); @@ -587,23 +590,23 @@ TEST_F(TestMobilityRules, go_event) auto dt = mio::abm::hours(1); // Check that person at work should not go to an event during a weekday evening, so they stay at work - EXPECT_EQ(mio::abm::go_to_event(rng_work, p_work, t_weekday, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Work); + EXPECT_EQ(mio::abm::go_to_recreation(rng_work, p_work, t_weekday, dt, mio::abm::Parameters(num_age_groups)), + mio::abm::ActivityType::Work); // Check that person at home during nighttime should not go to an event, so they stay at home - EXPECT_EQ(mio::abm::go_to_event(rng_home, p_home, t_night, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_recreation(rng_home, p_home, t_night, dt, mio::abm::Parameters(num_age_groups)), + mio::abm::ActivityType::Home); // Mock the random distribution to simulate event participation based on random draw ScopedMockDistribution>>> mock_exponential_dist; EXPECT_CALL(mock_exponential_dist.get_mock(), invoke).Times(1).WillOnce(testing::Return(0.01)); // Check that person at home goes to a social event on a weekday evening based on a low random value - EXPECT_EQ(mio::abm::go_to_event(rng_home, p_home, t_weekday, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::SocialEvent); + EXPECT_EQ(mio::abm::go_to_recreation(rng_home, p_home, t_weekday, dt, mio::abm::Parameters(num_age_groups)), + mio::abm::ActivityType::Recreation); // Check that person at home goes to a social event on a Saturday morning based on a low random value EXPECT_CALL(mock_exponential_dist.get_mock(), invoke).Times(1).WillOnce(testing::Return(0.01)); - EXPECT_EQ(mio::abm::go_to_event(rng_home, p_home, t_saturday, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::SocialEvent); + EXPECT_EQ(mio::abm::go_to_recreation(rng_home, p_home, t_saturday, dt, mio::abm::Parameters(num_age_groups)), + mio::abm::ActivityType::Recreation); } /** @@ -616,15 +619,15 @@ TEST_F(TestMobilityRules, event_return) auto dt = mio::abm::hours(3); mio::abm::Location home(mio::abm::LocationType::Home, 0, num_age_groups); - mio::abm::Location social_event(mio::abm::LocationType::SocialEvent, 1, num_age_groups); + mio::abm::Location social_event(mio::abm::LocationType::Recreation, 1, num_age_groups); // Initialize the person at the social event location - auto p = mio::abm::Person(this->get_rng(), social_event.get_type(), social_event.get_id(), - social_event.get_model_id(), age_group_15_to_34); + auto p = mio::abm::Person(this->get_rng(), social_event.get_type(), mio::abm::ActivityType::Recreation, + social_event.get_id(), social_event.get_model_id(), age_group_15_to_34); auto rng_p = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p); // Simulate the person spending 3 hours at the social event p.add_time_at_location(dt); // After spending the time at the social event, the person should return home - EXPECT_EQ(mio::abm::go_to_event(rng_p, p, t, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_recreation(rng_p, p, t, dt, params), mio::abm::LocationType::Home); } /** @@ -633,10 +636,10 @@ TEST_F(TestMobilityRules, event_return) TEST_F(TestMobilityRules, icu) { mio::abm::Location hospital(mio::abm::LocationType::Hospital, 0, num_age_groups); - auto t = mio::abm::TimePoint(12346); - auto dt = mio::abm::hours(1); - auto p_hosp = - make_test_person(this->get_rng(), hospital, age_group_15_to_34, mio::abm::InfectionState::InfectedCritical, t); + auto t = mio::abm::TimePoint(12346); + auto dt = mio::abm::hours(1); + auto p_hosp = make_test_person(this->get_rng(), hospital, mio::abm::ActivityType::Hospital, age_group_15_to_34, + mio::abm::InfectionState::InfectedCritical, t); auto rng_hosp = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_hosp); // Ensure critically infected person goes to the ICU @@ -644,8 +647,8 @@ TEST_F(TestMobilityRules, icu) mio::abm::LocationType::ICU); mio::abm::Location work(mio::abm::LocationType::Work, 1, num_age_groups); - auto p_work = - make_test_person(this->get_rng(), work, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms, t); + auto p_work = make_test_person(this->get_rng(), work, mio::abm::ActivityType::Work, age_group_15_to_34, + mio::abm::InfectionState::InfectedSymptoms, t); auto rng_work = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_work); // Ensure infected with symptions person can still go to work EXPECT_EQ(mio::abm::go_to_icu(rng_work, p_work, t, dt, mio::abm::Parameters(num_age_groups)), @@ -658,13 +661,13 @@ TEST_F(TestMobilityRules, icu) TEST_F(TestMobilityRules, recover) { mio::abm::Location hospital(mio::abm::LocationType::Hospital, 0); - auto t = mio::abm::TimePoint(12346); - auto dt = mio::abm::hours(1); - auto p_rec = - make_test_person(this->get_rng(), hospital, age_group_60_to_79, mio::abm::InfectionState::Recovered, t); + auto t = mio::abm::TimePoint(12346); + auto dt = mio::abm::hours(1); + auto p_rec = make_test_person(this->get_rng(), hospital, mio::abm::ActivityType::Hospital, age_group_60_to_79, + mio::abm::InfectionState::Recovered, t); auto rng_rec = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_rec); - auto p_inf = - make_test_person(this->get_rng(), hospital, age_group_60_to_79, mio::abm::InfectionState::InfectedSevere, t); + auto p_inf = make_test_person(this->get_rng(), hospital, mio::abm::ActivityType::Hospital, age_group_60_to_79, + mio::abm::InfectionState::InfectedSevere, t); auto rng_inf = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_inf); // Ensure recovered person returns home and infected severe person stay in hospital EXPECT_EQ(mio::abm::return_home_when_recovered(rng_rec, p_rec, t, dt, {num_age_groups}), @@ -681,7 +684,8 @@ TEST_F(TestMobilityRules, dead) mio::abm::Location icu(mio::abm::LocationType::ICU, 0); auto t = mio::abm::TimePoint(12346); auto dt = mio::abm::hours(1); - auto p_dead = make_test_person(this->get_rng(), icu, age_group_60_to_79, mio::abm::InfectionState::Dead, t); + auto p_dead = make_test_person(this->get_rng(), icu, mio::abm::ActivityType::ICU, age_group_60_to_79, + mio::abm::InfectionState::Dead, t); auto p_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_dead); EXPECT_EQ(mio::abm::get_buried(p_rng, p_dead, t, dt, {num_age_groups}), mio::abm::LocationType::Cemetery); diff --git a/cpp/tests/test_abm_model.cpp b/cpp/tests/test_abm_model.cpp index fe7926ff06..371ee1d1c9 100644 --- a/cpp/tests/test_abm_model.cpp +++ b/cpp/tests/test_abm_model.cpp @@ -17,6 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/location_id.h" #include "abm/person_id.h" #include "memilio/utils/random_number_generator.h" @@ -99,8 +100,8 @@ TEST_F(TestModel, addPerson) auto model = mio::abm::Model(num_age_groups); auto location = model.add_location(mio::abm::LocationType::School); - auto id1 = model.add_person(location, age_group_15_to_34); - auto id2 = model.add_person(location, age_group_35_to_59); + auto id1 = model.add_person(location, age_group_15_to_34, mio::abm::ActivityType::School); + auto id2 = model.add_person(location, age_group_35_to_59, mio::abm::ActivityType::Work); // Verify the number of persons in the model and their respective age groups. EXPECT_EQ(model.get_persons().size(), 2); @@ -123,8 +124,8 @@ TEST_F(TestModel, getNumberPersons) auto location = model.add_location(mio::abm::LocationType::School); // Add persons to the model. - model.add_person(location, age_group_15_to_34); - model.add_person(location, age_group_35_to_59); + model.add_person(location, age_group_15_to_34, mio::abm::ActivityType::School); + model.add_person(location, age_group_35_to_59, mio::abm::ActivityType::Work); EXPECT_TRUE(logger.read().empty()); @@ -161,12 +162,18 @@ TEST_F(TestModel, getSubpopulationCombined) auto home1 = model.add_location(mio::abm::LocationType::Home); // Add persons to these locations with various infection states. - add_test_person(model, school1, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms); - add_test_person(model, school1, age_group_15_to_34, mio::abm::InfectionState::Susceptible); - add_test_person(model, school2, age_group_15_to_34, mio::abm::InfectionState::Susceptible); - add_test_person(model, school2, age_group_15_to_34, mio::abm::InfectionState::Susceptible); - add_test_person(model, school3, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms); - add_test_person(model, home1, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms); + add_test_person(model, school1, mio::abm::ActivityType::School, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms); + add_test_person(model, school1, mio::abm::ActivityType::School, age_group_15_to_34, + mio::abm::InfectionState::Susceptible); + add_test_person(model, school2, mio::abm::ActivityType::School, age_group_15_to_34, + mio::abm::InfectionState::Susceptible); + add_test_person(model, school2, mio::abm::ActivityType::School, age_group_15_to_34, + mio::abm::InfectionState::Susceptible); + add_test_person(model, school3, mio::abm::ActivityType::School, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms); + add_test_person(model, home1, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms); // Verify the count of susceptible persons across all School locations. EXPECT_EQ(model.get_subpopulation_combined_per_location_type(t, mio::abm::InfectionState::Susceptible, @@ -194,22 +201,22 @@ TEST_F(TestModel, findLocation) auto work_id = model.add_location(mio::abm::LocationType::Work); // Add a person to the model and assign them to multiple locations. - auto person_id = add_test_person(model, home_id); + auto person_id = add_test_person(model, home_id, mio::abm::ActivityType::Home); auto& person = model.get_person(person_id); - person.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - person.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - person.set_assigned_location(mio::abm::LocationType::School, school_id, model.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + person.set_assigned_location(mio::abm::ActivityType::School, school_id, model.get_id()); // Verify that the find_location method correctly identifies each assigned location. - EXPECT_EQ(model.find_location(mio::abm::LocationType::Work, person_id), work_id); - EXPECT_EQ(model.find_location(mio::abm::LocationType::School, person_id), school_id); - EXPECT_EQ(model.find_location(mio::abm::LocationType::Home, person_id), home_id); + EXPECT_EQ(model.find_locations(mio::abm::ActivityType::Work, person_id)[0], work_id); + EXPECT_EQ(model.find_locations(mio::abm::ActivityType::School, person_id)[0], school_id); + EXPECT_EQ(model.find_locations(mio::abm::ActivityType::Home, person_id)[0], home_id); // Check that the method also works with a constant reference to the model. auto&& model_test = std::as_const(model); - EXPECT_EQ(model_test.find_location(mio::abm::LocationType::Work, person_id), work_id); - EXPECT_EQ(model_test.find_location(mio::abm::LocationType::School, person_id), school_id); - EXPECT_EQ(model_test.find_location(mio::abm::LocationType::Home, person_id), home_id); + EXPECT_EQ(model_test.find_locations(mio::abm::ActivityType::Work, person_id)[0], work_id); + EXPECT_EQ(model_test.find_locations(mio::abm::ActivityType::School, person_id)[0], school_id); + EXPECT_EQ(model_test.find_locations(mio::abm::ActivityType::Home, person_id)[0], home_id); } /** @@ -251,18 +258,21 @@ TEST_F(TestModel, evolveStateTransition) // Add locations and persons to the model with different initial infection states. auto location1 = model.add_location(mio::abm::LocationType::School); auto location2 = model.add_location(mio::abm::LocationType::Work); - add_test_person(model, location1, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms); - add_test_person(model, location1, age_group_15_to_34, mio::abm::InfectionState::Susceptible); - add_test_person(model, location2, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms); + add_test_person(model, location1, mio::abm::ActivityType::School, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms); + add_test_person(model, location1, mio::abm::ActivityType::School, age_group_15_to_34, + mio::abm::InfectionState::Susceptible); + add_test_person(model, location2, mio::abm::ActivityType::Work, age_group_15_to_34, + mio::abm::InfectionState::InfectedSymptoms); auto& p1 = model.get_persons()[0]; auto& p2 = model.get_persons()[1]; auto& p3 = model.get_persons()[2]; // Assign persons to their respective locations. - p1.set_assigned_location(mio::abm::LocationType::School, location1, model.get_id()); - p2.set_assigned_location(mio::abm::LocationType::School, location1, model.get_id()); - p3.set_assigned_location(mio::abm::LocationType::Work, location2, model.get_id()); + p1.set_assigned_location(mio::abm::ActivityType::School, location1, model.get_id()); + p2.set_assigned_location(mio::abm::ActivityType::School, location1, model.get_id()); + p3.set_assigned_location(mio::abm::ActivityType::Work, location2, model.get_id()); // Setup mock so p2 becomes infected ScopedMockDistribution>>> @@ -312,18 +322,20 @@ TEST_F(TestModel, evolveMobilityRules) .WillOnce(testing::Return(0.8)) // draw random school hour .WillRepeatedly(testing::Return(1.0)); - auto pid2 = add_test_person(model, home_id, age_group_5_to_14, mio::abm::InfectionState::Susceptible, t); - auto pid1 = add_test_person(model, home_id, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms, t); + auto pid2 = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_5_to_14, + mio::abm::InfectionState::Susceptible, t); + auto pid1 = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms, t); auto& p1 = model.get_person(pid1); auto& p2 = model.get_person(pid2); - p1.set_assigned_location(mio::abm::LocationType::School, school_id, model.get_id()); - p2.set_assigned_location(mio::abm::LocationType::School, school_id, model.get_id()); - p1.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p2.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p1.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p2.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); + p1.set_assigned_location(mio::abm::ActivityType::School, school_id, model.get_id()); + p2.set_assigned_location(mio::abm::ActivityType::School, school_id, model.get_id()); + p1.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p2.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p1.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p2.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); ScopedMockDistribution>>> mock_exponential_dist; @@ -368,7 +380,7 @@ TEST_F(TestModel, evolveMobilityTrips) // Add different location types to the model. auto home_id = model.add_location(mio::abm::LocationType::Home); - auto event_id = model.add_location(mio::abm::LocationType::SocialEvent); + auto event_id = model.add_location(mio::abm::LocationType::Recreation); auto work_id = model.add_location(mio::abm::LocationType::Work); auto hospital_id = model.add_location(mio::abm::LocationType::Hospital); @@ -386,11 +398,11 @@ TEST_F(TestModel, evolveMobilityTrips) .WillRepeatedly(testing::Return(0.8)); // this forces p1 and p3 to recover // Create persons with various infection states and assign them to multiple locations. - auto pid1 = model.add_person(home_id, age_group_15_to_34); - auto pid2 = model.add_person(home_id, age_group_15_to_34); - auto pid3 = model.add_person(home_id, age_group_15_to_34); - auto pid4 = model.add_person(hospital_id, age_group_15_to_34); - auto pid5 = model.add_person(home_id, age_group_15_to_34); + auto pid1 = model.add_person(home_id, age_group_15_to_34, mio::abm::ActivityType::Home); + auto pid2 = model.add_person(home_id, age_group_15_to_34, mio::abm::ActivityType::Home); + auto pid3 = model.add_person(home_id, age_group_15_to_34, mio::abm::ActivityType::Home); + auto pid4 = model.add_person(hospital_id, age_group_15_to_34, mio::abm::ActivityType::Hospital); + auto pid5 = model.add_person(home_id, age_group_15_to_34, mio::abm::ActivityType::Home); // Assign persons to locations for trips. auto& p1 = model.get_person(pid1); @@ -399,25 +411,28 @@ TEST_F(TestModel, evolveMobilityTrips) auto& p4 = model.get_person(pid4); auto& p5 = model.get_person(pid5); - p1.set_assigned_location(mio::abm::LocationType::SocialEvent, event_id, model.get_id()); - p2.set_assigned_location(mio::abm::LocationType::SocialEvent, event_id, model.get_id()); - p1.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p2.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p1.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p2.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p3.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p4.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p3.set_assigned_location(mio::abm::LocationType::Hospital, hospital_id, model.get_id()); - p4.set_assigned_location(mio::abm::LocationType::Hospital, hospital_id, model.get_id()); - p5.set_assigned_location(mio::abm::LocationType::SocialEvent, event_id, model.get_id()); - p5.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p5.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); + p1.set_assigned_location(mio::abm::ActivityType::Recreation, event_id, model.get_id()); + p2.set_assigned_location(mio::abm::ActivityType::Recreation, event_id, model.get_id()); + p1.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p2.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p1.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p2.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p3.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p4.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p3.set_assigned_location(mio::abm::ActivityType::Hospital, hospital_id, model.get_id()); + p4.set_assigned_location(mio::abm::ActivityType::Hospital, hospital_id, model.get_id()); + p5.set_assigned_location(mio::abm::ActivityType::Recreation, event_id, model.get_id()); + p5.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p5.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); // Set trips for persons between assigned locations. mio::abm::TripList& data = model.get_trip_list(); - mio::abm::Trip trip1(p1.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(9), work_id); - mio::abm::Trip trip2(p2.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(9), event_id); - mio::abm::Trip trip3(p5.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(9), event_id); + mio::abm::Trip trip1(p1.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(9), work_id, + mio::abm::ActivityType::Work); + mio::abm::Trip trip2(p2.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(9), event_id, + mio::abm::ActivityType::Recreation); + mio::abm::Trip trip3(p5.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(9), event_id, + mio::abm::ActivityType::Recreation); auto trips_part1 = std::vector{trip2, trip3}; auto trips_part2 = std::vector{trip1}; @@ -500,14 +515,14 @@ TEST_F(TestModel, reachCapacity) .WillRepeatedly(testing::Return(1.0)); // Create two persons with different infection states. - auto p1 = add_test_person(model, home_id, age_group_5_to_14); - auto p2 = add_test_person(model, home_id, age_group_5_to_14); + auto p1 = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_5_to_14); + auto p2 = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_5_to_14); // Assign both persons to School and Home. - model.get_person(p1).set_assigned_location(mio::abm::LocationType::School, school_id, 0); - model.get_person(p2).set_assigned_location(mio::abm::LocationType::School, school_id, 0); - model.get_person(p1).set_assigned_location(mio::abm::LocationType::Home, home_id, 0); - model.get_person(p2).set_assigned_location(mio::abm::LocationType::Home, home_id, 0); + model.get_person(p1).set_assigned_location(mio::abm::ActivityType::School, school_id, 0); + model.get_person(p2).set_assigned_location(mio::abm::ActivityType::School, school_id, 0); + model.get_person(p1).set_assigned_location(mio::abm::ActivityType::Home, home_id, 0); + model.get_person(p2).set_assigned_location(mio::abm::ActivityType::Home, home_id, 0); // Set the capacity of the school to 1 person with a distance requirement of 66. model.get_location(school_id).set_capacity(1, 66); @@ -555,25 +570,29 @@ TEST_F(TestModel, checkMobilityOfDeadPerson) EXPECT_CALL(mock_uniform_dist.get_mock(), invoke).WillRepeatedly(testing::Return(1.0)); // Create a person that is dead at time t - add_test_person(model, icu_id, age_group_60_to_79, mio::abm::InfectionState::Dead, t); + add_test_person(model, icu_id, mio::abm::ActivityType::ICU, age_group_60_to_79, mio::abm::InfectionState::Dead, t); // Create a person that is severe at hospital and will be dead at time t + dt - add_test_person(model, hospital_id, age_group_60_to_79, mio::abm::InfectionState::Dead, t + dt); + add_test_person(model, hospital_id, mio::abm::ActivityType::Hospital, age_group_60_to_79, + mio::abm::InfectionState::Dead, t + dt); auto& p_dead = model.get_persons()[0]; auto& p_severe = model.get_persons()[1]; - p_dead.set_assigned_location(mio::abm::LocationType::ICU, icu_id, model.get_id()); - p_dead.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p_dead.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_severe.set_assigned_location(mio::abm::LocationType::Hospital, hospital_id, model.get_id()); - p_severe.set_assigned_location(mio::abm::LocationType::ICU, icu_id, model.get_id()); - p_severe.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); + p_dead.set_assigned_location(mio::abm::ActivityType::ICU, icu_id, model.get_id()); + p_dead.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p_dead.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_severe.set_assigned_location(mio::abm::ActivityType::Hospital, hospital_id, model.get_id()); + p_severe.set_assigned_location(mio::abm::ActivityType::ICU, icu_id, model.get_id()); + p_severe.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); // Add trip to see if a dead person can change location outside of cemetery by scheduled trips mio::abm::TripList& trip_list = model.get_trip_list(); - mio::abm::Trip trip1(p_dead.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(2), home_id); - mio::abm::Trip trip2(p_dead.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(3), icu_id); - mio::abm::Trip trip3(p_severe.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(3), icu_id); + mio::abm::Trip trip1(p_dead.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(2), home_id, + mio::abm::ActivityType::Home); + mio::abm::Trip trip2(p_dead.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(3), icu_id, + mio::abm::ActivityType::ICU); + mio::abm::Trip trip3(p_severe.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(3), icu_id, + mio::abm::ActivityType::ICU); trip_list.add_trips({trip1, trip2, trip3}); // Check the dead person got burried and the severely infected person starts in Hospital @@ -612,12 +631,12 @@ TEST_F(TestModelTestingCriteria, testAddingAndUpdatingAndRunningTestingSchemes) auto test_time = mio::abm::minutes(30); // Add a person to the model with an infection state that requires testing. // Since tests are performed before current_time, the InfectionState of the Person has to take into account test_time - auto pid = add_test_person(model, home_id, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms, - current_time - test_time); + auto pid = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedSymptoms, current_time - test_time); auto& person = model.get_person(pid); auto rng_person = mio::abm::PersonalRandomNumberGenerator(model.get_rng(), person); - person.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - person.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + person.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); auto validity_period = mio::abm::days(1); const auto start_date = mio::abm::TimePoint(0) + mio::abm::days(1); @@ -851,16 +870,16 @@ TEST_F(TestModel, mobilityRulesWithAppliedNPIs) .WillRepeatedly(testing::Return(0.9)); // draw that satisfies all pre-conditions of NPIs // Since tests are performed before t, the InfectionState of all the Person have to take into account test_time - auto p_id_compliant_go_to_work = - add_test_person(model, home_id, age_group_15_to_34, mio::abm::InfectionState::Susceptible, t - test_time); - auto p_id_compliant_go_to_school = - add_test_person(model, home_id, age_group_5_to_14, mio::abm::InfectionState::Susceptible, t - test_time); - auto p_id_no_mask = - add_test_person(model, home_id, age_group_15_to_34, mio::abm::InfectionState::Susceptible, t - test_time); - auto p_id_no_test = add_test_person(model, home_id, age_group_15_to_34, - mio::abm::InfectionState::InfectedNoSymptoms, t - test_time); - auto p_id_no_isolation = add_test_person(model, home_id, age_group_15_to_34, - mio::abm::InfectionState::InfectedNoSymptoms, t - test_time); + auto p_id_compliant_go_to_work = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::Susceptible, t - test_time); + auto p_id_compliant_go_to_school = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_5_to_14, + mio::abm::InfectionState::Susceptible, t - test_time); + auto p_id_no_mask = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::Susceptible, t - test_time); + auto p_id_no_test = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms, t - test_time); + auto p_id_no_isolation = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms, t - test_time); auto& p_compliant_go_to_work = model.get_person(p_id_compliant_go_to_work); auto& p_compliant_go_to_school = model.get_person(p_id_compliant_go_to_school); @@ -868,17 +887,17 @@ TEST_F(TestModel, mobilityRulesWithAppliedNPIs) auto& p_no_test = model.get_person(p_id_no_test); auto& p_no_isolation = model.get_person(p_id_no_isolation); - p_compliant_go_to_work.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_compliant_go_to_work.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p_compliant_go_to_work.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_compliant_go_to_school.set_assigned_location(mio::abm::LocationType::School, school_id, model.get_id()); - p_compliant_go_to_school.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_no_mask.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p_no_mask.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_no_test.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p_no_test.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_no_isolation.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p_no_isolation.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); + p_compliant_go_to_work.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_compliant_go_to_work.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p_compliant_go_to_work.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_compliant_go_to_school.set_assigned_location(mio::abm::ActivityType::School, school_id, model.get_id()); + p_compliant_go_to_school.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_no_mask.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p_no_mask.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_no_test.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p_no_test.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_no_isolation.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p_no_isolation.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); auto testing_criteria = mio::abm::TestingCriteria( {}, {mio::abm::InfectionState::InfectedSymptoms, mio::abm::InfectionState::InfectedNoSymptoms}); @@ -967,16 +986,16 @@ TEST_F(TestModel, mobilityTripWithAppliedNPIs) .WillRepeatedly(testing::Return(0.9)); // draw that satisfies all pre-conditions of NPIs // Since tests are performed before t, the InfectionState of all the Person have to take into account test_time - auto p_id_compliant_go_to_work = - add_test_person(model, home_id, age_group_15_to_34, mio::abm::InfectionState::Susceptible, t - test_time); - auto p_id_compliant_go_to_school = - add_test_person(model, home_id, age_group_5_to_14, mio::abm::InfectionState::Susceptible, t - test_time); - auto p_id_no_mask = - add_test_person(model, home_id, age_group_15_to_34, mio::abm::InfectionState::Susceptible, t - test_time); - auto p_id_no_test = add_test_person(model, home_id, age_group_15_to_34, - mio::abm::InfectionState::InfectedNoSymptoms, t - test_time); - auto p_id_no_isolation = add_test_person(model, home_id, age_group_15_to_34, - mio::abm::InfectionState::InfectedNoSymptoms, t - test_time); + auto p_id_compliant_go_to_work = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::Susceptible, t - test_time); + auto p_id_compliant_go_to_school = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_5_to_14, + mio::abm::InfectionState::Susceptible, t - test_time); + auto p_id_no_mask = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::Susceptible, t - test_time); + auto p_id_no_test = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms, t - test_time); + auto p_id_no_isolation = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms, t - test_time); auto& p_compliant_go_to_work = model.get_person(p_id_compliant_go_to_work); auto& p_compliant_go_to_school = model.get_person(p_id_compliant_go_to_school); @@ -984,17 +1003,17 @@ TEST_F(TestModel, mobilityTripWithAppliedNPIs) auto& p_no_test = model.get_person(p_id_no_test); auto& p_no_isolation = model.get_person(p_id_no_isolation); - p_compliant_go_to_work.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_compliant_go_to_work.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p_compliant_go_to_work.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_compliant_go_to_school.set_assigned_location(mio::abm::LocationType::School, school_id, model.get_id()); - p_compliant_go_to_school.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_no_mask.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p_no_mask.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_no_test.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p_no_test.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_no_isolation.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); - p_no_isolation.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); + p_compliant_go_to_work.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_compliant_go_to_work.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p_compliant_go_to_work.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_compliant_go_to_school.set_assigned_location(mio::abm::ActivityType::School, school_id, model.get_id()); + p_compliant_go_to_school.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_no_mask.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p_no_mask.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_no_test.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p_no_test.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_no_isolation.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); + p_no_isolation.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); auto testing_criteria = mio::abm::TestingCriteria( {}, {mio::abm::InfectionState::InfectedSymptoms, mio::abm::InfectionState::InfectedNoSymptoms}); @@ -1019,11 +1038,11 @@ TEST_F(TestModel, mobilityTripWithAppliedNPIs) // Using trip list mio::abm::TripList& trip_list = model.get_trip_list(); - mio::abm::Trip trip1(p_compliant_go_to_work.get_id(), t, work_id); - mio::abm::Trip trip2(p_compliant_go_to_school.get_id(), t, school_id); - mio::abm::Trip trip3(p_no_mask.get_id(), t, work_id); - mio::abm::Trip trip4(p_no_test.get_id(), t, work_id); - mio::abm::Trip trip5(p_no_isolation.get_id(), t, work_id); + mio::abm::Trip trip1(p_compliant_go_to_work.get_id(), t, work_id, mio::abm::ActivityType::Work); + mio::abm::Trip trip2(p_compliant_go_to_school.get_id(), t, school_id, mio::abm::ActivityType::School); + mio::abm::Trip trip3(p_no_mask.get_id(), t, work_id, mio::abm::ActivityType::Work); + mio::abm::Trip trip4(p_no_test.get_id(), t, work_id, mio::abm::ActivityType::Work); + mio::abm::Trip trip5(p_no_isolation.get_id(), t, work_id, mio::abm::ActivityType::Work); trip_list.add_trips({trip1, trip2, trip3, trip4, trip5}); model.use_mobility_rules(false); model.evolve(t, dt); @@ -1087,13 +1106,14 @@ TEST_F(TestModel, personCanDieInHospital) EXPECT_CALL(mock_uniform_dist.get_mock(), invoke).WillRepeatedly(testing::Return(0.09)); // Create a person that has InfectedSymptoms at time t - dt. The person is dead at time t + dt - add_test_person(model, home_id, age_group_60_to_79, mio::abm::InfectionState::Dead, t + dt); + add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_60_to_79, mio::abm::InfectionState::Dead, + t + dt); auto& p_severe = model.get_persons()[0]; - p_severe.set_assigned_location(mio::abm::LocationType::Hospital, hospital_id, model.get_id()); - p_severe.set_assigned_location(mio::abm::LocationType::ICU, icu_id, model.get_id()); - p_severe.set_assigned_location(mio::abm::LocationType::Home, home_id, model.get_id()); - p_severe.set_assigned_location(mio::abm::LocationType::Work, work_id, model.get_id()); + p_severe.set_assigned_location(mio::abm::ActivityType::Hospital, hospital_id, model.get_id()); + p_severe.set_assigned_location(mio::abm::ActivityType::ICU, icu_id, model.get_id()); + p_severe.set_assigned_location(mio::abm::ActivityType::Home, home_id, model.get_id()); + p_severe.set_assigned_location(mio::abm::ActivityType::Work, work_id, model.get_id()); // Check the infection course goes from InfectedSymptoms to Severe to Dead and skips Critical EXPECT_EQ(p_severe.get_infection_state(t - dt), mio::abm::InfectionState::InfectedSymptoms); @@ -1118,7 +1138,7 @@ TEST_F(TestModel, reset_rng) { // use DefaultFactory to avoid using the RNG in the Person ctor auto p = mio::DefaultFactory::create(); - p.set_location(mio::abm::LocationType::Cemetery, mio::abm::LocationId(0), 0); + p.set_location(mio::abm::ActivityType::Cemetery, mio::abm::LocationType::Cemetery, mio::abm::LocationId(0), 0); model.add_person(mio::abm::Person(p, mio::abm::PersonId(0))); model.add_person(mio::abm::Person(p, mio::abm::PersonId(1))); } diff --git a/cpp/tests/test_abm_person.cpp b/cpp/tests/test_abm_person.cpp index 9bc2cabc40..9cf8e1eec8 100644 --- a/cpp/tests/test_abm_person.cpp +++ b/cpp/tests/test_abm_person.cpp @@ -17,6 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/location_id.h" #include "abm/model_functions.h" #include "abm/location_type.h" @@ -38,8 +39,8 @@ TEST_F(TestPerson, init) { mio::abm::Location location(mio::abm::LocationType::Work, 7, num_age_groups); auto t = mio::abm::TimePoint(0); - auto person = mio::abm::Person(this->get_rng(), location.get_type(), location.get_id(), location.get_model_id(), - age_group_60_to_79); + auto person = mio::abm::Person(this->get_rng(), location.get_type(), mio::abm::ActivityType::Work, + location.get_id(), location.get_model_id(), age_group_60_to_79); // Verify default state and location assignments. EXPECT_EQ(person.get_infection_state(t), mio::abm::InfectionState::Susceptible); @@ -61,27 +62,31 @@ TEST_F(TestPerson, change_location) mio::abm::Location loc1(mio::abm::LocationType::PublicTransport, 1, 6, 0, 1); mio::abm::Location loc2(mio::abm::LocationType::School, 2, num_age_groups); mio::abm::Location loc3(mio::abm::LocationType::PublicTransport, 3, 6, 0, 2); - auto person = make_test_person(this->get_rng(), home, age_group_0_to_4, mio::abm::InfectionState::Recovered); + auto person = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_0_to_4, + mio::abm::InfectionState::Recovered); // Check that a person does not change location to its current location person.add_time_at_location(mio::abm::hours(1)); - EXPECT_FALSE(mio::abm::change_location(person, home)); + EXPECT_FALSE(mio::abm::change_location(person, home, mio::abm::ActivityType::Home)); EXPECT_EQ(person.get_time_at_location(), mio::abm::hours(1)); EXPECT_EQ(person.get_location(), home.get_id()); // Change the location of the person a couple of times - EXPECT_TRUE(mio::abm::change_location(person, loc1, mio::abm::TransportMode::Unknown, {0})); + EXPECT_TRUE(mio::abm::change_location(person, loc1, mio::abm::ActivityType::Invalid, + mio::abm::TransportMode::Unknown, {0})); EXPECT_EQ(person.get_time_at_location(), mio::abm::TimeSpan(0)); EXPECT_EQ(person.get_location(), loc1.get_id()); EXPECT_EQ(person.get_last_transport_mode(), mio::abm::TransportMode::Unknown); - EXPECT_TRUE(mio::abm::change_location(person, loc2, mio::abm::TransportMode::Walking, {0})); + EXPECT_TRUE(mio::abm::change_location(person, loc2, mio::abm::ActivityType::Invalid, + mio::abm::TransportMode::Walking, {0})); EXPECT_EQ(person.get_time_at_location(), mio::abm::TimeSpan(0)); EXPECT_EQ(person.get_location(), loc2.get_id()); EXPECT_EQ(person.get_last_transport_mode(), mio::abm::TransportMode::Walking); // Test changing location with cell indices. - EXPECT_TRUE(mio::abm::change_location(person, loc3, mio::abm::TransportMode::Bike, {0, 1})); + EXPECT_TRUE(mio::abm::change_location(person, loc3, mio::abm::ActivityType::Invalid, mio::abm::TransportMode::Bike, + {0, 1})); EXPECT_EQ(person.get_time_at_location(), mio::abm::TimeSpan(0)); EXPECT_EQ(person.get_location(), loc3.get_id()); EXPECT_EQ(person.get_last_transport_mode(), mio::abm::TransportMode::Bike); @@ -96,30 +101,32 @@ TEST_F(TestPerson, change_location) TEST_F(TestPerson, setGetAssignedLocation) { mio::abm::Location location(mio::abm::LocationType::Work, 2, num_age_groups); - auto person = mio::abm::Person(this->get_rng(), location.get_type(), location.get_id(), location.get_model_id(), - age_group_35_to_59); + auto person = mio::abm::Person(this->get_rng(), location.get_type(), mio::abm::ActivityType::Work, + location.get_id(), location.get_model_id(), age_group_35_to_59); + auto p_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); // Assign and verify a location for the person. - person.set_assigned_location(location.get_type(), location.get_id(), location.get_model_id()); - EXPECT_EQ(person.get_assigned_location(mio::abm::LocationType::Work), mio::abm::LocationId(2)); + person.set_assigned_location(mio::abm::ActivityType::Work, location.get_id(), location.get_model_id()); + EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng), mio::abm::LocationId(2)); // Change the assigned location and verify. - person.set_assigned_location(mio::abm::LocationType::Work, mio::abm::LocationId(4), 0); - EXPECT_EQ(person.get_assigned_location(mio::abm::LocationType::Work), mio::abm::LocationId(4)); + person.set_assigned_location(mio::abm::ActivityType::Work, mio::abm::LocationId(4), 0); + EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng), mio::abm::LocationId(4)); // Fuzzing: assign random valid LocationId values and verify correctness. for (int i = 0; i < 100; ++i) { auto random_id = this->random_integer(0, std::numeric_limits::max()); - auto random_type = this->random_integer(0, (int)mio::abm::LocationType::Count - 1); - person.set_assigned_location((mio::abm::LocationType)random_type, mio::abm::LocationId(random_id), 0); - EXPECT_EQ(person.get_assigned_location((mio::abm::LocationType)random_type), mio::abm::LocationId(random_id)); + auto random_type = this->random_integer(0, (int)mio::abm::ActivityType::Count - 1); + person.set_assigned_location((mio::abm::ActivityType)random_type, mio::abm::LocationId(random_id), 0); + EXPECT_EQ(person.get_assigned_location((mio::abm::ActivityType)random_type, p_rng), + mio::abm::LocationId(random_id)); } // Boundary test cases: test with boundary LocationIds. - person.set_assigned_location(mio::abm::LocationType::Work, mio::abm::LocationId(0), 0); - EXPECT_EQ(person.get_assigned_location(mio::abm::LocationType::Work), mio::abm::LocationId(0)); + person.set_assigned_location(mio::abm::ActivityType::Work, mio::abm::LocationId(0), 0); + EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng), mio::abm::LocationId(0)); - person.set_assigned_location(mio::abm::LocationType::Work, mio::abm::LocationId(std::numeric_limits::max()), + person.set_assigned_location(mio::abm::ActivityType::Work, mio::abm::LocationId(std::numeric_limits::max()), 0); - EXPECT_EQ(person.get_assigned_location(mio::abm::LocationType::Work), + EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng), mio::abm::LocationId(std::numeric_limits::max())); } @@ -160,7 +167,7 @@ TEST_F(TestPerson, quarantine) infection_parameters.get().set_multiple({age_group_5_to_14}, true); infection_parameters.get().set_multiple({age_group_15_to_34, age_group_35_to_59}, true); - auto person = make_test_person(this->get_rng(), home, age_group_35_to_59, + auto person = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_35_to_59, mio::abm::InfectionState::InfectedSymptoms, t_morning, infection_parameters); auto rng_person = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); @@ -187,11 +194,11 @@ TEST_F(TestPerson, get_tested) mio::abm::TimePoint t(0); mio::abm::Location loc(mio::abm::LocationType::Home, 0, num_age_groups); - auto infected = - make_test_person(this->get_rng(), loc, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms); - auto rng_infected = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), infected); - auto susceptible = - mio::abm::Person(this->get_rng(), loc.get_type(), loc.get_id(), loc.get_model_id(), age_group_15_to_34); + auto infected = make_test_person(this->get_rng(), loc, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedSymptoms); + auto rng_infected = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), infected); + auto susceptible = mio::abm::Person(this->get_rng(), loc.get_type(), mio::abm::ActivityType::Home, loc.get_id(), + loc.get_model_id(), age_group_15_to_34); auto rng_suscetible = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), susceptible); auto pcr_parameters = params.get()[mio::abm::TestType::PCR]; @@ -253,11 +260,12 @@ TEST_F(TestPerson, getCells) mio::abm::Location home(mio::abm::LocationType::Home, 0, 6, 1); mio::abm::Location location(mio::abm::LocationType::PublicTransport, 1, 6, 0, 7); // Create a test person at the home location. - auto person = - make_test_person(this->get_rng(), home, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms); + auto person = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms); // Move the person to a new location with specified cells (3, 5). - EXPECT_TRUE(mio::abm::change_location(person, location, mio::abm::TransportMode::Unknown, {3, 5})); + EXPECT_TRUE(mio::abm::change_location(person, location, mio::abm::ActivityType::Invalid, + mio::abm::TransportMode::Unknown, {3, 5})); // Check that the person's cell indices have been updated correctly. EXPECT_EQ(person.get_cells().size(), 2); @@ -276,8 +284,8 @@ TEST_F(TestPerson, interact) mio::abm::Location loc(mio::abm::LocationType::Home, 0, num_age_groups); mio::abm::TimePoint t(0); // Create a person and set up a random number generator specific to that person. - auto person = - mio::abm::Person(this->get_rng(), loc.get_type(), loc.get_id(), loc.get_model_id(), age_group_15_to_34); + auto person = mio::abm::Person(this->get_rng(), loc.get_type(), mio::abm::ActivityType::Home, loc.get_id(), + loc.get_model_id(), age_group_15_to_34); auto rng_person = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); auto dt = mio::abm::seconds(8640); //0.1 days // Simulate interaction and check that the person accumulates time at the location. @@ -309,13 +317,13 @@ TEST_F(TestPerson, getMaskProtectiveFactor) { auto t = mio::abm::TimePoint(0); mio::abm::Location location(mio::abm::LocationType::School, 0, 6); - auto person_community = make_test_person(this->get_rng(), location); + auto person_community = make_test_person(this->get_rng(), location, mio::abm::ActivityType::School); person_community.set_mask(mio::abm::MaskType::Community, t); - auto person_surgical = make_test_person(this->get_rng(), location); + auto person_surgical = make_test_person(this->get_rng(), location, mio::abm::ActivityType::School); person_surgical.set_mask(mio::abm::MaskType::Surgical, t); - auto person_ffp2 = make_test_person(this->get_rng(), location); + auto person_ffp2 = make_test_person(this->get_rng(), location, mio::abm::ActivityType::School); person_ffp2.set_mask(mio::abm::MaskType::FFP2, t); - auto person_without = make_test_person(this->get_rng(), location); + auto person_without = make_test_person(this->get_rng(), location, mio::abm::ActivityType::School); person_without.set_mask(mio::abm::MaskType::None, t); mio::abm::Parameters params = mio::abm::Parameters(num_age_groups); @@ -335,10 +343,10 @@ TEST_F(TestPerson, getMaskProtectiveFactor) */ TEST_F(TestPerson, getLatestProtection) { - auto location = mio::abm::Location(mio::abm::LocationType::School, 0, num_age_groups); - auto person = mio::abm::Person(this->get_rng(), location.get_type(), location.get_id(), location.get_model_id(), - age_group_15_to_34); - auto prng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); + auto location = mio::abm::Location(mio::abm::LocationType::School, 0, num_age_groups); + auto person = mio::abm::Person(this->get_rng(), location.get_type(), mio::abm::ActivityType::School, + location.get_id(), location.get_model_id(), age_group_15_to_34); + auto prng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); mio::abm::Parameters params = mio::abm::Parameters(num_age_groups); auto t = mio::abm::TimePoint(0); @@ -362,7 +370,8 @@ TEST_F(TestPerson, getLatestProtection) */ TEST_F(TestPerson, rng) { - auto p = mio::abm::Person(this->get_rng(), mio::abm::LocationType::Home, 0, 0, age_group_35_to_59, 13); + auto p = mio::abm::Person(this->get_rng(), mio::abm::LocationType::Home, mio::abm::ActivityType::Home, 0, 0, + age_group_35_to_59, 13); EXPECT_EQ(p.get_rng_counter(), mio::Counter(0)); @@ -381,7 +390,7 @@ TEST_F(TestPerson, rng) TEST_F(TestPerson, addAndGetTestResult) { mio::abm::Location location(mio::abm::LocationType::School, 0, num_age_groups); - auto person = make_test_person(this->get_rng(), location); + auto person = make_test_person(this->get_rng(), location, mio::abm::ActivityType::School); auto t = mio::abm::TimePoint(0); // Tests if m_test_results initialized correctly EXPECT_EQ(person.get_test_result(mio::abm::TestType::Generic).time_of_testing, @@ -409,7 +418,7 @@ TEST_F(TestPerson, isCompliant) mio::abm::Location home(mio::abm::LocationType::Home, 0, num_age_groups); // Create test person and associated random number generator - auto person = make_test_person(this->get_rng(), home); + auto person = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home); auto rng_person = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); // Test cases with a complete truth table for compliance levels diff --git a/cpp/tests/test_abm_simulation.cpp b/cpp/tests/test_abm_simulation.cpp index 8fd25b66aa..5bef2c7072 100644 --- a/cpp/tests/test_abm_simulation.cpp +++ b/cpp/tests/test_abm_simulation.cpp @@ -17,6 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/location_type.h" #include "abm/simulation.h" #include "abm/result_simulation.h" @@ -33,15 +34,15 @@ TEST(TestSimulation, advance_random) auto model = mio::abm::Model(num_age_groups); auto location1 = model.add_location(mio::abm::LocationType::School); auto location2 = model.add_location(mio::abm::LocationType::School); - auto p1 = model.add_person(location1, age_group_5_to_14); - auto p2 = model.add_person(location1, age_group_5_to_14); - auto p3 = model.add_person(location2, age_group_5_to_14); - auto p4 = model.add_person(location2, age_group_5_to_14); + auto p1 = model.add_person(location1, age_group_5_to_14, mio::abm::ActivityType::School); + auto p2 = model.add_person(location1, age_group_5_to_14, mio::abm::ActivityType::School); + auto p3 = model.add_person(location2, age_group_5_to_14, mio::abm::ActivityType::School); + auto p4 = model.add_person(location2, age_group_5_to_14, mio::abm::ActivityType::School); - model.assign_location(p1, location1); - model.assign_location(p2, location1); - model.assign_location(p3, location2); - model.assign_location(p4, location2); + model.assign_location(p1, location1, mio::abm::ActivityType::School); + model.assign_location(p2, location1, mio::abm::ActivityType::School); + model.assign_location(p3, location2, mio::abm::ActivityType::School); + model.assign_location(p4, location2, mio::abm::ActivityType::School); auto sim = mio::abm::Simulation(mio::abm::TimePoint(0), std::move(model)); @@ -78,39 +79,49 @@ TEST(TestSimulation, advanceWithCommonHistory) auto icu_id = model.add_location(mio::abm::LocationType::ICU); auto hospital_id = model.add_location(mio::abm::LocationType::Hospital); auto school_id = model.add_location(mio::abm::LocationType::School); - auto social_id = model.add_location(mio::abm::LocationType::SocialEvent); + auto social_id = model.add_location(mio::abm::LocationType::Recreation); auto basics_id = model.add_location(mio::abm::LocationType::BasicsShop); auto public_id = model.add_location(mio::abm::LocationType::PublicTransport); - auto person1 = add_test_person(model, home_id, age_group_5_to_14, mio::abm::InfectionState::Exposed); - auto person2 = add_test_person(model, home_id, age_group_15_to_34, mio::abm::InfectionState::Exposed); - auto person3 = add_test_person(model, home_id, age_group_35_to_59, mio::abm::InfectionState::Dead); - - model.assign_location(person1, home_id); - model.assign_location(person2, home_id); - model.assign_location(person3, home_id); - model.assign_location(person1, school_id); - model.assign_location(person2, work_id); - model.assign_location(person2, icu_id); - model.assign_location(person2, hospital_id); - model.assign_location(person1, social_id); - model.assign_location(person2, social_id); - model.assign_location(person3, social_id); - model.assign_location(person1, basics_id); - model.assign_location(person2, basics_id); - model.assign_location(person3, basics_id); - model.assign_location(person2, public_id); + auto person1 = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_5_to_14, + mio::abm::InfectionState::Exposed); + auto person2 = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::Exposed); + auto person3 = add_test_person(model, home_id, mio::abm::ActivityType::Home, age_group_35_to_59, + mio::abm::InfectionState::Dead); + + model.assign_location(person1, home_id, mio::abm::ActivityType::Home); + model.assign_location(person2, home_id, mio::abm::ActivityType::Home); + model.assign_location(person3, home_id, mio::abm::ActivityType::Home); + model.assign_location(person1, school_id, mio::abm::ActivityType::School); + model.assign_location(person2, work_id, mio::abm::ActivityType::Work); + model.assign_location(person2, icu_id, mio::abm::ActivityType::ICU); + model.assign_location(person2, hospital_id, mio::abm::ActivityType::Hospital); + model.assign_location(person1, social_id, mio::abm::ActivityType::Recreation); + model.assign_location(person2, social_id, mio::abm::ActivityType::Recreation); + model.assign_location(person3, social_id, mio::abm::ActivityType::Recreation); + model.assign_location(person1, basics_id, mio::abm::ActivityType::BasicsShop); + model.assign_location(person2, basics_id, mio::abm::ActivityType::BasicsShop); + model.assign_location(person3, basics_id, mio::abm::ActivityType::BasicsShop); + model.assign_location(person2, public_id, mio::abm::ActivityType::Invalid); mio::abm::TripList& trip_list = model.get_trip_list(); // We add trips for person two to test the history and if it is working correctly - mio::abm::Trip trip1(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(2), home_id); - mio::abm::Trip trip2(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(3), home_id); - mio::abm::Trip trip3(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(4), home_id); - mio::abm::Trip trip4(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(5), home_id); - mio::abm::Trip trip5(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(6), home_id); - mio::abm::Trip trip6(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(7), home_id); - mio::abm::Trip trip7(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(8), home_id); + mio::abm::Trip trip1(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(2), home_id, + mio::abm::ActivityType::Home); + mio::abm::Trip trip2(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(3), home_id, + mio::abm::ActivityType::Home); + mio::abm::Trip trip3(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(4), home_id, + mio::abm::ActivityType::Home); + mio::abm::Trip trip4(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(5), home_id, + mio::abm::ActivityType::Home); + mio::abm::Trip trip5(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(6), home_id, + mio::abm::ActivityType::Home); + mio::abm::Trip trip6(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(7), home_id, + mio::abm::ActivityType::Home); + mio::abm::Trip trip7(static_cast(person2.get()), mio::abm::TimePoint(0) + mio::abm::hours(8), home_id, + mio::abm::ActivityType::Home); // Add to one vector auto trips = std::vector{trip1, trip2, trip3, trip4, trip5, trip6, trip7}; @@ -153,9 +164,9 @@ TEST(TestSimulation, ResultSimulation) // run a ResultSimulation on a minimal setup auto model = mio::abm::Model(num_age_groups); auto location = model.add_location(mio::abm::LocationType::Home); - auto person = model.add_person(location, age_group_15_to_34); + auto person = model.add_person(location, age_group_15_to_34, mio::abm::ActivityType::Home); - model.assign_location(person, location); + model.assign_location(person, location, mio::abm::ActivityType::Home); const auto t0 = mio::abm::TimePoint(0) + mio::abm::hours(100); const auto tmax = t0 + mio::abm::hours(50); diff --git a/cpp/tests/test_abm_testing_strategy.cpp b/cpp/tests/test_abm_testing_strategy.cpp index 64cbb88fc8..5a850cef48 100644 --- a/cpp/tests/test_abm_testing_strategy.cpp +++ b/cpp/tests/test_abm_testing_strategy.cpp @@ -17,6 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/testing_strategy.h" #include "abm_helpers.h" #include "random_number_test.h" @@ -30,8 +31,8 @@ TEST_F(TestTestingCriteria, addRemoveAndEvaluateTestCriteria) // Create test locations and a person in a specific infection state. mio::abm::Location home(mio::abm::LocationType::Home, 0, num_age_groups); mio::abm::Location work(mio::abm::LocationType::Work, 0, num_age_groups); - auto person = - make_test_person(this->get_rng(), home, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms); + auto person = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedSymptoms); mio::abm::TimePoint t{0}; // Initialize testing criteria with no age group or infection state set. @@ -105,8 +106,8 @@ TEST_F(TestTestingScheme, runScheme) make_test_person(this->get_rng(), loc_home, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms, start_date - test_params_pcr.required_time); auto rng_person1 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person1); - auto person2 = make_test_person(this->get_rng(), loc_home, age_group_15_to_34, mio::abm::InfectionState::Recovered, - start_date - test_params_pcr.required_time); + auto person2 = make_test_person(this->get_rng(), loc_home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::Recovered, start_date - test_params_pcr.required_time); auto rng_person2 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person2); // Mock uniform distribution to control random behavior in testing. @@ -154,8 +155,8 @@ TEST_F(TestTestingScheme, initAndRunTestingStrategy) make_test_person(this->get_rng(), loc_work, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms, start_date - test_params_pcr.required_time); auto rng_person1 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person1); - auto person2 = make_test_person(this->get_rng(), loc_work, age_group_15_to_34, mio::abm::InfectionState::Recovered, - start_date - test_params_pcr.required_time); + auto person2 = make_test_person(this->get_rng(), loc_work, mio::abm::ActivityType::Work, age_group_15_to_34, + mio::abm::InfectionState::Recovered, start_date - test_params_pcr.required_time); auto rng_person2 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person2); // Mock uniform distribution to control random behavior in testing. @@ -190,14 +191,14 @@ TEST_F(TestTestingCriteria, testingCriteriaEdgeCases) mio::abm::Location home(mio::abm::LocationType::Home, 0, num_age_groups); // Test with various infection states - auto person_exposed = - make_test_person(this->get_rng(), home, age_group_15_to_34, mio::abm::InfectionState::Exposed); - auto person_symptoms = - make_test_person(this->get_rng(), home, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms); - auto person_no_symptoms = - make_test_person(this->get_rng(), home, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms); - auto person_recovered = - make_test_person(this->get_rng(), home, age_group_15_to_34, mio::abm::InfectionState::Recovered); + auto person_exposed = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::Exposed); + auto person_symptoms = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedSymptoms); + auto person_no_symptoms = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms); + auto person_recovered = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::Recovered); mio::abm::TimePoint t{0}; @@ -217,14 +218,14 @@ TEST_F(TestTestingCriteria, testingCriteriaEdgeCases) auto testing_criteria_age = mio::abm::TestingCriteria(test_age_groups, {}); // Create persons with different age groups - auto person_young = - make_test_person(this->get_rng(), home, age_group_5_to_14, mio::abm::InfectionState::Susceptible); - auto person_adult = - make_test_person(this->get_rng(), home, age_group_15_to_34, mio::abm::InfectionState::Susceptible); - auto person_older = - make_test_person(this->get_rng(), home, age_group_35_to_59, mio::abm::InfectionState::Susceptible); - auto person_senior = - make_test_person(this->get_rng(), home, age_group_60_to_79, mio::abm::InfectionState::Susceptible); + auto person_young = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_5_to_14, + mio::abm::InfectionState::Susceptible); + auto person_adult = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::Susceptible); + auto person_older = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_35_to_59, + mio::abm::InfectionState::Susceptible); + auto person_senior = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_60_to_79, + mio::abm::InfectionState::Susceptible); // Should match only specified age groups EXPECT_EQ(testing_criteria_age.evaluate(person_young, t), false); @@ -236,12 +237,12 @@ TEST_F(TestTestingCriteria, testingCriteriaEdgeCases) auto testing_criteria_both = mio::abm::TestingCriteria(test_age_groups, test_infection_states); // Should match only when both criteria are met - auto person_adult_infected = - make_test_person(this->get_rng(), home, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms); - auto person_young_infected = - make_test_person(this->get_rng(), home, age_group_5_to_14, mio::abm::InfectionState::InfectedSymptoms); - auto person_adult_recovered = - make_test_person(this->get_rng(), home, age_group_15_to_34, mio::abm::InfectionState::Recovered); + auto person_adult_infected = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, + age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms); + auto person_young_infected = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, + age_group_5_to_14, mio::abm::InfectionState::InfectedSymptoms); + auto person_adult_recovered = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, + age_group_15_to_34, mio::abm::InfectionState::Recovered); EXPECT_EQ(testing_criteria_both.evaluate(person_adult_infected, t), true); EXPECT_EQ(testing_criteria_both.evaluate(person_young_infected, t), false); @@ -289,7 +290,7 @@ TEST_F(TestTestingScheme, testingSchemeResultCaching) // Create test person and location mio::abm::Location loc_home(mio::abm::LocationType::Home, 0, num_age_groups); - auto person = make_test_person(this->get_rng(), loc_home, age_group_15_to_34, + auto person = make_test_person(this->get_rng(), loc_home, mio::abm::ActivityType::Home, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms, start_date); auto rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); @@ -342,13 +343,13 @@ TEST_F(TestTestingScheme, differentTestTypes) // Create test persons with different infection states mio::abm::Location loc_home(mio::abm::LocationType::Home, 0, num_age_groups); auto person_infected = - make_test_person(this->get_rng(), loc_home, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms, - start_date - test_params_pcr.required_time); + make_test_person(this->get_rng(), loc_home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms, start_date - test_params_pcr.required_time); auto rng_infected = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person_infected); auto person_healthy = - make_test_person(this->get_rng(), loc_home, age_group_15_to_34, mio::abm::InfectionState::Susceptible, - start_date - test_params_pcr.required_time); + make_test_person(this->get_rng(), loc_home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::Susceptible, start_date - test_params_pcr.required_time); auto rng_healthy = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person_healthy); // Mock uniform distribution to control test results @@ -420,11 +421,11 @@ TEST_F(TestTestingScheme, multipleSchemesCombination) // Add schemes to different location types test_strategy.add_scheme(mio::abm::LocationType::School, testing_scheme_children); test_strategy.add_scheme(mio::abm::LocationType::Work, testing_scheme_adults); - test_strategy.add_scheme(mio::abm::LocationType::SocialEvent, testing_scheme_seniors); + test_strategy.add_scheme(mio::abm::LocationType::Recreation, testing_scheme_seniors); // Also add multiple location types at once std::vector public_locations = {mio::abm::LocationType::BasicsShop, - mio::abm::LocationType::SocialEvent}; + mio::abm::LocationType::Recreation}; test_strategy.add_scheme(public_locations, testing_scheme_adults); // Create locations @@ -434,10 +435,10 @@ TEST_F(TestTestingScheme, multipleSchemesCombination) mio::abm::Location loc_shop(mio::abm::LocationType::BasicsShop, 3, num_age_groups); // Create persons of different age groups - auto child = make_test_person(this->get_rng(), loc_home, age_group_5_to_14, mio::abm::InfectionState::Susceptible, - start_date); - auto adult = make_test_person(this->get_rng(), loc_home, age_group_35_to_59, mio::abm::InfectionState::Susceptible, - start_date); + auto child = make_test_person(this->get_rng(), loc_home, mio::abm::ActivityType::Home, age_group_5_to_14, + mio::abm::InfectionState::Susceptible, start_date); + auto adult = make_test_person(this->get_rng(), loc_home, mio::abm::ActivityType::Home, age_group_35_to_59, + mio::abm::InfectionState::Susceptible, start_date); auto rng_child = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), child); auto rng_adult = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), adult); @@ -493,9 +494,9 @@ TEST_F(TestTestingScheme, locationSpecificSchemes) mio::abm::Location shop2(mio::abm::LocationType::BasicsShop, 43, num_age_groups); // Different ID // Create a test person - auto person = - make_test_person(this->get_rng(), shop1, age_group_15_to_34, mio::abm::InfectionState::Susceptible, start_date); - auto rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); + auto person = make_test_person(this->get_rng(), shop1, mio::abm::ActivityType::BasicsShop, age_group_15_to_34, + mio::abm::InfectionState::Susceptible, start_date); + auto rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); // Mock uniform distribution to control test results ScopedMockDistribution>>> mock_uniform_dist; @@ -539,9 +540,9 @@ TEST_F(TestTestingScheme, testCompliance) mio::abm::Location shop1(mio::abm::LocationType::BasicsShop, 42, num_age_groups); // Has the specific ID // Create a test person - auto person = - make_test_person(this->get_rng(), shop1, age_group_15_to_34, mio::abm::InfectionState::Susceptible, start_date); - auto rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); + auto person = make_test_person(this->get_rng(), shop1, mio::abm::ActivityType::BasicsShop, age_group_15_to_34, + mio::abm::InfectionState::Susceptible, start_date); + auto rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); person.set_compliance(mio::abm::InterventionType::Testing, 0.1); // Set compliance for testing // Mock uniform distribution to control test results diff --git a/cpp/tests/test_graph_abm.cpp b/cpp/tests/test_graph_abm.cpp index e26fd7f6b6..40ed67981d 100644 --- a/cpp/tests/test_graph_abm.cpp +++ b/cpp/tests/test_graph_abm.cpp @@ -18,6 +18,7 @@ * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/location.h" #include "abm/location_id.h" #include "abm/mobility_data.h" @@ -52,11 +53,11 @@ TEST(TestGraphAbm, test_advance_node) auto home_id = model.add_location(mio::abm::LocationType::Home); auto& home = model.get_location(home_id); auto work = mio::abm::Location(mio::abm::LocationType::Work, mio::abm::LocationId(0), size_t(1), 2); - auto pid = model.add_person(home_id, mio::AgeGroup(0)); + auto pid = model.add_person(home_id, mio::AgeGroup(0), mio::abm::ActivityType::Home); auto index = model.get_person_index(pid); auto& p = model.get_person(pid); - p.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p.set_assigned_location(work.get_type(), work.get_id(), 2); + p.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p.set_assigned_location(mio::abm::ActivityType::Work, work.get_id(), 2); mio::ABMSimulationNode node(MockHistory{}, t, std::move(model)); EXPECT_EQ(node.get_simulation().get_model().get_activeness_statuses()[index], true); node.advance(t, dt); @@ -87,8 +88,8 @@ TEST(TestGraphAbm, test_apply_mobility) auto home_id = model1.add_location(mio::abm::LocationType::Home); auto work_id_2 = model2.add_location(mio::abm::LocationType::Work); auto work_id_3 = model3.add_location(mio::abm::LocationType::Work); - auto event_id_1 = model1.add_location(mio::abm::LocationType::SocialEvent); - auto event_id_2 = model2.add_location(mio::abm::LocationType::SocialEvent); + auto event_id_1 = model1.add_location(mio::abm::LocationType::Recreation); + auto event_id_2 = model2.add_location(mio::abm::LocationType::Recreation); auto& work_1 = model1.get_location(work_id_1); auto& work_2 = model2.get_location(work_id_2); auto& work_3 = model3.get_location(work_id_3); @@ -100,32 +101,31 @@ TEST(TestGraphAbm, test_apply_mobility) EXPECT_EQ(work_2.get_model_id(), 2); EXPECT_EQ(work_3.get_model_id(), 3); - auto p1_id = model1.add_person(home_id, mio::AgeGroup(0)); - auto p2_id = model1.add_person(home_id, mio::AgeGroup(0)); - auto p3_id = model1.add_person(home_id, mio::AgeGroup(1)); - auto p4_id = model1.add_person(home_id, mio::AgeGroup(1)); - auto p5_id = model1.add_person(home_id, mio::AgeGroup(0)); + auto p1_id = model1.add_person(home_id, mio::AgeGroup(0), mio::abm::ActivityType::Home); + auto p2_id = model1.add_person(home_id, mio::AgeGroup(0), mio::abm::ActivityType::Home); + auto p3_id = model1.add_person(home_id, mio::AgeGroup(1), mio::abm::ActivityType::Home); + auto p4_id = model1.add_person(home_id, mio::AgeGroup(1), mio::abm::ActivityType::Home); + auto p5_id = model1.add_person(home_id, mio::AgeGroup(0), mio::abm::ActivityType::Home); auto& p1 = model1.get_person(p1_id); auto& p2 = model1.get_person(p2_id); auto& p3 = model1.get_person(p3_id); auto& p4 = model1.get_person(p4_id); auto& p5 = model1.get_person(p5_id); - p1.set_assigned_location(work_1.get_type(), work_1.get_id(), work_1.get_model_id()); - p2.set_assigned_location(work_2.get_type(), work_2.get_id(), work_2.get_model_id()); - p5.set_assigned_location(work_3.get_type(), work_3.get_id(), work_3.get_model_id()); - p1.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p2.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p3.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p4.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p5.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p3.set_assigned_location(event_1.get_type(), event_1.get_id(), event_1.get_model_id()); - p4.set_assigned_location(event_2.get_type(), event_2.get_id(), event_2.get_model_id()); - + p1.set_assigned_location(mio::abm::ActivityType::Work, work_1.get_id(), work_1.get_model_id()); + p2.set_assigned_location(mio::abm::ActivityType::Work, work_2.get_id(), work_2.get_model_id()); + p5.set_assigned_location(mio::abm::ActivityType::Work, work_3.get_id(), work_3.get_model_id()); + p1.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p2.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p3.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p4.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p5.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p3.set_assigned_location(mio::abm::ActivityType::Recreation, event_1.get_id(), event_1.get_model_id()); + p4.set_assigned_location(mio::abm::ActivityType::Recreation, event_2.get_id(), event_2.get_model_id()); mio::abm::TripList& trips = model1.get_trip_list(); - mio::abm::Trip trip1(p3.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(8), event_id_1, model1.get_id(), - mio::abm::TransportMode::Unknown, {}); - mio::abm::Trip trip2(p4.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(8), event_id_2, model2.get_id(), - mio::abm::TransportMode::Unknown, {}); + mio::abm::Trip trip1(p3.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(8), event_id_1, + mio::abm::ActivityType::Recreation, model1.get_id(), mio::abm::TransportMode::Unknown, {}); + mio::abm::Trip trip2(p4.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(8), event_id_2, + mio::abm::ActivityType::Recreation, model2.get_id(), mio::abm::TransportMode::Unknown, {}); auto tripsvec = std::vector{trip1, trip2}; trips.add_trips(tripsvec); @@ -201,22 +201,22 @@ TEST(TestGraphABM, mask_compliance) //school and work require FFP2 masks school.set_required_mask(mio::abm::MaskType::FFP2); work.set_required_mask(mio::abm::MaskType::FFP2); - auto p_id1 = model.add_person(home_id, mio::AgeGroup(1)); - auto p_id2 = model.add_person(home_id, mio::AgeGroup(0)); + auto p_id1 = model.add_person(home_id, mio::AgeGroup(1), mio::abm::ActivityType::Home); + auto p_id2 = model.add_person(home_id, mio::AgeGroup(0), mio::abm::ActivityType::Home); auto& p1 = model.get_person(p_id1); auto& p2 = model.get_person(p_id2); - p1.set_assigned_location(work.get_type(), work.get_id(), work.get_model_id()); - p1.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); - p2.set_assigned_location(school.get_type(), school.get_id(), school.get_model_id()); - p2.set_assigned_location(home.get_type(), home.get_id(), home.get_model_id()); + p1.set_assigned_location(mio::abm::ActivityType::Work, work.get_id(), work.get_model_id()); + p1.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); + p2.set_assigned_location(mio::abm::ActivityType::School, school.get_id(), school.get_model_id()); + p2.set_assigned_location(mio::abm::ActivityType::Home, home.get_id(), home.get_model_id()); //person is not compliant with mask p1.set_compliance(mio::abm::InterventionType::Mask, 0.0); p2.set_compliance(mio::abm::InterventionType::Mask, 0.0); //add trips for p2 mio::abm::TripList& trips = model.get_trip_list(); - mio::abm::Trip trip1(p2.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(8), school_id, model.get_id(), - mio::abm::TransportMode::Unknown, {}); + mio::abm::Trip trip1(p2.get_id(), mio::abm::TimePoint(0) + mio::abm::hours(8), school_id, + mio::abm::ActivityType::School, model.get_id(), mio::abm::TransportMode::Unknown, {}); trips.add_trips({trip1}); @@ -244,8 +244,8 @@ TEST(TestGraphABM, test_get_person) auto model = mio::GraphABModel(size_t(2), 0, std::vector{&mio::abm::go_to_work}); auto home = model.add_location(mio::abm::LocationType::Home); auto work = model.add_location(mio::abm::LocationType::Work); - auto pid1 = model.add_person(home, mio::AgeGroup(0)); - auto pid2 = model.add_person(work, mio::AgeGroup(1)); + auto pid1 = model.add_person(home, mio::AgeGroup(0), mio::abm::ActivityType::Home); + auto pid2 = model.add_person(work, mio::AgeGroup(1), mio::abm::ActivityType::Work); auto& p1 = model.get_person(pid1); EXPECT_EQ(p1.get_location(), home); From f9f7b35dad5afe7386cdbd6af08c8634df172a09 Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Thu, 23 Apr 2026 10:37:19 +0200 Subject: [PATCH 02/12] fix build bugs --- cpp/examples/abm_parameter_study.cpp | 13 ++-- cpp/models/graph_abm/graph_abm_mobility.h | 2 +- cpp/tests/test_abm_lockdown_rules.cpp | 12 ++-- cpp/tests/test_abm_mobility_rules.cpp | 88 +++++++++++------------ cpp/tests/test_abm_person.cpp | 16 ++--- cpp/tests/test_abm_serialization.cpp | 25 ++++--- cpp/tests/test_abm_testing_strategy.cpp | 8 +-- 7 files changed, 86 insertions(+), 78 deletions(-) diff --git a/cpp/examples/abm_parameter_study.cpp b/cpp/examples/abm_parameter_study.cpp index 1f8627532a..4c3996a38e 100644 --- a/cpp/examples/abm_parameter_study.cpp +++ b/cpp/examples/abm_parameter_study.cpp @@ -17,6 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/result_simulation.h" #include "abm/household.h" #include "abm/lockdown_rules.h" @@ -143,17 +144,17 @@ mio::abm::Model make_model(const mio::RandomNumberGenerator& rng) for (auto& person : model.get_persons()) { const auto id = person.get_id(); //assign shop and event - model.assign_location(id, event); - model.assign_location(id, shop); + model.assign_location(id, event, mio::abm::ActivityType::Recreation); + model.assign_location(id, shop, mio::abm::ActivityType::BasicsShop); //assign hospital and ICU - model.assign_location(id, hospital); - model.assign_location(id, icu); + model.assign_location(id, hospital, mio::abm::ActivityType::Hospital); + model.assign_location(id, icu, mio::abm::ActivityType::ICU); //assign work/school to people depending on their age if (person.get_age() == age_group_5_to_14) { - model.assign_location(id, school); + model.assign_location(id, school, mio::abm::ActivityType::School); } if (person.get_age() == age_group_15_to_34 || person.get_age() == age_group_35_to_59) { - model.assign_location(id, work); + model.assign_location(id, work, mio::abm::ActivityType::Work); } } diff --git a/cpp/models/graph_abm/graph_abm_mobility.h b/cpp/models/graph_abm/graph_abm_mobility.h index f4b8e62218..f36f7f82f0 100644 --- a/cpp/models/graph_abm/graph_abm_mobility.h +++ b/cpp/models/graph_abm/graph_abm_mobility.h @@ -132,7 +132,7 @@ class ABMMobilityEdge target_type = model_to.get_location(target_id).get_type(); } //set correct location for person - person.set_location(target_type, target_id, model_to.get_id()); + person.set_location(person.get_activity_type(), target_type, target_id, model_to.get_id()); //add person to model_to model_to.add_person(std::move(person)); //remove person from model_from diff --git a/cpp/tests/test_abm_lockdown_rules.cpp b/cpp/tests/test_abm_lockdown_rules.cpp index d0de9c3a22..e004b95375 100644 --- a/cpp/tests/test_abm_lockdown_rules.cpp +++ b/cpp/tests/test_abm_lockdown_rules.cpp @@ -75,9 +75,9 @@ TEST_F(TestLockdownRules, school_closure) // Test that p1 stays home and p2 goes to school auto p1_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p1); - EXPECT_EQ(mio::abm::go_to_school(p1_rng, p1, t_morning, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_school(p1_rng, p1, t_morning, dt, params), mio::abm::ActivityType::Home); auto p2_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p2); - EXPECT_EQ(mio::abm::go_to_school(p2_rng, p2, t_morning, dt, params), mio::abm::LocationType::School); + EXPECT_EQ(mio::abm::go_to_school(p2_rng, p2, t_morning, dt, params), mio::abm::ActivityType::School); } /** @@ -124,7 +124,7 @@ TEST_F(TestLockdownRules, school_opening) // Test that after reopening, the person goes to school auto p_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p); - EXPECT_EQ(mio::abm::go_to_school(p_rng, p, t_morning, dt, params), mio::abm::LocationType::School); + EXPECT_EQ(mio::abm::go_to_school(p_rng, p, t_morning, dt, params), mio::abm::ActivityType::School); } /** @@ -172,9 +172,9 @@ TEST_F(TestLockdownRules, home_office) // Check that person1 goes to work and person2 stays at home. auto p1_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person1); - EXPECT_EQ(mio::abm::go_to_work(p1_rng, person1, t_morning, dt, params), mio::abm::LocationType::Work); + EXPECT_EQ(mio::abm::go_to_work(p1_rng, person1, t_morning, dt, params), mio::abm::ActivityType::Work); auto p2_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person2); - EXPECT_EQ(mio::abm::go_to_work(p2_rng, person2, t_morning, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_work(p2_rng, person2, t_morning, dt, params), mio::abm::ActivityType::Home); } /** @@ -218,7 +218,7 @@ TEST_F(TestLockdownRules, no_home_office) // Test that after removing the home office rules, p goes back to the office. auto p_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p); - EXPECT_EQ(mio::abm::go_to_work(p_rng, p, t_morning, dt, params), mio::abm::LocationType::Work); + EXPECT_EQ(mio::abm::go_to_work(p_rng, p, t_morning, dt, params), mio::abm::ActivityType::Work); } /** diff --git a/cpp/tests/test_abm_mobility_rules.cpp b/cpp/tests/test_abm_mobility_rules.cpp index 2280df17e7..08aed7d2b9 100644 --- a/cpp/tests/test_abm_mobility_rules.cpp +++ b/cpp/tests/test_abm_mobility_rules.cpp @@ -32,9 +32,9 @@ using TestMobilityRules = RandomNumberTest; TEST_F(TestMobilityRules, random_mobility) { int t = 0, dt = 1; - auto default_type = mio::abm::LocationType::Cemetery; - auto person = - mio::abm::Person(this->get_rng(), default_type, mio::abm::ActivityType::Cemetery, 0, 0, age_group_15_to_34); + auto default_type = mio::abm::ActivityType::Cemetery; + auto person = mio::abm::Person(this->get_rng(), mio::abm::LocationType::Cemetery, mio::abm::ActivityType::Cemetery, + 0, 0, age_group_15_to_34); auto p_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); auto params = mio::abm::Parameters(num_age_groups); @@ -106,11 +106,11 @@ TEST_F(TestMobilityRules, student_goes_to_school) params.get()[age_group_35_to_59] = true; // Test that child goes to school - EXPECT_EQ(mio::abm::go_to_school(child_rng, p_child, t_morning, dt, params), mio::abm::LocationType::School); + EXPECT_EQ(mio::abm::go_to_school(child_rng, p_child, t_morning, dt, params), mio::abm::ActivityType::School); // Test that adult does not go to school - EXPECT_EQ(mio::abm::go_to_school(adult_rng, p_adult, t_morning, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_school(adult_rng, p_adult, t_morning, dt, params), mio::abm::ActivityType::Home); // Test that child goes back home after school - EXPECT_EQ(mio::abm::go_to_school(child_rng, p_child, t_weekend, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_school(child_rng, p_child, t_weekend, dt, params), mio::abm::ActivityType::Home); } /** @@ -161,16 +161,16 @@ TEST_F(TestMobilityRules, students_go_to_school_in_different_times) // Mock randomness ensures children leave home at various school start times. EXPECT_EQ( mio::abm::go_to_school(rng_child_goes_to_school_at_6, p_child_goes_to_school_at_6, t_morning_6, dt, params), - mio::abm::LocationType::School); + mio::abm::ActivityType::School); EXPECT_EQ( mio::abm::go_to_school(rng_child_goes_to_school_at_6, p_child_goes_to_school_at_6, t_morning_8, dt, params), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); EXPECT_EQ( mio::abm::go_to_school(rng_child_goes_to_school_at_8, p_child_goes_to_school_at_8, t_morning_6, dt, params), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); EXPECT_EQ( mio::abm::go_to_school(rng_child_goes_to_school_at_8, p_child_goes_to_school_at_8, t_morning_8, dt, params), - mio::abm::LocationType::School); + mio::abm::ActivityType::School); } /** @@ -230,17 +230,17 @@ TEST_F(TestMobilityRules, students_go_to_school_in_different_times_with_smaller_ // Check that the first student goes to school at 6:00 AM EXPECT_EQ( mio::abm::go_to_school(rng_child_goes_to_school_at_6, p_child_goes_to_school_at_6, t_morning_6, dt, params), - mio::abm::LocationType::School); + mio::abm::ActivityType::School); EXPECT_EQ( mio::abm::go_to_school(rng_child_goes_to_school_at_6, p_child_goes_to_school_at_6, t_morning_8_30, dt, params), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); // Check that the second student goes to school at 8:30 AM EXPECT_EQ(mio::abm::go_to_school(rng_child_goes_to_school_at_8_30, p_child_goes_to_school_at_8_30, t_morning_6, dt, params), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); EXPECT_EQ(mio::abm::go_to_school(rng_child_goes_to_school_at_8_30, p_child_goes_to_school_at_8_30, t_morning_8_30, dt, params), - mio::abm::LocationType::School); + mio::abm::ActivityType::School); } /** * @brief Test return home from school. @@ -258,7 +258,7 @@ TEST_F(TestMobilityRules, school_return) // Ensure that the child returns home after school is over EXPECT_EQ(mio::abm::go_to_school(rng_child, p_child, t, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); } /** @@ -302,11 +302,11 @@ TEST_F(TestMobilityRules, worker_goes_to_work) params.get()[age_group_35_to_59] = true; // Check that the retiree (age group 60-79) should stay home and not go to work. - EXPECT_EQ(mio::abm::go_to_work(rng_retiree, p_retiree, t_morning, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_work(rng_retiree, p_retiree, t_morning, dt, params), mio::abm::ActivityType::Home); // Check that the adult (age group 15-34) should go to work at 8:00 AM. - EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t_morning, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t_morning, dt, params), mio::abm::ActivityType::Home); // Check that during the night (4:00 AM), the adult should stay home and not go to work. - EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t_night, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t_night, dt, params), mio::abm::ActivityType::Home); } /** @@ -352,11 +352,11 @@ TEST_F(TestMobilityRules, worker_goes_to_work_with_non_dividable_timespan) params.get()[age_group_35_to_59] = true; // Check that the retiree (age group 60-79) should stay home and not go to work even with non-dividable time step. - EXPECT_EQ(mio::abm::go_to_work(rng_retiree, p_retiree, t_morning, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_work(rng_retiree, p_retiree, t_morning, dt, params), mio::abm::ActivityType::Home); // Check that the adult (age group 15-34) should still go to work at 8:00 AM even with the non-dividable time step. - EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t_morning, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t_morning, dt, params), mio::abm::ActivityType::Home); // Check that during the night (4:00 AM), the adult should stay home and not go to work even with the non-dividable time step. - EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t_night, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t_night, dt, params), mio::abm::ActivityType::Home); } /** @@ -410,22 +410,22 @@ TEST_F(TestMobilityRules, workers_go_to_work_in_different_times) // Check that the worker going to work at 6 AM goes to work EXPECT_EQ(mio::abm::go_to_work(rng_adult_goes_to_work_at_6, p_adult_goes_to_work_at_6, t_morning_6, dt, params), - mio::abm::LocationType::Work); + mio::abm::ActivityType::Work); // Check that the worker going to work at 6 AM stays home at 8 AM (since they are already at work) EXPECT_EQ(mio::abm::go_to_work(rng_adult_goes_to_work_at_6, p_adult_goes_to_work_at_6, t_morning_8, dt, params), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); // Check that the worker going to work at 6 AM returns home at night EXPECT_EQ(mio::abm::go_to_work(rng_adult_goes_to_work_at_6, p_adult_goes_to_work_at_6, t_night, dt, params), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); // Check that the worker going to work at 8 AM stays home at 6 AM EXPECT_EQ(mio::abm::go_to_work(rng_adult_goes_to_work_at_8, p_adult_goes_to_work_at_8, t_morning_6, dt, params), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); // Check that the worker going to work at 8 AM goes to work at 8 AM EXPECT_EQ(mio::abm::go_to_work(rng_adult_goes_to_work_at_8, p_adult_goes_to_work_at_8, t_morning_8, dt, params), - mio::abm::LocationType::Work); + mio::abm::ActivityType::Work); // Check that the worker going to work at 8 AM returns home at night EXPECT_EQ(mio::abm::go_to_work(rng_adult_goes_to_work_at_8, p_adult_goes_to_work_at_8, t_night, dt, params), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); } /** @@ -443,7 +443,7 @@ TEST_F(TestMobilityRules, work_return) auto dt = mio::abm::hours(1); // Test that the worker, who is currently at work, goes home after 5 PM EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); } /** @@ -464,14 +464,14 @@ TEST_F(TestMobilityRules, quarantine) p_inf1.get_tested(rng_inf1, t, test_params); // Check detected infected person quarantines at home EXPECT_EQ(mio::abm::go_to_quarantine(rng_inf1, p_inf1, t, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); auto p_inf2 = make_test_person(this->get_rng(), work, mio::abm::ActivityType::Work, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms, t); auto rng_inf2 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_inf2); // Check that undetected infected person does not quaratine EXPECT_EQ(mio::abm::go_to_quarantine(rng_inf2, p_inf2, t, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Work); + mio::abm::ActivityType::Work); auto p_inf3 = make_test_person(this->get_rng(), hospital, mio::abm::ActivityType::Hospital, age_group_15_to_34, mio::abm::InfectionState::InfectedSevere, t); @@ -479,7 +479,7 @@ TEST_F(TestMobilityRules, quarantine) p_inf1.get_tested(rng_inf3, t, test_params); // Check that detected infected person does not leave hospital to quarantine EXPECT_EQ(mio::abm::go_to_quarantine(rng_inf3, p_inf3, t, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Hospital); + mio::abm::ActivityType::Hospital); } /** @@ -496,14 +496,14 @@ TEST_F(TestMobilityRules, hospital) // Ensure person goes to the hospital when severely infected EXPECT_EQ(mio::abm::go_to_hospital(rng_inf, p_inf, t, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Hospital); + mio::abm::ActivityType::Hospital); auto p_car = make_test_person(this->get_rng(), home, mio::abm::ActivityType::Home, age_group_15_to_34, mio::abm::InfectionState::InfectedSymptoms); auto rng_car = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_car); // Ensure person has infection symptoms still stay at home EXPECT_EQ(mio::abm::go_to_hospital(rng_car, p_car, t, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); } /** @@ -530,13 +530,13 @@ TEST_F(TestMobilityRules, go_shopping) // Check that an infected person stays in the hospital and doesn't go shopping EXPECT_EQ(mio::abm::go_to_shop(rng_hosp, p_hosp, t_weekday, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Hospital); + mio::abm::ActivityType::Hospital); // Check that a person at home doesn't go shopping on a Sunday EXPECT_EQ(mio::abm::go_to_shop(rng_home, p_home, t_sunday, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); // Check that a person at home doesn't go shopping on a Sunday EXPECT_EQ(mio::abm::go_to_shop(rng_home, p_home, t_night, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); // Mocking the random distribution to simulate a person going shopping on a weekday ScopedMockDistribution>>> @@ -544,7 +544,7 @@ TEST_F(TestMobilityRules, go_shopping) EXPECT_CALL(mock_exponential_dist.get_mock(), invoke).Times(1).WillOnce(testing::Return(0.01)); // Test that a person goes to a basic shop on a weekday at 9 AM EXPECT_EQ(mio::abm::go_to_shop(rng_home, p_home, t_weekday, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::BasicsShop); + mio::abm::ActivityType::BasicsShop); } /** @@ -566,7 +566,7 @@ TEST_F(TestMobilityRules, shop_return) // After spending sufficient time at the shop, the person should return home EXPECT_EQ(mio::abm::go_to_shop(rng_p, p, t, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); } /** @@ -627,7 +627,7 @@ TEST_F(TestMobilityRules, event_return) // Simulate the person spending 3 hours at the social event p.add_time_at_location(dt); // After spending the time at the social event, the person should return home - EXPECT_EQ(mio::abm::go_to_recreation(rng_p, p, t, dt, params), mio::abm::LocationType::Home); + EXPECT_EQ(mio::abm::go_to_recreation(rng_p, p, t, dt, params), mio::abm::ActivityType::Home); } /** @@ -644,7 +644,7 @@ TEST_F(TestMobilityRules, icu) // Ensure critically infected person goes to the ICU EXPECT_EQ(mio::abm::go_to_icu(rng_hosp, p_hosp, t, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::ICU); + mio::abm::ActivityType::ICU); mio::abm::Location work(mio::abm::LocationType::Work, 1, num_age_groups); auto p_work = make_test_person(this->get_rng(), work, mio::abm::ActivityType::Work, age_group_15_to_34, @@ -652,7 +652,7 @@ TEST_F(TestMobilityRules, icu) auto rng_work = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_work); // Ensure infected with symptions person can still go to work EXPECT_EQ(mio::abm::go_to_icu(rng_work, p_work, t, dt, mio::abm::Parameters(num_age_groups)), - mio::abm::LocationType::Work); + mio::abm::ActivityType::Work); } /** @@ -671,9 +671,9 @@ TEST_F(TestMobilityRules, recover) auto rng_inf = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_inf); // Ensure recovered person returns home and infected severe person stay in hospital EXPECT_EQ(mio::abm::return_home_when_recovered(rng_rec, p_rec, t, dt, {num_age_groups}), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); EXPECT_EQ(mio::abm::return_home_when_recovered(rng_inf, p_inf, t, dt, {num_age_groups}), - mio::abm::LocationType::Hospital); + mio::abm::ActivityType::Hospital); } /** @@ -688,5 +688,5 @@ TEST_F(TestMobilityRules, dead) mio::abm::InfectionState::Dead, t); auto p_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_dead); - EXPECT_EQ(mio::abm::get_buried(p_rng, p_dead, t, dt, {num_age_groups}), mio::abm::LocationType::Cemetery); + EXPECT_EQ(mio::abm::get_buried(p_rng, p_dead, t, dt, {num_age_groups}), mio::abm::ActivityType::Cemetery); } diff --git a/cpp/tests/test_abm_person.cpp b/cpp/tests/test_abm_person.cpp index 9cf8e1eec8..0c2aa65acb 100644 --- a/cpp/tests/test_abm_person.cpp +++ b/cpp/tests/test_abm_person.cpp @@ -106,27 +106,27 @@ TEST_F(TestPerson, setGetAssignedLocation) auto p_rng = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person); // Assign and verify a location for the person. person.set_assigned_location(mio::abm::ActivityType::Work, location.get_id(), location.get_model_id()); - EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng), mio::abm::LocationId(2)); + EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng).first, mio::abm::LocationId(2)); // Change the assigned location and verify. person.set_assigned_location(mio::abm::ActivityType::Work, mio::abm::LocationId(4), 0); - EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng), mio::abm::LocationId(4)); + EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng).first, mio::abm::LocationId(4)); // Fuzzing: assign random valid LocationId values and verify correctness. for (int i = 0; i < 100; ++i) { auto random_id = this->random_integer(0, std::numeric_limits::max()); auto random_type = this->random_integer(0, (int)mio::abm::ActivityType::Count - 1); person.set_assigned_location((mio::abm::ActivityType)random_type, mio::abm::LocationId(random_id), 0); - EXPECT_EQ(person.get_assigned_location((mio::abm::ActivityType)random_type, p_rng), + EXPECT_EQ(person.get_assigned_location((mio::abm::ActivityType)random_type, p_rng).first, mio::abm::LocationId(random_id)); } // Boundary test cases: test with boundary LocationIds. person.set_assigned_location(mio::abm::ActivityType::Work, mio::abm::LocationId(0), 0); - EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng), mio::abm::LocationId(0)); + EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng).first, mio::abm::LocationId(0)); person.set_assigned_location(mio::abm::ActivityType::Work, mio::abm::LocationId(std::numeric_limits::max()), 0); - EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng), + EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng).first, mio::abm::LocationId(std::numeric_limits::max())); } @@ -175,13 +175,13 @@ TEST_F(TestPerson, quarantine) person.get_tested(rng_person, t_morning, test_params); EXPECT_EQ(person.get_infection_state(t_morning), mio::abm::InfectionState::InfectedSymptoms); EXPECT_EQ(mio::abm::go_to_work(rng_person, person, t_morning, dt, infection_parameters), - mio::abm::LocationType::Home); + mio::abm::ActivityType::Home); EXPECT_EQ(person.get_infection_state(t_morning + dt), mio::abm::InfectionState::Recovered); // Test removal from quarantine. person.remove_quarantine(); EXPECT_EQ(mio::abm::go_to_work(rng_person, person, t_morning, dt, infection_parameters), - mio::abm::LocationType::Work); + mio::abm::ActivityType::Work); } /** @@ -300,7 +300,7 @@ TEST_F(TestPerson, setWearMask) { auto t = mio::abm::TimePoint(0); mio::abm::Location location(mio::abm::LocationType::School, 0, num_age_groups); - auto person = make_test_person(this->get_rng(), location); + auto person = make_test_person(this->get_rng(), location, mio::abm::ActivityType::School); // Test setting and verifying different mask types. person.set_mask(mio::abm::MaskType::None, t); diff --git a/cpp/tests/test_abm_serialization.cpp b/cpp/tests/test_abm_serialization.cpp index 7fd48dda52..dffa6e7495 100644 --- a/cpp/tests/test_abm_serialization.cpp +++ b/cpp/tests/test_abm_serialization.cpp @@ -35,6 +35,7 @@ #include "models/abm/model.h" #include #include +#include #ifdef MEMILIO_HAS_JSONCPP @@ -83,6 +84,7 @@ TEST(TestAbmSerialization, Trip) reference_json["destination"] = Json::UInt(i++); reference_json["model_id"] = Json::Int(i++); reference_json["trip_mode"] = Json::UInt(i++); + reference_json["activity"] = Json::UInt(i++); test_json_serialization(reference_json); } @@ -190,18 +192,23 @@ TEST(TestAbmSerialization, Person) return mio::serialize_json(values).value(); }; + auto json_uint_array_array = [](std::vector> values) { + return mio::serialize_json(values).value(); + }; + unsigned i = 1; // counter s.t. members have different values Json::Value reference_json; - reference_json["age_group"] = Json::UInt(i++); - reference_json["assigned_locations"] = json_uint_array({i++, i++, i++, i++, i++, i++, i++, i++, i++, i++, i++}); - reference_json["cells"] = json_uint_array({i++}); - reference_json["compliance"] = json_double_array({(double)i++, (double)i++, (double)i++}); - reference_json["infections"] = Json::Value(Json::arrayValue); - reference_json["last_transport_mode"] = Json::UInt(i++); - reference_json["location"] = Json::UInt(i++); - reference_json["location_type"] = Json::UInt(0); - reference_json["mask"]["mask_type"] = Json::UInt(0); + reference_json["age_group"] = Json::UInt(i++); + reference_json["assigned_locations"] = + json_uint_array_array({{i++, i++, i++, i++, i++, i++, i++, i++, i++, i++, i++}}); + reference_json["cells"] = json_uint_array({i++}); + reference_json["compliance"] = json_double_array({(double)i++, (double)i++, (double)i++}); + reference_json["infections"] = Json::Value(Json::arrayValue); + reference_json["last_transport_mode"] = Json::UInt(i++); + reference_json["location"] = Json::UInt(i++); + reference_json["location_type"] = Json::UInt(0); + reference_json["mask"]["mask_type"] = Json::UInt(0); reference_json["mask"]["time_first_used"]["seconds"] = Json::Int(i++); reference_json["home_isolation_start"]["seconds"] = Json::Int(i++); reference_json["rnd_go_to_school_hour"] = Json::Value((double)i++); diff --git a/cpp/tests/test_abm_testing_strategy.cpp b/cpp/tests/test_abm_testing_strategy.cpp index 5a850cef48..4e27d66cb3 100644 --- a/cpp/tests/test_abm_testing_strategy.cpp +++ b/cpp/tests/test_abm_testing_strategy.cpp @@ -103,8 +103,8 @@ TEST_F(TestTestingScheme, runScheme) mio::abm::Location loc_work(mio::abm::LocationType::Work, 0, num_age_groups); // Since tests are performed before start_date, the InfectionState of all the Person have to take into account the test's required_time auto person1 = - make_test_person(this->get_rng(), loc_home, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms, - start_date - test_params_pcr.required_time); + make_test_person(this->get_rng(), loc_home, mio::abm::ActivityType::Home, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms, start_date - test_params_pcr.required_time); auto rng_person1 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person1); auto person2 = make_test_person(this->get_rng(), loc_home, mio::abm::ActivityType::Home, age_group_15_to_34, mio::abm::InfectionState::Recovered, start_date - test_params_pcr.required_time); @@ -152,8 +152,8 @@ TEST_F(TestTestingScheme, initAndRunTestingStrategy) mio::abm::Location loc_work(mio::abm::LocationType::Work, 0); // Since tests are performed before start_date, the InfectionState of all the Person have to take into account the test's required_time auto person1 = - make_test_person(this->get_rng(), loc_work, age_group_15_to_34, mio::abm::InfectionState::InfectedNoSymptoms, - start_date - test_params_pcr.required_time); + make_test_person(this->get_rng(), loc_work, mio::abm::ActivityType::Work, age_group_15_to_34, + mio::abm::InfectionState::InfectedNoSymptoms, start_date - test_params_pcr.required_time); auto rng_person1 = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), person1); auto person2 = make_test_person(this->get_rng(), loc_work, mio::abm::ActivityType::Work, age_group_15_to_34, mio::abm::InfectionState::Recovered, start_date - test_params_pcr.required_time); From 471618011d4a756da7cfbec8f9fa7b20b5b0d2c6 Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Thu, 23 Apr 2026 11:21:43 +0200 Subject: [PATCH 03/12] fix tests --- cpp/models/abm/activity_type.h | 1 + cpp/models/abm/person.h | 1 + cpp/tests/test_abm_person.cpp | 31 ++++++++++++++++++++-------- cpp/tests/test_abm_serialization.cpp | 1 + cpp/tests/test_abm_simulation.cpp | 2 +- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/cpp/models/abm/activity_type.h b/cpp/models/abm/activity_type.h index 891e50e51c..ee6b174437 100644 --- a/cpp/models/abm/activity_type.h +++ b/cpp/models/abm/activity_type.h @@ -40,6 +40,7 @@ enum class ActivityType : std::uint32_t Hospital, ICU, Cemetery, // Location for all the dead persons. It is created once for the Model. + PublicTransport, Count, //last! Invalid diff --git a/cpp/models/abm/person.h b/cpp/models/abm/person.h index c799974528..e1a06b3ebe 100755 --- a/cpp/models/abm/person.h +++ b/cpp/models/abm/person.h @@ -419,6 +419,7 @@ class Person return Members("Person") .add("location", m_location) .add("location_type", m_location_type) + .add("activity_type", m_activity_type) .add("assigned_locations", m_assigned_locations) .add("vaccinations", m_vaccinations) .add("infections", m_infections) diff --git a/cpp/tests/test_abm_person.cpp b/cpp/tests/test_abm_person.cpp index 0c2aa65acb..a4b66a78c2 100644 --- a/cpp/tests/test_abm_person.cpp +++ b/cpp/tests/test_abm_person.cpp @@ -28,6 +28,7 @@ #include "abm_helpers.h" #include "random_number_test.h" +#include "gmock/gmock.h" #include using TestPerson = RandomNumberTest; @@ -100,6 +101,16 @@ TEST_F(TestPerson, change_location) */ TEST_F(TestPerson, setGetAssignedLocation) { + // Mock assigned location draws + ScopedMockDistribution>>> + mock_uniform_dist; + EXPECT_CALL(mock_uniform_dist.get_mock(), invoke) + .Times(testing::Exactly(4)) // 1 draw per get_assigned_location_draw + .WillOnce(testing::Return(0)) // LocationId(2) + .WillOnce(testing::Return(1)) // LocationId(4) + .WillOnce(testing::Return(2)) // LocationId(0) + .WillOnce(testing::Return(3)); // LocationId(max) + mio::abm::Location location(mio::abm::LocationType::Work, 2, num_age_groups); auto person = mio::abm::Person(this->get_rng(), location.get_type(), mio::abm::ActivityType::Work, location.get_id(), location.get_model_id(), age_group_35_to_59); @@ -111,15 +122,6 @@ TEST_F(TestPerson, setGetAssignedLocation) person.set_assigned_location(mio::abm::ActivityType::Work, mio::abm::LocationId(4), 0); EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng).first, mio::abm::LocationId(4)); - // Fuzzing: assign random valid LocationId values and verify correctness. - for (int i = 0; i < 100; ++i) { - auto random_id = this->random_integer(0, std::numeric_limits::max()); - auto random_type = this->random_integer(0, (int)mio::abm::ActivityType::Count - 1); - person.set_assigned_location((mio::abm::ActivityType)random_type, mio::abm::LocationId(random_id), 0); - EXPECT_EQ(person.get_assigned_location((mio::abm::ActivityType)random_type, p_rng).first, - mio::abm::LocationId(random_id)); - } - // Boundary test cases: test with boundary LocationIds. person.set_assigned_location(mio::abm::ActivityType::Work, mio::abm::LocationId(0), 0); EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng).first, mio::abm::LocationId(0)); @@ -128,6 +130,17 @@ TEST_F(TestPerson, setGetAssignedLocation) 0); EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng).first, mio::abm::LocationId(std::numeric_limits::max())); + + // Fuzzing: assign random valid LocationId values and verify correctness. + for (int i = 0; i < 100; ++i) { + + EXPECT_CALL(mock_uniform_dist.get_mock(), invoke).Times(testing::Exactly(1)).WillOnce(testing::Return(i + 4)); + + auto random_id = this->random_integer(0, std::numeric_limits::max()); + person.set_assigned_location(mio::abm::ActivityType::Work, mio::abm::LocationId(random_id), 0); + EXPECT_EQ(person.get_assigned_location(mio::abm::ActivityType::Work, p_rng).first, + mio::abm::LocationId(random_id)); + } } /** diff --git a/cpp/tests/test_abm_serialization.cpp b/cpp/tests/test_abm_serialization.cpp index dffa6e7495..41275577a7 100644 --- a/cpp/tests/test_abm_serialization.cpp +++ b/cpp/tests/test_abm_serialization.cpp @@ -208,6 +208,7 @@ TEST(TestAbmSerialization, Person) reference_json["last_transport_mode"] = Json::UInt(i++); reference_json["location"] = Json::UInt(i++); reference_json["location_type"] = Json::UInt(0); + reference_json["activity_type"] = Json::UInt(0); reference_json["mask"]["mask_type"] = Json::UInt(0); reference_json["mask"]["time_first_used"]["seconds"] = Json::Int(i++); reference_json["home_isolation_start"]["seconds"] = Json::Int(i++); diff --git a/cpp/tests/test_abm_simulation.cpp b/cpp/tests/test_abm_simulation.cpp index 5bef2c7072..58afd6dbfd 100644 --- a/cpp/tests/test_abm_simulation.cpp +++ b/cpp/tests/test_abm_simulation.cpp @@ -103,7 +103,7 @@ TEST(TestSimulation, advanceWithCommonHistory) model.assign_location(person1, basics_id, mio::abm::ActivityType::BasicsShop); model.assign_location(person2, basics_id, mio::abm::ActivityType::BasicsShop); model.assign_location(person3, basics_id, mio::abm::ActivityType::BasicsShop); - model.assign_location(person2, public_id, mio::abm::ActivityType::Invalid); + model.assign_location(person2, public_id, mio::abm::ActivityType::PublicTransport); mio::abm::TripList& trip_list = model.get_trip_list(); From 65e10d93278a25e78853b55015e5e9b32ecb91ce Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Thu, 23 Apr 2026 11:24:46 +0200 Subject: [PATCH 04/12] Remove old ActivityType struct --- cpp/models/abm/mobility_data.h | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/cpp/models/abm/mobility_data.h b/cpp/models/abm/mobility_data.h index 0d19d46a52..2fafb67106 100644 --- a/cpp/models/abm/mobility_data.h +++ b/cpp/models/abm/mobility_data.h @@ -43,21 +43,6 @@ enum class TransportMode : uint32_t Count //last!! }; -// /** -// * @brief Type of the activity. -// */ -// enum class ActivityType : uint32_t -// { -// Workplace, -// Education, -// Shopping, -// Leisure, -// PrivateMatters, -// OtherActivity, -// Home, -// UnknownActivity -// }; - } // namespace abm } // namespace mio From f69ee3cfc16c1551f220e057e306f66392a74cc3 Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:33:38 +0200 Subject: [PATCH 05/12] fix benchmark --- cpp/benchmarks/abm.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/cpp/benchmarks/abm.cpp b/cpp/benchmarks/abm.cpp index 70e4f9e494..109806c08c 100644 --- a/cpp/benchmarks/abm.cpp +++ b/cpp/benchmarks/abm.cpp @@ -17,9 +17,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "abm/activity_type.h" #include "abm/simulation.h" #include "benchmark/benchmark.h" +#include mio::abm::Simulation<> make_simulation(size_t num_persons, std::initializer_list seeds) { @@ -44,25 +46,28 @@ mio::abm::Simulation<> make_simulation(size_t num_persons, std::initializer_list auto age = mio::AgeGroup(mio::UniformIntDistribution::get_instance()( model.get_rng(), size_t(0), model.parameters.get_num_groups() - 1)); - auto person = model.add_person(home, age); - model.assign_location(uint32_t(i), home); + auto person = model.add_person(home, age, mio::abm::ActivityType::Home); + model.assign_location(uint32_t(i), home, mio::abm::ActivityType::Home); home_size++; } //create other locations - for (auto loc_type : - {mio::abm::LocationType::School, mio::abm::LocationType::Work, mio::abm::LocationType::Recreation, - mio::abm::LocationType::BasicsShop, mio::abm::LocationType::Hospital, mio::abm::LocationType::ICU}) { + for (auto types : {std::make_pair(mio::abm::LocationType::School, mio::abm::ActivityType::School), + std::make_pair(mio::abm::LocationType::Work, mio::abm::ActivityType::Work), + std::make_pair(mio::abm::LocationType::Recreation, mio::abm::ActivityType::Recreation), + std::make_pair(mio::abm::LocationType::BasicsShop, mio::abm::ActivityType::BasicsShop), + std::make_pair(mio::abm::LocationType::Hospital, mio::abm::ActivityType::Hospital), + std::make_pair(mio::abm::LocationType::ICU, mio::abm::ActivityType::ICU)}) { const auto num_locs = std::max(size_t(1), num_persons / 2'000); std::vector locs(num_locs); std::generate(locs.begin(), locs.end(), [&] { - return model.add_location(loc_type); + return model.add_location(types.first); }); for (size_t p = 0; p < num_persons; ++p) { auto loc_idx = mio::UniformIntDistribution::get_instance()(model.get_rng(), size_t(0), num_locs - 1); - model.assign_location(uint32_t(p), locs[loc_idx]); + model.assign_location(uint32_t(p), locs[loc_idx], types.second); } } From 0b023228d039000cb17fd9cc9aab432ecac66f3a Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Fri, 5 Jun 2026 11:33:00 +0200 Subject: [PATCH 06/12] test --- cpp/examples/abm_minimal.cpp | 21 ++++++++++++++- cpp/tests/test_abm_mobility_rules.cpp | 37 ++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/cpp/examples/abm_minimal.cpp b/cpp/examples/abm_minimal.cpp index 13f4c2bd8f..14fec2c561 100644 --- a/cpp/examples/abm_minimal.cpp +++ b/cpp/examples/abm_minimal.cpp @@ -22,6 +22,7 @@ #include "abm/model.h" #include "abm/common_abm_loggers.h" +#include #include int main() @@ -127,6 +128,10 @@ int main() } } + size_t num_teachers = 0; + size_t num_hosp_doctors = 0; + size_t num_icu_doctors = 0; + // Assign locations to the people for (auto& person : model.get_persons()) { const auto id = person.get_id(); @@ -141,7 +146,21 @@ int main() model.assign_location(id, school, mio::abm::ActivityType::School); } if (person.get_age() == age_group_15_to_34 || person.get_age() == age_group_35_to_59) { - model.assign_location(id, work, mio::abm::ActivityType::Work); + if (num_teachers < 3) { + model.assign_location(id, school, mio::abm::ActivityType::Work); + num_teachers++; + } + else if (num_hosp_doctors < 1) { + model.assign_location(id, hospital, mio::abm::ActivityType::Work); + num_hosp_doctors++; + } + else if (num_icu_doctors < 1) { + model.assign_location(id, icu, mio::abm::ActivityType::Work); + num_icu_doctors++; + } + else { + model.assign_location(id, work, mio::abm::ActivityType::Work); + } } } diff --git a/cpp/tests/test_abm_mobility_rules.cpp b/cpp/tests/test_abm_mobility_rules.cpp index 08aed7d2b9..1f30f40681 100644 --- a/cpp/tests/test_abm_mobility_rules.cpp +++ b/cpp/tests/test_abm_mobility_rules.cpp @@ -18,6 +18,7 @@ * limitations under the License. */ #include "abm/activity_type.h" +#include "abm/location.h" #include "abm/location_type.h" #include "abm/mobility_rules.h" #include "abm/person.h" @@ -267,6 +268,9 @@ TEST_F(TestMobilityRules, school_return) TEST_F(TestMobilityRules, worker_goes_to_work) { mio::abm::Location home(mio::abm::LocationType::Home, 0, num_age_groups); + mio::abm::Location work(mio::abm::LocationType::Work, 1, num_age_groups); + mio::abm::Location school(mio::abm::LocationType::School, 2, num_age_groups); + mio::abm::Location hospital(mio::abm::LocationType::Hospital, 3, num_age_groups); // Mock the uniform distribution to control the randomness for workers' decisions. ScopedMockDistribution>>> mock_uniform_dist; EXPECT_CALL(mock_uniform_dist.get_mock(), invoke) @@ -279,6 +283,14 @@ TEST_F(TestMobilityRules, worker_goes_to_work) .WillOnce(testing::Return(0.)) .WillOnce(testing::Return(0.)) .WillOnce(testing::Return(0.)) + .WillOnce(testing::Return(0.)) + .WillOnce(testing::Return(0.)) + .WillOnce(testing::Return(0.)) + .WillOnce(testing::Return(0.)) + .WillOnce(testing::Return(0.)) + .WillOnce(testing::Return(0.)) + .WillOnce(testing::Return(0.)) + .WillOnce(testing::Return(0.)) .WillRepeatedly(testing::Return(1.0)); auto p_retiree = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), @@ -286,9 +298,18 @@ TEST_F(TestMobilityRules, worker_goes_to_work) auto rng_retiree = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_retiree); auto p_adult = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), home.get_model_id(), age_group_15_to_34); - auto rng_adult = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_adult); - - auto t_morning = mio::abm::TimePoint(0) + mio::abm::hours(8); + p_adult.set_assigned_location(mio::abm::ActivityType::Work, work.get_id(), home.get_model_id()); + auto rng_adult = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_adult); + auto p_teacher = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_35_to_59); + p_teacher.set_assigned_location(mio::abm::ActivityType::Work, school.get_id(), school.get_model_id()); + auto rng_teacher = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_teacher); + auto p_doctor = mio::abm::Person(this->get_rng(), home.get_type(), mio::abm::ActivityType::Home, home.get_id(), + home.get_model_id(), age_group_35_to_59); + p_doctor.set_assigned_location(mio::abm::ActivityType::Work, hospital.get_id(), hospital.get_model_id()); + auto rng_doctor = mio::abm::PersonalRandomNumberGenerator(this->get_rng(), p_doctor); + + auto t_morning = mio::abm::TimePoint(0) + mio::abm::hours(6); auto t_night = mio::abm::TimePoint(0) + mio::abm::days(1) + mio::abm::hours(4); auto dt = mio::abm::hours(1); @@ -303,10 +324,14 @@ TEST_F(TestMobilityRules, worker_goes_to_work) // Check that the retiree (age group 60-79) should stay home and not go to work. EXPECT_EQ(mio::abm::go_to_work(rng_retiree, p_retiree, t_morning, dt, params), mio::abm::ActivityType::Home); - // Check that the adult (age group 15-34) should go to work at 8:00 AM. - EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t_morning, dt, params), mio::abm::ActivityType::Home); - // Check that during the night (4:00 AM), the adult should stay home and not go to work. + // Check that the adults (age group 15-34) should go to work at 6:00 AM. + EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t_morning, dt, params), mio::abm::ActivityType::Work); + EXPECT_EQ(mio::abm::go_to_work(rng_teacher, p_teacher, t_morning, dt, params), mio::abm::ActivityType::Work); + EXPECT_EQ(mio::abm::go_to_work(rng_doctor, p_doctor, t_morning, dt, params), mio::abm::ActivityType::Work); + // Check that during the night (4:00 AM), the adults should stay home and not go to work. EXPECT_EQ(mio::abm::go_to_work(rng_adult, p_adult, t_night, dt, params), mio::abm::ActivityType::Home); + EXPECT_EQ(mio::abm::go_to_work(rng_teacher, p_teacher, t_night, dt, params), mio::abm::ActivityType::Home); + EXPECT_EQ(mio::abm::go_to_work(rng_doctor, p_doctor, t_night, dt, params), mio::abm::ActivityType::Home); } /** From 944b1a7d0647e76c9ff4dd7440069ac527f5fcd3 Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Fri, 5 Jun 2026 11:57:21 +0200 Subject: [PATCH 07/12] bindings + review comments --- cpp/models/abm/person.cpp | 19 +++++++------ cpp/models/abm/person.h | 13 +++++---- .../simulation/bindings/models/abm.cpp | 28 +++++++++++++++---- pycode/memilio-simulation/tests/test_abm.py | 22 +++++++-------- 4 files changed, 50 insertions(+), 32 deletions(-) diff --git a/cpp/models/abm/person.cpp b/cpp/models/abm/person.cpp index 765e0f3db0..9c2ba077cf 100755 --- a/cpp/models/abm/person.cpp +++ b/cpp/models/abm/person.cpp @@ -98,11 +98,11 @@ LocationId Person::get_location() const return m_location; } -void Person::set_location(ActivityType type, LocationType location_type, LocationId id, int model_id) +void Person::set_location(ActivityType activity_type, LocationType location_type, LocationId id, int model_id) { m_location = id; m_location_type = location_type; - m_activity_type = type; + m_activity_type = activity_type; m_location_model_id = model_id; m_time_at_location = TimeSpan(0); } @@ -117,18 +117,19 @@ Infection& Person::get_infection() return m_infections.back(); } -void Person::set_assigned_location(ActivityType type, LocationId id, int model_id = 0) +void Person::set_assigned_location(ActivityType activity_type, LocationId id, int model_id = 0) { - m_assigned_locations[static_cast(type)].push_back(id); - m_assigned_location_model_ids[static_cast(type)].push_back(model_id); + m_assigned_locations[static_cast(activity_type)].push_back(id); + m_assigned_location_model_ids[static_cast(activity_type)].push_back(model_id); } -std::pair Person::get_assigned_location(ActivityType type, PersonalRandomNumberGenerator& rng) const +std::pair Person::get_assigned_location(ActivityType activity_type, + PersonalRandomNumberGenerator& rng) const { size_t index = UniformIntDistribution::get_instance()( - rng, size_t(0), m_assigned_locations[static_cast(type)].size() - 1); - return {m_assigned_locations[static_cast(type)][index], - m_assigned_location_model_ids[static_cast(type)][index]}; + rng, size_t(0), m_assigned_locations[static_cast(activity_type)].size() - 1); + return {m_assigned_locations[static_cast(activity_type)][index], + m_assigned_location_model_ids[static_cast(activity_type)][index]}; } bool Person::goes_to_work(TimePoint t, const Parameters& params) const diff --git a/cpp/models/abm/person.h b/cpp/models/abm/person.h index e1a06b3ebe..510b8af7b9 100755 --- a/cpp/models/abm/person.h +++ b/cpp/models/abm/person.h @@ -158,12 +158,12 @@ class Person /** * @brief Change the location of the person. - * @param[in] type The ActivityType the Person does at the new Location. + * @param[in] activity_type The ActivityType the Person does at the new Location. * @param[in] location_type The LocationType of the new Location. * @param[in] id The LocationId of the new Location. * @param[in] model_id The model id of the new Location. */ - void set_location(ActivityType type, LocationType location_type, LocationId id, int model_id); + void set_location(ActivityType activity_type, LocationType location_type, LocationId id, int model_id); /** * @brief Get the time the Person has been at its current Location. @@ -190,19 +190,20 @@ class Person * Model::assign_location with a valid LocationId, obtained e.g. through Model::add_location. * * The assigned Location is saved by the index of its LocationId. - * @param[in] type The ActivityType the Person does at the Location. + * @param[in] activity_type The ActivityType the Person does at the Location. * @param[in] id The LocationId of the Location. * @param[in] model_id The model id of the Location. */ - void set_assigned_location(ActivityType type, LocationId id, int model_id); + void set_assigned_location(ActivityType activity_type, LocationId id, int model_id); /** * @brief Returns the index of an assigned Location of the Person. The index is uniformly sampled from the LocationIds of the assigned ActivityType. - * @param[in] type #ActivityType of the assigned Location. + * @param[in] activity_type #ActivityType of the assigned Location. * @param[in] rng RandomNumberGenerator for sampling the index of the assigned LocationId. * @return The index in the LocationId and the model id of the assigned Location. */ - std::pair get_assigned_location(ActivityType type, PersonalRandomNumberGenerator& rng) const; + std::pair get_assigned_location(ActivityType activity_type, + PersonalRandomNumberGenerator& rng) const; /** * @brief Get the assigned Location%s of the Person. diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp index 289395bf4c..ed6ab6d498 100644 --- a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp +++ b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp @@ -19,6 +19,7 @@ */ //Includes from pymio +#include "abm/activity_type.h" #include "abm/person_id.h" #include "pybind_util.h" #include "utils/custom_index_array.h" @@ -60,7 +61,19 @@ PYBIND11_MODULE(_simulation_abm, m) .value("Home", mio::abm::LocationType::Home) .value("School", mio::abm::LocationType::School) .value("Work", mio::abm::LocationType::Work) - .value("SocialEvent", mio::abm::LocationType::SocialEvent) + .value("SocialEvent", mio::abm::LocationType::Recreation) + .value("BasicsShop", mio::abm::LocationType::BasicsShop) + .value("Hospital", mio::abm::LocationType::Hospital) + .value("ICU", mio::abm::LocationType::ICU) + .value("Car", mio::abm::LocationType::Car) + .value("PublicTransport", mio::abm::LocationType::PublicTransport) + .value("TransportWithoutContact", mio::abm::LocationType::TransportWithoutContact); + + pymio::iterable_enum(m, "ActivityType") + .value("Home", mio::abm::LocationType::Home) + .value("School", mio::abm::LocationType::School) + .value("Work", mio::abm::LocationType::Work) + .value("SocialEvent", mio::abm::LocationType::Recreation) .value("BasicsShop", mio::abm::LocationType::BasicsShop) .value("Hospital", mio::abm::LocationType::Hospital) .value("ICU", mio::abm::LocationType::ICU) @@ -147,7 +160,7 @@ PYBIND11_MODULE(_simulation_abm, m) .def("index", &mio::abm::PersonId::get); pymio::bind_class(m, "Person") - .def("set_assigned_location", py::overload_cast( + .def("set_assigned_location", py::overload_cast( &mio::abm::Person::set_assigned_location)) .def_property_readonly("location", py::overload_cast<>(&mio::abm::Person::get_location, py::const_)) .def_property_readonly("age", &mio::abm::Person::get_age) @@ -201,11 +214,14 @@ PYBIND11_MODULE(_simulation_abm, m) pymio::bind_class(m, "Model") .def(py::init()) .def("add_location", &mio::abm::Model::add_location, py::arg("location_type"), py::arg("num_cells") = 1) - .def("add_person", py::overload_cast(&mio::abm::Model::add_person), - py::arg("location_id"), py::arg("age_group")) + .def("add_person", + py::overload_cast( + &mio::abm::Model::add_person), + py::arg("location_id"), py::arg("age_group"), py::arg("activity_type")) .def("assign_location", - py::overload_cast(&mio::abm::Model::assign_location), - py::arg("person_id"), py::arg("location_id")) + py::overload_cast( + &mio::abm::Model::assign_location), + py::arg("person_id"), py::arg("location_id"), py::arg("activity_type")) .def_property_readonly("locations", py::overload_cast<>(&mio::abm::Model::get_locations, py::const_), py::keep_alive<1, 0>{}) //keep this model alive while contents are referenced in ranges .def_property_readonly("persons", py::overload_cast<>(&mio::abm::Model::get_persons, py::const_), diff --git a/pycode/memilio-simulation/tests/test_abm.py b/pycode/memilio-simulation/tests/test_abm.py index eca79085e3..b86ff894ad 100644 --- a/pycode/memilio-simulation/tests/test_abm.py +++ b/pycode/memilio-simulation/tests/test_abm.py @@ -47,13 +47,9 @@ def test_locations(self): model = sim.model home_id = model.add_location(abm.LocationType.Home) - social_event_id = model.add_location(abm.LocationType.SocialEvent) self.assertEqual(len(model.locations), 3) home = model.locations[home_id.index()] - self.assertEqual(home.type, abm.LocationType.Home) - - testing_ages = [mio.AgeGroup(0)] home.infection_parameters.MaximumContacts = 10 self.assertEqual(home.infection_parameters.MaximumContacts, 10) @@ -65,10 +61,12 @@ def test_persons(self): model = sim.model home_id = model.add_location(abm.LocationType.Home) - social_event_id = model.add_location(abm.LocationType.SocialEvent) + social_event_id = model.add_location(abm.LocationType.Recreation) - p1_id = model.add_person(home_id, mio.AgeGroup(2)) - p2_id = model.add_person(social_event_id, mio.AgeGroup(5)) + p1_id = model.add_person( + home_id, mio.AgeGroup(2), abm.ActivityType.Home) + p2_id = model.add_person(social_event_id, mio.AgeGroup( + 5), abm.ActivityType.Recreation) p1 = model.persons[p1_id.index()] p2 = model.persons[p2_id.index()] @@ -88,10 +86,12 @@ def test_simulation(self): # add some locations and persons home_id = model.add_location(abm.LocationType.Home) - social_event_id = model.add_location(abm.LocationType.SocialEvent) + social_event_id = model.add_location(abm.LocationType.Recreation) work_id = model.add_location(abm.LocationType.Work) - p1_id = model.add_person(home_id, mio.AgeGroup(0)) - p2_id = model.add_person(home_id, mio.AgeGroup(2)) + p1_id = model.add_person( + home_id, mio.AgeGroup(0), abm.ActivityType.Home) + p2_id = model.add_person( + home_id, mio.AgeGroup(2), abm.ActivityType.Home) for loc_id in [home_id, social_event_id, work_id]: model.assign_location(p1_id, loc_id) @@ -100,7 +100,7 @@ def test_simulation(self): # trips trip_list = abm.TripList() trip_list.add_trips( - [abm.Trip(abm.PersonId(0), abm.TimePoint(0) + abm.hours(8), social_event_id), abm.Trip(abm.PersonId(1), abm.TimePoint(0) + abm.hours(8), work_id)]) + [abm.Trip(abm.PersonId(0), abm.TimePoint(0) + abm.hours(8), social_event_id, abm.ActivityType.Recreation), abm.Trip(abm.PersonId(1), abm.TimePoint(0) + abm.hours(8), work_id, abm.ActivityType.Work)]) model.trip_list = trip_list model.use_mobility_rules = False From 93e3e41216544dbb8ac83c5da14af76d1e9fa2f0 Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Fri, 5 Jun 2026 12:36:33 +0200 Subject: [PATCH 08/12] bindings --- .../simulation/bindings/models/abm.cpp | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp index ed6ab6d498..7d71722675 100644 --- a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp +++ b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp @@ -70,16 +70,16 @@ PYBIND11_MODULE(_simulation_abm, m) .value("TransportWithoutContact", mio::abm::LocationType::TransportWithoutContact); pymio::iterable_enum(m, "ActivityType") - .value("Home", mio::abm::LocationType::Home) - .value("School", mio::abm::LocationType::School) - .value("Work", mio::abm::LocationType::Work) - .value("SocialEvent", mio::abm::LocationType::Recreation) - .value("BasicsShop", mio::abm::LocationType::BasicsShop) - .value("Hospital", mio::abm::LocationType::Hospital) - .value("ICU", mio::abm::LocationType::ICU) - .value("Car", mio::abm::LocationType::Car) - .value("PublicTransport", mio::abm::LocationType::PublicTransport) - .value("TransportWithoutContact", mio::abm::LocationType::TransportWithoutContact); + .value("Home", mio::abm::ActivityType::Home) + .value("School", mio::abm::ActivityType::School) + .value("Work", mio::abm::ActivityType::Work) + .value("SocialEvent", mio::abm::ActivityType::Recreation) + .value("BasicsShop", mio::abm::ActivityType::BasicsShop) + .value("Hospital", mio::abm::ActivityType::Hospital) + .value("ICU", mio::abm::ActivityType::ICU) + .value("Car", mio::abm::ActivityType::Car) + .value("PublicTransport", mio::abm::ActivityType::PublicTransport) + .value("TransportWithoutContact", mio::abm::ActivityType::TransportWithoutContact); pymio::iterable_enum(m, "TestType") .value("Generic", mio::abm::TestType::Generic) @@ -199,11 +199,12 @@ PYBIND11_MODULE(_simulation_abm, m) pymio::bind_Range().get_persons())>(m, "_ModelPersonsRange"); pymio::bind_class(m, "Trip") - .def(py::init(), py::arg("person_id"), - py::arg("time"), py::arg("destination")) + .def(py::init(), + py::arg("person_id"), py::arg("time"), py::arg("destination"), py::arg("activity")) .def_readwrite("person_id", &mio::abm::Trip::person_id) .def_readwrite("trip_time", &mio::abm::Trip::trip_time) - .def_readwrite("destination", &mio::abm::Trip::destination); + .def_readwrite("destination", &mio::abm::Trip::destination) + .def_readwrite("activity", &mio::abm::Trip::activity); pymio::bind_class(m, "TripList") .def(py::init<>()) From f599344795ac57d7149103f8df29d384772ed83b Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Fri, 5 Jun 2026 12:43:37 +0200 Subject: [PATCH 09/12] bindings --- .../memilio/simulation/bindings/models/abm.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp index 7d71722675..4e80616161 100644 --- a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp +++ b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp @@ -77,11 +77,9 @@ PYBIND11_MODULE(_simulation_abm, m) .value("BasicsShop", mio::abm::ActivityType::BasicsShop) .value("Hospital", mio::abm::ActivityType::Hospital) .value("ICU", mio::abm::ActivityType::ICU) - .value("Car", mio::abm::ActivityType::Car) .value("PublicTransport", mio::abm::ActivityType::PublicTransport) - .value("TransportWithoutContact", mio::abm::ActivityType::TransportWithoutContact); - pymio::iterable_enum(m, "TestType") + pymio::iterable_enum(m, "TestType") .value("Generic", mio::abm::TestType::Generic) .value("Antigen", mio::abm::TestType::Antigen) .value("PCR", mio::abm::TestType::PCR); From 40936f4136ff0a4c38df7e9adec3f3d3f25a7cf3 Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Fri, 5 Jun 2026 12:54:48 +0200 Subject: [PATCH 10/12] bindings and documentation --- docs/source/cpp/mobility_based_abm.rst | 12 ++++++------ .../memilio/simulation/bindings/models/abm.cpp | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/source/cpp/mobility_based_abm.rst b/docs/source/cpp/mobility_based_abm.rst index a854494fcb..783adbf4d0 100644 --- a/docs/source/cpp/mobility_based_abm.rst +++ b/docs/source/cpp/mobility_based_abm.rst @@ -123,13 +123,13 @@ level of the susceptible person. Mobility phase ~~~~~~~~~~~~~~ -During the mobility phase, each person may change their location. +During the mobility phase, each person may change their location. A person can move between its assigned locations according to different activity types that can but not have to match the location type. For instance, a location of ``LocationType::School`` can be assigned to students with ``ActivityType::School`` but also to teachers using ``ActivityType::Work``. -The available location types defined in `location_type.h `_ are: +The available location and activity types defined in `location_type.h `_ and `activity_type.h `_ , respectively, are: * **Home**: Home location of a person - * **School**: School location for children - * **Work**: Workplace for adults + * **School**: School location + * **Work**: Workplace * **SocialEvent**: Locations for social gatherings (e.g., parties, events) * **BasicsShop**: Basic shop for essential goods (e.g., grocery store) * **Hospital**: Hospital for severely infected persons @@ -164,7 +164,7 @@ The optional mobility rules consist of: * Going to a social event in the evening or on weekends * Going to a shop randomly during the day (except Sunday) -Another way of mobility 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 the destination. +Another way of mobility is using trips. A trip consists of the ID of the person that performs this trip, a time point when this trip is performed, the destination and the activity type at the destination. At the beginning of the simulation, a list with all trips is initialized and followed during the simulation. The agents do the same trips every day. As before, agents that are in quarantine or in the hospital cannot change their location. Trips can be used even for locations that are not the assigned locations for the respective person. @@ -222,7 +222,7 @@ People are added with an age. Then we have to assign them, so the model knows th .. code-block:: cpp - auto person = model.add_person(home, age_group_0_to_4); + auto person = model.add_person(home, age_group_0_to_4, mio::abm::ActivityType::Home); person.set_assigned_location(home); Note that adding the person to the model in one location does not mean that this location is in the list of assigned locations the person can visit afterwards. diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp index 4e80616161..c2882d7a09 100644 --- a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp +++ b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp @@ -77,9 +77,9 @@ PYBIND11_MODULE(_simulation_abm, m) .value("BasicsShop", mio::abm::ActivityType::BasicsShop) .value("Hospital", mio::abm::ActivityType::Hospital) .value("ICU", mio::abm::ActivityType::ICU) - .value("PublicTransport", mio::abm::ActivityType::PublicTransport) + .value("PublicTransport", mio::abm::ActivityType::PublicTransport); - pymio::iterable_enum(m, "TestType") + pymio::iterable_enum(m, "TestType") .value("Generic", mio::abm::TestType::Generic) .value("Antigen", mio::abm::TestType::Antigen) .value("PCR", mio::abm::TestType::PCR); From 7864b96f5fd977cfbbcb0b2c16affa2103cfcdbe Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Fri, 5 Jun 2026 15:59:57 +0200 Subject: [PATCH 11/12] bindings --- .../memilio/simulation/bindings/models/abm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp index c2882d7a09..9e11288217 100644 --- a/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp +++ b/pycode/memilio-simulation/memilio/simulation/bindings/models/abm.cpp @@ -61,7 +61,7 @@ PYBIND11_MODULE(_simulation_abm, m) .value("Home", mio::abm::LocationType::Home) .value("School", mio::abm::LocationType::School) .value("Work", mio::abm::LocationType::Work) - .value("SocialEvent", mio::abm::LocationType::Recreation) + .value("Recreation", mio::abm::LocationType::Recreation) .value("BasicsShop", mio::abm::LocationType::BasicsShop) .value("Hospital", mio::abm::LocationType::Hospital) .value("ICU", mio::abm::LocationType::ICU) @@ -73,7 +73,7 @@ PYBIND11_MODULE(_simulation_abm, m) .value("Home", mio::abm::ActivityType::Home) .value("School", mio::abm::ActivityType::School) .value("Work", mio::abm::ActivityType::Work) - .value("SocialEvent", mio::abm::ActivityType::Recreation) + .value("Recreation", mio::abm::ActivityType::Recreation) .value("BasicsShop", mio::abm::ActivityType::BasicsShop) .value("Hospital", mio::abm::ActivityType::Hospital) .value("ICU", mio::abm::ActivityType::ICU) From f209fc12524bfa61473d9c8428be809644ea03ac Mon Sep 17 00:00:00 2001 From: jubicker <113909589+jubicker@users.noreply.github.com> Date: Fri, 5 Jun 2026 16:18:50 +0200 Subject: [PATCH 12/12] bindings --- pycode/memilio-simulation/tests/test_abm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pycode/memilio-simulation/tests/test_abm.py b/pycode/memilio-simulation/tests/test_abm.py index b86ff894ad..40f8b2c39d 100644 --- a/pycode/memilio-simulation/tests/test_abm.py +++ b/pycode/memilio-simulation/tests/test_abm.py @@ -93,9 +93,9 @@ def test_simulation(self): p2_id = model.add_person( home_id, mio.AgeGroup(2), abm.ActivityType.Home) - for loc_id in [home_id, social_event_id, work_id]: - model.assign_location(p1_id, loc_id) - model.assign_location(p2_id, loc_id) + for loc in [(home_id, abm.ActivityType.Home), (social_event_id, abm.ActivityType.Recreation), (work_id, abm.ActivityType.Work)]: + model.assign_location(p1_id, loc[0], loc[1]) + model.assign_location(p2_id, loc[0], loc[1]) # trips trip_list = abm.TripList()