Line data Source code
1 : /* 2 : * Copyright (C) 2020-2024 MEmilio 3 : * 4 : * Authors: Julia Bicker 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 MIO_ABM_GRAPH_MOBILITY_H 22 : #define MIO_ABM_GRAPH_MOBILITY_H 23 : 24 : #include "abm/simulation.h" 25 : #include "abm/time.h" 26 : #include "abm/location_type.h" 27 : #include "abm/parameters.h" 28 : #include "abm/person.h" 29 : #include "abm/person_id.h" 30 : #include "abm/model_functions.h" 31 : #include "graph_abm/graph_abmodel.h" 32 : #include "memilio/mobility/graph_simulation.h" 33 : #include "memilio/mobility/graph.h" 34 : #include "memilio/utils/compiler_diagnostics.h" 35 : #include <algorithm> 36 : #include <cstddef> 37 : #include <iostream> 38 : #include <utility> 39 : #include <vector> 40 : 41 : namespace mio 42 : { 43 : /** 44 : * @brief Represents the ABM simulation in one node of the ABM graph model. 45 : */ 46 : template <class... History> 47 : class ABMSimulationNode 48 : { 49 : 50 : public: 51 : using Sim = abm::Simulation<GraphABModel>; 52 : 53 : template <class... Args, typename = std::enable_if_t<std::is_constructible<Sim, Args...>::value, void>> 54 6 : ABMSimulationNode(std::tuple<History...>&& history, Args&&... args) 55 6 : : m_simulation(std::forward<Args>(args)...) 56 6 : , m_history(history) 57 : { 58 6 : } 59 : 60 : /** 61 : *@brief Get abm simulation in this node. 62 : */ 63 62 : Sim& get_simulation() 64 : { 65 62 : return m_simulation; 66 : } 67 : const Sim& get_simulation() const 68 : { 69 : return m_simulation; 70 : } 71 : 72 : /** 73 : * @brief Get history object(s) in this node. 74 : */ 75 : std::tuple<History...>& get_history() 76 : { 77 : return m_history; 78 : } 79 : const std::tuple<History...>& get_history() const 80 : { 81 : return m_history; 82 : } 83 : 84 : /** 85 : * @brief advances the simulation in this node by t+dt and logs information in History object(s) 86 : * @tparam History history object type(s) 87 : * @param[in] t Current time point 88 : * @param[in] dt Time span that shoulb be advanced 89 : * @param[in, out] history History object(s) storing simulation information 90 : */ 91 24 : void advance(mio::abm::TimePoint t, mio::abm::TimeSpan dt) 92 : { 93 24 : m_simulation.advance(t + dt, std::get<0>(m_history)); 94 24 : } 95 : 96 : private: 97 : Sim m_simulation; ///< ABM Simulation of the node 98 : std::tuple<History...> m_history; 99 : }; 100 : 101 : /** 102 : * Represents the mobility between two nodes. 103 : */ 104 : template <class... History> 105 : class ABMMobilityEdge 106 : { 107 : 108 : public: 109 : /** 110 : * @brief Exchanges persons via the edge. 111 : * Commuters are given by the person buffer of node_from. 112 : * @param[in] node_from Commuters home node 113 : * @param[in] node_to Node commuters (temporarily) move to 114 : * @param[in] t Echange time point 115 : */ 116 22 : void apply_mobility(ABMSimulationNode<History...>& node_from, ABMSimulationNode<History...>& node_to, 117 : abm::TimePoint /*t*/) 118 : { 119 22 : auto& model_from = node_from.get_simulation().get_model(); 120 22 : auto& model_to = node_to.get_simulation().get_model(); 121 22 : auto& persons_to_change = model_from.get_person_buffer(); 122 : //sort vector such that we start removing the persons from the bottom 123 22 : std::sort(persons_to_change.begin(), persons_to_change.end()); 124 : //iterate over all persons that change from node_from 125 26 : for (int i = int(persons_to_change.size()) - 1; i >= 0; --i) { 126 4 : auto& person = model_from.get_persons()[persons_to_change[i]]; 127 4 : auto target_type = person.get_location_type(); 128 : //check if Person uses this edge 129 4 : if (person.get_assigned_location_model_id(target_type) == model_to.get_id()) { 130 3 : auto target_id = person.get_assigned_location(target_type); 131 : //set correct location for person 132 3 : person.set_location(target_type, target_id, model_to.get_id()); 133 : //add person to model_to 134 3 : model_to.add_person(std::move(person)); 135 : //remove person from model_from 136 3 : model_from.remove_person(persons_to_change[i]); 137 : //correct indices in persons buffer from node_from 138 : //here it is required that the vector is sorted 139 5 : for (size_t j = i + 1; j < persons_to_change.size(); ++j) { 140 2 : persons_to_change[j]--; 141 : } 142 : //delete current index from list 143 3 : persons_to_change.erase(persons_to_change.begin() + i); 144 : } 145 : } 146 22 : } 147 : }; 148 : 149 : /** 150 : * @brief Edge functor for abm graph simulation. 151 : * @see ABMMobilityEdge::apply_mobility 152 : * The attribute dt is required by the GraphSimulation class and therefore an input argument of the function. 153 : * However it is not used in ABMMobilityEdge::apply_mobility. 154 : * @param[in] t Time point the functor is applied. 155 : * @param[in] edge ABMMobilityEdge for which the functor is applied. 156 : * @param[in] node_from Edge start node. 157 : * @param[in] node_to Edge end node. 158 : */ 159 : template <class... History> 160 20 : void apply_mobility(abm::TimePoint t, abm::TimeSpan /*dt*/, ABMMobilityEdge<History...>& edge, 161 : ABMSimulationNode<History...>& node_from, ABMSimulationNode<History...>& node_to) 162 : { 163 20 : edge.apply_mobility(node_from, node_to, t); 164 20 : } 165 : 166 : /** 167 : * @brief Node functor for abm graph simulation. 168 : * @see ABMSimulationNode::advance 169 : * @param[in] t Time point the functor is applied. 170 : * @param[in] dt Time interval the node is advanced. 171 : * @param[in] node ABMSimulationNode to which the functor is applied. 172 : */ 173 : template <class... History> 174 20 : void advance_model(abm::TimePoint t, abm::TimeSpan dt, ABMSimulationNode<History...>& node) 175 : { 176 20 : node.advance(t, dt); 177 20 : } 178 : 179 : /** 180 : * @brief Creates an abm graph simulation. 181 : * Every dt time step for each edge the persons that want to change to a location in another node 182 : * are removed from the model in their former location's node and added to the model of the new location. 183 : * @param[in] t0 Start time point of the simulation. 184 : * @param[in] dt Step between mobility on edges. 185 : * @param[in] graph Graph for simulation. 186 : */ 187 : template <class... History> 188 : GraphSimulation<Graph<ABMSimulationNode<History...>, ABMMobilityEdge<History...>>, abm::TimePoint, abm::TimeSpan, 189 : void (*)(mio::abm::TimePoint, mio::abm::TimeSpan, mio::ABMMobilityEdge<History...>&, 190 : mio::ABMSimulationNode<History...>&, mio::ABMSimulationNode<History...>&), 191 : void (*)(mio::abm::TimePoint, mio::abm::TimeSpan, mio::ABMSimulationNode<History...>&)> 192 1 : make_abm_graph_sim(abm::TimePoint t0, abm::TimeSpan dt, 193 : Graph<ABMSimulationNode<History...>, ABMMobilityEdge<History...>>&& graph) 194 : { 195 1 : return make_graph_sim(t0, dt, std::move(graph), &advance_model<History...>, &apply_mobility<History...>); 196 : } 197 : 198 : } // namespace mio 199 : 200 : #endif // MIO_ABM_GRAPH_MOBILITY_H