142 {
144 alignment = 0.0;
145
147 QUILL_LOG_WARNING(log, "Invalid climbing image for MMF: {}",
149 return -1;
150 }
151
155 } else {
157 }
158 double tangentNorm = initialMode.norm();
159 if (tangentNorm < 1e-8) {
160 QUILL_LOG_WARNING(log, "Tangent too small for MMF initialization");
161 return -1;
162 }
163 initialMode /= tangentNorm;
164
165 auto tempMinModeSearch = std::make_shared<MinModeSaddleSearch>(
168
169 int minModeStatus;
170 try {
171 minModeStatus = tempMinModeSearch->run(
cfg_.max_steps);
172 } catch (const eonc::DimerModeRestoredException &) {
174 QUILL_LOG_DEBUG(log, "MMF: Dimer restored to best state");
175 } catch (const eonc::DimerModeLostException &) {
177 QUILL_LOG_WARNING(log, "Dimer lost mode during MMF refinement");
178 }
179
181
182 double eigenvalue = tempMinModeSearch->getEigenvalue();
183 if (eigenvalue > 0.0) {
184 QUILL_LOG_WARNING(log,
185 "MMF skipped: Positive curvature detected (eig={:.4f}).",
186 eigenvalue);
187 return -2;
188 }
189
190 AtomMatrix finalModeMatrix = tempMinModeSearch->getEigenvector();
191 VectorXd finalMode = VectorXd::Map(finalModeMatrix.data(), 3 * neb.
atoms);
192 VectorXd currentTangent =
194 alignment = std::abs(finalMode.normalized().dot(currentTangent.normalized()));
195
198 if (alignment <
cfg_.angle_tol) {
199 QUILL_LOG_WARNING(
200 log,
201 "MMF converged/restored but mode drifted (alignment={:.3f} < {:.3f})",
202 alignment,
cfg_.angle_tol);
203 return -1;
204 }
207 return 0;
209 return 1;
210 } else {
211 QUILL_LOG_WARNING(log, "MMF failed. Mode-tangent alignment: {:.3f}",
212 alignment);
213 return -1;
214 }
215}
@ STATUS_BAD_MAX_ITERATIONS
@ STATUS_DIMER_RESTORED_BEST
std::vector< std::shared_ptr< AtomMatrix > > tangent
std::shared_ptr< Potential > pot