66 {
68
71
73 if (dimer && !dimer->rotationDidConverge) {
74 if (dimer->getEigenvalue() < 0.0) {
77 "[MinMode] Dimer restored to best state with C_tau={:.4f}",
78 dimer->getEigenvalue());
79 throw eonc::DimerModeRestoredException();
80 } else {
81 throw eonc::DimerModeLostException();
82 }
83 }
85 }
86
89
92
93 if (eigenvalue > 0.0) {
94 if (
params.saddle_search_options().perp_force_ratio > 0.0) {
95 double d =
params.saddle_search_options().perp_force_ratio;
96 force = d * force - (1.0 + d) * proj;
97 }
else if (
params.saddle_search_options().confine_positive.enabled) {
98 if (
params.saddle_search_options().confine_positive.bowl_breakout) {
100 const long nAtoms =
matter->numberOfAtoms();
101 int nBowlActive = static_cast<int>(std::min<long>(
102 params.saddle_search_options().confine_positive.bowl_active,
103 nAtoms));
104 if (nBowlActive <= 0) {
105 force.setZero();
106 } else {
107 std::vector<int> indices_max(nBowlActive);
108
109
110 for (int j = 0; j < nBowlActive; j++) {
111 double f_max = forceTemp.row(0).norm();
112 int i_max = 0;
113 for (
long i = 0; i <
matter->numberOfAtoms(); i++) {
114 if (f_max < forceTemp.row(i).norm()) {
115 f_max = forceTemp.row(i).norm();
116 i_max = static_cast<int>(i);
117 }
118 }
119 forceTemp.row(i_max).setZero();
120 indices_max[j] = i_max;
121 }
122 forceTemp.setZero();
123 for (int j = 0; j < nBowlActive; j++) {
124 forceTemp.row(indices_max[j]) = -proj.row(indices_max[j]);
125 }
126 force = forceTemp;
127 }
128 } else {
129 int sufficientForce = 0;
130 double minForce =
131 params.saddle_search_options().confine_positive.min_force;
132 const long maxBoostTries = std::max(
133 3 *
matter->numberOfAtoms(),
134 params.saddle_search_options().confine_positive.min_active);
135 long boostTries = 0;
136 while (
137 sufficientForce <
138 params.saddle_search_options().confine_positive.min_active &&
139 boostTries < maxBoostTries) {
140 sufficientForce = 0;
141 force =
matter->getForces();
142 for (
long i = 0; i <
matter->numberOfAtoms(); i++) {
143 for (int k = 0; k < 3; k++) {
144 if (std::abs(force(i, k)) < minForce) {
145 force(i, k) = 0;
146 } else {
147 sufficientForce++;
148 force(i, k) =
149 -
params.saddle_search_options().confine_positive.boost *
150 proj(i, k);
151 }
152 }
153 }
154 minForce *=
155 params.saddle_search_options().confine_positive.scale_ratio;
156 boostTries++;
157 }
158 }
159 } else {
160 force = -proj;
161 }
162 } else {
163 force += -2.0 * proj;
164 }
165
166 VectorXd forceV = VectorXd::Map(force.data(), 3 *
matter->numberOfAtoms());
167 return -forceV;
168 }
double matDot(const AtomMatrix &a, const AtomMatrix &b)
SIMD-optimized dot product for contiguous Eigen matrices.
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
#define EONC_LOG_DEBUG(...)
void eigenmodeCompute(LowestEigenmode &s, std::shared_ptr< Matter > matter, AtomMatrix direction)
ImprovedDimer * asImprovedDimer(LowestEigenmode &s)
double eigenmodeGetEigenvalue(LowestEigenmode &s)
AtomMatrix eigenmodeGetEigenvector(LowestEigenmode &s)