27 if (!min1 || !saddle || !min2) {
31 VectorXd min1Freqs, saddleFreqs, min2Freqs;
40 atoms =
movedAtoms(parameters, min1, saddle, min2);
43 if (atoms.size() == 0) {
49 Hessian hessian(parameters, min1);
50 min1Freqs = hessian.
getFreqs(min1, atoms);
51 if (min1Freqs.size() == 0) {
61 saddleFreqs = hessian.
getFreqs(saddle, atoms);
62 if (saddleFreqs.size() == 0) {
72 min2Freqs = hessian.
getFreqs(min2, atoms);
73 if (min2Freqs.size() == 0) {
85 if ((min1Freqs.size() != saddleFreqs.size()) ||
86 (min2Freqs.size() != saddleFreqs.size())) {
88 EONC_LOG_ERROR(
"[Prefactor] Bad prefactor: Hessian sizes do not match");
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));
108 if (numNegFreq != 0) {
109 EONC_LOG_DEBUG(
"[Prefactor] Error: {} negative modes at min1", numNegFreq);
114 for (
int i = 0; i < saddleFreqs.size(); i++) {
115 if (saddleFreqs(i) < 0) {
119 if (numNegFreq != 1) {
125 for (
int i = 0; i < min2Freqs.size(); i++) {
126 if (min2Freqs(i) < 0) {
130 if (numNegFreq != 0) {
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];
155 double h_bar = 6.582119e-16;
156 double h = 4.135667e-15;
157 double temp = (h_bar / (2.0 * kB_T));
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));
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));
168 pref1 = (2.0 * kB_T / h) * pref1;
169 pref2 = (2.0 * kB_T / h) * pref2;
171 EONC_LOG_DEBUG(
"[Prefactor] reactant to product prefactor: {:.3e}", pref1);
172 EONC_LOG_DEBUG(
"[Prefactor] product to reactant prefactor: {:.3e}", pref2);
177 std::ofstream outFile(
"freqs.dat", std::ios::app);
178 if (!outFile.is_open())
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) {
195 VectorXi moved(nAtoms);
196 moved.setConstant(-1);
203 diffMin1.array() *= saddle->
getFree().array();
204 diffMin2.array() *= saddle->
getFree().array();
207 for (
int i = 0; i < nAtoms; i++) {
208 if ((diffMin1.row(i).norm() >
210 (diffMin2.row(i).norm() >
214 if (std::find(moved.data(), moved.data() + nMoved, i) ==
215 moved.data() + nMoved) {
219 for (
int j = 0; j < nAtoms; j++) {
220 double diffRSaddle = saddle->
distance(i, j);
224 if (std::find(moved.data(), moved.data() + nMoved, j) ==
225 moved.data() + nMoved) {
233 return moved.head(nMoved);
242 VectorXi moved(nAtoms);
243 moved.setConstant(-1);
250 diffMin1.array() *= saddle->
getFree().array();
251 diffMin2.array() *= saddle->
getFree().array();
253 VectorXd diff(nAtoms);
254 diff.setConstant(0.0);
258 "[Prefactor] including all atoms that make up {:.3f}% of the motion",
262 for (
int i = 0; i < nAtoms; i++) {
263 diff[i] = std::max(diffMin1.row(i).norm(), diffMin2.row(i).norm());
265 if (diff[i] <= diff[mini]) {
270 EONC_LOG_DEBUG(
"[Prefactor] sum of atom distances moved {:.4f}", sum);
276 while (nMoved < nFree &&
280 for (
int i = 0; i < nAtoms; i++) {
284 if (std::find(moved.data(), moved.data() + nMoved, i) !=
285 moved.data() + nMoved) {
288 if (maxi < 0 || diff[i] >= diff[maxi]) {
295 moved[nMoved] = maxi;
300 int totalAtoms = nMoved;
301 for (
int i = 0; i < nMoved; i++) {
302 for (
int j = 0; j < nAtoms; j++) {
306 double diffRSaddle = saddle->
distance(moved[i], j);
311 if (std::find(moved.data(), moved.data() + totalAtoms, j) ==
312 moved.data() + totalAtoms) {
313 moved[totalAtoms++] = j;
318 EONC_LOG_DEBUG(
"[Prefactor] including {} atoms in the hessian ({} moved + {} "
320 totalAtoms, nMoved, totalAtoms - nMoved);
321 return moved.head(totalAtoms);
327 VectorXi moved(nAtoms);
328 moved.setConstant(-1);
331 for (
int i = 0; i < nAtoms; i++) {
337 return moved.head(nMoved);
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
#define EONC_LOG_DEBUG(...)
#define EONC_LOG_ERROR(...)
VectorXd removeZeroFreqs(const VectorXd &freqs)
VectorXd getFreqs(Matter *matterIn, const VectorXi &atomsIn)
const AtomMatrix & getPositions() const
AtomMatrix getFree() const
long int numberOfAtoms() const
AtomMatrix pbc(const AtomMatrix &diff) const
double distance(long index1, long index2) const
long int numberOfFreeAtoms() const
int getFixed(long int atom) const
1 if every Cartesian axis of the atom is fixed, else 0.
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
VectorXi allFreeAtoms(Matter *matter)
VectorXi movedAtomsPct(const Parameters ¶meters, Matter *min1, Matter *saddle, Matter *min2)
VectorXi movedAtoms(const Parameters ¶meters, Matter *min1, Matter *saddle, Matter *min2)
int getPrefactors(const Parameters ¶meters, Matter *min1, Matter *saddle, Matter *min2, double &pref1, double &pref2)
constexpr std::string_view RATE_QQHTST
constexpr std::string_view FILTER_FRACTION
quill::Logger * get() noexcept
Get or create the default "combi" logger.
RAII resource manager for the ARTn C library with global synchronization.
std::string filter_scheme