Loading...
Searching...
No Matches
eonc::Prefactor Namespace Reference

Functions

int getPrefactors (const Parameters &parameters, Matter *min1, Matter *saddle, Matter *min2, double &pref1, double &pref2)
VectorXi movedAtoms (const Parameters &parameters, Matter *min1, Matter *saddle, Matter *min2)
VectorXi movedAtomsPct (const Parameters &parameters, Matter *min1, Matter *saddle, Matter *min2)
VectorXi allFreeAtoms (Matter *matter)
VectorXd removeZeroFreqs (const Parameters &parameters, VectorXd freqs)
void logFreqs (const VectorXd &freqs, const char *name)

Variables

const char RATE_HTST [] = "htst"
const char RATE_QQHTST [] = "qqhtst"
const char FILTER_CUTOFF [] = "cutoff"
const char FILTER_FRACTION [] = "fraction"

Function Documentation

◆ allFreeAtoms()

VectorXi eonc::Prefactor::allFreeAtoms ( Matter * matter)

Definition at line 310 of file Prefactor.cpp.

310 {
311 long nAtoms = matter->numberOfAtoms();
312
313 VectorXi moved(nAtoms);
314 moved.setConstant(-1);
315
316 int nMoved = 0;
317 for (int i = 0; i < nAtoms; i++) {
318 if (!matter->getFixed(i)) {
319 moved[nMoved] = i;
320 nMoved++;
321 }
322 }
323 return moved.head(nMoved);
324}
long int numberOfAtoms() const
Definition Matter.cpp:209
int getFixed(long int atom) const
1 if every Cartesian axis of the atom is fixed, else 0.
Definition Matter.cpp:402

◆ getPrefactors()

int eonc::Prefactor::getPrefactors ( const Parameters & parameters,
Matter * min1,
Matter * saddle,
Matter * min2,
double & pref1,
double & pref2 )

Definition at line 22 of file Prefactor.cpp.

