Loading...
Searching...
No Matches
eonc::Dynamics Class Reference

#include <Dynamics.h>

Public Member Functions

 Dynamics (Matter *matter, const DynamicsConfig &config)
 Dynamics (Matter *matter, const Parameters &parameters)
 ~Dynamics ()
void setTemperature (double temperature)
void oneStep (int stepNumber=-1)
void velocityVerlet ()
void run ()
void andersenCollision ()
void setThermalVelocity ()
void rescaleVelocity ()
void noseHooverVerlet ()
 Nose-Hoover chain thermostat (Martyna-Klein-Tuckerman algorithm).
void langevinVerlet ()
 Langevin dynamics (velocity-Verlet with friction and random forces).

Static Public Attributes

static const char ANDERSEN [] = "andersen"
static const char NOSE_HOOVER [] = "nose_hoover"
static const char LANGEVIN [] = "langevin"
static const char NONE [] = "none"
static const char PILE [] = "pile"
static const char PIGLET [] = "piglet"

Private Member Functions

void nhcChainHalfStep (AtomMatrix &vel, double &kinE)
 One Martyna-Klein-Tuckerman chain half-step.
void runPathIntegral ()
 Ring-polymer trajectory. Beads do not enter velocityVerlet.

Private Attributes

long nAtoms {0}
long nFreeCoords {0}
Matter * matter
DynamicsConfig m_config
double dt {0.0}
double kB {0.0}
double temperature {0.0}
double vxi1 {0.0}
double vxi2 {0.0}
double xi1 {0.0}
double xi2 {0.0}
eonc::log::Scoped log

Detailed Description

Definition at line 70 of file Dynamics.h.

Constructor & Destructor Documentation

◆ Dynamics() [1/2]

eonc::Dynamics::Dynamics ( Matter * matter,
const DynamicsConfig & config )

Definition at line 29 of file Dynamics.cpp.

30 : matter{matter_in},
31 m_config{config} {
32 if (!matter) {
33 throw std::invalid_argument("Dynamics: null Matter");
34 }
35 dt = m_config.time_step;
36 nAtoms = matter->numberOfAtoms();
37 // Unfixed axes only. A partly fixed atom is not three degrees of freedom.
38 nFreeCoords = 0;
39 for (long i = 0; i < nAtoms; ++i) {
40 for (int axis = 0; axis < 3; ++axis) {
41 if (!matter->getFixed(i, axis)) {
43 }
44 }
45 }
46 temperature = m_config.temperature;
47 kB = m_config.kB;
48 vxi1 = vxi2 = xi1 = xi2 = 0.0;
49}
double temperature
Definition Dynamics.h:112
Matter * matter
Definition Dynamics.h:107
DynamicsConfig m_config
Definition Dynamics.h:108

◆ Dynamics() [2/2]

eonc::Dynamics::Dynamics ( Matter * matter,
const Parameters & parameters )
inline

Definition at line 83 of file Dynamics.h.

Dynamics(Matter *matter, const DynamicsConfig &config)
Definition Dynamics.cpp:29
static DynamicsConfig fromParams(const Parameters &p)
Definition Dynamics.h:47

◆ ~Dynamics()

eonc::Dynamics::~Dynamics ( )
default

Member Function Documentation

◆ andersenCollision()

void eonc::Dynamics::andersenCollision ( )

Definition at line 224 of file Dynamics.cpp.

224 {
225 double alpha = m_config.andersen_alpha;
226 double tCol = m_config.andersen_tcol;
227 double pCol = 1.0 - std::exp(-m_config.time_step / tCol);
228
229 AtomMatrix velocity = matter->getVelocities();
230 auto mass = matter->getMasses();
231
232 for (long i = 0; i < nAtoms; i++) {
233 if (eonc::rng::randomDouble() < pCol && !matter->getFixed(i)) {
234 for (int j = 0; j < 3; j++) {
235 double vOld = velocity(i, j);
236 const double vNew = (mass[i] > 0.0 && kB > 0.0 && temperature > 0.0)
237 ? std::sqrt(kB * temperature / mass[i]) *
238 eonc::rng::gaussRandom(0.0, 1.0)
239 : 0.0;
240 velocity(i, j) = std::sqrt(1.0 - alpha * alpha) * vOld + alpha * vNew;
241 }
242 }
243 }
244 matter->setVelocities(velocity);
245}
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
double randomDouble()
double gaussRandom(double avg, double std)

◆ langevinVerlet()

void eonc::Dynamics::langevinVerlet ( )

Langevin dynamics (velocity-Verlet with friction and random forces).

Matter::getFixed(atom) is true only when every axis is fixed, so noise and the position kick are applied per free axis.

