22#include "reaction_methods/ReactionAlgorithm.hpp"
29#include "system/System.hpp"
34#include <boost/mpi/collectives/all_reduce.hpp>
35#include <boost/mpi/collectives/broadcast.hpp>
36#include <boost/serialization/serialization.hpp>
88 auto const &box_geo = *
system.box_geo;
93 if (
auto p = get_local_particle(
p_id)) {
95#ifdef ESPRESSO_ELECTROSTATICS
107 if (
auto p = get_local_particle(
p_id)) {
113 p->image_box() = image_box;
118 auto &cell_structure = *
system.cell_structure;
121 system.on_particle_change();
131 volume = box_geo.volume();
168#ifdef ESPRESSO_ELECTROSTATICS
176 if (
auto p = get_local_particle(
p_id)) {
178#ifdef ESPRESSO_ELECTROSTATICS
190 auto const type =
reaction.product_types[i];
192 auto const p_id = create_particle(type);
193 check_exclusion_range(
p_id, type);
198 auto const type =
reaction.reactant_types[i];
202 check_exclusion_range(
p_id, type);
203 hide_particle(
p_id, type);
213 auto const type =
reaction.reactant_types[i];
214 for (
int j = 0;
j <
reaction.reactant_coefficients[i];
j++) {
217 check_exclusion_range(
p_id, type);
218 hide_particle(
p_id, type);
222 auto const type =
reaction.product_types[i];
223 for (
int j = 0;
j <
reaction.product_coefficients[i];
j++) {
224 auto const p_id = create_particle(type);
225 check_exclusion_range(
p_id, type);
238std::unordered_map<int, int>
242 for (
int type :
reaction.reactant_types) {
246 for (
int type :
reaction.product_types) {
266 auto E_pot_new = std::numeric_limits<double>::max();
275 auto constexpr exp_min = -708.4;
279 reaction.accumulator_potential_energy_difference_exponential(
283 if (-get_random_logarithmic_number() >=
ln_bf) {
313void ReactionAlgorithm::hide_particle(
int p_id,
int p_type)
const {
315 if (
auto p = get_local_particle(
p_id)) {
317#ifdef ESPRESSO_ELECTROSTATICS
326void ReactionAlgorithm::check_exclusion_range(
int p_id,
int p_type) {
345 system.on_observable_calc();
357 auto const &box_geo = *
system.box_geo;
358 auto &cell_structure = *
system.cell_structure;
363 if (
auto const p2_ptr = cell_structure.get_local_particle(
p2_id)) {
376 auto const d_min = box_geo.get_mi_vector(
p2.pos(),
p1.pos()).norm();
384 if (m_comm.rank() != 0) {
387 }
else if (m_comm.rank() == 0) {
388 m_comm.recv(boost::mpi::any_source, 1,
402 throw std::domain_error(
"Invalid particle id: " + std::to_string(
p_id));
422 throw std::runtime_error(
423 "Particle id is greater than the max seen particle id");
431 throw std::domain_error(
"center_x is outside the box");
433 throw std::domain_error(
"center_y is outside the box");
435 throw std::domain_error(
"radius is invalid");
438 m_cyl_radius = radius;
439 m_reaction_constraint = ReactionConstraint::CYL_Z;
446 throw std::domain_error(
"slab_start_z is outside the box");
448 throw std::domain_error(
"slab_end_z is outside the box");
450 throw std::domain_error(
"slab_end_z must be >= slab_start_z");
453 m_reaction_constraint = ReactionConstraint::SLAB_Z;
463 if (m_reaction_constraint == ReactionConstraint::CYL_Z) {
467 m_cyl_radius * std::sqrt(m_uniform_real_distribution(m_generator));
469 2. * std::numbers::pi * m_uniform_real_distribution(m_generator);
472 out_pos[2] = box_geo.length()[2] * m_uniform_real_distribution(m_generator);
473 }
else if (m_reaction_constraint == ReactionConstraint::SLAB_Z) {
474 out_pos[0] = box_geo.length()[0] * m_uniform_real_distribution(m_generator);
475 out_pos[1] = box_geo.length()[1] * m_uniform_real_distribution(m_generator);
476 out_pos[2] = m_slab_start_z + (m_slab_end_z - m_slab_start_z) *
477 m_uniform_real_distribution(m_generator);
479 assert(m_reaction_constraint == ReactionConstraint::NONE);
480 out_pos[0] = box_geo.length()[0] * m_uniform_real_distribution(m_generator);
481 out_pos[1] = box_geo.length()[1] * m_uniform_real_distribution(m_generator);
482 out_pos[2] = box_geo.length()[2] * m_uniform_real_distribution(m_generator);
490int ReactionAlgorithm::create_particle(
int p_type) {
503 auto vel = get_random_velocity_vector();
506 if (
auto p = get_local_particle(
p_id)) {
507 p->v() = std::sqrt(
kT / p->mass()) * vel;
509#ifdef ESPRESSO_ELECTROSTATICS
522 for (
int i = 0; i < n_particles; i++) {
532 auto vel = get_random_velocity_vector();
533 if (
auto p = get_real_particle(
p_id)) {
535 p->v() = std::sqrt(
kT / p->mass()) * vel;
536 if (m_comm.rank() != 0) {
539 }
else if (m_comm.rank() == 0) {
540 m_comm.recv(boost::mpi::any_source, 42,
old_state);
542 boost::mpi::broadcast(m_comm,
old_state, 0);
546 check_exclusion_range(
p_id, type);
557 throw std::domain_error(
"Parameter 'type_mc' must be >= 0");
559 if (n_particles < 0) {
560 throw std::domain_error(
561 "Parameter 'particle_number_to_be_changed' must be >= 0");
564 if (n_particles == 0) {
581 ? std::numeric_limits<double>::max()
583 auto constexpr exp_min = -708.4;
601 if (m_uniform_real_distribution(m_generator) <
bf) {
623 for (
int pid =
pid1 + 1; pid <
pid2; ++pid) {
632 auto const obs =
system.calculate_energy();
635 boost::mpi::broadcast(m_comm, pot, 0);
639Particle *ReactionAlgorithm::get_real_particle(
int p_id)
const {
642 auto ptr =
system.cell_structure->get_local_particle(
p_id);
643 if (ptr !=
nullptr and ptr->is_ghost()) {
646 assert(boost::mpi::all_reduce(m_comm,
static_cast<int>(ptr !=
nullptr),
647 std::plus<>()) == 1);
651Particle *ReactionAlgorithm::get_local_particle(
int p_id)
const {
654 auto ptr =
system.cell_structure->get_local_particle(
p_id);
655 assert(boost::mpi::all_reduce(
656 m_comm,
static_cast<int>(ptr !=
nullptr and not ptr->is_ghost()),
657 std::plus<>()) == 1);
Vector implementation and trait types for boost qvm interoperability.
std::optional< std::vector< int > > get_short_range_neighbors(System::System const &system, int const pid, double const distance)
Get ids of particles that are within a certain distance of another particle.
This file contains everything related to the global cell structure / cell system.
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.
int m_tried_configurational_MC_moves
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)
bool particle_inside_exclusion_range_touched
int i_random(int maxint)
draws a random integer from the uniform distribution in the range [0,maxint-1]
std::unordered_map< int, double > charges_of_types
void set_cyl_constraint(double center_x, double center_y, double radius)
std::unordered_map< int, double > exclusion_radius_per_type
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 restore_old_system_state()
Restore last valid system state.
bool all_reactant_particles_exist(SingleReaction const ¤t_reaction) const
Checks whether all particles exist for the provided reaction.
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...
int m_accepted_configurational_MC_moves
std::vector< std::shared_ptr< SingleReaction > > reactions
double exclusion_range
Hard sphere radius.
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.
bool neighbor_search_order_n
auto const & get_old_system_state() const
std::vector< int > m_empty_p_ids_smaller_than_max_seen_particle
void on_particle_change()
Called every time a particle property changes.
void on_particle_local_change()
Called every time a particle local property changes.
std::shared_ptr< BoxGeometry > box_geo
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
bool contains(Range &&rng, T const &value)
Check whether a range contains a value.
void serialize(Archive &ar, std::tuple< T... > &pack, unsigned int const)
Serialize std::tuple.
std::vector< int > get_particle_ids_parallel()
void make_new_particle(int p_id, Utils::Vector3d const &pos)
Create a new particle and attach it to a cell.
int number_of_particles_with_type(int type)
void set_particle_pos(int p_id, Utils::Vector3d const &pos)
Move particle to a new position.
void init_type_map(int type)
int get_random_p_id(int type, int random_index_in_type_map)
Find a particle of given type and return its id.
void remove_particle(int p_id)
Remove particle with a given identity.
int get_maximal_particle_id()
Get maximal particle id.
void on_particle_type_change(int p_id, int old_type, int new_type)
Particles creation and deletion.
Struct holding all information for one particle.
std::vector< std::tuple< int, Utils::Vector3d, Utils::Vector3d > > moved