Loading...
Searching...
No Matches
NEBForceProjection.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*/
13#include "eon/HelperFunctions.h"
14
15#include <algorithm>
16#include <cmath>
17
18namespace eonc::neb {
19
20// matDot is now in Eigen.h (shared across all files)
21
23 const AtomMatrix &posDiffPrev, double energy,
24 double energyPrev, double energyNext,
25 bool use_old_tangent) {
26 AtomMatrix tang;
27
28 if (use_old_tangent) {
29 tang = posDiffNext;
30 } else {
31 // Improved tangent scheme
32 if (energyNext > energy && energy > energyPrev) {
33 tang = posDiffNext;
34 } else if (energy > energyNext && energyPrev > energy) {
35 tang = posDiffPrev;
36 } else {
37 // Extremum: energy-weighted combination
38 double energyDiffPrev = energyPrev - energy;
39 double energyDiffNext = energyNext - energy;
40 double minDiffEnergy =
41 std::min(std::abs(energyDiffPrev), std::abs(energyDiffNext));
42 double maxDiffEnergy =
43 std::max(std::abs(energyDiffPrev), std::abs(energyDiffNext));
44
45 if (energyDiffPrev > energyDiffNext) {
46 tang = posDiffNext * minDiffEnergy + posDiffPrev * maxDiffEnergy;
47 } else {
48 tang = posDiffNext * maxDiffEnergy + posDiffPrev * minDiffEnergy;
49 }
50 }
51 }
52
53 // Normalize with safety check
54 double norm = tang.norm();
55 if (norm > 1e-10) {
56 tang /= norm;
57 } else {
58 // Fallback: use direction to next image
59 tang = posDiffNext;
60 norm = tang.norm();
61 if (norm > 1e-10) {
62 tang /= norm;
63 }
64 }
65
66 return tang;
67}
68
69AtomMatrix forcePerp(const AtomMatrix &force, const AtomMatrix &tangent) {
70 return force - matDot(force, tangent) * tangent;
71}
72
74 const AtomMatrix &tangent,
75 const AtomMatrix &forceDNEB) {
76 return force - 2.0 * matDot(force, tangent) * tangent + forceDNEB;
77}
78
79AtomMatrix computeDNEB(const AtomMatrix &forceSpring, const AtomMatrix &tangent,
80 const AtomMatrix &fPerp) {
81 AtomMatrix forceSpringPerp =
82 forceSpring - matDot(forceSpring, tangent) * tangent;
83
84 const double forceSpringPerpNorm = forceSpringPerp.norm();
85 const double forcePerpNorm = fPerp.norm();
86
87 if (forceSpringPerpNorm > 1e-10 && forcePerpNorm > 1e-10) {
88 AtomMatrix forcePerpNormalized = fPerp / forcePerpNorm;
89 AtomMatrix dneb =
90 forceSpringPerp -
91 matDot(forceSpringPerp, forcePerpNormalized) * forcePerpNormalized;
92
93 double switching = 2.0 / eonc::helpers::pi *
94 std::atan(forcePerpNorm * forcePerpNorm /
95 (forceSpringPerpNorm * forceSpringPerpNorm));
96 dneb *= switching;
97 return dneb;
98 }
99
100 return AtomMatrix::Zero(tangent.rows(), tangent.cols());
101}
102
103void zeroTranslation(AtomMatrix &projectedForce, int nFreeAtoms, int nAtoms) {
104 if (nFreeAtoms == nAtoms) {
105 for (int j = 0; j <= 2; j++) {
106 double translationMag = projectedForce.col(j).sum();
107 int natoms = projectedForce.col(j).size();
108 projectedForce.col(j).array() -=
109 translationMag / static_cast<double>(natoms);
110 }
111 }
112}
113
114} // namespace eonc::neb
double matDot(const AtomMatrix &a, const AtomMatrix &b)
SIMD-optimized dot product for contiguous Eigen matrices.
Definition Eigen.h:50
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
constexpr double pi
void zeroTranslation(AtomMatrix &projectedForce, int nFreeAtoms, int nAtoms)
Zero net translational force for fully free systems.
AtomMatrix climbingImageForce(const AtomMatrix &force, const AtomMatrix &tangent, const AtomMatrix &forceDNEB)
Compute the climbing image projected force.
AtomMatrix computeTangent(const AtomMatrix &posDiffNext, const AtomMatrix &posDiffPrev, double energy, double energyPrev, double energyNext, bool use_old_tangent)
Compute the tangent vector at image i using the improved tangent scheme.
AtomMatrix forcePerp(const AtomMatrix &force, const AtomMatrix &tangent)
Compute the perpendicular component of force relative to the tangent.
AtomMatrix computeDNEB(const AtomMatrix &forceSpring, const AtomMatrix &tangent, const AtomMatrix &fPerp)
Compute the doubly-nudged elastic band perpendicular spring force.