Definition at line 332 of file Dynamics.cpp.

332 {
333 const double gamma = m_config.langevin_friction;
334 AtomMatrix pos = matter->getPositions();
335 AtomMatrix vel = matter->getVelocities();
336 AtomMatrix acc = matter->getAccelerations();
337 AtomMatrix noise = AtomMatrix::Zero(nAtoms, 3);
338 const auto mass = matter->getMasses();
339
340 // Zero a frozen axis by assignment. Multiplying by the free mask leaves
341 // a NaN in place, and setPositions stores every component.
342 auto holdFixed = [&](AtomMatrix &m) {
343 for (long i = 0; i < nAtoms; i++) {
344 for (int j = 0; j < 3; j++) {
345 if (matter->getFixed(i, j)) {
346 m(i, j) = 0.0;
347 }
348 }
349 }
350 };
351 auto addNoise = [&]() {
352 noise.setZero();
353 for (long i = 0; i < nAtoms; i++) {
354 for (int j = 0; j < 3; j++) {
355 if (matter->getFixed(i, j)) {
356 continue;
357 }
358 noise(i, j) = std::sqrt(4.0 * gamma * kB * temperature / dt / mass[i]) *
359 eonc::rng::gaussRandom(0.0, 1.0);
360 }
361 }
362 };
363
364 addNoise();
365 AtomMatrix friction = -gamma * vel;
366 holdFixed(friction);
367 holdFixed(acc);
368 acc += friction + noise;
369
370 vel += acc * 0.5 * dt;
371 holdFixed(vel);
372 pos += vel * dt;
373 matter->setPositions(pos);
374
375 acc = matter->getAccelerations();
376 addNoise();
377 friction = -gamma * vel;
378 holdFixed(friction);
379 holdFixed(acc);
380 acc += friction + noise;
381 vel += 0.5 * dt * acc;
382 holdFixed(vel);
383 matter->setVelocities(vel);
384}

◆ nhcChainHalfStep()

void eonc::Dynamics::nhcChainHalfStep ( AtomMatrix & vel,
double & kinE )
private

One Martyna-Klein-Tuckerman chain half-step.

G2 is always (Q1 vxi1^2 - kT) / Q2.

Definition at line 275 of file Dynamics.cpp.

275 {
276 const double dt2 = 0.5 * dt;
277 const double dt4 = 0.25 * dt;
278 const double dt8 = 0.125 * dt;
279 const double q1 = m_config.nose_mass;
280 const double q2 = q1;
281 const double Temp = kB * temperature;
282 if (!(q1 > 0.0)) {
283 throw std::invalid_argument("thermostat.nose_mass must be positive");
284 }
285
286 // Martyna, Klein, Tuckerman JCP 97, 2635 (1992): G2 = (Q1 v_ξ1² − kT) / Q2.
287 auto g2 = [&]() { return (q1 * vxi1 * vxi1 - Temp) / q2; };
288 auto g1 = [&]() { return (2.0 * kinE - nFreeCoords * Temp) / q1; };
289
290 vxi2 += g2() * dt4;
291 vxi1 *= std::exp(-vxi2 * dt8);
292 vxi1 += g1() * dt4;
293 vxi1 *= std::exp(-vxi2 * dt8);
294 xi1 += vxi1 * dt2;
295 xi2 += vxi2 * dt2;
296 const double s = std::exp(-vxi1 * dt2);
297 vel *= s;
298 kinE *= s * s;
299 vxi1 *= std::exp(-vxi2 * dt8);
300 vxi1 += g1() * dt4;
301 vxi1 *= std::exp(-vxi2 * dt8);
302 vxi2 += g2() * dt4;
303}

◆ noseHooverVerlet()

void eonc::Dynamics::noseHooverVerlet ( )

Nose-Hoover chain thermostat (Martyna-Klein-Tuckerman algorithm).

Two chain variables (xi1, xi2) with velocities (vxi1, vxi2).

Definition at line 307 of file Dynamics.cpp.

307 {
308 const double dt2 = 0.5 * dt;
309 AtomMatrix vel = matter->getVelocities();
310 AtomMatrix pos = matter->getPositions();
311 double kinE = matter->getKineticEnergy();
312
313 nhcChainHalfStep(vel, kinE);
314
315 pos += vel * dt2;
316 matter->setPositions(pos);
317 AtomMatrix acc = matter->getAccelerations();
318 vel += acc * dt;
319 pos += vel * dt2;
320 matter->setPositions(pos);
321 matter->setVelocities(vel);
322 kinE = matter->getKineticEnergy();
323
324 nhcChainHalfStep(vel, kinE);
325
326 matter->setVelocities(vel);
327}
void nhcChainHalfStep(AtomMatrix &vel, double &kinE)
One Martyna-Klein-Tuckerman chain half-step.
Definition Dynamics.cpp:275

