Loading...
Searching...
No Matches
Dynamics.cpp
Go to the documentation of this file.
1/*
2** This file is part of eOn.
3**
4** SPDX-License-Identifier: BSD-3-Clause
5**
6** Copyright (c) 2010--present, eOn Development Team
7** All rights reserved.
8**
9** Repo:
10** https://github.com/TheochemUI/eOn
11*/
12#include "eon/Dynamics.h"
13#include "eon/EonLogger.h"
14
15#include <cmath>
16
17using namespace eonc::helpers;
18
19const char Dynamics::ANDERSEN[] = "andersen";
20const char Dynamics::NOSE_HOOVER[] = "nose_hoover";
21const char Dynamics::LANGEVIN[] = "langevin";
22const char Dynamics::NONE[] = "none";
23
25 : matter{matter_in},
27 dt = m_config.time_step;
28 nAtoms = matter->numberOfAtoms();
29 nFreeCoords = matter->numberOfFreeAtoms() * 3;
30 temperature = m_config.temperature;
31 kB = m_config.kB;
32 vxi1 = vxi2 = xi1 = xi2 = 0.0;
33}
34
35Dynamics::~Dynamics() = default;
36
37void Dynamics::setTemperature(double temperature_in) {
38 temperature = temperature_in;
39}
40
41void Dynamics::oneStep(int stepNumber) {
42 if (m_config.thermostat_kind == ANDERSEN) {
45 } else if (m_config.thermostat_kind == NOSE_HOOVER) {
47 } else if (m_config.thermostat_kind == LANGEVIN) {
49 } else if (m_config.thermostat_kind == NONE) {
51 }
52
53 if (stepNumber != -1) {
54 if (stepNumber == 1) {
55 QUILL_LOG_DEBUG(log, "{} {:8s} {:10s} {:12s} {:12s} {:10s}\n",
56 "[Dynamics]", "Step", "KE", "PE", "TE", "KinT");
57 }
58 double kinE = matter->getKineticEnergy();
59 double potE = matter->getPotentialEnergy();
60 double kinT = 2.0 * kinE / nFreeCoords / kB;
61
62 if (stepNumber % m_config.write_movies_interval == 0) {
63 QUILL_LOG_DEBUG(log, "{} {:8} {:10.4} {:12.4} {:12.4} {:10.2}\n",
64 "[Dynamics]", stepNumber, kinE, potE, kinE + potE, kinT);
65 }
66 }
67}
68
70 AtomMatrix positions = matter->getPositions();
71 AtomMatrix velocities = matter->getVelocities();
72 AtomMatrix accInit = matter->getAccelerations();
73
74 positions += dt * velocities + 0.5 * dt * dt * accInit;
75 matter->setPositions(positions);
76
77 AtomMatrix accFinal = matter->getAccelerations();
78 velocities += 0.5 * dt * (accInit + accFinal);
79 matter->setVelocities(velocities);
80}
81
83 double sumT = 0.0, sumT2 = 0.0;
84
86
87 if (m_config.thermostat_kind != NONE) {
88 QUILL_LOG_DEBUG(log,
89 "{} Running NVT molecular dynamics: {:8.2f} K for {} "
90 "steps ({:.4e} s)\n",
91 "[Dynamics]", temperature, m_config.steps,
92 1e-15 * m_config.time_step * m_config.timeUnit *
93 m_config.steps);
94 } else {
95 QUILL_LOG_DEBUG(log, "{} Running NVE molecular dynamics: {} steps\n",
96 "[Dynamics]", m_config.steps);
97 }
98
99 if (m_config.write_movies) {
100 if (!eonc::io::io_ok(matter->matter2con("dynamics", false))) {
101 QUILL_LOG_WARNING(log, "Failed to write dynamics movie header frame");
102 }
103 }
104
105 QUILL_LOG_DEBUG(log, "{} {:8} {:10} {:12} {:12} {:10}\n", "[Dynamics]",
106 "step", "KE", "PE", "TE", "kinT");
107
108 for (long step = 0; step <= m_config.steps; step++) {
109 oneStep();
110
111 double kinE = matter->getKineticEnergy();
112 double potE = matter->getPotentialEnergy();
113 double kinT = 2.0 * kinE / nFreeCoords / kB;
114 sumT += kinT;
115 sumT2 += kinT * kinT;
116
117 if (step % m_config.write_movies_interval == 0) {
118 QUILL_LOG_DEBUG(log, "{} {} {} {} {} {}\n", "[Dynamics]", step, kinE,
119 potE, kinE + potE, kinT);
120 }
121
122 if (m_config.write_movies && (step % m_config.write_movies_interval == 0)) {
123 if (!eonc::io::io_ok(matter->matter2con("dynamics", true))) {
124 QUILL_LOG_WARNING(log, "Failed to append dynamics movie frame");
125 }
126 }
127 }
128
129 double avgT = sumT / static_cast<double>(m_config.steps);
130 double varT = sumT2 / static_cast<double>(m_config.steps) - avgT * avgT;
131 double stdT = std::sqrt(varT);
132 QUILL_LOG_DEBUG(log,
133 "{} Temperature : Average = {:.2f} ; StdDev = {:.2f} ; "
134 "Factor = {:.2f}\n",
135 "[Dynamics]", avgT, stdT,
136 varT / avgT / avgT * nFreeCoords / 2.0);
137}
138
140 double alpha = m_config.andersen_alpha;
141 double tCol = m_config.andersen_tcol;
142 double pCol = 1.0 - std::exp(-m_config.time_step / tCol);
143
144 AtomMatrix velocity = matter->getVelocities();
145 auto mass = matter->getMasses();
146
147 for (long i = 0; i < nAtoms; i++) {
148 if (randomDouble() < pCol && !matter->getFixed(i)) {
149 for (int j = 0; j < 3; j++) {
150 double vOld = velocity(i, j);
151 double vNew =
152 std::sqrt(kB * temperature / mass[i]) * gaussRandom(0.0, 1.0);
153 velocity(i, j) = std::sqrt(1.0 - alpha * alpha) * vOld + alpha * vNew;
154 }
155 }
156 }
157 matter->setVelocities(velocity);
158}
159
161 AtomMatrix velocity = matter->getVelocities();
162 auto mass = matter->getMasses();
163
164 for (long i = 0; i < nAtoms; i++) {
165 if (!matter->getFixed(i)) {
166 for (int j = 0; j < 3; j++) {
167 velocity(i, j) =
168 std::sqrt(kB * temperature / mass[i]) * gaussRandom(0.0, 1.0);
169 }
170 }
171 }
172 matter->setVelocities(velocity);
173}
174
176 AtomMatrix velocity = matter->getVelocities();
177 double kinE = matter->getKineticEnergy();
178 double kinT = 2.0 * kinE / nFreeCoords / kB;
179 matter->setVelocities(velocity * std::sqrt(temperature / kinT));
180}
181
185 double dt2 = 0.5 * dt;
186 double dt4 = 0.25 * dt;
187 double dt8 = 0.125 * dt;
188 double q1 = m_config.nose_mass;
189 double q2 = q1;
190 double Temp = kB * temperature;
191
192 AtomMatrix vel = matter->getVelocities();
193 AtomMatrix pos = matter->getPositions();
194 double kinE = matter->getKineticEnergy();
195
196 // Forward half-step for chain variables
197 double g2 = (q1 * vxi1 * vxi1 - Temp);
198 vxi2 += g2 * dt4;
199 vxi1 *= std::exp(-vxi2 * dt8);
200 double g1 = (2.0 * kinE - nFreeCoords * Temp) / q1;
201 vxi1 += g1 * dt4;
202 vxi1 *= std::exp(-vxi2 * dt8);
203 xi1 += vxi1 * dt2;
204 xi2 += vxi2 * dt2;
205 double s = std::exp(-vxi1 * dt2);
206 vel *= s;
207 kinE *= s * s;
208 vxi1 *= std::exp(-vxi2 * dt8);
209 g1 = (2.0 * kinE - nFreeCoords * Temp) / q1;
210 vxi1 += g1 * dt4;
211 vxi1 *= std::exp(-vxi2 * dt8);
212 g2 = (q1 * vxi1 * vxi1 - Temp) / q2;
213 vxi2 += g2 * dt4;
214
215 // Position + velocity Verlet step
216 pos += vel * dt2;
217 matter->setPositions(pos);
218 AtomMatrix acc = matter->getAccelerations();
219 vel += acc * dt;
220 pos += vel * dt2;
221 kinE = matter->getKineticEnergy();
222
223 // Backward half-step for chain variables
224 g2 = (q1 * vxi1 * vxi1 - Temp);
225 vxi2 += g2 * dt4;
226 vxi1 *= std::exp(-vxi2 * dt8);
227 g1 = (2.0 * kinE - nFreeCoords * Temp) / q1;
228 vxi1 += g1 * dt4;
229 vxi1 *= std::exp(-vxi2 * dt8);
230 xi1 += vxi1 * dt2;
231 xi2 += vxi2 * dt2;
232 s = std::exp(-vxi1 * dt2);
233 vel *= s;
234 kinE *= s * s;
235 vxi1 *= std::exp(-vxi2 * dt8);
236 g1 = (2.0 * kinE - nFreeCoords * Temp) / q1;
237 vxi1 += g1 * dt4;
238 vxi1 *= std::exp(-vxi2 * dt8);
239 g2 = (q1 * vxi1 * vxi1 - Temp) / q2;
240 vxi2 += g2 * dt4;
241
242 matter->setPositions(pos);
243 matter->setVelocities(vel);
244}
245
248 double gamma = m_config.langevin_friction;
249 AtomMatrix pos = matter->getPositions();
250 AtomMatrix vel = matter->getVelocities();
251 AtomMatrix acc = matter->getAccelerations();
252 AtomMatrix noise = acc; // same shape
253 auto mass = matter->getMasses();
254
255 // Generate friction + stochastic forces
256 AtomMatrix friction = -gamma * vel;
257 for (long i = 0; i < nAtoms; i++) {
258 if (!matter->getFixed(i)) {
259 for (int j = 0; j < 3; j++) {
260 noise(i, j) = std::sqrt(4.0 * gamma * kB * temperature / dt / mass[i]) *
261 gaussRandom(0.0, 1.0);
262 }
263 }
264 }
265 acc += friction + noise;
266
267 vel += acc * 0.5 * dt;
268 pos += vel * dt;
269 matter->setPositions(pos);
270
271 // Second half-step
272 acc = matter->getAccelerations();
273 friction = -gamma * vel;
274 for (long i = 0; i < nAtoms; i++) {
275 if (!matter->getFixed(i)) {
276 for (int j = 0; j < 3; j++) {
277 noise(i, j) = std::sqrt(4.0 * gamma * kB * temperature / dt / mass[i]) *
278 gaussRandom(0.0, 1.0);
279 }
280 }
281 }
282 acc += friction + noise;
283 vel += 0.5 * dt * acc;
284 matter->setVelocities(vel);
285}
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
static const char NOSE_HOOVER[]
Definition Dynamics.h:58
Dynamics(Matter *matter, const DynamicsConfig &config)
Definition Dynamics.cpp:24
static const char NONE[]
Definition Dynamics.h:60
static const char LANGEVIN[]
Definition Dynamics.h:59
static const char ANDERSEN[]
Definition Dynamics.h:57
long nFreeCoords
Definition Dynamics.h:81
void velocityVerlet()
Definition Dynamics.cpp:69
static const char NOSE_HOOVER[]
Definition Dynamics.h:58
void langevinVerlet()
Langevin dynamics (velocity-Verlet with friction and random forces).
Definition Dynamics.cpp:247
double temperature
Definition Dynamics.h:88
double vxi2
Definition Dynamics.h:89
Matter * matter
Definition Dynamics.h:83
void rescaleVelocity()
Definition Dynamics.cpp:175
void oneStep(int stepNumber=-1)
Definition Dynamics.cpp:41
eonc::log::Scoped log
Definition Dynamics.h:90
void setTemperature(double temperature)
Definition Dynamics.cpp:37
double vxi1
Definition Dynamics.h:89
static const char NONE[]
Definition Dynamics.h:60
void andersenCollision()
Definition Dynamics.cpp:139
static const char LANGEVIN[]
Definition Dynamics.h:59
DynamicsConfig m_config
Definition Dynamics.h:84
void noseHooverVerlet()
Nose-Hoover chain thermostat (Martyna-Klein-Tuckerman algorithm).
Definition Dynamics.cpp:184
void setThermalVelocity()
Definition Dynamics.cpp:160
static const char ANDERSEN[]
Definition Dynamics.h:57
double randomDouble()
double gaussRandom(double avg, double std)
constexpr bool io_ok(IoStatus s) noexcept
Definition ConFileIO.h:38
Configuration extracted from Parameters for Dynamics.
Definition Dynamics.h:24