Loading [MathJax]/extensions/TeX/AMSmath.js
ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
velocity_verlet_npt.cpp
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
20#include "config/config.hpp"
21
22#ifdef NPT
24
25#include "BoxGeometry.hpp"
26#include "Particle.hpp"
27#include "ParticleRange.hpp"
29#include "communication.hpp"
30#include "errorhandling.hpp"
31#include "npt.hpp"
32#include "system/System.hpp"
33#include "thermostat.hpp"
35
36#include <utils/Vector.hpp>
37#include <utils/math/sqr.hpp>
38
39#include <boost/mpi/collectives.hpp>
40
41#include <cmath>
42#include <functional>
43
44/**
45 * @brief Propagate the particle's velocity.
46 * @f$ v(t+dt) = v(t+0.5*dt) + 0.5*dt * a(t+dt) @f$
47 */
49 NptIsoParameters const &nptiso, InstantaneousPressure &npt_inst_pressure,
50 ParticleRangeNPT const &particles, double time_step) {
51
52 npt_inst_pressure.p_vel = {};
53 for (auto &p : particles) {
54 for (unsigned int j = 0; j < 3; j++) {
55 if (!p.is_fixed_along(j)) {
57 npt_inst_pressure.p_vel[j] += Utils::sqr(p.v()[j]) * p.mass();
58 }
59 p.v()[j] += p.force()[j] * time_step / 2.0 / p.mass();
60 }
61 }
62 }
63}
64
65/**
66 * @brief Scale and communicate instantaneous NpT pressure and
67 * propagate the conjugate momentum for volume.
68 * @f$ p_{\epsilon}(t+dt) = p_{\epsilon}(t)
69 * + (P_{\text{inst}} - P_{\text{ext}})*0.5*dt @f$
70 */
71static void
73 InstantaneousPressure &npt_inst_pressure,
74 double time_step) {
75 /* finalize derivation of p_inst */
76 npt_inst_pressure.p_inst = {0., 0.};
77 for (unsigned int i = 0; i < 3; i++) {
79 npt_inst_pressure.p_inst[0] +=
80 npt_inst_pressure.p_vir[i] + npt_inst_pressure.p_vel[i];
81 npt_inst_pressure.p_inst[1] += npt_inst_pressure.p_vir[i];
82 }
83 }
84
85 Utils::Vector2d p_sum = {0., 0.};
86 boost::mpi::reduce(comm_cart, npt_inst_pressure.p_inst, p_sum,
87 std::plus<Utils::Vector2d>(), 0);
88
89 /* propagate p_epsilon */
90 if (this_node == 0) {
91 npt_inst_pressure.p_inst = p_sum / (nptiso.dimension * nptiso.volume);
92 nptiso.p_epsilon +=
93 (npt_inst_pressure.p_inst[0] - nptiso.p_ext) * 0.5 * time_step;
94 }
95}
96
97static void
99 IsotropicNptThermostat const &npt_iso,
100 double time_step, System::System &system) {
101
102 auto &box_geo = *system.box_geo;
103 auto &cell_structure = *system.cell_structure;
104 auto &npt_inst_pressure = *system.npt_inst_pressure;
105 auto &nptiso = *system.nptiso;
106 Utils::Vector3d scal{};
107 double L_halfdt = 0.0;
108 double L_dt = 0.0;
109
110 /* finalize derivation of p_inst and propagate p_epsilon;
111 * @f$ p_{\epsilon}(t+dt) = p_{\epsilon}(t)
112 * + (P_{\text{inst}} - P_{\text{ext}})*0.5*dt @f$
113 */
114 velocity_verlet_npt_finalize_p_inst(nptiso, npt_inst_pressure, time_step);
115
116 /* 1st adjust \ref NptIsoParameters::nptiso.volume with dt/2;
117 * @f$ V(t+0.5*dt) = V(t) + 0.5*p_{\epsilon}*dt @f$
118 * and prepare pos and vel-rescaling
119 */
120 if (this_node == 0) {
121 nptiso.volume += nptiso.inv_piston * nptiso.p_epsilon * 0.5 * time_step;
122 // L(t)**2 / L(t+0.5*dt)**2, where the numerator follows time in position,
123 // and the denominator follows time in velocity
124 scal[2] = Utils::sqr(box_geo.length()[nptiso.non_const_dim]) /
125 pow(nptiso.volume, 2.0 / nptiso.dimension);
126 if (nptiso.volume < 0.0) {
128 << "your choice of piston= " << nptiso.piston << ", dt= " << time_step
129 << ", p_epsilon= " << nptiso.p_epsilon
130 << " just caused the volume to become negative, decrease dt";
131 nptiso.volume = box_geo.volume();
132 scal[2] = 1;
133 }
134
135 L_halfdt = pow(nptiso.volume, 1.0 / nptiso.dimension);
136
137 // L(t+0.5*dt) / L(t)
138 scal[1] = L_halfdt * box_geo.length_inv()[nptiso.non_const_dim];
139 // L(t) / L(t+0.5*dt)
140 scal[0] = 1. / scal[1];
141 }
142 boost::mpi::broadcast(comm_cart, scal, 0);
143
144 /* 1st propagate positions with dt/2 and rescaling pos;
145 * @f$ pos[t+0.5*dt] = (L(t+0.5*dt) / L(t)) *
146 * (pos[t] + (L(t)**2 / L(t+0.5*dt)**2) * vel[t+0.5*dt] * 0.5 * dt) @f$
147 */
148 for (auto &p : particles) {
149 for (unsigned int j = 0; j < 3; j++) {
150 if (!p.is_fixed_along(j)) {
151 if (nptiso.geometry & NptIsoParameters::nptgeom_dir[j]) {
152 p.pos()[j] =
153 scal[1] * (p.pos()[j] + scal[2] * p.v()[j] * 0.5 * time_step);
154 p.pos_at_last_verlet_update()[j] *= scal[1];
155 p.v()[j] *= scal[0];
156 } else {
157 p.pos()[j] += p.v()[j] * 0.5 * time_step;
158 }
159 }
160 }
161 }
162
163 /* stochastic reservoirs for conjugate momentum for V;
164 * @f$ p_{\epsilon} = p_{epsilon}(t) \exp(- \gamma_V dt / W)
165 * + \sqrt{k_B T (1 - \exp(-2 \gamma_V dt / W)}N(0,1) @f$,
166 * 2nd adjust \ref NptIsoParameters::nptiso.volume with dt/2;
167 * @f$ V(t+dt) = V(t+0.5*dt) + 0.5*p_{\epsilon}*dt @f$,
168 * and prepare pos- and vel-rescaling
169 */
170 if (this_node == 0) {
171 nptiso.p_epsilon =
172 propagate_thermV_nptiso(npt_iso, nptiso.p_epsilon, nptiso.piston);
173 nptiso.volume += nptiso.inv_piston * nptiso.p_epsilon * 0.5 * time_step;
174 L_dt = pow(nptiso.volume, 1.0 / nptiso.dimension);
175
176 scal[2] = 1.0;
177 scal[1] = L_dt / L_halfdt;
178 scal[0] = 1. / scal[1];
179 }
180 boost::mpi::broadcast(comm_cart, scal, 0);
181
182 /* stochastic reserviors for velocities;
183 * @f$ p(t+0.5*dt) = p(t+0.5*dt) \exp(- \gamma_0 dt / m)
184 * + \sqrt{k_B T (1 - \exp(-2 \gamma_0 dt)}N(0,1) @f$
185 * and 2nd propagate positions with dt/2 while rescaling positions velocities
186 * @f$ pos[t+dt] = (L(t+dt) / L(t+0.5*dt)) *
187 * (pos[t+0.5*dt] + vel[t+0.5*dt]) @f$
188 */
189 for (auto &p : particles) {
190 auto const v_therm =
191 propagate_therm0_nptiso(npt_iso, p.v(), p.mass(), p.id());
192 for (unsigned int j = 0; j < 3; j++) {
193 if (!p.is_fixed_along(j)) {
194 if (nptiso.geometry & NptIsoParameters::nptgeom_dir[j]) {
195 p.v()[j] = v_therm[j];
196 p.pos()[j] =
197 scal[1] * (p.pos()[j] + scal[2] * p.v()[j] * 0.5 * time_step);
198 p.pos_at_last_verlet_update()[j] *= scal[1];
199 p.v()[j] *= scal[0];
200 } else {
201 p.pos()[j] += p.v()[j] * 0.5 * time_step;
202 }
203 }
204 }
205 }
206
207 cell_structure.set_resort_particles(Cells::RESORT_LOCAL);
208
209 /* Apply new volume to the box-length, communicate it, and account for
210 * necessary adjustments to the cell geometry */
211 Utils::Vector3d new_box;
212
213 if (this_node == 0) {
214 new_box = box_geo.length();
215
216 for (unsigned int i = 0; i < 3; i++) {
217 if (nptiso.cubic_box ||
218 nptiso.geometry & NptIsoParameters::nptgeom_dir[i]) {
219 new_box[i] = L_dt;
220 }
221 }
222 }
223
224 boost::mpi::broadcast(comm_cart, new_box, 0);
225
226 box_geo.set_length(new_box);
227 // fast box length update
228 system.on_boxl_change(true);
229}
230
231/**
232 * @brief Propagate the particle's velocity.
233 * @f$ v(t+0.5*dt) = v(t) + 0.5*dt * a(t) @f$
234 */
236 double time_step) {
237 auto &nptiso = *System::get_system().nptiso;
238 auto &npt_inst_pressure = *System::get_system().npt_inst_pressure;
239 npt_inst_pressure.p_vel = {};
240
241 for (auto &p : particles) {
242 for (unsigned int j = 0; j < 3; j++) {
243 if (!p.is_fixed_along(j)) {
244 p.v()[j] += p.force()[j] * time_step / 2.0 / p.mass();
245 if (nptiso.geometry & NptIsoParameters::nptgeom_dir[j]) {
246 npt_inst_pressure.p_vel[j] += Utils::sqr(p.v()[j]) * p.mass();
247 }
248 }
249 }
250 }
251}
252
254 IsotropicNptThermostat const &npt_iso,
255 double time_step, System::System &system) {
256 velocity_verlet_npt_propagate_vel(particles, time_step);
257 velocity_verlet_npt_propagate_pos(particles, npt_iso, time_step, system);
258}
259
261 double time_step, System::System &system) {
262 auto &nptiso = *system.nptiso;
263 auto &npt_inst_pressure = *system.npt_inst_pressure;
264 velocity_verlet_npt_propagate_vel_final(nptiso, npt_inst_pressure, particles,
265 time_step);
266 velocity_verlet_npt_finalize_p_inst(nptiso, npt_inst_pressure, time_step);
267}
268
269#endif // NPT
Vector implementation and trait types for boost qvm interoperability.
Main system class.
void on_boxl_change(bool skip_method_adaption=false)
Called when the box length has changed.
std::shared_ptr< InstantaneousPressure > npt_inst_pressure
std::shared_ptr< NptIsoParameters > nptiso
std::shared_ptr< CellStructure > cell_structure
std::shared_ptr< BoxGeometry > box_geo
boost::mpi::communicator comm_cart
The communicator.
int this_node
The number of this node.
This file contains the defaults for ESPResSo.
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
#define runtimeErrorMsg()
System & get_system()
DEVICE_QUALIFIER constexpr T sqr(T x)
Calculates the SQuaRe of x.
Definition sqr.hpp:28
Exports for the NpT code.
double propagate_thermV_nptiso(IsotropicNptThermostat const &npt_iso, double p_epsilon, double piston)
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:85
Utils::Vector3d p_vel
ideal gas components of p_inst, derived from the velocities
Definition npt.hpp:92
Utils::Vector3d p_vir
virial (short-range) components of p_inst
Definition npt.hpp:90
Utils::Vector2d p_inst
instantaneous pressure for p_inst[0] and virial pressure for p_inst[1] the system currently has
Definition npt.hpp:88
Thermostat for isotropic NPT dynamics.
Parameters of the isotropic NpT-integration scheme.
Definition npt.hpp:41
int geometry
geometry information for the NpT integrator.
Definition npt.hpp:65
static constexpr std::array< int, 3 > nptgeom_dir
Definition npt.hpp:81
double p_ext
desired pressure to which the algorithm strives to
Definition npt.hpp:56
int dimension
The number of dimensions in which NpT boxlength motion is coupled to particles.
Definition npt.hpp:68
double p_epsilon
conjugate momentum of volume
Definition npt.hpp:58
double volume
isotropic volume.
Definition npt.hpp:52
static void velocity_verlet_npt_propagate_vel(ParticleRangeNPT const &particles, double time_step)
Propagate the particle's velocity.
static 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_step_1(ParticleRangeNPT const &particles, IsotropicNptThermostat const &npt_iso, double time_step, System::System &system)
Special propagator for NpT isotropic.
void velocity_verlet_npt_step_2(ParticleRangeNPT const &particles, double time_step, System::System &system)
Final integration step of the Velocity Verlet+NpT integrator.
static void velocity_verlet_npt_propagate_pos(ParticleRangeNPT const &particles, IsotropicNptThermostat const &npt_iso, double time_step, System::System &system)
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.