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)
void logFreqs (const VectorXd &freqs, const char *name)

Variables

constexpr std::string_view RATE_HTST {"htst"}
constexpr std::string_view RATE_QQHTST {"qqhtst"}
constexpr std::string_view FILTER_CUTOFF {"cutoff"}
constexpr std::string_view FILTER_FRACTION {"fraction"}

Function Documentation

◆ allFreeAtoms()

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

Definition at line 324 of file Prefactor.cpp.

324 {
325 long nAtoms = matter->numberOfAtoms();
326
327 VectorXi moved(nAtoms);
328 moved.setConstant(-1);
329
330 int nMoved = 0;
331 for (int i = 0; i < nAtoms; i++) {
332 if (!matter->getFixed(i)) {
333 moved[nMoved] = i;
334 nMoved++;
335 }
336 }
337 return moved.head(nMoved);
338}
long int numberOfAtoms() const
Definition Matter.cpp:273
int getFixed(long int atom) const
1 if every Cartesian axis of the atom is fixed, else 0.
Definition Matter.cpp:505

◆ getPrefactors()

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

Definition at line 24 of file Prefactor.cpp.

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

◆ logFreqs()

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

Definition at line 176 of file Prefactor.cpp.

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

◆ movedAtoms()

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

Definition at line 191 of file Prefactor.cpp.

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

◆ movedAtomsPct()

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

Definition at line 236 of file Prefactor.cpp.

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

Variable Documentation

◆ FILTER_CUTOFF

std::string_view eonc::Prefactor::FILTER_CUTOFF {"cutoff"}
inlineconstexpr

Definition at line 26 of file Prefactor.h.

26{"cutoff"};

◆ FILTER_FRACTION

std::string_view eonc::Prefactor::FILTER_FRACTION {"fraction"}
inlineconstexpr

Definition at line 27 of file Prefactor.h.

27{"fraction"};

◆ RATE_HTST

std::string_view eonc::Prefactor::RATE_HTST {"htst"}
inlineconstexpr

Definition at line 24 of file Prefactor.h.

24{"htst"};

◆ RATE_QQHTST

std::string_view eonc::Prefactor::RATE_QQHTST {"qqhtst"}
inlineconstexpr

Definition at line 25 of file Prefactor.h.

25{"qqhtst"};