single_well.h Source File

CPP API: single_well.h Source File
single_well.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2020-2026 MEmilio
3 *
4 * Authors: Julia Bicker, René Schmieding
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_SINGLE_WELL_H
22 #define MIO_D_ABM_SINGLE_WELL_H
23 
24 #include "memilio/config.h"
25 #include "memilio/math/eigen.h"
26 #include "d_abm/parameters.h"
29 
34 {
35 public:
36  using Position = Eigen::Vector2d;
37 
44  SWPositionSampler(const Position& bottom_left, const Position& top_right, ScalarType margin)
45  {
46  auto assign_range = [&](Position range_x, Position range_y) {
47  range_x += Position{margin, -margin};
48  range_y += Position{margin, -margin};
49  m_range = {range_x, range_y};
50  };
51 
52  assign_range({bottom_left.x(), top_right.x()}, {bottom_left.y(), top_right.y()});
53  }
54 
59  {
60  return {mio::UniformDistribution<ScalarType>::get_instance()(mio::thread_local_rng(), m_range.first[0],
61  m_range.first[1]),
62  mio::UniformDistribution<ScalarType>::get_instance()(mio::thread_local_rng(), m_range.second[0],
63  m_range.second[1])};
64  }
65 
66 private:
67  // stores pairs of (x-range, y-range)
68  std::pair<Position, Position> m_range;
69 };
70 
76 template <class InfectionState>
78 {
79 public:
80  using Position = Eigen::Vector2d;
82 
83  struct Agent {
86  };
87 
96  SingleWell(const std::vector<Agent>& agents, const std::vector<mio::AdoptionRate<ScalarType, Status>>& rates,
97  ScalarType contact_radius = 0.4, ScalarType sigma = 0.4, std::vector<Status> non_moving_states = {})
98  : populations(agents)
99  , m_contact_radius(contact_radius)
100  , m_sigma(sigma)
101  , m_non_moving_states(non_moving_states)
102  {
103  for (auto& agent : populations) {
104  mio::unused(agent);
105  assert(is_in_domain(agent.position));
106  }
107  for (auto& r : rates) {
108  m_adoption_rates.emplace(std::forward_as_tuple(r.region, r.from, r.to), r);
109  }
110  }
111 
117  inline static constexpr void adopt(Agent& agent, const Status& new_status)
118  {
119  agent.status = new_status;
120  }
121 
128  ScalarType adoption_rate(const Agent& agent, const Status& new_status) const
129  {
130  ScalarType rate = 0;
131  // get the correct adoption rate
132  const size_t well = 0;
133  auto map_itr = m_adoption_rates.find({well, agent.status, new_status});
134  if (map_itr != m_adoption_rates.end()) {
135  const auto& adoption_rate = map_itr->second;
136  // calculate the current rate, depending on order
137  if (adoption_rate.influences.size() == 0) { // first order adoption
138  // contact independant rate
139  rate = adoption_rate.factor;
140  }
141  else { // second order adoption
142  // accumulate rate per contact with a status in influences
143  size_t num_contacts = 0;
144  ScalarType influences = 0;
145  for (auto& contact : populations) {
146  // check if contact is indeed a contact
147  if (is_contact(agent, contact)) {
148  num_contacts++;
149  for (size_t i = 0; i < adoption_rate.influences.size(); i++) {
150  if (contact.status == adoption_rate.influences[i].status) {
151  influences += adoption_rate.influences[i].factor;
152  }
153  }
154  }
155  }
156  // rate = factor * "concentration of contacts with status new_status"
157  if (num_contacts > 0) {
158  rate = adoption_rate.factor * (influences / num_contacts);
159  }
160  }
161  }
162  // else: no adoption from agent.status to new_status exist
163  return rate;
164  }
165 
171  void move(const ScalarType /*t*/, const ScalarType dt, Agent& agent)
172  {
173  if (std::find(m_non_moving_states.begin(), m_non_moving_states.end(), agent.status) ==
174  m_non_moving_states.end()) {
175  Position p = {
176  mio::DistributionAdapter<std::normal_distribution<ScalarType>>::get_instance()(m_rng, 0.0, 1.0),
177  mio::DistributionAdapter<std::normal_distribution<ScalarType>>::get_instance()(m_rng, 0.0, 1.0)};
178 
179  agent.position = agent.position - dt * grad_U(agent.position) + (m_sigma * std::sqrt(dt)) * p;
180  }
181  //else{agent has non-moving status}
182  }
183 
188  Eigen::VectorX<ScalarType> time_point() const
189  {
190  Eigen::VectorX<ScalarType> val = Eigen::VectorX<ScalarType>::Zero(static_cast<size_t>(Status::Count));
191  for (auto& agent : populations) {
192  val[static_cast<size_t>(agent.status)] += 1;
193  }
194  return val;
195  }
196 
197  std::map<std::tuple<mio::regions::Region, Status, Status>, mio::AdoptionRate<ScalarType, Status>>&
199  {
200  return m_adoption_rates;
201  }
202 
207  mio::RandomNumberGenerator& get_rng()
208  {
209  return m_rng;
210  }
211 
212  std::vector<Agent> populations;
213 
214 private:
220  static Position grad_U(const Position p)
221  {
222  // U is a single well potential
223  // U(x0,x1) = (x0^4 + x1^4)/2
224  return {2 * p[0] * p[0] * p[0], 2 * p[1] * p[1] * p[1]};
225  }
226 
233  bool is_contact(const Agent& agent, const Agent& contact) const
234  {
235  // test if contact is in the contact radius and test if agent and contact are different objects
236  return (agent.position - contact.position).norm() < m_contact_radius && (&agent != &contact);
237  }
238 
244  bool is_in_domain(const Position& p, const ScalarType lower_domain_border = -2,
245  const ScalarType upper_domain_border = 2) const
246  {
247  // restrict domain to [lower_domain_border, upper_domain_border]^2 where "escaping" is impossible, i.e. it holds x <= grad_U(x) for dt <= 0.1
248  return lower_domain_border <= p[0] && p[0] <= upper_domain_border && lower_domain_border <= p[1] &&
249  p[1] <= upper_domain_border;
250  }
251 
252  std::map<std::tuple<mio::regions::Region, Status, Status>, mio::AdoptionRate<ScalarType, Status>>
256  std::vector<Status> m_non_moving_states;
257  mio::RandomNumberGenerator m_rng;
258 };
259 
260 #endif //MIO_D_ABM_SINGLE_WELL_H
A Sampler for sampling a position for the singlewell potential F(x,y) = (x^4 + y^4)/2,...
Definition: single_well.h:34
SWPositionSampler(const Position &bottom_left, const Position &top_right, ScalarType margin)
Create a sampler.
Definition: single_well.h:44
std::pair< Position, Position > m_range
Definition: single_well.h:68
Position operator()() const
Sampling a position within [bottom_left.x + margin, bottom_left.y + margin] x [top_right....
Definition: single_well.h:58
Eigen::Vector2d Position
Definition: single_well.h:36
Implementation of diffusive ABM, see dabm::Model.
Definition: single_well.h:78
InfectionState Status
Definition: single_well.h:81
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: single_well.h:171
std::map< std::tuple< mio::regions::Region, Status, Status >, mio::AdoptionRate< ScalarType, Status > > & get_adoption_rates()
Definition: single_well.h:198
mio::RandomNumberGenerator & get_rng()
Get the RandomNumberGenerator used by this Model for random events.
Definition: single_well.h:207
std::vector< Status > m_non_moving_states
Infection states within which agents do not change their location.
Definition: single_well.h:256
bool is_in_domain(const Position &p, const ScalarType lower_domain_border=-2, const ScalarType upper_domain_border=2) const
Restrict domain to [-2, 2]^2 where "escaping" is impossible.
Definition: single_well.h:244
ScalarType adoption_rate(const Agent &agent, const Status &new_status) const
Calculate adoption rate for an Agent.
Definition: single_well.h:128
mio::RandomNumberGenerator m_rng
Model's random number generator.
Definition: single_well.h:257
static Position grad_U(const Position p)
Calculate the gradient of the potential at a given position.
Definition: single_well.h:220
bool is_contact(const Agent &agent, const Agent &contact) const
Evaluate whether two agents are within their contact radius.
Definition: single_well.h:233
Eigen::VectorX< ScalarType > time_point() const
Calculate the current system state i.e.
Definition: single_well.h:188
ScalarType m_contact_radius
Agents' interaction radius. Within this radius agents are considered as contacts.
Definition: single_well.h:254
ScalarType m_sigma
Noise term of the diffusion process.
Definition: single_well.h:255
Eigen::Vector2d Position
Definition: single_well.h:80
static constexpr void adopt(Agent &agent, const Status &new_status)
Perform infection state adoption for an Agent.
Definition: single_well.h:117
std::vector< Agent > populations
Vector containing all Agents in the model.
Definition: single_well.h:212
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: single_well.h:253
SingleWell(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^4 + y^4)/2.
Definition: single_well.h:96
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
RandomNumberGenerator & thread_local_rng()
Definition: random_number_generator.cpp:25
Definition: single_well.h:83
Position position
Definition: single_well.h:84
Status status
Definition: single_well.h:85
Struct defining a possible status adoption in a Model based on Poisson Processes.
Definition: adoption_rate.h:49