◆ oneStep()

void eonc::Dynamics::oneStep ( int stepNumber = -1)

Definition at line 57 of file Dynamics.cpp.

57 {
58 if (m_config.thermostat_kind == ANDERSEN) {
61 } else if (m_config.thermostat_kind == NOSE_HOOVER) {
63 } else if (m_config.thermostat_kind == LANGEVIN) {
65 } else if (m_config.thermostat_kind == NONE) {
67 } else if (m_config.thermostat_kind == PILE ||
68 m_config.thermostat_kind == PIGLET) {
69 throw std::invalid_argument(
70 "path-integral dynamics is a ring-polymer trajectory, not a "
71 "velocity Verlet step");
72 }
73
74 if (stepNumber != -1) {
75 if (stepNumber == 1) {
76 QUILL_LOG_DEBUG(log, "{} {:8s} {:10s} {:12s} {:12s} {:10s}\n",
77 "[Dynamics]", "Step", "KE", "PE", "TE", "KinT");
78 }
79 double kinE = matter->getKineticEnergy();
80 double potE = matter->getPotentialEnergy();
81 const double kinT =
82 (nFreeCoords > 0 && kB > 0.0) ? 2.0 * kinE / nFreeCoords / kB : 0.0;
83
84 if (stepNumber % m_config.write_movies_interval == 0) {
85 QUILL_LOG_DEBUG(log, "{} {:8} {:10.4} {:12.4} {:12.4} {:10.2}\n",
86 "[Dynamics]", stepNumber, kinE, potE, kinE + potE, kinT);
87 }
88 }
89}
static const char NONE[]
Definition Dynamics.h:76
static const char LANGEVIN[]
Definition Dynamics.h:75
void langevinVerlet()
Langevin dynamics (velocity-Verlet with friction and random forces).
Definition Dynamics.cpp:332
void noseHooverVerlet()
Nose-Hoover chain thermostat (Martyna-Klein-Tuckerman algorithm).
Definition Dynamics.cpp:307
void andersenCollision()
Definition Dynamics.cpp:224
static const char ANDERSEN[]
Definition Dynamics.h:73
static const char NOSE_HOOVER[]
Definition Dynamics.h:74
eonc::log::Scoped log
Definition Dynamics.h:114
static const char PILE[]
Definition Dynamics.h:77
static const char PIGLET[]
Definition Dynamics.h:78
void velocityVerlet()
Definition Dynamics.cpp:91

◆ rescaleVelocity()

void eonc::Dynamics::rescaleVelocity ( )

Definition at line 264 of file Dynamics.cpp.

264 {
265 AtomMatrix velocity = matter->getVelocities();
266 double kinE = matter->getKineticEnergy();
267 const double kinT =
268 (nFreeCoords > 0 && kB > 0.0) ? 2.0 * kinE / nFreeCoords / kB : 0.0;
269 if (!(kinT > 0.0) || !(temperature > 0.0)) {
270 return;
271 }
272 matter->setVelocities(velocity * std::sqrt(temperature / kinT));
273}

◆ run()

void eonc::Dynamics::run ( )

Definition at line 161 of file Dynamics.cpp.