24 {
25 VectorXd min1Freqs, saddleFreqs, min2Freqs;
26
27 // determine which atoms moved in the process
28 VectorXi atoms;
29
30 if (parameters.prefactor_options.filter_scheme ==
32 atoms = movedAtomsPct(parameters, min1, saddle, min2);
33 } else {
34 atoms = movedAtoms(parameters, min1, saddle, min2);
35 }
36
37 assert(atoms.rows() > 0);
38
39 // calculate min1 frequencies
40 Hessian hessian(parameters, min1);
41 min1Freqs = hessian.getFreqs(min1, atoms);
42 if (min1Freqs.size() == 0) {
43 EONC_LOG_ERROR("[Prefactor] Bad hessian: min1");
44 return -1;
45 }
46 // remove zero modes
48 min1Freqs = hessian.removeZeroFreqs(min1Freqs);
49 }
50
51 // calculate saddle frequencies
52 saddleFreqs = hessian.getFreqs(saddle, atoms);
53 if (saddleFreqs.size() == 0) {
54 EONC_LOG_ERROR("[Prefactor] Bad hessian: saddle");
55 return -1;
56 }
57 // remove zero modes
59 saddleFreqs = hessian.removeZeroFreqs(saddleFreqs);
60 }
61
62 // calculate min2 frequencies
63 min2Freqs = hessian.getFreqs(min2, atoms);
64 if (min2Freqs.size() == 0) {
65 if (!parameters.main_options.quiet) {
66 EONC_LOG_ERROR("[Prefactor] Bad hessian: min2");
67 }
68 return -1;
69 }
70 // remove zero modes
72 min2Freqs = hessian.removeZeroFreqs(min2Freqs);
73 }
74
75 // check Hessian sizes
76 // BUG FIX: original checked min1 vs saddle twice, never min2
77 if ((min1Freqs.size() != saddleFreqs.size()) ||
78 (min2Freqs.size() != saddleFreqs.size())) {
79 if (!parameters.main_options.quiet) {
80 EONC_LOG_ERROR("[Prefactor] Bad prefactor: Hessian sizes do not match");
81 }
82 return -1;
83 }
84
85 logFreqs(min1Freqs, "minimum 1");
86 logFreqs(saddleFreqs, "saddle");
87 logFreqs(min2Freqs, "minimum 2");
88
89 // check for correct number of negative modes
90 // Bound each loop by its own vector: removeZeroFreqs returns a shorter
91 // vector than the 3N it was handed, and each of the three is shrunk by a
92 // separate call.
93 int numNegFreq = 0;
94 for (int i = 0; i < min1Freqs.size(); i++) {
95 if (min1Freqs(i) < 0) {
96 EONC_LOG_DEBUG("[Prefactor] min1 had negative mode of {}", min1Freqs(i));
97 numNegFreq++;
98 }
99 }
100 if (numNegFreq != 0) {
101 EONC_LOG_DEBUG("[Prefactor] Error: {} negative modes at min1", numNegFreq);
102 return -1;
103 }
104
105 numNegFreq = 0;
106 for (int i = 0; i < saddleFreqs.size(); i++) {
107 if (saddleFreqs(i) < 0) {
108 numNegFreq++;
109 }
110 }
111 if (numNegFreq != 1) {
112 EONC_LOG_DEBUG("Error: {} negative modes at saddle", numNegFreq);
113 return -1;
114 }
115
116 numNegFreq = 0;
117 for (int i = 0; i < min2Freqs.size(); i++) {
118 if (min2Freqs(i) < 0) {
119 numNegFreq++;
120 }
121 }
122 if (numNegFreq != 0) {
123 EONC_LOG_DEBUG("Error: {} negative modes at min2", numNegFreq);
124 return -1;
125 }
126
127 // calculate the prefactors
128 pref1 = 1.0;
129 pref2 = 1.0;
130
132
133 // products are calculated this way in order to avoid overflow
134 for (int i = 0; i < saddleFreqs.size(); i++) {
135 pref1 *= min1Freqs[i];
136 pref2 *= min2Freqs[i];
137 if (saddleFreqs[i] > 0) {
138 pref1 /= saddleFreqs[i];
139 pref2 /= saddleFreqs[i];
140 }
141 }
142 pref1 = std::sqrt(pref1) / (2 * eonc::helpers::pi * 10.18e-15);
143 pref2 = std::sqrt(pref2) / (2 * eonc::helpers::pi * 10.18e-15);
144 } else if (parameters.prefactor_options.rate ==
146 double kB_T = parameters.main_options.temperature * 8.617332e-5; // eV
147 double h_bar = 6.582119e-16; // eV*s
148 double h = 4.135667e-15; // eV*s
149 double temp = (h_bar / (2.0 * kB_T));
150
151 for (int i = 0; i < min1Freqs.size(); i++) {
152 pref1 = pref1 * (std::sinh(temp * (std::sqrt(min1Freqs[i]) / 10.18e-15)));
153 pref2 = pref2 * (std::sinh(temp * (std::sqrt(min2Freqs[i]) / 10.18e-15)));
154
155 if (saddleFreqs[i] > 0) {
156 pref1 =
157 pref1 / (std::sinh(temp * (std::sqrt(saddleFreqs[i]) / 10.18e-15)));
158 pref2 =
159 pref2 / (std::sinh(temp * (std::sqrt(saddleFreqs[i]) / 10.18e-15)));
160 }
161 }
162 pref1 = 2. * kB_T / (h)*pref1;
163 pref2 = 2. * kB_T / (h)*pref2;
164 }
165 EONC_LOG_DEBUG("[Prefactor] reactant to product prefactor: {:.3e}", pref1);
166 EONC_LOG_DEBUG("[Prefactor] product to reactant prefactor: {:.3e}", pref2);
167 return 0;
168}
#define EONC_LOG_DEBUG(...)
Definition EonLogger.h:244
#define EONC_LOG_ERROR(...)
Definition EonLogger.h:262
struct eonc::Parameters::structure_comparison_options_t structure_comparison_options
struct eonc::Parameters::prefactor_options_t prefactor_options
struct eonc::Parameters::main_options_t main_options
void logFreqs(const VectorXd &freqs, const char *name)
VectorXi movedAtomsPct(const Parameters &parameters, Matter *min1, Matter *saddle, Matter *min2)
VectorXi movedAtoms(const Parameters &parameters, Matter *min1, Matter *saddle, Matter *min2)
const char RATE_HTST[]
Definition Prefactor.h:22
const char RATE_QQHTST[]
Definition Prefactor.h:23
const char FILTER_FRACTION[]
Definition Prefactor.h:25
constexpr double pi

◆ logFreqs()

void eonc::Prefactor::logFreqs ( const VectorXd & freqs,
const char * name )

Definition at line 170 of file Prefactor.cpp.

170 {
171 std::ofstream outFile("freqs.dat", std::ios::app);
172 if (!outFile.is_open())
173 return;
174
175 outFile << std::format("[Prefactor] Frequencies at {}\n", name);
176 for (int i = 0; i < freqs.size(); i++) {
177 outFile << "\n" << std::format("{:10.6f} ", freqs(i));
178 if ((i + 1) % 5 == 0) {
179 outFile << "\n";
180 }
181 }
182 outFile << "\n";
183}

◆ movedAtoms()

VectorXi eonc::Prefactor::movedAtoms ( const Parameters & parameters,
Matter * min1,
Matter * saddle,
Matter * min2 )

Definition at line 185 of file Prefactor.cpp.

