quad_well.h Source File

CPP API: quad_well.h Source File
quad_well.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2020-2026 MEmilio
3 *
4 * Authors: René Schmieding, 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_D_ABM_QUAD_WELL_H
22 #define MIO_D_ABM_QUAD_WELL_H
23 
24 #include "memilio/math/eigen.h"
25 #include "d_abm/parameters.h"
28 #include <string>
29 #include <vector>
30 
31 using Position = Eigen::Vector2d;
32 
34 inline size_t well_index(const Position& p)
35 {
36  // 0|1
37  // -+-
38  // 2|3
39  return (p.x() >= 0) + 2 * (p.y() < 0);
40 }
41 
47 template <class InfectionState>
48 class QuadWell
49 {
50 
51 public:
53 
57  struct Agent {
60  };
61 
70  QuadWell(const std::vector<Agent>& agents, const std::vector<mio::AdoptionRate<ScalarType, Status>>& rates,
71  ScalarType contact_radius = 0.4, ScalarType sigma = 0.4, std::vector<Status> non_moving_states = {})
72  : populations(agents)
73  , m_contact_radius(contact_radius)
74  , m_sigma(sigma)
75  , m_non_moving_states(non_moving_states)
76  , m_number_transitions(static_cast<size_t>(Status::Count), Eigen::MatrixX<ScalarType>::Zero(4, 4))
77  {
78  for (auto& agent : populations) {
79  mio::unused(agent);
80  assert(is_in_domain(agent.position));
81  }
82  for (auto& r : rates) {
83  m_adoption_rates.emplace(std::forward_as_tuple(r.region, r.from, r.to), r);
84  }
85  }
86 
92  inline static constexpr void adopt(Agent& agent, const Status& new_status)
93  {
94  agent.status = new_status;
95  }
96 
103  ScalarType adoption_rate(const Agent& agent, const Status& new_status) const
104  {
105  ScalarType rate = 0;
106  // get the correct adoption rate
107  const size_t well = well_index(agent.position);
108  auto map_itr = m_adoption_rates.find({well, agent.status, new_status});
109  if (map_itr != m_adoption_rates.end()) {
110  const auto& adoption_rate = map_itr->second;
111  // calculate the current rate, depending on order
112  if (adoption_rate.influences.size() == 0) { // first order adoption
113  // contact independant rate
114  rate = adoption_rate.factor;
115  }
116  else { // second order adoption
117  // accumulate rate per contact with a status in influences
118  size_t num_contacts = 0;
119  ScalarType influences = 0;
120  for (auto& contact : populations) {
121  // check if contact is indeed a contact
122  if (is_contact(agent, contact)) {
123  num_contacts++;
124  for (size_t i = 0; i < adoption_rate.influences.size(); i++) {
125  if (contact.status == adoption_rate.influences[i].status) {
126  influences += adoption_rate.influences[i].factor;
127  }
128  }
129  }
130  }
131  // rate = factor * "concentration of contacts with status new_status"
132  if (num_contacts > 0) {
133  rate = adoption_rate.factor * (influences / num_contacts);
134  }
135  }
136  }
137  // else: no adoption from agent.status to new_status exist
138  return rate;
139  }
140 
146  void move(const ScalarType /*t*/, const ScalarType dt, Agent& agent)
147  {
148  const auto old_well = well_index(agent.position);
149  if (std::find(m_non_moving_states.begin(), m_non_moving_states.end(), agent.status) ==
150  m_non_moving_states.end() &&
151  std::find(m_non_moving_regions.begin(), m_non_moving_regions.end(), old_well) ==
152  m_non_moving_regions.end()) {
153  Position p = {
154  mio::DistributionAdapter<std::normal_distribution<ScalarType>>::get_instance()(m_rng, 0.0, 1.0),
155  mio::DistributionAdapter<std::normal_distribution<ScalarType>>::get_instance()(m_rng, 0.0, 1.0)};
156 
157  agent.position = agent.position - dt * grad_U(agent.position) + (m_sigma * std::sqrt(dt)) * p;
158  const auto new_well = well_index(agent.position);
159  if (old_well != new_well) {
160  m_number_transitions[static_cast<size_t>(agent.status)](old_well, new_well)++;
161  }
162  }
163  //else{agent has non-moving status or region}
164  }
165 
170  Eigen::VectorX<ScalarType> time_point() const
171  {
172  Eigen::VectorX<ScalarType> val = Eigen::VectorX<ScalarType>::Zero(4 * static_cast<size_t>(Status::Count));
173  for (auto& agent : populations) {
174  // split population into the wells given by grad_U
175  auto position =
176  static_cast<size_t>(agent.status) + well_index(agent.position) * static_cast<size_t>(Status::Count);
177  val[position] += 1;
178  }
179  return val;
180  }
181 
186  const std::vector<Eigen::MatrixX<ScalarType>>& number_transitions() const
187  {
188  return m_number_transitions;
189  }
190 
191  std::vector<Eigen::MatrixX<ScalarType>>& number_transitions()
192  {
193  return m_number_transitions;
194  }
195 
200  std::map<std::tuple<mio::regions::Region, Status, Status>, mio::AdoptionRate<ScalarType, Status>>&
202  {
203  return m_adoption_rates;
204  }
205 
209  void set_non_moving_regions(std::vector<size_t> non_moving_regions)
210  {
211  m_non_moving_regions = non_moving_regions;
212  }
213 
218  mio::RandomNumberGenerator& get_rng()
219  {
220  return m_rng;
221  }
222 
223  std::vector<Agent> populations;
224 
225 private:
231  static Position grad_U(const Position x)
232  {
233  // U is a quad well potential
234  // U(x0,x1) = (x0^2 - 1)^2 + (x1^2 - 1)^2
235  return {4 * x[0] * (x[0] * x[0] - 1), 4 * x[1] * (x[1] * x[1] - 1)};
236  }
237 
244  bool is_contact(const Agent& agent, const Agent& contact) const
245  {
246  // test if contact is in the contact radius and test if agent and contact are different objects
247  return (agent.position - contact.position).norm() < m_contact_radius && (&agent != &contact) &&
248  well_index(agent.position) == well_index(contact.position);
249  }
250 
256  bool is_in_domain(const Position& p) const
257  {
258  return -2 <= p[0] && p[0] <= 2 && -2 <= p[1] && p[1] <= 2;
259  }
260 
261  std::map<std::tuple<mio::regions::Region, Status, Status>, mio::AdoptionRate<ScalarType, Status>>
265  std::vector<Status> m_non_moving_states;
266  std::vector<size_t> m_non_moving_regions{};
267  std::vector<Eigen::MatrixX<ScalarType>>
269  mio::RandomNumberGenerator m_rng;
270 };
271 
272 #endif
Implementation of diffusive ABM, see dabm::Model.
Definition: quad_well.h:49
ScalarType m_contact_radius
Agents' interaction radius. Within this radius agents are considered as contacts.
Definition: quad_well.h:263
std::map< std::tuple< mio::regions::Region, Status, Status >, mio::AdoptionRate< ScalarType, Status > > m_adoption_rates
Map of AdoptionRates according to their region index and their from -> to infection states.
Definition: quad_well.h:262
Eigen::VectorX< ScalarType > time_point() const
Calculate the current system state i.e.
Definition: quad_well.h:170
static Position grad_U(const Position x)
Claculate the gradient of the potential at a given position.
Definition: quad_well.h:231
ScalarType adoption_rate(const Agent &agent, const Status &new_status) const
Calculate adoption rate for an Agent.
Definition: quad_well.h:103
void move(const ScalarType, const ScalarType dt, Agent &agent)
Perform one integration step of the diffusion process for a given Agent using the Euler-Maruyama meth...
Definition: quad_well.h:146
QuadWell(const std::vector< Agent > &agents, const std::vector< mio::AdoptionRate< ScalarType, Status >> &rates, ScalarType contact_radius=0.4, ScalarType sigma=0.4, std::vector< Status > non_moving_states={})
Set up a diffusive ABM using the quadwell potential F(x,y) = (x^2 -1)^2+(y^2-1)^2.
Definition: quad_well.h:70
mio::RandomNumberGenerator & get_rng()
Get the RandomNumberGenerator used by this Model for random events.
Definition: quad_well.h:218
std::vector< Eigen::MatrixX< ScalarType > > m_number_transitions
Vector that contains for every infection state a matrix with entry (k,l) the number of spatial transi...
Definition: quad_well.h:268
bool is_in_domain(const Position &p) const
Restrict domain to [-2, 2]^2 where "escaping" is impossible.
Definition: quad_well.h:256
std::map< std::tuple< mio::regions::Region, Status, Status >, mio::AdoptionRate< ScalarType, Status > > & get_adoption_rates()
Get AdoptionRate mapping.
Definition: quad_well.h:201
mio::RandomNumberGenerator m_rng
Model's random number generator.
Definition: quad_well.h:269
std::vector< size_t > m_non_moving_regions
Regions without movement.
Definition: quad_well.h:266
static constexpr void adopt(Agent &agent, const Status &new_status)
Perform infection state adoption for an Agent.
Definition: quad_well.h:92
ScalarType m_sigma
Noise term of the diffusion process.
Definition: quad_well.h:264
std::vector< Agent > populations
Vector containing all Agents in the model.
Definition: quad_well.h:223
void set_non_moving_regions(std::vector< size_t > non_moving_regions)
Set regions where no movement happens.
Definition: quad_well.h:209
std::vector< Status > m_non_moving_states
Infection states within which agents do not change their location.
Definition: quad_well.h:265
const std::vector< Eigen::MatrixX< ScalarType > > & number_transitions() const
Get the number of spatial transitions that happened until the current system state.
Definition: quad_well.h:186
bool is_contact(const Agent &agent, const Agent &contact) const
Evaluate whether two agents are within their contact radius.
Definition: quad_well.h:244
InfectionState Status
Definition: quad_well.h:52
std::vector< Eigen::MatrixX< ScalarType > > & number_transitions()
Definition: quad_well.h:191
double ScalarType
Configuration of memilio library.
Definition: memilio/config.h:30
ad::internal::unary_intermediate< AD_TAPE_REAL, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::operations::ad_sqrt< AD_TAPE_REAL > > sqrt(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x1)
Definition: ad.hpp:1023
InfectionState
InfectionState in ABM.
Definition: abm/infection_state.h:35
auto i
Definition: io.h:809
void unused(T &&...)
Does nothing, can be used to mark variables as not used.
Definition: compiler_diagnostics.h:30
size_t well_index(const Position &p)
Get the index of the well containing the given position.
Definition: quad_well.h:34
Eigen::Vector2d Position
Definition: quad_well.h:31
Struct defining an agent for the diffusive ABM.
Definition: quad_well.h:57
Status status
Definition: quad_well.h:59
Position position
Definition: quad_well.h:58
Struct defining a possible status adoption in a Model based on Poisson Processes.
Definition: adoption_rate.h:49