161 {
162 if (m_config.thermostat_kind == PILE || m_config.thermostat_kind == PIGLET) {
164 return;
165 }
166 double sumT = 0.0, sumT2 = 0.0;
167
169
170 if (m_config.thermostat_kind != NONE) {
171 QUILL_LOG_DEBUG(log,
172 "{} Running NVT molecular dynamics: {:8.2f} K for {} "
173 "steps ({:.4e} s)\n",
174 "[Dynamics]", temperature, m_config.steps,
175 1e-15 * m_config.time_step * m_config.timeUnit *
176 m_config.steps);
177 } else {
178 QUILL_LOG_DEBUG(log, "{} Running NVE molecular dynamics: {} steps\n",
179 "[Dynamics]", m_config.steps);
180 }
181
182 if (m_config.write_movies) {
183 if (!eonc::io::io_ok(matter->matter2con("dynamics", false))) {
184 QUILL_LOG_WARNING(log, "Failed to write dynamics movie header frame");
185 }
186 }
187
188 QUILL_LOG_DEBUG(log, "{} {:8} {:10} {:12} {:12} {:10}\n", "[Dynamics]",
189 "step", "KE", "PE", "TE", "kinT");
190
191 for (long step = 0; step < m_config.steps; step++) {
192 oneStep();
193
194 double kinE = matter->getKineticEnergy();
195 double potE = matter->getPotentialEnergy();
196 const double kinT =
197 (nFreeCoords > 0 && kB > 0.0) ? 2.0 * kinE / nFreeCoords / kB : 0.0;
198 sumT += kinT;
199 sumT2 += kinT * kinT;
200
201 if (step % m_config.write_movies_interval == 0) {
202 QUILL_LOG_DEBUG(log, "{} {} {} {} {} {}\n", "[Dynamics]", step, kinE,
203 potE, kinE + potE, kinT);
204 }
205
206 if (m_config.write_movies && (step % m_config.write_movies_interval == 0)) {
207 if (!eonc::io::io_ok(matter->matter2con("dynamics", true))) {
208 QUILL_LOG_WARNING(log, "Failed to append dynamics movie frame");
209 }
210 }
211 }
212
213 const double nstat = static_cast<double>(std::max(m_config.steps, 1L));
214 double avgT = sumT / nstat;
215 double varT = sumT2 / nstat - avgT * avgT;
216 double stdT = std::sqrt(varT);
217 QUILL_LOG_DEBUG(log,
218 "{} Temperature : Average = {:.2f} ; StdDev = {:.2f} ; "
219 "Factor = {:.2f}\n",
220 "[Dynamics]", avgT, stdT,
221 varT / avgT / avgT * nFreeCoords / 2.0);
222}
void setThermalVelocity()
Definition Dynamics.cpp:247
void oneStep(int stepNumber=-1)
Definition Dynamics.cpp:57
void runPathIntegral()
Ring-polymer trajectory. Beads do not enter velocityVerlet.
Definition Dynamics.cpp:104
constexpr bool io_ok(IoStatus s) noexcept
Definition ConFileIO.h:38

◆ runPathIntegral()

void eonc::Dynamics::runPathIntegral ( )
private

Ring-polymer trajectory. Beads do not enter velocityVerlet.

Definition at line 104 of file Dynamics.cpp.

