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, bool useSwitching) {
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 if (useSwitching) {
94 double switching = 2.0 / eonc::helpers::pi *
95 std::atan(forcePerpNorm * forcePerpNorm /
96 (forceSpringPerpNorm * forceSpringPerpNorm));
97 dneb *= switching;
98 }
99 return dneb;
100 }
101
102 return AtomMatrix::Zero(tangent.rows(), tangent.cols());
103}
104
105void zeroTranslation(AtomMatrix &projectedForce, int nFreeAtoms, int nAtoms) {
106 if (nFreeAtoms == nAtoms) {
107 for (int j = 0; j <= 2; j++) {
108 double translationMag = projectedForce.col(j).sum();
109 int natoms = projectedForce.col(j).size();
110 projectedForce.col(j).array() -=
111 translationMag / static_cast<double>(natoms);
112 }
113 }
114}
115
116} // 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
AtomMatrix computeDNEB(const AtomMatrix &forceSpring, const AtomMatrix &tangent, const AtomMatrix &fPerp, bool useSwitching)
Compute the doubly-nudged elastic band perpendicular spring force.
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.