diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index caae9380ce..62b748cd32 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -100,9 +100,9 @@ add_executable(abm_minimal_example abm_minimal.cpp) target_link_libraries(abm_minimal_example PRIVATE memilio abm) target_compile_options(abm_minimal_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) -add_executable(abm_history_example abm_history_object.cpp) -target_link_libraries(abm_history_example PRIVATE memilio abm) -target_compile_options(abm_history_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) +add_executable(abm_example abm.cpp) +target_link_libraries(abm_example PRIVATE memilio abm) +target_compile_options(abm_example PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) add_executable(ide_seir_example ide_seir.cpp) target_link_libraries(ide_seir_example PRIVATE memilio ide_seir) diff --git a/cpp/simulations/abm.cpp b/cpp/examples/abm.cpp similarity index 65% rename from cpp/simulations/abm.cpp rename to cpp/examples/abm.cpp index ab0df1be70..69fadee7f4 100644 --- a/cpp/simulations/abm.cpp +++ b/cpp/examples/abm.cpp @@ -29,8 +29,6 @@ #include "memilio/utils/random_number_generator.h" #include "memilio/utils/uncertain_value.h" -namespace fs = boost::filesystem; - // Assign the name to general age group. size_t num_age_groups = 6; const auto age_group_0_to_4 = mio::AgeGroup(0); @@ -187,72 +185,14 @@ void create_model_from_statistical_data(mio::abm::Model& model) * The private Households are divided with respect to the amount of people living in each household. For a one person household we have the exact age distribution. For the rest we have data about which kind of family lives in them. The different kinds of families are: A family with two parents and the rest are children, a family with one parent and the rest are children and "other" families with no exact data about their age. */ - // Refugee - auto refugee = mio::abm::HouseholdMember(num_age_groups); - refugee.set_age_weight(age_group_0_to_4, 25); - refugee.set_age_weight(age_group_5_to_14, 12); - refugee.set_age_weight(age_group_15_to_34, 25); - refugee.set_age_weight(age_group_35_to_59, 9); - refugee.set_age_weight(age_group_60_to_79, 1); - refugee.set_age_weight(age_group_80_plus, 1); - int refugee_number_of_people = 74; - int refugee_number_of_households = 12; - auto refugeeGroup = make_uniform_households(refugee, refugee_number_of_people, refugee_number_of_households); - - add_household_group_to_model(model, refugeeGroup); - - // Disabled - auto disabled = mio::abm::HouseholdMember(num_age_groups); - disabled.set_age_weight(age_group_0_to_4, 2); - disabled.set_age_weight(age_group_5_to_14, 6); - disabled.set_age_weight(age_group_15_to_34, 13); - disabled.set_age_weight(age_group_35_to_59, 42); - disabled.set_age_weight(age_group_60_to_79, 97); - disabled.set_age_weight(age_group_80_plus, 32); - int disabled_number_of_people = 194; - int disabled_number_of_households = 8; - - auto disabledGroup = make_uniform_households(disabled, disabled_number_of_people, disabled_number_of_households); - - add_household_group_to_model(model, disabledGroup); - - // Retirement - auto retired = mio::abm::HouseholdMember(num_age_groups); - retired.set_age_weight(age_group_15_to_34, 1); - retired.set_age_weight(age_group_35_to_59, 30); - retired.set_age_weight(age_group_60_to_79, 185); - retired.set_age_weight(age_group_80_plus, 530); - int retirement_number_of_people = 744; - int retirement_number_of_households = 16; - - auto retirementGroup = - make_uniform_households(retired, retirement_number_of_people, retirement_number_of_households); - - add_household_group_to_model(model, retirementGroup); - - // Others - auto other = mio::abm::HouseholdMember(num_age_groups); - other.set_age_weight(age_group_0_to_4, 30); - other.set_age_weight(age_group_5_to_14, 40); - other.set_age_weight(age_group_15_to_34, 72); - other.set_age_weight(age_group_35_to_59, 40); - other.set_age_weight(age_group_60_to_79, 30); - other.set_age_weight(age_group_80_plus, 10); - int others_number_of_people = 222; - int others_number_of_households = 20; - - auto otherGroup = make_uniform_households(other, others_number_of_people, others_number_of_households); - - add_household_group_to_model(model, otherGroup); - // One Person Household (we have exact age data about this) auto one_person_household_member = mio::abm::HouseholdMember(num_age_groups); one_person_household_member.set_age_weight(age_group_15_to_34, 4364); one_person_household_member.set_age_weight(age_group_35_to_59, 7283); one_person_household_member.set_age_weight(age_group_60_to_79, 4100); one_person_household_member.set_age_weight(age_group_80_plus, 1800); - int one_person_number_of_people = 15387; - int one_person_number_of_households = 15387; + int one_person_number_of_people = 1538; + int one_person_number_of_households = 1538; auto onePersonGroup = make_uniform_households(one_person_household_member, one_person_number_of_people, one_person_number_of_households); @@ -279,33 +219,33 @@ void create_model_from_statistical_data(mio::abm::Model& model) random.set_age_weight(age_group_80_plus, 5038); // Two person households - int two_person_full_families = 11850; - int two_person_half_families = 1765; - int two_person_other_families = 166; + int two_person_full_families = 1185; + int two_person_half_families = 176; + int two_person_other_families = 16; auto twoPersonHouseholds = make_homes_with_families(child, parent, random, 2, two_person_full_families, two_person_half_families, two_person_other_families); add_household_group_to_model(model, twoPersonHouseholds); // Three person households - int three_person_full_families = 4155; - int three_person_half_families = 662; - int three_person_other_families = 175; + int three_person_full_families = 415; + int three_person_half_families = 66; + int three_person_other_families = 17; auto threePersonHouseholds = make_homes_with_families(child, parent, random, 3, three_person_full_families, three_person_half_families, three_person_other_families); add_household_group_to_model(model, threePersonHouseholds); // Four person households - int four_person_full_families = 3551; - int four_person_half_families = 110; - int four_person_other_families = 122; + int four_person_full_families = 355; + int four_person_half_families = 11; + int four_person_other_families = 12; auto fourPersonHouseholds = make_homes_with_families(child, parent, random, 4, four_person_full_families, four_person_half_families, four_person_other_families); add_household_group_to_model(model, fourPersonHouseholds); // Five plus person households - int fiveplus_person_full_families = 1245; - int fiveplus_person_half_families = 80; - int fiveplus_person_other_families = 82; + int fiveplus_person_full_families = 124; + int fiveplus_person_half_families = 8; + int fiveplus_person_other_families = 8; auto fivePlusPersonHouseholds = make_homes_with_families(child, parent, random, 5, fiveplus_person_full_families, fiveplus_person_half_families, fiveplus_person_other_families); @@ -315,7 +255,7 @@ void create_model_from_statistical_data(mio::abm::Model& model) /** * Add locations to the model and assign locations to the people. */ -void create_assign_locations(mio::abm::Model& model) +void create_assign_locations_and_testing_schemes(mio::abm::Model& model) { // Add one social event with 100 maximum contacts. // Maximum contacs limit the number of people that a person can infect while being at this location. @@ -329,7 +269,7 @@ void create_assign_locations(mio::abm::Model& model) auto testing_criteria = mio::abm::TestingCriteria(); auto validity_period = mio::abm::days(2); auto start_date = mio::abm::TimePoint(0); - auto end_date = mio::abm::TimePoint(0) + mio::abm::days(60); + auto end_date = mio::abm::TimePoint(0) + mio::abm::days(20); auto probability = mio::UncertainValue<>(); assign_uniform_distribution(probability, 0.5, 1.0); @@ -436,195 +376,201 @@ void create_assign_locations(mio::abm::Model& model) auto test_at_work = std::vector{mio::abm::LocationType::Work}; auto testing_criteria_work = mio::abm::TestingCriteria(); - - assign_uniform_distribution(probability, 0.1, 0.5); - auto testing_scheme_work = mio::abm::TestingScheme(testing_criteria_work, validity_period, start_date, end_date, - test_params, probability.draw_sample()); + auto testing_scheme_work = mio::abm::TestingScheme(testing_criteria_work, validity_period, start_date, end_date, + test_params, probability.draw_sample()); model.get_testing_strategy().add_testing_scheme(mio::abm::LocationType::Work, testing_scheme_work); } /** * Assign an infection state to each person. */ -void assign_infection_state(mio::abm::Model& model, mio::abm::TimePoint t, double exposed_prob, - double infected_no_symptoms_prob, double infected_symptoms_prob, double recovered_prob) +void assign_infection_state_masks_and_compliance(mio::abm::Model& model) { - auto persons = model.get_persons(); - for (auto& person : persons) { - auto rng = mio::abm::PersonalRandomNumberGenerator(person); - auto infection_state = determine_infection_state(rng, exposed_prob, infected_no_symptoms_prob, - infected_symptoms_prob, recovered_prob); - if (infection_state != mio::abm::InfectionState::Susceptible) { - person.add_new_infection(mio::abm::Infection(rng, mio::abm::VirusVariant::Wildtype, person.get_age(), - model.parameters, t, infection_state, - person.get_latest_protection(), false)); + for (auto& person : model.get_persons()) { + auto prng = mio::abm::PersonalRandomNumberGenerator(person); + //some % of people are infected, large enough to have some infection activity without everyone dying + auto pct_infected = 0.05; + if (mio::UniformDistribution::get_instance()(prng, 0.0, 1.0) < pct_infected) { + auto state = mio::abm::InfectionState( + mio::UniformIntDistribution::get_instance()(prng, 1, int(mio::abm::InfectionState::Count) - 1)); + auto infection = mio::abm::Infection(prng, mio::abm::VirusVariant::Wildtype, person.get_age(), + model.parameters, mio::abm::TimePoint(0), state); + person.add_new_infection(std::move(infection)); + } + + //equal chance of (moderate) mask refusal and (moderate) mask eagerness + auto pct_compliance_values = std::array{0.05 /*0*/, 0.2 /*0.25*/, 0.5 /*0.5*/, 0.2 /*0.75*/, 0.05 /*1*/}; + auto compliance_value = 0.0025 * mio::DiscreteDistribution::get_instance()(prng, pct_compliance_values); + person.set_compliance(mio::abm::InterventionType::Mask, compliance_value); + } + + //masks at locations + for (auto& loc : model.get_locations()) { + //some % of locations require masks + //skip homes so persons always have a place to go, simulation might break otherwise + auto pct_require_mask = 0.2; + if (loc.get_type() != mio::abm::LocationType::Home && + mio::UniformDistribution::get_instance()(model.get_rng()) < pct_require_mask) { + loc.set_required_mask(mio::abm::MaskType::Community); } } } -void set_parameters(mio::abm::Parameters params) +std::pair get_my_and_sigma(std::pair mean_and_std) { - // Set the age group the can go to school is AgeGroup(1) (i.e. 5-14) - params.get()[age_group_5_to_14] = true; - // Set the age group the can go to work is AgeGroup(2) and AgeGroup(3) (i.e. 15-34 and 35-59) - params.get().set_multiple({age_group_15_to_34, age_group_35_to_59}, true); - - params.set( - {{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, mio::ParameterDistributionLogNormal(4., 1.)}); - - params.set( - {{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, mio::ParameterDistributionLogNormal(4., 1.)}); - - params.set( - {{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, mio::ParameterDistributionLogNormal(4., 1.)}); - - params.set( - {{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, mio::ParameterDistributionLogNormal(4., 1.)}); - - params.set( - {{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, mio::ParameterDistributionLogNormal(4., 1.)}); - - params.set( - {{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, mio::ParameterDistributionLogNormal(4., 1.)}); - - params.set( - {{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, mio::ParameterDistributionLogNormal(4., 1.)}); - - params.set( - {{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, mio::ParameterDistributionLogNormal(4., 1.)}); - - params.set( - {{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, mio::ParameterDistributionLogNormal(4., 1.)}); + auto mean = mean_and_std.first; + auto stddev = mean_and_std.second; + double my = log(mean * mean / sqrt(mean * mean + stddev * stddev)); + double sigma = sqrt(log(1 + stddev * stddev / (mean * mean))); + return {my, sigma}; } +void set_parameters(mio::abm::Parameters& params) +{ + // Set the Time parameters for the infection same for every age group for now + + // Incubation period (Exposed to No Symptoms) + auto incubation_period_my_sigma = get_my_and_sigma({4.5, 1.5}); + params.get() = + mio::ParameterDistributionLogNormal(incubation_period_my_sigma.first, incubation_period_my_sigma.second); + + // Infected No Symptoms to Symptoms + auto infected_no_symptoms_to_symptoms_my_sigma = get_my_and_sigma({1.1, 0.9}); + params.get() = mio::ParameterDistributionLogNormal( + infected_no_symptoms_to_symptoms_my_sigma.first, infected_no_symptoms_to_symptoms_my_sigma.second); + + // Infected No Symptoms to Recovered + auto infected_no_symptoms_to_recovered_my_sigma = get_my_and_sigma({8.0, 2.0}); + params.get() = mio::ParameterDistributionLogNormal( + infected_no_symptoms_to_recovered_my_sigma.first, infected_no_symptoms_to_recovered_my_sigma.second); + + // Infected Symptoms to Severe + auto infected_symptoms_to_severe_my_sigma = get_my_and_sigma({6.6, 4.9}); + params.get() = mio::ParameterDistributionLogNormal( + infected_symptoms_to_severe_my_sigma.first, infected_symptoms_to_severe_my_sigma.second); + + // Infected Symptoms to Recovered + auto infected_symptoms_to_recovered_my_sigma = get_my_and_sigma({8.0, 2.0}); + params.get() = mio::ParameterDistributionLogNormal( + infected_symptoms_to_recovered_my_sigma.first, infected_symptoms_to_recovered_my_sigma.second); + + // Infected Severe to Critical + auto infected_severe_to_critical_my_sigma = get_my_and_sigma({1.5, 2.0}); + params.get() = mio::ParameterDistributionLogNormal( + infected_severe_to_critical_my_sigma.first, infected_severe_to_critical_my_sigma.second); + + // Infected Severe to Recovered + auto infected_severe_to_recovered_my_sigma = get_my_and_sigma({18.1, 6.3}); + params.get() = mio::ParameterDistributionLogNormal( + infected_severe_to_recovered_my_sigma.first, infected_severe_to_recovered_my_sigma.second); + + // Infected Critical to Dead + auto infected_critical_to_dead_my_sigma = get_my_and_sigma({10.7, 4.8}); + params.get() = mio::ParameterDistributionLogNormal( + infected_critical_to_dead_my_sigma.first, infected_critical_to_dead_my_sigma.second); + + // Infected Critical to Recovered + auto infected_critical_to_recovered_my_sigma = get_my_and_sigma({18.1, 6.3}); + params.get() = mio::ParameterDistributionLogNormal( + infected_critical_to_recovered_my_sigma.first, infected_critical_to_recovered_my_sigma.second); + + // Set percentage parameters (unchanged) + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.50; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.55; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = + 0.60; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = + 0.70; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = + 0.83; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.90; + + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.02; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.03; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.04; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.07; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.17; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.24; + + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.1; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.11; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.12; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.14; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.33; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.62; + + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.12; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = 0.13; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.15; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.26; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.40; + params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.48; + + // Set other parameters + params.get() = 0.0; +} /** * Create a sampled model with start time t0. * @param t0 the start time of the simulation */ -mio::abm::Model create_sampled_model(const mio::abm::TimePoint& t0) +mio::abm::Model create_sampled_model() { - // mio::thread_local_rng().seed( - // {123144124, 835345345, 123123123, 99123}); //set seeds, e.g., for debugging - printf("Parameter Sample Seeds: "); - for (auto s : mio::thread_local_rng().get_seeds()) { - printf("%u, ", s); - } - printf("\n"); - - // Assumed percentage of infection state at the beginning of the simulation. - ScalarType exposed_prob = 0.005, infected_no_symptoms_prob = 0.001, infected_symptoms_prob = 0.001, - recovered_prob = 0.0; //Set global infection parameters (similar to infection parameters in SECIR model) and initialize the model auto model = mio::abm::Model(num_age_groups); set_parameters(model.parameters); - - // model.get_rng().seed( - // {23144124, 1835345345, 9343763, 9123}); //set seeds, e.g., for debugging - printf("ABM Simulation Seeds: "); - for (auto s : model.get_rng().get_seeds()) { - printf("%u, ", s); - } - printf("\n"); - // Create the model object from statistical data. create_model_from_statistical_data(model); // Assign an infection state to each person. - assign_infection_state(model, t0, exposed_prob, infected_no_symptoms_prob, infected_symptoms_prob, recovered_prob); + assign_infection_state_masks_and_compliance(model); // Add locations and assign locations to the people. - create_assign_locations(model); - - auto t_lockdown = mio::abm::TimePoint(0) + mio::abm::days(20); - - // During the lockdown, 25% of people work from home and schools are closed for 90% of students. - // Social events are very rare. - mio::abm::set_home_office(t_lockdown, 0.25, model.parameters); - mio::abm::set_school_closure(t_lockdown, 0.9, model.parameters); - mio::abm::close_social_events(t_lockdown, 0.9, model.parameters); + create_assign_locations_and_testing_schemes(model); return model; } /** * Run the ABM simulation. - * @param result_dir Directory where all results of the parameter study will be stored. + * @param result_dir Directory where all results will be stored. * @param num_runs Number of runs. - * @param save_single_runs [Default: true] Defines if single run results are written to the disk. - * @returns Any io error that occurs during reading or writing of files. + * @param save_single_runs If true, single run results are written to disk. */ -mio::IOResult run(const fs::path& result_dir, size_t num_runs, bool save_single_runs = true) +void run() { - - auto t0 = mio::abm::TimePoint(0); // Start time per simulation - auto tmax = mio::abm::TimePoint(0) + mio::abm::days(60); // End time per simulation - auto ensemble_results = std::vector>>{}; // Vector of collected results - ensemble_results.reserve(size_t(num_runs)); - auto ensemble_params = std::vector>{}; - ensemble_params.reserve(size_t(num_runs)); - auto run_idx = size_t(1); // The run index + auto t0 = mio::abm::TimePoint(0); + auto tmax = t0 + mio::abm::days(20); // Create the sampled simulation with start time t0 - auto model = create_sampled_model(t0); - ensemble_params.push_back(std::vector{model}); - - // Loop over a number of runs - while (run_idx <= num_runs) { - // Make a simulation using a copy from the original model - auto sim = mio::abm::Simulation(t0, mio::abm::Model(model)); - // Add a time series writer to the simulation - mio::History historyTimeSeries{ - Eigen::Index(mio::abm::InfectionState::Count)}; - // Advance the model to tmax - sim.advance(tmax, historyTimeSeries); - // Collect the results from the simulation - ensemble_results.push_back(std::vector>{std::get<0>(historyTimeSeries.get_log())}); - // Increase the run index - ++run_idx; + auto model = create_sampled_model(); + + auto sim = mio::abm::Simulation(t0, std::move(model)); + sim.advance(tmax); + + // Print the infection states at the end of the simulation + Eigen::VectorXd sum = Eigen::VectorXd::Zero(Eigen::Index(mio::abm::InfectionState::Count)); + for (auto& location : sim.get_model().get_locations()) { + for (uint32_t inf_state = 0; inf_state < (int)mio::abm::InfectionState::Count; inf_state++) { + sum[inf_state] += + sim.get_model().get_subpopulation(location.get_id(), tmax, mio::abm::InfectionState(inf_state)); + } + } + auto inf_states = std::vector{"S", "E", "I_NS", "I_Sy", "I_Sev", "I_Crit", "R", "D"}; + std::cout << "Infection states at simulation end:"; + for (int i = 0; i < (int)mio::abm::InfectionState::Count; i++) { + std::cout << " " << inf_states[i] << ": " << sum[i]; } - // Save all results to files - BOOST_OUTCOME_TRY(save_results(ensemble_results, ensemble_params, {0}, result_dir, save_single_runs)); - return mio::success(); + std::cout << std::endl; } -int main(int argc, char** argv) +int main() { - mio::set_log_level(mio::LogLevel::warn); - std::string result_dir = "."; - size_t num_runs; - bool save_single_runs = true; - - if (argc == 2) { - num_runs = atoi(argv[1]); - printf("Number of run is %s.\n", argv[1]); - printf("Saving results to the current directory.\n"); - } - - else if (argc == 3) { - num_runs = atoi(argv[1]); - result_dir = argv[2]; - printf("Number of runs is %s.\n", argv[1]); - printf("Saving results to \"%s\".\n", result_dir.c_str()); - } - else { - printf("Usage:\n"); - printf("abm_example \n"); - printf("\tRun the simulation for time(s).\n"); - printf("\tStore the results in the current directory.\n"); - printf("abm_example \n"); - printf("\tRun the simulation for time(s).\n"); - printf("\tStore the results in .\n"); - return 0; - } - - auto result = run(result_dir, num_runs, save_single_runs); - if (!result) { - printf("%s\n", result.error().formatted_message().c_str()); - return -1; - } + std::cout << "Starting ABM simulation..." << std::endl; + run(); + std::cout << "ABM simulation finished." << std::endl; return 0; } diff --git a/cpp/examples/abm_history_object.cpp b/cpp/examples/abm_history_object.cpp deleted file mode 100644 index 70e8939f60..0000000000 --- a/cpp/examples/abm_history_object.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* -* Copyright (C) 2020-2025 MEmilio -* -* Authors: Khoa Nguyen -* -* 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. -*/ -#include "abm/household.h" -#include "abm/lockdown_rules.h" -#include "abm/simulation.h" -#include "abm/model.h" -#include "abm/location_type.h" -#include "memilio/utils/abstract_parameter_distribution.h" -#include "memilio/io/history.h" -#include "memilio/utils/parameter_distributions.h" - -#include -#include - -std::string convert_loc_id_to_string(std::tuple tuple_id) -{ - return std::to_string(static_cast(std::get<0>(tuple_id))) + "_" + - std::to_string(std::get<1>(tuple_id)); -} - -template -void write_log_to_file(const T& history) -{ - auto logg = history.get_log(); - // Write the results to a file. - auto loc_id = std::get<1>(logg); - auto time_points = std::get<0>(logg); - std::string input; - std::ofstream myfile("test_output.txt"); - myfile << "Locations as numbers:\n"; - for (auto&& id : loc_id[0]) { - myfile << convert_loc_id_to_string(id) << "\n"; - } - myfile << "Timepoints:\n"; - - for (auto&& t : time_points) { - input += std::to_string(t) + " "; - } - myfile << input << "\n"; - - myfile.close(); -} - -int main() -{ - mio::set_log_level(mio::LogLevel::warn); - // This is a minimal example with children and adults < 60y. - // We divided them into 4 different age groups, which are defined as follows: - const size_t num_age_groups = 4; - const auto age_group_0_to_4 = mio::AgeGroup(0); - const auto age_group_5_to_14 = mio::AgeGroup(1); - const auto age_group_15_to_34 = mio::AgeGroup(2); - const auto age_group_35_to_59 = mio::AgeGroup(3); - - // Create the model with 4 age groups. - auto model = mio::abm::Model(num_age_groups); - mio::ParameterDistributionLogNormal log_norm(4., 1.); - // Set same infection parameter for all age groups. For example, the incubation period is log normally distributed with parameters 4 and 1. - model.parameters.get() = mio::ParameterDistributionLogNormal(4., 1.); - - // Set the age group the can go to school is AgeGroup(1) (i.e. 5-14) - model.parameters.get()[age_group_5_to_14] = true; - // Set the age group the can go to work is AgeGroup(2) and AgeGroup(3) (i.e. 15-34 and 35-59) - model.parameters.get().set_multiple({age_group_15_to_34, age_group_35_to_59}, true); - - // There are 3 households for each household group. - int n_households = 3; - - // For more than 1 family households we need families. These are parents and children and randoms (which are distributed like the data we have for these households). - auto child = mio::abm::HouseholdMember(num_age_groups); // A child is 50/50% 0-4 or 5-14. - child.set_age_weight(age_group_0_to_4, 1); - child.set_age_weight(age_group_5_to_14, 1); - - auto parent = mio::abm::HouseholdMember(num_age_groups); // A parent is 50/50% 15-34 or 35-59. - parent.set_age_weight(age_group_15_to_34, 1); - parent.set_age_weight(age_group_35_to_59, 1); - - // Two-person household with one parent and one child. - auto twoPersonHousehold_group = mio::abm::HouseholdGroup(); - auto twoPersonHousehold_full = mio::abm::Household(); - twoPersonHousehold_full.add_members(child, 1); - twoPersonHousehold_full.add_members(parent, 1); - twoPersonHousehold_group.add_households(twoPersonHousehold_full, n_households); - add_household_group_to_model(model, twoPersonHousehold_group); - - // Three-person household with two parent and one child. - auto threePersonHousehold_group = mio::abm::HouseholdGroup(); - auto threePersonHousehold_full = mio::abm::Household(); - threePersonHousehold_full.add_members(child, 1); - threePersonHousehold_full.add_members(parent, 2); - threePersonHousehold_group.add_households(threePersonHousehold_full, n_households); - add_household_group_to_model(model, threePersonHousehold_group); - - // 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); - 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); - model.get_location(hospital).get_infection_parameters().set(5); - auto icu = model.add_location(mio::abm::LocationType::ICU); - model.get_location(icu).get_infection_parameters().set(5); - // Add one supermarket, maximum constacts are assumed to be 20. - auto shop = model.add_location(mio::abm::LocationType::BasicsShop); - model.get_location(shop).get_infection_parameters().set(20); - // At every school, the maximum contacts are 20. - auto school = model.add_location(mio::abm::LocationType::School); - model.get_location(school).get_infection_parameters().set(20); - // At every workplace, maximum contacts are 10. - auto work = model.add_location(mio::abm::LocationType::Work); - model.get_location(work).get_infection_parameters().set(10); - - // People can get tested at work (and do this with 0.5 probability) from time point 0 to day 30. - auto validity_period = mio::abm::days(1); - auto probability = 0.5; - auto start_date = mio::abm::TimePoint(0); - auto end_date = mio::abm::TimePoint(0) + mio::abm::days(30); - auto test_type = mio::abm::TestType::Antigen; - auto test_parameters = model.parameters.get()[test_type]; - auto testing_criteria_work = mio::abm::TestingCriteria(); - auto testing_scheme_work = mio::abm::TestingScheme(testing_criteria_work, validity_period, start_date, end_date, - test_parameters, probability); - model.get_testing_strategy().add_testing_scheme(mio::abm::LocationType::Work, testing_scheme_work); - - // Assign infection state to each person. - // The infection states are chosen randomly. - auto persons = model.get_persons(); - for (auto& person : persons) { - auto rng = mio::abm::PersonalRandomNumberGenerator(person); - mio::abm::InfectionState infection_state = - (mio::abm::InfectionState)(rand() % ((uint32_t)mio::abm::InfectionState::Count - 1)); - if (infection_state != mio::abm::InfectionState::Susceptible) - person.add_new_infection(mio::abm::Infection(rng, mio::abm::VirusVariant::Wildtype, person.get_age(), - model.parameters, start_date, infection_state)); - } - - // Assign locations to the people - 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); - //assign hospital and ICU - model.assign_location(pid, hospital); - model.assign_location(pid, icu); - //assign work/school to people depending on their age - if (person.get_age() == age_group_5_to_14) { - model.assign_location(pid, school); - } - if (person.get_age() == age_group_15_to_34 || person.get_age() == age_group_35_to_59) { - model.assign_location(pid, work); - } - } - - // During the lockdown, social events are closed for 90% of people. - auto t_lockdown = mio::abm::TimePoint(0) + mio::abm::days(10); - mio::abm::close_social_events(t_lockdown, 0.9, model.parameters); - - auto t0 = mio::abm::TimePoint(0); - auto tmax = mio::abm::TimePoint(0) + mio::abm::days(30); - auto sim = mio::abm::Simulation(t0, std::move(model)); - - struct LogTimePoint : mio::LogAlways { - using Type = double; - static Type log(const mio::abm::Simulation<>& sim) - { - return sim.get_time().hours(); - } - }; - struct LogLocationIds : mio::LogOnce { - using Type = std::vector>; - static Type log(const mio::abm::Simulation<>& sim) - { - Type location_ids{}; - for (auto& location : sim.get_model().get_locations()) { - location_ids.push_back(std::make_tuple(location.get_type(), location.get_id().get())); - } - return location_ids; - } - }; - - mio::History history; - - sim.advance(tmax, history); - - write_log_to_file(history); -} diff --git a/cpp/simulations/CMakeLists.txt b/cpp/simulations/CMakeLists.txt index a784b83ba5..155940f118 100644 --- a/cpp/simulations/CMakeLists.txt +++ b/cpp/simulations/CMakeLists.txt @@ -7,15 +7,7 @@ if(MEMILIO_HAS_JSONCPP AND MEMILIO_HAS_HDF5) target_link_libraries(2021_vaccination_delta PRIVATE memilio ode_secirvvs Boost::filesystem ${HDF5_C_LIBRARIES}) target_compile_options(2021_vaccination_delta PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - add_executable(abm_simulation abm.cpp) - target_link_libraries(abm_simulation PRIVATE memilio abm Boost::filesystem ${HDF5_C_LIBRARIES}) - target_compile_options(abm_simulation PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - add_executable(munich_graph_sim munich_graph_sim) target_link_libraries(munich_graph_sim PRIVATE memilio ode_secir abm Boost::filesystem ${HDF5_C_LIBRARIES}) target_compile_options(munich_graph_sim PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) - - add_executable(abm_braunschweig abm_braunschweig.cpp) - target_link_libraries(abm_braunschweig PRIVATE memilio abm Boost::filesystem ${HDF5_C_LIBRARIES}) - target_compile_options(abm_braunschweig PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) endif() diff --git a/cpp/simulations/abm_braunschweig.cpp b/cpp/simulations/abm_braunschweig.cpp deleted file mode 100644 index f1758ada16..0000000000 --- a/cpp/simulations/abm_braunschweig.cpp +++ /dev/null @@ -1,1044 +0,0 @@ -/* -* Copyright (C) 2020-2025 MEmilio -* -* Authors: Sascha Korf, Carlotta Gerstein -* -* 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. -*/ -#include "abm/common_abm_loggers.h" -#include "abm/location_id.h" -#include "abm/lockdown_rules.h" -#include "abm/parameters.h" -#include "abm/parameters.h" -#include "abm/person.h" -#include "abm/person_id.h" -#include "abm/simulation.h" -#include "abm/model.h" -#include "memilio/utils/abstract_parameter_distribution.h" -#include "memilio/epidemiology/age_group.h" -#include "memilio/io/io.h" -#include "memilio/io/result_io.h" -#include "memilio/utils/parameter_distributions.h" -#include "memilio/utils/uncertain_value.h" -#include "boost/algorithm/string/split.hpp" -#include "boost/algorithm/string/classification.hpp" - -#include -#include -#include -#include - -namespace fs = boost::filesystem; - -// Assign the name to general age group. -size_t num_age_groups = 6; -const auto age_group_0_to_4 = mio::AgeGroup(0); -const auto age_group_5_to_14 = mio::AgeGroup(1); -const auto age_group_15_to_34 = mio::AgeGroup(2); -const auto age_group_35_to_59 = mio::AgeGroup(3); -const auto age_group_60_to_79 = mio::AgeGroup(4); -const auto age_group_80_plus = mio::AgeGroup(5); - -/** - * Set a value and distribution of an UncertainValue. - * Assigns average of min and max as a value and UNIFORM(min, max) as a distribution. - * @param p uncertain value to set. - * @param min minimum of distribution. - * @param max minimum of distribution. - */ -void assign_uniform_distribution(mio::UncertainValue<>& p, ScalarType min, ScalarType max) -{ - p = mio::UncertainValue<>(0.5 * (max + min)); - p.set_distribution(mio::ParameterDistributionUniform(min, max)); -} - -/** - * Determine the infection state of a person at the beginning of the simulation. - * The infection states are chosen randomly. They are distributed according to the probabilites set in the example. - * @return random infection state - */ -mio::abm::InfectionState determine_infection_state(mio::abm::PersonalRandomNumberGenerator& rng, ScalarType exposed, - ScalarType infected_no_symptoms, ScalarType infected_symptoms, - ScalarType recovered) -{ - ScalarType susceptible = 1 - exposed - infected_no_symptoms - infected_symptoms - recovered; - std::vector weights = { - susceptible, exposed, infected_no_symptoms, infected_symptoms / 3, infected_symptoms / 3, - infected_symptoms / 3, recovered}; - if (weights.size() != (size_t)mio::abm::InfectionState::Count - 1) { - mio::log_error("Initialization in ABM wrong, please correct vector length."); - } - auto state = mio::DiscreteDistribution::get_instance()(rng, weights); - return (mio::abm::InfectionState)state; -} - -/** - * Assign an infection state to each person. - */ -void assign_infection_state(mio::abm::Model& model, mio::abm::TimePoint t, double exposed_prob, - double infected_no_symptoms_prob, double infected_symptoms_prob, double recovered_prob) -{ - auto persons = model.get_persons(); - for (auto& person : persons) { - auto rng = mio::abm::PersonalRandomNumberGenerator(person); - auto infection_state = determine_infection_state(rng, exposed_prob, infected_no_symptoms_prob, - infected_symptoms_prob, recovered_prob); - if (infection_state != mio::abm::InfectionState::Susceptible) - person.add_new_infection(mio::abm::Infection(rng, mio::abm::VirusVariant::Wildtype, person.get_age(), - model.parameters, t, infection_state)); - } -} -int stringToMinutes(const std::string& input) -{ - size_t colonPos = input.find(":"); - if (colonPos == std::string::npos) { - // Handle invalid input (no colon found) - return -1; // You can choose a suitable error code here. - } - - std::string xStr = input.substr(0, colonPos); - std::string yStr = input.substr(colonPos + 1); - - int x = std::stoi(xStr); - int y = std::stoi(yStr); - return x * 60 + y; -} - -int longLatToInt(const std::string& input) -{ - double y = std::stod(input) * 1e+5; //we want the 5 numbers after digit - return (int)y; -} -void split_line(std::string string, std::vector* row) -{ - std::vector strings; - - std::string x = ",,", y = ",-1,"; - size_t pos; - while ((pos = string.find(x)) != std::string::npos) { - string.replace(pos, 2, y); - } // Temporary fix to handle empty cells. - boost::split(strings, string, boost::is_any_of(",")); - std::transform(strings.begin(), strings.end(), std::back_inserter(*row), [&](std::string s) { - if (s.find(":") != std::string::npos) { - return stringToMinutes(s); - } - else if (s.find(".") != std::string::npos) { - return longLatToInt(s); - } - else { - return std::stoi(s); - } - }); -} - -mio::abm::LocationType get_location_type(uint32_t acitivity_end) -{ - mio::abm::LocationType type; - switch (acitivity_end) { - case 1: - type = mio::abm::LocationType::Work; - break; - case 2: - type = mio::abm::LocationType::School; - break; - case 3: - type = mio::abm::LocationType::BasicsShop; - break; - case 4: - type = mio::abm::LocationType::SocialEvent; // Freizeit - break; - case 5: - type = mio::abm::LocationType::BasicsShop; // Private Erledigung - break; - case 6: - type = mio::abm::LocationType::SocialEvent; // Sonstiges - break; - default: - type = mio::abm::LocationType::Home; - break; - } - return type; -} - -mio::AgeGroup determine_age_group(uint32_t age) -{ - if (age <= 4) { - return age_group_0_to_4; - } - else if (age <= 14) { - return age_group_5_to_14; - } - else if (age <= 34) { - return age_group_15_to_34; - } - else if (age <= 59) { - return age_group_35_to_59; - } - else if (age <= 79) { - return age_group_60_to_79; - } - else { - return age_group_80_plus; - } -} - -void create_model_from_data(mio::abm::Model& model, const std::string& filename, const mio::abm::TimePoint t0, - int max_number_persons) -{ - // Open File - const fs::path p = filename; - if (!fs::exists(p)) { - mio::log_error("Cannot read in data. File does not exist."); - } - // File pointer - std::fstream fin; - - // Open an existing file - fin.open(filename, std::ios::in); - std::vector row; - std::vector row_string; - std::string line; - - // Read the Titles from the Data file - std::getline(fin, line); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - std::vector titles; - boost::split(titles, line, boost::is_any_of(",")); - uint32_t count_of_titles = 0; - std::map index = {}; - for (auto const& title : titles) { - index.insert({title, count_of_titles}); - row_string.push_back(title); - count_of_titles++; - } - - std::map locations = {}; - std::map pids_data_to_model = {}; - std::map person_ids = {}; - std::map> locations_before; - std::map> locations_after; - - // For the model we need: Hospitals, ICUs (for both we just create one for now), Homes for each unique householdID, One Person for each person_id with respective age and home_id. - - // We assume that no person goes to an hospital, altough e.g. "Sonstiges" could be a hospital - auto hospital = model.add_location(mio::abm::LocationType::Hospital); - model.get_location(hospital).get_infection_parameters().set(5); - model.get_location(hospital).set_capacity(std::numeric_limits::max(), - std::numeric_limits::max()); - auto icu = model.add_location(mio::abm::LocationType::ICU); - model.get_location(icu).get_infection_parameters().set(5); - model.get_location(icu).set_capacity(std::numeric_limits::max(), std::numeric_limits::max()); - - // First we determine the persons number and their starting locations - int number_of_persons = 0; - - while (std::getline(fin, line)) { - row.clear(); - - // read columns in this row - split_line(line, &row); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - - uint32_t person_id = row[index["puid"]]; - auto it_person_id = person_ids.find(person_id); - if (it_person_id == person_ids.end()) { - if (number_of_persons >= max_number_persons) - break; //This is okay because the data is sorted by person_id - person_ids.insert({person_id, number_of_persons}); - number_of_persons++; - } - - // The starting location of a person is the end location of the last trip he made, either on the same day or on - // the day before - uint32_t target_location_id = std::abs(row[index["loc_id_end"]]); - int trip_start = row[index["start_time"]]; - if (trip_start < t0.hour_of_day()) { - auto it_person = locations_before.find(person_id); - if (it_person == locations_before.end()) { - locations_before.insert({person_id, std::make_pair(target_location_id, trip_start)}); - } - else { - if (it_person->second.second <= trip_start) { - it_person->second.first = target_location_id; - it_person->second.second = trip_start; - } - } - } - else { - auto it_person = locations_after.find(person_id); - if (it_person == locations_after.end()) { - locations_after.insert({person_id, std::make_pair(target_location_id, trip_start)}); - } - else { - if (it_person->second.second <= trip_start) { - it_person->second.first = target_location_id; - it_person->second.second = trip_start; - } - } - } - } - - fin.clear(); - fin.seekg(0); - std::getline(fin, line); // Skip header row - - // Add all locations to the model - while (std::getline(fin, line)) { - row.clear(); - - // read columns in this row - split_line(line, &row); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - - uint32_t person_id = row[index["puid"]]; - if (person_ids.find(person_id) == person_ids.end()) - break; - - uint32_t home_id = row[index["huid"]]; - uint32_t target_location_id = std::abs(row[index["loc_id_end"]]); - uint32_t activity_end = row[index["activity_end"]]; - mio::abm::GeographicalLocation location_long_lat = {(double)row[index["lon_end"]] / 1e+5, - (double)row[index["lat_end"]] / 1e+5}; - mio::abm::LocationId home; - auto it_home = locations.find(home_id); - if (it_home == locations.end()) { - home = model.add_location(mio::abm::LocationType::Home, 1); - locations.insert({home_id, home}); - mio::abm::GeographicalLocation location_long_lat_home = {(double)row[index["lon_start"]] / 1e+5, - (double)row[index["lat_start"]] / 1e+5}; - model.get_location(home).set_geographical_location(location_long_lat_home); - } - else { - home = it_home->second; - } - - mio::abm::LocationId location; - auto it_location = locations.find( - target_location_id); // Check if location already exists also for home which have the same id (home_id = target_location_id) - if (it_location == locations.end()) { - location = model.add_location( - get_location_type(activity_end), - 1); // Assume one place has one activity, this may be untrue but not important for now(?) - locations.insert({target_location_id, location}); - model.get_location(location).set_geographical_location(location_long_lat); - } - } - fin.clear(); - fin.seekg(0); - std::getline(fin, line); // Skip header row - - // Add the persons and trips - while (std::getline(fin, line)) { - row.clear(); - - // read columns in this row - split_line(line, &row); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - - uint64_t person_data_id = row[index["puid"]]; - if (person_ids.find(person_data_id) == person_ids.end()) - break; - - uint32_t age = row[index["age"]]; - uint32_t home_id = row[index["huid"]]; - uint32_t target_location_id = std::abs(row[index["loc_id_end"]]); - uint32_t start_location_id = std::abs(row[index["loc_id_start"]]); - uint32_t trip_start = row[index["start_time"]]; - uint32_t transport_mode = row[index["travel_mode"]]; - uint32_t acticity_end = row[index["activity_end"]]; - - // Add the trip to the trip list person and location must exist at this point - auto target_location = locations.find(target_location_id)->second; - auto start_location = locations.find(start_location_id)->second; - - auto pid_itr = pids_data_to_model.find(person_data_id); - - if (pid_itr == pids_data_to_model.end()) { // person has not been added to model yet - auto it_first_location_id = locations_before.find(person_data_id); - if (it_first_location_id == locations_before.end()) { - it_first_location_id = locations_after.find(person_data_id); - } - auto first_location_id = it_first_location_id->second.first; - auto first_location = locations.find(first_location_id)->second; - auto person_model_id = model.add_person(first_location, determine_age_group(age)); - auto home = locations.find(home_id)->second; - model.assign_location(person_model_id, home); - model.assign_location(person_model_id, hospital); - model.assign_location(person_model_id, icu); - pid_itr = pids_data_to_model.insert_or_assign(person_data_id, person_model_id).first; - } - - model.assign_location( - pid_itr->second, - target_location); //This assumes that we only have in each tripchain only one location type for each person - if (locations.find(start_location_id) == locations.end()) { - // For trips where the start location is not known use Home instead - start_location = model.get_person(pid_itr->second).get_assigned_location(mio::abm::LocationType::Home); - } - model.get_trip_list().add_trip( - mio::abm::Trip(static_cast(pid_itr->first), - mio::abm::TimePoint(0) + mio::abm::minutes(trip_start), target_location, start_location, - mio::abm::TransportMode(transport_mode), mio::abm::LocationType(acticity_end))); - } - model.get_trip_list().use_weekday_trips_on_weekend(); -} - -void set_parameters(mio::abm::Parameters params) -{ - // Set the age group the can go to school is AgeGroup(1) (i.e. 5-14) - params.get()[age_group_5_to_14] = true; - // Set the age group the can go to work is AgeGroup(2) and AgeGroup(3) (i.e. 15-34 and 35-59) - params.get().set_multiple({age_group_15_to_34, age_group_35_to_59}, true); - params.set( - {{mio::abm::VirusVariant::Count, mio::AgeGroup(num_age_groups)}, mio::ParameterDistributionLogNormal(4., 1.)}); - - //0-4 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = - mio::ParameterDistributionLogNormal(4., 1.); - - //5-14 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_5_to_14}] = - mio::ParameterDistributionLogNormal(4., 1.); - - //15-34 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - mio::ParameterDistributionLogNormal(4., 1.); - - //35-59 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - mio::ParameterDistributionLogNormal(4., 1.); - - //60-79 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - mio::ParameterDistributionLogNormal(4., 1.); - - //80+ - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - mio::ParameterDistributionLogNormal(4., 1.); - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - mio::ParameterDistributionLogNormal(4., 1.); - - // Set each parameter for vaccinated people including personal infection and vaccine protection levels. - // Summary: https://doi.org/10.1038/s41577-021-00550-x, - - //0-4 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.161; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.015; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - - // Protection of reinfection is the same for all age-groups, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_0_to_4, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_0_to_4, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.91}, {60, 0.92}, {90, 0.88}, {120, 0.84}, {150, 0.81}, {180, 0.88}, {450, 0.5}}}; - - // Set up age-related severe protection levels, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_0_to_4, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {450, 0.5}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_0_to_4, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.88}, {60, 0.91}, {90, 0.98}, {120, 0.94}, {150, 0.88}, {450, 0.5}}}; - - //5-14 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.161; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.015; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_0_to_4}] = 0.001; - - // Protection of reinfection is the same for all age-groups, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_5_to_14, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_5_to_14, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.91}, {60, 0.92}, {90, 0.88}, {120, 0.84}, {150, 0.81}, {180, 0.88}, {450, 0.5}}}; - - // Set up age-related severe protection levels, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_5_to_14, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {450, 0.5}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_5_to_14, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.88}, {60, 0.91}, {90, 0.98}, {120, 0.94}, {150, 0.88}, {450, 0.5}}}; - - //15-34 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = - 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.001; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.013; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_15_to_34}] = 0.021; - - // Set up personal infection and vaccine protection levels, based on: https://doi.org/10.1038/s41577-021-00550-x, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_15_to_34, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_15_to_34, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.89}, {60, 0.84}, {90, 0.78}, {120, 0.68}, {150, 0.57}, {180, 0.39}, {450, 0.1}}}; - // Set up age-related severe protection levels, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_15_to_34, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {450, 0.5}}}; - // Information is from: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_15_to_34, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.88}, {60, 0.91}, {90, 0.98}, {120, 0.94}, {150, 0.88}, {180, 0.90}, {450, 0.5}}}; - - //35-59 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = - 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.003; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.02; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_35_to_59}] = 0.008; - // Protection of reinfection is the same for all age-groups, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_35_to_59, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_35_to_59, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.89}, {60, 0.84}, {90, 0.78}, {120, 0.68}, {150, 0.57}, {180, 0.39}, {450, 0.1}}}; - // Set up age-related severe protection levels, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_35_to_59, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {450, 0.5}}}; - // Information is from: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_35_to_59, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.88}, {60, 0.91}, {90, 0.98}, {120, 0.94}, {150, 0.88}, {180, 0.90}, {450, 0.5}}}; - //60-79 - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = - 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.009; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.035; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_60_to_79}] = 0.023; - // Protection of reinfection is the same for all age-groups, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_60_to_79, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_60_to_79, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.87}, {60, 0.85}, {90, 0.78}, {120, 0.67}, {150, 0.61}, {180, 0.50}, {450, 0.1}}}; - // Set up personal severe protection levels. - // Protection of severe infection of age group 65 + is different from other age group, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_60_to_79, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {360, 0.5}}}; - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_60_to_79, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.91}, {60, 0.86}, {90, 0.91}, {120, 0.94}, {150, 0.95}, {180, 0.90}, {450, 0.5}}}; - - //80+ - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = - 0.179; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.012; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.036; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; - params.get()[{mio::abm::VirusVariant::Wildtype, age_group_80_plus}] = 0.052; - // Protection of reinfection is the same for all age-groups, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5, https://doi.org/10.1038/s41591-021-01377-8 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_80_plus, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.852}, - {180, 0.852}, - {210, 0.845}, - {240, 0.828}, - {270, 0.797}, - {300, 0.759}, - {330, 0.711}, - {360, 0.661}, - {390, 0.616}, - {420, 0.580}, - {450, 0.559}, - {450, 0.550}}}; - // Information is from: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_80_plus, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.80}, {60, 0.79}, {90, 0.75}, {120, 0.56}, {150, 0.49}, {180, 0.43}, {450, 0.1}}}; - // Set up personal severe protection levels. - // Protection of severe infection of age group 65 + is different from other age group, based on: - // https://doi.org/10.1016/S0140-6736(22)02465-5 - params.get()[{mio::abm::ProtectionType::NaturalInfection, age_group_0_to_4, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.967}, - {30, 0.975}, - {60, 0.977}, - {90, 0.974}, - {120, 0.963}, - {150, 0.947}, - {180, 0.93}, - {210, 0.929}, - {240, 0.923}, - {270, 0.908}, - {300, 0.893}, - {330, 0.887}, - {360, 0.887}, - {360, 0.5}}}; - // Information is based on: https://doi.org/10.1016/S0140-6736(21)02183-8 - params.get()[{mio::abm::ProtectionType::GenericVaccine, age_group_80_plus, - mio::abm::VirusVariant::Wildtype}] = { - mio::TimeSeriesFunctorType::LinearInterpolation, - {{0, 0.5}, {30, 0.84}, {60, 0.88}, {90, 0.89}, {120, 0.86}, {150, 0.85}, {180, 0.83}, {450, 0.5}}}; -} - -/** - * Create a sampled simulation with start time t0. - * @param t0 The start time of the Simulation. - */ -mio::abm::Simulation<> create_sampled_simulation(const std::string& input_file, const mio::abm::TimePoint& t0, - int max_num_persons) -{ - // Assumed percentage of infection state at the beginning of the simulation. - ScalarType exposed_prob = 0.005, infected_no_symptoms_prob = 0.001, infected_symptoms_prob = 0.001, - recovered_prob = 0.0; - - //Set global infection parameters (similar to infection parameters in SECIR model) and initialize the model - auto model = mio::abm::Model(num_age_groups); - - set_parameters(model.parameters); - - // Create the model object from statistical data. - create_model_from_data(model, input_file, t0, max_num_persons); - model.use_mobility_rules(false); - - // Assign an infection state to each person. - assign_infection_state(model, t0, exposed_prob, infected_no_symptoms_prob, infected_symptoms_prob, recovered_prob); - - auto sim = mio::abm::Simulation(t0, std::move(model)); - return sim; -} - -template -void write_log_to_file_person_and_location_data(const T& history) -{ - auto logg = history.get_log(); - auto loc_id = std::get<0>(logg)[0]; - auto agent_id = std::get<1>(logg)[0]; - // Write lo to a text file. - std::ofstream myfile("locations_lookup.txt"); - myfile << "location_id, location_type, latitude, longitude\n"; - for (uint32_t loc_id_index = 0; loc_id_index < loc_id.size(); ++loc_id_index) { - auto id = std::get<0>(loc_id[loc_id_index]); - auto location_type = (int)std::get<1>(loc_id[loc_id_index]); - auto id_longitute = std::get<2>(loc_id[loc_id_index]).longitude; - auto id_latitude = std::get<2>(loc_id[loc_id_index]).latitude; - myfile << id << ", " << location_type << ", " << id_longitute << ", " << id_latitude << "\n"; - } - myfile.close(); - - std::ofstream myfile2("agents_lookup.txt"); - myfile2 << "agent_id, home_id, age\n"; - for (uint32_t agent_id_index = 0; agent_id_index < agent_id.size(); ++agent_id_index) { - auto id = std::get<0>(agent_id[agent_id_index]); - auto home_id = std::get<1>(agent_id[agent_id_index]); - auto age = std::get<2>(agent_id[agent_id_index]); - myfile2 << id << ", " << home_id << ", " << age << "\n"; - } - myfile2.close(); -} - -template -void write_log_to_file_trip_data(const T& history) -{ - - auto mobility_data = std::get<0>(history.get_log()); - std::ofstream myfile3("mobility_data.txt"); - myfile3 << "agent_id, trip_id, start_location, end_location, start_time, end_time, transport_mode, activity, " - "infection_state \n"; - int trips_id = 0; - for (uint32_t mobility_data_index = 2; mobility_data_index < mobility_data.size(); ++mobility_data_index) { - myfile3 << "timestep Nr.: " << mobility_data_index - 1 << "\n"; - for (uint32_t trip_index = 0; trip_index < mobility_data[mobility_data_index].size(); trip_index++) { - auto agent_id = std::get<0>(mobility_data[mobility_data_index][trip_index]); - - int start_index = mobility_data_index - 1; - using Type = std::tuple; - while (!std::binary_search(std::begin(mobility_data[start_index]), std::end(mobility_data[start_index]), - mobility_data[mobility_data_index][trip_index], - [](const Type& v1, const Type& v2) { - return std::get<0>(v1) < std::get<0>(v2); - })) { - start_index--; - } - auto start_location_iterator = - std::lower_bound(std::begin(mobility_data[start_index]), std::end(mobility_data[start_index]), - mobility_data[mobility_data_index][trip_index], [](const Type& v1, const Type& v2) { - return std::get<0>(v1) < std::get<0>(v2); - }); - auto start_location = (int)std::get<1>(*start_location_iterator).get(); - - auto end_location = (int)std::get<1>(mobility_data[mobility_data_index][trip_index]).get(); - - auto start_time = (int)std::get<2>(mobility_data[mobility_data_index][trip_index]).seconds(); - auto end_time = (int)std::get<2>(mobility_data[mobility_data_index][trip_index]).seconds(); - - auto transport_mode = (int)std::get<3>(mobility_data[mobility_data_index][trip_index]); - auto activity = (int)std::get<4>(mobility_data[mobility_data_index][trip_index]); - auto infection_state = (int)std::get<5>(mobility_data[mobility_data_index][trip_index]); - myfile3 << agent_id << ", " << trips_id << ", " << start_location << " , " << end_location << " , " - << start_time << " , " << end_time << " , " << transport_mode << " , " << activity << " , " - << infection_state << "\n"; - trips_id++; - } - } - myfile3.close(); -} - -mio::IOResult run(const std::string& input_file, const fs::path& result_dir, size_t num_runs, - bool save_single_runs = true) -{ - - auto t0 = mio::abm::TimePoint(0); // Start time per simulation - auto tmax = mio::abm::TimePoint(0) + mio::abm::days(2); // End time per simulation - auto ensemble_results = std::vector>>{}; // Vector of collected results - ensemble_results.reserve(size_t(num_runs)); - auto run_idx = size_t(1); // The run index - auto save_result_result = mio::IOResult(mio::success()); // Variable informing over successful IO operations - auto max_num_persons = 1000; - - // Loop over a number of runs - while (run_idx <= num_runs) { - - // Create the sampled simulation with start time t0. - auto sim = create_sampled_simulation(input_file, t0, max_num_persons); - //output object - mio::History - historyPersonInf; - mio::History historyTimeSeries{ - Eigen::Index(mio::abm::InfectionState::Count)}; - mio::History historyPersonInfDelta; - // Collect the id of location in model. - std::vector loc_ids; - for (auto& location : sim.get_model().get_locations()) { - loc_ids.push_back(location.get_id().get()); - } - // Advance the model to tmax - sim.advance(tmax, historyPersonInf, historyTimeSeries, historyPersonInfDelta); - // TODO: update result of the simulation to be a vector of location result. - auto temp_sim_result = std::vector>{std::get<0>(historyTimeSeries.get_log())}; - // Push result of the simulation back to the result vector - ensemble_results.push_back(temp_sim_result); - // Option to save the current run result to file - if (save_result_result && save_single_runs) { - auto result_dir_run = result_dir / ("abm_result_run_" + std::to_string(run_idx) + ".h5"); - save_result_result = save_result(ensemble_results.back(), loc_ids, 1, result_dir_run.string()); - } - write_log_to_file_person_and_location_data(historyPersonInf); - write_log_to_file_trip_data(historyPersonInfDelta); - ++run_idx; - } - BOOST_OUTCOME_TRY(save_result_result); - return mio::success(); -} - -int main(int argc, char** argv) -{ - mio::set_log_level(mio::LogLevel::warn); - - std::string result_dir = "."; - std::string input_file = ""; - size_t num_runs; - bool save_single_runs = true; - - if (argc == 2) { - num_runs = atoi(argv[1]); - printf("Number of run is %s.\n", argv[1]); - printf("Saving results to the current directory.\n"); - } - - else if (argc == 3) { - num_runs = atoi(argv[1]); - result_dir = argv[2]; - printf("Number of run is %s.\n", argv[1]); - printf("Saving results to \"%s\".\n", result_dir.c_str()); - } - else { - printf("Usage:\n"); - printf("abm_example \n"); - printf("\tRun the simulation for time(s).\n"); - printf("\tStore the results in the current directory.\n"); - printf("abm_braunschweig \n"); - printf("\tRun the simulation for time(s).\n"); - printf("\tStore the results in .\n"); - printf("Running with number of runs = 1.\n"); - num_runs = 1; - } - - // mio::thread_local_rng().seed({...}); //set seeds, e.g., for debugging - //printf("Seeds: "); - //for (auto s : mio::thread_local_rng().get_seeds()) { - // printf("%u, ", s); - //} - //printf("\n"); - - auto result = run(input_file, result_dir, num_runs, save_single_runs); - if (!result) { - printf("%s\n", result.error().formatted_message().c_str()); - return -1; - } - return 0; -}