eOn client
Long-timescale dynamics: aKMC, NEB, parallel replica
☾
Toggle main menu visibility
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
17
using namespace
eonc::helpers
;
18
19
const
char
Dynamics::ANDERSEN
[] =
"andersen"
;
20
const
char
Dynamics::NOSE_HOOVER
[] =
"nose_hoover"
;
21
const
char
Dynamics::LANGEVIN
[] =
"langevin"
;
22
const
char
Dynamics::NONE
[] =
"none"
;
23
24
Dynamics::Dynamics
(
Matter
*matter_in,
const
DynamicsConfig
&
config
)
25
:
matter
{matter_in},
26
m_config
{
config
} {
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
35
Dynamics::~Dynamics
() =
default
;
36
37
void
Dynamics::setTemperature
(
double
temperature_in) {
38
temperature
= temperature_in;
39
}
40
41
void
Dynamics::oneStep
(
int
stepNumber) {
42
if
(
m_config
.thermostat_kind ==
ANDERSEN
) {
43
andersenCollision
();
44
velocityVerlet
();
45
}
else
if
(
m_config
.thermostat_kind ==
NOSE_HOOVER
) {
46
noseHooverVerlet
();
47
}
else
if
(
m_config
.thermostat_kind ==
LANGEVIN
) {
48
langevinVerlet
();
49
}
else
if
(
m_config
.thermostat_kind ==
NONE
) {
50
velocityVerlet
();
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
69
void
Dynamics::velocityVerlet
() {
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
82
void
Dynamics::run
() {
83
double
sumT = 0.0, sumT2 = 0.0;
84
85
setThermalVelocity
();
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
139
void
Dynamics::andersenCollision
() {
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
160
void
Dynamics::setThermalVelocity
() {
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
175
void
Dynamics::rescaleVelocity
() {
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
184
void
Dynamics::noseHooverVerlet
() {
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
247
void
Dynamics::langevinVerlet
() {
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
}
Dynamics.h
AtomMatrix
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition
Eigen.h:37
EonLogger.h
Dynamics::NOSE_HOOVER
static const char NOSE_HOOVER[]
Definition
Dynamics.h:58
Dynamics::Dynamics
Dynamics(Matter *matter, const DynamicsConfig &config)
Definition
Dynamics.cpp:24
Dynamics::NONE
static const char NONE[]
Definition
Dynamics.h:60
Dynamics::LANGEVIN
static const char LANGEVIN[]
Definition
Dynamics.h:59
Dynamics::ANDERSEN
static const char ANDERSEN[]
Definition
Dynamics.h:57
eonc::Dynamics::kB
double kB
Definition
Dynamics.h:87
eonc::Dynamics::nFreeCoords
long nFreeCoords
Definition
Dynamics.h:81
eonc::Dynamics::velocityVerlet
void velocityVerlet()
Definition
Dynamics.cpp:69
eonc::Dynamics::NOSE_HOOVER
static const char NOSE_HOOVER[]
Definition
Dynamics.h:58
eonc::Dynamics::langevinVerlet
void langevinVerlet()
Langevin dynamics (velocity-Verlet with friction and random forces).
Definition
Dynamics.cpp:247
eonc::Dynamics::temperature
double temperature
Definition
Dynamics.h:88
eonc::Dynamics::run
void run()
Definition
Dynamics.cpp:82
eonc::Dynamics::dt
double dt
Definition
Dynamics.h:86
eonc::Dynamics::vxi2
double vxi2
Definition
Dynamics.h:89
eonc::Dynamics::matter
Matter * matter
Definition
Dynamics.h:83
eonc::Dynamics::xi1
double xi1
Definition
Dynamics.h:89
eonc::Dynamics::rescaleVelocity
void rescaleVelocity()
Definition
Dynamics.cpp:175
eonc::Dynamics::oneStep
void oneStep(int stepNumber=-1)
Definition
Dynamics.cpp:41
eonc::Dynamics::log
eonc::log::Scoped log
Definition
Dynamics.h:90
eonc::Dynamics::setTemperature
void setTemperature(double temperature)
Definition
Dynamics.cpp:37
eonc::Dynamics::xi2
double xi2
Definition
Dynamics.h:89
eonc::Dynamics::vxi1
double vxi1
Definition
Dynamics.h:89
eonc::Dynamics::nAtoms
long nAtoms
Definition
Dynamics.h:81
eonc::Dynamics::NONE
static const char NONE[]
Definition
Dynamics.h:60
eonc::Dynamics::~Dynamics
~Dynamics()
eonc::Dynamics::andersenCollision
void andersenCollision()
Definition
Dynamics.cpp:139
eonc::Dynamics::LANGEVIN
static const char LANGEVIN[]
Definition
Dynamics.h:59
eonc::Dynamics::m_config
DynamicsConfig m_config
Definition
Dynamics.h:84
eonc::Dynamics::noseHooverVerlet
void noseHooverVerlet()
Nose-Hoover chain thermostat (Martyna-Klein-Tuckerman algorithm).
Definition
Dynamics.cpp:184
eonc::Dynamics::setThermalVelocity
void setThermalVelocity()
Definition
Dynamics.cpp:160
eonc::Dynamics::ANDERSEN
static const char ANDERSEN[]
Definition
Dynamics.h:57
eonc::Matter
Definition
Matter.h:92
eonc::config
Definition
ParametersINI.cpp:40
eonc::helpers
Definition
EnvHelpers.cc:5
eonc::helpers::randomDouble
double randomDouble()
Definition
RandomNumbers.cpp:62
eonc::helpers::gaussRandom
double gaussRandom(double avg, double std)
Definition
RandomNumbers.cpp:80
eonc::io::io_ok
constexpr bool io_ok(IoStatus s) noexcept
Definition
ConFileIO.h:38
eonc::DynamicsConfig
Configuration extracted from Parameters for Dynamics.
Definition
Dynamics.h:24
client
Dynamics.cpp
Generated by
1.17.0
Generated by
Doxygen 1.17.0
Analytics by
Antics
provided by
TurtleTech ehf