ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
velocity_verlet_npt_Andersen.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_NPT
24
25#include "BoxGeometry.hpp"
26#include "Particle.hpp"
28#include "communication.hpp"
29#include "errorhandling.hpp"
30#include "system/System.hpp"
32
33#include <utils/Vector.hpp>
34
35#include <boost/mpi/collectives.hpp>
36
37#include <cmath>
38#include <functional>
39
40/**
41 * @brief Scale and communicate instantaneous NpT pressure and
42 * propagate the conjugate momentum for volume.
43 * @f$ p_{\epsilon}(t+dt) = p_{\epsilon}(t)
44 * + (P_{\text{inst}} - P_{\text{ext}})*0.5*dt @f$
45 */
46static void
48 InstantaneousPressure &npt_inst_pressure,
49 double time_step) {
50 /* finalize derivation of p_inst */
51 npt_inst_pressure.p_inst = {0., 0.};
52 for (auto i = 0u; i < 3u; ++i) {
54 npt_inst_pressure.p_inst[0] +=
55 npt_inst_pressure.p_vir[i] + npt_inst_pressure.p_vel[i];
56 npt_inst_pressure.p_inst[1] += npt_inst_pressure.p_vir[i];
57 }
58 }
59
60 Utils::Vector2d p_sum = {0., 0.};
61 boost::mpi::reduce(::comm_cart, npt_inst_pressure.p_inst, p_sum,
62 std::plus<Utils::Vector2d>(), 0);
63
64 /* propagate p_epsilon */
65 if (::this_node == 0) {
66 npt_inst_pressure.p_inst = p_sum / (nptiso.dimension * nptiso.volume);
67 nptiso.p_epsilon +=
68 (npt_inst_pressure.p_inst[0] - nptiso.p_ext) * 0.5 * time_step;
69 }
70}
71
72static void handle_negative_volume(auto &nptiso, auto const &box_geo,
73 double time_step) {
74 if (nptiso.volume < 0.) {
75 runtimeErrorMsg() << "your choice of piston=" << nptiso.piston
76 << ", time_step=" << time_step
77 << ", p_epsilon=" << nptiso.p_epsilon
78 << " just caused the volume to become negative."
79 << " The system is now in an indeterminate state."
80 << " Restart the simulation with a smaller time_step.";
81 nptiso.volume = box_geo.volume();
82 }
83}
84
85/**
86 * @brief propagate positions and the volume and add thermal fluctuation.
87 * A and V are the position and volume propagators for half-time step.
88 * O is the propagator corresponding to Ornstein-Uhlenbeck process
89 * representing the stochastic thermostat.
90 * The time evolution follows the sequence A-V-O-V-A in this function,
91 * with propagators applied right to left.
92 */
94 ParticleRangeNPT const &particles, IsotropicNptThermostat const &npt_iso,
95 double time_step, System::System &system) {
96
97 auto &box_geo = *system.box_geo;
98 auto &cell_structure = *system.cell_structure;
99 auto &npt_inst_pressure = *system.npt_inst_pressure;
100 auto &nptiso = *system.nptiso;
102 double L_halfdt = 0.0;
103 double L_dt = 0.0;
104
105 /* finalize derivation of p_inst and propagate p_epsilon;
106 * @f$ p_{\epsilon}(t+dt) = p_{\epsilon}(t)
107 * + (P_{\text{inst}} - P_{\text{ext}})*0.5*dt @f$
108 */
109 velocity_verlet_npt_finalize_p_inst(nptiso, npt_inst_pressure, time_step);
110
111 /* 1st adjust \ref NptIsoParameters::nptiso.volume with dt/2;
112 * @f$ V(t+0.5*dt) = V(t) + 0.5*p_{\epsilon}*dt @f$
113 * and prepare pos and vel-rescaling
114 */
115 if (::this_node == 0) {
116 nptiso.volume += nptiso.inv_piston * nptiso.p_epsilon * 0.5 * time_step;
117 handle_negative_volume(nptiso, box_geo, time_step);
118 // L(t)**2 / L(t+0.5*dt)**2, where the numerator follows time in position,
119 // and the denominator follows time in velocity
120 scal[2] = Utils::sqr(box_geo.length()[nptiso.non_const_dim]) /
121 std::pow(nptiso.volume, 2.0 / nptiso.dimension);
122 L_halfdt = std::pow(nptiso.volume, 1.0 / nptiso.dimension);
123
124 // L(t+0.5*dt) / L(t)
125 scal[1] = L_halfdt * box_geo.length_inv()[nptiso.non_const_dim];
126 // L(t) / L(t+0.5*dt)
127 scal[0] = 1. / scal[1];
128 }
129 boost::mpi::broadcast(::comm_cart, scal, 0);
130
131 /* 1st propagate positions with dt/2 and rescaling pos;
132 * @f$ pos[t+0.5*dt] = (L(t+0.5*dt) / L(t)) *
133 * (pos[t] + (L(t)**2 / L(t+0.5*dt)**2) * vel[t+0.5*dt] * 0.5 * dt) @f$
134 */
135 for (auto &p : particles) {
136 for (auto j = 0u; j < 3u; ++j) {
137 if (!p.is_fixed_along(j)) {
138 if (nptiso.geometry & NptIsoParameters::nptgeom_dir[j]) {
139 p.pos()[j] =
140 scal[1] * (p.pos()[j] + scal[2] * p.v()[j] * 0.5 * time_step);
141 p.pos_at_last_verlet_update()[j] *= scal[1];
142 p.v()[j] *= scal[0];
143 } else {
144 p.pos()[j] += p.v()[j] * 0.5 * time_step;
145 }
146 }
147 }
148 }
149
150 /* stochastic reservoirs for conjugate momentum for V;
151 * @f$ p_{\epsilon} = p_{epsilon}(t) \exp(- \gamma_V dt / W)
152 * + \sqrt{k_B T (1 - \exp(-2 \gamma_V dt / W)}N(0,1) @f$,
153 * 2nd adjust \ref NptIsoParameters::nptiso.volume with dt/2;
154 * @f$ V(t+dt) = V(t+0.5*dt) + 0.5*p_{\epsilon}*dt @f$,
155 * and prepare pos- and vel-rescaling
156 */
157 if (::this_node == 0) {
158 nptiso.p_epsilon = propagate_thermV_nptiso(npt_iso, nptiso.p_epsilon);
159 nptiso.volume += nptiso.inv_piston * nptiso.p_epsilon * 0.5 * time_step;
160 handle_negative_volume(nptiso, box_geo, time_step);
161 L_dt = std::pow(nptiso.volume, 1.0 / nptiso.dimension);
162
163 scal[2] = 1.0;
164 scal[1] = L_dt / L_halfdt;
165 scal[0] = 1. / scal[1];
166 }
167 boost::mpi::broadcast(::comm_cart, scal, 0);
168
169 /* stochastic reservoirs for velocities;
170 * @f$ p(t+0.5*dt) = p(t+0.5*dt) \exp(- \gamma_0 dt / m)
171 * + \sqrt{k_B T (1 - \exp(-2 \gamma_0 dt)}N(0,1) @f$
172 * and 2nd propagate positions with dt/2 while rescaling positions velocities
173 * @f$ pos[t+dt] = (L(t+dt) / L(t+0.5*dt)) *
174 * (pos[t+0.5*dt] + vel[t+0.5*dt]) @f$
175 */
176 for (auto &p : particles) {
177 auto const v_therm =
178 propagate_therm0_nptiso(npt_iso, p.v(), p.mass(), p.id());
179 for (auto j = 0u; j < 3u; ++j) {
180 if (!p.is_fixed_along(j)) {
181 if (nptiso.geometry & NptIsoParameters::nptgeom_dir[j]) {
182 p.v()[j] = v_therm[j];
183 p.pos()[j] =
184 scal[1] * (p.pos()[j] + scal[2] * p.v()[j] * 0.5 * time_step);
185 p.pos_at_last_verlet_update()[j] *= scal[1];
186 p.v()[j] *= scal[0];
187 } else {
188 p.pos()[j] += p.v()[j] * 0.5 * time_step;
189 }
190 }
191 }
192 }
193
194 cell_structure.set_resort_particles(Cells::RESORT_LOCAL);
195
196 /* Apply new volume to the box-length, communicate it, and account for
197 * necessary adjustments to the cell geometry */
199
200 if (::this_node == 0) {
201 new_box = box_geo.length();
202 for (auto i = 0u; i < 3u; ++i) {
203 if (nptiso.cubic_box ||
204 nptiso.geometry & NptIsoParameters::nptgeom_dir[i]) {
205 new_box[i] = L_dt;
206 }
207 }
208 }
209
210 boost::mpi::broadcast(::comm_cart, new_box, 0);
211
212 box_geo.set_length(new_box);
213 // fast box length update
214 system.on_boxl_change(true);
215}
216
218 IsotropicNptThermostat const &npt_iso,
219 double time_step,
221 auto &nptiso = *system.nptiso;
222 auto &npt_inst_pressure = *system.npt_inst_pressure;
223 velocity_verlet_npt_propagate_vel(nptiso, npt_inst_pressure, particles,
224 time_step);
225 velocity_verlet_npt_propagate_AVOVA_And(particles, npt_iso, time_step,
226 system);
227}
228
230 double time_step,
232 auto &nptiso = *system.nptiso;
233 auto &npt_inst_pressure = *system.npt_inst_pressure;
234 velocity_verlet_npt_propagate_vel_final(nptiso, npt_inst_pressure, particles,
235 time_step);
236 velocity_verlet_npt_finalize_p_inst(nptiso, npt_inst_pressure, time_step);
237}
238
239#endif // ESPRESSO_NPT
Vector implementation and trait types for boost qvm interoperability.
Main system class.
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
boost::mpi::communicator comm_cart
The communicator.
int this_node
The number of this node.
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
#define runtimeErrorMsg()
DEVICE_QUALIFIER constexpr T sqr(T x)
Calculates the SQuaRe of x.
Definition sqr.hpp:28
double propagate_thermV_nptiso(IsotropicNptThermostat const &npt_iso, double p_epsilon)
Added noise and friction for NpT-sims to NptIsoParameters::p_epsilon; .
Utils::Vector3d propagate_therm0_nptiso(IsotropicNptThermostat const &npt_iso, Utils::Vector3d const &vel, double mass, int p_identity)
Add velocity-dependent noise and friction for NpT-sims to the particle's velocity; .
Instantaneous pressure during force calculation for NPT integration.
Definition npt.hpp:92
Utils::Vector3d p_vel
ideal gas components of p_inst, derived from the velocities
Definition npt.hpp:99
Utils::Vector3d p_vir
virial (short-range) components of p_inst
Definition npt.hpp:97
Utils::Vector2d p_inst
instantaneous pressure for p_inst[0] and virial pressure for p_inst[1] the system currently has
Definition npt.hpp:95
Thermostat for isotropic NPT dynamics.
Parameters of the isotropic NpT-integration scheme.
Definition npt.hpp:42
int geometry
geometry information for the NpT integrator.
Definition npt.hpp:72
static constexpr std::array< int, 3 > nptgeom_dir
Definition npt.hpp:88
double p_ext
desired pressure to which the algorithm strives to
Definition npt.hpp:59
int dimension
The number of dimensions in which NpT boxlength motion is coupled to particles.
Definition npt.hpp:75
double p_epsilon
conjugate momentum of volume
Definition npt.hpp:61
double volume
isotropic volume.
Definition npt.hpp:53
void velocity_verlet_npt_propagate_vel_final(NptIsoParameters const &nptiso, InstantaneousPressure &npt_inst_pressure, ParticleRangeNPT const &particles, double time_step)
Propagate the particle's velocity.
void velocity_verlet_npt_propagate_vel(NptIsoParameters const &nptiso, InstantaneousPressure &npt_inst_pressure, ParticleRangeNPT const &particles, double time_step)
Propagate the particle's velocity.
static void velocity_verlet_npt_finalize_p_inst(NptIsoParameters &nptiso, InstantaneousPressure &npt_inst_pressure, double time_step)
Scale and communicate instantaneous NpT pressure and propagate the conjugate momentum for volume.
static void velocity_verlet_npt_propagate_AVOVA_And(ParticleRangeNPT const &particles, IsotropicNptThermostat const &npt_iso, double time_step, System::System &system)
propagate positions and the volume and add thermal fluctuation.
static void handle_negative_volume(auto &nptiso, auto const &box_geo, double time_step)
void velocity_verlet_npt_Andersen_step_1(ParticleRangeNPT const &particles, IsotropicNptThermostat const &npt_iso, double time_step, System::System &system)
Special propagator for velocity Verlet NpT with the Andersen method.
void velocity_verlet_npt_Andersen_step_2(ParticleRangeNPT const &particles, double time_step, System::System &system)
Final integration step of the velocity Verlet NpT integrator with the Andersen method.