ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
core/reaction_methods/ReactionAlgorithm.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19#ifndef REACTION_METHODS_REACTION_ALGORITHM_HPP
20#define REACTION_METHODS_REACTION_ALGORITHM_HPP
21
22#include "config/config.hpp"
23
24#include "SingleReaction.hpp"
25
26#include "Particle.hpp"
27#include "random.hpp"
28
29#include <utils/Vector.hpp>
30
31#include <functional>
32#include <memory>
33#include <optional>
34#include <random>
35#include <stdexcept>
36#include <tuple>
37#include <unordered_map>
38#include <utility>
39#include <vector>
40
41namespace boost::mpi {
42class communicator;
43} // namespace boost::mpi
44
45namespace ReactionMethods {
46
47/** Base class for reaction ensemble methods */
49private:
50 boost::mpi::communicator const &m_comm;
51
52public:
54 boost::mpi::communicator const &comm, int seed, double kT,
55 double exclusion_range,
56 std::unordered_map<int, double> const &exclusion_radius_per_type)
57 : m_comm{comm}, kT{kT}, exclusion_range{exclusion_range},
58 m_generator(Random::mt19937(std::seed_seq({seed, seed, seed}))),
59 m_normal_distribution(0.0, 1.0), m_uniform_real_distribution(0.0, 1.0),
60 m_exponential_distribution(1.) {
61 if (kT < 0.) {
62 throw std::domain_error("Invalid value for 'kT'");
63 }
64 if (exclusion_range < 0.) {
65 throw std::domain_error("Invalid value for 'exclusion_range'");
66 }
69 }
70
71 virtual ~ReactionAlgorithm() = default;
72
73 std::vector<std::shared_ptr<SingleReaction>> reactions;
74 std::unordered_map<int, double> charges_of_types;
75 double kT;
76 /**
77 * Hard sphere radius. If particles are closer than this value,
78 * it is assumed that their interaction energy gets approximately
79 * infinite, therefore these configurations do not contribute
80 * to the partition function and ensemble averages.
81 */
83 std::unordered_map<int, double> exclusion_radius_per_type;
84 double volume;
86
90 return static_cast<double>(m_accepted_configurational_MC_moves) /
91 static_cast<double>(m_tried_configurational_MC_moves);
92 }
93
94 auto get_kT() const { return kT; }
95 auto get_exclusion_range() const { return exclusion_range; }
96 auto get_volume() const { return volume; }
97 void set_volume(double new_volume) {
98 if (new_volume <= 0.) {
99 throw std::domain_error("Invalid value for 'volume'");
100 }
101 volume = new_volume;
102 }
103 void update_volume();
104 void
105 set_exclusion_radius_per_type(std::unordered_map<int, double> const &map) {
106 auto max_exclusion_range = exclusion_range;
107 for (auto const &item : map) {
108 auto const type = item.first;
109 auto const exclusion_radius = item.second;
110 if (exclusion_radius < 0.) {
111 throw std::domain_error("Invalid excluded_radius value for type " +
112 std::to_string(type) + ": radius " +
113 std::to_string(exclusion_radius));
114 }
115 max_exclusion_range =
116 std::max(max_exclusion_range, 2. * exclusion_radius);
117 }
119 m_max_exclusion_range = max_exclusion_range;
120 }
121
122 void remove_constraint() { m_reaction_constraint = ReactionConstraint::NONE; }
123 void set_cyl_constraint(double center_x, double center_y, double radius);
124 void set_slab_constraint(double slab_start_z, double slab_end_z);
126 if (m_reaction_constraint != ReactionConstraint::SLAB_Z) {
127 throw std::runtime_error("no slab constraint is currently active");
128 }
129 return {m_slab_start_z, m_slab_end_z};
130 }
131
133 void delete_particle(int p_id);
134 void add_reaction(std::shared_ptr<SingleReaction> const &new_reaction);
135 void delete_reaction(int reaction_id) {
136 reactions.erase(reactions.begin() + reaction_id);
137 }
138
141
142protected:
144
145public:
147 std::vector<int> created{};
148 std::vector<std::tuple<int, int>> changed{};
149 std::vector<std::tuple<int, int>> hidden{};
150 std::vector<std::tuple<int, Utils::Vector3d, Utils::Vector3d>> moved{};
151 std::unordered_map<int, int> old_particle_numbers{};
152 int reaction_id{-1};
153 };
154
155 bool is_reaction_under_way() const { return m_system_changes != nullptr; }
156 auto const &get_old_system_state() const {
157 if (not is_reaction_under_way()) {
158 throw std::runtime_error("No chemical reaction is currently under way");
159 }
160 return *m_system_changes;
161 }
162
163protected:
164 /** @brief Restore last valid system state. */
166 /** @brief Clear last valid system state. */
168 assert(is_reaction_under_way());
169 m_system_changes = nullptr;
170 }
171 /** @brief Open new handle for system state tracking. */
173 assert(not is_reaction_under_way());
174 m_system_changes = std::make_shared<ParticleChanges>();
175 return *m_system_changes;
176 }
177 std::shared_ptr<ParticleChanges> m_system_changes;
178
179public:
180 /**
181 * Carry out a reaction MC move and calculate the new potential energy.
182 * Particles are selected without replacement.
183 * The previous state of the system is cached.
184 * @returns Potential energy of the system after the move.
185 */
186 std::optional<double> create_new_trial_state(int reaction_id);
187 /**
188 * Accept or reject a reaction MC move made by @ref create_new_trial_state
189 * based on a logarithmic probability acceptance @c ln_bf.
190 * The previous state of the system is either restored from the cache if
191 * the move is rejected, or cleared from the cache if the move is accepted.
192 * @returns Potential energy of the system after the move was accepted or
193 * rejected.
194 */
195 double make_reaction_mc_move_attempt_logarithmic(int reaction_id,
196 double ln_bf,
197 double E_pot_old,
198 double E_pot_new);
199
200 /**
201 * Attempt displacement MC moves for particles of a given type.
202 * Particles are selected without replacement.
203 * @param type Type of particles to move.
204 * @param n_particles Number of particles of that type to move.
205 * @returns true if all moves were accepted.
206 */
207 bool make_displacement_mc_move_attempt(int type, int n_particles);
208
209 /** @brief Compute the system potential energy. */
210 double calculate_potential_energy() const;
211
212protected:
213 /**
214 * Carry out displacement MC moves for particles of a given type.
215 * Particles are selected without replacement.
216 * @param type Type of particles to move.
217 * @param n_particles Number of particles of that type to move.
218 */
219 void displacement_mc_move(int type, int n_particles);
220
221 /** @brief Carry out a chemical reaction and save the old system state. */
223 ParticleChanges &bookkeeping);
224
225public:
226 /**
227 * @brief draws a random integer from the uniform distribution in the range
228 * [0,maxint-1]
229 *
230 * @param maxint range.
231 */
232 int i_random(int maxint) {
233 std::uniform_int_distribution<int> uniform_int_dist(0, maxint - 1);
234 return uniform_int_dist(m_generator);
235 }
236
237protected:
238 bool
239 all_reactant_particles_exist(SingleReaction const &current_reaction) const;
240
241private:
242 std::mt19937 m_generator;
243 std::normal_distribution<double> m_normal_distribution;
244 std::uniform_real_distribution<double> m_uniform_real_distribution;
245 std::exponential_distribution<double> m_exponential_distribution;
246
247 std::unordered_map<int, int>
248 get_particle_numbers(SingleReaction const &reaction) const;
249
250 int create_particle(int p_type);
251 void hide_particle(int p_id, int p_type) const;
252 void check_exclusion_range(int p_id, int p_type);
253 auto get_random_uniform_number() {
254 return m_uniform_real_distribution(m_generator);
255 }
256 auto get_random_logarithmic_number() {
257 return m_exponential_distribution(m_generator);
258 }
259 auto get_random_velocity_vector() {
260 return Utils::Vector3d{m_normal_distribution(m_generator),
261 m_normal_distribution(m_generator),
262 m_normal_distribution(m_generator)};
263 }
264
265 enum class ReactionConstraint { NONE, CYL_Z, SLAB_Z };
266 ReactionConstraint m_reaction_constraint = ReactionConstraint::NONE;
267 double m_cyl_radius = -10.0;
268 double m_cyl_x = -10.0;
269 double m_cyl_y = -10.0;
270 double m_slab_start_z = -10.0;
271 double m_slab_end_z = -10.0;
272 double m_max_exclusion_range = 0.;
273
274 Particle *get_real_particle(int p_id) const;
275 Particle *get_local_particle(int p_id) const;
276
277protected:
279};
280
281} // namespace ReactionMethods
282#endif
Vector implementation and trait types for boost qvm interoperability.
double make_reaction_mc_move_attempt_logarithmic(int reaction_id, double ln_bf, double E_pot_old, double E_pot_new)
Accept or reject a reaction MC move made by create_new_trial_state based on a logarithmic probability...
void add_reaction(std::shared_ptr< SingleReaction > const &new_reaction)
Adds a reaction to the reaction system.
double calculate_potential_energy() const
Compute the system potential energy.
void make_reaction_attempt(::ReactionMethods::SingleReaction const &reaction, ParticleChanges &bookkeeping)
Carry out a chemical reaction and save the old system state.
Utils::Vector3d get_random_position_in_box()
Writes a random position inside the central box into the provided array.
void set_slab_constraint(double slab_start_z, double slab_end_z)
int i_random(int maxint)
draws a random integer from the uniform distribution in the range [0,maxint-1]
virtual ~ReactionAlgorithm()=default
void set_cyl_constraint(double center_x, double center_y, double radius)
void setup_bookkeeping_of_empty_pids()
Cleans the list of empty pids and searches for empty pid in the system.
void displacement_mc_move(int type, int n_particles)
Carry out displacement MC moves for particles of a given type.
void update_volume()
Automatically sets the volume which is used by the reaction ensemble to the volume of a cuboid box.
void set_exclusion_radius_per_type(std::unordered_map< int, double > const &map)
void restore_old_system_state()
Restore last valid system state.
bool all_reactant_particles_exist(SingleReaction const &current_reaction) const
Checks whether all particles exist for the provided reaction.
ReactionAlgorithm(boost::mpi::communicator const &comm, int seed, double kT, double exclusion_range, std::unordered_map< int, double > const &exclusion_radius_per_type)
auto & make_new_system_state()
Open new handle for system state tracking.
void clear_old_system_state()
Clear last valid system state.
void delete_particle(int p_id)
Deletes the particle with the given p_id and stores the id if the deletion created a hole in the part...
std::vector< std::shared_ptr< SingleReaction > > reactions
std::optional< double > create_new_trial_state(int reaction_id)
Carry out a reaction MC move and calculate the new potential energy.
bool make_displacement_mc_move_attempt(int type, int n_particles)
Attempt displacement MC moves for particles of a given type.
Communicator communicator
STL namespace.
Random number generation using Philox.
Struct holding all information for one particle.
Definition Particle.hpp:435
std::vector< std::tuple< int, Utils::Vector3d, Utils::Vector3d > > moved