186 {
187 long nAtoms = saddle->numberOfAtoms();
188
189 VectorXi moved(nAtoms);
190 moved.setConstant(-1);
191
192 AtomMatrix diffMin1 =
193 saddle->pbc(saddle->getPositions() - min1->getPositions());
194 AtomMatrix diffMin2 =
195 saddle->pbc(saddle->getPositions() - min2->getPositions());
196
197 diffMin1.array() *= saddle->getFree().array();
198 diffMin2.array() *= saddle->getFree().array();
199
200 int nMoved = 0;
201 for (int i = 0; i < nAtoms; i++) {
202 if ((diffMin1.row(i).norm() >
204 (diffMin2.row(i).norm() >
206 // Avoid Eigen Array == scalar in boolean context (C++20 / Eigen 3.3
207 // manylinux toolchains reject Array comparison as bool).
208 if (std::find(moved.data(), moved.data() + nMoved, i) ==
209 moved.data() + nMoved) {
210 moved[nMoved] = i;
211 nMoved++;
212 }
213 for (int j = 0; j < nAtoms; j++) {
214 double diffRSaddle = saddle->distance(i, j);
215
216 if (diffRSaddle < parameters.prefactor_options.within_radius &&
217 (!saddle->getFixed(j))) {
218 if (std::find(moved.data(), moved.data() + nMoved, j) ==
219 moved.data() + nMoved) {
220 moved[nMoved] = j;
221 nMoved++;
222 }
223 }
224 }
225 }
226 }
227 return moved.head(nMoved);
228}
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
double distance(long index1, long index2) const
Definition Matter.cpp:360
AtomMatrix getFree() const
Definition Matter.cpp:580
AtomMatrix pbc(const AtomMatrix &diff) const
Definition Matter.h:163
const AtomMatrix & getPositions() const
Definition Matter.cpp:236

◆ movedAtomsPct()

VectorXi eonc::Prefactor::movedAtomsPct ( const Parameters & parameters,
Matter * min1,
Matter * saddle,
Matter * min2 )

Definition at line 230 of file Prefactor.cpp.

232 {
233 long nAtoms = saddle->numberOfAtoms();
234 long nFree = saddle->numberOfFreeAtoms();
235
236 VectorXi moved(nAtoms);
237 moved.setConstant(-1);
238
239 AtomMatrix diffMin1 =
240 saddle->pbc(saddle->getPositions() - min1->getPositions());
241 AtomMatrix diffMin2 =
242 saddle->pbc(saddle->getPositions() - min2->getPositions());
243
244 diffMin1.array() *= saddle->getFree().array();
245 diffMin2.array() *= saddle->getFree().array();
246
247 VectorXd diff(nAtoms);
248 diff.setConstant(0.0);
249
250 QUILL_LOG_DEBUG(
252 "[Prefactor] including all atoms that make up {:.3f}% of the motion",
253 parameters.prefactor_options.filter_fraction * 100);
254 double sum = 0.0;
255 int mini = 0;
256 for (int i = 0; i < nAtoms; i++) {
257 diff[i] = std::max(diffMin1.row(i).norm(), diffMin2.row(i).norm());
258 sum += diff[i];
259 if (diff[i] <= diff[mini]) {
260 mini = i;
261 }
262 }
263
264 EONC_LOG_DEBUG("[Prefactor] sum of atom distances moved {:.4f}", sum);
265 EONC_LOG_DEBUG("[Prefactor] max moved atom distance: {:.4f}",
266 diff.maxCoeff());
267
268 int nMoved = 0;
269 double d = 0.0;
270 while (d / sum <= parameters.prefactor_options.filter_fraction &&
271 nMoved < nFree) {
272 int maxi = mini;
273 for (int i = 0; i < nAtoms; i++) {
274 if (diff[i] >= diff[maxi]) {
275 if (std::find(moved.data(), moved.data() + nMoved, i) ==
276 moved.data() + nMoved) {
277 maxi = i;
278 }
279 }
280 }
281 moved[nMoved] = maxi;
282 nMoved++;
283 d += diff[maxi];
284 }
285
286 int totalAtoms = nMoved;
287 for (int i = 0; i < nMoved; i++) {
288 for (int j = 0; j < nAtoms; j++) {
289 if (moved[i] == j)
290 continue;
291
292 double diffRSaddle = saddle->distance(moved[i], j);
293
294 if (diffRSaddle < parameters.prefactor_options.within_radius &&
295 (!saddle->getFixed(j))) {
296
297 if (std::find(moved.data(), moved.data() + totalAtoms, j) ==
298 moved.data() + totalAtoms) {
299 moved[totalAtoms++] = j;
300 }
301 }
302 }
303 }
304 EONC_LOG_DEBUG("[Prefactor] including {} atoms in the hessian ({} moved + {} "
305 "neighbors)",
306 totalAtoms, nMoved, totalAtoms - nMoved);
307 return moved.head(totalAtoms);
308}
long int numberOfFreeAtoms() const
Definition Matter.cpp:475
quill::Logger * get() noexcept
Get or create the default "combi" logger.
Definition EonLogger.h:44

◆ removeZeroFreqs()

VectorXd eonc::Prefactor::removeZeroFreqs ( const Parameters & parameters,
VectorXd freqs )

Variable Documentation

◆ FILTER_CUTOFF

const char eonc::Prefactor::FILTER_CUTOFF[] = "cutoff"

Definition at line 24 of file Prefactor.h.

◆ FILTER_FRACTION

const char eonc::Prefactor::FILTER_FRACTION[] = "fraction"

Definition at line 25 of file Prefactor.h.

◆ RATE_HTST

const char eonc::Prefactor::RATE_HTST[] = "htst"

Definition at line 22 of file Prefactor.h.

◆ RATE_QQHTST

const char eonc::Prefactor::RATE_QQHTST[] = "qqhtst"

Definition at line 23 of file Prefactor.h.