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