ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
sd_interface.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2026 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
20#include <config/config.hpp>
21
22#ifdef ESPRESSO_STOKESIAN_DYNAMICS
23
24#include "sd_interface.hpp"
25
26#include "stokesian_dynamics/sd_cpu.hpp"
27
28#include "BoxGeometry.hpp"
29#include "Particle.hpp"
30#include "communication.hpp"
31#include "errorhandling.hpp"
32#include "system/System.hpp"
33#include "thermostat.hpp"
34
35#include <utils/Vector.hpp>
38
39#include <boost/serialization/is_bitwise_serializable.hpp>
40
41#include <algorithm>
42#include <cmath>
43#include <cstddef>
44#include <iterator>
45#include <stdexcept>
46#include <string>
47#include <unordered_set>
48#include <utility>
49#include <vector>
50
51/* type for particle data transfer between nodes */
53 SD_particle_data() = default;
54 explicit SD_particle_data(Particle const &p)
55 : type(p.type()), pos(p.pos()), ext_force(p.force_and_torque()) {}
56
57 int type = 0;
58
59 /* particle position */
60 Utils::Vector3d pos = {0., 0., 0.};
61
62 /* external force */
64
65 template <class Archive> void serialize(Archive &ar, long int /* version */) {
66 ar & type;
67 ar & pos;
68 ar & ext_force;
69 }
70};
71
72BOOST_IS_BITWISE_SERIALIZABLE(SD_particle_data)
73
74/** Update translational and rotational velocities of all particles. */
75template <typename ParticleIterable>
76static void sd_update_locally(ParticleIterable const &parts,
77 std::vector<double> const &v_sd) {
78 std::size_t i = 0;
79
80 // Even though on the head node, the v_sd vector is larger than
81 // the (local) parts vector, this should still work. Because the local
82 // particles correspond to the first 6*n entries in the head node's v_sd
83 // (which holds the velocities of ALL particles).
84
85 for (auto &p : parts) {
86 // Copy velocities
87 p.v()[0] = v_sd[6 * i + 0];
88 p.v()[1] = v_sd[6 * i + 1];
89 p.v()[2] = v_sd[6 * i + 2];
90
91 p.omega()[0] = v_sd[6 * i + 3];
92 p.omega()[1] = v_sd[6 * i + 4];
93 p.omega()[2] = v_sd[6 * i + 5];
94
95 ++i;
96 }
97}
98
100 std::unordered_map<int, double> radii,
101 int flags)
102 : viscosity{viscosity}, radii{radii}, flags{flags} {
103 if (viscosity < 0.) {
104 throw std::domain_error("Viscosity has an invalid value: " +
105 std::to_string(viscosity));
106 }
107 /* Check that radii are positive */
108 for (auto const &[p_type, radius] : radii) {
109 if (radius < 0.) {
110 throw std::domain_error(
111 "Particle radius for type " + std::to_string(p_type) +
112 " has an invalid value: " + std::to_string(radius));
113 }
114 }
115}
116
118 ParticleRangeStokesian const &particles) const {
119 std::unordered_set<int> local_types;
120 for (auto const &p : particles) {
121 local_types.emplace(p.type());
122 }
123 std::vector<int> all_types(local_types.begin(), local_types.end());
125 if (::comm_cart.rank() == 0) {
126 for (auto const ptype :
127 std::unordered_set<int>(all_types.begin(), all_types.end())) {
128 if (not radii.contains(ptype)) {
129 runtimeErrorMsg() << "Stokesian Dynamics: no radius defined for "
130 "particle type "
131 << ptype;
132 }
133 }
134 }
135}
136
138 ParticleRangeStokesian const &particles,
139 StokesianThermostat const &stokesian, double const time_step,
140 double const kT) const {
141
142 std::vector<SD_particle_data> parts_buffer{};
143 parts_buffer.reserve(particles.size());
144
145 for (auto const &p : particles) {
146 parts_buffer.emplace_back(p);
147 }
148 Utils::Mpi::gather_buffer(parts_buffer, ::comm_cart, 0);
149
150 /* Buffer that holds local particle data, and all particles on the head
151 * node used for sending particle data to head node. */
152 if (::comm_cart.rank() == 0) {
153 std::size_t n_part = parts_buffer.size();
154
155 x_host.resize(6 * n_part);
156 f_host.resize(6 * n_part);
157 a_host.resize(n_part);
158
159 std::size_t i = 0;
160 for (auto const &p : parts_buffer) {
161 x_host[6 * i + 0] = p.pos[0];
162 x_host[6 * i + 1] = p.pos[1];
163 x_host[6 * i + 2] = p.pos[2];
164 // Actual orientation is not needed, just need default.
165 x_host[6 * i + 3] = 1.;
166 x_host[6 * i + 4] = 0.;
167 x_host[6 * i + 5] = 0.;
168
169 f_host[6 * i + 0] = p.ext_force.f[0];
170 f_host[6 * i + 1] = p.ext_force.f[1];
171 f_host[6 * i + 2] = p.ext_force.f[2];
172
173 f_host[6 * i + 3] = p.ext_force.torque[0];
174 f_host[6 * i + 4] = p.ext_force.torque[1];
175 f_host[6 * i + 5] = p.ext_force.torque[2];
176
177 a_host[i] = radii.at(p.type);
178
179 ++i;
180 }
181
182 v_sd = sd_cpu(x_host, f_host, a_host, n_part, viscosity,
183 std::sqrt(kT / time_step),
184 static_cast<std::size_t>(stokesian.rng_counter()),
185 static_cast<std::size_t>(stokesian.rng_seed()), flags);
186 } else { // if (this_node == 0)
187 v_sd.resize(particles.size() * 6);
188 } // if (this_node == 0) {...} else
189
191 v_sd.data(), static_cast<int>(particles.size() * 6), ::comm_cart, 0);
192 sd_update_locally(particles, v_sd);
193}
194
195#endif // ESPRESSO_STOKESIAN_DYNAMICS
Vector implementation and trait types for boost qvm interoperability.
base_type::size_type size() const
boost::mpi::communicator comm_cart
The communicator.
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
#define runtimeErrorMsg()
void gather_buffer(std::vector< T, Allocator > &buffer, boost::mpi::communicator const &comm, int root=0)
Gather buffer with different size on each node.
void scatter_buffer(T *buffer, int n_elem, boost::mpi::communicator comm, int root=0)
Scatter buffer with different size on each node.
static void sd_update_locally(ParticleIterable const &parts, std::vector< double > const &v_sd)
Update translational and rotational velocities of all particles.
See for the Stokesian dynamics method used here.
uint64_t rng_counter() const
Get current value of the RNG.
uint32_t rng_seed() const
Force information on a particle.
Definition Particle.hpp:331
Struct holding all information for one particle.
Definition Particle.hpp:436
SD_particle_data()=default
SD_particle_data(Particle const &p)
Utils::Vector3d pos
void serialize(Archive &ar, long int)
ParticleForce ext_force
StokesianDynamics()=default
void propagate_vel_pos(ParticleRangeStokesian const &particles, StokesianThermostat const &stokesian, double time_step, double kT) const
Take the forces and torques on all particles and compute velocities.
void sanity_checks(ParticleRangeStokesian const &particles) const
std::unordered_map< int, double > radii
Thermostat for Stokesian dynamics.