ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
thermostats/brownian_inline.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010
4 * Max-Planck-Institute for Polymer Research, Theory Group
5 *
6 * This file is part of ESPResSo.
7 *
8 * ESPResSo is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * ESPResSo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#pragma once
23
24#include "config/config.hpp"
25
26#include "Particle.hpp"
27#include "random.hpp"
28#include "rotation.hpp"
29#include "thermostat.hpp"
30
31#include <utils/Vector.hpp>
32
33#include <cmath>
34
35/** Determine position: viscous drag driven by conservative forces.
36 * From eq. (14.39) in @cite schlick10a.
37 * @param[in] brownian_gamma Brownian translational gamma
38 * @param[in] p Particle
39 * @param[in] dt Time step
40 */
42 Particle const &p, double dt) {
43 // The friction tensor Z from the Eq. (14.31) of schlick10a:
45
46#ifdef ESPRESSO_THERMOSTAT_PER_PARTICLE
47 if (p.gamma() >= Thermostat::GammaType{}) {
48 gamma = p.gamma();
49 } else
50#endif
51 {
52 gamma = brownian_gamma;
53 }
54
55#ifdef ESPRESSO_PARTICLE_ANISOTROPY
56 // Particle frictional isotropy check.
57 auto const aniso_flag = (gamma[0] != gamma[1]) || (gamma[1] != gamma[2]);
59 if (aniso_flag) {
61 auto const delta_pos_body = hadamard_division(force_body * dt, gamma);
63 }
64#endif
65
66 Utils::Vector3d position = {};
67 for (unsigned int j = 0; j < 3; j++) {
68 // Second (deterministic) term of the Eq. (14.39) of schlick10a.
69 // Only a conservative part of the force is used here
70#ifdef ESPRESSO_PARTICLE_ANISOTROPY
71 if (aniso_flag) {
72 if (!p.is_fixed_along(j)) {
73 position[j] = delta_pos_lab[j];
74 }
75 } else {
76 if (!p.is_fixed_along(j)) {
77 position[j] = p.force()[j] * dt / gamma[j];
78 }
79 }
80#else
81 if (!p.is_fixed_along(j)) {
82 position[j] = p.force()[j] * dt / gamma;
83 }
84#endif // ESPRESSO_PARTICLE_ANISOTROPY
85 }
86 return position;
87}
88
89/** Set the terminal velocity driven by the conservative forces drag.
90 * From eq. (14.34) in @cite schlick10a.
91 * @param[in] brownian_gamma Brownian translational gamma
92 * @param[in] p Particle
93 */
95 Particle const &p) {
96 // The friction tensor Z from the eq. (14.31) of schlick10a:
98
99#ifdef ESPRESSO_THERMOSTAT_PER_PARTICLE
100 if (p.gamma() >= Thermostat::GammaType{}) {
101 gamma = p.gamma();
102 } else
103#endif
104 {
105 gamma = brownian_gamma;
106 }
107
108#ifdef ESPRESSO_PARTICLE_ANISOTROPY
109 // Particle frictional isotropy check.
110 auto const aniso_flag = (gamma[0] != gamma[1]) || (gamma[1] != gamma[2]);
112 if (aniso_flag) {
113 auto const force_body = convert_vector_space_to_body(p, p.force());
114 auto const vel_body = hadamard_division(force_body, gamma);
116 }
117#endif
118
120 for (unsigned int j = 0; j < 3; j++) {
121 // First (deterministic) term of the eq. (14.34) of schlick10a taking
122 // into account eq. (14.35). Only conservative part of the force is used
123 // here.
124#ifdef ESPRESSO_PARTICLE_ANISOTROPY
125 if (aniso_flag) {
126 if (!p.is_fixed_along(j)) {
127 velocity[j] = vel_lab[j];
128 }
129 } else {
130 if (!p.is_fixed_along(j)) {
131 velocity[j] = p.force()[j] / gamma[j];
132 }
133 }
134#else // ESPRESSO_PARTICLE_ANISOTROPY
135 if (!p.is_fixed_along(j)) {
136 velocity[j] = p.force()[j] / gamma;
137 }
138#endif // ESPRESSO_PARTICLE_ANISOTROPY
139 }
140 return velocity;
141}
142
143/** Determine the positions: random walk part.
144 * From eq. (14.37) in @cite schlick10a.
145 * @param[in] brownian Parameters
146 * @param[in] p Particle
147 * @param[in] dt Time step
148 * @param[in] kT Thermal energy
149 */
151 Particle const &p, double dt,
152 [[maybe_unused]] double kT) {
153 Thermostat::GammaType sigma_pos = brownian.sigma_pos;
154#ifdef ESPRESSO_THERMOSTAT_PER_PARTICLE
155 // override default if particle-specific gamma
156 if (p.gamma() >= Thermostat::GammaType{}) {
157 if (kT > 0.0) {
158 sigma_pos = BrownianThermostat::sigma(kT, p.gamma());
159 } else {
160 sigma_pos = Thermostat::GammaType{};
161 }
162 }
163#endif // ESPRESSO_THERMOSTAT_PER_PARTICLE
164
165 // Eq. (14.37) is factored by the Gaussian noise (12.22) with its squared
166 // magnitude defined in the second eq. (14.38), schlick10a.
168 auto const noise = Random::noise_gaussian<RNGSalt::BROWNIAN_WALK>(
169 brownian.rng_counter(), brownian.rng_seed(), p.id());
170 for (unsigned int j = 0; j < 3; j++) {
171 if (!p.is_fixed_along(j)) {
172#ifndef ESPRESSO_PARTICLE_ANISOTROPY
173 if (sigma_pos > 0.0) {
174 delta_pos_body[j] = sigma_pos * sqrt(dt) * noise[j];
175 } else {
176 delta_pos_body[j] = 0.0;
177 }
178#else
179 if (sigma_pos[j] > 0.0) {
180 delta_pos_body[j] = sigma_pos[j] * sqrt(dt) * noise[j];
181 } else {
182 delta_pos_body[j] = 0.0;
183 }
184#endif // ESPRESSO_PARTICLE_ANISOTROPY
185 }
186 }
187
188#ifdef ESPRESSO_PARTICLE_ANISOTROPY
189 // Particle frictional isotropy check.
190 auto const aniso_flag =
191 (sigma_pos[0] != sigma_pos[1]) || (sigma_pos[1] != sigma_pos[2]);
193 if (aniso_flag) {
195 }
196#endif
197
198 Utils::Vector3d position = {};
199 for (unsigned int j = 0; j < 3; j++) {
200 if (!p.is_fixed_along(j)) {
201#ifdef ESPRESSO_PARTICLE_ANISOTROPY
202 position[j] += aniso_flag ? delta_pos_lab[j] : delta_pos_body[j];
203#else
204 position[j] += delta_pos_body[j];
205#endif
206 }
207 }
208 return position;
209}
210
211/** Determine the velocities: random walk part.
212 * From eq. (10.2.16) in @cite pottier10a.
213 * @param[in] brownian Parameters
214 * @param[in] p Particle
215 */
217 Particle const &p) {
218 auto const noise = Random::noise_gaussian<RNGSalt::BROWNIAN_INC>(
219 brownian.rng_counter(), brownian.rng_seed(), p.id());
221 for (unsigned int j = 0; j < 3; j++) {
222 if (!p.is_fixed_along(j)) {
223 // Random (heat) velocity. See eq. (10.2.16) taking into account eq.
224 // (10.2.18) and (10.2.29), pottier10a. Note, that the pottier10a units
225 // system (see Eq. (10.1.1) there) has been adapted towards the ESPResSo
226 // and the referenced above schlick10a one, which is defined by the eq.
227 // (14.31) of schlick10a. A difference is the mass factor to the friction
228 // tensor. The noise is Gaussian according to the convention at p. 237
229 // (last paragraph), pottier10a.
230 velocity[j] += brownian.sigma_vel * noise[j] / sqrt(p.mass());
231 }
232 }
233 return velocity;
234}
235
236#ifdef ESPRESSO_ROTATION
237
238/** Determine quaternions: viscous drag driven by conservative torques.
239 * An analogy of eq. (14.39) in @cite schlick10a.
240 * @param[in] brownian_gamma_rotation Brownian rotational gamma
241 * @param[in] p Particle
242 * @param[in] dt Time step
243 */
246 double dt) {
248
249#ifdef ESPRESSO_THERMOSTAT_PER_PARTICLE
250 if (p.gamma_rot() >= Thermostat::GammaType{}) {
251 gamma = p.gamma_rot();
252 } else
253#endif
254 {
256 }
257
259 for (unsigned int j = 0; j < 3; j++) {
260 if (p.can_rotate_around(j)) {
261 // only a conservative part of the torque is used here
262#ifndef ESPRESSO_PARTICLE_ANISOTROPY
263 dphi[j] = p.torque()[j] * dt / gamma;
264#else
265 dphi[j] = p.torque()[j] * dt / gamma[j];
266#endif // ESPRESSO_PARTICLE_ANISOTROPY
267 }
268 }
269 dphi = mask(p.rotation(), dphi);
270 double dphi_m = dphi.norm();
271 if (dphi_m != 0.) {
272 auto const dphi_u = dphi / dphi_m;
274 }
275 return p.quat();
276}
277
278/** Set the terminal angular velocity driven by the conservative torques drag.
279 * An analogy of the 1st term of eq. (14.34) in @cite schlick10a.
280 * @param[in] brownian_gamma_rotation Brownian rotational gamma
281 * @param[in] p Particle
282 */
283inline Utils::Vector3d
285 Particle const &p) {
287
288#ifdef ESPRESSO_THERMOSTAT_PER_PARTICLE
289 if (p.gamma_rot() >= Thermostat::GammaType{}) {
290 gamma = p.gamma_rot();
291 } else
292#endif
293 {
295 }
296
297 Utils::Vector3d omega = {};
298 for (unsigned int j = 0; j < 3; j++) {
299 if (p.can_rotate_around(j)) {
300#ifdef ESPRESSO_PARTICLE_ANISOTROPY
301 omega[j] = p.torque()[j] / gamma[j];
302#else
303 omega[j] = p.torque()[j] / gamma;
304#endif // ESPRESSO_PARTICLE_ANISOTROPY
305 }
306 }
307 return mask(p.rotation(), omega);
308}
309
310/** Determine the quaternions: random walk part.
311 * An analogy of eq. (14.37) in @cite schlick10a.
312 * @param[in] brownian Parameters
313 * @param[in] p Particle
314 * @param[in] dt Time step
315 * @param[in] kT Thermal energy
316 */
319 double dt, double kT) {
320
321 Thermostat::GammaType sigma_pos = brownian.sigma_pos_rotation;
322#ifdef ESPRESSO_THERMOSTAT_PER_PARTICLE
323 // override default if particle-specific gamma
324 if (p.gamma_rot() >= Thermostat::GammaType{}) {
325 if (kT > 0.) {
326 sigma_pos = BrownianThermostat::sigma(kT, p.gamma_rot());
327 } else {
328 sigma_pos = {}; // just an indication of the infinity
329 }
330 }
331#endif // ESPRESSO_THERMOSTAT_PER_PARTICLE
332
334 auto const noise = Random::noise_gaussian<RNGSalt::BROWNIAN_ROT_INC>(
335 brownian.rng_counter(), brownian.rng_seed(), p.id());
336 for (unsigned int j = 0; j < 3; j++) {
337 if (p.can_rotate_around(j)) {
338#ifndef ESPRESSO_PARTICLE_ANISOTROPY
339 if (sigma_pos > 0.0) {
340 dphi[j] = noise[j] * sigma_pos * sqrt(dt);
341 }
342#else
343 if (sigma_pos[j] > 0.0) {
344 dphi[j] = noise[j] * sigma_pos[j] * sqrt(dt);
345 }
346#endif // ESPRESSO_PARTICLE_ANISOTROPY
347 }
348 }
349 dphi = mask(p.rotation(), dphi);
350 // making the algorithm independent of the order of the rotations
351 double dphi_m = dphi.norm();
352 if (dphi_m != 0) {
353 auto const dphi_u = dphi / dphi_m;
355 }
356 return p.quat();
357}
358
359/** Determine the angular velocities: random walk part.
360 * An analogy of eq. (10.2.16) in @cite pottier10a.
361 * @param[in] brownian Parameters
362 * @param[in] p Particle
363 */
364inline Utils::Vector3d
366 auto const sigma_vel = brownian.sigma_vel_rotation;
367
369 auto const noise = Random::noise_gaussian<RNGSalt::BROWNIAN_ROT_WALK>(
370 brownian.rng_counter(), brownian.rng_seed(), p.id());
371 for (unsigned int j = 0; j < 3; j++) {
372 if (p.can_rotate_around(j)) {
373 domega[j] = sigma_vel * noise[j] / sqrt(p.rinertia()[j]);
374 }
375 }
376 return mask(p.rotation(), domega);
377}
378#endif // ESPRESSO_ROTATION
Vector implementation and trait types for boost qvm interoperability.
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
Random number generation using Philox.
static Utils::Vector3d velocity(Particle const &p_ref, Particle const &p_vs)
Velocity of the virtual site.
Definition relative.cpp:65
This file contains all subroutines required to process rotational motion.
Utils::Vector3d convert_vector_body_to_space(const Particle &p, const Utils::Vector3d &vec)
Definition rotation.hpp:58
Utils::Vector3d convert_vector_space_to_body(const Particle &p, const Utils::Vector3d &v)
Definition rotation.hpp:62
Utils::Quaternion< double > local_rotate_particle_body(Particle const &p, const Utils::Vector3d &axis_body_frame, const double phi)
Rotate the particle p around the body-frame defined NORMALIZED axis aBodyFrame by amount phi.
Definition rotation.hpp:120
uint64_t rng_counter() const
Get current value of the RNG.
uint32_t rng_seed() const
Thermostat for Brownian dynamics.
GammaType sigma_pos
Translational noise standard deviation.
double sigma_vel_rotation
Angular velocity noise standard deviation.
double sigma_vel
Translational velocity noise standard deviation.
GammaType sigma_pos_rotation
Rotational noise standard deviation.
static GammaType sigma(double kT, GammaType const &gamma)
Calculate the noise prefactor.
Struct holding all information for one particle.
Definition Particle.hpp:450
auto const & rinertia() const
Definition Particle.hpp:587
auto const & mass() const
Definition Particle.hpp:507
auto const & quat() const
Definition Particle.hpp:532
auto const & rotation() const
Definition Particle.hpp:513
auto const & gamma() const
Definition Particle.hpp:622
bool can_rotate_around(unsigned int const axis) const
Definition Particle.hpp:516
auto const & gamma_rot() const
Definition Particle.hpp:625
auto const & torque() const
Definition Particle.hpp:534
bool is_fixed_along(unsigned int const axis) const
Definition Particle.hpp:633
auto const & force() const
Definition Particle.hpp:490
auto const & id() const
Definition Particle.hpp:469
Quaternion representation.
Utils::Vector3d bd_random_walk_vel_rot(BrownianThermostat const &brownian, Particle const &p)
Determine the angular velocities: random walk part.
Utils::Quaternion< double > bd_drag_rot(Thermostat::GammaType const &brownian_gamma_rotation, Particle &p, double dt)
Determine quaternions: viscous drag driven by conservative torques.
Utils::Vector3d bd_random_walk(BrownianThermostat const &brownian, Particle const &p, double dt, double kT)
Determine the positions: random walk part.
Utils::Vector3d bd_drag_vel(Thermostat::GammaType const &brownian_gamma, Particle const &p)
Set the terminal velocity driven by the conservative forces drag.
Utils::Vector3d bd_random_walk_vel(BrownianThermostat const &brownian, Particle const &p)
Determine the velocities: random walk part.
Utils::Quaternion< double > bd_random_walk_rot(BrownianThermostat const &brownian, Particle const &p, double dt, double kT)
Determine the quaternions: random walk part.
Utils::Vector3d bd_drag(Thermostat::GammaType const &brownian_gamma, Particle const &p, double dt)
Determine position: viscous drag driven by conservative forces.
Utils::Vector3d bd_drag_vel_rot(Thermostat::GammaType const &brownian_gamma_rotation, Particle const &p)
Set the terminal angular velocity driven by the conservative torques drag.