From f5465e4f3d8f793e90b80dce4ee4f3fd12d83237 Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 17 May 2023 16:44:11 +0200 Subject: [PATCH 01/38] graph abm class --- cpp/CMakeLists.txt | 1 + cpp/examples/CMakeLists.txt | 4 ++ cpp/examples/graph_abm.cpp | 101 +++++++++++++++++++++++++++ cpp/models/abm/world.h | 3 + cpp/models/graph_abm/CMakeLists.txt | 10 +++ cpp/models/graph_abm/graph_world.cpp | 30 ++++++++ cpp/models/graph_abm/graph_world.h | 52 ++++++++++++++ 7 files changed, 201 insertions(+) create mode 100644 cpp/examples/graph_abm.cpp create mode 100644 cpp/models/graph_abm/CMakeLists.txt create mode 100644 cpp/models/graph_abm/graph_world.cpp create mode 100644 cpp/models/graph_abm/graph_world.h diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 1793d7b5a8..e8073bb739 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -116,6 +116,7 @@ add_subdirectory(memilio) if(MEMILIO_BUILD_MODELS) add_subdirectory(models/abm) + add_subdirectory(models/graph_abm) add_subdirectory(models/ode_secir) add_subdirectory(models/ode_secirvvs) add_subdirectory(models/ide_secir) diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index f826aa9aae..ed8d773294 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -29,6 +29,10 @@ target_link_libraries(graph_example PRIVATE memilio ode_seir) add_executable(abm_minimal_example abm_minimal.cpp) target_link_libraries(abm_minimal_example PRIVATE memilio abm) +add_executable(graph_abm_example graph_abm.cpp) +target_link_libraries(graph_abm_example PRIVATE memilio graph_abm) +target_link_libraries(graph_abm_example PRIVATE memilio abm) + add_executable(twitter_migration_example twitter_migration.cpp) target_link_libraries(twitter_migration_example PRIVATE memilio ode_secir) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp new file mode 100644 index 0000000000..527d75f751 --- /dev/null +++ b/cpp/examples/graph_abm.cpp @@ -0,0 +1,101 @@ +/* +* Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) +* +* 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/abm.h" +#include "graph_abm/graph_world.h" +#include "abm/household.h" +#include "memilio/mobility/graph.h" +#include "memilio/mobility/meta_mobility_instant.h" +#include + +int main() +{ + // Set global infection parameters (similar to infection parameters in SECIR model) and initialize the world + mio::abm::GlobalInfectionParameters infection_params; + + // Set same infection parameter for all age groups. For example, the incubation period is 4 days. + infection_params.get() = 4.; + + // Create the worlds with infection parameters. + auto world1 = mio::graph_abm::GraphWorld(infection_params); + auto world2 = mio::graph_abm::GraphWorld(infection_params); + + //add households for world 1 + auto child = mio::abm::HouseholdMember(); // A child is 50/50% 0-4 or 5-14. + child.set_age_weight(mio::abm::AgeGroup::Age0to4, 1); + child.set_age_weight(mio::abm::AgeGroup::Age5to14, 1); + + auto parent = mio::abm::HouseholdMember(); // A parent is 50/50% 15-34 or 35-59. + parent.set_age_weight(mio::abm::AgeGroup::Age15to34, 1); + parent.set_age_weight(mio::abm::AgeGroup::Age35to59, 1); + + auto two_person_household_group1 = mio::abm::HouseholdGroup(); + auto two_person_household_group2 = mio::abm::HouseholdGroup(); + auto two_person_family = mio::abm::Household(); + two_person_family.add_members(child, 1); + two_person_family.add_members(parent, 1); + auto two_person_adults = mio::abm::Household(); + two_person_adults.add_members(parent, 2); + two_person_household_group1.add_households(two_person_family, 2); + two_person_household_group1.add_households(two_person_adults, 1); + two_person_household_group2.add_households(two_person_family, 1); + two_person_household_group2.add_households(two_person_adults, 3); + + auto three_person_household_group1 = mio::abm::HouseholdGroup(); + auto three_person_household_group2 = mio::abm::HouseholdGroup(); + auto three_person_family = mio::abm::Household(); + three_person_family.add_members(child, 1); + three_person_family.add_members(parent, 2); + three_person_household_group1.add_households(three_person_family, 2); + three_person_household_group2.add_households(three_person_family, 1); + + //add households to world 1 + add_household_group_to_world(world1, two_person_household_group1); + add_household_group_to_world(world1, three_person_household_group1); + //add households to world 2 + add_household_group_to_world(world2, two_person_household_group2); + add_household_group_to_world(world2, three_person_household_group2); + + auto t0 = mio::abm::TimePoint(0); + + mio::Graph, mio::MigrationEdge> g; + g.add_node(1, t0, std::move(world1)); + g.add_node(2, t0, std::move(world2)); + + // The results are saved in a table with 9 rows. + // The first row is t = time, the others correspond to the number of people with a certain infection state at this time: + // S = Susceptible, E = Exposed, C = Carrier, I = Infected, I_s = Infected_Severe, + // I_c = Infected_Critical, R_C = Recovered_Carrier, R_I = Recovered_Infected, D = Dead + // auto f_abm = fopen("abm_minimal.txt", "w"); + // fprintf(f_abm, "# t S E C I I_s I_c R_C R_I D\n"); + // for (auto i = 0; i < sim.get_result().get_num_time_points(); ++i) { + // fprintf(f_abm, "%f ", sim.get_result().get_time(i)); + // auto v = sim.get_result().get_value(i); + // for (auto j = 0; j < v.size(); ++j) { + // fprintf(f_abm, "%f", v[j]); + // if (j < v.size() - 1) { + // fprintf(f_abm, " "); + // } + // } + // if (i < sim.get_result().get_num_time_points() - 1) { + // fprintf(f_abm, "\n"); + // } + // } + // fclose(f_abm); +} diff --git a/cpp/models/abm/world.h b/cpp/models/abm/world.h index f50b41cf0d..e9c61554d4 100644 --- a/cpp/models/abm/world.h +++ b/cpp/models/abm/world.h @@ -196,8 +196,11 @@ class World */ void migration(TimePoint t, TimeSpan dt); +private: std::vector> m_persons; std::vector> m_locations; + +protected: TestingStrategy m_testing_strategy; GlobalInfectionParameters m_infection_parameters; MigrationParameters m_migration_parameters; diff --git a/cpp/models/graph_abm/CMakeLists.txt b/cpp/models/graph_abm/CMakeLists.txt new file mode 100644 index 0000000000..c874d66fa1 --- /dev/null +++ b/cpp/models/graph_abm/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(graph_abm + graph_world.cpp + graph_world.h +) +target_link_libraries(graph_abm PUBLIC memilio) +target_include_directories(graph_abm PUBLIC + $ + $ +) +target_compile_options(graph_abm PRIVATE ${MEMILIO_CXX_FLAGS_ENABLE_WARNING_ERRORS}) diff --git a/cpp/models/graph_abm/graph_world.cpp b/cpp/models/graph_abm/graph_world.cpp new file mode 100644 index 0000000000..9f9f95d9e8 --- /dev/null +++ b/cpp/models/graph_abm/graph_world.cpp @@ -0,0 +1,30 @@ +/* +* Copyright (C) 2020-2021 German Aerospace Center (DLR-SC) +* & Helmholtz Centre for Infection Research (HZI) +* +* Authors: Julia Bicker, Daniel Abele, Martin J. Kuehn +* +* 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/world.h" +#include "graph_abm/graph_world.h" + +namespace mio +{ +namespace graph_abm +{ + +} // namespace graph_abm +} // namespace mio diff --git a/cpp/models/graph_abm/graph_world.h b/cpp/models/graph_abm/graph_world.h new file mode 100644 index 0000000000..b8b63a4220 --- /dev/null +++ b/cpp/models/graph_abm/graph_world.h @@ -0,0 +1,52 @@ +/* +* Copyright (C) 2020-2021 German Aerospace Center (DLR-SC) +* & Helmholtz Centre for Infection Research (HZI) +* +* Authors: Julia Bicker, Daniel Abele, Martin J. Kuehn +* +* 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 EPI_GRAPH_ABM_WORLD_H +#define EPI_GRAPH_ABM_WORLD_H + +#include "abm/world.h" + +#include +#include + +namespace mio +{ +namespace graph_abm +{ + +class GraphWorld : public mio::abm::World +{ + //use abm::World constructors + using mio::abm::World::World; + using Base = mio::abm::World; + + //public: +private: + std::vector> m_persons_internal; + std::vector> m_persons_external; + std::vector> m_locations_internal; + std::vector> m_locations_external; + std::vector> m_external_location_mapping; +}; + +} // namespace graph_abm +} // namespace mio + +#endif From b41c36fa490ede5a1b7cda331dbf1fe7492abe85 Mon Sep 17 00:00:00 2001 From: jubicker Date: Mon, 22 May 2023 09:07:00 +0200 Subject: [PATCH 02/38] templatize add_households --- cpp/examples/graph_abm.cpp | 3 ++ cpp/models/abm/household.cpp | 54 ++++++++++++++++-------------- cpp/models/graph_abm/graph_world.h | 21 ++++++++++-- 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index 527d75f751..66f664139a 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -72,6 +72,9 @@ int main() add_household_group_to_world(world2, two_person_household_group2); add_household_group_to_world(world2, three_person_household_group2); + //add internal locations for both worlds + //auto event = + auto t0 = mio::abm::TimePoint(0); mio::Graph, mio::MigrationEdge> g; diff --git a/cpp/models/abm/household.cpp b/cpp/models/abm/household.cpp index 440d4e7c63..c2e4ef73bf 100755 --- a/cpp/models/abm/household.cpp +++ b/cpp/models/abm/household.cpp @@ -54,38 +54,40 @@ void HouseholdGroup::add_households(Household household, int number_of_household m_number_of_households += number_of_households; } -void add_household_to_world(World& world, const Household& household) +template +void add_household_to_world(worldType& world, const Household& household) { - auto home = world.add_location(LocationType::Home); - auto members = household.get_members(); - world.get_individualized_location(home).set_capacity(household.get_total_number_of_members(), - household.get_total_number_of_members() * - household.get_space_per_member()); + // auto home = world.add_location(LocationType::Home); + // auto members = household.get_members(); + // world.get_individualized_location(home).set_capacity(household.get_total_number_of_members(), + // household.get_total_number_of_members() * + // household.get_space_per_member()); - for (auto& memberTouple : members) { - int count; - HouseholdMember member; - std::tie(member, count) = memberTouple; - for (int j = 0; j < count; j++) { - auto age_group = pick_age_group_from_age_distribution(member.get_age_weights()); - auto& person = world.add_person(home, age_group); - person.set_assigned_location(home); - } - } + // for (auto& memberTouple : members) { + // int count; + // HouseholdMember member; + // std::tie(member, count) = memberTouple; + // for (int j = 0; j < count; j++) { + // auto age_group = pick_age_group_from_age_distribution(member.get_age_weights()); + // auto& person = world.add_person(home, age_group); + // person.set_assigned_location(home); + // } + // } } -void add_household_group_to_world(World& world, const HouseholdGroup& household_group) +template +void add_household_group_to_world(worldType& world, const HouseholdGroup& household_group) { - auto households = household_group.get_households(); + // auto households = household_group.get_households(); - for (auto& householdTuple : households) { - int count; - Household household; - std::tie(household, count) = householdTuple; - for (int j = 0; j < count; j++) { - add_household_to_world(world, household); - } - } + // for (auto& householdTuple : households) { + // int count; + // Household household; + // std::tie(household, count) = householdTuple; + // for (int j = 0; j < count; j++) { + // add_household_to_world(world, household); + // } + // } } } // namespace abm diff --git a/cpp/models/graph_abm/graph_world.h b/cpp/models/graph_abm/graph_world.h index b8b63a4220..6154542eb5 100644 --- a/cpp/models/graph_abm/graph_world.h +++ b/cpp/models/graph_abm/graph_world.h @@ -22,6 +22,7 @@ #define EPI_GRAPH_ABM_WORLD_H #include "abm/world.h" +#include "abm/location_type.h" #include #include @@ -37,11 +38,27 @@ class GraphWorld : public mio::abm::World using mio::abm::World::World; using Base = mio::abm::World; - //public: +public: + mio::abm::LocationId add_external_location(mio::abm::LocationType type, uint32_t num_cells) + { + mio::abm::LocationId id = {static_cast(m_locations_external.size()), type}; + m_locations_external.emplace_back(std::make_unique(id, num_cells)); + return id; + } + mio::abm::Person& add_person(const mio::abm::LocationId id, mio::abm::AgeGroup age) + { + uint32_t person_id = static_cast(m_persons_internal.size()); + m_persons_internal.push_back( + std::make_shared(get_individualized_location(id), age, person_id)); + auto& person = *m_persons_internal.back(); + get_individualized_location(id).add_person(person); + return person; + } + private: std::vector> m_persons_internal; std::vector> m_persons_external; - std::vector> m_locations_internal; + //std::vector> m_locations_internal; std::vector> m_locations_external; std::vector> m_external_location_mapping; }; From 289739a0d05b434549f7935566e0c2e09f96de07 Mon Sep 17 00:00:00 2001 From: jubicker Date: Tue, 23 May 2023 10:12:12 +0200 Subject: [PATCH 03/38] templatize graph simulation --- cpp/examples/graph_abm.cpp | 149 +++++++++++++++++- cpp/memilio/compartments/parameter_studies.h | 9 +- cpp/memilio/mobility/graph_simulation.h | 62 +++++--- .../metapopulation_mobility_instant.h | 12 +- cpp/models/abm/household.cpp | 80 ++++------ cpp/models/abm/household.h | 51 +++++- cpp/models/abm/world.h | 2 +- cpp/models/graph_abm/graph_world.h | 29 +++- cpp/tests/test_graph_simulation.cpp | 12 +- cpp/tests/test_mobility.cpp | 6 +- 10 files changed, 311 insertions(+), 101 deletions(-) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index 66f664139a..60df7cb811 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -21,7 +21,7 @@ #include "graph_abm/graph_world.h" #include "abm/household.h" #include "memilio/mobility/graph.h" -#include "memilio/mobility/meta_mobility_instant.h" +#include "memilio/mobility/metapopulation_mobility_instant.h" #include int main() @@ -73,13 +73,152 @@ int main() add_household_group_to_world(world2, three_person_household_group2); //add internal locations for both worlds - //auto event = + //world1 + std::vector events_w1; + std::vector works_w1; + //add two social events + auto event1_w1 = world1.add_location(mio::abm::LocationType::SocialEvent); + world1.get_individualized_location(event1_w1).get_infection_parameters().set(5); + auto event2_w1 = world1.add_location(mio::abm::LocationType::SocialEvent); + world1.get_individualized_location(event2_w1).get_infection_parameters().set(10); + events_w1.push_back(event1_w1); + events_w1.push_back(event2_w1); + // Add hospital and ICU with 5 maximum contacs. + auto hospital = world1.add_location(mio::abm::LocationType::Hospital); + world1.get_individualized_location(hospital).get_infection_parameters().set(5); + auto icu = world1.add_location(mio::abm::LocationType::ICU); + world1.get_individualized_location(icu).get_infection_parameters().set(5); + // Add one supermarket, maximum constacts are assumed to be 20. + auto shop_w1 = world1.add_location(mio::abm::LocationType::BasicsShop); + world1.get_individualized_location(shop_w1).get_infection_parameters().set(20); + // At every school, the maximum contacts are 20. + auto school = world1.add_location(mio::abm::LocationType::School); + world1.get_individualized_location(school).get_infection_parameters().set(20); + // At every workplace, maximum contacts are 10. + auto work1_w1 = world1.add_location(mio::abm::LocationType::Work); + world1.get_individualized_location(work1_w1).get_infection_parameters().set(10); + auto work2_w1 = world1.add_location(mio::abm::LocationType::Work); + world1.get_individualized_location(work2_w1).get_infection_parameters().set(10); + works_w1.push_back(work1_w1); + works_w1.push_back(work2_w1); - auto t0 = mio::abm::TimePoint(0); + //world2 + std::vector events_w2; + std::vector works_w2; + //add one social event + auto event_w2 = world2.add_location(mio::abm::LocationType::SocialEvent); + world2.get_individualized_location(event_w2).get_infection_parameters().set(5); + events_w2.push_back(event_w2); + // Add one supermarket, maximum constacts are assumed to be 20. + auto shop_w2 = world2.add_location(mio::abm::LocationType::BasicsShop); + world2.get_individualized_location(shop_w2).get_infection_parameters().set(20); + // At every workplace, maximum contacts are 10. + auto work_w2 = world2.add_location(mio::abm::LocationType::Work); + world2.get_individualized_location(work_w2).get_infection_parameters().set(10); + works_w2.push_back(work_w2); + + //add external locations + //world 1 + auto external_work_w1 = world1.add_external_location(mio::abm::LocationType::Work); + world1.insert_external_location_to_map(1, external_work_w1, work_w2); + works_w1.push_back(external_work_w1); + + //world 2 + //TODO: MaximumContacts for external locations setzen + auto external_event_w2 = world2.add_external_location(mio::abm::LocationType::SocialEvent); + world2.insert_external_location_to_map(0, external_event_w2, event2_w1); + events_w2.push_back(external_event_w2); + auto external_hospital_w2 = world2.add_external_location(mio::abm::LocationType::Hospital); + world2.insert_external_location_to_map(0, external_hospital_w2, hospital); + auto external_icu_w2 = world2.add_external_location(mio::abm::LocationType::ICU); + world2.insert_external_location_to_map(0, external_icu_w2, icu); + auto external_school_w2 = world2.add_external_location(mio::abm::LocationType::School); + world2.insert_external_location_to_map(0, external_school_w2, school); + auto external_work_w2 = world2.add_external_location(mio::abm::LocationType::Work); + world2.insert_external_location_to_map(0, external_work_w2, work2_w1); + works_w2.push_back(external_work_w2); + + auto start_date = mio::abm::TimePoint(0); + + //assign infection states + //world 1 + auto persons_w1 = world1.get_persons(); + for (auto& person : persons_w1) { + 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(mio::abm::VirusVariant::Wildtype, person.get_age(), + world1.get_global_infection_parameters(), start_date, + infection_state)); + } + //world 2 + auto persons_w2 = world2.get_persons(); + for (auto& person : persons_w2) { + 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(mio::abm::VirusVariant::Wildtype, person.get_age(), + world2.get_global_infection_parameters(), start_date, + infection_state)); + } + + //assign locations + //word 1 + for (auto& person : persons_w1) { + //choose one of the events with same probability and assign to person + auto event = + events_w1[mio::DiscreteDistribution::get_instance()(std::vector(events_w1.size(), 1.0))]; + person.set_assigned_location(event); + //assign shop + person.set_assigned_location(shop_w1); + //assign hospital and ICU + person.set_assigned_location(hospital); + person.set_assigned_location(icu); + //assign work and school dependent on person's age + if (person.get_age() == mio::abm::AgeGroup::Age5to14) { + person.set_assigned_location(school); + } + if (person.get_age() == mio::abm::AgeGroup::Age15to34 || person.get_age() == mio::abm::AgeGroup::Age35to59) { + auto work = + works_w1[mio::DiscreteDistribution::get_instance()(std::vector(works_w1.size(), 1.0))]; + person.set_assigned_location(work); + } + } + //world 2 + for (auto& person : persons_w2) { + //choose one of the events with same probability and assign to person + auto event = + events_w2[mio::DiscreteDistribution::get_instance()(std::vector(events_w2.size(), 1.0))]; + person.set_assigned_location(event); + //assign shop + person.set_assigned_location(shop_w2); + //assign hospital and ICU + person.set_assigned_location(hospital); + person.set_assigned_location(icu); + //assign work and school dependent on person's age + if (person.get_age() == mio::abm::AgeGroup::Age5to14) { + person.set_assigned_location(school); + } + if (person.get_age() == mio::abm::AgeGroup::Age15to34 || person.get_age() == mio::abm::AgeGroup::Age35to59) { + auto work = + works_w2[mio::DiscreteDistribution::get_instance()(std::vector(works_w2.size(), 1.0))]; + person.set_assigned_location(work); + } + } + + auto t0 = mio::abm::TimePoint(0); + auto dt = mio::abm::hours(12); + auto tmax = mio::abm::TimePoint(0) + mio::abm::days(30); mio::Graph, mio::MigrationEdge> g; - g.add_node(1, t0, std::move(world1)); - g.add_node(2, t0, std::move(world2)); + g.add_node(0, t0, std::move(world1)); + g.add_node(1, t0, std::move(world2)); + g.add_edge(0, 1, 1); + g.add_edge(1, 0, 1); + + //auto sim = mio::make_migration_sim(t0, dt, std::move(g)); + + //sim.advance(tmax); // The results are saved in a table with 9 rows. // The first row is t = time, the others correspond to the number of people with a certain infection state at this time: diff --git a/cpp/memilio/compartments/parameter_studies.h b/cpp/memilio/compartments/parameter_studies.h index 80fd8daed2..15f7920c18 100644 --- a/cpp/memilio/compartments/parameter_studies.h +++ b/cpp/memilio/compartments/parameter_studies.h @@ -141,7 +141,8 @@ class ParameterStudy #endif auto run_distribution = distribute_runs(m_num_runs, num_procs); - auto start_run_idx = std::accumulate(run_distribution.begin(), run_distribution.begin() + size_t(rank), size_t(0)); + auto start_run_idx = + std::accumulate(run_distribution.begin(), run_distribution.begin() + size_t(rank), size_t(0)); auto end_run_idx = start_run_idx + run_distribution[size_t(rank)]; std::vector> ensemble_result; @@ -154,7 +155,7 @@ class ParameterStudy //- the RNG has been freshly seeded/initialized before this call //- the seeds are identical on all MPI processes //- the block size of the RNG is sufficiently big to cover one run - // (when in doubt, use a larger block size; fast-forwarding the RNG is cheap and the period length + // (when in doubt, use a larger block size; fast-forwarding the RNG is cheap and the period length // of the mt19937 RNG is huge) mio::thread_local_rng().forward_to_block(run_idx); @@ -296,7 +297,7 @@ class ParameterStudy private: //sample parameters and create simulation template - mio::GraphSimulation create_sampled_simulation(SampleGraphFunction sample_graph) + mio::GraphSimulation create_sampled_simulation(SampleGraphFunction sample_graph) { SimulationGraph sim_graph; @@ -316,7 +317,7 @@ class ParameterStudy //evenly distribute runs //lower processes do one more run if runs are not evenly distributable auto num_runs_local = num_runs / num_procs; //integer division! - auto remainder = num_runs % num_procs; + auto remainder = num_runs % num_procs; std::vector run_distribution(num_procs); std::fill(run_distribution.begin(), run_distribution.begin() + remainder, num_runs_local + 1); diff --git a/cpp/memilio/mobility/graph_simulation.h b/cpp/memilio/mobility/graph_simulation.h index b15bf7f08d..162db9452b 100644 --- a/cpp/memilio/mobility/graph_simulation.h +++ b/cpp/memilio/mobility/graph_simulation.h @@ -22,6 +22,7 @@ #include "memilio/mobility/graph.h" #include "memilio/utils/random_number_generator.h" +#include "models/abm/time.h" namespace mio { @@ -29,16 +30,21 @@ namespace mio /** * @brief abstract simulation on a graph with alternating node and edge actions */ -template > +template < + class Graph, class Timepoint, class Timespan, + class edge_f = std::function, + std::enable_if_t<((std::is_same::value || std::is_same::value) && + (std::is_same::value || std::is_same::value)), + bool> = true> class GraphSimulationBase { public: - using node_function = std::function; + using node_function = std::function; using edge_function = edge_f; - GraphSimulationBase(double t0, double dt, const Graph& g, const node_function& node_func, + GraphSimulationBase(Timepoint t0, Timespan dt, const Graph& g, const node_function& node_func, const edge_function&& edge_func) : m_t(t0) , m_dt(dt) @@ -48,7 +54,7 @@ class GraphSimulationBase { } - GraphSimulationBase(double t0, double dt, Graph&& g, const node_function& node_func, + GraphSimulationBase(Timepoint t0, Timespan dt, Graph&& g, const node_function& node_func, const edge_function&& edge_func) : m_t(t0) , m_dt(dt) @@ -58,7 +64,7 @@ class GraphSimulationBase { } - void advance(double t_max = 1.0) + void advance(Timepoint t_max = 1.0) { auto dt = m_dt; while (m_t < t_max) { @@ -79,7 +85,7 @@ class GraphSimulationBase } } - double get_t() const + Timepoint get_t() const { return m_t; } @@ -100,28 +106,32 @@ class GraphSimulationBase } protected: - double m_t; - double m_dt; + Timepoint m_t; + Timespan m_dt; Graph m_graph; node_function m_node_func; edge_function m_edge_func; }; -template -class GraphSimulation : public GraphSimulationBase +template < + class Graph, class Timepoint, class Timespan, + std::enable_if_t<((std::is_same::value || std::is_same::value) && + (std::is_same::value || std::is_same::value)), + bool> = true> +class GraphSimulation : public GraphSimulationBase { - using GraphSimulationBase::GraphSimulationBase; + using GraphSimulationBase::GraphSimulationBase; }; template class GraphSimulationStochastic - : public GraphSimulationBase> { - using Base = - GraphSimulationBase>; + using Base = GraphSimulationBase>; using node_function = typename Base::node_function; using edge_function = typename Base::edge_function; @@ -181,8 +191,8 @@ class GraphSimulationStochastic //perform transition Base::m_edge_func(event_edge.property, flat_index, - Base::m_graph.nodes()[event_edge.start_node_idx].property, - Base::m_graph.nodes()[event_edge.end_node_idx].property); + Base::m_graph.nodes()[event_edge.start_node_idx].property, + Base::m_graph.nodes()[event_edge.end_node_idx].property); //calculate new cumulative rate cumulative_rate = get_cumulative_transition_rate(); @@ -241,15 +251,19 @@ class GraphSimulationStochastic std::vector m_rates; }; -template -auto make_graph_sim(double t0, double dt, Graph&& g, NodeF&& node_func, EdgeF&& edge_func) +template < + class Graph, class NodeF, class EdgeF, class Timepoint, class Timespan, + std::enable_if_t<((std::is_same::value || std::is_same::value) && + (std::is_same::value || std::is_same::value)), + bool> = true> +auto make_graph_sim(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, EdgeF&& edge_func) { - return GraphSimulation>(t0, dt, std::forward(g), std::forward(node_func), - std::forward(edge_func)); + return GraphSimulation, Timepoint, Timespan>( + t0, dt, std::forward(g), std::forward(node_func), std::forward(edge_func)); } -template -auto make_graph_sim_stochastic(double t0, double dt, Graph&& g, NodeF&& node_func, EdgeF&& edge_func) +template +auto make_graph_sim_stochastic(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, EdgeF&& edge_func) { return GraphSimulationStochastic>( t0, dt, std::forward(g), std::forward(node_func), std::forward(edge_func)); diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index a46eafdf7b..716a2dd5a1 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -519,16 +519,16 @@ void apply_migration(double t, double dt, MigrationEdge& migrationEdge, Simulati * @param graph set up for migration simulation * @{ */ -template -GraphSimulation, MigrationEdge>> -make_migration_sim(double t0, double dt, const Graph, MigrationEdge>& graph) +template +GraphSimulation, MigrationEdge>, Timepoint, Timespan> +make_migration_sim(Timepoint t0, Timespan dt, const Graph, MigrationEdge>& graph) { return make_graph_sim(t0, dt, graph, &evolve_model, &apply_migration); } -template -GraphSimulation, MigrationEdge>> -make_migration_sim(double t0, double dt, Graph, MigrationEdge>&& graph) +template +GraphSimulation, MigrationEdge>, Timepoint, Timespan> +make_migration_sim(Timepoint t0, Timespan dt, Graph, MigrationEdge>&& graph) { return make_graph_sim(t0, dt, std::move(graph), &evolve_model, &apply_migration); } diff --git a/cpp/models/abm/household.cpp b/cpp/models/abm/household.cpp index c2e4ef73bf..0530298b24 100755 --- a/cpp/models/abm/household.cpp +++ b/cpp/models/abm/household.cpp @@ -20,6 +20,7 @@ #include "abm/household.h" #include "memilio/math/eigen.h" +#include "graph_abm/graph_world.h" #include namespace mio @@ -27,21 +28,6 @@ namespace mio namespace abm { -namespace -{ -/** - * @brief Picks an age from a CustomIndexArray with a weight for each AgeGroup according to a discrete distribution. - * @param[in] age_groups A CustomIndexArray with the weights. - * @return The picked AgeGroup. - */ -AgeGroup pick_age_group_from_age_distribution(const CustomIndexArray& age_groups) -{ - auto age_group_weights = age_groups.array().cast().eval(); - size_t age_group = DiscreteDistribution::get_instance()(age_group_weights); - return (AgeGroup)age_group; -} -} // namespace - void Household::add_members(HouseholdMember household_member, int number_of_members) { m_household_member_list.push_back(std::make_tuple(household_member, number_of_members)); @@ -54,41 +40,41 @@ void HouseholdGroup::add_households(Household household, int number_of_household m_number_of_households += number_of_households; } -template -void add_household_to_world(worldType& world, const Household& household) -{ - // auto home = world.add_location(LocationType::Home); - // auto members = household.get_members(); - // world.get_individualized_location(home).set_capacity(household.get_total_number_of_members(), - // household.get_total_number_of_members() * - // household.get_space_per_member()); +// void add_household_to_world(mio::graph_abm::GraphWorld& world, const Household& household) +// { +// auto home = world.add_location(LocationType::Home); +// auto members = household.get_members(); +// world.get_individualized_location(home).set_capacity(household.get_total_number_of_members(), +// household.get_total_number_of_members() * +// household.get_space_per_member()); - // for (auto& memberTouple : members) { - // int count; - // HouseholdMember member; - // std::tie(member, count) = memberTouple; - // for (int j = 0; j < count; j++) { - // auto age_group = pick_age_group_from_age_distribution(member.get_age_weights()); - // auto& person = world.add_person(home, age_group); - // person.set_assigned_location(home); - // } - // } -} +// for (auto& memberTouple : members) { +// int count; +// HouseholdMember member; +// std::tie(member, count) = memberTouple; +// for (int j = 0; j < count; j++) { +// auto age_group = pick_age_group_from_age_distribution(member.get_age_weights()); +// auto& person = world.add_person(home, age_group); +// person.set_assigned_location(home); +// } +// } +// } -template -void add_household_group_to_world(worldType& world, const HouseholdGroup& household_group) -{ - // auto households = household_group.get_households(); +// void add_household_group_to_graph_world(int world, const abm::HouseholdGroup& household_group) +// { +// mio::unused(world); +// mio::unused(household_group); +// // auto households = household_group.get_households(); - // for (auto& householdTuple : households) { - // int count; - // Household household; - // std::tie(household, count) = householdTuple; - // for (int j = 0; j < count; j++) { - // add_household_to_world(world, household); - // } - // } -} +// // for (auto& householdTuple : households) { +// // int count; +// // abm::Household household; +// // std::tie(household, count) = householdTuple; +// // for (int j = 0; j < count; j++) { +// // add_household_to_world(world, household); +// // } +// // } +// } } // namespace abm } // namespace mio diff --git a/cpp/models/abm/household.h b/cpp/models/abm/household.h index 3b081160ad..c3e484dcdd 100644 --- a/cpp/models/abm/household.h +++ b/cpp/models/abm/household.h @@ -33,6 +33,21 @@ namespace mio namespace abm { +namespace +{ +/** + * @brief Picks an age from a CustomIndexArray with a weight for each AgeGroup according to a discrete distribution. + * @param[in] age_groups A CustomIndexArray with the weights. + * @return The picked AgeGroup. + */ +AgeGroup pick_age_group_from_age_distribution(const CustomIndexArray& age_groups) +{ + auto age_group_weights = age_groups.array().cast().eval(); + size_t age_group = DiscreteDistribution::get_instance()(age_group_weights); + return (AgeGroup)age_group; +} +} // namespace + /** * @file * A HouseholdMember has a vector with weighted age distribution from which the age can be calculated. @@ -199,14 +214,46 @@ class HouseholdGroup * @param[in,out] world The World to which the Household has to be added. * @param[in] household The Household to add to World. */ -void add_household_to_world(World& world, const Household& household); +template +inline void add_household_to_world(WorldType& world, const Household& household) +{ + auto home = world.add_location(LocationType::Home); + auto members = household.get_members(); + world.get_individualized_location(home).set_capacity(household.get_total_number_of_members(), + household.get_total_number_of_members() * + household.get_space_per_member()); + + for (auto& memberTouple : members) { + int count; + HouseholdMember member; + std::tie(member, count) = memberTouple; + for (int j = 0; j < count; j++) { + auto age_group = pick_age_group_from_age_distribution(member.get_age_weights()); + auto& person = world.add_person(home, age_group); + person.set_assigned_location(home); + } + } +} /** * @brief Adds Household%s from a HouseholdGroup to the World. * @param[in,out] world The World to which the group has to be added. * @param[in] household_group The HouseholdGroup to add. */ -void add_household_group_to_world(World& world, const HouseholdGroup& household_group); +template +inline void add_household_group_to_world(WorldType& world, const HouseholdGroup& household_group) +{ + auto households = household_group.get_households(); + + for (auto& householdTuple : households) { + int count; + Household household; + std::tie(household, count) = householdTuple; + for (int j = 0; j < count; j++) { + add_household_to_world(world, household); + } + } +} } // namespace abm } // namespace mio diff --git a/cpp/models/abm/world.h b/cpp/models/abm/world.h index e9c61554d4..63f951cb2a 100644 --- a/cpp/models/abm/world.h +++ b/cpp/models/abm/world.h @@ -198,9 +198,9 @@ class World private: std::vector> m_persons; - std::vector> m_locations; protected: + std::vector> m_locations; TestingStrategy m_testing_strategy; GlobalInfectionParameters m_infection_parameters; MigrationParameters m_migration_parameters; diff --git a/cpp/models/graph_abm/graph_world.h b/cpp/models/graph_abm/graph_world.h index 6154542eb5..84e0ae9540 100644 --- a/cpp/models/graph_abm/graph_world.h +++ b/cpp/models/graph_abm/graph_world.h @@ -23,6 +23,7 @@ #include "abm/world.h" #include "abm/location_type.h" +#include #include #include @@ -39,9 +40,12 @@ class GraphWorld : public mio::abm::World using Base = mio::abm::World; public: - mio::abm::LocationId add_external_location(mio::abm::LocationType type, uint32_t num_cells) + using ConstPersonIterator = + PointerDereferencingIterator>::const_iterator>; + + mio::abm::LocationId add_external_location(mio::abm::LocationType type, uint32_t num_cells = 1) { - mio::abm::LocationId id = {static_cast(m_locations_external.size()), type}; + mio::abm::LocationId id = {static_cast(m_locations_external.size() + Base::m_locations.size()), type}; m_locations_external.emplace_back(std::make_unique(id, num_cells)); return id; } @@ -54,13 +58,32 @@ class GraphWorld : public mio::abm::World get_individualized_location(id).add_person(person); return person; } + void insert_external_location_to_map(int node_to, mio::abm::LocationId id_this_world, + mio::abm::LocationId id_other_world) + { + if (m_external_location_mapping.find(node_to) != m_external_location_mapping.end()) { + auto& mapping = m_external_location_mapping[node_to]; + mapping.push_back(std::make_pair(id_this_world, id_other_world)); + } + else { + std::vector> v = { + std::make_pair(id_this_world, id_other_world)}; + m_external_location_mapping.insert( + std::pair>>(node_to, v)); + } + } + auto get_persons() const -> Range> + { + return std::make_pair(ConstPersonIterator(m_persons_internal.begin()), + ConstPersonIterator(m_persons_internal.end())); + } private: std::vector> m_persons_internal; std::vector> m_persons_external; //std::vector> m_locations_internal; std::vector> m_locations_external; - std::vector> m_external_location_mapping; + std::map>> m_external_location_mapping; }; } // namespace graph_abm diff --git a/cpp/tests/test_graph_simulation.cpp b/cpp/tests/test_graph_simulation.cpp index a487ee6579..5c85119928 100644 --- a/cpp/tests/test_graph_simulation.cpp +++ b/cpp/tests/test_graph_simulation.cpp @@ -63,9 +63,9 @@ TEST(TestGraphSimulation, simulate) MockEdgeFunc edge_func; MockNodeFunc node_func; - const auto t0 = 1; - const auto tmax = 3.0; - const auto dt = 1.0; + const double t0 = 1; + const double tmax = 3.0; + const double dt = 1.0; testing::ExpectationSet node_func_calls; @@ -169,8 +169,8 @@ TEST(TestGraphSimulation, persistentChangesDuringSimulation) ++n2; }; - auto t0 = 0; - auto dt = 1; + double t0 = 0.; + double dt = 1.; auto sim = mio::make_graph_sim(t0, dt, g, node_func, edge_func); int num_steps = 2; sim.advance(t0 + num_steps * dt); @@ -230,7 +230,7 @@ struct MoveOnly { MoveOnly& operator=(MoveOnly&&) = default; }; using MoveOnlyGraph = mio::Graph; -using MoveOnlyGraphSim = mio::GraphSimulation; +using MoveOnlyGraphSim = mio::GraphSimulation; } // namespace diff --git a/cpp/tests/test_mobility.cpp b/cpp/tests/test_mobility.cpp index 5c78841325..56b04e8fad 100644 --- a/cpp/tests/test_mobility.cpp +++ b/cpp/tests/test_mobility.cpp @@ -34,9 +34,9 @@ TEST(TestMobility, compareNoMigrationWithSingleIntegration) { - auto t0 = 0; - auto tmax = 5; - auto dt = 0.5; + double t0 = 0.; + double tmax = 5.; + double dt = 0.5; mio::oseir::Model model1; model1.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = 0.9; From 45e4f182ab7d139a349c1a5fea643d660edb36eb Mon Sep 17 00:00:00 2001 From: jubicker Date: Tue, 23 May 2023 10:29:15 +0200 Subject: [PATCH 04/38] resolve multiple declaration --- cpp/examples/graph_abm.cpp | 10 +++++----- cpp/models/abm/household.h | 27 ++++++++++++--------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index 60df7cb811..2008d89b5c 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -210,11 +210,11 @@ int main() auto dt = mio::abm::hours(12); auto tmax = mio::abm::TimePoint(0) + mio::abm::days(30); - mio::Graph, mio::MigrationEdge> g; - g.add_node(0, t0, std::move(world1)); - g.add_node(1, t0, std::move(world2)); - g.add_edge(0, 1, 1); - g.add_edge(1, 0, 1); + // mio::Graph, mio::MigrationEdge> g; + // g.add_node(0, t0, std::move(world1)); + // g.add_node(1, t0, std::move(world2)); + // g.add_edge(0, 1, 1); + // g.add_edge(1, 0, 1); //auto sim = mio::make_migration_sim(t0, dt, std::move(g)); diff --git a/cpp/models/abm/household.h b/cpp/models/abm/household.h index c3e484dcdd..11f8e873da 100644 --- a/cpp/models/abm/household.h +++ b/cpp/models/abm/household.h @@ -33,21 +33,6 @@ namespace mio namespace abm { -namespace -{ -/** - * @brief Picks an age from a CustomIndexArray with a weight for each AgeGroup according to a discrete distribution. - * @param[in] age_groups A CustomIndexArray with the weights. - * @return The picked AgeGroup. - */ -AgeGroup pick_age_group_from_age_distribution(const CustomIndexArray& age_groups) -{ - auto age_group_weights = age_groups.array().cast().eval(); - size_t age_group = DiscreteDistribution::get_instance()(age_group_weights); - return (AgeGroup)age_group; -} -} // namespace - /** * @file * A HouseholdMember has a vector with weighted age distribution from which the age can be calculated. @@ -208,6 +193,18 @@ class HouseholdGroup times it is in the group.*/ }; +/** + * @brief Picks an age from a CustomIndexArray with a weight for each AgeGroup according to a discrete distribution. + * @param[in] age_groups A CustomIndexArray with the weights. + * @return The picked AgeGroup. + */ +inline AgeGroup pick_age_group_from_age_distribution(const CustomIndexArray& age_groups) +{ + auto age_group_weights = age_groups.array().cast().eval(); + size_t age_group = DiscreteDistribution::get_instance()(age_group_weights); + return (AgeGroup)age_group; +} + /** * @brief Adds a specific Household to the World. * Adds Person%s to the World according to the age distribution of the HouseholdMember%s of the Household. From 071cd0c5bc77a4e289a15426876e07c52c81be2a Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 24 May 2023 10:11:53 +0200 Subject: [PATCH 05/38] test --- cpp/examples/graph_abm.cpp | 12 +++++----- cpp/memilio/mobility/graph_simulation.h | 22 +++++++++++++++++++ .../metapopulation_mobility_instant.h | 12 ++++++++++ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index 2008d89b5c..38e1656477 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -210,13 +210,13 @@ int main() auto dt = mio::abm::hours(12); auto tmax = mio::abm::TimePoint(0) + mio::abm::days(30); - // mio::Graph, mio::MigrationEdge> g; - // g.add_node(0, t0, std::move(world1)); - // g.add_node(1, t0, std::move(world2)); - // g.add_edge(0, 1, 1); - // g.add_edge(1, 0, 1); + mio::Graph, mio::MigrationEdge> g; + g.add_node(0, t0, std::move(world1)); + g.add_node(1, t0, std::move(world2)); + g.add_edge(0, 1, Eigen::VectorXd::Constant((size_t)1, 1.)); + g.add_edge(1, 0, Eigen::VectorXd::Constant((size_t)1, 1.)); - //auto sim = mio::make_migration_sim(t0, dt, std::move(g)); + auto sim = mio::make_migration_sim_test(t0, dt, std::move(g)); //sim.advance(tmax); diff --git a/cpp/memilio/mobility/graph_simulation.h b/cpp/memilio/mobility/graph_simulation.h index 162db9452b..4bd272ce84 100644 --- a/cpp/memilio/mobility/graph_simulation.h +++ b/cpp/memilio/mobility/graph_simulation.h @@ -54,6 +54,13 @@ class GraphSimulationBase { } + GraphSimulationBase(Timepoint t0, Timespan dt, const Graph& g) + : m_t(t0) + , m_dt(dt) + , m_graph(g) + { + } + GraphSimulationBase(Timepoint t0, Timespan dt, Graph&& g, const node_function& node_func, const edge_function&& edge_func) : m_t(t0) @@ -262,6 +269,21 @@ auto make_graph_sim(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, Edg t0, dt, std::forward(g), std::forward(node_func), std::forward(edge_func)); } +template < + class Graph, class NodeF, class EdgeF, class Timepoint, class Timespan, + std::enable_if_t<((std::is_same::value || std::is_same::value) && + (std::is_same::value || std::is_same::value)), + bool> = true> +auto make_graph_sim_test(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, EdgeF&& edge_func) +{ + mio::unused(t0); + mio::unused(dt); + mio::unused(node_func); + mio::unused(edge_func); + return 0; + //return GraphSimulation, Timepoint, Timespan>(t0, dt, std::forward(g)); +} + template auto make_graph_sim_stochastic(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, EdgeF&& edge_func) { diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index 716a2dd5a1..e99fcf6220 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -31,6 +31,7 @@ #include "memilio/epidemiology/dynamic_npis.h" #include "memilio/compartments/simulation.h" #include "memilio/utils/date.h" +#include "models/abm/time.h" #include "boost/filesystem.hpp" @@ -533,6 +534,17 @@ make_migration_sim(Timepoint t0, Timespan dt, Graph, Migrati return make_graph_sim(t0, dt, std::move(graph), &evolve_model, &apply_migration); } +template +//GraphSimulation, MigrationEdge>, Timepoint, Timespan> +int make_migration_sim_test(Timepoint t0, Timespan dt, Graph, MigrationEdge>&& graph) +{ + mio::unused(t0); + mio::unused(dt); + mio::unused(graph); + return 0; + //return make_graph_sim_test(0.0, 0.0, std::move(graph), &evolve_model, &apply_migration); +} + /** @} */ } // namespace mio From 90a453c688a12a38493cc61c0e0d0407639bf365 Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 24 May 2023 16:12:32 +0200 Subject: [PATCH 06/38] add time templates and interaction fct --- cpp/examples/graph_abm.cpp | 4 +-- cpp/memilio/mobility/graph_simulation.h | 18 +++++------ .../metapopulation_mobility_instant.h | 21 ++++++------- .../metapopulation_mobility_stochastic.h | 4 +-- cpp/models/abm/person.cpp | 9 +++++- cpp/models/abm/person.h | 29 +++++++++++++++-- cpp/models/graph_abm/graph_world.cpp | 7 +++++ cpp/models/graph_abm/graph_world.h | 31 ++++++++++++++++--- 8 files changed, 89 insertions(+), 34 deletions(-) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index 38e1656477..e9e92c8e4a 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -33,8 +33,8 @@ int main() infection_params.get() = 4.; // Create the worlds with infection parameters. - auto world1 = mio::graph_abm::GraphWorld(infection_params); - auto world2 = mio::graph_abm::GraphWorld(infection_params); + auto world1 = mio::graph_abm::GraphWorld(0, infection_params); + auto world2 = mio::graph_abm::GraphWorld(1, infection_params); //add households for world 1 auto child = mio::abm::HouseholdMember(); // A child is 50/50% 0-4 or 5-14. diff --git a/cpp/memilio/mobility/graph_simulation.h b/cpp/memilio/mobility/graph_simulation.h index 4bd272ce84..d90d954858 100644 --- a/cpp/memilio/mobility/graph_simulation.h +++ b/cpp/memilio/mobility/graph_simulation.h @@ -54,10 +54,11 @@ class GraphSimulationBase { } - GraphSimulationBase(Timepoint t0, Timespan dt, const Graph& g) + GraphSimulationBase(Timepoint t0, Timespan dt, Graph&& g, const node_function& node_func) : m_t(t0) , m_dt(dt) - , m_graph(g) + , m_graph(std::move(g)) + , m_node_func(node_func) { } @@ -270,18 +271,13 @@ auto make_graph_sim(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, Edg } template < - class Graph, class NodeF, class EdgeF, class Timepoint, class Timespan, + class Graph, class NodeF, class Timepoint, class Timespan, std::enable_if_t<((std::is_same::value || std::is_same::value) && (std::is_same::value || std::is_same::value)), - bool> = true> -auto make_graph_sim_test(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, EdgeF&& edge_func) + bool> = true> //, class EdgeF +auto make_graph_sim_test(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func) //, EdgeF&& edge_func { - mio::unused(t0); - mio::unused(dt); - mio::unused(node_func); - mio::unused(edge_func); - return 0; - //return GraphSimulation, Timepoint, Timespan>(t0, dt, std::forward(g)); + return GraphSimulation, Timepoint, Timespan>(t0, dt, std::forward(g), std::forward(node_func)); } template diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index e99fcf6220..11bc03cb04 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -93,7 +93,8 @@ class SimulationNode return m_t0; } - void evolve(double t, double dt) + template + void evolve(Timepoint t, Timespan dt) { m_simulation.advance(t + dt); m_last_state = m_simulation.get_result().get_last_value(); @@ -493,8 +494,8 @@ void MigrationEdge::apply_migration(double t, double dt, SimulationNode& no * edge functor for migration simulation. * @see SimulationNode::evolve */ -template -void evolve_model(double t, double dt, SimulationNode& node) +template +void evolve_model(Timepoint t, Timespan dt, SimulationNode& node) { node.evolve(t, dt); } @@ -524,25 +525,21 @@ template GraphSimulation, MigrationEdge>, Timepoint, Timespan> make_migration_sim(Timepoint t0, Timespan dt, const Graph, MigrationEdge>& graph) { - return make_graph_sim(t0, dt, graph, &evolve_model, &apply_migration); + return make_graph_sim(t0, dt, graph, &evolve_model, &apply_migration); } template GraphSimulation, MigrationEdge>, Timepoint, Timespan> make_migration_sim(Timepoint t0, Timespan dt, Graph, MigrationEdge>&& graph) { - return make_graph_sim(t0, dt, std::move(graph), &evolve_model, &apply_migration); + return make_graph_sim(t0, dt, std::move(graph), &evolve_model, &apply_migration); } template -//GraphSimulation, MigrationEdge>, Timepoint, Timespan> -int make_migration_sim_test(Timepoint t0, Timespan dt, Graph, MigrationEdge>&& graph) +GraphSimulation, MigrationEdge>, Timepoint, Timespan> +make_migration_sim_test(Timepoint t0, Timespan dt, Graph, MigrationEdge>&& graph) { - mio::unused(t0); - mio::unused(dt); - mio::unused(graph); - return 0; - //return make_graph_sim_test(0.0, 0.0, std::move(graph), &evolve_model, &apply_migration); + return make_graph_sim_test(t0, dt, std::move(graph), &evolve_model); // &apply_migration) } /** @} */ diff --git a/cpp/memilio/mobility/metapopulation_mobility_stochastic.h b/cpp/memilio/mobility/metapopulation_mobility_stochastic.h index b6a5bc2bbf..eb87ea77b1 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_stochastic.h +++ b/cpp/memilio/mobility/metapopulation_mobility_stochastic.h @@ -227,14 +227,14 @@ template GraphSimulationStochastic, MigrationEdgeStochastic>> make_migration_sim(double t0, double dt, const Graph, MigrationEdgeStochastic>& graph) { - return make_graph_sim_stochastic(t0, dt, graph, &evolve_model, &apply_migration); + return make_graph_sim_stochastic(t0, dt, graph, &evolve_model, &apply_migration); } template GraphSimulationStochastic, MigrationEdgeStochastic>> make_migration_sim(double t0, double dt, Graph, MigrationEdgeStochastic>&& graph) { - return make_graph_sim_stochastic(t0, dt, std::move(graph), &evolve_model, + return make_graph_sim_stochastic(t0, dt, std::move(graph), &evolve_model, &apply_migration); } diff --git a/cpp/models/abm/person.cpp b/cpp/models/abm/person.cpp index 9f99365db6..4c29f125f0 100755 --- a/cpp/models/abm/person.cpp +++ b/cpp/models/abm/person.cpp @@ -31,7 +31,7 @@ namespace mio namespace abm { -Person::Person(Location& location, AgeGroup age, uint32_t person_id) +Person::Person(Location& location, AgeGroup age, uint32_t person_id, uint32_t world_id) : m_location(&location) , m_assigned_locations((uint32_t)LocationType::Count, INVALID_LOCATION_INDEX) , m_quarantine(false) @@ -42,6 +42,8 @@ Person::Person(Location& location, AgeGroup age, uint32_t person_id) , m_wears_mask(false) , m_mask_compliance((uint32_t)LocationType::Count, 0.) , m_person_id(person_id) + , m_world_id(world_id) + , m_is_active_in_world(true) , m_cells{0} { m_random_workgroup = UniformDistribution::get_instance()(); @@ -204,6 +206,11 @@ uint32_t Person::get_person_id() return m_person_id; } +uint32_t Person::get_world_id() +{ + return m_world_id; +} + std::vector& Person::get_cells() { return m_cells; diff --git a/cpp/models/abm/person.h b/cpp/models/abm/person.h index b44b3e6b21..582299b723 100755 --- a/cpp/models/abm/person.h +++ b/cpp/models/abm/person.h @@ -53,15 +53,16 @@ class Person * @param location Initial location of the person. * @param age The age group of the person. * @param person_id Index of the person. + * @param world_id Home world id of the person. */ - explicit Person(Location& location, AgeGroup age, uint32_t person_id = INVALID_PERSON_ID); + explicit Person(Location& location, AgeGroup age, uint32_t person_id = INVALID_PERSON_ID, uint32_t world_id = 0); /** * compare two persons */ bool operator==(const Person& other) const { - return (m_person_id == other.m_person_id); + return (m_person_id == other.m_person_id && m_world_id == other.m_world_id); } /** @@ -256,6 +257,11 @@ class Person */ uint32_t get_person_id(); + /** + * @brief Get the world id of the person. + */ + uint32_t get_world_id(); + /** * @brief Get index of cells of the person. */ @@ -328,6 +334,23 @@ class Person return m_wears_mask; } + /** + * @brief Set whether a person is currently active in its home world. + * @param[in] active_in_world If true, the person is considered in migration and interaction in its home world. + */ + void set_is_active_in_world(bool active_in_world) + { + m_is_active_in_world = active_in_world; + } + + /** + * @return True if the person is currently active in its home world. + */ + bool get_is_active_in_world() const + { + return m_is_active_in_world; + } + /** * @brief Get the multiplicative factor on how likely an infection is due to the immune system. * @param[in] v VirusVariant to take into consideration. @@ -367,6 +390,8 @@ class Person bool m_wears_mask = false; std::vector m_mask_compliance; uint32_t m_person_id; + uint32_t m_world_id; + bool m_is_active_in_world; std::vector m_cells; }; diff --git a/cpp/models/graph_abm/graph_world.cpp b/cpp/models/graph_abm/graph_world.cpp index 9f9f95d9e8..dbc2980e58 100644 --- a/cpp/models/graph_abm/graph_world.cpp +++ b/cpp/models/graph_abm/graph_world.cpp @@ -26,5 +26,12 @@ namespace mio namespace graph_abm { +void World::interaction(TimePoint t, TimeSpan dt) +{ + for (auto&& person : m_persons) { + person->interact(t, dt, m_infection_parameters); + } +} + } // namespace graph_abm } // namespace mio diff --git a/cpp/models/graph_abm/graph_world.h b/cpp/models/graph_abm/graph_world.h index 84e0ae9540..e1e47512f4 100644 --- a/cpp/models/graph_abm/graph_world.h +++ b/cpp/models/graph_abm/graph_world.h @@ -35,29 +35,44 @@ namespace graph_abm class GraphWorld : public mio::abm::World { - //use abm::World constructors - using mio::abm::World::World; using Base = mio::abm::World; public: using ConstPersonIterator = PointerDereferencingIterator>::const_iterator>; + GraphWorld(uint32_t world_id, const mio::abm::GlobalInfectionParameters& params = {}) + : Base(params) + , m_world_id(world_id) + { + } + mio::abm::LocationId add_external_location(mio::abm::LocationType type, uint32_t num_cells = 1) { mio::abm::LocationId id = {static_cast(m_locations_external.size() + Base::m_locations.size()), type}; m_locations_external.emplace_back(std::make_unique(id, num_cells)); return id; } + // mio::abm::Person& add_person(const mio::abm::LocationId id, mio::abm::AgeGroup age) + // { + // uint32_t person_id = static_cast(m_persons_internal.size()); + // m_persons_internal.push_back( + // std::make_pair(std::make_shared(get_individualized_location(id), age, person_id), true)); + // auto& person = *((m_persons_internal.back()).first); + // get_individualized_location(id).add_person(person); + // return person; + // } + mio::abm::Person& add_person(const mio::abm::LocationId id, mio::abm::AgeGroup age) { uint32_t person_id = static_cast(m_persons_internal.size()); m_persons_internal.push_back( - std::make_shared(get_individualized_location(id), age, person_id)); + std::make_shared(get_individualized_location(id), age, person_id, m_world_id)); auto& person = *m_persons_internal.back(); get_individualized_location(id).add_person(person); return person; } + void insert_external_location_to_map(int node_to, mio::abm::LocationId id_this_world, mio::abm::LocationId id_other_world) { @@ -79,10 +94,18 @@ class GraphWorld : public mio::abm::World } private: + /** + * @brief Person%s interact at their Location and may become infected. + * @param[in] t The current TimePoint. + * @param[in] dt The length of the time step of the Simulation. + */ + void interaction(mio::abm::TimePoint t, mio::abm::TimeSpan dt); + + uint32_t m_world_id; std::vector> m_persons_internal; std::vector> m_persons_external; - //std::vector> m_locations_internal; std::vector> m_locations_external; + //map has for every graph node id specified by the integer a mapping mapping the id from m_locations_external to the corresponding id in the other node std::map>> m_external_location_mapping; }; From dab9070447eb070e2bfd3905e98bf4d6e671fb88 Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 24 May 2023 16:12:46 +0200 Subject: [PATCH 07/38] interaction function --- cpp/models/graph_abm/graph_world.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cpp/models/graph_abm/graph_world.cpp b/cpp/models/graph_abm/graph_world.cpp index dbc2980e58..cbf4a49517 100644 --- a/cpp/models/graph_abm/graph_world.cpp +++ b/cpp/models/graph_abm/graph_world.cpp @@ -26,9 +26,12 @@ namespace mio namespace graph_abm { -void World::interaction(TimePoint t, TimeSpan dt) +void GraphWorld::interaction(mio::abm::TimePoint t, mio::abm::TimeSpan dt) { - for (auto&& person : m_persons) { + for (auto&& person : m_persons_internal) { + person->interact(t, dt, m_infection_parameters); + } + for (auto&& person : m_persons_external) { person->interact(t, dt, m_infection_parameters); } } From 54ebd4cb44edaf45c9828f9757535abd2ae95122 Mon Sep 17 00:00:00 2001 From: jubicker Date: Fri, 26 May 2023 10:13:01 +0200 Subject: [PATCH 08/38] evolve function --- cpp/examples/graph_abm.cpp | 22 ++--- cpp/models/abm/location.h | 12 ++- cpp/models/abm/location_type.h | 8 +- cpp/models/abm/person.cpp | 25 ++++-- cpp/models/abm/person.h | 37 ++++----- cpp/models/abm/world.cpp | 9 +- cpp/models/abm/world.h | 19 +++-- cpp/models/graph_abm/graph_world.cpp | 105 +++++++++++++++++++++-- cpp/models/graph_abm/graph_world.h | 119 ++++++++++++++------------- cpp/tests/test_abm_location.cpp | 12 +-- cpp/tests/test_abm_person.cpp | 10 +-- 11 files changed, 241 insertions(+), 137 deletions(-) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index e9e92c8e4a..173bd1b5c8 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -33,8 +33,8 @@ int main() infection_params.get() = 4.; // Create the worlds with infection parameters. - auto world1 = mio::graph_abm::GraphWorld(0, infection_params); - auto world2 = mio::graph_abm::GraphWorld(1, infection_params); + auto world1 = mio::graph_abm::GraphWorld(infection_params, 0); + auto world2 = mio::graph_abm::GraphWorld(infection_params, 1); //add households for world 1 auto child = mio::abm::HouseholdMember(); // A child is 50/50% 0-4 or 5-14. @@ -119,24 +119,12 @@ int main() //add external locations //world 1 - auto external_work_w1 = world1.add_external_location(mio::abm::LocationType::Work); - world1.insert_external_location_to_map(1, external_work_w1, work_w2); - works_w1.push_back(external_work_w1); + works_w1.push_back(work_w2); //world 2 //TODO: MaximumContacts for external locations setzen - auto external_event_w2 = world2.add_external_location(mio::abm::LocationType::SocialEvent); - world2.insert_external_location_to_map(0, external_event_w2, event2_w1); - events_w2.push_back(external_event_w2); - auto external_hospital_w2 = world2.add_external_location(mio::abm::LocationType::Hospital); - world2.insert_external_location_to_map(0, external_hospital_w2, hospital); - auto external_icu_w2 = world2.add_external_location(mio::abm::LocationType::ICU); - world2.insert_external_location_to_map(0, external_icu_w2, icu); - auto external_school_w2 = world2.add_external_location(mio::abm::LocationType::School); - world2.insert_external_location_to_map(0, external_school_w2, school); - auto external_work_w2 = world2.add_external_location(mio::abm::LocationType::Work); - world2.insert_external_location_to_map(0, external_work_w2, work2_w1); - works_w2.push_back(external_work_w2); + events_w2.push_back(event2_w1); + works_w2.push_back(work2_w1); auto start_date = mio::abm::TimePoint(0); diff --git a/cpp/models/abm/location.h b/cpp/models/abm/location.h index e5ba3a2ea0..95c80bb7fe 100644 --- a/cpp/models/abm/location.h +++ b/cpp/models/abm/location.h @@ -102,8 +102,8 @@ class Location */ Location(LocationId loc_id, uint32_t num_cells = 1); - Location(LocationType loc_type, uint32_t loc_index, uint32_t num_cells = 1) - : Location(LocationId{loc_index, loc_type}, num_cells) + Location(LocationType loc_type, uint32_t loc_index, uint32_t loc_world_id = 0, uint32_t num_cells = 1) + : Location(LocationId{loc_index, loc_type, loc_world_id}, num_cells) { } @@ -136,6 +136,14 @@ class Location return m_id.index; } + /** + * @brief Get the world id of this Location. + */ + unsigned get_world_id() const + { + return m_id.world_id; + } + /** * @brief Compute the transmission factor for contact transmission of the virus in a Cell. * @param[in] cell_index Cell index of the Cell. diff --git a/cpp/models/abm/location_type.h b/cpp/models/abm/location_type.h index 05684f4f17..d8af8c7e8c 100644 --- a/cpp/models/abm/location_type.h +++ b/cpp/models/abm/location_type.h @@ -47,7 +47,8 @@ enum class LocationType : std::uint32_t Count //last! }; -static constexpr uint32_t INVALID_LOCATION_INDEX = std::numeric_limits::max(); +static constexpr uint32_t INVALID_LOCATION_INDEX = std::numeric_limits::max(); +static constexpr uint32_t INVALID_LOCATION_WORLD_ID = std::numeric_limits::max(); /** * LocationId identifies a Location uniquely. It consists of the LocationType of the Location and an Index. @@ -56,15 +57,16 @@ static constexpr uint32_t INVALID_LOCATION_INDEX = std::numeric_limits struct LocationId { uint32_t index; LocationType type; + uint32_t world_id; bool operator==(const LocationId& rhs) const { - return (index == rhs.index && type == rhs.type); + return (index == rhs.index && type == rhs.type && world_id == rhs.world_id); } bool operator!=(const LocationId& rhs) const { - return !(index == rhs.index && type == rhs.type); + return !(index == rhs.index && type == rhs.type && world_id == rhs.world_id); } }; diff --git a/cpp/models/abm/person.cpp b/cpp/models/abm/person.cpp index 4c29f125f0..30f217c2bb 100755 --- a/cpp/models/abm/person.cpp +++ b/cpp/models/abm/person.cpp @@ -33,7 +33,8 @@ namespace abm Person::Person(Location& location, AgeGroup age, uint32_t person_id, uint32_t world_id) : m_location(&location) - , m_assigned_locations((uint32_t)LocationType::Count, INVALID_LOCATION_INDEX) + , m_assigned_locations((uint32_t)LocationType::Count, + std::make_pair(INVALID_LOCATION_INDEX, INVALID_LOCATION_WORLD_ID)) , m_quarantine(false) , m_age(age) , m_time_at_location(0) @@ -43,7 +44,6 @@ Person::Person(Location& location, AgeGroup age, uint32_t person_id, uint32_t wo , m_mask_compliance((uint32_t)LocationType::Count, 0.) , m_person_id(person_id) , m_world_id(world_id) - , m_is_active_in_world(true) , m_cells{0} { m_random_workgroup = UniformDistribution::get_instance()(); @@ -60,14 +60,16 @@ void Person::interact(TimePoint t, TimeSpan dt, const GlobalInfectionParameters& m_time_at_location += dt; } -void Person::migrate_to(Location& loc_new, const std::vector& cells) +void Person::migrate_to(Location& loc_new, const std::vector& cells, bool add_to_new_location) { if (*m_location != loc_new) { m_location->remove_person(*this); m_location = &loc_new; m_cells = cells; - loc_new.add_person(*this, cells); - m_time_at_location = TimeSpan(0); + if (add_to_new_location) { + loc_new.add_person(*this, cells); + m_time_at_location = TimeSpan(0); + } } } @@ -116,17 +118,24 @@ void Person::set_assigned_location(Location& location) * For now only use it like this: auto home_id = world.add_location(mio::abm::LocationType::Home); * person.set_assigned_location(home); */ - m_assigned_locations[(uint32_t)location.get_type()] = location.get_index(); + m_assigned_locations[(uint32_t)location.get_type()].first = location.get_index(); + m_assigned_locations[(uint32_t)location.get_type()].second = location.get_world_id(); } void Person::set_assigned_location(LocationId id) { - m_assigned_locations[(uint32_t)id.type] = id.index; + m_assigned_locations[(uint32_t)id.type].first = id.index; + m_assigned_locations[(uint32_t)id.type].second = id.world_id; } uint32_t Person::get_assigned_location_index(LocationType type) const { - return m_assigned_locations[(uint32_t)type]; + return m_assigned_locations[(uint32_t)type].first; +} + +uint32_t Person::get_assigned_location_world_id(LocationType type) const +{ + return m_assigned_locations[(uint32_t)type].second; } bool Person::goes_to_work(TimePoint t, const MigrationParameters& params) const diff --git a/cpp/models/abm/person.h b/cpp/models/abm/person.h index 582299b723..d0da8d7253 100755 --- a/cpp/models/abm/person.h +++ b/cpp/models/abm/person.h @@ -79,7 +79,7 @@ class Person * @param[in] loc_new The new location of the person. * @param[in] cells_new The new cells of the person. * */ - void migrate_to(Location& loc_new, const std::vector& cells_new = {0}); + void migrate_to(Location& loc_new, const std::vector& cells_new = {0}, bool add_to_new_location = true); /** * @brief Get the latest Infection of the Person. @@ -177,16 +177,23 @@ class Person void set_assigned_location(LocationId id); /** - * @brief Returns the index of a assigned location of the person. - * Assume that a person has at most one assigned location of a certrain location type. + * @brief Returns the index of an assigned location of the person. + * Assume that a person has at most one assigned location of a certain location type. * @param[in] type Location type of the assigned location. */ uint32_t get_assigned_location_index(LocationType type) const; + /** + * @brief Returns the world id of an assigned location of the person. + * Assume that a person has at most one assigned location of a certain location type. + * @param[in] type Location type of the assigned location. + */ + uint32_t get_assigned_location_world_id(LocationType type) const; + /** * @brief Returns the assigned locations of the person. */ - const std::vector& get_assigned_locations() const + const std::vector>& get_assigned_locations() const { return m_assigned_locations; } @@ -334,23 +341,6 @@ class Person return m_wears_mask; } - /** - * @brief Set whether a person is currently active in its home world. - * @param[in] active_in_world If true, the person is considered in migration and interaction in its home world. - */ - void set_is_active_in_world(bool active_in_world) - { - m_is_active_in_world = active_in_world; - } - - /** - * @return True if the person is currently active in its home world. - */ - bool get_is_active_in_world() const - { - return m_is_active_in_world; - } - /** * @brief Get the multiplicative factor on how likely an infection is due to the immune system. * @param[in] v VirusVariant to take into consideration. @@ -375,7 +365,8 @@ class Person private: observer_ptr m_location; - std::vector m_assigned_locations; + //the first integer specifies the location index and the second the locations world id (does not need to match the person's world id) + std::vector> m_assigned_locations; std::vector m_vaccinations; std::vector m_infections; bool m_quarantine = false; @@ -391,7 +382,7 @@ class Person std::vector m_mask_compliance; uint32_t m_person_id; uint32_t m_world_id; - bool m_is_active_in_world; + //bool m_is_active_in_world; std::vector m_cells; }; diff --git a/cpp/models/abm/world.cpp b/cpp/models/abm/world.cpp index 7c27386fc1..12e05d5e11 100755 --- a/cpp/models/abm/world.cpp +++ b/cpp/models/abm/world.cpp @@ -35,7 +35,7 @@ namespace abm LocationId World::add_location(LocationType type, uint32_t num_cells) { - LocationId id = {static_cast(m_locations.size()), type}; + LocationId id = {static_cast(m_locations.size()), type, m_world_id}; m_locations.emplace_back(std::make_unique(id, num_cells)); return id; } @@ -43,7 +43,7 @@ LocationId World::add_location(LocationType type, uint32_t num_cells) Person& World::add_person(const LocationId id, AgeGroup age) { uint32_t person_id = static_cast(m_persons.size()); - m_persons.push_back(std::make_unique(get_individualized_location(id), age, person_id)); + m_persons.push_back(std::make_unique(get_individualized_location(id), age, person_id, m_world_id)); auto& person = *m_persons.back(); get_individualized_location(id).add_person(person); return person; @@ -158,9 +158,10 @@ Location& World::get_individualized_location(LocationId id) Location& World::find_location(LocationType type, const Person& person) { - auto index = person.get_assigned_location_index(type); + auto index = person.get_assigned_location_index(type); + auto world_id = person.get_assigned_location_world_id(type); assert(index != INVALID_LOCATION_INDEX && "unexpected error."); - return get_individualized_location({index, type}); + return get_individualized_location({index, type, world_id}); } size_t World::get_subpopulation_combined(TimePoint t, InfectionState s, LocationType type) const diff --git a/cpp/models/abm/world.h b/cpp/models/abm/world.h index 63f951cb2a..3359fddda8 100644 --- a/cpp/models/abm/world.h +++ b/cpp/models/abm/world.h @@ -54,8 +54,9 @@ class World * @brief Create a World. * @param[in] params Parameters of the Infection that are the same everywhere in the World. */ - World(const GlobalInfectionParameters& params = {}) - : m_infection_parameters(params) + World(const GlobalInfectionParameters& params = {}, uint32_t world_id = 0) + : m_world_id(world_id) + , m_infection_parameters(params) , m_migration_parameters() , m_trip_list() { @@ -184,22 +185,22 @@ class World private: /** - * @brief Person%s interact at their Location and may become infected. + * @brief Person%s move in the World according to rules. * @param[in] t The current TimePoint. * @param[in] dt The length of the time step of the Simulation. */ - void interaction(TimePoint t, TimeSpan dt); + void migration(TimePoint t, TimeSpan dt); + +protected: /** - * @brief Person%s move in the World according to rules. + * @brief Person%s interact at their Location and may become infected. * @param[in] t The current TimePoint. * @param[in] dt The length of the time step of the Simulation. */ - void migration(TimePoint t, TimeSpan dt); + void interaction(TimePoint t, TimeSpan dt); -private: std::vector> m_persons; - -protected: + uint32_t m_world_id; std::vector> m_locations; TestingStrategy m_testing_strategy; GlobalInfectionParameters m_infection_parameters; diff --git a/cpp/models/graph_abm/graph_world.cpp b/cpp/models/graph_abm/graph_world.cpp index cbf4a49517..7f3455b955 100644 --- a/cpp/models/graph_abm/graph_world.cpp +++ b/cpp/models/graph_abm/graph_world.cpp @@ -26,14 +26,109 @@ namespace mio namespace graph_abm { -void GraphWorld::interaction(mio::abm::TimePoint t, mio::abm::TimeSpan dt) +// void GraphWorld::interaction(mio::abm::TimePoint t, mio::abm::TimeSpan dt) +// { +// for (auto&& person : m_persons_internal) { +// //only persons that are active in the world should interact +// if (person->get_is_active_in_world()) { +// person->interact(t, dt, m_infection_parameters); +// } +// } +// for (auto&& person : m_persons_external) { +// person->interact(t, dt, m_infection_parameters); +// } +// } + +// void GraphWorld::begin_step(mio::abm::TimePoint t, mio::abm::TimeSpan dt) +// { +// for (auto& location : Base::m_locations) { +// location->cache_exposure_rates(t, dt); +// } +// for (auto& location : m_locations_external) { +// location->cache_exposure_rates(t, dt); +// } +// } + +mio::abm::Location& GraphWorld::find_location(mio::abm::LocationType type, const mio::abm::Person& person) { - for (auto&& person : m_persons_internal) { - person->interact(t, dt, m_infection_parameters); + auto index = person.get_assigned_location_index(type); + auto world_id = person.get_assigned_location_world_id(type); + if (world_id == Base::m_world_id) { + return Base::get_individualized_location({index, type, world_id}); + } + else { //location is in other world + mio::abm::Location loc = mio::abm::Location(type, index, world_id); + auto iter = std::find_if(m_locations_external.begin(), m_locations_external.end(), + [loc](const std::unique_ptr& loc_ext) { + return ((loc.get_type() == loc_ext->get_type()) && + (loc.get_index() == loc_ext->get_index()) && + (loc.get_world_id() == loc_ext->get_world_id())); + }); + if (iter != m_locations_external.end()) { + return *(*iter); + } + else { + m_locations_external.emplace_back(std::make_unique(loc)); + return *m_locations_external.back(); + } } - for (auto&& person : m_persons_external) { - person->interact(t, dt, m_infection_parameters); +} + +void GraphWorld::migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt) +{ + + for (auto person_iter = Base::m_persons.begin(); person_iter != Base::m_persons.end(); + ++person_iter) { //auto& person : Base::m_persons + for (auto rule : Base::m_migration_rules) { + //check if transition rule can be applied + auto target_type = rule.first(*(*person_iter), t, dt, m_migration_parameters); + auto& target_location = find_location(target_type, *(*person_iter)); + auto current_location = (*person_iter)->get_location(); + if (m_testing_strategy.run_strategy(*(*person_iter), target_location, t)) { + if (target_location != current_location && + target_location.get_number_persons() < target_location.get_capacity().persons) { + bool wears_mask = (*person_iter)->apply_mask_intervention(target_location); + if (wears_mask) { + if (target_location.get_world_id() != Base::m_world_id) { + //person changes world + m_persons_to_migrate.push_back(std::move(*person_iter)); + Base::m_persons.erase(person_iter); + (*person_iter)->migrate_to(target_location, {0}, false); + } + (*person_iter)->migrate_to(target_location); + } + break; + } + } + } } + // check if a person makes a trip + //TODO + // size_t num_trips = m_trip_list.num_trips(); + // if (num_trips != 0) { + // while (m_trip_list.get_current_index() < num_trips && m_trip_list.get_next_trip_time() < t + dt) { + // auto& trip = m_trip_list.get_next_trip(); + // auto& person = m_persons[trip.person_id]; + // auto current_location = person->get_location(); + // if (!person->is_in_quarantine() && current_location == get_individualized_location(trip.migration_origin)) { + // auto& target_location = get_individualized_location(trip.migration_destination); + // if (m_testing_strategy.run_strategy(*person, target_location, t)) { + // person->apply_mask_intervention(target_location); + // person->migrate_to(target_location); + // } + // } + // m_trip_list.increase_index(); + // } + // } +} + +void GraphWorld::evolve(mio::abm::TimePoint t, mio::abm::TimeSpan dt) +{ + Base::begin_step(t, dt); + Base::interaction(t, dt); + Base::get_testing_strategy().update_activity_status(t); + migration(t, dt); + Base::end_step(t, dt); } } // namespace graph_abm diff --git a/cpp/models/graph_abm/graph_world.h b/cpp/models/graph_abm/graph_world.h index e1e47512f4..df769114e5 100644 --- a/cpp/models/graph_abm/graph_world.h +++ b/cpp/models/graph_abm/graph_world.h @@ -35,78 +35,87 @@ namespace graph_abm class GraphWorld : public mio::abm::World { + //use abm::World constructors + using mio::abm::World::World; using Base = mio::abm::World; public: - using ConstPersonIterator = - PointerDereferencingIterator>::const_iterator>; - - GraphWorld(uint32_t world_id, const mio::abm::GlobalInfectionParameters& params = {}) - : Base(params) - , m_world_id(world_id) - { - } + // mio::abm::LocationId add_external_location(mio::abm::LocationType type, uint32_t num_cells = 1) + // { + // mio::abm::LocationId id = {static_cast(m_locations_external.size() + Base::m_locations.size()), type}; + // m_locations_external.emplace_back(std::make_unique(id, num_cells)); + // return id; + // } - mio::abm::LocationId add_external_location(mio::abm::LocationType type, uint32_t num_cells = 1) - { - mio::abm::LocationId id = {static_cast(m_locations_external.size() + Base::m_locations.size()), type}; - m_locations_external.emplace_back(std::make_unique(id, num_cells)); - return id; - } // mio::abm::Person& add_person(const mio::abm::LocationId id, mio::abm::AgeGroup age) // { - // uint32_t person_id = static_cast(m_persons_internal.size()); - // m_persons_internal.push_back( - // std::make_pair(std::make_shared(get_individualized_location(id), age, person_id), true)); - // auto& person = *((m_persons_internal.back()).first); + // uint32_t person_id = static_cast(Base::m_persons.size()); + // Base::m_persons.push_back( + // std::make_unique(get_individualized_location(id), age, person_id, m_world_id)); + // auto& person = *m_persons_internal.back(); // get_individualized_location(id).add_person(person); // return person; // } - mio::abm::Person& add_person(const mio::abm::LocationId id, mio::abm::AgeGroup age) - { - uint32_t person_id = static_cast(m_persons_internal.size()); - m_persons_internal.push_back( - std::make_shared(get_individualized_location(id), age, person_id, m_world_id)); - auto& person = *m_persons_internal.back(); - get_individualized_location(id).add_person(person); - return person; - } + // void insert_external_location_to_map(int node_to, mio::abm::LocationId id_this_world, + // mio::abm::LocationId id_other_world) + // { + // if (m_external_location_mapping.find(node_to) != m_external_location_mapping.end()) { + // auto& mapping = m_external_location_mapping[node_to]; + // mapping.push_back(std::make_pair(id_this_world, id_other_world)); + // } + // else { + // std::vector> v = { + // std::make_pair(id_this_world, id_other_world)}; + // m_external_location_mapping.insert( + // std::pair>>(node_to, v)); + // } + // } + // auto get_persons() const -> Range> + // { + // return std::make_pair(ConstPersonIterator(m_persons_internal.begin()), + // ConstPersonIterator(m_persons_internal.end())); + // } - void insert_external_location_to_map(int node_to, mio::abm::LocationId id_this_world, - mio::abm::LocationId id_other_world) - { - if (m_external_location_mapping.find(node_to) != m_external_location_mapping.end()) { - auto& mapping = m_external_location_mapping[node_to]; - mapping.push_back(std::make_pair(id_this_world, id_other_world)); - } - else { - std::vector> v = { - std::make_pair(id_this_world, id_other_world)}; - m_external_location_mapping.insert( - std::pair>>(node_to, v)); - } - } - auto get_persons() const -> Range> - { - return std::make_pair(ConstPersonIterator(m_persons_internal.begin()), - ConstPersonIterator(m_persons_internal.end())); - } + // /** + // * Prepare the World for the next simulation step. + // * @param[in] t Current time. + // * @param[in] dt Length of the time step. + // */ + // void begin_step(mio::abm::TimePoint t, mio::abm::TimeSpan dt); -private: - /** - * @brief Person%s interact at their Location and may become infected. + /** @brief Person%s move in the World according to rules. * @param[in] t The current TimePoint. * @param[in] dt The length of the time step of the Simulation. */ - void interaction(mio::abm::TimePoint t, mio::abm::TimeSpan dt); + void migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt); + + /** + * Evolve the world one time step. + * @param[in] t Current time. + * @param[in] dt Length of the time step. + */ + void evolve(mio::abm::TimePoint t, mio::abm::TimeSpan dt); + + /** + * @brief Find an assigned Location of a Person. + * @param[in] type The #LocationType that specifies the assigned Location. + * @param[in] person The Person. + * @return Pointer to the assigned Location. If the location is in another world, the function will return the location in m_locations_external. + */ + mio::abm::Location& find_location(mio::abm::LocationType type, const mio::abm::Person& person); + +private: + // /** + // * @brief Person%s interact at their Location and may become infected. + // * @param[in] t The current TimePoint. + // * @param[in] dt The length of the time step of the Simulation. + // */ + // void interaction(mio::abm::TimePoint t, mio::abm::TimeSpan dt); - uint32_t m_world_id; - std::vector> m_persons_internal; - std::vector> m_persons_external; + //persons that will migrate to other worlds + std::vector> m_persons_to_migrate; std::vector> m_locations_external; - //map has for every graph node id specified by the integer a mapping mapping the id from m_locations_external to the corresponding id in the other node - std::map>> m_external_location_mapping; }; } // namespace graph_abm diff --git a/cpp/tests/test_abm_location.cpp b/cpp/tests/test_abm_location.cpp index ffe1c42e1f..33145aff94 100644 --- a/cpp/tests/test_abm_location.cpp +++ b/cpp/tests/test_abm_location.cpp @@ -36,7 +36,7 @@ TEST(TestLocation, init) TEST(TestLocation, initCell) { - auto location = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0, 2); + auto location = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0, 0, 2); ASSERT_EQ(location.get_cells().size(), 2); } @@ -48,8 +48,8 @@ TEST(TestLocation, getIndex) TEST(TestLocation, addRemovePerson) { - auto home = mio::abm::Location(mio::abm::LocationType::Home, 0, 1); - auto location = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0, 3); + auto home = mio::abm::Location(mio::abm::LocationType::Home, 0,0, 1); + auto location = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0,0, 3); auto person1 = make_test_person(home, mio::abm::AgeGroup::Age5to14, mio::abm::InfectionState::Infected); auto person2 = make_test_person(home, mio::abm::AgeGroup::Age15to34, mio::abm::InfectionState::Infected); @@ -97,8 +97,8 @@ TEST(TestLocation, CacheExposureRate) mio::abm::GlobalInfectionParameters params; // setup a location with some chance of exposure - auto home = mio::abm::Location(mio::abm::LocationType::Home, 0, 1); - auto location = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0, 3); + auto home = mio::abm::Location(mio::abm::LocationType::Home, 0, 0, 1); + auto location = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0,0, 3); auto infected1 = mio::abm::Person(home, age); infected1.add_new_infection(mio::abm::Infection(variant, age, params, t)); infected1.migrate_to(location, {0}); @@ -190,7 +190,7 @@ TEST(TestLocation, computeSpacePerPersonRelative) { using testing::Return; - auto home = mio::abm::Location(mio::abm::LocationType::Home, 0, 3); + auto home = mio::abm::Location(mio::abm::LocationType::Home, 0, 0, 3); home.set_capacity(4, 264, 0); // Capacity for Cell 1 home.set_capacity(2, 132, 1); // Capacity for Cell 2 home.set_capacity(0, 0, 2); // Capacity for Cell 3 diff --git a/cpp/tests/test_abm_person.cpp b/cpp/tests/test_abm_person.cpp index ef01f2d5de..1b59469a76 100644 --- a/cpp/tests/test_abm_person.cpp +++ b/cpp/tests/test_abm_person.cpp @@ -34,9 +34,9 @@ TEST(TestPerson, migrate) { auto t = mio::abm::TimePoint(0); auto home = mio::abm::Location(mio::abm::LocationType::Home, 0); - auto loc1 = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0, 1); + auto loc1 = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0, 0, 1); auto loc2 = mio::abm::Location(mio::abm::LocationType::School, 0); - auto loc3 = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0, 2); + auto loc3 = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0, 0, 2); auto person = make_test_person(home, mio::abm::AgeGroup::Age0to4, mio::abm::InfectionState::Recovered_Carrier); person.migrate_to(loc1, {0}); @@ -68,7 +68,7 @@ TEST(TestPerson, setGetAssignedLocation) person.set_assigned_location(location); ASSERT_EQ((int)person.get_assigned_location_index(mio::abm::LocationType::Work), 2); - person.set_assigned_location({4, mio::abm::LocationType::Work}); + person.set_assigned_location({4, mio::abm::LocationType::Work, 0}); ASSERT_EQ((int)person.get_assigned_location_index(mio::abm::LocationType::Work), 4); } @@ -157,8 +157,8 @@ TEST(TestPerson, get_tested) TEST(TestPerson, getCells) { - auto home = mio::abm::Location(mio::abm::LocationType::Home, 0, 1); - auto location = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0, 2); + auto home = mio::abm::Location(mio::abm::LocationType::Home, 0, 0, 1); + auto location = mio::abm::Location(mio::abm::LocationType::PublicTransport, 0, 0, 2); auto person = make_test_person(home, mio::abm::AgeGroup::Age15to34, mio::abm::InfectionState::Carrier); home.add_person(person); person.migrate_to(location, {0, 1}); From e2ba3fa3ae321d373d7f85a4af30586916fc2e46 Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 31 May 2023 14:08:25 +0200 Subject: [PATCH 09/38] add graph simulation file --- .../metapopulation_mobility_instant.h | 26 +++++++- cpp/models/abm/simulation.h | 3 +- cpp/models/graph_abm/CMakeLists.txt | 2 + cpp/models/graph_abm/graph_simulation.cpp | 37 +++++++++++ cpp/models/graph_abm/graph_simulation.h | 66 +++++++++++++++++++ cpp/models/graph_abm/graph_world.h | 2 +- 6 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 cpp/models/graph_abm/graph_simulation.cpp create mode 100644 cpp/models/graph_abm/graph_simulation.h diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index 11bc03cb04..6a9a3afa00 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -32,6 +32,8 @@ #include "memilio/compartments/simulation.h" #include "memilio/utils/date.h" #include "models/abm/time.h" +//#include "models/abm/simulation.h" +//#include "models/graph_abm/graph_simulation.h" #include "boost/filesystem.hpp" @@ -93,7 +95,7 @@ class SimulationNode return m_t0; } - template + template void evolve(Timepoint t, Timespan dt) { m_simulation.advance(t + dt); @@ -303,6 +305,25 @@ class MigrationEdge std::pair m_dynamic_npi = {-std::numeric_limits::max(), SimulationTime(0)}; }; +class MigrationEdgeABM +{ +public: + MigrationEdgeABM() + { + } + + // template ::value, bool> = true> + // void apply_migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt, SimulationNode& node_from, + // SimulationNode& node_to); +}; + +// template ::value, bool>> +// void MigrationEdgeABM::apply_migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt, SimulationNode& node_from, +// SimulationNode& node_to) +// { +// //for (auto& a : node_from.get_simulation().get_world()) +// } + /** * adjust number of migrated people when they return according to the model. * E.g. during the time in the other node, some people who left as susceptible will return exposed. @@ -539,7 +560,8 @@ template GraphSimulation, MigrationEdge>, Timepoint, Timespan> make_migration_sim_test(Timepoint t0, Timespan dt, Graph, MigrationEdge>&& graph) { - return make_graph_sim_test(t0, dt, std::move(graph), &evolve_model); // &apply_migration) + return make_graph_sim_test(t0, dt, std::move(graph), + &evolve_model); // &apply_migration) } /** @} */ diff --git a/cpp/models/abm/simulation.h b/cpp/models/abm/simulation.h index 1efd8bdb19..88e89aac9c 100644 --- a/cpp/models/abm/simulation.h +++ b/cpp/models/abm/simulation.h @@ -83,10 +83,11 @@ class Simulation } private: + World m_world; ///< The World to simulate. +protected: void initialize_locations(TimePoint t); void store_result_at(TimePoint t); - World m_world; ///< The World to simulate. TimeSeries m_result; ///< The result of the Simulation. TimePoint m_t; ///< The current TimePoint of the Simulation. TimeSpan m_dt; ///< The length of the time steps. diff --git a/cpp/models/graph_abm/CMakeLists.txt b/cpp/models/graph_abm/CMakeLists.txt index c874d66fa1..1e7e27f86a 100644 --- a/cpp/models/graph_abm/CMakeLists.txt +++ b/cpp/models/graph_abm/CMakeLists.txt @@ -1,6 +1,8 @@ add_library(graph_abm graph_world.cpp graph_world.h + graph_simulation.cpp + graph_simulation.h ) target_link_libraries(graph_abm PUBLIC memilio) target_include_directories(graph_abm PUBLIC diff --git a/cpp/models/graph_abm/graph_simulation.cpp b/cpp/models/graph_abm/graph_simulation.cpp new file mode 100644 index 0000000000..22e8e6966e --- /dev/null +++ b/cpp/models/graph_abm/graph_simulation.cpp @@ -0,0 +1,37 @@ +/* +* Copyright (C) 2020-2021 German Aerospace Center (DLR-SC) +* +* Authors: Daniel Abele, 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 "graph_abm/graph_simulation.h" + +namespace mio +{ +namespace graph_abm +{ +GraphSimulation::GraphSimulation(mio::abm::TimePoint t, GraphWorld&& graph_world) + : Base(t) + , m_graph_world(std::move(graph_world)) +{ + Base::m_dt = mio::abm::hours(1); + Base::m_result = mio::TimeSeries(Eigen::Index(mio::abm::InfectionState::Count)); + Base::initialize_locations(t); + Base::store_result_at(t); +} + +} // namespace graph_abm +} // namespace mio diff --git a/cpp/models/graph_abm/graph_simulation.h b/cpp/models/graph_abm/graph_simulation.h new file mode 100644 index 0000000000..d8a435c770 --- /dev/null +++ b/cpp/models/graph_abm/graph_simulation.h @@ -0,0 +1,66 @@ +/* +* Copyright (C) 2020-2021 German Aerospace Center (DLR-SC) +* +* Authors: Daniel Abele +* +* 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 EPI_ABM_GRAPH_SIMULATOR_H +#define EPI_ABM_GRAPH_SIMULATOR_H + +#include "models/graph_abm/graph_world.h" +#include "abm/simulation.h" +#include "memilio/utils/time_series.h" + +namespace mio +{ +namespace graph_abm +{ + +/** + * @brief Run the Simulation in discrete steps, evolve the World and report results. + */ +class GraphSimulation : public mio::abm::Simulation +{ + using Base = mio::abm::Simulation; + +public: + /** + * @brief Create a graph simulation. + * @param[in] t0 The starting time of the Simulation. + * @param[in] graph_world The GraphWorld to simulate. + */ + GraphSimulation(mio::abm::TimePoint t0, GraphWorld&& graph_world); + + /** + * @brief Get the GraphWorld that this Simulation evolves. + */ + GraphWorld& get_graph_world() + { + return m_graph_world; + } + const GraphWorld& get_graph_world() const + { + return m_graph_world; + } + +private: + GraphWorld m_graph_world; +}; + +} // namespace graph_abm +} // namespace mio + +#endif diff --git a/cpp/models/graph_abm/graph_world.h b/cpp/models/graph_abm/graph_world.h index df769114e5..85f55bccb9 100644 --- a/cpp/models/graph_abm/graph_world.h +++ b/cpp/models/graph_abm/graph_world.h @@ -97,7 +97,7 @@ class GraphWorld : public mio::abm::World */ void evolve(mio::abm::TimePoint t, mio::abm::TimeSpan dt); - /** + /** * @brief Find an assigned Location of a Person. * @param[in] type The #LocationType that specifies the assigned Location. * @param[in] person The Person. From 8b4a66790552472c691a90ad20e0ec02cf5a5ea8 Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 31 May 2023 16:00:42 +0200 Subject: [PATCH 10/38] fix includes --- cpp/examples/abm_minimal.cpp | 4 +- cpp/examples/graph_abm.cpp | 10 ++-- cpp/memilio/mobility/graph_simulation.h | 6 +-- .../metapopulation_mobility_instant.h | 49 +++++++++++------- cpp/models/abm/abm.h | 30 +++++------ cpp/models/abm/household.cpp | 2 +- cpp/models/abm/household.h | 4 +- cpp/models/abm/infection.cpp | 2 +- cpp/models/abm/infection.h | 8 +-- cpp/models/abm/location.cpp | 8 +-- cpp/models/abm/location.h | 12 ++--- cpp/models/abm/lockdown_rules.cpp | 6 +-- cpp/models/abm/lockdown_rules.h | 8 +-- cpp/models/abm/mask.cpp | 8 +-- cpp/models/abm/mask.h | 4 +- cpp/models/abm/migration_rules.cpp | 12 ++--- cpp/models/abm/migration_rules.h | 6 +-- cpp/models/abm/parameters.cpp | 2 +- cpp/models/abm/parameters.h | 10 ++-- cpp/models/abm/person.cpp | 12 ++--- cpp/models/abm/person.h | 16 +++--- cpp/models/abm/random_events.h | 2 +- cpp/models/abm/simulation.cpp | 2 +- cpp/models/abm/simulation.h | 4 +- cpp/models/abm/testing_strategy.cpp | 2 +- cpp/models/abm/testing_strategy.h | 8 +-- cpp/models/abm/time.cpp | 2 +- cpp/models/abm/trip_list.cpp | 6 +-- cpp/models/abm/trip_list.h | 8 +-- cpp/models/abm/vaccine.h | 2 +- cpp/models/abm/world.cpp | 19 ++++--- cpp/models/abm/world.h | 18 ++++--- cpp/models/graph_abm/graph_simulation.h | 2 +- cpp/models/graph_abm/graph_world.cpp | 6 ++- cpp/models/graph_abm/graph_world.h | 51 +++---------------- cpp/simulations/abm.cpp | 2 +- cpp/tests/abm_helpers.h | 2 +- cpp/tests/test_abm_household.cpp | 4 +- cpp/tests/test_abm_location.cpp | 2 +- cpp/tests/test_epi_data_io.cpp | 2 +- .../memilio/simulation/abm.cpp | 2 +- 41 files changed, 178 insertions(+), 187 deletions(-) diff --git a/cpp/examples/abm_minimal.cpp b/cpp/examples/abm_minimal.cpp index 8c0bf2ccf8..5749656b2d 100644 --- a/cpp/examples/abm_minimal.cpp +++ b/cpp/examples/abm_minimal.cpp @@ -17,8 +17,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/abm.h" -#include "abm/household.h" +#include "models/abm/abm.h" +#include "models/abm/household.h" #include int main() diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index 173bd1b5c8..b7192f56e7 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -17,9 +17,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/abm.h" +#include "models/abm/abm.h" #include "graph_abm/graph_world.h" -#include "abm/household.h" +#include "models/abm/household.h" #include "memilio/mobility/graph.h" #include "memilio/mobility/metapopulation_mobility_instant.h" #include @@ -198,11 +198,11 @@ int main() auto dt = mio::abm::hours(12); auto tmax = mio::abm::TimePoint(0) + mio::abm::days(30); - mio::Graph, mio::MigrationEdge> g; + mio::Graph, mio::MigrationEdgeABM> g; g.add_node(0, t0, std::move(world1)); g.add_node(1, t0, std::move(world2)); - g.add_edge(0, 1, Eigen::VectorXd::Constant((size_t)1, 1.)); - g.add_edge(1, 0, Eigen::VectorXd::Constant((size_t)1, 1.)); + g.add_edge(0, 1); //, Eigen::VectorXd::Constant((size_t)1, 1.) + g.add_edge(1, 0); //, Eigen::VectorXd::Constant((size_t)1, 1.) auto sim = mio::make_migration_sim_test(t0, dt, std::move(g)); diff --git a/cpp/memilio/mobility/graph_simulation.h b/cpp/memilio/mobility/graph_simulation.h index d90d954858..8f06374a81 100644 --- a/cpp/memilio/mobility/graph_simulation.h +++ b/cpp/memilio/mobility/graph_simulation.h @@ -271,13 +271,13 @@ auto make_graph_sim(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, Edg } template < - class Graph, class NodeF, class Timepoint, class Timespan, + class Graph, class NodeF, class EdgeF, class Timepoint, class Timespan, std::enable_if_t<((std::is_same::value || std::is_same::value) && (std::is_same::value || std::is_same::value)), bool> = true> //, class EdgeF -auto make_graph_sim_test(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func) //, EdgeF&& edge_func +auto make_graph_sim_test(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, EdgeF&& edge_func) { - return GraphSimulation, Timepoint, Timespan>(t0, dt, std::forward(g), std::forward(node_func)); + return GraphSimulation, Timepoint, Timespan>(t0, dt, std::forward(g), std::forward(node_func), std::forward(edge_func)); } template diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index 6a9a3afa00..b866dc1980 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -33,7 +33,7 @@ #include "memilio/utils/date.h" #include "models/abm/time.h" //#include "models/abm/simulation.h" -//#include "models/graph_abm/graph_simulation.h" +#include "models/graph_abm/graph_simulation.h" #include "boost/filesystem.hpp" @@ -312,17 +312,26 @@ class MigrationEdgeABM { } - // template ::value, bool> = true> - // void apply_migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt, SimulationNode& node_from, - // SimulationNode& node_to); + template ::value, bool> = true> + void apply_migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt, SimulationNode& node_from, + SimulationNode& node_to); }; -// template ::value, bool>> -// void MigrationEdgeABM::apply_migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt, SimulationNode& node_from, -// SimulationNode& node_to) -// { -// //for (auto& a : node_from.get_simulation().get_world()) -// } +template ::value, bool>> +void MigrationEdgeABM::apply_migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt, SimulationNode& node_from, + SimulationNode& node_to) +{ + mio::unused(t); + mio::unused(dt); + mio::unused(node_from); + mio::unused(node_to); + for (auto person_iter = node_from.get_simulation().get_graph_world().get_persons_to_migrate().begin(); + person_iter != node_from.get_simulation().get_graph_world().get_persons_to_migrate().end(); ++person_iter) { + if (((*person_iter)->get_location()).get_world_id() == + node_to.get_simulation().get_graph_world().get_world_id()) { + } + } +} /** * adjust number of migrated people when they return according to the model. @@ -525,8 +534,11 @@ void evolve_model(Timepoint t, Timespan dt, SimulationNode& node) * edge functor for migration simulation. * @see MigrationEdge::apply_migration */ -template -void apply_migration(double t, double dt, MigrationEdge& migrationEdge, SimulationNode& node_from, +template < + class Sim, class Timepoint, class Timespan, class Edge, + std::enable_if_t<((std::is_same::value) || (std::is_same::value)), + bool> = true> +void apply_migration(Timepoint t, Timespan dt, Edge& migrationEdge, SimulationNode& node_from, SimulationNode& node_to) { migrationEdge.apply_migration(t, dt, node_from, node_to); @@ -553,15 +565,16 @@ template GraphSimulation, MigrationEdge>, Timepoint, Timespan> make_migration_sim(Timepoint t0, Timespan dt, Graph, MigrationEdge>&& graph) { - return make_graph_sim(t0, dt, std::move(graph), &evolve_model, &apply_migration); + return make_graph_sim(t0, dt, std::move(graph), &evolve_model, + &apply_migration); } -template -GraphSimulation, MigrationEdge>, Timepoint, Timespan> -make_migration_sim_test(Timepoint t0, Timespan dt, Graph, MigrationEdge>&& graph) +template +GraphSimulation, Edge>, Timepoint, Timespan> +make_migration_sim_test(Timepoint t0, Timespan dt, Graph, Edge>&& graph) { - return make_graph_sim_test(t0, dt, std::move(graph), - &evolve_model); // &apply_migration) + return make_graph_sim_test(t0, dt, std::move(graph), &evolve_model, + &apply_migration); } /** @} */ diff --git a/cpp/models/abm/abm.h b/cpp/models/abm/abm.h index 6cacb2259b..8a273e06f3 100644 --- a/cpp/models/abm/abm.h +++ b/cpp/models/abm/abm.h @@ -23,21 +23,21 @@ #ifndef EPI_ABM_H #define EPI_ABM_H -#include "abm/parameters.h" -#include "abm/simulation.h" -#include "abm/world.h" -#include "abm/person.h" -#include "abm/location.h" -#include "abm/location_type.h" +#include "models/abm/parameters.h" +#include "models/abm/simulation.h" +#include "models/abm/world.h" +#include "models/abm/person.h" +#include "models/abm/location.h" +#include "models/abm/location_type.h" #include "memilio/utils/random_number_generator.h" -#include "abm/migration_rules.h" -#include "abm/testing_strategy.h" -#include "abm/infection.h" -#include "abm/infection_state.h" -#include "abm/virus_variant.h" -#include "abm/vaccine.h" -#include "abm/age.h" -#include "abm/household.h" -#include "abm/lockdown_rules.h" +#include "models/abm/migration_rules.h" +#include "models/abm/testing_strategy.h" +#include "models/abm/infection.h" +#include "models/abm/infection_state.h" +#include "models/abm/virus_variant.h" +#include "models/abm/vaccine.h" +#include "models/abm/age.h" +#include "models/abm/household.h" +#include "models/abm/lockdown_rules.h" #endif \ No newline at end of file diff --git a/cpp/models/abm/household.cpp b/cpp/models/abm/household.cpp index 0530298b24..44dcfa5ecb 100755 --- a/cpp/models/abm/household.cpp +++ b/cpp/models/abm/household.cpp @@ -18,7 +18,7 @@ * limitations under the License. */ -#include "abm/household.h" +#include "models/abm/household.h" #include "memilio/math/eigen.h" #include "graph_abm/graph_world.h" #include diff --git a/cpp/models/abm/household.h b/cpp/models/abm/household.h index 11f8e873da..e888190699 100644 --- a/cpp/models/abm/household.h +++ b/cpp/models/abm/household.h @@ -22,8 +22,8 @@ #ifndef EPI_ABM_HOUSEHOLD_H #define EPI_ABM_HOUSEHOLD_H -#include "abm/abm.h" -#include "abm/age.h" +#include "models/abm/abm.h" +#include "models/abm/age.h" #include "memilio/utils/custom_index_array.h" #include #include diff --git a/cpp/models/abm/infection.cpp b/cpp/models/abm/infection.cpp index 5b9b9b6df9..bd6788ae55 100644 --- a/cpp/models/abm/infection.cpp +++ b/cpp/models/abm/infection.cpp @@ -18,7 +18,7 @@ * limitations under the License. */ -#include "abm/infection.h" +#include "models/abm/infection.h" #include namespace mio diff --git a/cpp/models/abm/infection.h b/cpp/models/abm/infection.h index c6760e4633..7c30cd57fb 100644 --- a/cpp/models/abm/infection.h +++ b/cpp/models/abm/infection.h @@ -20,10 +20,10 @@ #ifndef EPI_ABM_INFECTION_H #define EPI_ABM_INFECTION_H -#include "abm/time.h" -#include "abm/infection_state.h" -#include "abm/virus_variant.h" -#include "abm/parameters.h" +#include "models/abm/time.h" +#include "models/abm/infection_state.h" +#include "models/abm/virus_variant.h" +#include "models/abm/parameters.h" #include diff --git a/cpp/models/abm/location.cpp b/cpp/models/abm/location.cpp index 229e1e5f58..d5ea5b32ed 100644 --- a/cpp/models/abm/location.cpp +++ b/cpp/models/abm/location.cpp @@ -17,11 +17,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/mask_type.h" -#include "abm/mask.h" -#include "abm/location.h" +#include "models/abm/mask_type.h" +#include "models/abm/mask.h" +#include "models/abm/location.h" #include "memilio/utils/random_number_generator.h" -#include "abm/random_events.h" +#include "models/abm/random_events.h" #include diff --git a/cpp/models/abm/location.h b/cpp/models/abm/location.h index 95c80bb7fe..628291eb10 100644 --- a/cpp/models/abm/location.h +++ b/cpp/models/abm/location.h @@ -20,12 +20,12 @@ #ifndef EPI_ABM_LOCATION_H #define EPI_ABM_LOCATION_H -#include "abm/person.h" -#include "abm/mask_type.h" -#include "abm/parameters.h" -#include "abm/location_type.h" -#include "abm/infection_state.h" -#include "abm/vaccine.h" +#include "models/abm/person.h" +#include "models/abm/mask_type.h" +#include "models/abm/parameters.h" +#include "models/abm/location_type.h" +#include "models/abm/infection_state.h" +#include "models/abm/vaccine.h" #include "memilio/math/eigen.h" #include "memilio/utils/custom_index_array.h" diff --git a/cpp/models/abm/lockdown_rules.cpp b/cpp/models/abm/lockdown_rules.cpp index 5a509537ba..18ca35b6d1 100644 --- a/cpp/models/abm/lockdown_rules.cpp +++ b/cpp/models/abm/lockdown_rules.cpp @@ -17,9 +17,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/lockdown_rules.h" -#include "abm/person.h" -#include "abm/time.h" +#include "models/abm/lockdown_rules.h" +#include "models/abm/person.h" +#include "models/abm/time.h" namespace mio { diff --git a/cpp/models/abm/lockdown_rules.h b/cpp/models/abm/lockdown_rules.h index 034a8b6b52..850339c117 100644 --- a/cpp/models/abm/lockdown_rules.h +++ b/cpp/models/abm/lockdown_rules.h @@ -20,10 +20,10 @@ #ifndef EPI_ABM_LOCKDOWN_RULES_H #define EPI_ABM_LOCKDOWN_RULES_H -#include "abm/time.h" -#include "abm/location_type.h" -#include "abm/person.h" -#include "abm/parameters.h" +#include "models/abm/time.h" +#include "models/abm/location_type.h" +#include "models/abm/person.h" +#include "models/abm/parameters.h" #include "memilio/epidemiology/damping.h" #include "memilio/epidemiology/contact_matrix.h" diff --git a/cpp/models/abm/mask.cpp b/cpp/models/abm/mask.cpp index 70c940699d..b41149458e 100644 --- a/cpp/models/abm/mask.cpp +++ b/cpp/models/abm/mask.cpp @@ -18,10 +18,10 @@ * limitations under the License. */ -#include "abm/mask_type.h" -#include "abm/parameters.h" -#include "abm/mask.h" -#include "abm/time.h" +#include "models/abm/mask_type.h" +#include "models/abm/parameters.h" +#include "models/abm/mask.h" +#include "models/abm/time.h" namespace mio { diff --git a/cpp/models/abm/mask.h b/cpp/models/abm/mask.h index 71223b2b09..d8af57a6cc 100644 --- a/cpp/models/abm/mask.h +++ b/cpp/models/abm/mask.h @@ -21,8 +21,8 @@ #ifndef EPI_ABM_MASK_H #define EPI_ABM_MASK_H -#include "abm/mask_type.h" -#include "abm/time.h" +#include "models/abm/mask_type.h" +#include "models/abm/time.h" namespace mio { diff --git a/cpp/models/abm/migration_rules.cpp b/cpp/models/abm/migration_rules.cpp index dfb3714c8a..bffbd4b7ee 100644 --- a/cpp/models/abm/migration_rules.cpp +++ b/cpp/models/abm/migration_rules.cpp @@ -18,13 +18,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/migration_rules.h" -#include "abm/person.h" -#include "abm/location.h" -#include "abm/random_events.h" -#include "abm/location.h" +#include "models/abm/migration_rules.h" +#include "models/abm/person.h" +#include "models/abm/location.h" +#include "models/abm/random_events.h" +#include "models/abm/location.h" #include "memilio/utils/random_number_generator.h" -#include "abm/location_type.h" +#include "models/abm/location_type.h" #include diff --git a/cpp/models/abm/migration_rules.h b/cpp/models/abm/migration_rules.h index 3da67fe446..060eb9dff3 100644 --- a/cpp/models/abm/migration_rules.h +++ b/cpp/models/abm/migration_rules.h @@ -21,9 +21,9 @@ #ifndef EPI_ABM_MIGRATION_RULES_H #define EPI_ABM_MIGRATION_RULES_H -#include "abm/location_type.h" -#include "abm/parameters.h" -#include "abm/time.h" +#include "models/abm/location_type.h" +#include "models/abm/parameters.h" +#include "models/abm/time.h" namespace mio { diff --git a/cpp/models/abm/parameters.cpp b/cpp/models/abm/parameters.cpp index ca5fcee4b8..0981817887 100644 --- a/cpp/models/abm/parameters.cpp +++ b/cpp/models/abm/parameters.cpp @@ -17,4 +17,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/parameters.h" +#include "models/abm/parameters.h" diff --git a/cpp/models/abm/parameters.h b/cpp/models/abm/parameters.h index 3330927824..78957bdb15 100644 --- a/cpp/models/abm/parameters.h +++ b/cpp/models/abm/parameters.h @@ -20,11 +20,11 @@ #ifndef EPI_ABM_PARAMETERS_H #define EPI_ABM_PARAMETERS_H -#include "abm/age.h" -#include "abm/mask_type.h" -#include "abm/time.h" -#include "abm/virus_variant.h" -#include "abm/vaccine.h" +#include "models/abm/age.h" +#include "models/abm/mask_type.h" +#include "models/abm/time.h" +#include "models/abm/virus_variant.h" +#include "models/abm/vaccine.h" #include "memilio/utils/custom_index_array.h" #include "memilio/utils/uncertain_value.h" #include "memilio/math/eigen.h" diff --git a/cpp/models/abm/person.cpp b/cpp/models/abm/person.cpp index 30f217c2bb..304c5d79d8 100755 --- a/cpp/models/abm/person.cpp +++ b/cpp/models/abm/person.cpp @@ -17,12 +17,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/person.h" -#include "abm/location_type.h" -#include "abm/mask_type.h" -#include "abm/parameters.h" -#include "abm/world.h" -#include "abm/location.h" +#include "models/abm/person.h" +#include "models/abm/location_type.h" +#include "models/abm/mask_type.h" +#include "models/abm/parameters.h" +#include "models/abm/world.h" +#include "models/abm/location.h" #include "memilio/utils/random_number_generator.h" #include diff --git a/cpp/models/abm/person.h b/cpp/models/abm/person.h index d0da8d7253..67066ef598 100755 --- a/cpp/models/abm/person.h +++ b/cpp/models/abm/person.h @@ -20,14 +20,14 @@ #ifndef EPI_ABM_PERSON_H #define EPI_ABM_PERSON_H -#include "abm/age.h" -#include "abm/location_type.h" -#include "abm/parameters.h" -#include "abm/time.h" -#include "abm/infection.h" -#include "abm/vaccine.h" -#include "abm/mask_type.h" -#include "abm/mask.h" +#include "models/abm/age.h" +#include "models/abm/location_type.h" +#include "models/abm/parameters.h" +#include "models/abm/time.h" +#include "models/abm/infection.h" +#include "models/abm/vaccine.h" +#include "models/abm/mask_type.h" +#include "models/abm/mask.h" #include "memilio/utils/memory.h" #include diff --git a/cpp/models/abm/random_events.h b/cpp/models/abm/random_events.h index c7566fa233..5f7c2a273b 100644 --- a/cpp/models/abm/random_events.h +++ b/cpp/models/abm/random_events.h @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/time.h" +#include "models/abm/time.h" #include "memilio/utils/random_number_generator.h" #include #include diff --git a/cpp/models/abm/simulation.cpp b/cpp/models/abm/simulation.cpp index e355e12eab..53a3eaf4c4 100644 --- a/cpp/models/abm/simulation.cpp +++ b/cpp/models/abm/simulation.cpp @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/simulation.h" +#include "models/abm/simulation.h" namespace mio { diff --git a/cpp/models/abm/simulation.h b/cpp/models/abm/simulation.h index 88e89aac9c..a59ba7b830 100644 --- a/cpp/models/abm/simulation.h +++ b/cpp/models/abm/simulation.h @@ -20,8 +20,8 @@ #ifndef EPI_ABM_SIMULATOR_H #define EPI_ABM_SIMULATOR_H -#include "abm/world.h" -#include "abm/time.h" +#include "models/abm/world.h" +#include "models/abm/time.h" #include "memilio/utils/time_series.h" namespace mio diff --git a/cpp/models/abm/testing_strategy.cpp b/cpp/models/abm/testing_strategy.cpp index e6360a7958..cdeb979b3d 100644 --- a/cpp/models/abm/testing_strategy.cpp +++ b/cpp/models/abm/testing_strategy.cpp @@ -19,7 +19,7 @@ * limitations under the License. */ -#include "abm/testing_strategy.h" +#include "models/abm/testing_strategy.h" #include "memilio/utils/random_number_generator.h" namespace mio diff --git a/cpp/models/abm/testing_strategy.h b/cpp/models/abm/testing_strategy.h index 94a2a9cd21..5020fa3da9 100644 --- a/cpp/models/abm/testing_strategy.h +++ b/cpp/models/abm/testing_strategy.h @@ -21,10 +21,10 @@ #ifndef EPI_ABM_TESTING_SCHEME_H #define EPI_ABM_TESTING_SCHEME_H -#include "abm/parameters.h" -#include "abm/person.h" -#include "abm/location.h" -#include "abm/time.h" +#include "models/abm/parameters.h" +#include "models/abm/person.h" +#include "models/abm/location.h" +#include "models/abm/time.h" namespace mio { diff --git a/cpp/models/abm/time.cpp b/cpp/models/abm/time.cpp index 02c4a1a003..b7b6b14dc5 100644 --- a/cpp/models/abm/time.cpp +++ b/cpp/models/abm/time.cpp @@ -17,4 +17,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/time.h" +#include "models/abm/time.h" diff --git a/cpp/models/abm/trip_list.cpp b/cpp/models/abm/trip_list.cpp index ded1527e9d..6cb582b87d 100644 --- a/cpp/models/abm/trip_list.cpp +++ b/cpp/models/abm/trip_list.cpp @@ -17,9 +17,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/trip_list.h" -#include "abm/location.h" -#include "abm/random_events.h" +#include "models/abm/trip_list.h" +#include "models/abm/location.h" +#include "models/abm/random_events.h" #include diff --git a/cpp/models/abm/trip_list.h b/cpp/models/abm/trip_list.h index 9e488b8eb5..de71ca31d7 100644 --- a/cpp/models/abm/trip_list.h +++ b/cpp/models/abm/trip_list.h @@ -20,10 +20,10 @@ #ifndef EPI_ABM_TRIP_LIST_H #define EPI_ABM_TRIP_LIST_H -#include "abm/parameters.h" -#include "abm/location.h" -#include "abm/infection.h" -#include "abm/location_type.h" +#include "models/abm/parameters.h" +#include "models/abm/location.h" +#include "models/abm/infection.h" +#include "models/abm/location_type.h" #include "memilio/math/eigen.h" #include diff --git a/cpp/models/abm/vaccine.h b/cpp/models/abm/vaccine.h index c78def0284..af11154313 100644 --- a/cpp/models/abm/vaccine.h +++ b/cpp/models/abm/vaccine.h @@ -20,7 +20,7 @@ #ifndef EPI_ABM_VACCINE_H #define EPI_ABM_VACCINE_H -#include "abm/time.h" +#include "models/abm/time.h" #include diff --git a/cpp/models/abm/world.cpp b/cpp/models/abm/world.cpp index 12e05d5e11..ff10e10122 100755 --- a/cpp/models/abm/world.cpp +++ b/cpp/models/abm/world.cpp @@ -18,15 +18,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/world.h" -#include "abm/mask_type.h" -#include "abm/person.h" -#include "abm/location.h" -#include "abm/migration_rules.h" +#include "models/abm/world.h" +#include "models/abm/mask_type.h" +#include "models/abm/person.h" +#include "models/abm/location.h" +#include "models/abm/migration_rules.h" #include "memilio/utils/random_number_generator.h" #include "memilio/utils/stl_util.h" -#include "abm/infection.h" -#include "abm/vaccine.h" +#include "models/abm/infection.h" +#include "models/abm/vaccine.h" namespace mio { @@ -183,6 +183,11 @@ const MigrationParameters& World::get_migration_parameters() const return m_migration_parameters; } +uint32_t World::get_world_id() +{ + return m_world_id; +} + GlobalInfectionParameters& World::get_global_infection_parameters() { return m_infection_parameters; diff --git a/cpp/models/abm/world.h b/cpp/models/abm/world.h index 3359fddda8..cf63de1c6e 100644 --- a/cpp/models/abm/world.h +++ b/cpp/models/abm/world.h @@ -21,12 +21,12 @@ #ifndef EPI_ABM_WORLD_H #define EPI_ABM_WORLD_H -#include "abm/parameters.h" -#include "abm/location.h" -#include "abm/person.h" -#include "abm/lockdown_rules.h" -#include "abm/trip_list.h" -#include "abm/testing_strategy.h" +#include "models/abm/parameters.h" +#include "models/abm/location.h" +#include "models/abm/person.h" +#include "models/abm/lockdown_rules.h" +#include "models/abm/trip_list.h" +#include "models/abm/testing_strategy.h" #include "memilio/utils/pointer_dereferencing_iterator.h" #include "memilio/utils/stl_util.h" @@ -150,6 +150,12 @@ class World const MigrationParameters& get_migration_parameters() const; + /** + * @brief Get the world_id. + * @return m_world_id. + */ + uint32_t get_world_id(); + /** * @brief Get the GlobalInfectionParameters. * @return Reference to the GlobalInfectionParameters. diff --git a/cpp/models/graph_abm/graph_simulation.h b/cpp/models/graph_abm/graph_simulation.h index d8a435c770..83d8222edd 100644 --- a/cpp/models/graph_abm/graph_simulation.h +++ b/cpp/models/graph_abm/graph_simulation.h @@ -21,7 +21,7 @@ #define EPI_ABM_GRAPH_SIMULATOR_H #include "models/graph_abm/graph_world.h" -#include "abm/simulation.h" +#include "models/abm/simulation.h" #include "memilio/utils/time_series.h" namespace mio diff --git a/cpp/models/graph_abm/graph_world.cpp b/cpp/models/graph_abm/graph_world.cpp index 7f3455b955..6338edf567 100644 --- a/cpp/models/graph_abm/graph_world.cpp +++ b/cpp/models/graph_abm/graph_world.cpp @@ -18,7 +18,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/world.h" +#include "models/abm/world.h" #include "graph_abm/graph_world.h" namespace mio @@ -122,6 +122,10 @@ void GraphWorld::migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt) // } } +std::vector>& GraphWorld::get_persons_to_migrate(){ + return m_persons_to_migrate; +} + void GraphWorld::evolve(mio::abm::TimePoint t, mio::abm::TimeSpan dt) { Base::begin_step(t, dt); diff --git a/cpp/models/graph_abm/graph_world.h b/cpp/models/graph_abm/graph_world.h index 85f55bccb9..731bcd3459 100644 --- a/cpp/models/graph_abm/graph_world.h +++ b/cpp/models/graph_abm/graph_world.h @@ -21,8 +21,8 @@ #ifndef EPI_GRAPH_ABM_WORLD_H #define EPI_GRAPH_ABM_WORLD_H -#include "abm/world.h" -#include "abm/location_type.h" +#include "models/abm/world.h" +#include "models/abm/location_type.h" #include #include @@ -40,49 +40,12 @@ class GraphWorld : public mio::abm::World using Base = mio::abm::World; public: - // mio::abm::LocationId add_external_location(mio::abm::LocationType type, uint32_t num_cells = 1) - // { - // mio::abm::LocationId id = {static_cast(m_locations_external.size() + Base::m_locations.size()), type}; - // m_locations_external.emplace_back(std::make_unique(id, num_cells)); - // return id; - // } - // mio::abm::Person& add_person(const mio::abm::LocationId id, mio::abm::AgeGroup age) - // { - // uint32_t person_id = static_cast(Base::m_persons.size()); - // Base::m_persons.push_back( - // std::make_unique(get_individualized_location(id), age, person_id, m_world_id)); - // auto& person = *m_persons_internal.back(); - // get_individualized_location(id).add_person(person); - // return person; - // } - - // void insert_external_location_to_map(int node_to, mio::abm::LocationId id_this_world, - // mio::abm::LocationId id_other_world) - // { - // if (m_external_location_mapping.find(node_to) != m_external_location_mapping.end()) { - // auto& mapping = m_external_location_mapping[node_to]; - // mapping.push_back(std::make_pair(id_this_world, id_other_world)); - // } - // else { - // std::vector> v = { - // std::make_pair(id_this_world, id_other_world)}; - // m_external_location_mapping.insert( - // std::pair>>(node_to, v)); - // } - // } - // auto get_persons() const -> Range> - // { - // return std::make_pair(ConstPersonIterator(m_persons_internal.begin()), - // ConstPersonIterator(m_persons_internal.end())); - // } - - // /** - // * Prepare the World for the next simulation step. - // * @param[in] t Current time. - // * @param[in] dt Length of the time step. - // */ - // void begin_step(mio::abm::TimePoint t, mio::abm::TimeSpan dt); + /** + * @brief Get reference to all Person%s that will migrate to another world. + * @return A reference to the vector of all Person%s that will migrate. + */ + std::vector>& get_persons_to_migrate(); /** @brief Person%s move in the World according to rules. * @param[in] t The current TimePoint. diff --git a/cpp/simulations/abm.cpp b/cpp/simulations/abm.cpp index 8abd86a208..5850ad9062 100644 --- a/cpp/simulations/abm.cpp +++ b/cpp/simulations/abm.cpp @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/abm.h" +#include "models/abm/abm.h" #include "memilio/io/result_io.h" #include "memilio/utils/uncertain_value.h" #include "boost/filesystem.hpp" diff --git a/cpp/tests/abm_helpers.h b/cpp/tests/abm_helpers.h index 1a1dc06c50..d7ed980c45 100644 --- a/cpp/tests/abm_helpers.h +++ b/cpp/tests/abm_helpers.h @@ -20,7 +20,7 @@ #ifndef ABM_HELPERS_H #define ABM_HELPERS_H -#include "abm/abm.h" +#include "models/abm/abm.h" #include "memilio/math/eigen_util.h" #include "matchers.h" #include "gtest/gtest.h" diff --git a/cpp/tests/test_abm_household.cpp b/cpp/tests/test_abm_household.cpp index d6674a41b1..c120e3fe5a 100644 --- a/cpp/tests/test_abm_household.cpp +++ b/cpp/tests/test_abm_household.cpp @@ -17,8 +17,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/household.h" -#include "abm/abm.h" +#include "models/abm/household.h" +#include "models/abm/abm.h" #include TEST(TestHouseholds, test_add_household_to_world) diff --git a/cpp/tests/test_abm_location.cpp b/cpp/tests/test_abm_location.cpp index 33145aff94..06f55d3777 100644 --- a/cpp/tests/test_abm_location.cpp +++ b/cpp/tests/test_abm_location.cpp @@ -17,7 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "abm/infection.h" +#include "models/abm/infection.h" #include "abm_helpers.h" #include diff --git a/cpp/tests/test_epi_data_io.cpp b/cpp/tests/test_epi_data_io.cpp index 09c614bd70..76cced3577 100644 --- a/cpp/tests/test_epi_data_io.cpp +++ b/cpp/tests/test_epi_data_io.cpp @@ -18,7 +18,7 @@ * limitations under the License. */ -#include "abm/infection_state.h" +#include "models/abm/infection_state.h" #include "memilio/epidemiology/age_group.h" #include "memilio/geography/regions.h" #include "memilio/io/epi_data.h" diff --git a/pycode/memilio-simulation/memilio/simulation/abm.cpp b/pycode/memilio-simulation/memilio/simulation/abm.cpp index 1e2afbe680..7141e023c4 100644 --- a/pycode/memilio-simulation/memilio/simulation/abm.cpp +++ b/pycode/memilio-simulation/memilio/simulation/abm.cpp @@ -22,7 +22,7 @@ #include "utils/custom_index_array.h" #include "utils/parameter_set.h" #include "utils/index.h" -#include "abm/abm.h" +#include "models/abm/abm.h" #include "pybind11/attr.h" #include "pybind11/cast.h" #include "pybind11/pybind11.h" From d7069bada0366c343fe64bef2b77ce883aa92cfe Mon Sep 17 00:00:00 2001 From: jubicker Date: Thu, 1 Jun 2023 09:34:24 +0200 Subject: [PATCH 11/38] add edge function --- cpp/examples/graph_abm.cpp | 6 +-- cpp/memilio/mobility/graph_simulation.h | 10 ----- .../metapopulation_mobility_instant.h | 24 ++++++------ cpp/models/abm/person.cpp | 19 +++++++--- cpp/models/abm/person.h | 10 ++++- cpp/models/graph_abm/graph_world.cpp | 37 ++++++------------- cpp/models/graph_abm/graph_world.h | 9 ++++- 7 files changed, 55 insertions(+), 60 deletions(-) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index b7192f56e7..4046baba17 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -196,7 +196,7 @@ int main() auto t0 = mio::abm::TimePoint(0); auto dt = mio::abm::hours(12); - auto tmax = mio::abm::TimePoint(0) + mio::abm::days(30); + auto tmax = mio::abm::TimePoint(0) + mio::abm::days(7); mio::Graph, mio::MigrationEdgeABM> g; g.add_node(0, t0, std::move(world1)); @@ -204,9 +204,9 @@ int main() g.add_edge(0, 1); //, Eigen::VectorXd::Constant((size_t)1, 1.) g.add_edge(1, 0); //, Eigen::VectorXd::Constant((size_t)1, 1.) - auto sim = mio::make_migration_sim_test(t0, dt, std::move(g)); + auto sim = mio::make_migration_sim(t0, dt, std::move(g)); - //sim.advance(tmax); + sim.advance(tmax); // The results are saved in a table with 9 rows. // The first row is t = time, the others correspond to the number of people with a certain infection state at this time: diff --git a/cpp/memilio/mobility/graph_simulation.h b/cpp/memilio/mobility/graph_simulation.h index 8f06374a81..3b8c22c03a 100644 --- a/cpp/memilio/mobility/graph_simulation.h +++ b/cpp/memilio/mobility/graph_simulation.h @@ -270,16 +270,6 @@ auto make_graph_sim(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, Edg t0, dt, std::forward(g), std::forward(node_func), std::forward(edge_func)); } -template < - class Graph, class NodeF, class EdgeF, class Timepoint, class Timespan, - std::enable_if_t<((std::is_same::value || std::is_same::value) && - (std::is_same::value || std::is_same::value)), - bool> = true> //, class EdgeF -auto make_graph_sim_test(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, EdgeF&& edge_func) -{ - return GraphSimulation, Timepoint, Timespan>(t0, dt, std::forward(g), std::forward(node_func), std::forward(edge_func)); -} - template auto make_graph_sim_stochastic(Timepoint t0, Timespan dt, Graph&& g, NodeF&& node_func, EdgeF&& edge_func) { diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index b866dc1980..8d6fc96352 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -323,12 +323,18 @@ void MigrationEdgeABM::apply_migration(mio::abm::TimePoint t, mio::abm::TimeSpan { mio::unused(t); mio::unused(dt); - mio::unused(node_from); - mio::unused(node_to); for (auto person_iter = node_from.get_simulation().get_graph_world().get_persons_to_migrate().begin(); person_iter != node_from.get_simulation().get_graph_world().get_persons_to_migrate().end(); ++person_iter) { if (((*person_iter)->get_location()).get_world_id() == node_to.get_simulation().get_graph_world().get_world_id()) { + auto& target_location = node_to.get_simulation().get_graph_world().find_location( + ((*person_iter)->get_location()).get_type(), *(*person_iter)); + //let person migrate to location in target world + (*person_iter)->migrate_to_other_world(target_location, true); + //add person to target world + node_to.get_simulation().get_graph_world().add_existing_person(std::move(*person_iter)); + //remove person from origin world + node_from.get_simulation().get_graph_world().get_persons_to_migrate().erase(person_iter); } } } @@ -561,20 +567,12 @@ make_migration_sim(Timepoint t0, Timespan dt, const Graph, M return make_graph_sim(t0, dt, graph, &evolve_model, &apply_migration); } -template -GraphSimulation, MigrationEdge>, Timepoint, Timespan> -make_migration_sim(Timepoint t0, Timespan dt, Graph, MigrationEdge>&& graph) -{ - return make_graph_sim(t0, dt, std::move(graph), &evolve_model, - &apply_migration); -} - template GraphSimulation, Edge>, Timepoint, Timespan> -make_migration_sim_test(Timepoint t0, Timespan dt, Graph, Edge>&& graph) +make_migration_sim(Timepoint t0, Timespan dt, Graph, Edge>&& graph) { - return make_graph_sim_test(t0, dt, std::move(graph), &evolve_model, - &apply_migration); + return make_graph_sim(t0, dt, std::move(graph), &evolve_model, + &apply_migration); } /** @} */ diff --git a/cpp/models/abm/person.cpp b/cpp/models/abm/person.cpp index 304c5d79d8..e6d8a0aa4a 100755 --- a/cpp/models/abm/person.cpp +++ b/cpp/models/abm/person.cpp @@ -60,16 +60,25 @@ void Person::interact(TimePoint t, TimeSpan dt, const GlobalInfectionParameters& m_time_at_location += dt; } -void Person::migrate_to(Location& loc_new, const std::vector& cells, bool add_to_new_location) +void Person::migrate_to(Location& loc_new, const std::vector& cells) { if (*m_location != loc_new) { m_location->remove_person(*this); m_location = &loc_new; m_cells = cells; - if (add_to_new_location) { - loc_new.add_person(*this, cells); - m_time_at_location = TimeSpan(0); - } + loc_new.add_person(*this, cells); + m_time_at_location = TimeSpan(0); + } +} + +void Person::migrate_to_other_world(Location& loc_new, bool set_time_at_location, const std::vector& cells) +{ + m_location->remove_person(*this); + m_location = &loc_new; + m_cells = cells; + loc_new.add_person(*this, cells); + if (set_time_at_location) { + m_time_at_location = TimeSpan(0); } } diff --git a/cpp/models/abm/person.h b/cpp/models/abm/person.h index 67066ef598..0fae60c25c 100755 --- a/cpp/models/abm/person.h +++ b/cpp/models/abm/person.h @@ -79,7 +79,15 @@ class Person * @param[in] loc_new The new location of the person. * @param[in] cells_new The new cells of the person. * */ - void migrate_to(Location& loc_new, const std::vector& cells_new = {0}, bool add_to_new_location = true); + void migrate_to(Location& loc_new, const std::vector& cells_new = {0}); + + /** + * @brief migrate to a different location in another world. + * @param[in] loc_new The new location of the person. + * @param[in] cells_new The new cells of the person. + */ + void migrate_to_other_world(Location& loc_new, bool set_time_at_location, + const std::vector& cells_new = {0}); /** * @brief Get the latest Infection of the Person. diff --git a/cpp/models/graph_abm/graph_world.cpp b/cpp/models/graph_abm/graph_world.cpp index 6338edf567..2a5b7ca2f7 100644 --- a/cpp/models/graph_abm/graph_world.cpp +++ b/cpp/models/graph_abm/graph_world.cpp @@ -26,29 +26,6 @@ namespace mio namespace graph_abm { -// void GraphWorld::interaction(mio::abm::TimePoint t, mio::abm::TimeSpan dt) -// { -// for (auto&& person : m_persons_internal) { -// //only persons that are active in the world should interact -// if (person->get_is_active_in_world()) { -// person->interact(t, dt, m_infection_parameters); -// } -// } -// for (auto&& person : m_persons_external) { -// person->interact(t, dt, m_infection_parameters); -// } -// } - -// void GraphWorld::begin_step(mio::abm::TimePoint t, mio::abm::TimeSpan dt) -// { -// for (auto& location : Base::m_locations) { -// location->cache_exposure_rates(t, dt); -// } -// for (auto& location : m_locations_external) { -// location->cache_exposure_rates(t, dt); -// } -// } - mio::abm::Location& GraphWorld::find_location(mio::abm::LocationType type, const mio::abm::Person& person) { auto index = person.get_assigned_location_index(type); @@ -74,6 +51,11 @@ mio::abm::Location& GraphWorld::find_location(mio::abm::LocationType type, const } } +void GraphWorld::add_existing_person(std::unique_ptr&& person) +{ + Base::m_persons.push_back(std::move(person)); +} + void GraphWorld::migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt) { @@ -93,9 +75,11 @@ void GraphWorld::migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt) //person changes world m_persons_to_migrate.push_back(std::move(*person_iter)); Base::m_persons.erase(person_iter); - (*person_iter)->migrate_to(target_location, {0}, false); + (*person_iter)->migrate_to_other_world(target_location, false); + } + else { + (*person_iter)->migrate_to(target_location); } - (*person_iter)->migrate_to(target_location); } break; } @@ -122,7 +106,8 @@ void GraphWorld::migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt) // } } -std::vector>& GraphWorld::get_persons_to_migrate(){ +std::vector>& GraphWorld::get_persons_to_migrate() +{ return m_persons_to_migrate; } diff --git a/cpp/models/graph_abm/graph_world.h b/cpp/models/graph_abm/graph_world.h index 731bcd3459..17d155b3d8 100644 --- a/cpp/models/graph_abm/graph_world.h +++ b/cpp/models/graph_abm/graph_world.h @@ -40,12 +40,11 @@ class GraphWorld : public mio::abm::World using Base = mio::abm::World; public: - /** * @brief Get reference to all Person%s that will migrate to another world. * @return A reference to the vector of all Person%s that will migrate. */ - std::vector>& get_persons_to_migrate(); + std::vector>& get_persons_to_migrate(); /** @brief Person%s move in the World according to rules. * @param[in] t The current TimePoint. @@ -68,6 +67,12 @@ class GraphWorld : public mio::abm::World */ mio::abm::Location& find_location(mio::abm::LocationType type, const mio::abm::Person& person); + /** + * @brief Add an existing Person to a world. + * @param[in] person Unique pointer to the person that should beadded to world. + */ + void add_existing_person(std::unique_ptr&& person); + private: // /** // * @brief Person%s interact at their Location and may become infected. From bd1ebc25938b8a46531910f9eb34a5def335a1b1 Mon Sep 17 00:00:00 2001 From: jubicker Date: Thu, 1 Jun 2023 15:48:03 +0200 Subject: [PATCH 12/38] migration bug fix --- .../metapopulation_mobility_instant.h | 18 ++++++----- cpp/models/abm/simulation.h | 2 +- cpp/models/graph_abm/graph_simulation.cpp | 31 +++++++++++++++++-- cpp/models/graph_abm/graph_simulation.h | 8 +++++ cpp/models/graph_abm/graph_world.cpp | 28 +++++++++-------- 5 files changed, 64 insertions(+), 23 deletions(-) diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index 8d6fc96352..b41178ea81 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -323,19 +323,23 @@ void MigrationEdgeABM::apply_migration(mio::abm::TimePoint t, mio::abm::TimeSpan { mio::unused(t); mio::unused(dt); - for (auto person_iter = node_from.get_simulation().get_graph_world().get_persons_to_migrate().begin(); - person_iter != node_from.get_simulation().get_graph_world().get_persons_to_migrate().end(); ++person_iter) { - if (((*person_iter)->get_location()).get_world_id() == + size_t person_iter = 0; + auto& persons_to_migrate = node_from.get_simulation().get_graph_world().get_persons_to_migrate(); + while (person_iter < persons_to_migrate.size()) { + if (((persons_to_migrate[person_iter])->get_location()).get_world_id() == node_to.get_simulation().get_graph_world().get_world_id()) { auto& target_location = node_to.get_simulation().get_graph_world().find_location( - ((*person_iter)->get_location()).get_type(), *(*person_iter)); + (persons_to_migrate[person_iter]->get_location()).get_type(), *persons_to_migrate[person_iter]); //let person migrate to location in target world - (*person_iter)->migrate_to_other_world(target_location, true); + persons_to_migrate[person_iter]->migrate_to_other_world(target_location, true); //add person to target world - node_to.get_simulation().get_graph_world().add_existing_person(std::move(*person_iter)); + node_to.get_simulation().get_graph_world().add_existing_person(std::move(persons_to_migrate[person_iter])); //remove person from origin world - node_from.get_simulation().get_graph_world().get_persons_to_migrate().erase(person_iter); + node_from.get_simulation().get_graph_world().get_persons_to_migrate().erase( + node_from.get_simulation().get_graph_world().get_persons_to_migrate().begin() + person_iter); + continue; } + ++person_iter; } } diff --git a/cpp/models/abm/simulation.h b/cpp/models/abm/simulation.h index a59ba7b830..76bfd34e5b 100644 --- a/cpp/models/abm/simulation.h +++ b/cpp/models/abm/simulation.h @@ -84,10 +84,10 @@ class Simulation private: World m_world; ///< The World to simulate. -protected: void initialize_locations(TimePoint t); void store_result_at(TimePoint t); +protected: TimeSeries m_result; ///< The result of the Simulation. TimePoint m_t; ///< The current TimePoint of the Simulation. TimeSpan m_dt; ///< The length of the time steps. diff --git a/cpp/models/graph_abm/graph_simulation.cpp b/cpp/models/graph_abm/graph_simulation.cpp index 22e8e6966e..ba2ee51926 100644 --- a/cpp/models/graph_abm/graph_simulation.cpp +++ b/cpp/models/graph_abm/graph_simulation.cpp @@ -29,8 +29,35 @@ GraphSimulation::GraphSimulation(mio::abm::TimePoint t, GraphWorld&& graph_world { Base::m_dt = mio::abm::hours(1); Base::m_result = mio::TimeSeries(Eigen::Index(mio::abm::InfectionState::Count)); - Base::initialize_locations(t); - Base::store_result_at(t); + initialize_locations(t); + store_result_at(t); +} + +void GraphSimulation::initialize_locations(mio::abm::TimePoint t) +{ + for (auto& location : m_graph_world.get_locations()) { + location.initialize_subpopulations(t); + } +} + +void GraphSimulation::store_result_at(mio::abm::TimePoint t) +{ + Base::m_result.add_time_point(t.days()); + Base::m_result.get_last_value().setZero(); + for (auto& location : m_graph_world.get_locations()) { + Base::m_result.get_last_value() += location.get_subpopulations().get_last_value().cast(); + } +} + +void GraphSimulation::advance(mio::abm::TimePoint tmax) +{ + auto t = Base::m_t; + while (t < tmax) { + auto dt = std::min(Base::m_dt, tmax - t); + m_graph_world.evolve(t, dt); + t += Base::m_dt; + store_result_at(t); + } } } // namespace graph_abm diff --git a/cpp/models/graph_abm/graph_simulation.h b/cpp/models/graph_abm/graph_simulation.h index 83d8222edd..ce8d212f27 100644 --- a/cpp/models/graph_abm/graph_simulation.h +++ b/cpp/models/graph_abm/graph_simulation.h @@ -56,7 +56,15 @@ class GraphSimulation : public mio::abm::Simulation return m_graph_world; } + /** + * @brief Run the Simulation from the current time to tmax. + * @param[in] tmax Time to stop. + */ + void advance(mio::abm::TimePoint tmax); + private: + void initialize_locations(mio::abm::TimePoint t); + void store_result_at(mio::abm::TimePoint t); GraphWorld m_graph_world; }; diff --git a/cpp/models/graph_abm/graph_world.cpp b/cpp/models/graph_abm/graph_world.cpp index 2a5b7ca2f7..00187f6b88 100644 --- a/cpp/models/graph_abm/graph_world.cpp +++ b/cpp/models/graph_abm/graph_world.cpp @@ -58,33 +58,35 @@ void GraphWorld::add_existing_person(std::unique_ptr&& person) void GraphWorld::migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt) { - - for (auto person_iter = Base::m_persons.begin(); person_iter != Base::m_persons.end(); - ++person_iter) { //auto& person : Base::m_persons + size_t person_iter = 0; + while (person_iter < Base::m_persons.size()) { for (auto rule : Base::m_migration_rules) { //check if transition rule can be applied - auto target_type = rule.first(*(*person_iter), t, dt, m_migration_parameters); - auto& target_location = find_location(target_type, *(*person_iter)); - auto current_location = (*person_iter)->get_location(); - if (m_testing_strategy.run_strategy(*(*person_iter), target_location, t)) { + auto target_type = rule.first(*Base::m_persons[person_iter], t, dt, m_migration_parameters); + auto& target_location = find_location(target_type, *Base::m_persons[person_iter]); + auto current_location = Base::m_persons[person_iter]->get_location(); + if (m_testing_strategy.run_strategy(*Base::m_persons[person_iter], target_location, t)) { if (target_location != current_location && target_location.get_number_persons() < target_location.get_capacity().persons) { - bool wears_mask = (*person_iter)->apply_mask_intervention(target_location); + bool wears_mask = Base::m_persons[person_iter]->apply_mask_intervention(target_location); if (wears_mask) { if (target_location.get_world_id() != Base::m_world_id) { //person changes world - m_persons_to_migrate.push_back(std::move(*person_iter)); - Base::m_persons.erase(person_iter); - (*person_iter)->migrate_to_other_world(target_location, false); + Base::m_persons[person_iter]->migrate_to_other_world(target_location, false); + m_persons_to_migrate.push_back(std::move(Base::m_persons[person_iter])); + Base::m_persons.erase(Base::m_persons.begin() + person_iter); + goto CONTINUE_PERSON; } else { - (*person_iter)->migrate_to(target_location); + Base::m_persons[person_iter]->migrate_to(target_location); } } - break; } } } + ++person_iter; + CONTINUE_PERSON: + continue; } // check if a person makes a trip //TODO From 154529aeda9315d17054e232dbd966e086e449b2 Mon Sep 17 00:00:00 2001 From: jubicker Date: Fri, 2 Jun 2023 12:09:58 +0200 Subject: [PATCH 13/38] examples output --- cpp/examples/graph_abm.cpp | 44 +++++++++++------------ cpp/models/graph_abm/graph_simulation.cpp | 1 + 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index 4046baba17..167d4f9ab8 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -201,31 +201,31 @@ int main() mio::Graph, mio::MigrationEdgeABM> g; g.add_node(0, t0, std::move(world1)); g.add_node(1, t0, std::move(world2)); - g.add_edge(0, 1); //, Eigen::VectorXd::Constant((size_t)1, 1.) - g.add_edge(1, 0); //, Eigen::VectorXd::Constant((size_t)1, 1.) + g.add_edge(0, 1); + g.add_edge(1, 0); auto sim = mio::make_migration_sim(t0, dt, std::move(g)); sim.advance(tmax); - // The results are saved in a table with 9 rows. - // The first row is t = time, the others correspond to the number of people with a certain infection state at this time: - // S = Susceptible, E = Exposed, C = Carrier, I = Infected, I_s = Infected_Severe, - // I_c = Infected_Critical, R_C = Recovered_Carrier, R_I = Recovered_Infected, D = Dead - // auto f_abm = fopen("abm_minimal.txt", "w"); - // fprintf(f_abm, "# t S E C I I_s I_c R_C R_I D\n"); - // for (auto i = 0; i < sim.get_result().get_num_time_points(); ++i) { - // fprintf(f_abm, "%f ", sim.get_result().get_time(i)); - // auto v = sim.get_result().get_value(i); - // for (auto j = 0; j < v.size(); ++j) { - // fprintf(f_abm, "%f", v[j]); - // if (j < v.size() - 1) { - // fprintf(f_abm, " "); - // } - // } - // if (i < sim.get_result().get_num_time_points() - 1) { - // fprintf(f_abm, "\n"); - // } - // } - // fclose(f_abm); + for (auto& n : sim.get_graph().nodes()) { + std::cout << "node " << n.id << "\n"; + std::cout << "\n"; + + std::cout << "# t S E C I I_s I_c R_C R_I D\n"; + for (auto i = 0; i < n.property.get_result().get_num_time_points(); ++i) { + std::cout << n.property.get_result().get_time(i) << " "; + auto v = n.property.get_result().get_value(i); + for (auto j = 0; j < v.size(); ++j) { + std::cout << v[j] << " "; + if (j < v.size() - 1) { + std::cout << " "; + } + } + if (i < n.property.get_result().get_num_time_points() - 1) { + std::cout << "\n"; + } + } + std::cout << "\n"; + } } diff --git a/cpp/models/graph_abm/graph_simulation.cpp b/cpp/models/graph_abm/graph_simulation.cpp index ba2ee51926..4baf8641f7 100644 --- a/cpp/models/graph_abm/graph_simulation.cpp +++ b/cpp/models/graph_abm/graph_simulation.cpp @@ -58,6 +58,7 @@ void GraphSimulation::advance(mio::abm::TimePoint tmax) t += Base::m_dt; store_result_at(t); } + Base::m_t = tmax; } } // namespace graph_abm From a724540157c2584c174a489022c1d522e70596cd Mon Sep 17 00:00:00 2001 From: jubicker Date: Tue, 6 Jun 2023 08:05:21 +0200 Subject: [PATCH 14/38] end simulation --- cpp/examples/graph_abm.cpp | 5 ++--- cpp/memilio/mobility/graph_simulation.h | 10 ++++++++++ .../mobility/metapopulation_mobility_instant.h | 8 ++++++++ cpp/models/graph_abm/graph_simulation.cpp | 11 +++++++++++ cpp/models/graph_abm/graph_simulation.h | 6 ++++++ 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index 167d4f9ab8..682641c282 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -196,7 +196,7 @@ int main() auto t0 = mio::abm::TimePoint(0); auto dt = mio::abm::hours(12); - auto tmax = mio::abm::TimePoint(0) + mio::abm::days(7); + auto tmax = mio::abm::TimePoint(0) + mio::abm::days(10); mio::Graph, mio::MigrationEdgeABM> g; g.add_node(0, t0, std::move(world1)); @@ -206,8 +206,7 @@ int main() auto sim = mio::make_migration_sim(t0, dt, std::move(g)); - sim.advance(tmax); - + sim.advance(tmax, true); for (auto& n : sim.get_graph().nodes()) { std::cout << "node " << n.id << "\n"; std::cout << "\n"; diff --git a/cpp/memilio/mobility/graph_simulation.h b/cpp/memilio/mobility/graph_simulation.h index 3b8c22c03a..9e85082216 100644 --- a/cpp/memilio/mobility/graph_simulation.h +++ b/cpp/memilio/mobility/graph_simulation.h @@ -72,6 +72,16 @@ class GraphSimulationBase { } + void advance(Timepoint t_max, bool store_results_at_end) + { + advance(t_max); + if (store_results_at_end) { + for (auto& n : m_graph.nodes()) { + n.property.end_simulation(t_max); + } + } + } + void advance(Timepoint t_max = 1.0) { auto dt = m_dt; diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index b41178ea81..aceab5412c 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -102,6 +102,11 @@ class SimulationNode m_last_state = m_simulation.get_result().get_last_value(); } + void end_simulation(mio::abm::TimePoint tmax) + { + m_simulation.end_simulation(tmax); + } + private: Sim m_simulation; Eigen::VectorXd m_last_state; @@ -321,6 +326,9 @@ template & node_from, SimulationNode& node_to) { + if (t == mio::abm::TimePoint(0) + mio::abm::days(10)) { + std::cout << "max"; + } mio::unused(t); mio::unused(dt); size_t person_iter = 0; diff --git a/cpp/models/graph_abm/graph_simulation.cpp b/cpp/models/graph_abm/graph_simulation.cpp index 4baf8641f7..573c7ca090 100644 --- a/cpp/models/graph_abm/graph_simulation.cpp +++ b/cpp/models/graph_abm/graph_simulation.cpp @@ -61,5 +61,16 @@ void GraphSimulation::advance(mio::abm::TimePoint tmax) Base::m_t = tmax; } +void GraphSimulation::end_simulation(mio::abm::TimePoint tmax) +{ + for (auto& location : m_graph_world.get_locations()) { + location.store_subpopulations(tmax); + } + Base::m_result.get_last_value().setZero(); + for (auto& location : m_graph_world.get_locations()) { + Base::m_result.get_last_value() += location.get_subpopulations().get_last_value().cast(); + } +} + } // namespace graph_abm } // namespace mio diff --git a/cpp/models/graph_abm/graph_simulation.h b/cpp/models/graph_abm/graph_simulation.h index ce8d212f27..ca15f6a884 100644 --- a/cpp/models/graph_abm/graph_simulation.h +++ b/cpp/models/graph_abm/graph_simulation.h @@ -62,6 +62,12 @@ class GraphSimulation : public mio::abm::Simulation */ void advance(mio::abm::TimePoint tmax); + /** + * @brief Saves the final timestep in m_results at the end of the simulation. + * @param[in] tmax Last timepoint. + */ + void end_simulation(mio::abm::TimePoint tmax); + private: void initialize_locations(mio::abm::TimePoint t); void store_result_at(mio::abm::TimePoint t); From e016060ecfeab6ec73e8dcb8a21d655f5588085a Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 7 Jun 2023 12:13:52 +0200 Subject: [PATCH 15/38] add migration with trips --- cpp/models/abm/trip_list.h | 4 +- cpp/models/graph_abm/graph_world.cpp | 72 +++++++++++++++++++++------- cpp/models/graph_abm/graph_world.h | 21 +++++--- 3 files changed, 72 insertions(+), 25 deletions(-) diff --git a/cpp/models/abm/trip_list.h b/cpp/models/abm/trip_list.h index de71ca31d7..4a1748561f 100644 --- a/cpp/models/abm/trip_list.h +++ b/cpp/models/abm/trip_list.h @@ -40,10 +40,12 @@ namespace abm struct Trip { uint32_t person_id; /**< Person that makes the trip and corresponds to the index into the structure m_persons from World, where all Person%s are saved.*/ + uint32_t person_world_id; TimePoint time; ///< Time at which a Person changes the Location. LocationId migration_destination; ///< Location where the Person migrates to. LocationId migration_origin; ///< Location where the Person starts the Trip. - std::vector cells; /**< If migration_destination consists of different Cell%s, this gives the index of the + std::vector + cells; /**< If migration_destination consists of different Cell%s, this gives the index of the Cell%s the Person migrates to.*/ /** diff --git a/cpp/models/graph_abm/graph_world.cpp b/cpp/models/graph_abm/graph_world.cpp index 00187f6b88..db3993dca0 100644 --- a/cpp/models/graph_abm/graph_world.cpp +++ b/cpp/models/graph_abm/graph_world.cpp @@ -51,11 +51,42 @@ mio::abm::Location& GraphWorld::find_location(mio::abm::LocationType type, const } } +mio::abm::Location& GraphWorld::get_individualized_location(mio::abm::LocationId id) +{ + if (id.world_id == Base::m_world_id) { + return *m_locations[id.index]; + } + else { + mio::abm::Location loc = mio::abm::Location(id.type, id.index, id.world_id); + auto iter = std::find_if(m_locations_external.begin(), m_locations_external.end(), + [loc](const std::unique_ptr& loc_ext) { + return ((loc.get_type() == loc_ext->get_type()) && + (loc.get_index() == loc_ext->get_index()) && + (loc.get_world_id() == loc_ext->get_world_id())); + }); + if (iter != m_locations_external.end()) { + return *(*iter); + } + else { + m_locations_external.emplace_back(std::make_unique(loc)); + return *m_locations_external.back(); + } + } +} + void GraphWorld::add_existing_person(std::unique_ptr&& person) { Base::m_persons.push_back(std::move(person)); } +std::unique_ptr& GraphWorld::get_person(uint32_t person_id, uint32_t person_world_id) +{ + return *std::find_if(Base::m_persons.begin(), Base::m_persons.end(), + [person_id, person_world_id](const std::unique_ptr& person) { + return (person_id == person->get_person_id() && person_world_id == person->get_world_id()); + }); +} + void GraphWorld::migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt) { size_t person_iter = 0; @@ -89,23 +120,30 @@ void GraphWorld::migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt) continue; } // check if a person makes a trip - //TODO - // size_t num_trips = m_trip_list.num_trips(); - // if (num_trips != 0) { - // while (m_trip_list.get_current_index() < num_trips && m_trip_list.get_next_trip_time() < t + dt) { - // auto& trip = m_trip_list.get_next_trip(); - // auto& person = m_persons[trip.person_id]; - // auto current_location = person->get_location(); - // if (!person->is_in_quarantine() && current_location == get_individualized_location(trip.migration_origin)) { - // auto& target_location = get_individualized_location(trip.migration_destination); - // if (m_testing_strategy.run_strategy(*person, target_location, t)) { - // person->apply_mask_intervention(target_location); - // person->migrate_to(target_location); - // } - // } - // m_trip_list.increase_index(); - // } - // } + size_t num_trips = m_trip_list.num_trips(); + if (num_trips != 0) { + while (m_trip_list.get_current_index() < num_trips && m_trip_list.get_next_trip_time() < t + dt) { + auto& trip = m_trip_list.get_next_trip(); + auto& person = get_person(trip.person_id, trip.person_world_id); + auto current_location = person->get_location(); + if (!person->is_in_quarantine() && current_location == get_individualized_location(trip.migration_origin)) { + auto& target_location = get_individualized_location(trip.migration_destination); + person->apply_mask_intervention(target_location); + if (m_testing_strategy.run_strategy(*person, target_location, t)) { + if (target_location.get_world_id() != Base::m_world_id) { + //person changes world + person->migrate_to_other_world(target_location, false); + m_persons_to_migrate.push_back(std::move(person)); + Base::m_persons.erase(Base::m_persons.begin() + trip.person_id); + } + else { + person->migrate_to(target_location); + } + } + } + m_trip_list.increase_index(); + } + } } std::vector>& GraphWorld::get_persons_to_migrate() diff --git a/cpp/models/graph_abm/graph_world.h b/cpp/models/graph_abm/graph_world.h index 17d155b3d8..1617153713 100644 --- a/cpp/models/graph_abm/graph_world.h +++ b/cpp/models/graph_abm/graph_world.h @@ -73,14 +73,21 @@ class GraphWorld : public mio::abm::World */ void add_existing_person(std::unique_ptr&& person); -private: - // /** - // * @brief Person%s interact at their Location and may become infected. - // * @param[in] t The current TimePoint. - // * @param[in] dt The length of the time step of the Simulation. - // */ - // void interaction(mio::abm::TimePoint t, mio::abm::TimeSpan dt); + /** + * @brief Get an individualized Location. + * @param[in] id LocationId of the Location. + * @return Reference to the Location. + */ + mio::abm::Location& get_individualized_location(mio::abm::LocationId id); + /** + * @brief Get person by id. + * @param[in] person_id PersonId of the Person. + * @return Reference to unique pointer in m_persons. + */ + std::unique_ptr& get_person(uint32_t person_id, uint32_t person_world_id); + +private: //persons that will migrate to other worlds std::vector> m_persons_to_migrate; std::vector> m_locations_external; From 82eacc23fc9549c07d8a58c899eb13b7f119d21a Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 7 Jun 2023 15:31:05 +0200 Subject: [PATCH 16/38] begin tests --- cpp/tests/CMakeLists.txt | 17 +++++++------- cpp/tests/test_graph_abm.cpp | 43 ++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 cpp/tests/test_graph_abm.cpp diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index e04bcd2ec8..221b952e32 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -20,6 +20,7 @@ set(TESTSOURCES test_parameter_studies.cpp test_graph.cpp test_graph_simulation.cpp + test_graph_abm.cpp test_stl_util.cpp test_uncertain.cpp test_random_number_generator.cpp @@ -63,17 +64,17 @@ set(TESTSOURCES ) if(MEMILIO_HAS_JSONCPP) -set(TESTSOURCES ${TESTSOURCES} -test_json_serializer.cpp -test_epi_data_io.cpp -) + set(TESTSOURCES ${TESTSOURCES} + test_json_serializer.cpp + test_epi_data_io.cpp + ) endif() if(MEMILIO_HAS_JSONCPP AND MEMILIO_HAS_HDF5) -set(TESTSOURCES ${TESTSOURCES} -test_save_parameters.cpp -test_save_results.cpp -) + set(TESTSOURCES ${TESTSOURCES} + test_save_parameters.cpp + test_save_results.cpp + ) endif() add_executable(memilio-test ${TESTSOURCES}) diff --git a/cpp/tests/test_graph_abm.cpp b/cpp/tests/test_graph_abm.cpp new file mode 100644 index 0000000000..f9450abf5c --- /dev/null +++ b/cpp/tests/test_graph_abm.cpp @@ -0,0 +1,43 @@ +/* +* Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) +* +* Authors: Julia Bicker, Martin J. Kuehn +* +* 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 "models/graph_abm/graph_world.h" +#include "models/abm/world.h" +#include "models/abm/person.h" +#include "abm_helpers.h" +#include + +TEST(TestGraphWorld, test_find_location) +{ + mio::abm::GlobalInfectionParameters infection_params; + //auto world = mio::abm::World(infection_params, 0); + auto world1 = mio::graph_abm::GraphWorld(infection_params, 0); + auto world2 = mio::graph_abm::GraphWorld(infection_params, 1); + auto loc1 = world1.add_location(mio::abm::LocationType::Home); + auto loc2 = world2.add_location(mio::abm::LocationType::Work); + auto& loc = world1.get_individualized_location(loc1); + mio::unused(loc); + // auto person = mio::abm::Person(loc, mio::abm::AgeGroup::Age35to59, 0, 0); + // person.set_assigned_location(loc1); + // person.set_assigned_location(loc2); + // auto& found_loc1 = world1.find_location(mio::abm::LocationType::Home, person); + // auto& found_loc2 = world1.find_location(mio::abm::LocationType::Work, person); + // ASSERT_EQ(found_loc1, loc1); + // ASSERT_EQ(found_loc2, loc2); +} \ No newline at end of file From dd6ac0e5f14fbbd02d6cbcc7eafea8a259c0b7af Mon Sep 17 00:00:00 2001 From: jubicker Date: Fri, 9 Jun 2023 08:20:33 +0200 Subject: [PATCH 17/38] test find location --- cpp/models/graph_abm/graph_world.cpp | 22 ++-------------------- cpp/tests/test_graph_abm.cpp | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/cpp/models/graph_abm/graph_world.cpp b/cpp/models/graph_abm/graph_world.cpp index db3993dca0..8c680a2b79 100644 --- a/cpp/models/graph_abm/graph_world.cpp +++ b/cpp/models/graph_abm/graph_world.cpp @@ -30,31 +30,13 @@ mio::abm::Location& GraphWorld::find_location(mio::abm::LocationType type, const { auto index = person.get_assigned_location_index(type); auto world_id = person.get_assigned_location_world_id(type); - if (world_id == Base::m_world_id) { - return Base::get_individualized_location({index, type, world_id}); - } - else { //location is in other world - mio::abm::Location loc = mio::abm::Location(type, index, world_id); - auto iter = std::find_if(m_locations_external.begin(), m_locations_external.end(), - [loc](const std::unique_ptr& loc_ext) { - return ((loc.get_type() == loc_ext->get_type()) && - (loc.get_index() == loc_ext->get_index()) && - (loc.get_world_id() == loc_ext->get_world_id())); - }); - if (iter != m_locations_external.end()) { - return *(*iter); - } - else { - m_locations_external.emplace_back(std::make_unique(loc)); - return *m_locations_external.back(); - } - } + return get_individualized_location({index, type, world_id}); } mio::abm::Location& GraphWorld::get_individualized_location(mio::abm::LocationId id) { if (id.world_id == Base::m_world_id) { - return *m_locations[id.index]; + return *Base::m_locations[id.index]; } else { mio::abm::Location loc = mio::abm::Location(id.type, id.index, id.world_id); diff --git a/cpp/tests/test_graph_abm.cpp b/cpp/tests/test_graph_abm.cpp index f9450abf5c..39280d573e 100644 --- a/cpp/tests/test_graph_abm.cpp +++ b/cpp/tests/test_graph_abm.cpp @@ -18,26 +18,24 @@ * limitations under the License. */ #include "models/graph_abm/graph_world.h" +#include "models/graph_abm/graph_world.cpp" #include "models/abm/world.h" #include "models/abm/person.h" #include "abm_helpers.h" -#include +//#include TEST(TestGraphWorld, test_find_location) { mio::abm::GlobalInfectionParameters infection_params; - //auto world = mio::abm::World(infection_params, 0); auto world1 = mio::graph_abm::GraphWorld(infection_params, 0); auto world2 = mio::graph_abm::GraphWorld(infection_params, 1); - auto loc1 = world1.add_location(mio::abm::LocationType::Home); - auto loc2 = world2.add_location(mio::abm::LocationType::Work); - auto& loc = world1.get_individualized_location(loc1); - mio::unused(loc); - // auto person = mio::abm::Person(loc, mio::abm::AgeGroup::Age35to59, 0, 0); - // person.set_assigned_location(loc1); - // person.set_assigned_location(loc2); - // auto& found_loc1 = world1.find_location(mio::abm::LocationType::Home, person); - // auto& found_loc2 = world1.find_location(mio::abm::LocationType::Work, person); - // ASSERT_EQ(found_loc1, loc1); - // ASSERT_EQ(found_loc2, loc2); + auto home = world1.add_location(mio::abm::LocationType::Home); + auto work = world2.add_location(mio::abm::LocationType::Work); + auto person = mio::abm::Person(world1.get_individualized_location({0, mio::abm::LocationType::Home, 0}), mio::abm::AgeGroup::Age35to59, 0, 0); + person.set_assigned_location(home); + person.set_assigned_location(work); + auto& found_home = world1.find_location(mio::abm::LocationType::Home, person); + auto& found_work = world1.find_location(mio::abm::LocationType::Work, person); + ASSERT_EQ(found_home, home); + ASSERT_EQ(found_work, work); } \ No newline at end of file From 9d8711bf53884ab61a29d7396b4d64b32e456187 Mon Sep 17 00:00:00 2001 From: jubicker Date: Fri, 9 Jun 2023 08:22:56 +0200 Subject: [PATCH 18/38] include --- cpp/tests/test_graph_abm.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/tests/test_graph_abm.cpp b/cpp/tests/test_graph_abm.cpp index 39280d573e..790ecf35ea 100644 --- a/cpp/tests/test_graph_abm.cpp +++ b/cpp/tests/test_graph_abm.cpp @@ -22,7 +22,7 @@ #include "models/abm/world.h" #include "models/abm/person.h" #include "abm_helpers.h" -//#include +#include TEST(TestGraphWorld, test_find_location) { @@ -31,7 +31,8 @@ TEST(TestGraphWorld, test_find_location) auto world2 = mio::graph_abm::GraphWorld(infection_params, 1); auto home = world1.add_location(mio::abm::LocationType::Home); auto work = world2.add_location(mio::abm::LocationType::Work); - auto person = mio::abm::Person(world1.get_individualized_location({0, mio::abm::LocationType::Home, 0}), mio::abm::AgeGroup::Age35to59, 0, 0); + auto person = mio::abm::Person(world1.get_individualized_location({0, mio::abm::LocationType::Home, 0}), + mio::abm::AgeGroup::Age35to59, 0, 0); person.set_assigned_location(home); person.set_assigned_location(work); auto& found_home = world1.find_location(mio::abm::LocationType::Home, person); From 5a462a6df43df1fbc8b9255c32bb7517eecb8461 Mon Sep 17 00:00:00 2001 From: jubicker Date: Fri, 30 Jun 2023 16:21:34 +0200 Subject: [PATCH 19/38] fix migration for trips and add migration test --- cpp/models/abm/trip_list.h | 3 +- cpp/models/graph_abm/graph_world.cpp | 18 ++- cpp/models/graph_abm/graph_world.h | 2 +- cpp/tests/test_graph_abm.cpp | 191 ++++++++++++++++++++++++++- 4 files changed, 204 insertions(+), 10 deletions(-) diff --git a/cpp/models/abm/trip_list.h b/cpp/models/abm/trip_list.h index 4a1748561f..8ec00ad0bc 100644 --- a/cpp/models/abm/trip_list.h +++ b/cpp/models/abm/trip_list.h @@ -57,9 +57,10 @@ struct Trip { * @param[in] input_cells The index of the Cell%s the Person migrates to. */ Trip(uint32_t id, TimePoint time_new, LocationId destination, LocationId origin, - const std::vector& input_cells = {}) + const std::vector& input_cells = {}, uint32_t world_id = 0) { person_id = id; + person_world_id = world_id; time = time_new; migration_destination = destination; migration_origin = origin; diff --git a/cpp/models/graph_abm/graph_world.cpp b/cpp/models/graph_abm/graph_world.cpp index 8c680a2b79..18475259ba 100644 --- a/cpp/models/graph_abm/graph_world.cpp +++ b/cpp/models/graph_abm/graph_world.cpp @@ -61,12 +61,13 @@ void GraphWorld::add_existing_person(std::unique_ptr&& person) Base::m_persons.push_back(std::move(person)); } -std::unique_ptr& GraphWorld::get_person(uint32_t person_id, uint32_t person_world_id) +std::vector>::iterator GraphWorld::get_person(uint32_t person_id, + uint32_t person_world_id) { - return *std::find_if(Base::m_persons.begin(), Base::m_persons.end(), - [person_id, person_world_id](const std::unique_ptr& person) { - return (person_id == person->get_person_id() && person_world_id == person->get_world_id()); - }); + return std::find_if(Base::m_persons.begin(), Base::m_persons.end(), + [person_id, person_world_id](const std::unique_ptr& person) { + return (person_id == person->get_person_id() && person_world_id == person->get_world_id()); + }); } void GraphWorld::migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt) @@ -106,7 +107,9 @@ void GraphWorld::migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt) if (num_trips != 0) { while (m_trip_list.get_current_index() < num_trips && m_trip_list.get_next_trip_time() < t + dt) { auto& trip = m_trip_list.get_next_trip(); - auto& person = get_person(trip.person_id, trip.person_world_id); + auto person_iterator = get_person(trip.person_id, trip.person_world_id); + auto& person = *person_iterator; + auto person_index = person_iterator - Base::m_persons.begin(); auto current_location = person->get_location(); if (!person->is_in_quarantine() && current_location == get_individualized_location(trip.migration_origin)) { auto& target_location = get_individualized_location(trip.migration_destination); @@ -116,7 +119,8 @@ void GraphWorld::migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt) //person changes world person->migrate_to_other_world(target_location, false); m_persons_to_migrate.push_back(std::move(person)); - Base::m_persons.erase(Base::m_persons.begin() + trip.person_id); + //TODO: hier ist das problem + Base::m_persons.erase(Base::m_persons.begin() + person_index); } else { person->migrate_to(target_location); diff --git a/cpp/models/graph_abm/graph_world.h b/cpp/models/graph_abm/graph_world.h index 1617153713..2a7d84a555 100644 --- a/cpp/models/graph_abm/graph_world.h +++ b/cpp/models/graph_abm/graph_world.h @@ -85,7 +85,7 @@ class GraphWorld : public mio::abm::World * @param[in] person_id PersonId of the Person. * @return Reference to unique pointer in m_persons. */ - std::unique_ptr& get_person(uint32_t person_id, uint32_t person_world_id); + std::vector>::iterator get_person(uint32_t person_id, uint32_t person_world_id); private: //persons that will migrate to other worlds diff --git a/cpp/tests/test_graph_abm.cpp b/cpp/tests/test_graph_abm.cpp index 790ecf35ea..549e1814f4 100644 --- a/cpp/tests/test_graph_abm.cpp +++ b/cpp/tests/test_graph_abm.cpp @@ -39,4 +39,193 @@ TEST(TestGraphWorld, test_find_location) auto& found_work = world1.find_location(mio::abm::LocationType::Work, person); ASSERT_EQ(found_home, home); ASSERT_EQ(found_work, work); -} \ No newline at end of file +} + +TEST(TestGraphWorld, test_evolve_state_transition) +{ + using testing::Return; + + auto t = mio::abm::TimePoint(0); + auto dt = mio::abm::hours(1); + + auto params = mio::abm::GlobalInfectionParameters{}; + //setup so p1 and p3 don't transition + params.get()[{mio::abm::VirusVariant::Wildtype, mio::abm::AgeGroup::Age15to34, + mio::abm::VaccinationState::Unvaccinated}] = 2 * dt.days(); + params.get()[{mio::abm::VirusVariant::Wildtype, mio::abm::AgeGroup::Age15to34, + mio::abm::VaccinationState::Unvaccinated}] = 2 * dt.days(); + params.get()[{mio::abm::VirusVariant::Wildtype, mio::abm::AgeGroup::Age15to34, + mio::abm::VaccinationState::Unvaccinated}] = 2 * dt.days(); + params.get()[{mio::abm::VirusVariant::Wildtype, mio::abm::AgeGroup::Age15to34, + mio::abm::VaccinationState::Unvaccinated}] = 2 * dt.days(); + params.get()[{mio::abm::VirusVariant::Wildtype, mio::abm::AgeGroup::Age15to34, + mio::abm::VaccinationState::Unvaccinated}] = 2 * dt.days(); + + auto world = mio::graph_abm::GraphWorld(params, 0); + auto location1 = world.add_location(mio::abm::LocationType::School); + auto& p1 = add_test_person(world, location1, mio::abm::AgeGroup::Age15to34, mio::abm::InfectionState::Infected); + auto& p2 = add_test_person(world, location1, mio::abm::AgeGroup::Age15to34, mio::abm::InfectionState::Susceptible); + p1.set_assigned_location(location1); + p2.set_assigned_location(location1); + + //setup mock so p2 becomes infected + ScopedMockDistribution>>> + mock_exponential_dist; + EXPECT_CALL(mock_exponential_dist.get_mock(), invoke).Times(1).WillOnce(Return(0.0)); + + world.evolve(t, dt); + + EXPECT_EQ(p1.get_infection_state(t + dt), mio::abm::InfectionState::Infected); + EXPECT_EQ(p2.get_infection_state(t + dt), mio::abm::InfectionState::Exposed); +} + +TEST(TestGraphWorld, test_evolve_migration) +{ + using testing::Return; + + { //test migration rules + auto t = mio::abm::TimePoint(0) + mio::abm::hours(6); + auto dt = mio::abm::hours(1); + + auto params = mio::abm::GlobalInfectionParameters{}; + + auto world1 = mio::graph_abm::GraphWorld(params, 0); + auto world2 = mio::graph_abm::GraphWorld(params, 1); + //home and school are in world1 + auto home_id = world1.add_location(mio::abm::LocationType::Home); + auto school_id = world1.add_location(mio::abm::LocationType::School); + //work is in world2 + auto work_id = world2.add_location(mio::abm::LocationType::Work); + + ScopedMockDistribution>>> + mock_uniform_dist; + EXPECT_CALL(mock_uniform_dist.get_mock(), invoke) + .Times(testing::AtLeast(8)) + .WillOnce(testing::Return(0.0)) // draw random work group + .WillOnce(testing::Return(0.0)) // draw random school group + .WillOnce(testing::Return(0.0)) // draw random work hour + .WillOnce(testing::Return(0.0)) // draw random school hour + .WillOnce(testing::Return(0.0)) // draw random work group + .WillOnce(testing::Return(0.0)) // draw random school group + .WillOnce(testing::Return(0.0)) // draw random work hour + .WillOnce(testing::Return(0.0)) // draw random school hour + .WillRepeatedly(testing::Return(1.0)); + + auto& p1 = + add_test_person(world1, home_id, mio::abm::AgeGroup::Age15to34, mio::abm::InfectionState::Susceptible, t); + auto& p2 = + add_test_person(world1, home_id, mio::abm::AgeGroup::Age5to14, mio::abm::InfectionState::Susceptible, t); + + p1.set_assigned_location(home_id); + p2.set_assigned_location(home_id); + p1.set_assigned_location(work_id); + p2.set_assigned_location(school_id); + + world1.evolve(t, dt); + world2.evolve(t, dt); + + auto& school = world1.get_individualized_location(school_id); + auto& work = world1.get_individualized_location(work_id); + + EXPECT_EQ(p1.get_location(), work); + EXPECT_EQ(p2.get_location(), school); + EXPECT_EQ(school.get_number_persons(), 1); + EXPECT_EQ(work.get_number_persons(), 1); + + EXPECT_EQ(world1.get_persons_to_migrate().size(), 1); + } + { //test trips + auto t = mio::abm::TimePoint(0) + mio::abm::hours(8); + auto dt = mio::abm::hours(2); + + auto params = mio::abm::GlobalInfectionParameters{}; + + //setup so p1-p5 don't transition + params.get()[{mio::abm::VirusVariant::Wildtype, mio::abm::AgeGroup::Age15to34, + mio::abm::VaccinationState::Unvaccinated}] = 2 * dt.days(); + params.get()[{mio::abm::VirusVariant::Wildtype, mio::abm::AgeGroup::Age15to34, + mio::abm::VaccinationState::Unvaccinated}] = 2 * dt.days(); + params.get()[{mio::abm::VirusVariant::Wildtype, mio::abm::AgeGroup::Age15to34, + mio::abm::VaccinationState::Unvaccinated}] = 2 * dt.days(); + params.get()[{mio::abm::VirusVariant::Wildtype, mio::abm::AgeGroup::Age15to34, + mio::abm::VaccinationState::Unvaccinated}] = 2 * dt.days(); + + auto world1 = mio::graph_abm::GraphWorld(params, 0); + auto world2 = mio::graph_abm::GraphWorld(params, 1); + world1.use_migration_rules(false); + world2.use_migration_rules(false); + //home is in world1 + auto home_id = world1.add_location(mio::abm::LocationType::Home); + //other locations are in world2 + auto event_id = world2.add_location(mio::abm::LocationType::SocialEvent); + auto work_id = world2.add_location(mio::abm::LocationType::Work); + auto hospital_id = world2.add_location(mio::abm::LocationType::Hospital); + + //create persons + auto& p1 = + add_test_person(world1, home_id, mio::abm::AgeGroup::Age15to34, mio::abm::InfectionState::Susceptible, t); + auto& p2 = + add_test_person(world1, home_id, mio::abm::AgeGroup::Age5to14, mio::abm::InfectionState::Susceptible, t); + auto& p3 = add_test_person(world1, home_id, mio::abm::AgeGroup::Age5to14, + mio::abm::InfectionState::Infected_Severe, t); + auto& p4 = + add_test_person(world1, home_id, mio::abm::AgeGroup::Age15to34, mio::abm::InfectionState::Susceptible, t); + auto& p5 = + add_test_person(world1, home_id, mio::abm::AgeGroup::Age15to34, mio::abm::InfectionState::Susceptible, t); + + p1.set_assigned_location(home_id); + p1.set_assigned_location(work_id); + p1.set_assigned_location(event_id); + p2.set_assigned_location(home_id); + p2.set_assigned_location(event_id); + p3.set_assigned_location(home_id); + p3.set_assigned_location(hospital_id); + p4.set_assigned_location(home_id); + p4.set_assigned_location(work_id); + p4.set_assigned_location(event_id); + p5.set_assigned_location(home_id); + p5.set_assigned_location(work_id); + p5.set_assigned_location(event_id); + + mio::abm::TripList& trip_list = world1.get_trip_list(); + mio::abm::Trip trip1(p1.get_person_id(), mio::abm::TimePoint(0) + mio::abm::hours(9), work_id, home_id, {}, + p1.get_world_id()); + mio::abm::Trip trip2(p2.get_person_id(), mio::abm::TimePoint(0) + mio::abm::hours(9), event_id, home_id, {}, + p2.get_world_id()); + mio::abm::Trip trip3(p4.get_person_id(), mio::abm::TimePoint(0) + mio::abm::hours(9), event_id, home_id, {}, + p4.get_world_id()); + mio::abm::Trip trip4(p5.get_person_id(), mio::abm::TimePoint(0) + mio::abm::hours(9), event_id, work_id, {}, + p5.get_world_id()); + trip_list.add_trip(trip1); + trip_list.add_trip(trip2); + trip_list.add_trip(trip3); + trip_list.add_trip(trip4); + + mio::unused(trip1); + mio::unused(trip_list); + + ScopedMockDistribution>>> + mock_exponential_dist; + EXPECT_CALL(mock_exponential_dist.get_mock(), invoke).WillRepeatedly(Return(1.)); //no state transitions + + world1.evolve(t, dt); + world2.evolve(t, dt); + + auto& event = world1.get_individualized_location(event_id); + auto& work = world1.get_individualized_location(work_id); + auto& home = world1.get_individualized_location(home_id); + auto& hospital = world1.get_individualized_location(hospital_id); + + EXPECT_EQ(p1.get_location(), work); + EXPECT_EQ(p2.get_location(), event); + EXPECT_EQ(p3.get_location(), hospital); + EXPECT_EQ(p4.get_location(), event); + EXPECT_EQ(p5.get_location(), home); + EXPECT_EQ(event.get_number_persons(), 2); + EXPECT_EQ(work.get_number_persons(), 1); + EXPECT_EQ(home.get_number_persons(), 1); + EXPECT_EQ(hospital.get_number_persons(), 1); + + EXPECT_EQ(world1.get_persons_to_migrate().size(), 4); + } +} From 86cfd7f2aaefb3b49461859eb3b83f219e2295a0 Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 5 Jul 2023 11:24:43 +0200 Subject: [PATCH 20/38] test graph simulation --- cpp/tests/CMakeLists.txt | 1 + cpp/tests/test_abm_graph_simulation.cpp | 110 ++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 cpp/tests/test_abm_graph_simulation.cpp diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 221b952e32..ae6c519c07 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -21,6 +21,7 @@ set(TESTSOURCES test_graph.cpp test_graph_simulation.cpp test_graph_abm.cpp + test_abm_graph_simulation.cpp test_stl_util.cpp test_uncertain.cpp test_random_number_generator.cpp diff --git a/cpp/tests/test_abm_graph_simulation.cpp b/cpp/tests/test_abm_graph_simulation.cpp new file mode 100644 index 0000000000..80153046b2 --- /dev/null +++ b/cpp/tests/test_abm_graph_simulation.cpp @@ -0,0 +1,110 @@ +/* +* Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) +* +* Authors: Daniel Abele, Elisabeth Kluth, David Kerkmann, Sascha Korf, Martin J. Kuehn, 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 "models/graph_abm/graph_world.h" +#include "models/abm/world.h" +#include "models/abm/person.h" +#include "models/graph_abm/graph_simulation.h" +#include "abm_helpers.h" + +TEST(TestGraphSimulation, advance_random) +{ + mio::abm::GlobalInfectionParameters infection_params; + auto world = mio::graph_abm::GraphWorld(infection_params, 0); + auto location1 = world.add_location(mio::abm::LocationType::School); + auto location2 = world.add_location(mio::abm::LocationType::School); + auto& p1 = world.add_person(location1, mio::abm::AgeGroup::Age5to14); + auto& p2 = world.add_person(location1, mio::abm::AgeGroup::Age5to14); + auto& p3 = world.add_person(location2, mio::abm::AgeGroup::Age5to14); + auto& p4 = world.add_person(location2, mio::abm::AgeGroup::Age5to14); + p1.set_assigned_location(location1); + p2.set_assigned_location(location1); + p3.set_assigned_location(location2); + p4.set_assigned_location(location2); + + auto t0 = mio::abm::TimePoint(0); + + auto sim = mio::graph_abm::GraphSimulation(t0, std::move(world)); + + //auto sim = mio::graph_abm::GraphSimulation(mio::abm::TimePoint(0), std::move(world)); + + // sim.advance(mio::abm::TimePoint(0) + mio::abm::hours(50)); + // ASSERT_EQ(sim.get_result().get_num_time_points(), 51); + // ASSERT_THAT(sim.get_result().get_times(), ElementsAreLinspace(0.0, 50.0 / 24.0, 51)); + // for (auto&& v : sim.get_result()) { + // ASSERT_EQ(v.sum(), 4); + // } +} + +// TEST(TestDiscreteDistribution, generate) +// { +// using namespace mio; +// auto distribution = mio::DiscreteDistribution(); + +// std::vector weights; +// for (size_t i = 0; i < 50; i++) { +// weights = {}; +// ASSERT_EQ(distribution(weights), 0); + +// weights = {0.5}; +// ASSERT_EQ(distribution(weights), 0); + +// weights = {0.5, 1.3, 0.1, 0.4, 0.3}; +// auto d = distribution(weights); +// ASSERT_GE(d, 0); +// ASSERT_LE(d, 4); +// } +// } + +// TEST(TestSimulation, advance_subpopulation) +// { +// auto world = mio::abm::World(); +// auto location_id = world.add_location(mio::abm::LocationType::School); +// auto& school = world.get_individualized_location(location_id); +// auto person1 = +// add_test_person(world, location_id, mio::abm::AgeGroup::Age5to14, mio::abm::InfectionState::Infected); +// auto person2 = +// add_test_person(world, location_id, mio::abm::AgeGroup::Age15to34, mio::abm::InfectionState::Infected); +// auto person3 = +// add_test_person(world, location_id, mio::abm::AgeGroup::Age35to59, mio::abm::InfectionState::Exposed); + +// auto sim = mio::abm::Simulation(mio::abm::TimePoint(0), std::move(world)); +// sim.advance(mio::abm::TimePoint(0) + mio::abm::hours(50)); + +// for (size_t i = 0; i < 51; i++) { +// auto v = school.get_subpopulations().get_value(i); +// // Check whether the number of persons in infected state at the location is consistent +// ASSERT_LE(v[size_t(mio::abm::InfectionState::Infected)], 3); +// // Check the time evolution is correct +// ASSERT_EQ(school.get_subpopulations().get_time(i), ScalarType(i) / 24); +// } +// } + +// TEST(TestSimulation, initializeSubpopulation) +// { +// auto world = mio::abm::World(); +// auto loc_id = world.add_location(mio::abm::LocationType::PublicTransport, 3); +// auto loc = world.get_individualized_location(loc_id); +// ASSERT_EQ(loc.get_subpopulations().get_num_time_points(), 0); + +// auto t = mio::abm::TimePoint(0); +// auto sim = mio::abm::Simulation(t + mio::abm::days(7), std::move(world)); + +// ASSERT_EQ(sim.get_world().get_individualized_location(loc_id).get_subpopulations().get_time(0), 7); +// } From 17cebc75eba8be35ebc226dee73367190dcc7545 Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 5 Jul 2023 15:42:42 +0200 Subject: [PATCH 21/38] test simulation --- .../metapopulation_mobility_instant.h | 3 - cpp/tests/test_abm_graph_simulation.cpp | 108 ++++++++---------- 2 files changed, 46 insertions(+), 65 deletions(-) diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index aceab5412c..e650ae1598 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -326,9 +326,6 @@ template & node_from, SimulationNode& node_to) { - if (t == mio::abm::TimePoint(0) + mio::abm::days(10)) { - std::cout << "max"; - } mio::unused(t); mio::unused(dt); size_t person_iter = 0; diff --git a/cpp/tests/test_abm_graph_simulation.cpp b/cpp/tests/test_abm_graph_simulation.cpp index 80153046b2..5c41ad0278 100644 --- a/cpp/tests/test_abm_graph_simulation.cpp +++ b/cpp/tests/test_abm_graph_simulation.cpp @@ -21,6 +21,7 @@ #include "models/abm/world.h" #include "models/abm/person.h" #include "models/graph_abm/graph_simulation.h" +#include "models/graph_abm/graph_simulation.cpp" #include "abm_helpers.h" TEST(TestGraphSimulation, advance_random) @@ -29,6 +30,7 @@ TEST(TestGraphSimulation, advance_random) auto world = mio::graph_abm::GraphWorld(infection_params, 0); auto location1 = world.add_location(mio::abm::LocationType::School); auto location2 = world.add_location(mio::abm::LocationType::School); + auto home = world.add_location(mio::abm::LocationType::Home); auto& p1 = world.add_person(location1, mio::abm::AgeGroup::Age5to14); auto& p2 = world.add_person(location1, mio::abm::AgeGroup::Age5to14); auto& p3 = world.add_person(location2, mio::abm::AgeGroup::Age5to14); @@ -37,74 +39,56 @@ TEST(TestGraphSimulation, advance_random) p2.set_assigned_location(location1); p3.set_assigned_location(location2); p4.set_assigned_location(location2); + p1.set_assigned_location(home); + p2.set_assigned_location(home); + p3.set_assigned_location(home); + p4.set_assigned_location(home); - auto t0 = mio::abm::TimePoint(0); + auto sim = mio::graph_abm::GraphSimulation(mio::abm::TimePoint(0), std::move(world)); - auto sim = mio::graph_abm::GraphSimulation(t0, std::move(world)); - - //auto sim = mio::graph_abm::GraphSimulation(mio::abm::TimePoint(0), std::move(world)); - - // sim.advance(mio::abm::TimePoint(0) + mio::abm::hours(50)); - // ASSERT_EQ(sim.get_result().get_num_time_points(), 51); - // ASSERT_THAT(sim.get_result().get_times(), ElementsAreLinspace(0.0, 50.0 / 24.0, 51)); - // for (auto&& v : sim.get_result()) { - // ASSERT_EQ(v.sum(), 4); - // } + sim.advance(mio::abm::TimePoint(0) + mio::abm::hours(18)); + ASSERT_EQ(sim.get_result().get_num_time_points(), 19); + ASSERT_THAT(sim.get_result().get_times(), ElementsAreLinspace(0.0, 18.0 / 24.0, 19)); + for (auto&& v : sim.get_result()) { + ASSERT_EQ(v.sum(), 4); + } } -// TEST(TestDiscreteDistribution, generate) -// { -// using namespace mio; -// auto distribution = mio::DiscreteDistribution(); - -// std::vector weights; -// for (size_t i = 0; i < 50; i++) { -// weights = {}; -// ASSERT_EQ(distribution(weights), 0); - -// weights = {0.5}; -// ASSERT_EQ(distribution(weights), 0); - -// weights = {0.5, 1.3, 0.1, 0.4, 0.3}; -// auto d = distribution(weights); -// ASSERT_GE(d, 0); -// ASSERT_LE(d, 4); -// } -// } - -// TEST(TestSimulation, advance_subpopulation) -// { -// auto world = mio::abm::World(); -// auto location_id = world.add_location(mio::abm::LocationType::School); -// auto& school = world.get_individualized_location(location_id); -// auto person1 = -// add_test_person(world, location_id, mio::abm::AgeGroup::Age5to14, mio::abm::InfectionState::Infected); -// auto person2 = -// add_test_person(world, location_id, mio::abm::AgeGroup::Age15to34, mio::abm::InfectionState::Infected); -// auto person3 = -// add_test_person(world, location_id, mio::abm::AgeGroup::Age35to59, mio::abm::InfectionState::Exposed); +TEST(TestGraphSimulation, advance_subpopulation) +{ + mio::abm::GlobalInfectionParameters infection_params; + auto world = mio::graph_abm::GraphWorld(infection_params, 0); + auto location_id = world.add_location(mio::abm::LocationType::School); + auto& school = world.get_individualized_location(location_id); + auto person1 = + add_test_person(world, location_id, mio::abm::AgeGroup::Age5to14, mio::abm::InfectionState::Infected); + auto person2 = + add_test_person(world, location_id, mio::abm::AgeGroup::Age15to34, mio::abm::InfectionState::Infected); + auto person3 = + add_test_person(world, location_id, mio::abm::AgeGroup::Age35to59, mio::abm::InfectionState::Exposed); -// auto sim = mio::abm::Simulation(mio::abm::TimePoint(0), std::move(world)); -// sim.advance(mio::abm::TimePoint(0) + mio::abm::hours(50)); + auto sim = mio::graph_abm::GraphSimulation(mio::abm::TimePoint(0), std::move(world)); + sim.advance(mio::abm::TimePoint(0) + mio::abm::hours(50)); -// for (size_t i = 0; i < 51; i++) { -// auto v = school.get_subpopulations().get_value(i); -// // Check whether the number of persons in infected state at the location is consistent -// ASSERT_LE(v[size_t(mio::abm::InfectionState::Infected)], 3); -// // Check the time evolution is correct -// ASSERT_EQ(school.get_subpopulations().get_time(i), ScalarType(i) / 24); -// } -// } + for (size_t i = 0; i < 51; i++) { + auto v = school.get_subpopulations().get_value(i); + // Check whether the number of persons in infected state at the location is consistent + ASSERT_LE(v[size_t(mio::abm::InfectionState::Infected)], 3); + // Check the time evolution is correct + ASSERT_EQ(school.get_subpopulations().get_time(i), ScalarType(i) / 24); + } +} -// TEST(TestSimulation, initializeSubpopulation) -// { -// auto world = mio::abm::World(); -// auto loc_id = world.add_location(mio::abm::LocationType::PublicTransport, 3); -// auto loc = world.get_individualized_location(loc_id); -// ASSERT_EQ(loc.get_subpopulations().get_num_time_points(), 0); +TEST(TestGraphSimulation, initializeSubpopulation) +{ + mio::abm::GlobalInfectionParameters infection_params; + auto world = mio::graph_abm::GraphWorld(infection_params, 0); + auto loc_id = world.add_location(mio::abm::LocationType::PublicTransport); + auto loc = world.get_individualized_location(loc_id); + ASSERT_EQ(loc.get_subpopulations().get_num_time_points(), 0); -// auto t = mio::abm::TimePoint(0); -// auto sim = mio::abm::Simulation(t + mio::abm::days(7), std::move(world)); + auto t = mio::abm::TimePoint(0); + auto sim = mio::abm::Simulation(t + mio::abm::days(7), std::move(world)); -// ASSERT_EQ(sim.get_world().get_individualized_location(loc_id).get_subpopulations().get_time(0), 7); -// } + ASSERT_EQ(sim.get_world().get_individualized_location(loc_id).get_subpopulations().get_time(0), 7); +} From b46250b8e5b059afc6760466c3a3f6cb897697d4 Mon Sep 17 00:00:00 2001 From: jubicker Date: Thu, 6 Jul 2023 16:52:46 +0200 Subject: [PATCH 22/38] test add person and migration --- cpp/tests/test_graph_abm.cpp | 17 ++++++++++++ cpp/tests/test_mobility.cpp | 50 ++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/cpp/tests/test_graph_abm.cpp b/cpp/tests/test_graph_abm.cpp index 549e1814f4..000a009ba6 100644 --- a/cpp/tests/test_graph_abm.cpp +++ b/cpp/tests/test_graph_abm.cpp @@ -229,3 +229,20 @@ TEST(TestGraphWorld, test_evolve_migration) EXPECT_EQ(world1.get_persons_to_migrate().size(), 4); } } + +TEST(TestGraphWorld, test_add_existing_person) +{ + auto params = mio::abm::GlobalInfectionParameters{}; + auto world = mio::graph_abm::GraphWorld(params, 0); + + auto loc = mio::abm::Location(mio::abm::LocationType::Home, 0, 0); + auto person_ptr = std::make_unique(loc, mio::abm::AgeGroup::Age35to59, 0, 0); + world.add_existing_person(std::move(person_ptr)); + + EXPECT_EQ(world.get_persons().size(), 1); + auto& person = *world.get_person(0, 0); + mio::unused(person); + EXPECT_EQ(person->get_person_id(), 0U); + EXPECT_EQ(person->get_world_id(), 0U); + EXPECT_EQ(person->get_age(), mio::abm::AgeGroup::Age35to59); +} diff --git a/cpp/tests/test_mobility.cpp b/cpp/tests/test_mobility.cpp index 56b04e8fad..3f2c6d9cea 100644 --- a/cpp/tests/test_mobility.cpp +++ b/cpp/tests/test_mobility.cpp @@ -27,6 +27,7 @@ #include "memilio/math/eigen_util.h" #include "memilio/math/eigen.h" #include "memilio/compartments/simulation.h" +#include "graph_abm/graph_world.h" #include "matchers.h" #include "gtest/gtest.h" @@ -167,3 +168,52 @@ TEST(TestMobility, edgeApplyMigration) EXPECT_DOUBLE_EQ(node1.get_result().get_last_value().sum(), 900); EXPECT_DOUBLE_EQ(node2.get_result().get_last_value().sum(), 1100); } + +TEST(TestMobility, ABMEdgeApplyMigration) +{ + mio::abm::GlobalInfectionParameters infection_params; + auto world1 = mio::graph_abm::GraphWorld(infection_params, 0); + auto world2 = mio::graph_abm::GraphWorld(infection_params, 1); + + //add locations + auto home = world1.add_location(mio::abm::LocationType::Home); + auto work = world2.add_location(mio::abm::LocationType::Work); + auto school = world2.add_location(mio::abm::LocationType::School); + world1.add_person(home, mio::abm::AgeGroup::Age5to14); + world1.add_person(home, mio::abm::AgeGroup::Age35to59); + + for (auto& person : world1.get_persons()) { + person.set_assigned_location(home); + if (person.get_age() == mio::abm::AgeGroup::Age5to14) { + person.set_assigned_location(school); + } + else { + person.set_assigned_location(work); + } + } + + auto t0 = mio::abm::TimePoint(0); + auto dt = mio::abm::hours(12); + auto tmax = mio::abm::TimePoint(0) + mio::abm::days(10); + + mio::SimulationNode node1(t0, std::move(world1)); + mio::SimulationNode node2(t0, std::move(world2)); + + mio::MigrationEdgeABM edge; + + EXPECT_EQ(node1.get_simulation().get_graph_world().get_persons_to_migrate().size(), 0); + EXPECT_EQ(node1.get_simulation().get_graph_world().get_persons().size(), 2); + EXPECT_EQ(node2.get_simulation().get_graph_world().get_persons().size(), 0); + + node1.evolve(t0, dt); + node2.evolve(t0, dt); + + EXPECT_EQ(node1.get_simulation().get_graph_world().get_persons_to_migrate().size(), 2); + EXPECT_EQ(node1.get_simulation().get_graph_world().get_persons().size(), 0); + EXPECT_EQ(node2.get_simulation().get_graph_world().get_persons().size(), 0); + t0 += dt; + edge.apply_migration(t0, dt, node1, node2); + EXPECT_EQ(node1.get_simulation().get_graph_world().get_persons_to_migrate().size(), 0); + EXPECT_EQ(node1.get_simulation().get_graph_world().get_persons().size(), 0); + EXPECT_EQ(node2.get_simulation().get_graph_world().get_persons().size(), 2); +} From ea19c85cd9f91e2dbe6257a570dfb8a0c230e0d3 Mon Sep 17 00:00:00 2001 From: jubicker Date: Fri, 7 Jul 2023 08:40:42 +0200 Subject: [PATCH 23/38] test advance and migrate to --- cpp/tests/test_abm_graph_simulation.cpp | 30 ++++++++++++++++++++++--- cpp/tests/test_abm_person.cpp | 18 +++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/cpp/tests/test_abm_graph_simulation.cpp b/cpp/tests/test_abm_graph_simulation.cpp index 5c41ad0278..1ee09e2fc4 100644 --- a/cpp/tests/test_abm_graph_simulation.cpp +++ b/cpp/tests/test_abm_graph_simulation.cpp @@ -22,6 +22,8 @@ #include "models/abm/person.h" #include "models/graph_abm/graph_simulation.h" #include "models/graph_abm/graph_simulation.cpp" +#include "memilio/mobility/graph_simulation.h" +#include "memilio/mobility/metapopulation_mobility_instant.h" #include "abm_helpers.h" TEST(TestGraphSimulation, advance_random) @@ -30,7 +32,7 @@ TEST(TestGraphSimulation, advance_random) auto world = mio::graph_abm::GraphWorld(infection_params, 0); auto location1 = world.add_location(mio::abm::LocationType::School); auto location2 = world.add_location(mio::abm::LocationType::School); - auto home = world.add_location(mio::abm::LocationType::Home); + auto home = world.add_location(mio::abm::LocationType::Home); auto& p1 = world.add_person(location1, mio::abm::AgeGroup::Age5to14); auto& p2 = world.add_person(location1, mio::abm::AgeGroup::Age5to14); auto& p3 = world.add_person(location2, mio::abm::AgeGroup::Age5to14); @@ -57,7 +59,7 @@ TEST(TestGraphSimulation, advance_random) TEST(TestGraphSimulation, advance_subpopulation) { mio::abm::GlobalInfectionParameters infection_params; - auto world = mio::graph_abm::GraphWorld(infection_params, 0); + auto world = mio::graph_abm::GraphWorld(infection_params, 0); auto location_id = world.add_location(mio::abm::LocationType::School); auto& school = world.get_individualized_location(location_id); auto person1 = @@ -82,7 +84,7 @@ TEST(TestGraphSimulation, advance_subpopulation) TEST(TestGraphSimulation, initializeSubpopulation) { mio::abm::GlobalInfectionParameters infection_params; - auto world = mio::graph_abm::GraphWorld(infection_params, 0); + auto world = mio::graph_abm::GraphWorld(infection_params, 0); auto loc_id = world.add_location(mio::abm::LocationType::PublicTransport); auto loc = world.get_individualized_location(loc_id); ASSERT_EQ(loc.get_subpopulations().get_num_time_points(), 0); @@ -92,3 +94,25 @@ TEST(TestGraphSimulation, initializeSubpopulation) ASSERT_EQ(sim.get_world().get_individualized_location(loc_id).get_subpopulations().get_time(0), 7); } + +TEST(TestGraphSimulation, stopsAtTmaxGraphABM) +{ + mio::abm::GlobalInfectionParameters infection_params; + auto world1 = mio::graph_abm::GraphWorld(infection_params, 0); + auto world2 = mio::graph_abm::GraphWorld(infection_params, 1); + + auto t0 = mio::abm::TimePoint(0); + auto dt = mio::abm::hours(12); + auto tmax = mio::abm::TimePoint(0) + mio::abm::days(5); + + mio::Graph, mio::MigrationEdgeABM> g; + g.add_node(0, t0, std::move(world1)); + g.add_node(1, t0, std::move(world2)); + g.add_edge(0, 1); + + auto sim = mio::make_migration_sim(t0, dt, std::move(g)); + + sim.advance(tmax, true); + + EXPECT_EQ(sim.get_t(), tmax); +} diff --git a/cpp/tests/test_abm_person.cpp b/cpp/tests/test_abm_person.cpp index 1b59469a76..78fef2f0bf 100644 --- a/cpp/tests/test_abm_person.cpp +++ b/cpp/tests/test_abm_person.cpp @@ -248,3 +248,21 @@ TEST(TestPerson, getProtectiveFactor) ASSERT_EQ(person_ffp2.get_mask_protective_factor(params), 0.9); ASSERT_EQ(person_without.get_mask_protective_factor(params), 0.); } + +TEST(TestPerson, migrateToOtherWorld) +{ + auto t = mio::abm::TimePoint(0); + + auto home = mio::abm::Location(mio::abm::LocationType::Home, 0, 0); + auto work = mio::abm::Location(mio::abm::LocationType::Work, 1, 1); + + auto person = make_test_person(home, mio::abm::AgeGroup::Age35to59, mio::abm::InfectionState::Susceptible); + + person.migrate_to_other_world(work, true); + + ASSERT_EQ(person.get_location(), work); + ASSERT_EQ(work.get_subpopulation(t, mio::abm::InfectionState::Susceptible), 1); + ASSERT_EQ(home.get_subpopulation(t, mio::abm::InfectionState::Susceptible), 0); + ASSERT_EQ(work.get_cells()[0].m_persons.size(), 1); + ASSERT_EQ(home.get_cells()[0].m_persons.size(), 0); +} From 880fec813ba7cadb80c58aaf024281788fb253a6 Mon Sep 17 00:00:00 2001 From: jubicker Date: Fri, 7 Jul 2023 09:01:06 +0200 Subject: [PATCH 24/38] delete unused variable --- cpp/tests/test_mobility.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/tests/test_mobility.cpp b/cpp/tests/test_mobility.cpp index 3f2c6d9cea..f2f052e8f4 100644 --- a/cpp/tests/test_mobility.cpp +++ b/cpp/tests/test_mobility.cpp @@ -194,7 +194,6 @@ TEST(TestMobility, ABMEdgeApplyMigration) auto t0 = mio::abm::TimePoint(0); auto dt = mio::abm::hours(12); - auto tmax = mio::abm::TimePoint(0) + mio::abm::days(10); mio::SimulationNode node1(t0, std::move(world1)); mio::SimulationNode node2(t0, std::move(world2)); From 57e849210ad725c1c860ee578c1c8c82a36d3803 Mon Sep 17 00:00:00 2001 From: jubicker Date: Fri, 7 Jul 2023 09:17:15 +0200 Subject: [PATCH 25/38] fix bindings --- .../memilio/generation/template/template_string.py | 2 +- .../memilio/simulation/mobility/graph_simulation.h | 4 ++-- .../memilio-simulation/memilio/simulation/secir.cpp | 12 +++++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/pycode/memilio-generation/memilio/generation/template/template_string.py b/pycode/memilio-generation/memilio/generation/template/template_string.py index 989e9a5575..85a7532409 100644 --- a/pycode/memilio-generation/memilio/generation/template/template_string.py +++ b/pycode/memilio-generation/memilio/generation/template/template_string.py @@ -263,7 +263,7 @@ def simulation_graph(intermed_repr: IntermediateRepresentation) -> str: "pymio::bind_SimulationNode<{namespace}{simulation_class}<>>(m, \"SimulationNode\");\n\t" "pymio::bind_ModelGraph<{namespace}{model_class}>(m, \"ModelGraph\");\n\t" "pymio::bind_MigrationGraph<{namespace}{simulation_class}<>>(m, \"MigrationGraph\");\n\t" - "pymio::bind_GraphSimulation>, mio::MigrationEdge>>(m, \"MigrationSimulation\");\n\t" + "pymio::bind_GraphSimulation>, mio::MigrationEdge>, double, double>(m, \"MigrationSimulation\");\n\t" ).format( namespace=intermed_repr.namespace, model_class=intermed_repr.model_class, diff --git a/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h b/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h index 51414455ed..aba3dde5dd 100644 --- a/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h +++ b/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h @@ -31,10 +31,10 @@ namespace pymio /* * @brief bind GraphSimulation for any node and edge type */ -template +template void bind_GraphSimulation(pybind11::module& m, std::string const& name) { - using GS = mio::GraphSimulation; + using GS = mio::GraphSimulation; pybind11::class_(m, name.c_str()) .def(pybind11::init([](Graph& graph, double t0, double dt) { return std::make_unique(mio::make_migration_sim(t0, dt, std::move(graph))); diff --git a/pycode/memilio-simulation/memilio/simulation/secir.cpp b/pycode/memilio-simulation/memilio/simulation/secir.cpp index 8b8edced58..e69cf68b1a 100644 --- a/pycode/memilio-simulation/memilio/simulation/secir.cpp +++ b/pycode/memilio-simulation/memilio/simulation/secir.cpp @@ -79,20 +79,22 @@ void bind_ParameterStudy(py::module& m, std::string const& name) .def_property_readonly("secir_model_graph", py::overload_cast<>(&mio::ParameterStudy::get_model_graph, py::const_), py::return_value_policy::reference_internal) - .def("run", + .def( + "run", [](mio::ParameterStudy& self, - std::function, mio::MigrationEdge>, size_t)> handle_result) { + std::function, mio::MigrationEdge>, size_t)> + handle_result) { self.run( [](auto&& g) { return draw_sample(g); }, [&handle_result](auto&& g, auto&& run_idx) { //handle_result_function needs to return something - //we don't want to run an unknown python object through parameterstudies, so + //we don't want to run an unknown python object through parameterstudies, so //we just return 0 and ignore the list returned by run(). //So python will behave slightly different than c++ handle_result(std::move(g), run_idx); - return 0; + return 0; }); }, py::arg("handle_result_func")) @@ -206,7 +208,7 @@ PYBIND11_MODULE(_simulation_secir, m) pymio::bind_SimulationNode>(m, "SimulationNode"); pymio::bind_ModelGraph(m, "ModelGraph"); pymio::bind_MigrationGraph(m, "MigrationGraph"); - pymio::bind_GraphSimulation(m, "MigrationSimulation"); + pymio::bind_GraphSimulation(m, "MigrationSimulation"); //normally, std::vector is bound to any python iterable, but this doesn't work for move-only elements //Bound the vector as a custom type that serves as output of ParameterStudy::run and input to From d59801b0445b162a3722d94d75f72f336ae45db1 Mon Sep 17 00:00:00 2001 From: jubicker Date: Fri, 7 Jul 2023 09:50:22 +0200 Subject: [PATCH 26/38] fix python bindings --- .../memilio/generation/template/template_string.py | 2 +- .../memilio/simulation/mobility/graph_simulation.h | 6 +++--- pycode/memilio-simulation/memilio/simulation/secir.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pycode/memilio-generation/memilio/generation/template/template_string.py b/pycode/memilio-generation/memilio/generation/template/template_string.py index 85a7532409..989e9a5575 100644 --- a/pycode/memilio-generation/memilio/generation/template/template_string.py +++ b/pycode/memilio-generation/memilio/generation/template/template_string.py @@ -263,7 +263,7 @@ def simulation_graph(intermed_repr: IntermediateRepresentation) -> str: "pymio::bind_SimulationNode<{namespace}{simulation_class}<>>(m, \"SimulationNode\");\n\t" "pymio::bind_ModelGraph<{namespace}{model_class}>(m, \"ModelGraph\");\n\t" "pymio::bind_MigrationGraph<{namespace}{simulation_class}<>>(m, \"MigrationGraph\");\n\t" - "pymio::bind_GraphSimulation>, mio::MigrationEdge>, double, double>(m, \"MigrationSimulation\");\n\t" + "pymio::bind_GraphSimulation>, mio::MigrationEdge>>(m, \"MigrationSimulation\");\n\t" ).format( namespace=intermed_repr.namespace, model_class=intermed_repr.model_class, diff --git a/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h b/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h index aba3dde5dd..a9dff7c0c7 100644 --- a/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h +++ b/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h @@ -31,10 +31,10 @@ namespace pymio /* * @brief bind GraphSimulation for any node and edge type */ -template +template void bind_GraphSimulation(pybind11::module& m, std::string const& name) { - using GS = mio::GraphSimulation; + using GS = mio::GraphSimulation; pybind11::class_(m, name.c_str()) .def(pybind11::init([](Graph& graph, double t0, double dt) { return std::make_unique(mio::make_migration_sim(t0, dt, std::move(graph))); @@ -47,7 +47,7 @@ void bind_GraphSimulation(pybind11::module& m, std::string const& name) }, pybind11::return_value_policy::reference_internal) .def_property_readonly("t", &GS::get_t) - .def("advance", &GS::advance, pybind11::arg("tmax")); + .def("advance", py::overload_cast(&GS::advance), pybind11::arg("tmax")); } } // namespace pymio diff --git a/pycode/memilio-simulation/memilio/simulation/secir.cpp b/pycode/memilio-simulation/memilio/simulation/secir.cpp index e69cf68b1a..ace3bca6b9 100644 --- a/pycode/memilio-simulation/memilio/simulation/secir.cpp +++ b/pycode/memilio-simulation/memilio/simulation/secir.cpp @@ -208,7 +208,7 @@ PYBIND11_MODULE(_simulation_secir, m) pymio::bind_SimulationNode>(m, "SimulationNode"); pymio::bind_ModelGraph(m, "ModelGraph"); pymio::bind_MigrationGraph(m, "MigrationGraph"); - pymio::bind_GraphSimulation(m, "MigrationSimulation"); + pymio::bind_GraphSimulation(m, "MigrationSimulation"); //normally, std::vector is bound to any python iterable, but this doesn't work for move-only elements //Bound the vector as a custom type that serves as output of ParameterStudy::run and input to From d96e755049830c6612768fbd521ba3fa9402e0d4 Mon Sep 17 00:00:00 2001 From: jubicker Date: Fri, 7 Jul 2023 10:57:26 +0200 Subject: [PATCH 27/38] fix bindings --- .../memilio/simulation/mobility/graph_simulation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h b/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h index a9dff7c0c7..eaa8bfd65b 100644 --- a/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h +++ b/pycode/memilio-simulation/memilio/simulation/mobility/graph_simulation.h @@ -47,7 +47,7 @@ void bind_GraphSimulation(pybind11::module& m, std::string const& name) }, pybind11::return_value_policy::reference_internal) .def_property_readonly("t", &GS::get_t) - .def("advance", py::overload_cast(&GS::advance), pybind11::arg("tmax")); + .def("advance", pybind11::overload_cast(&GS::advance), pybind11::arg("tmax")); } } // namespace pymio From c8253af3226f38d3a40189464d3d9bfb07a1b7ad Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 12 Jul 2023 15:04:33 +0200 Subject: [PATCH 28/38] hybrid graph class --- cpp/memilio/CMakeLists.txt | 4 + cpp/memilio/mobility/hybrid_graph.cpp | 25 +++++ cpp/memilio/mobility/hybrid_graph.h | 60 +++++++++++ .../mobility/hybrid_graph_simulation.cpp | 25 +++++ .../mobility/hybrid_graph_simulation.h | 99 +++++++++++++++++++ .../metapopulation_mobility_instant.h | 8 +- 6 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 cpp/memilio/mobility/hybrid_graph.cpp create mode 100644 cpp/memilio/mobility/hybrid_graph.h create mode 100644 cpp/memilio/mobility/hybrid_graph_simulation.cpp create mode 100644 cpp/memilio/mobility/hybrid_graph_simulation.h diff --git a/cpp/memilio/CMakeLists.txt b/cpp/memilio/CMakeLists.txt index c6e851e550..1f12275aff 100644 --- a/cpp/memilio/CMakeLists.txt +++ b/cpp/memilio/CMakeLists.txt @@ -61,6 +61,10 @@ add_library(memilio mobility/graph_simulation.cpp mobility/graph.h mobility/graph.cpp + mobility/hybrid_graph.h + mobility/hybrid_graph.cpp + mobility/hybrid_graph_simulation.h + mobility/hybrid_graph_simulation.cpp utils/visitor.h utils/uncertain_value.h utils/uncertain_value.cpp diff --git a/cpp/memilio/mobility/hybrid_graph.cpp b/cpp/memilio/mobility/hybrid_graph.cpp new file mode 100644 index 0000000000..4cf3617fe1 --- /dev/null +++ b/cpp/memilio/mobility/hybrid_graph.cpp @@ -0,0 +1,25 @@ +/* +* Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) +* +* Authors: Julia Bicker, Daniel Abele +* +* 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 "memilio/mobility/hybrid_graph.h" + +namespace mio +{ + +} diff --git a/cpp/memilio/mobility/hybrid_graph.h b/cpp/memilio/mobility/hybrid_graph.h new file mode 100644 index 0000000000..1840db4f79 --- /dev/null +++ b/cpp/memilio/mobility/hybrid_graph.h @@ -0,0 +1,60 @@ +/* +* Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) +* +* Authors: Julia Bicker, Daniel Abele, Martin J. Kuehn +* +* 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 HYBRID_GRAPH_H +#define HYBRID_GRAPH_H + +#include "memilio/mobility/graph.h" + +namespace mio +{ + +/** + * @brief generic hybrid graph structure + */ +template +class HybridGraph +{ +public: + HybridGraph(const ABMGraph& abm_graph, const ODEGraph& ode_graph, const SetupABMFromOdeFct& setup_func, + std::vector> household_distributions = {}) + : m_abm_graph(abm_graph) + , m_ode_graph(ode_graph) + , m_abm_nodes_to_ode_nodes(setup_func(household_distributions)) + { + } + + HybridGraph(ABMGraph&& abm_graph, ODEGraph&& ode_graph, const SetupABMFromOdeFct& setup_func, + std::vector> household_distributions = {}) + : m_abm_graph(std::move(abm_graph)) + , m_ode_graph(std::move(ode_graph)) + , m_abm_nodes_to_ode_nodes(setup_func(household_distributions)) + { + } + +private: + ABMGraph m_abm_graph; + ODEGraph m_ode_graph; + std::vector> m_abm_nodes_to_ode_nodes; + std::vector> m_hybrid_edges; +}; + +} // namespace mio + +#endif //HYBRID_GRAPH_H diff --git a/cpp/memilio/mobility/hybrid_graph_simulation.cpp b/cpp/memilio/mobility/hybrid_graph_simulation.cpp new file mode 100644 index 0000000000..787c737df1 --- /dev/null +++ b/cpp/memilio/mobility/hybrid_graph_simulation.cpp @@ -0,0 +1,25 @@ +/* +* Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) +* +* Authors: Daniel Abele +* +* 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 "memilio/mobility/hybrid_graph_simulation.h" + +namespace mio +{ + +} diff --git a/cpp/memilio/mobility/hybrid_graph_simulation.h b/cpp/memilio/mobility/hybrid_graph_simulation.h new file mode 100644 index 0000000000..280010fcac --- /dev/null +++ b/cpp/memilio/mobility/hybrid_graph_simulation.h @@ -0,0 +1,99 @@ +/* +* Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) +* +* Authors: Julia Bicker, Daniel Abele +* +* 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_MOBILITY_HYBRID_GRAPH_SIMULATION_H +#define MIO_MOBILITY_HYBRID_GRAPH_SIMULATION_H + +#include "memilio/mobility/hybrid_graph_simulation.h" + +namespace mio +{ +template +class HybridGraphSimulation +{ + using node_function_abm = std::function; //, typename HybridGraph::NodeProperty&)>; + using node_function_ode = std::function; //typename HybridGraph::ODEGraph::NodeProperty&)>; + + using edge_function_abm = + std::function; //, typename HybridGraph::ABMGraph::EdgeProperty&, + //typename HybridGraph::ABMGraph::NodeProperty&, + //typename HybridGraph::ABMGraph::NodeProperty&)>; + using edge_function_ode = std::function; //typename HybridGraph::ODEGraph::EdgeProperty&, + //typename HybridGraph::ODEGraph::NodeProperty&, + //typename HybridGraph::ODEGraph::NodeProperty&)>; + using edge_function_hybrid = + std::function; //, typename HybridGraph::MigrationEdgeHybrid&, + //typename HybridGraph::ABMGraph::NodeProperty&, + //typename HybridGraph::ODEGraph::NodeProperty&)>; + + using time_conversion_function = std::function; + HybridGraphSimulation(Timepoint t0, Timespan dt, const HybridGraph& g, const node_function_abm& node_func_abm, + const node_function_ode& node_func_ode, const edge_function_abm& edge_func_abm, + const edge_function_ode& edge_func_ode, const edge_function_hybrid& edge_func_hybrid, + const time_conversion_function& time_conversion_func) + : m_t_abm(t0) + , m_dt_abm(dt) + , m_t_ode(time_conversion_func(t0)) + , m_dt_ode(time_conversion_func(Timepoint(0) + dt)) + , m_graph(g) + , m_node_func_abm(node_func_abm) + , m_node_func_ode(node_func_ode) + , m_edge_func_abm(edge_func_abm) + , m_edge_func_ode(edge_func_ode) + , m_edge_func_hybrid(edge_func_hybrid) + { + } + + HybridGraphSimulation(Timepoint t0, Timespan dt, HybridGraph&& g, const node_function_abm& node_func_abm, + const node_function_ode& node_func_ode, const edge_function_abm& edge_func_abm, + const edge_function_ode& edge_func_ode, const edge_function_hybrid& edge_func_hybrid) + : m_t(t0) + , m_dt(dt) + , m_t_ode(time_conversion_func(t0)) + , m_dt_ode(time_conversion_func(Timepoint(0) + dt)) + , m_graph(std::move(g)) + , m_node_func_abm(node_func_abm) + , m_node_func_ode(node_func_ode) + , m_edge_func_abm(edge_func_abm) + , m_edge_func_ode(edge_func_ode) + , m_edge_func_hybrid(edge_func_hybrid) + { + } + + void advance(Timepoint tmax) + { + auto dt = m_t + } + +private: + Timepoint m_t_abm; + Timespan m_dt_abm; + double m_t_ode; + double m_dt_ode; + HybridGraph m_graph; + node_function_abm m_node_func_abm; + node_function_ode m_node_func_ode; + edge_function_abm m_edge_func_abm; + edge_function_ode m_edge_func_ode; + edge_function_hybrid m_edge_func_hybrid; +}; + +} // namespace mio +#endif //MIO_MOBILITY_HYBRID_GRAPH_SIMULATION_H diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index e650ae1598..8a81ad30fe 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -318,16 +318,14 @@ class MigrationEdgeABM } template ::value, bool> = true> - void apply_migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt, SimulationNode& node_from, + void apply_migration(mio::abm::TimePoint /*t*/, mio::abm::TimeSpan /*dt*/, SimulationNode& node_from, SimulationNode& node_to); }; template ::value, bool>> -void MigrationEdgeABM::apply_migration(mio::abm::TimePoint t, mio::abm::TimeSpan dt, SimulationNode& node_from, - SimulationNode& node_to) +void MigrationEdgeABM::apply_migration(mio::abm::TimePoint /*t*/, mio::abm::TimeSpan /*dt*/, + SimulationNode& node_from, SimulationNode& node_to) { - mio::unused(t); - mio::unused(dt); size_t person_iter = 0; auto& persons_to_migrate = node_from.get_simulation().get_graph_world().get_persons_to_migrate(); while (person_iter < persons_to_migrate.size()) { From ae55ca44fc5edf152ebda3b6ccac68aac6036e22 Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 12 Jul 2023 15:16:58 +0200 Subject: [PATCH 29/38] fix functions in hybrid graph sim --- .../mobility/hybrid_graph_simulation.h | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/cpp/memilio/mobility/hybrid_graph_simulation.h b/cpp/memilio/mobility/hybrid_graph_simulation.h index 280010fcac..f095986c51 100644 --- a/cpp/memilio/mobility/hybrid_graph_simulation.h +++ b/cpp/memilio/mobility/hybrid_graph_simulation.h @@ -22,26 +22,27 @@ #define MIO_MOBILITY_HYBRID_GRAPH_SIMULATION_H #include "memilio/mobility/hybrid_graph_simulation.h" +#include namespace mio { template class HybridGraphSimulation { - using node_function_abm = std::function; //, typename HybridGraph::NodeProperty&)>; - using node_function_ode = std::function; //typename HybridGraph::ODEGraph::NodeProperty&)>; + using node_function_abm = std::function; + using node_function_ode = std::function; using edge_function_abm = - std::function; //, typename HybridGraph::ABMGraph::EdgeProperty&, - //typename HybridGraph::ABMGraph::NodeProperty&, - //typename HybridGraph::ABMGraph::NodeProperty&)>; - using edge_function_ode = std::function; //typename HybridGraph::ODEGraph::EdgeProperty&, - //typename HybridGraph::ODEGraph::NodeProperty&, - //typename HybridGraph::ODEGraph::NodeProperty&)>; + std::function; + using edge_function_ode = std::function; using edge_function_hybrid = - std::function; //, typename HybridGraph::MigrationEdgeHybrid&, - //typename HybridGraph::ABMGraph::NodeProperty&, - //typename HybridGraph::ODEGraph::NodeProperty&)>; + std::function; using time_conversion_function = std::function; HybridGraphSimulation(Timepoint t0, Timespan dt, const HybridGraph& g, const node_function_abm& node_func_abm, @@ -64,8 +65,8 @@ class HybridGraphSimulation HybridGraphSimulation(Timepoint t0, Timespan dt, HybridGraph&& g, const node_function_abm& node_func_abm, const node_function_ode& node_func_ode, const edge_function_abm& edge_func_abm, const edge_function_ode& edge_func_ode, const edge_function_hybrid& edge_func_hybrid) - : m_t(t0) - , m_dt(dt) + : m_t_abm(t0) + , m_dt_abm(dt) , m_t_ode(time_conversion_func(t0)) , m_dt_ode(time_conversion_func(Timepoint(0) + dt)) , m_graph(std::move(g)) @@ -77,10 +78,10 @@ class HybridGraphSimulation { } - void advance(Timepoint tmax) - { - auto dt = m_t - } + // void advance(Timepoint tmax) + // { + // auto dt = m_t; + // } private: Timepoint m_t_abm; From 1f3f292f1c5afd22ea83b88e652173996d3f5f0d Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 12 Jul 2023 16:21:51 +0200 Subject: [PATCH 30/38] add getter --- cpp/memilio/mobility/hybrid_graph.h | 10 ++++ .../mobility/hybrid_graph_simulation.h | 49 +++++++++++++------ 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/cpp/memilio/mobility/hybrid_graph.h b/cpp/memilio/mobility/hybrid_graph.h index 1840db4f79..5af4520239 100644 --- a/cpp/memilio/mobility/hybrid_graph.h +++ b/cpp/memilio/mobility/hybrid_graph.h @@ -48,6 +48,16 @@ class HybridGraph { } + ABMGraph& get_abm_graph() + { + return m_abm_graph; + } + + ODEGraph& get_ode_graph() + { + return m_ode_graph; + } + private: ABMGraph m_abm_graph; ODEGraph m_ode_graph; diff --git a/cpp/memilio/mobility/hybrid_graph_simulation.h b/cpp/memilio/mobility/hybrid_graph_simulation.h index f095986c51..079107eac5 100644 --- a/cpp/memilio/mobility/hybrid_graph_simulation.h +++ b/cpp/memilio/mobility/hybrid_graph_simulation.h @@ -32,17 +32,15 @@ class HybridGraphSimulation using node_function_abm = std::function; using node_function_ode = std::function; - using edge_function_abm = - std::function; - using edge_function_ode = std::function; - using edge_function_hybrid = - std::function; + using edge_function_abm = std::function; + using edge_function_ode = std::function; + using edge_function_hybrid = std::function; using time_conversion_function = std::function; HybridGraphSimulation(Timepoint t0, Timespan dt, const HybridGraph& g, const node_function_abm& node_func_abm, @@ -64,7 +62,8 @@ class HybridGraphSimulation HybridGraphSimulation(Timepoint t0, Timespan dt, HybridGraph&& g, const node_function_abm& node_func_abm, const node_function_ode& node_func_ode, const edge_function_abm& edge_func_abm, - const edge_function_ode& edge_func_ode, const edge_function_hybrid& edge_func_hybrid) + const edge_function_ode& edge_func_ode, const edge_function_hybrid& edge_func_hybrid, + const time_conversion_function& time_conversion_func) : m_t_abm(t0) , m_dt_abm(dt) , m_t_ode(time_conversion_func(t0)) @@ -78,10 +77,28 @@ class HybridGraphSimulation { } - // void advance(Timepoint tmax) - // { - // auto dt = m_t; - // } + void advance(Timepoint tmax, const time_conversion_function& time_conversion_func) + { + while (m_t_abm < t_max) { + if (m_t_abm + m_dt_abm > t_max) { + m_dt_abm = t_max - m_t_abm; + m_dt_ode = time_conversion_func(tmax) - m_t_ode; + } + + //advance abm nodes until t+dt + for (auto& abm_node : m_graph.get_abm_graph().nodes()) { + m_node_func_abm(m_t_abm, m_dt_abm, abm_node.property); + } + + //advance ode nodes until t+dt + for (auto& ode_node : m_graph.get_ode_graph().nodes()) { + m_node_func_ode(m_t_ode, m_dt_ode, ode_node.property); + } + + m_t_abm += m_dt_abm; + m_t_ode += m_dt_ode; + } + } private: Timepoint m_t_abm; From b8049c0df9a2fe673cf8e23e6b0e9215ed3e5284 Mon Sep 17 00:00:00 2001 From: jubicker Date: Wed, 12 Jul 2023 16:24:38 +0200 Subject: [PATCH 31/38] bug fix variable name --- cpp/memilio/mobility/hybrid_graph_simulation.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/memilio/mobility/hybrid_graph_simulation.h b/cpp/memilio/mobility/hybrid_graph_simulation.h index 079107eac5..6d9771b729 100644 --- a/cpp/memilio/mobility/hybrid_graph_simulation.h +++ b/cpp/memilio/mobility/hybrid_graph_simulation.h @@ -77,12 +77,12 @@ class HybridGraphSimulation { } - void advance(Timepoint tmax, const time_conversion_function& time_conversion_func) + void advance(Timepoint t_max, const time_conversion_function& time_conversion_func) { while (m_t_abm < t_max) { if (m_t_abm + m_dt_abm > t_max) { m_dt_abm = t_max - m_t_abm; - m_dt_ode = time_conversion_func(tmax) - m_t_ode; + m_dt_ode = time_conversion_func(t_max) - m_t_ode; } //advance abm nodes until t+dt From e3421592b27e1d44ce375d2b80f20a136cbb43be Mon Sep 17 00:00:00 2001 From: jubicker Date: Thu, 13 Jul 2023 11:13:45 +0200 Subject: [PATCH 32/38] advance method for hybrid graph sim --- cpp/memilio/mobility/hybrid_graph.h | 77 ++++++++++++++++++- .../mobility/hybrid_graph_simulation.h | 26 +++++++ 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/cpp/memilio/mobility/hybrid_graph.h b/cpp/memilio/mobility/hybrid_graph.h index 5af4520239..b814de0a4f 100644 --- a/cpp/memilio/mobility/hybrid_graph.h +++ b/cpp/memilio/mobility/hybrid_graph.h @@ -21,6 +21,7 @@ #define HYBRID_GRAPH_H #include "memilio/mobility/graph.h" +#include "memilio/utils/stl_util.h" namespace mio { @@ -48,20 +49,90 @@ class HybridGraph { } - ABMGraph& get_abm_graph() + ABMGraph& get_abm_graph() & { return m_abm_graph; } - ODEGraph& get_ode_graph() + const ABMGraph& get_abm_graph() const& + { + return m_abm_graph; + } + + ODEGraph& get_ode_graph() & + { + return m_ode_graph; + } + + const ODEGraph& get_ode_graph() const& { return m_ode_graph; } + auto hybrid_edges() + { + return make_range(begin(m_hybrid_edges), end(m_hybrid_edges)); + } + + auto hybrid_edges() const + { + return make_range(begin(m_hybrid_edges), end(m_hybrid_edges)); + } + + Node& get_abm_node_from_hybrid_edge(Edge& edge) + { + auto start_idx = edge.start_node_idx; + auto end_idx = edge.end_node_idx; + auto iter = std::find_if(m_abm_graph.nodes().begin(), m_abm_graph.nodes().end(), + [start_idx](const Node& node) { + return node.id == start_idx; + }); + if (iter != m_abm_graph.nodes().end()) { + return *iter; + } + else { + iter = std::find_if(m_abm_graph.nodes().begin(), m_abm_graph.nodes().end(), + [end_idx](const Node& node) { + return node.id == end_idx; + }); + if (iter != m_abm_graph.nodes().end()) { + return *iter; + } + else { + mio::log_error("Hybrid edge is not in graph"); + } + } + } + + Node& get_ode_node_from_hybrid_edge(Edge& edge) + { + auto start_idx = edge.start_node_idx; + auto end_idx = edge.end_node_idx; + auto iter = std::find_if(m_ode_graph.nodes().begin(), m_ode_graph.nodes().end(), + [start_idx](const Node& node) { + return node.id == start_idx; + }); + if (iter != m_ode_graph.nodes().end()) { + return *iter; + } + else { + iter = std::find_if(m_ode_graph.nodes().begin(), m_ode_graph.nodes().end(), + [end_idx](const Node& node) { + return node.id == end_idx; + }); + if (iter != m_ode_graph.nodes().end()) { + return *iter; + } + else { + mio::log_error("Hybrid edge is not in graph"); + } + } + } + private: ABMGraph m_abm_graph; ODEGraph m_ode_graph; - std::vector> m_abm_nodes_to_ode_nodes; + std::vector> m_abm_nodes_to_ode_nodes; std::vector> m_hybrid_edges; }; diff --git a/cpp/memilio/mobility/hybrid_graph_simulation.h b/cpp/memilio/mobility/hybrid_graph_simulation.h index 6d9771b729..43a9557e1c 100644 --- a/cpp/memilio/mobility/hybrid_graph_simulation.h +++ b/cpp/memilio/mobility/hybrid_graph_simulation.h @@ -97,6 +97,32 @@ class HybridGraphSimulation m_t_abm += m_dt_abm; m_t_ode += m_dt_ode; + + //advance abm edges + for (auto& abm_edge : m_graph.get_abm_graph().edges()) { + m_edge_func_abm(m_t_abm, m_dt_abm, abm_edge.property, + m_graph.get_abm_graph().nodes()[abm_edge.start_node_idx].property, + m_graph.get_abm_graph().nodes()[abm_edge.end_node_idx].property); + } + + //advance ode_edges + for (auto& ode_edge : m_graph.get_ode_graph().edges()) { + m_edge_func_ode(m_t_ode, m_dt_ode, ode_edge.property, + m_graph.get_ode_graph().nodes()[ode_edge.start_node_idx].property, + m_graph.get_ode_graph().nodes()[ode_edge.end_node_idx].property); + } + + //advance hybrid edges + for (auto& hybrid_edge : m_graph.hybrid_edges()) { + m_edge_func_hybrid(m_t_abm, m_dt_abm, hybrid_edge.property, + m_graph.get_abm_node_from_hybrid_edge(hybrid_edge), + m_graph.get_ode_node_from_hybrid_edge(hybrid_edge)); + } + } + + //store results for abm nodes for last timepoint + for (auto& abm_node : m_graph.get_abm_graph().nodes()) { + n.property.end_simulation(t_max); } } From 519747eda430208f50acdd3a0b31bec8788549af Mon Sep 17 00:00:00 2001 From: jubicker Date: Thu, 20 Jul 2023 15:20:13 +0200 Subject: [PATCH 33/38] apply migration hybrid edge --- cpp/memilio/CMakeLists.txt | 2 + cpp/memilio/mobility/hybrid_graph.h | 12 +- .../mobility/hybrid_graph_simulation.h | 7 +- .../metapopulation_mobility_hybrid.cpp | 25 ++++ .../mobility/metapopulation_mobility_hybrid.h | 140 ++++++++++++++++++ .../metapopulation_mobility_instant.h | 1 - 6 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 cpp/memilio/mobility/metapopulation_mobility_hybrid.cpp create mode 100644 cpp/memilio/mobility/metapopulation_mobility_hybrid.h diff --git a/cpp/memilio/CMakeLists.txt b/cpp/memilio/CMakeLists.txt index 1f12275aff..513b9271dc 100644 --- a/cpp/memilio/CMakeLists.txt +++ b/cpp/memilio/CMakeLists.txt @@ -57,6 +57,8 @@ add_library(memilio mobility/metapopulation_mobility_instant.cpp mobility/metapopulation_mobility_stochastic.h mobility/metapopulation_mobility_stochastic.cpp + mobility/metapopulation_mobility_hybrid.h + mobility/metapopulation_mobility_hybrid.cpp mobility/graph_simulation.h mobility/graph_simulation.cpp mobility/graph.h diff --git a/cpp/memilio/mobility/hybrid_graph.h b/cpp/memilio/mobility/hybrid_graph.h index b814de0a4f..4fa93f8966 100644 --- a/cpp/memilio/mobility/hybrid_graph.h +++ b/cpp/memilio/mobility/hybrid_graph.h @@ -33,6 +33,8 @@ template ; + HybridGraph(const ABMGraph& abm_graph, const ODEGraph& ode_graph, const SetupABMFromOdeFct& setup_func, std::vector> household_distributions = {}) : m_abm_graph(abm_graph) @@ -84,7 +86,7 @@ class HybridGraph auto start_idx = edge.start_node_idx; auto end_idx = edge.end_node_idx; auto iter = std::find_if(m_abm_graph.nodes().begin(), m_abm_graph.nodes().end(), - [start_idx](const Node& node) { + [start_idx](const Node& node) { return node.id == start_idx; }); if (iter != m_abm_graph.nodes().end()) { @@ -92,7 +94,7 @@ class HybridGraph } else { iter = std::find_if(m_abm_graph.nodes().begin(), m_abm_graph.nodes().end(), - [end_idx](const Node& node) { + [end_idx](const Node& node) { return node.id == end_idx; }); if (iter != m_abm_graph.nodes().end()) { @@ -109,7 +111,7 @@ class HybridGraph auto start_idx = edge.start_node_idx; auto end_idx = edge.end_node_idx; auto iter = std::find_if(m_ode_graph.nodes().begin(), m_ode_graph.nodes().end(), - [start_idx](const Node& node) { + [start_idx](const Node& node) { return node.id == start_idx; }); if (iter != m_ode_graph.nodes().end()) { @@ -117,7 +119,7 @@ class HybridGraph } else { iter = std::find_if(m_ode_graph.nodes().begin(), m_ode_graph.nodes().end(), - [end_idx](const Node& node) { + [end_idx](const Node& node) { return node.id == end_idx; }); if (iter != m_ode_graph.nodes().end()) { @@ -133,7 +135,7 @@ class HybridGraph ABMGraph m_abm_graph; ODEGraph m_ode_graph; std::vector> m_abm_nodes_to_ode_nodes; - std::vector> m_hybrid_edges; + std::vector m_hybrid_edges; }; } // namespace mio diff --git a/cpp/memilio/mobility/hybrid_graph_simulation.h b/cpp/memilio/mobility/hybrid_graph_simulation.h index 43a9557e1c..80d24f2e8c 100644 --- a/cpp/memilio/mobility/hybrid_graph_simulation.h +++ b/cpp/memilio/mobility/hybrid_graph_simulation.h @@ -38,7 +38,7 @@ class HybridGraphSimulation using edge_function_ode = std::function; - using edge_function_hybrid = std::function; @@ -114,15 +114,14 @@ class HybridGraphSimulation //advance hybrid edges for (auto& hybrid_edge : m_graph.hybrid_edges()) { - m_edge_func_hybrid(m_t_abm, m_dt_abm, hybrid_edge.property, - m_graph.get_abm_node_from_hybrid_edge(hybrid_edge), + m_edge_func_hybrid(m_t_ode, m_dt_ode, hybrid_edge, m_graph.get_abm_node_from_hybrid_edge(hybrid_edge), m_graph.get_ode_node_from_hybrid_edge(hybrid_edge)); } } //store results for abm nodes for last timepoint for (auto& abm_node : m_graph.get_abm_graph().nodes()) { - n.property.end_simulation(t_max); + abm_node.property.end_simulation(t_max); } } diff --git a/cpp/memilio/mobility/metapopulation_mobility_hybrid.cpp b/cpp/memilio/mobility/metapopulation_mobility_hybrid.cpp new file mode 100644 index 0000000000..2c203e5139 --- /dev/null +++ b/cpp/memilio/mobility/metapopulation_mobility_hybrid.cpp @@ -0,0 +1,25 @@ +/* +* Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) +* +* Authors: Julia Bicker, Daniel Abele +* +* 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 "memilio/mobility/metapopulation_mobility_hybrid.h" + +namespace mio +{ + +} // namespace mio diff --git a/cpp/memilio/mobility/metapopulation_mobility_hybrid.h b/cpp/memilio/mobility/metapopulation_mobility_hybrid.h new file mode 100644 index 0000000000..10f11e7633 --- /dev/null +++ b/cpp/memilio/mobility/metapopulation_mobility_hybrid.h @@ -0,0 +1,140 @@ +/* +* Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) +* +* Authors: Julia Bicker, Daniel Abele +* +* 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 METAPOPULATION_MOBILITY_HYBRID_H +#define METAPOPULATION_MOBILITY_HYBRID_H + +#include "memilio/mobility/metapopulation_mobility_instant.h" + +namespace mio +{ +template +class MigrationEdgeHybrid +{ +public: + //used if start node is abm node, because then we do not need MigrationParameters + MigrationEdgeHybrid(const AbmToOdeConversion& abm_to_ode_fct, const OdeToAbmConversion& ode_to_abm_fct, + size_t num_compartments) + : m_abm_to_ode_fct(abm_to_ode_fct) + , m_ode_to_abm_fct(ode_to_abm_fct) + , m_migrated_compartments(num_compartments) + , m_start_node_is_abm(true) + { + } + + //constructors with parameters are used if start node is ode node + MigrationEdgeHybrid(const MigrationParameters& params, const AbmToOdeConversion& abm_to_ode_fct, + const OdeToAbmConversion& ode_to_abm_fct) + : m_parameters(params) + , m_migrated_compartments(params.get_coefficients().get_shape().rows()) + , m_abm_to_ode_fct(abm_to_ode_fct) + , m_ode_to_abm_fct(ode_to_abm_fct) + , m_start_node_is_abm(false) + { + } + + MigrationEdgeHybrid(const Eigen::VectorXd& coeffs, const AbmToOdeConversion& abm_to_ode_fct, + const OdeToAbmConversion& ode_to_abm_fct) + : m_parameters(coeffs) + , m_migrated_compartments(coeffs.rows()) + , m_abm_to_ode_fct(abm_to_ode_fct) + , m_ode_to_abm_fct(ode_to_abm_fct) + , m_start_node_is_abm(false) + { + } + + /** + * @brief compute migration between an abm node and an ode node. + * For the abm node, migration is based on agents' migration rules and for an ode node, + * migration is based on coefficients. Migrations are deleted from the start node and added to the target node. + * @param[in] t time of migration + * @param[in, out] node_abm abm node. Can be start or target node. + * @param[in, out] node_ode ode node. Can be start or target node. + */ + template + void apply_migration(double t, double dt, NodeAbm& node_abm, NodeOde& node_ode, NodeAbm& abm_node_to_ode_node) + { + mio::unused(abm_node_to_ode_node); + if (m_start_node_is_abm) { + //check whether agents should return + if (m_migrated_agents.size() == 0) { + size_t person_iter = 0; + auto& persons_to_migrate = + node_abm.property.get_simulation().get_graph_world().get_persons_to_migrate(); + while (person_iter < persons_to_migrate.size()) { + //get the persons that want to go to the target node + if ((persons_to_migrate[person_iter]->get_location()).get_world_id() == node_ode.id) { + m_migrated_agents.push_back(std::move(persons_to_migrate[person_iter])); + node_abm.get_simulation().get_graph_world().get_persons_to_migrate().erase( + node_abm.get_simulation().get_graph_world().get_persons_to_migrate().begin() + person_iter); + continue; + } + ++person_iter; + } + m_migrated_compartments.add_time_point(t, m_abm_to_ode_fct(m_migrated_agents)); + node_ode.get_result().get_last_value() += m_migrated_compartments.get_last_value(); + } + //agents return from ode node + else { + auto total = + find_value_reverse(node_ode.get_result(), m_migrated_compartments.get_last_time(), 1e-10, 1e-10); + calculate_migration_returns(m_migrated_compartments.get_last_value(), node_ode.get_simulation(), *total, + m_migrated_compartments.get_last_time(), dt); + + Eigen::VectorXd remaining_after_return = + (node_ode.get_result().get_last_value() - m_migrated_compartments.get_last_value()).eval(); + for (Eigen::Index j = 0; j < node_ode.get_result().get_last_value().size(); ++j) { + if (remaining_after_return(j) < 0) { + auto num_comparts = (Eigen::Index)NodeOde::Sim::Model::Compartments::Count; + auto group = Eigen::Index(j / num_comparts); + auto compart = j % num_comparts; + log(remaining_after_return(j) < -1e-3 ? LogLevel::warn : LogLevel::info, + "Underflow during migration returns at time {}, compartment {}, age group {}: {}", t, + compart, group, remaining_after_return(j)); + Eigen::Index max_index; + slice(remaining_after_return, {group * num_comparts, num_comparts}).maxCoeff(&max_index); + log_info("Transferring to compartment {}", max_index); + max_index += group * num_comparts; + m_migrated_compartments.get_last_value()(max_index) -= remaining_after_return(j); + m_migrated_compartments.get_last_value()(j) += remaining_after_return(j); + } + } + node_ode.get_result().get_last_value() -= m_migrated_compartments.get_last_value(); + m_ode_to_abm_fct(m_migrated_compartments.get_last_value(), m_migrated_agents); + while (m_migrated_agents.size() > 0) { + node_abm.get_simulation().get_graph_world().add_existing_person(std::move(m_migrated_agents[0])); + m_migrated_agents.erase(m_migrated_agents.begin()); + } + m_migrated_compartments.remove_time_point(m_migrated_compartments.get_last_time()); + } + } + } + +private: + boost::optional m_parameters; + boost::optional>> m_migrated_agents; + TimeSeries m_migrated_compartments; + bool m_start_node_is_abm; + AbmToOdeConversion m_abm_to_ode_fct; + OdeToAbmConversion m_ode_to_abm_fct; +}; + +} // namespace mio + +#endif //METAPOPULATION_MOBILITY_HYBRID_H diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index 8a81ad30fe..aeb33f63e1 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -32,7 +32,6 @@ #include "memilio/compartments/simulation.h" #include "memilio/utils/date.h" #include "models/abm/time.h" -//#include "models/abm/simulation.h" #include "models/graph_abm/graph_simulation.h" #include "boost/filesystem.hpp" From c115b15f5ceb71055c869601514ea8036088cf43 Mon Sep 17 00:00:00 2001 From: jubicker Date: Fri, 21 Jul 2023 14:54:02 +0200 Subject: [PATCH 34/38] apply migration hybrid edge ode start node --- .../mobility/metapopulation_mobility_hybrid.h | 87 +++++++++++++++---- 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/cpp/memilio/mobility/metapopulation_mobility_hybrid.h b/cpp/memilio/mobility/metapopulation_mobility_hybrid.h index 10f11e7633..be86975188 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_hybrid.h +++ b/cpp/memilio/mobility/metapopulation_mobility_hybrid.h @@ -24,15 +24,16 @@ namespace mio { -template +template class MigrationEdgeHybrid { public: //used if start node is abm node, because then we do not need MigrationParameters MigrationEdgeHybrid(const AbmToOdeConversion& abm_to_ode_fct, const OdeToAbmConversion& ode_to_abm_fct, - size_t num_compartments) + const OdeToAbmMapping& ode_to_abm_mapping, size_t num_compartments) : m_abm_to_ode_fct(abm_to_ode_fct) , m_ode_to_abm_fct(ode_to_abm_fct) + , m_ode_to_abm_mapping(ode_to_abm_mapping) , m_migrated_compartments(num_compartments) , m_start_node_is_abm(true) { @@ -40,33 +41,35 @@ class MigrationEdgeHybrid //constructors with parameters are used if start node is ode node MigrationEdgeHybrid(const MigrationParameters& params, const AbmToOdeConversion& abm_to_ode_fct, - const OdeToAbmConversion& ode_to_abm_fct) + const OdeToAbmConversion& ode_to_abm_fct, const OdeToAbmMapping& ode_to_abm_mapping) : m_parameters(params) , m_migrated_compartments(params.get_coefficients().get_shape().rows()) , m_abm_to_ode_fct(abm_to_ode_fct) , m_ode_to_abm_fct(ode_to_abm_fct) + , m_ode_to_abm_mapping(ode_to_abm_mapping) , m_start_node_is_abm(false) { } MigrationEdgeHybrid(const Eigen::VectorXd& coeffs, const AbmToOdeConversion& abm_to_ode_fct, - const OdeToAbmConversion& ode_to_abm_fct) + const OdeToAbmConversion& ode_to_abm_fct, const OdeToAbmMapping& ode_to_abm_mapping) : m_parameters(coeffs) , m_migrated_compartments(coeffs.rows()) , m_abm_to_ode_fct(abm_to_ode_fct) , m_ode_to_abm_fct(ode_to_abm_fct) + , m_ode_to_abm_mapping(ode_to_abm_mapping) , m_start_node_is_abm(false) { } /** - * @brief compute migration between an abm node and an ode node. - * For the abm node, migration is based on agents' migration rules and for an ode node, - * migration is based on coefficients. Migrations are deleted from the start node and added to the target node. - * @param[in] t time of migration - * @param[in, out] node_abm abm node. Can be start or target node. - * @param[in, out] node_ode ode node. Can be start or target node. - */ + * @brief compute migration between an abm node and an ode node. + * For the abm node, migration is based on agents' migration rules and for an ode node, + * migration is based on coefficients. Migrations are deleted from the start node and added to the target node. + * @param[in] t time of migration + * @param[in, out] node_abm abm node. Can be start or target node. + * @param[in, out] node_ode ode node. Can be start or target node. + */ template void apply_migration(double t, double dt, NodeAbm& node_abm, NodeOde& node_ode, NodeAbm& abm_node_to_ode_node) { @@ -80,6 +83,7 @@ class MigrationEdgeHybrid while (person_iter < persons_to_migrate.size()) { //get the persons that want to go to the target node if ((persons_to_migrate[person_iter]->get_location()).get_world_id() == node_ode.id) { + //agents a removed from start node world and added to migrated agents m_migrated_agents.push_back(std::move(persons_to_migrate[person_iter])); node_abm.get_simulation().get_graph_world().get_persons_to_migrate().erase( node_abm.get_simulation().get_graph_world().get_persons_to_migrate().begin() + person_iter); @@ -87,16 +91,21 @@ class MigrationEdgeHybrid } ++person_iter; } + //convert migrating agents to ode compartments m_migrated_compartments.add_time_point(t, m_abm_to_ode_fct(m_migrated_agents)); + //add migrating compartments to ode node node_ode.get_result().get_last_value() += m_migrated_compartments.get_last_value(); } //agents return from ode node else { + //returning compartments with euler step auto total = find_value_reverse(node_ode.get_result(), m_migrated_compartments.get_last_time(), 1e-10, 1e-10); calculate_migration_returns(m_migrated_compartments.get_last_value(), node_ode.get_simulation(), *total, m_migrated_compartments.get_last_time(), dt); - + //the lower-order return calculation may in rare cases produce negative compartments, + //especially at the beginning of the simulation. + //fix by subtracting the supernumerous returns from the biggest compartment of the age group. Eigen::VectorXd remaining_after_return = (node_ode.get_result().get_last_value() - m_migrated_compartments.get_last_value()).eval(); for (Eigen::Index j = 0; j < node_ode.get_result().get_last_value().size(); ++j) { @@ -115,24 +124,66 @@ class MigrationEdgeHybrid m_migrated_compartments.get_last_value()(j) += remaining_after_return(j); } } + //substract returning compartments from ode nodes node_ode.get_result().get_last_value() -= m_migrated_compartments.get_last_value(); + //convert return compartments to agents by setting migrated agents' status and location m_ode_to_abm_fct(m_migrated_compartments.get_last_value(), m_migrated_agents); + //add returning agents to abm node and remove them from migrated agents while (m_migrated_agents.size() > 0) { node_abm.get_simulation().get_graph_world().add_existing_person(std::move(m_migrated_agents[0])); m_migrated_agents.erase(m_migrated_agents.begin()); } + //remove returned compartments m_migrated_compartments.remove_time_point(m_migrated_compartments.get_last_time()); } } + //start node is ode + else { + if (m_migrated_compartments.get_num_time_points() == 0) { + //update agents status and location + m_ode_to_abm_fct(node_ode.get_result().get_last_value(), + abm_node_to_ode_node.property.get_simulation().get_graph_world().get_persons()); + + if ((m_parameters.get_coefficients().get_matrix_at(t).array() > 0.0).any()) { + m_migrated_compartments.add_time_point( + t, + (node_ode.get_last_state().array() * m_parameters.get_coefficients().get_matrix_at(t).array() * + get_migration_factors(node_ode, t, node_ode.get_last_state()).array()) + .matrix()); + m_ode_to_abm_mapping(m_migrated_compartments.get_last_value(), + abm_node_to_ode_node.property.get_simulation().get_graph_world().get_persons(), + m_migrated_agents); + while (m_migrated_agents.size() > 0) { + auto& target_location = node_abm.get_simulation().get_graph_world().find_location( + (m_migrated_agents[0]->get_location()).get_type(), *m_migrated_agents[0]); + //let person migrate to location in target world + m_migrated_agents[0]->migrate_to_other_world(target_location, true); + //add person to abm node + node_abm.get_simulation().get_graph_world().add_existing_person( + std::move(m_migrated_agents[0])); + m_migrated_agents.erase(m_migrated_agents.begin()); + } + } + } + //agents should return + else { + } + } } private: - boost::optional m_parameters; - boost::optional>> m_migrated_agents; - TimeSeries m_migrated_compartments; - bool m_start_node_is_abm; - AbmToOdeConversion m_abm_to_ode_fct; - OdeToAbmConversion m_ode_to_abm_fct; + boost::optional + m_parameters; ///< Parameters to calculated migrating compartments is start node is ode node + boost::optional>> + m_migrated_agents; ///< Agents that have migrated to target node + TimeSeries m_migrated_compartments; ///< compartments that have migrated to target node + bool m_start_node_is_abm; ///< whether node from is an abm node + AbmToOdeConversion m_abm_to_ode_fct; ///< Gets a vector with agents and returns the corresponding compartments + OdeToAbmConversion + m_ode_to_abm_fct; ///< Gets an ode node and the corresponding abm node. Updates the agents from the abm node (status and location). + OdeToAbmMapping + m_ode_to_abm_mapping; ///< Gets the migrating compartments and the abm node from which they should migrate. Picks agents according to migrating compartments from abm node, + ///< deletes them from abm node, sets their target location and adds them to m_migrated_agets }; } // namespace mio From 4aae32a5b916a22ed0de898e5a961b6b43c07350 Mon Sep 17 00:00:00 2001 From: jubicker Date: Tue, 1 Aug 2023 08:01:18 +0200 Subject: [PATCH 35/38] apply hybrid migration --- cpp/examples/graph_abm.cpp | 2 +- cpp/memilio/mobility/hybrid_graph.h | 25 +++++++- .../mobility/hybrid_graph_simulation.h | 30 ++++++--- .../mobility/metapopulation_mobility_hybrid.h | 62 ++++++++++++++++--- 4 files changed, 100 insertions(+), 19 deletions(-) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index 682641c282..30c958ad4e 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -183,7 +183,7 @@ int main() //assign hospital and ICU person.set_assigned_location(hospital); person.set_assigned_location(icu); - //assign work and school dependent on person's age + // Assign work and school dependent on Person's AgeGroup. if (person.get_age() == mio::abm::AgeGroup::Age5to14) { person.set_assigned_location(school); } diff --git a/cpp/memilio/mobility/hybrid_graph.h b/cpp/memilio/mobility/hybrid_graph.h index 4fa93f8966..08591bcfb8 100644 --- a/cpp/memilio/mobility/hybrid_graph.h +++ b/cpp/memilio/mobility/hybrid_graph.h @@ -81,6 +81,29 @@ class HybridGraph return make_range(begin(m_hybrid_edges), end(m_hybrid_edges)); } + std::vector&> get_hybrid_ode_nodes() + { + std::vector&> hybrid_ode_nodes; + for (auto& edge : m_hybrid_edges) { + hybrid_ode_nodes.push_back(get_ode_node_from_hybrid_edge(edge)); + } + return hybrid_ode_nodes; + } + + Node& get_abm_node_to_ode_node(Node& ode_node) + { + auto iter = std::find_if(m_abm_nodes_to_ode_nodes.begin(), m_abm_nodes_to_ode_nodes.end(), + [ode_node.id](const Node& node) { + return node.id == ode_node.id; + }); + if (iter != m - m_abm_nodes_to_ode_nodes.end()) { + return *iter; + } + else { + mio::log_error("No abm node to ode node exists."); + } + } + Node& get_abm_node_from_hybrid_edge(Edge& edge) { auto start_idx = edge.start_node_idx; @@ -140,4 +163,4 @@ class HybridGraph } // namespace mio -#endif //HYBRID_GRAPH_H +#endif //MIO_HYBRID_GRAPH_H diff --git a/cpp/memilio/mobility/hybrid_graph_simulation.h b/cpp/memilio/mobility/hybrid_graph_simulation.h index 80d24f2e8c..3aed0f8bd8 100644 --- a/cpp/memilio/mobility/hybrid_graph_simulation.h +++ b/cpp/memilio/mobility/hybrid_graph_simulation.h @@ -29,7 +29,7 @@ namespace mio template class HybridGraphSimulation { - using node_function_abm = std::function; + using node_function_abm = std::function; using node_function_ode = std::function; using edge_function_abm = std::function; - using edge_function_hybrid = std::function; + using edge_function_hybrid = std::function; + + using time_conversion_function = std::function; + using ode_to_abm_conversion_function = std::function; - using time_conversion_function = std::function; HybridGraphSimulation(Timepoint t0, Timespan dt, const HybridGraph& g, const node_function_abm& node_func_abm, const node_function_ode& node_func_ode, const edge_function_abm& edge_func_abm, const edge_function_ode& edge_func_ode, const edge_function_hybrid& edge_func_hybrid, - const time_conversion_function& time_conversion_func) + const time_conversion_function& time_conversion_func, + const ode_to_abm_conversion_function& ode_to_abm_conversion_function) : m_t_abm(t0) , m_dt_abm(dt) , m_t_ode(time_conversion_func(t0)) @@ -57,13 +61,15 @@ class HybridGraphSimulation , m_edge_func_abm(edge_func_abm) , m_edge_func_ode(edge_func_ode) , m_edge_func_hybrid(edge_func_hybrid) + , m_ode_to_abm_conversion_function(ode_to_abm_conversion_function) { } HybridGraphSimulation(Timepoint t0, Timespan dt, HybridGraph&& g, const node_function_abm& node_func_abm, const node_function_ode& node_func_ode, const edge_function_abm& edge_func_abm, const edge_function_ode& edge_func_ode, const edge_function_hybrid& edge_func_hybrid, - const time_conversion_function& time_conversion_func) + const time_conversion_function& time_conversion_func, + const ode_to_abm_conversion_function& ode_to_abm_conversion_function) : m_t_abm(t0) , m_dt_abm(dt) , m_t_ode(time_conversion_func(t0)) @@ -74,6 +80,7 @@ class HybridGraphSimulation , m_edge_func_abm(edge_func_abm) , m_edge_func_ode(edge_func_ode) , m_edge_func_hybrid(edge_func_hybrid) + , m_ode_to_abm_conversion_function(ode_to_abm_conversion_function) { } @@ -98,6 +105,11 @@ class HybridGraphSimulation m_t_abm += m_dt_abm; m_t_ode += m_dt_ode; + //update abm nodes to ode nodes for hybrid edges + for (auto& node : m_graph.get_hybrid_ode_nodes()) { + m_ode_to_abm_conversion_function(node, m_graph.get_abm_node_to_ode_node(node)); + } + //advance abm edges for (auto& abm_edge : m_graph.get_abm_graph().edges()) { m_edge_func_abm(m_t_abm, m_dt_abm, abm_edge.property, @@ -114,8 +126,9 @@ class HybridGraphSimulation //advance hybrid edges for (auto& hybrid_edge : m_graph.hybrid_edges()) { + auto& ode_node = m_graph.get_ode_node_from_hybrid_edge(hybrid_edge); m_edge_func_hybrid(m_t_ode, m_dt_ode, hybrid_edge, m_graph.get_abm_node_from_hybrid_edge(hybrid_edge), - m_graph.get_ode_node_from_hybrid_edge(hybrid_edge)); + ode_node, m_graph.get_abm_node_to_ode_node(ode_node)); } } @@ -136,6 +149,7 @@ class HybridGraphSimulation edge_function_abm m_edge_func_abm; edge_function_ode m_edge_func_ode; edge_function_hybrid m_edge_func_hybrid; + ode_to_abm_conversion_function m_ode_to_abm_conversion_function; }; } // namespace mio diff --git a/cpp/memilio/mobility/metapopulation_mobility_hybrid.h b/cpp/memilio/mobility/metapopulation_mobility_hybrid.h index be86975188..c1fc54837f 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_hybrid.h +++ b/cpp/memilio/mobility/metapopulation_mobility_hybrid.h @@ -73,7 +73,6 @@ class MigrationEdgeHybrid template void apply_migration(double t, double dt, NodeAbm& node_abm, NodeOde& node_ode, NodeAbm& abm_node_to_ode_node) { - mio::unused(abm_node_to_ode_node); if (m_start_node_is_abm) { //check whether agents should return if (m_migrated_agents.size() == 0) { @@ -92,7 +91,7 @@ class MigrationEdgeHybrid ++person_iter; } //convert migrating agents to ode compartments - m_migrated_compartments.add_time_point(t, m_abm_to_ode_fct(m_migrated_agents)); + m_migrated_compartments.add_time_point(t, m_agents_to_compartments_fct(m_migrated_agents)); //add migrating compartments to ode node node_ode.get_result().get_last_value() += m_migrated_compartments.get_last_value(); } @@ -126,33 +125,34 @@ class MigrationEdgeHybrid } //substract returning compartments from ode nodes node_ode.get_result().get_last_value() -= m_migrated_compartments.get_last_value(); - //convert return compartments to agents by setting migrated agents' status and location + //convert returning compartments to agents by setting migrated agents' status and location m_ode_to_abm_fct(m_migrated_compartments.get_last_value(), m_migrated_agents); //add returning agents to abm node and remove them from migrated agents while (m_migrated_agents.size() > 0) { node_abm.get_simulation().get_graph_world().add_existing_person(std::move(m_migrated_agents[0])); m_migrated_agents.erase(m_migrated_agents.begin()); } - //remove returned compartments + //remove compartments that migrated to abm m_migrated_compartments.remove_time_point(m_migrated_compartments.get_last_time()); } } //start node is ode else { + //check whether agents should return if (m_migrated_compartments.get_num_time_points() == 0) { - //update agents status and location - m_ode_to_abm_fct(node_ode.get_result().get_last_value(), - abm_node_to_ode_node.property.get_simulation().get_graph_world().get_persons()); if ((m_parameters.get_coefficients().get_matrix_at(t).array() > 0.0).any()) { + //get migrating compartments m_migrated_compartments.add_time_point( t, (node_ode.get_last_state().array() * m_parameters.get_coefficients().get_matrix_at(t).array() * get_migration_factors(node_ode, t, node_ode.get_last_state()).array()) .matrix()); + //get agents corresponding to migrating compartments m_ode_to_abm_mapping(m_migrated_compartments.get_last_value(), abm_node_to_ode_node.property.get_simulation().get_graph_world().get_persons(), m_migrated_agents); + //add persons to abm node they migrate to while (m_migrated_agents.size() > 0) { auto& target_location = node_abm.get_simulation().get_graph_world().find_location( (m_migrated_agents[0]->get_location()).get_type(), *m_migrated_agents[0]); @@ -167,6 +167,38 @@ class MigrationEdgeHybrid } //agents should return else { + //if agents return from abm node, they are in m_persons_to_migrate in the abm node they come from + size_t person_iter = 0; + auto& persons_to_migrate = + node_abm.property.get_simulation().get_graph_world().get_persons_to_migrate(); + while (person_iter < persons_to_migrate.size()) { + //get the persons that want to go to the target node + if ((persons_to_migrate[person_iter]->get_location()).get_world_id() == node_ode.id) { + //agents a removed from start node world and added to migrated agents + m_migrated_agents.push_back(std::move(persons_to_migrate[person_iter])); + node_abm.get_simulation().get_graph_world().get_persons_to_migrate().erase( + node_abm.get_simulation().get_graph_world().get_persons_to_migrate().begin() + person_iter); + continue; + } + ++person_iter; + } + //remove returned agents from migrated compartments + m_migrated_compartments.remove_time_point(m_migrated_compartments.get_last_time()); + //get compartments that return from abm + m_migrated_compartments.add_time_point(t, m_agents_to_compartments_fct(m_migrated_agents)); + //add compartments to ode node + node_ode.get_result().get_last_value() += m_migrated_compartments.get_last_value(); + //remove compartments from m_migrated_compartments again after that have been added to ode node + m_migrated_compartments.remove_time_point(m_migrated_compartments.get_last_time()); + //add agents to abm corresponding to ode node and remove them from m_migrated_agents + while (m_migrated_agents.size() > 0) { + auto& target_location = abm_node_to_ode_node.get_simulation().get_graph_world().find_location( + (m_migrated_agents[0]->get_location()).get_type(), *m_migrated_agents[0]); + m_migrated_agents[0]->migrate_to_other_world(target_location, true); + abm_node_to_ode_node.get_simulation().get_graph_world().add_existing_person( + std::move(m_migrated_agents[0])); + m_migrated_agents.erase(m_migrated_agents.begin()); + } } } } @@ -178,14 +210,26 @@ class MigrationEdgeHybrid m_migrated_agents; ///< Agents that have migrated to target node TimeSeries m_migrated_compartments; ///< compartments that have migrated to target node bool m_start_node_is_abm; ///< whether node from is an abm node - AbmToOdeConversion m_abm_to_ode_fct; ///< Gets a vector with agents and returns the corresponding compartments + AbmToOdeConversion + m_agents_to_compartments_fct; ///< Gets a vector with agents and returns the corresponding compartments OdeToAbmConversion m_ode_to_abm_fct; ///< Gets an ode node and the corresponding abm node. Updates the agents from the abm node (status and location). OdeToAbmMapping m_ode_to_abm_mapping; ///< Gets the migrating compartments and the abm node from which they should migrate. Picks agents according to migrating compartments from abm node, - ///< deletes them from abm node, sets their target location and adds them to m_migrated_agets + ///< deletes them from abm node, sets their target location and adds them to m_migrated_agents }; +/** + * edge functor for hybrid migration simulation. + * @see MigrationEdgeHybrid::apply_migration + */ +template +void apply_migration(double t, double dt, MigrationEdgeHybrid& migrationEdge, NodeOde& node_from, + NodeAbm& node_to, NodeAbm& abm_to_ode_node) +{ + migrationEdge.apply_migration(t, dt, node_from, node_to, abm_to_ode_node); +} + } // namespace mio #endif //METAPOPULATION_MOBILITY_HYBRID_H From 993cdb3df768aa6c6a94f8f2c860820f18f20215 Mon Sep 17 00:00:00 2001 From: jubicker Date: Tue, 1 Aug 2023 11:18:10 +0200 Subject: [PATCH 36/38] rename MigrationEdge to MobilityEdgeCompartments --- cpp/examples/graph.cpp | 2 +- cpp/examples/ode_secir_parameter_study.cpp | 8 +++---- cpp/memilio/compartments/parameter_studies.h | 2 +- cpp/memilio/data/analyze_result.h | 2 +- cpp/memilio/mobility/README.md | 2 +- .../mobility/metapopulation_mobility_hybrid.h | 10 ++++---- .../metapopulation_mobility_instant.h | 23 ++++++++++--------- cpp/tests/test_analyze_result.cpp | 2 +- cpp/tests/test_dynamic_npis.cpp | 2 +- cpp/tests/test_mobility.cpp | 8 +++---- 10 files changed, 31 insertions(+), 30 deletions(-) diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index df56e57541..37d5a0d618 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -46,7 +46,7 @@ int main(int argc, char** argv) model_group1.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = 9990; model_group1.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 10; - mio::Graph>, mio::MigrationEdge> g; + mio::Graph>, mio::MobilityEdgeCompartments> g; g.add_node(1001, model_group1, t0); g.add_node(1002, model_group2, t0); g.add_edge(0, 1, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.01)); diff --git a/cpp/examples/ode_secir_parameter_study.cpp b/cpp/examples/ode_secir_parameter_study.cpp index 7e26dd347e..8c8551fc21 100644 --- a/cpp/examples/ode_secir_parameter_study.cpp +++ b/cpp/examples/ode_secir_parameter_study.cpp @@ -30,9 +30,9 @@ * @param t0 starting point of simulation * @param tmax end point of simulation */ -mio::IOResult -write_single_run_result(const int run, - const mio::Graph>, mio::MigrationEdge>& graph) +mio::IOResult write_single_run_result( + const int run, + const mio::Graph>, mio::MobilityEdgeCompartments>& graph) { std::string abs_path; BOOST_OUTCOME_TRY(created, mio::create_directory("results", abs_path)); @@ -150,7 +150,7 @@ int main() auto write_result_status = write_single_run_result(run, graph); if (!write_result_status) { std::cout << "Error writing result: " << write_result_status.error().formatted_message(); - } + } return 0; //Result handler must return something, but only meaningful when using MPI. }; parameter_study.run(sample_graph, handle_result); diff --git a/cpp/memilio/compartments/parameter_studies.h b/cpp/memilio/compartments/parameter_studies.h index 15f7920c18..6369701c8e 100644 --- a/cpp/memilio/compartments/parameter_studies.h +++ b/cpp/memilio/compartments/parameter_studies.h @@ -58,7 +58,7 @@ class ParameterStudy * The Graph type that stores simulations and their results of each run. * This is the output of ParameterStudies for each run. */ - using SimulationGraph = mio::Graph, mio::MigrationEdge>; + using SimulationGraph = mio::Graph, mio::MobilityEdgeCompartments>; /** * create study for graph of compartment models. diff --git a/cpp/memilio/data/analyze_result.h b/cpp/memilio/data/analyze_result.h index 28ddbfaa77..cb44670caa 100644 --- a/cpp/memilio/data/analyze_result.h +++ b/cpp/memilio/data/analyze_result.h @@ -109,7 +109,7 @@ std::vector> ensemble_percentile(const std::vector std::vector> -interpolate_simulation_result(const Graph, MigrationEdge>& graph_result) +interpolate_simulation_result(const Graph, MobilityEdgeCompartments>& graph_result) { std::vector> interpolated; interpolated.reserve(graph_result.nodes().size()); diff --git a/cpp/memilio/mobility/README.md b/cpp/memilio/mobility/README.md index 0edde57e76..0edc2075f6 100644 --- a/cpp/memilio/mobility/README.md +++ b/cpp/memilio/mobility/README.md @@ -6,7 +6,7 @@ At each time step, the simulation executes two following phases: 1. Evolve the simulation for each node independently 2. Exchange people between nodes along the edges. The number of people exchanged depends on coefficients. The coefficient `a_i` of edge `e_xy` represents the percentage of people in compartment `i` moving from node `x` to node `y`. Like the contact matrices used in compartment models, the coefficients may contain dampings that change their value over time. During the next time step, the exchanged population will stay at their destination and participate in the evolution of that simulation. Afterwards, the people return. The total number of people returning is the same as the number that left. But the number of people in each compartment is adjusted according to the epidemiological situation in the destination node, e.g. some susceptible people that went from one node to another will have been exposed, so they return in a different compartment. -See the [mobility header](metapopulation_mobility_instant.h) and the `MigrationEdge` and `SimulationNode` classes for technical details of the two phases. +See the [mobility header](metapopulation_mobility_instant.h) and the `MobilityEdgeCompartments` and `SimulationNode` classes for technical details of the two phases. Utility classes: - Graph: Abstract class (template) that stores the simulation instances (nodes) and the connections between them (edges). diff --git a/cpp/memilio/mobility/metapopulation_mobility_hybrid.h b/cpp/memilio/mobility/metapopulation_mobility_hybrid.h index c1fc54837f..cb1c3348ad 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_hybrid.h +++ b/cpp/memilio/mobility/metapopulation_mobility_hybrid.h @@ -31,7 +31,7 @@ class MigrationEdgeHybrid //used if start node is abm node, because then we do not need MigrationParameters MigrationEdgeHybrid(const AbmToOdeConversion& abm_to_ode_fct, const OdeToAbmConversion& ode_to_abm_fct, const OdeToAbmMapping& ode_to_abm_mapping, size_t num_compartments) - : m_abm_to_ode_fct(abm_to_ode_fct) + : m_agents_to_compartments_fct(abm_to_ode_fct) , m_ode_to_abm_fct(ode_to_abm_fct) , m_ode_to_abm_mapping(ode_to_abm_mapping) , m_migrated_compartments(num_compartments) @@ -44,7 +44,7 @@ class MigrationEdgeHybrid const OdeToAbmConversion& ode_to_abm_fct, const OdeToAbmMapping& ode_to_abm_mapping) : m_parameters(params) , m_migrated_compartments(params.get_coefficients().get_shape().rows()) - , m_abm_to_ode_fct(abm_to_ode_fct) + , m_agents_to_compartments_fct(abm_to_ode_fct) , m_ode_to_abm_fct(ode_to_abm_fct) , m_ode_to_abm_mapping(ode_to_abm_mapping) , m_start_node_is_abm(false) @@ -55,7 +55,7 @@ class MigrationEdgeHybrid const OdeToAbmConversion& ode_to_abm_fct, const OdeToAbmMapping& ode_to_abm_mapping) : m_parameters(coeffs) , m_migrated_compartments(coeffs.rows()) - , m_abm_to_ode_fct(abm_to_ode_fct) + , m_agents_to_compartments_fct(abm_to_ode_fct) , m_ode_to_abm_fct(ode_to_abm_fct) , m_ode_to_abm_mapping(ode_to_abm_mapping) , m_start_node_is_abm(false) @@ -102,6 +102,7 @@ class MigrationEdgeHybrid find_value_reverse(node_ode.get_result(), m_migrated_compartments.get_last_time(), 1e-10, 1e-10); calculate_migration_returns(m_migrated_compartments.get_last_value(), node_ode.get_simulation(), *total, m_migrated_compartments.get_last_time(), dt); + //QUESTION: Does m_migrated_compartmnets still have only one time point after applying calculate_migration_returns fct i.e. is the old value overwritten by the function //the lower-order return calculation may in rare cases produce negative compartments, //especially at the beginning of the simulation. //fix by subtracting the supernumerous returns from the biggest compartment of the age group. @@ -206,8 +207,7 @@ class MigrationEdgeHybrid private: boost::optional m_parameters; ///< Parameters to calculated migrating compartments is start node is ode node - boost::optional>> - m_migrated_agents; ///< Agents that have migrated to target node + std::vector> m_migrated_agents; ///< Agents that have migrated to target node TimeSeries m_migrated_compartments; ///< compartments that have migrated to target node bool m_start_node_is_abm; ///< whether node from is an abm node AbmToOdeConversion diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index aeb33f63e1..fd2f60aa40 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -252,14 +252,14 @@ class MigrationParameters /** * represents the migration between two nodes. */ -class MigrationEdge +class MobilityEdgeCompartments { public: /** * create edge with coefficients. * @param coeffs % of people in each group and compartment that migrate in each time step. */ - MigrationEdge(const MigrationParameters& params) + MobilityEdgeCompartments(const MigrationParameters& params) : m_parameters(params) , m_migrated(params.get_coefficients().get_shape().rows()) , m_return_times(0) @@ -271,7 +271,7 @@ class MigrationEdge * create edge with coefficients. * @param coeffs % of people in each group and compartment that migrate in each time step. */ - MigrationEdge(const Eigen::VectorXd& coeffs) + MobilityEdgeCompartments(const Eigen::VectorXd& coeffs) : m_parameters(coeffs) , m_migrated(coeffs.rows()) , m_return_times(0) @@ -457,7 +457,8 @@ void test_commuters(SimulationNode& node, Eigen::Ref migra } template -void MigrationEdge::apply_migration(double t, double dt, SimulationNode& node_from, SimulationNode& node_to) +void MobilityEdgeCompartments::apply_migration(double t, double dt, SimulationNode& node_from, + SimulationNode& node_to) { //check dynamic npis if (m_t_last_dynamic_npi_check == -std::numeric_limits::infinity()) { @@ -544,12 +545,12 @@ void evolve_model(Timepoint t, Timespan dt, SimulationNode& node) /** * edge functor for migration simulation. - * @see MigrationEdge::apply_migration + * @see MobilityEdgeCompartments::apply_migration */ -template < - class Sim, class Timepoint, class Timespan, class Edge, - std::enable_if_t<((std::is_same::value) || (std::is_same::value)), - bool> = true> +template ::value) || + (std::is_same::value)), + bool> = true> void apply_migration(Timepoint t, Timespan dt, Edge& migrationEdge, SimulationNode& node_from, SimulationNode& node_to) { @@ -567,8 +568,8 @@ void apply_migration(Timepoint t, Timespan dt, Edge& migrationEdge, SimulationNo * @{ */ template -GraphSimulation, MigrationEdge>, Timepoint, Timespan> -make_migration_sim(Timepoint t0, Timespan dt, const Graph, MigrationEdge>& graph) +GraphSimulation, MobilityEdgeCompartments>, Timepoint, Timespan> +make_migration_sim(Timepoint t0, Timespan dt, const Graph, MobilityEdgeCompartments>& graph) { return make_graph_sim(t0, dt, graph, &evolve_model, &apply_migration); } diff --git a/cpp/tests/test_analyze_result.cpp b/cpp/tests/test_analyze_result.cpp index 8f019daaf9..2bf424d86e 100644 --- a/cpp/tests/test_analyze_result.cpp +++ b/cpp/tests/test_analyze_result.cpp @@ -170,7 +170,7 @@ TEST(TestInterpolateGraph, basic) { using Model = mio::osecir::Model; using Simulation = mio::Simulation; - auto g = mio::Graph, mio::MigrationEdge>(); + auto g = mio::Graph, mio::MobilityEdgeCompartments>(); g.add_node(0, Model(1), 0.5); g.add_node(1, Model(1), 0.5); for (auto& n : g.nodes()) { diff --git a/cpp/tests/test_dynamic_npis.cpp b/cpp/tests/test_dynamic_npis.cpp index 7be8888bd5..7814f8d529 100644 --- a/cpp/tests/test_dynamic_npis.cpp +++ b/cpp/tests/test_dynamic_npis.cpp @@ -281,7 +281,7 @@ TEST(DynamicNPIs, migration) mio::MigrationParameters parameters(coeffs); parameters.set_dynamic_npis_infected(npis); - mio::MigrationEdge edge(parameters); + mio::MobilityEdgeCompartments edge(parameters); ASSERT_EQ(edge.get_parameters().get_coefficients()[0].get_dampings().size(), 0); //initial diff --git a/cpp/tests/test_mobility.cpp b/cpp/tests/test_mobility.cpp index f2f052e8f4..badd4b8aef 100644 --- a/cpp/tests/test_mobility.cpp +++ b/cpp/tests/test_mobility.cpp @@ -53,7 +53,7 @@ TEST(TestMobility, compareNoMigrationWithSingleIntegration) model2.populations.set_total(500); auto graph_sim = mio::make_migration_sim( - t0, dt, mio::Graph>, mio::MigrationEdge>()); + t0, dt, mio::Graph>, mio::MobilityEdgeCompartments>()); auto& g = graph_sim.get_graph(); g.add_node(0, model1, t0); g.add_node(1, model2, t0); @@ -133,7 +133,7 @@ TEST(TestMobility, edgeApplyMigration) mio::SimulationNode> node2(model, t); //setup edge - mio::MigrationEdge edge(Eigen::VectorXd::Constant(8, 0.1)); + mio::MobilityEdgeCompartments edge(Eigen::VectorXd::Constant(8, 0.1)); //forward migration edge.apply_migration(t, 0.5, node1, node2); @@ -192,8 +192,8 @@ TEST(TestMobility, ABMEdgeApplyMigration) } } - auto t0 = mio::abm::TimePoint(0); - auto dt = mio::abm::hours(12); + auto t0 = mio::abm::TimePoint(0); + auto dt = mio::abm::hours(12); mio::SimulationNode node1(t0, std::move(world1)); mio::SimulationNode node2(t0, std::move(world2)); From c6cb337ca1e4aa7a0fd1c956f7e8926eeb54e6da Mon Sep 17 00:00:00 2001 From: jubicker Date: Tue, 1 Aug 2023 11:32:02 +0200 Subject: [PATCH 37/38] rename MigrationEdge abm and hybrid --- cpp/examples/graph_abm.cpp | 2 +- cpp/memilio/mobility/hybrid_graph.h | 8 ++++---- .../mobility/metapopulation_mobility_hybrid.h | 18 +++++++++--------- .../mobility/metapopulation_mobility_instant.h | 10 +++++----- cpp/tests/test_abm_graph_simulation.cpp | 2 +- cpp/tests/test_mobility.cpp | 2 +- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/cpp/examples/graph_abm.cpp b/cpp/examples/graph_abm.cpp index 30c958ad4e..47aa6aed38 100644 --- a/cpp/examples/graph_abm.cpp +++ b/cpp/examples/graph_abm.cpp @@ -198,7 +198,7 @@ int main() auto dt = mio::abm::hours(12); auto tmax = mio::abm::TimePoint(0) + mio::abm::days(10); - mio::Graph, mio::MigrationEdgeABM> g; + mio::Graph, mio::MobilityEdgeAgents> g; g.add_node(0, t0, std::move(world1)); g.add_node(1, t0, std::move(world2)); g.add_edge(0, 1); diff --git a/cpp/memilio/mobility/hybrid_graph.h b/cpp/memilio/mobility/hybrid_graph.h index 08591bcfb8..5b757248ba 100644 --- a/cpp/memilio/mobility/hybrid_graph.h +++ b/cpp/memilio/mobility/hybrid_graph.h @@ -29,11 +29,11 @@ namespace mio /** * @brief generic hybrid graph structure */ -template +template class HybridGraph { public: - using HybridEdge = Edge; + using HybridEdge = Edge; HybridGraph(const ABMGraph& abm_graph, const ODEGraph& ode_graph, const SetupABMFromOdeFct& setup_func, std::vector> household_distributions = {}) @@ -104,7 +104,7 @@ class HybridGraph } } - Node& get_abm_node_from_hybrid_edge(Edge& edge) + Node& get_abm_node_from_hybrid_edge(Edge& edge) { auto start_idx = edge.start_node_idx; auto end_idx = edge.end_node_idx; @@ -129,7 +129,7 @@ class HybridGraph } } - Node& get_ode_node_from_hybrid_edge(Edge& edge) + Node& get_ode_node_from_hybrid_edge(Edge& edge) { auto start_idx = edge.start_node_idx; auto end_idx = edge.end_node_idx; diff --git a/cpp/memilio/mobility/metapopulation_mobility_hybrid.h b/cpp/memilio/mobility/metapopulation_mobility_hybrid.h index cb1c3348ad..943d7b54a4 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_hybrid.h +++ b/cpp/memilio/mobility/metapopulation_mobility_hybrid.h @@ -25,12 +25,12 @@ namespace mio { template -class MigrationEdgeHybrid +class MobilityEdgeHybrid { public: //used if start node is abm node, because then we do not need MigrationParameters - MigrationEdgeHybrid(const AbmToOdeConversion& abm_to_ode_fct, const OdeToAbmConversion& ode_to_abm_fct, - const OdeToAbmMapping& ode_to_abm_mapping, size_t num_compartments) + MobilityEdgeHybrid(const AbmToOdeConversion& abm_to_ode_fct, const OdeToAbmConversion& ode_to_abm_fct, + const OdeToAbmMapping& ode_to_abm_mapping, size_t num_compartments) : m_agents_to_compartments_fct(abm_to_ode_fct) , m_ode_to_abm_fct(ode_to_abm_fct) , m_ode_to_abm_mapping(ode_to_abm_mapping) @@ -40,8 +40,8 @@ class MigrationEdgeHybrid } //constructors with parameters are used if start node is ode node - MigrationEdgeHybrid(const MigrationParameters& params, const AbmToOdeConversion& abm_to_ode_fct, - const OdeToAbmConversion& ode_to_abm_fct, const OdeToAbmMapping& ode_to_abm_mapping) + MobilityEdgeHybrid(const MigrationParameters& params, const AbmToOdeConversion& abm_to_ode_fct, + const OdeToAbmConversion& ode_to_abm_fct, const OdeToAbmMapping& ode_to_abm_mapping) : m_parameters(params) , m_migrated_compartments(params.get_coefficients().get_shape().rows()) , m_agents_to_compartments_fct(abm_to_ode_fct) @@ -51,8 +51,8 @@ class MigrationEdgeHybrid { } - MigrationEdgeHybrid(const Eigen::VectorXd& coeffs, const AbmToOdeConversion& abm_to_ode_fct, - const OdeToAbmConversion& ode_to_abm_fct, const OdeToAbmMapping& ode_to_abm_mapping) + MobilityEdgeHybrid(const Eigen::VectorXd& coeffs, const AbmToOdeConversion& abm_to_ode_fct, + const OdeToAbmConversion& ode_to_abm_fct, const OdeToAbmMapping& ode_to_abm_mapping) : m_parameters(coeffs) , m_migrated_compartments(coeffs.rows()) , m_agents_to_compartments_fct(abm_to_ode_fct) @@ -221,10 +221,10 @@ class MigrationEdgeHybrid /** * edge functor for hybrid migration simulation. - * @see MigrationEdgeHybrid::apply_migration + * @see MobilityEdgeHybrid::apply_migration */ template -void apply_migration(double t, double dt, MigrationEdgeHybrid& migrationEdge, NodeOde& node_from, +void apply_migration(double t, double dt, MobilityEdgeHybrid& migrationEdge, NodeOde& node_from, NodeAbm& node_to, NodeAbm& abm_to_ode_node) { migrationEdge.apply_migration(t, dt, node_from, node_to, abm_to_ode_node); diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index fd2f60aa40..ec04f141e0 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -309,10 +309,10 @@ class MobilityEdgeCompartments std::pair m_dynamic_npi = {-std::numeric_limits::max(), SimulationTime(0)}; }; -class MigrationEdgeABM +class MobilityEdgeAgents { public: - MigrationEdgeABM() + MobilityEdgeAgents() { } @@ -322,8 +322,8 @@ class MigrationEdgeABM }; template ::value, bool>> -void MigrationEdgeABM::apply_migration(mio::abm::TimePoint /*t*/, mio::abm::TimeSpan /*dt*/, - SimulationNode& node_from, SimulationNode& node_to) +void MobilityEdgeAgents::apply_migration(mio::abm::TimePoint /*t*/, mio::abm::TimeSpan /*dt*/, + SimulationNode& node_from, SimulationNode& node_to) { size_t person_iter = 0; auto& persons_to_migrate = node_from.get_simulation().get_graph_world().get_persons_to_migrate(); @@ -549,7 +549,7 @@ void evolve_model(Timepoint t, Timespan dt, SimulationNode& node) */ template ::value) || - (std::is_same::value)), + (std::is_same::value)), bool> = true> void apply_migration(Timepoint t, Timespan dt, Edge& migrationEdge, SimulationNode& node_from, SimulationNode& node_to) diff --git a/cpp/tests/test_abm_graph_simulation.cpp b/cpp/tests/test_abm_graph_simulation.cpp index 57cd5b9c9d..38db49e201 100644 --- a/cpp/tests/test_abm_graph_simulation.cpp +++ b/cpp/tests/test_abm_graph_simulation.cpp @@ -105,7 +105,7 @@ TEST(TestGraphSimulation, stopsAtTmaxGraphABM) auto dt = mio::abm::hours(12); auto tmax = mio::abm::TimePoint(0) + mio::abm::days(5); - mio::Graph, mio::MigrationEdgeABM> g; + mio::Graph, mio::MobilityEdgeAgents> g; g.add_node(0, t0, std::move(world1)); g.add_node(1, t0, std::move(world2)); g.add_edge(0, 1); diff --git a/cpp/tests/test_mobility.cpp b/cpp/tests/test_mobility.cpp index badd4b8aef..7525b58bbe 100644 --- a/cpp/tests/test_mobility.cpp +++ b/cpp/tests/test_mobility.cpp @@ -198,7 +198,7 @@ TEST(TestMobility, ABMEdgeApplyMigration) mio::SimulationNode node1(t0, std::move(world1)); mio::SimulationNode node2(t0, std::move(world2)); - mio::MigrationEdgeABM edge; + mio::MobilityEdgeAgents edge; EXPECT_EQ(node1.get_simulation().get_graph_world().get_persons_to_migrate().size(), 0); EXPECT_EQ(node1.get_simulation().get_graph_world().get_persons().size(), 2); From c697e448149de3b3a140a6dfc5b0176a23c16745 Mon Sep 17 00:00:00 2001 From: jubicker Date: Tue, 15 Aug 2023 13:43:45 +0200 Subject: [PATCH 38/38] undo migrationEdge renaming --- cpp/examples/graph.cpp | 2 +- cpp/examples/ode_secir_parameter_study.cpp | 2 +- cpp/memilio/compartments/parameter_studies.h | 2 +- cpp/memilio/data/analyze_result.h | 2 +- cpp/memilio/io/mobility_io.h | 7 +++--- cpp/memilio/mobility/README.md | 2 +- .../metapopulation_mobility_instant.h | 23 +++++++++---------- .../metapopulation_mobility_stochastic.h | 3 ++- .../2020_npis_sarscov2_wildtype_germany.cpp | 13 +++++------ ...021_vaccination_sarscov2_delta_germany.cpp | 13 +++++------ cpp/tests/test_analyze_result.cpp | 2 +- cpp/tests/test_dynamic_npis.cpp | 2 +- cpp/tests/test_graph.cpp | 4 ++-- cpp/tests/test_mobility.cpp | 4 ++-- cpp/tests/test_save_results.cpp | 4 ++-- 15 files changed, 42 insertions(+), 43 deletions(-) diff --git a/cpp/examples/graph.cpp b/cpp/examples/graph.cpp index 37d5a0d618..df56e57541 100644 --- a/cpp/examples/graph.cpp +++ b/cpp/examples/graph.cpp @@ -46,7 +46,7 @@ int main(int argc, char** argv) model_group1.populations[{mio::Index(mio::oseir::InfectionState::Susceptible)}] = 9990; model_group1.populations[{mio::Index(mio::oseir::InfectionState::Exposed)}] = 10; - mio::Graph>, mio::MobilityEdgeCompartments> g; + mio::Graph>, mio::MigrationEdge> g; g.add_node(1001, model_group1, t0); g.add_node(1002, model_group2, t0); g.add_edge(0, 1, Eigen::VectorXd::Constant((size_t)mio::oseir::InfectionState::Count, 0.01)); diff --git a/cpp/examples/ode_secir_parameter_study.cpp b/cpp/examples/ode_secir_parameter_study.cpp index 8c8551fc21..7083228d95 100644 --- a/cpp/examples/ode_secir_parameter_study.cpp +++ b/cpp/examples/ode_secir_parameter_study.cpp @@ -32,7 +32,7 @@ */ mio::IOResult write_single_run_result( const int run, - const mio::Graph>, mio::MobilityEdgeCompartments>& graph) + const mio::Graph>, mio::MigrationEdge>& graph) { std::string abs_path; BOOST_OUTCOME_TRY(created, mio::create_directory("results", abs_path)); diff --git a/cpp/memilio/compartments/parameter_studies.h b/cpp/memilio/compartments/parameter_studies.h index 6369701c8e..15f7920c18 100644 --- a/cpp/memilio/compartments/parameter_studies.h +++ b/cpp/memilio/compartments/parameter_studies.h @@ -58,7 +58,7 @@ class ParameterStudy * The Graph type that stores simulations and their results of each run. * This is the output of ParameterStudies for each run. */ - using SimulationGraph = mio::Graph, mio::MobilityEdgeCompartments>; + using SimulationGraph = mio::Graph, mio::MigrationEdge>; /** * create study for graph of compartment models. diff --git a/cpp/memilio/data/analyze_result.h b/cpp/memilio/data/analyze_result.h index cb44670caa..28ddbfaa77 100644 --- a/cpp/memilio/data/analyze_result.h +++ b/cpp/memilio/data/analyze_result.h @@ -109,7 +109,7 @@ std::vector> ensemble_percentile(const std::vector std::vector> -interpolate_simulation_result(const Graph, MobilityEdgeCompartments>& graph_result) +interpolate_simulation_result(const Graph, MigrationEdge>& graph_result) { std::vector> interpolated; interpolated.reserve(graph_result.nodes().size()); diff --git a/cpp/memilio/io/mobility_io.h b/cpp/memilio/io/mobility_io.h index 82ae3e6519..3872ae9994 100644 --- a/cpp/memilio/io/mobility_io.h +++ b/cpp/memilio/io/mobility_io.h @@ -133,7 +133,8 @@ IOResult write_graph(const Graph& graph, const * @param read_edges boolean value that decides whether the edges of the graph should also be read in. */ template -IOResult> read_graph(const std::string& directory, int ioflags = IOF_None, bool read_edges = true) +IOResult> read_graph(const std::string& directory, int ioflags = IOF_None, + bool read_edges = true) { std::string abs_path; if (!file_exists(directory, abs_path)) { @@ -160,7 +161,7 @@ IOResult> read_graph(const std::string& direct } //read edges; nodes must already be available for that) - if(read_edges){ + if (read_edges) { for (auto inode = size_t(0); inode < graph.nodes().size(); ++inode) { //list of edges auto edge_filename = path_join(abs_path, "GraphEdges_node" + std::to_string(inode) + ".json"); @@ -177,7 +178,7 @@ IOResult> read_graph(const std::string& direct if (end_node_idx >= graph.nodes().size()) { log_error("EndNodeIndex not in range of number of graph nodes."); return failure(StatusCode::OutOfRange, - edge_filename + ", EndNodeIndex not in range of number of graph nodes."); + edge_filename + ", EndNodeIndex not in range of number of graph nodes."); } BOOST_OUTCOME_TRY(parameters, deserialize_json(e["Parameters"], Tag{}, ioflags)); graph.add_edge(start_node_idx, end_node_idx, parameters); diff --git a/cpp/memilio/mobility/README.md b/cpp/memilio/mobility/README.md index 0edc2075f6..0edde57e76 100644 --- a/cpp/memilio/mobility/README.md +++ b/cpp/memilio/mobility/README.md @@ -6,7 +6,7 @@ At each time step, the simulation executes two following phases: 1. Evolve the simulation for each node independently 2. Exchange people between nodes along the edges. The number of people exchanged depends on coefficients. The coefficient `a_i` of edge `e_xy` represents the percentage of people in compartment `i` moving from node `x` to node `y`. Like the contact matrices used in compartment models, the coefficients may contain dampings that change their value over time. During the next time step, the exchanged population will stay at their destination and participate in the evolution of that simulation. Afterwards, the people return. The total number of people returning is the same as the number that left. But the number of people in each compartment is adjusted according to the epidemiological situation in the destination node, e.g. some susceptible people that went from one node to another will have been exposed, so they return in a different compartment. -See the [mobility header](metapopulation_mobility_instant.h) and the `MobilityEdgeCompartments` and `SimulationNode` classes for technical details of the two phases. +See the [mobility header](metapopulation_mobility_instant.h) and the `MigrationEdge` and `SimulationNode` classes for technical details of the two phases. Utility classes: - Graph: Abstract class (template) that stores the simulation instances (nodes) and the connections between them (edges). diff --git a/cpp/memilio/mobility/metapopulation_mobility_instant.h b/cpp/memilio/mobility/metapopulation_mobility_instant.h index ec04f141e0..a4b1313761 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_instant.h +++ b/cpp/memilio/mobility/metapopulation_mobility_instant.h @@ -252,14 +252,14 @@ class MigrationParameters /** * represents the migration between two nodes. */ -class MobilityEdgeCompartments +class MigrationEdge { public: /** * create edge with coefficients. * @param coeffs % of people in each group and compartment that migrate in each time step. */ - MobilityEdgeCompartments(const MigrationParameters& params) + MigrationEdge(const MigrationParameters& params) : m_parameters(params) , m_migrated(params.get_coefficients().get_shape().rows()) , m_return_times(0) @@ -271,7 +271,7 @@ class MobilityEdgeCompartments * create edge with coefficients. * @param coeffs % of people in each group and compartment that migrate in each time step. */ - MobilityEdgeCompartments(const Eigen::VectorXd& coeffs) + MigrationEdge(const Eigen::VectorXd& coeffs) : m_parameters(coeffs) , m_migrated(coeffs.rows()) , m_return_times(0) @@ -457,8 +457,7 @@ void test_commuters(SimulationNode& node, Eigen::Ref migra } template -void MobilityEdgeCompartments::apply_migration(double t, double dt, SimulationNode& node_from, - SimulationNode& node_to) +void MigrationEdge::apply_migration(double t, double dt, SimulationNode& node_from, SimulationNode& node_to) { //check dynamic npis if (m_t_last_dynamic_npi_check == -std::numeric_limits::infinity()) { @@ -545,12 +544,12 @@ void evolve_model(Timepoint t, Timespan dt, SimulationNode& node) /** * edge functor for migration simulation. - * @see MobilityEdgeCompartments::apply_migration + * @see MigrationEdge::apply_migration */ -template ::value) || - (std::is_same::value)), - bool> = true> +template < + class Sim, class Timepoint, class Timespan, class Edge, + std::enable_if_t<((std::is_same::value) || (std::is_same::value)), + bool> = true> void apply_migration(Timepoint t, Timespan dt, Edge& migrationEdge, SimulationNode& node_from, SimulationNode& node_to) { @@ -568,8 +567,8 @@ void apply_migration(Timepoint t, Timespan dt, Edge& migrationEdge, SimulationNo * @{ */ template -GraphSimulation, MobilityEdgeCompartments>, Timepoint, Timespan> -make_migration_sim(Timepoint t0, Timespan dt, const Graph, MobilityEdgeCompartments>& graph) +GraphSimulation, MigrationEdge>, Timepoint, Timespan> +make_migration_sim(Timepoint t0, Timespan dt, const Graph, MigrationEdge>& graph) { return make_graph_sim(t0, dt, graph, &evolve_model, &apply_migration); } diff --git a/cpp/memilio/mobility/metapopulation_mobility_stochastic.h b/cpp/memilio/mobility/metapopulation_mobility_stochastic.h index eb87ea77b1..05b4ecfef5 100644 --- a/cpp/memilio/mobility/metapopulation_mobility_stochastic.h +++ b/cpp/memilio/mobility/metapopulation_mobility_stochastic.h @@ -227,7 +227,8 @@ template GraphSimulationStochastic, MigrationEdgeStochastic>> make_migration_sim(double t0, double dt, const Graph, MigrationEdgeStochastic>& graph) { - return make_graph_sim_stochastic(t0, dt, graph, &evolve_model, &apply_migration); + return make_graph_sim_stochastic(t0, dt, graph, &evolve_model, + &apply_migration); } template diff --git a/cpp/simulations/2020_npis_sarscov2_wildtype_germany.cpp b/cpp/simulations/2020_npis_sarscov2_wildtype_germany.cpp index 3c77f99a62..0dc8c037e8 100644 --- a/cpp/simulations/2020_npis_sarscov2_wildtype_germany.cpp +++ b/cpp/simulations/2020_npis_sarscov2_wildtype_germany.cpp @@ -547,7 +547,7 @@ mio::IOResult run(RunMode mode, const fs::path& data_dir, const fs::path& auto parameter_study = mio::ParameterStudy>{params_graph, 0.0, num_days_sim, 0.5, size_t(num_runs)}; auto save_single_run_result = mio::IOResult(mio::success()); - auto ensemble = parameter_study.run( + auto ensemble = parameter_study.run( [](auto&& graph) { return draw_sample(graph); }, @@ -556,8 +556,8 @@ mio::IOResult run(RunMode mode, const fs::path& data_dir, const fs::path& auto params = std::vector{}; params.reserve(results_graph.nodes().size()); - std::transform(results_graph.nodes().begin(), results_graph.nodes().end(), - std::back_inserter(params), [](auto&& node) { + std::transform(results_graph.nodes().begin(), results_graph.nodes().end(), std::back_inserter(params), + [](auto&& node) { return node.property.get_simulation().get_model(); }); @@ -568,13 +568,12 @@ mio::IOResult run(RunMode mode, const fs::path& data_dir, const fs::path& return std::make_pair(std::move(interpolated_result), std::move(params)); }); - if (ensemble.size() > 0){ + if (ensemble.size() > 0) { auto ensemble_results = std::vector>>{}; ensemble_results.reserve(ensemble.size()); auto ensemble_params = std::vector>{}; ensemble_params.reserve(ensemble.size()); - for (auto&& run: ensemble) - { + for (auto&& run : ensemble) { ensemble_results.emplace_back(std::move(run.first)); ensemble_params.emplace_back(std::move(run.second)); } @@ -595,7 +594,7 @@ int main(int argc, char** argv) //- log level //- ... - mio::set_log_level(mio::LogLevel::warn); + mio::set_log_level(mio::LogLevel::warn); mio::mpi::init(); RunMode mode; diff --git a/cpp/simulations/2021_vaccination_sarscov2_delta_germany.cpp b/cpp/simulations/2021_vaccination_sarscov2_delta_germany.cpp index 68888019a7..d40bb5f0bc 100644 --- a/cpp/simulations/2021_vaccination_sarscov2_delta_germany.cpp +++ b/cpp/simulations/2021_vaccination_sarscov2_delta_germany.cpp @@ -633,16 +633,16 @@ mio::IOResult run(RunMode mode, const fs::path& data_dir, const fs::path& auto parameter_study = mio::ParameterStudy>{params_graph, 0.0, num_days_sim, 0.5, num_runs}; auto save_single_run_result = mio::IOResult(mio::success()); - auto ensemble = parameter_study.run( + auto ensemble = parameter_study.run( [&](auto&& graph) { return draw_sample(graph, high); }, [&](auto results_graph, auto&& run_idx) { auto interpolated_result = mio::interpolate_simulation_result(results_graph); - auto params = std::vector(); + auto params = std::vector(); params.reserve(results_graph.nodes().size()); - std::transform(results_graph.nodes().begin(), results_graph.nodes().end(), - std::back_inserter(params), [](auto&& node) { + std::transform(results_graph.nodes().begin(), results_graph.nodes().end(), std::back_inserter(params), + [](auto&& node) { return node.property.get_simulation().get_model(); }); @@ -654,13 +654,12 @@ mio::IOResult run(RunMode mode, const fs::path& data_dir, const fs::path& return std::make_pair(interpolated_result, params); }); - if (ensemble.size() > 0){ + if (ensemble.size() > 0) { auto ensemble_results = std::vector>>{}; ensemble_results.reserve(ensemble.size()); auto ensemble_params = std::vector>{}; ensemble_params.reserve(ensemble.size()); - for (auto&& run: ensemble) - { + for (auto&& run : ensemble) { ensemble_results.emplace_back(std::move(run.first)); ensemble_params.emplace_back(std::move(run.second)); } diff --git a/cpp/tests/test_analyze_result.cpp b/cpp/tests/test_analyze_result.cpp index 2bf424d86e..8f019daaf9 100644 --- a/cpp/tests/test_analyze_result.cpp +++ b/cpp/tests/test_analyze_result.cpp @@ -170,7 +170,7 @@ TEST(TestInterpolateGraph, basic) { using Model = mio::osecir::Model; using Simulation = mio::Simulation; - auto g = mio::Graph, mio::MobilityEdgeCompartments>(); + auto g = mio::Graph, mio::MigrationEdge>(); g.add_node(0, Model(1), 0.5); g.add_node(1, Model(1), 0.5); for (auto& n : g.nodes()) { diff --git a/cpp/tests/test_dynamic_npis.cpp b/cpp/tests/test_dynamic_npis.cpp index 7814f8d529..7be8888bd5 100644 --- a/cpp/tests/test_dynamic_npis.cpp +++ b/cpp/tests/test_dynamic_npis.cpp @@ -281,7 +281,7 @@ TEST(DynamicNPIs, migration) mio::MigrationParameters parameters(coeffs); parameters.set_dynamic_npis_infected(npis); - mio::MobilityEdgeCompartments edge(parameters); + mio::MigrationEdge edge(parameters); ASSERT_EQ(edge.get_parameters().get_coefficients()[0].get_dampings().size(), 0); //initial diff --git a/cpp/tests/test_graph.cpp b/cpp/tests/test_graph.cpp index de04b2730f..86a88245b1 100644 --- a/cpp/tests/test_graph.cpp +++ b/cpp/tests/test_graph.cpp @@ -223,8 +223,8 @@ TEST(TestGraph, set_edges) const auto& read_function_edges = mock_read_mobility; auto result = - mio::set_edges( + mio::set_edges( dir, params_graph, migrating_compartments, size_t(2), read_function_edges, std::vector{0., 0., 1.0, 1.0, 0.33, 0., 0.}); diff --git a/cpp/tests/test_mobility.cpp b/cpp/tests/test_mobility.cpp index 7525b58bbe..b33b8fbb86 100644 --- a/cpp/tests/test_mobility.cpp +++ b/cpp/tests/test_mobility.cpp @@ -53,7 +53,7 @@ TEST(TestMobility, compareNoMigrationWithSingleIntegration) model2.populations.set_total(500); auto graph_sim = mio::make_migration_sim( - t0, dt, mio::Graph>, mio::MobilityEdgeCompartments>()); + t0, dt, mio::Graph>, mio::MigrationEdge>()); auto& g = graph_sim.get_graph(); g.add_node(0, model1, t0); g.add_node(1, model2, t0); @@ -133,7 +133,7 @@ TEST(TestMobility, edgeApplyMigration) mio::SimulationNode> node2(model, t); //setup edge - mio::MobilityEdgeCompartments edge(Eigen::VectorXd::Constant(8, 0.1)); + mio::MigrationEdge edge(Eigen::VectorXd::Constant(8, 0.1)); //forward migration edge.apply_migration(t, 0.5, node1, node2); diff --git a/cpp/tests/test_save_results.cpp b/cpp/tests/test_save_results.cpp index e58cfb67ae..d78ee8673d 100644 --- a/cpp/tests/test_save_results.cpp +++ b/cpp/tests/test_save_results.cpp @@ -115,7 +115,7 @@ TEST(TestSaveResult, save_result_with_params) { //rng needs to be reseeded right before using parallel parameterstudies //to keep the rest of the tests independent, we install a temporary RNG for this test - auto rng = mio::thread_local_rng(); + auto rng = mio::thread_local_rng(); mio::thread_local_rng() = mio::RandomNumberGenerator(); mio::log_thread_local_rng_seeds(mio::LogLevel::warn); @@ -231,7 +231,7 @@ TEST(TestSaveResult, save_percentiles_and_sums) { //rng needs to be reseeded right before using parallel parameterstudies //to keep the rest of the tests independent, we install a temporary RNG for this test - auto prev_rng = mio::thread_local_rng(); + auto prev_rng = mio::thread_local_rng(); mio::thread_local_rng() = mio::RandomNumberGenerator(); mio::log_thread_local_rng_seeds(mio::LogLevel::warn);