eOn client
Long-timescale dynamics: aKMC, NEB, parallel replica
☾
Toggle main menu visibility
Loading...
Searching...
No Matches
ConjugateGradients.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
*/
12
#include "
eon/ConjugateGradients.h
"
13
#include "
eon/SafeMath.h
"
14
15
#include <cmath>
16
17
Eigen::VectorXd
ConjugateGradients::getStep
() {
18
double
a = std::fabs(
m_force
.dot(
m_forceOld
));
19
double
b =
m_forceOld
.squaredNorm();
20
double
gamma = 0.0;
21
if
(a < 0.5 * b) {
22
// Polak-Ribiere way to determine how much to mix in of old direction
23
gamma =
eonc::safemath::safe_div
(
m_force
.dot(
m_force
-
m_forceOld
), b, 0.0);
24
}
else
{
25
gamma = 0;
26
}
27
m_direction
=
m_force
+ gamma *
m_directionOld
;
28
m_directionNorm
=
m_direction
;
29
eonc::safemath::safe_normalize_inplace(
m_directionNorm
);
30
m_directionOld
=
m_direction
;
31
m_forceOld
=
m_force
;
32
33
// Only if value for max nr of iteration before reset
34
if
(
m_optConfig
.opts.cg.max_iter_before_reset > 0 &&
35
m_optConfig
.opts.cg.max_iter_before_reset <=
m_cg_i
) {
36
m_cg_i
= 0;
37
m_forceOld
.setZero();
38
m_directionOld
.setZero();
39
}
40
m_cg_i
+= 1;
41
42
return
m_direction
;
43
}
44
45
int
ConjugateGradients::step
(
double
a_maxMove) {
46
bool
converged;
47
if
(
m_optConfig
.opts.cg.line_search) {
48
converged =
line_search
(a_maxMove);
49
}
else
{
50
converged =
single_step
(a_maxMove);
51
}
52
if
(converged)
53
return
1;
54
return
0;
55
}
56
57
int
ConjugateGradients::line_search
(
double
a_maxMove) {
58
Eigen::VectorXd pos;
59
Eigen::VectorXd posStep;
60
Eigen::VectorXd forceBeforeStep;
61
double
stepSize;
62
double
projectedForce;
63
double
projectedForceBeforeStep;
64
double
curvature;
65
66
forceBeforeStep = -
m_objf
->getGradient();
67
m_force
= forceBeforeStep;
68
getStep
();
69
pos =
m_objf
->getPositions();
70
projectedForceBeforeStep =
m_force
.dot(
m_directionNorm
);
71
72
// move system an infinitesimal step to determine the optimal step size along
73
// the search line
74
posStep = pos +
m_directionNorm
*
m_optConfig
.finiteDifference;
75
m_objf
->setPositions(posStep);
76
m_force
= -
m_objf
->getGradient(
true
);
77
projectedForce =
m_force
.dot(
m_directionNorm
);
78
stepSize =
m_optConfig
.finiteDifference;
79
80
int
line_i = 0;
81
do
{
82
// Determine curvature from last step (Secant method)
83
curvature = std::fabs(
eonc::safemath::safe_div
(
84
projectedForceBeforeStep - projectedForce, stepSize, 0.0));
85
stepSize =
eonc::safemath::safe_div
(projectedForce, curvature, a_maxMove);
86
87
if
(a_maxMove < std::fabs(stepSize)) {
88
// first part get the sign of stepSize
89
stepSize = ((stepSize > 0) - (stepSize < 0)) * a_maxMove;
90
}
91
92
forceBeforeStep =
m_force
;
93
projectedForceBeforeStep = projectedForce;
94
95
pos += stepSize *
m_directionNorm
;
96
m_objf
->setPositions(pos);
97
m_force
= -
m_objf
->getGradient();
98
projectedForce =
m_force
.dot(
m_directionNorm
);
99
100
line_i += 1;
101
102
// Line search considered converged based in the ratio between the projected
103
// force and the norm of the true force
104
}
while
(
m_optConfig
.opts.cg.line_converged <
105
std::fabs(projectedForce) /
106
(std::sqrt(
m_force
.dot(
m_force
) +
107
m_optConfig
.opts.cg.line_converged)) &&
108
line_i <
m_optConfig
.opts.cg.line_search_max_iter);
109
if
(
m_objf
->isConverged())
110
return
1;
111
return
0;
112
}
113
114
int
ConjugateGradients::single_step
(
double
a_maxMove) {
115
Eigen::VectorXd pos;
116
Eigen::VectorXd posStep;
117
Eigen::VectorXd forceAfterStep;
118
119
m_force
= -
m_objf
->getGradient();
120
pos =
m_objf
->getPositions();
121
getStep
();
122
123
// move system an infinitesimal step to determine the optimal step size along
124
// the search line
125
posStep = pos +
m_directionNorm
*
m_optConfig
.finiteDifference;
126
m_objf
->setPositions(posStep);
127
forceAfterStep = -
m_objf
->getGradient(
true
);
128
129
// Determine curvature
130
double
projectedForce1 =
m_force
.dot(
m_directionNorm
);
131
double
projectedForce2 = forceAfterStep.dot(
m_directionNorm
);
132
double
curvature =
eonc::safemath::safe_div
(
133
projectedForce1 - projectedForce2,
m_optConfig
.finiteDifference, 0.0);
134
135
double
stepSize = a_maxMove;
136
137
if
(curvature > 0.0) {
138
stepSize =
eonc::safemath::safe_div
(projectedForce1, curvature, a_maxMove);
139
}
140
141
if
(
m_optConfig
.bowlBreakout && a_maxMove < 0.0) {
142
stepSize = -a_maxMove;
143
a_maxMove = -a_maxMove;
144
}
145
146
if
(!
m_optConfig
.opts.cg.no_overshooting) {
147
if
(
m_optConfig
.bowlBreakout) {
148
// max displacement is based on system not single atom
149
pos +=
eonc::helpers::maxMotionAppliedV
(stepSize *
m_directionNorm
,
150
a_maxMove);
151
}
else
{
152
pos +=
eonc::helpers::maxAtomMotionAppliedV
(stepSize *
m_directionNorm
,
153
a_maxMove);
154
}
155
m_objf
->setPositions(pos);
156
}
else
{
157
// negative if product of the projected forces before and after the step are
158
// in opposite directions
159
double
passedMinimum = -1.;
160
double
forceChange = 0.;
161
while
(passedMinimum < 0.0 &&
162
0.1 * std::fabs(projectedForce1) < std::fabs(projectedForce2)) {
163
posStep = pos +
eonc::helpers::maxAtomMotionAppliedV
(
164
stepSize *
m_directionNorm
, a_maxMove);
165
m_objf
->setPositions(posStep);
166
forceAfterStep = -
m_objf
->getGradient(
true
);
167
projectedForce2 = forceAfterStep.dot(
m_directionNorm
);
168
169
passedMinimum = projectedForce1 * projectedForce2;
170
if
(passedMinimum < 0.0 &&
171
0.1 * std::fabs(projectedForce1) < std::fabs(projectedForce2)) {
172
forceChange = (projectedForce1 - projectedForce2);
173
stepSize =
eonc::safemath::safe_div
(projectedForce1, forceChange, 0.0) *
174
stepSize;
175
QUILL_LOG_DEBUG(
m_log
,
"Force changed {}, step size adjusted to {}"
,
176
forceChange, stepSize);
177
}
178
}
179
}
180
if
(
m_optConfig
.opts.cg.knock_out_max_move) {
181
if
(stepSize >= a_maxMove) {
182
// knockout old search direction
183
m_directionOld
.setZero();
184
m_forceOld
.setZero();
185
QUILL_LOG_DEBUG(
m_log
,
"Resetting the old search direction"
);
186
}
187
}
188
189
return
m_objf
->isConverged() ? 1 : 0;
190
}
191
192
int
ConjugateGradients::run
(
size_t
a_maxIterations,
double
a_maxMove) {
193
size_t
iterations = 0;
194
while
(!
m_objf
->isConverged() && iterations <= a_maxIterations) {
195
step
(a_maxMove);
196
iterations++;
197
}
198
return
m_objf
->isConverged() ? 1 : 0;
199
}
ConjugateGradients.h
Direct optimization for energy minimization.
SafeMath.h
ConjugateGradients::getStep
Eigen::VectorXd getStep()
Gets the direction of the next step.
Definition
ConjugateGradients.cpp:17
eonc::ConjugateGradients::line_search
int line_search(double a_maxMove)
Steps the conjugate gradient.
Definition
ConjugateGradients.cpp:57
eonc::ConjugateGradients::m_force
Eigen::VectorXd m_force
Current force vector.
Definition
ConjugateGradients.h:78
eonc::ConjugateGradients::m_directionNorm
Eigen::VectorXd m_directionNorm
Normalised version of the current direction vector.
Definition
ConjugateGradients.h:76
eonc::ConjugateGradients::m_directionOld
Eigen::VectorXd m_directionOld
Algorithms previous step direction.
Definition
ConjugateGradients.h:74
eonc::ConjugateGradients::m_cg_i
size_t m_cg_i
Counts the number of discrete steps until algorithm convergence.
Definition
ConjugateGradients.h:84
eonc::ConjugateGradients::single_step
int single_step(double a_maxMove)
Steps the conjugate gradient.
Definition
ConjugateGradients.cpp:114
eonc::ConjugateGradients::run
int run(size_t a_maxIterations, double a_maxMove) override
Runs the conjugate gradient.
Definition
ConjugateGradients.cpp:192
eonc::ConjugateGradients::getStep
Eigen::VectorXd getStep()
Gets the direction of the next step.
Definition
ConjugateGradients.cpp:17
eonc::ConjugateGradients::m_direction
Eigen::VectorXd m_direction
Current step direction of the conjugate gradient.
Definition
ConjugateGradients.h:72
eonc::ConjugateGradients::step
int step(double a_maxMove) override
Calls the next step in the algorithm.
Definition
ConjugateGradients.cpp:45
eonc::ConjugateGradients::m_forceOld
Eigen::VectorXd m_forceOld
Previous force vector.
Definition
ConjugateGradients.h:80
eonc::ConjugateGradients::m_log
eonc::log::FileScoped m_log
Definition
ConjugateGradients.h:81
eonc::Optimizer::m_optConfig
const OptimizerConfig m_optConfig
Definition
Optimizer.h:67
eonc::Optimizer::m_objf
std::shared_ptr< ObjectiveFunction > m_objf
Definition
Optimizer.h:68
eonc::helpers::maxMotionAppliedV
VectorXd maxMotionAppliedV(const VectorXd v1, double maxMotion)
Definition
GeometryAnalysis.cpp:341
eonc::helpers::maxAtomMotionAppliedV
VectorXd maxAtomMotionAppliedV(const VectorXd v1, double maxMotion)
Definition
GeometryAnalysis.cpp:319
eonc::safemath::safe_div
constexpr double safe_div(double num, double denom, double fallback=0.0)
Definition
SafeMath.h:21
client
ConjugateGradients.cpp
Generated by
1.17.0
Generated by
Doxygen 1.17.0
Analytics by
Antics
provided by
TurtleTech ehf