Line data Source code
1 : /* 2 : * Copyright (C) 2020-2023 German Aerospace Center (DLR-SC) 3 : * 4 : * Authors: Sascha Korf 5 : * 6 : * Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de> 7 : * 8 : * Licensed under the Apache License, Version 2.0 (the "License"); 9 : * you may not use this file except in compliance with the License. 10 : * You may obtain a copy of the License at 11 : * 12 : * http://www.apache.org/licenses/LICENSE-2.0 13 : * 14 : * Unless required by applicable law or agreed to in writing, software 15 : * distributed under the License is distributed on an "AS IS" BASIS, 16 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 : * See the License for the specific language governing permissions and 18 : * limitations under the License. 19 : */ 20 : 21 : #ifndef ABM_COMMON_LOGGERS_H 22 : #define ABM_COMMON_LOGGERS_H 23 : 24 : #include "abm/infection_state.h" 25 : #include "abm/person_id.h" 26 : #include "abm/simulation.h" 27 : #include "memilio/io/history.h" 28 : #include "memilio/utils/time_series.h" 29 : #include "models/abm/location_type.h" 30 : #include "abm/mobility_data.h" 31 : #include "memilio/utils/mioomp.h" 32 : 33 : namespace mio 34 : { 35 : namespace abm 36 : { 37 : 38 : /** 39 : * @brief Struct to save specific mobility data of an agent. 40 : * The data consists of: 41 : * 42 : */ 43 : struct mobility_data { 44 : uint32_t agent_id; 45 : uint32_t from_id; 46 : uint32_t to_id; 47 : mio::abm::TimePoint start_time; 48 : mio::abm::TimePoint end_time; 49 : mio::abm::TransportMode transport_mode; 50 : mio::abm::ActivityType activity_type; 51 : mio::abm::InfectionState infection_state; 52 : }; 53 : 54 1350 : constexpr mio::abm::ActivityType guess_activity_type(mio::abm::LocationType current_location) 55 : { 56 1350 : switch (current_location) { 57 792 : case mio::abm::LocationType::Home: 58 792 : return mio::abm::ActivityType::Home; 59 18 : case mio::abm::LocationType::Work: 60 18 : return mio::abm::ActivityType::Workplace; 61 0 : case mio::abm::LocationType::School: 62 0 : return mio::abm::ActivityType::Education; 63 18 : case mio::abm::LocationType::SocialEvent: 64 18 : return mio::abm::ActivityType::Leisure; 65 36 : case mio::abm::LocationType::BasicsShop: 66 36 : return mio::abm::ActivityType::Shopping; 67 18 : case mio::abm::LocationType::ICU: 68 18 : return mio::abm::ActivityType::OtherActivity; 69 18 : case mio::abm::LocationType::Hospital: 70 18 : return mio::abm::ActivityType::OtherActivity; 71 432 : case mio::abm::LocationType::Cemetery: 72 432 : return mio::abm::ActivityType::OtherActivity; 73 18 : default: 74 18 : return mio::abm::ActivityType::UnknownActivity; 75 : } 76 : } 77 : 78 : /** 79 : * @brief Logger to log the LocationInformation of the simulation. 80 : */ 81 : struct LogLocationInformation : mio::LogOnce { 82 : using Type = std::vector< 83 : std::tuple<mio::abm::LocationId, mio::abm::LocationType, mio::abm::GeographicalLocation, size_t, int>>; 84 : /** 85 : * @brief Log the LocationInformation of the simulation. 86 : * @param[in] sim The simulation of the abm. 87 : * @return A vector of tuples with the LocationInformation, where each tuple contains the following information: 88 : * -# The index of the location. 89 : * -# The type of the location. 90 : * -# The geographical location of the location. 91 : * -# The number of cells in the location. 92 : * -# The capacity of the location. 93 : */ 94 9 : static Type log(const mio::abm::Simulation& sim) 95 : { 96 9 : Type location_information{}; 97 90 : for (auto& location : sim.get_model().get_locations()) { 98 81 : auto n_cells = location.get_cells().size(); 99 81 : int loc_capacity = 0; 100 162 : for (int i = 0; i < (int)n_cells; i++) { 101 81 : loc_capacity += location.get_capacity(i).persons; 102 : } 103 162 : location_information.push_back(std::make_tuple( 104 162 : location.get_id(), location.get_type(), location.get_geographical_location(), n_cells, loc_capacity)); 105 : } 106 18 : return location_information; 107 9 : } 108 : }; 109 : 110 : /** 111 : * @brief Logger to log the Person%s Information in the simulation. 112 : */ 113 : struct LogPersonInformation : mio::LogOnce { 114 : using Type = std::vector<std::tuple<mio::abm::PersonId, mio::abm::LocationId, mio::AgeGroup>>; 115 : /** 116 : * @brief Log the LocationInformation of the simulation. 117 : * @param[in] sim The simulation of the abm. 118 : * @return A vector of tuples with the LocationInformation, where each tuple contains the following information: 119 : * -# The person id. 120 : * -# The index of the home location. 121 : * -# The age group of the person. 122 : */ 123 9 : static Type log(const mio::abm::Simulation& sim) 124 : { 125 9 : Type person_information{}; 126 9 : person_information.reserve(sim.get_model().get_persons().size()); 127 36 : for (auto& person : sim.get_model().get_persons()) { 128 54 : person_information.push_back(std::make_tuple( 129 54 : person.get_id(), sim.get_model().find_location(mio::abm::LocationType::Home, person.get_id()), 130 54 : person.get_age())); 131 : } 132 18 : return person_information; 133 9 : } 134 : }; 135 : 136 : /** 137 : * @brief Logger to log mobility data of the agents in the simulation. 138 : */ 139 : struct LogDataForMobility : mio::LogAlways { 140 : using Type = std::vector<std::tuple<mio::abm::PersonId, mio::abm::LocationId, mio::abm::TimePoint, 141 : mio::abm::TransportMode, mio::abm::ActivityType, mio::abm::InfectionState>>; 142 : /** 143 : * @brief Log the mobility data of the agents in the simulation. 144 : * @param[in] sim The simulation of the ABM. 145 : * @return A vector of tuples with the mobility Data, where each tuple contains the following information: 146 : * -# The person id. 147 : * -# The index of the location. 148 : * -# The time point. 149 : * -# The transport mode. 150 : * -# The activity type. 151 : * -# The infection state. 152 : */ 153 450 : static Type log(const mio::abm::Simulation& sim) 154 : { 155 450 : Type mobility_data{}; 156 1800 : for (Person p : sim.get_model().get_persons()) { 157 1350 : mobility_data.push_back( 158 4050 : std::make_tuple(p.get_id(), p.get_location(), sim.get_time(), p.get_last_transport_mode(), 159 2700 : guess_activity_type(p.get_location_type()), p.get_infection_state(sim.get_time()))); 160 1350 : } 161 900 : return mobility_data; 162 450 : } 163 : }; 164 : 165 : /** 166 : * @brief Logger to log the TimeSeries of the number of Person%s in an #InfectionState. 167 : */ 168 : struct LogInfectionState : mio::LogAlways { 169 : using Type = std::pair<mio::abm::TimePoint, Eigen::VectorXd>; 170 : /** 171 : * @brief Log the TimeSeries of the number of Person%s in an #InfectionState. 172 : * @param[in] sim The simulation of the abm. 173 : * @return A pair of the TimePoint and the TimeSeries of the number of Person%s in an #InfectionState. 174 : */ 175 684 : static Type log(const mio::abm::Simulation& sim) 176 : { 177 : 178 684 : Eigen::VectorXd sum = Eigen::VectorXd::Zero(Eigen::Index(mio::abm::InfectionState::Count)); 179 684 : auto curr_time = sim.get_time(); 180 : PRAGMA_OMP(for) 181 4086 : for (auto& location : sim.get_model().get_locations()) { 182 30618 : for (uint32_t inf_state = 0; inf_state < (int)mio::abm::InfectionState::Count; inf_state++) { 183 27216 : sum[inf_state] += sim.get_model().get_subpopulation(location.get_id(), curr_time, 184 : mio::abm::InfectionState(inf_state)); 185 : } 186 : } 187 1368 : return std::make_pair(curr_time, sum); 188 684 : } 189 : }; 190 : 191 : /** 192 : * @brief This is like the DataWriterToMemory, but it only logs time series data. 193 : * @tparam Loggers The loggers that are used to log data. The loggers must return a touple with a TimePoint and a value. 194 : */ 195 : template <class... Loggers> 196 : struct TimeSeriesWriter { 197 : using Data = std::tuple<mio::TimeSeries<ScalarType>>; 198 : template <class Logger> 199 : /** 200 : * @brief This function adds an entry to the TimeSeries consisting of the TimePoint and the value. The Loggers must return a touple with a TimePoint and a value of return type Eigen::VectorXd. 201 : * @param[in] t The data from the logger. 202 : * @param[in,out] data The data tuple. 203 : */ 204 684 : static void add_record(const typename Logger::Type& t, Data& data) 205 : { 206 684 : std::get<index_of_type_v<Logger, Loggers...>>(data).add_time_point(t.first.days(), t.second); 207 684 : } 208 : }; 209 : 210 : /** 211 : * @brief This class writes data retrieved from loggers to memory. It can be used as the Writer template parameter for the History class. 212 : * This specialization just saves the difference to the last saved data. Suitable when one wants to save huge data with a few changes. 213 : * @tparam Loggers The loggers that are used to log data. 214 : */ 215 : template <class... Loggers> 216 : struct DataWriterToMemoryDelta { 217 : using Data = std::tuple<std::vector<typename Loggers::Type>...>; 218 : template <class Logger> 219 : /** 220 : * @brief This function adds an entry to the data vector. 221 : * @param[in] t The data from the logger. 222 : * @param[in,out] data The data tuple. 223 : * @details The data is only added if it differs from the last entry. For this we use the first entry as a reference for the current position. 224 : */ 225 225 : static void add_record(const typename Logger::Type& t, Data& data) 226 : { 227 : 228 225 : if (std::get<index_of_type_v<Logger, Loggers...>>(data).size() > 0) { 229 216 : typename Logger::Type diff_vector{}; 230 216 : auto& current_state_vec = std::get<index_of_type_v<Logger, Loggers...>>(data).front(); 231 864 : for (auto i = 0; i < (int)current_state_vec.size(); i++) { 232 648 : if (std::get<1>(t[i]) != std::get<1>(current_state_vec[i])) { 233 90 : std::get<1>(current_state_vec[i]) = std::get<1>(t[i]); 234 90 : diff_vector.push_back(t[i]); 235 : } 236 : } 237 216 : std::get<index_of_type_v<Logger, Loggers...>>(data).push_back(diff_vector); 238 216 : } 239 : else { 240 9 : std::get<index_of_type_v<Logger, Loggers...>>(data).push_back( 241 : t); // We use the first entry as a reference for the current position. 242 9 : std::get<index_of_type_v<Logger, Loggers...>>(data).push_back(t); 243 : } 244 225 : } 245 : }; 246 : 247 : } // namespace abm 248 : } // namespace mio 249 : #endif //ABM_COMMON_LOGGERS_H