Loading...
Searching...
No Matches
GleThermostat.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 <fstream>
13#include <sstream>
14#include <vector>
15
16#include <unsupported/Eigen/MatrixFunctions>
17
18#include "eon/GleThermostat.h"
19
20namespace eonc {
21
22MatrixXd GleThermostat::loadDriftMatrix(const std::string &path) {
23 std::ifstream in(path);
24 if (!in) {
25 return MatrixXd();
26 }
27 std::vector<std::vector<double>> rows;
28 std::string line;
29 while (std::getline(in, line)) {
30 const auto hash = line.find('#');
31 if (hash != std::string::npos) {
32 line = line.substr(0, hash);
33 }
34 std::istringstream ss(line);
35 std::vector<double> row;
36 double v;
37 while (ss >> v) {
38 row.push_back(v);
39 }
40 if (!row.empty()) {
41 rows.push_back(std::move(row));
42 }
43 }
44 const auto n = static_cast<long>(rows.size());
45 if (n == 0) {
46 return MatrixXd();
47 }
48 MatrixXd a(n, n);
49 for (long i = 0; i < n; ++i) {
50 if (static_cast<long>(rows[i].size()) != n) {
51 return MatrixXd();
52 }
53 for (long j = 0; j < n; ++j) {
54 a(i, j) = rows[i][j];
55 }
56 }
57 return a;
58}
59
60GleThermostat::GleThermostat(const MatrixXd &a_drift, double kbt,
61 double dt_half, long n_dof) {
62 const long dim = a_drift.rows();
63 if (dim == 0 || a_drift.cols() != dim || !(kbt > 0.0) || !(dt_half > 0.0) ||
64 n_dof <= 0) {
65 return;
66 }
67 m_T = (-a_drift * dt_half).exp();
68 // Fluctuation-dissipation: S S^T = kbt (I - T T^T). The right-hand
69 // side is symmetric positive semi-definite; factor through its
70 // eigendecomposition with negative rounding clamped so a
71 // deterministic (dt -> 0) or overdamped block cannot poison the
72 // Cholesky.
73 const MatrixXd cov =
74 kbt * (MatrixXd::Identity(dim, dim) - m_T * m_T.transpose());
75 Eigen::SelfAdjointEigenSolver<MatrixXd> es(cov);
76 if (es.info() != Eigen::Success) {
77 return;
78 }
79 m_S = es.eigenvectors() *
80 es.eigenvalues().cwiseMax(0.0).cwiseSqrt().asDiagonal();
81 m_Z = MatrixXd::Zero(dim, n_dof);
82 m_valid = true;
83}
84
85void GleThermostat::apply(VectorXd &vel, const VectorXd &masses3N,
86 const std::function<double()> &gauss) {
87 if (!m_valid || vel.size() != m_Z.cols()) {
88 return;
89 }
90 const VectorXd sqrtM = masses3N.cwiseSqrt();
91 m_Z.row(0) = (vel.cwiseProduct(sqrtM)).transpose();
92 MatrixXd xi(m_Z.rows(), m_Z.cols());
93 for (long i = 0; i < xi.rows(); ++i) {
94 for (long j = 0; j < xi.cols(); ++j) {
95 xi(i, j) = gauss();
96 }
97 }
98 m_Z = m_T * m_Z + m_S * xi;
99 vel = m_Z.row(0).transpose().cwiseQuotient(sqrtM);
100}
101
102} // namespace eonc
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, eOnStorageOrder > MatrixXd
Definition Eigen.h:33
MatrixXd m_S
noise factor, S S^T = kbt (I - T T^T)
MatrixXd m_T
exp(-A dt/2)
void apply(VectorXd &vel, const VectorXd &masses3N, const std::function< double()> &gauss)
One OU half-step on the mass-scaled velocities; gauss supplies standard-normal draws from the job's d...
MatrixXd m_Z
extended state, (1 + n_aux) x n_dof
GleThermostat(const MatrixXd &a_drift, double kbt, double dt_half, long n_dof)
Build from the drift matrix, target kB*T (eV), the half-step dt (internal units), and the number of f...
static MatrixXd loadDriftMatrix(const std::string &path)
Load a drift matrix from a gle4md-layout text file ('#' starts a comment).
RAII resource manager for the ARTn C library with global synchronization.