104 {
105 auto pot = matter->getPotential();
106 if (!pot) {
107 throw std::invalid_argument("path-integral dynamics has no potential");
108 }
109 const long atoms = matter->numberOfAtoms();
110 std::vector<double> masses(static_cast<size_t>(atoms));
111 std::vector<int> numbers(static_cast<size_t>(atoms));
112 std::vector<char> free(static_cast<size_t>(3 * atoms), 1);
113 const VectorXi z = matter->getAtomicNrs();
114 for (long i = 0; i < atoms; ++i) {
115 masses[static_cast<size_t>(i)] = matter->getMass(i);
116 numbers[static_cast<size_t>(i)] = z[i];
117 for (int axis = 0; axis < 3; ++axis) {
118 if (matter->getFixed(i, axis)) {
119 free[static_cast<size_t>(3 * i + axis)] = 0;
120 }
121 }
122 }
123 pathintegral::Options opt;
124 opt.beads = m_config.path_beads;
125 opt.temperature = temperature;
126 opt.kB = kB;
127 opt.hbar = tunneling::kHbar;
128 opt.dt = dt;
129 opt.springs = m_config.path_springs == "eco" ? pathintegral::Springs::Eco
131 opt.thermostat = m_config.thermostat_kind == PIGLET
134 opt.pileTau = m_config.path_pile_tau;
135 opt.pileScale = m_config.path_pile_scale;
136 opt.ecoOmegaMax = m_config.path_eco_omega_max;
137 opt.gleFile = m_config.path_gle_file;
138 opt.seed = m_config.path_seed;
139 pathintegral::RingPolymer ring(atoms, masses, numbers, free, opt);
140 const AtomMatrix pos = matter->getPositions();
141 ring.setAllBeads(pos.data());
142 const Matrix3d box =
143 matter->getPeriodic() ? matter->getCell() : Matrix3d::Zero().eval();
144 for (long step = 0; step < m_config.steps; ++step) {
145 ring.step(*pot, box.data(), false);
146 }
147 const VectorXd centroid = ring.centroid();
148 const VectorXd velocity = ring.centroidVelocity();
149 AtomMatrix out = pos;
150 AtomMatrix vel = matter->getVelocities();
151 for (long i = 0; i < atoms; ++i) {
152 for (int axis = 0; axis < 3; ++axis) {
153 out(i, axis) = centroid[3 * i + axis];
154 vel(i, axis) = velocity[3 * i + axis];
155 }
156 }
157 matter->setPositions(out);
158 matter->setVelocities(vel);
159}
Eigen::Matrix< double, 3, 3, eOnStorageOrder > Matrix3d
Definition Eigen.h:35
constexpr double kHbar
hbar in eV^0.5 amu^0.5 Angstrom, correctly rounded from the exact SI values (h = 6....
Definition Tunneling.h:37

◆ setTemperature()

void eonc::Dynamics::setTemperature ( double temperature)

Definition at line 53 of file Dynamics.cpp.

53 {
54 temperature = temperature_in;
55}

◆ setThermalVelocity()

void eonc::Dynamics::setThermalVelocity ( )

Definition at line 247 of file Dynamics.cpp.

247 {
248 AtomMatrix velocity = matter->getVelocities();
249 auto mass = matter->getMasses();
250
251 for (long i = 0; i < nAtoms; i++) {
252 if (!matter->getFixed(i)) {
253 for (int j = 0; j < 3; j++) {
254 velocity(i, j) = (mass[i] > 0.0 && kB > 0.0 && temperature > 0.0)
255 ? std::sqrt(kB * temperature / mass[i]) *
256 eonc::rng::gaussRandom(0.0, 1.0)
257 : 0.0;
258 }
259 }
260 }
261 matter->setVelocities(velocity);
262}

◆ velocityVerlet()

void eonc::Dynamics::velocityVerlet ( )

Definition at line 91 of file Dynamics.cpp.

91 {
92 AtomMatrix positions = matter->getPositions();
93 AtomMatrix velocities = matter->getVelocities();
94 AtomMatrix accInit = matter->getAccelerations();
95
96 positions += dt * velocities + 0.5 * dt * dt * accInit;
97 matter->setPositions(positions);
98
99 AtomMatrix accFinal = matter->getAccelerations();
100 velocities += 0.5 * dt * (accInit + accFinal);
101 matter->setVelocities(velocities);
102}

Member Data Documentation

◆ ANDERSEN

const char eonc::Dynamics::ANDERSEN = "andersen"
static

Definition at line 73 of file Dynamics.h.

◆ dt

double eonc::Dynamics::dt {0.0}
private

Definition at line 110 of file Dynamics.h.

110{0.0};

◆ kB

double eonc::Dynamics::kB {0.0}
private

Definition at line 111 of file Dynamics.h.

111{0.0};

◆ LANGEVIN

const char eonc::Dynamics::LANGEVIN = "langevin"
static

Definition at line 75 of file Dynamics.h.

◆ log

eonc::log::Scoped eonc::Dynamics::log
private

Definition at line 114 of file Dynamics.h.

◆ m_config

DynamicsConfig eonc::Dynamics::m_config
private

Definition at line 108 of file Dynamics.h.

◆ matter

Matter* eonc::Dynamics::matter
private

Definition at line 107 of file Dynamics.h.

◆ nAtoms

long eonc::Dynamics::nAtoms {0}
private

Definition at line 105 of file Dynamics.h.

105{0}, nFreeCoords{0};

◆ nFreeCoords

long eonc::Dynamics::nFreeCoords {0}
private

Definition at line 105 of file Dynamics.h.

105{0}, nFreeCoords{0};

◆ NONE

const char eonc::Dynamics::NONE = "none"
static

Definition at line 76 of file Dynamics.h.

◆ NOSE_HOOVER

const char eonc::Dynamics::NOSE_HOOVER = "nose_hoover"
static

Definition at line 74 of file Dynamics.h.

◆ PIGLET

const char eonc::Dynamics::PIGLET = "piglet"
static

Definition at line 78 of file Dynamics.h.

◆ PILE

const char eonc::Dynamics::PILE = "pile"
static

Definition at line 77 of file Dynamics.h.

◆ temperature

double eonc::Dynamics::temperature {0.0}
private

Definition at line 112 of file Dynamics.h.

112{0.0};

◆ vxi1

double eonc::Dynamics::vxi1 {0.0}
private

Definition at line 113 of file Dynamics.h.

113{0.0}, vxi2{0.0}, xi1{0.0}, xi2{0.0};

◆ vxi2

double eonc::Dynamics::vxi2 {0.0}
private

Definition at line 113 of file Dynamics.h.

113{0.0}, vxi2{0.0}, xi1{0.0}, xi2{0.0};

◆ xi1

double eonc::Dynamics::xi1 {0.0}
private

Definition at line 113 of file Dynamics.h.

113{0.0}, vxi2{0.0}, xi1{0.0}, xi2{0.0};

◆ xi2

double eonc::Dynamics::xi2 {0.0}
private

Definition at line 113 of file Dynamics.h.

113{0.0}, vxi2{0.0}, xi1{0.0}, xi2{0.0};

The documentation for this class was generated from the following files: