Loading...
Searching...
No Matches
BiasedGradientSquaredDescent.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*/
14#include "eon/HelperFunctions.h"
15#include "eon/Matter.h"
17#include "eon/Optimizer.h"
19#include "eon/SafeMath.h"
20
21#include <cmath>
22
23namespace eonc {
24
27
28public:
29 BGSDObjectiveFunction(Matter &matterRef, double reactantEnergyPassed,
30 double bgsdAlphaPassed,
31 const Parameters &parametersPassed)
32 : ObjectiveFunction(parametersPassed),
33 matter{matterRef} {
34 bgsdAlpha = bgsdAlphaPassed;
35 reactantEnergy = reactantEnergyPassed;
36 }
37
39
40 double getEnergy() {
41 VectorXd Vforce = matter.getForcesFreeV();
42 double Henergy = 0.5 * Vforce.dot(Vforce) +
43 0.5 * bgsdAlpha *
44 (matter.getPotentialEnergy() -
45 (reactantEnergy + params.bgsd_options().beta)) *
46 (matter.getPotentialEnergy() -
47 (reactantEnergy + params.bgsd_options().beta));
48 return Henergy;
49 }
50
51 VectorXd getGradient(bool /*fdstep*/ = false) {
52 VectorXd Vforce = matter.getForcesFreeV();
53 const double magVforce = Vforce.norm();
54 const double fd = params.bgsd_options().gradient_finite_difference;
55 if (!(magVforce > 0.0) || !std::isfinite(magVforce) || !(fd > 0.0)) {
56 return VectorXd::Zero(Vforce.size());
57 }
58 const VectorXd normVforce = Vforce / magVforce;
59 const VectorXd Vpositions = matter.getPositionsFreeV();
60 matter.setPositionsFreeV(Vpositions - normVforce * fd);
61 VectorXd Vforcenew = matter.getForcesFreeV();
62 matter.setPositionsFreeV(Vpositions);
63 VectorXd Hforce = magVforce * (Vforcenew - Vforce) / fd +
64 bgsdAlpha *
65 (matter.getPotentialEnergy() -
66 (reactantEnergy + params.bgsd_options().beta)) *
67 Vforce;
68 return -Hforce;
69 }
70
71 double getGradientnorm() {
72 VectorXd Hforce = getGradient();
73 double Hnorm = Hforce.norm();
74 return Hnorm;
75 }
76
77 void setPositions(const VectorXd &x) { matter.setPositionsFreeV(x); }
78 VectorXd getPositions() { return matter.getPositionsFreeV(); }
79 int degreesOfFreedom() { return 3 * matter.numberOfFreeAtoms(); }
80 bool isConverged() { return isConvergedH() && isConvergedV(); }
81 bool isConvergedH() {
82 return getConvergenceH() < params.bgsd_options().h_force_convergence;
83 }
84 bool isConvergedV() {
85 return getConvergenceV() < params.bgsd_options().grad2energy_convergence;
86 }
88 return getConvergenceH() < params.bgsd_options().grad2force_convergence;
89 }
90
91 double getConvergence() { return getGradient().norm(); }
92 double getConvergenceH() { return getGradient().norm(); }
93 double getConvergenceV() { return getEnergy(); }
94 VectorXd difference(const VectorXd &a, const VectorXd &b) {
95 return matter.pbcV(a - b);
96 }
97
98private:
100 double bgsdAlpha;
101};
102
104 auto objf = std::make_shared<BGSDObjectiveFunction>(
105 *saddle, reactantEnergy, params.bgsd_options().alpha, params);
107 objf, params.optimizer_options().method, params);
108 int iteration = 0;
109 const int max_iter = params.optimizer_options().max_iterations;
110 QUILL_LOG_DEBUG(
111 log,
112 "starting optimization of H with params alpha and beta: {:.2f} {:.2f}",
113 params.bgsd_options().alpha, params.bgsd_options().beta);
114 while (iteration < max_iter && (!objf->isConvergedH() || iteration == 0)) {
115 if (!std::isfinite(objf->getEnergy())) {
116 break;
117 }
118 optim->step(params.optimizer_options().max_move);
119 QUILL_LOG_DEBUG(log,
120 "iteration {} Henergy, gradientHnorm, and Venergy: "
121 "{:.8f} {:.8f} {:.8f}",
122 iteration, objf->getEnergy(), objf->getGradientnorm(),
123 saddle->getPotentialEnergy());
124 iteration++;
125 }
126 auto objf2 = std::make_shared<BGSDObjectiveFunction>(*saddle, reactantEnergy,
127 0.0, params);
128 auto optim2 = eonc::helpers::create::mkOptim(
129 objf2, params.optimizer_options().method, params);
130 int iter2 = 0;
131 while (iter2 < max_iter && (!objf2->isConvergedV() || iter2 == 0)) {
132 if (objf2->isConvergedIP() || !std::isfinite(objf2->getEnergy())) {
133 break;
134 }
135 optim2->step(params.optimizer_options().max_move);
136 QUILL_LOG_DEBUG(log,
137 "gradient squared iteration {} Henergy, gradientHnorm, "
138 "and Venergy: {:.8f} {:.8f} {:.8f}",
139 iteration, objf2->getEnergy(), objf2->getGradientnorm(),
140 saddle->getPotentialEnergy());
141 ++iteration;
142 ++iter2;
143 }
144
145 auto minModeMethod = eonc::buildEigenmodeStrategy(saddle, params, pot);
146
147 eigenvector.setRandom();
148 for (int i = 0; i < saddle->numberOfAtoms(); i++) {
149 for (int j = 0; j < 3; j++) {
150 if (saddle->getFixed(i)) {
151 eigenvector(i, j) = 0.0;
152 };
153 }
154 }
155 eonc::safemath::safe_normalize_inplace(eigenvector);
156 eonc::eigenmodeCompute(*minModeMethod, saddle, eigenvector);
159 QUILL_LOG_DEBUG(log, "lowest eigenvalue {:.8f}", eigenvalue);
160 status = objf2->isConvergedV() ? 0 : 1;
161 return status;
162}
163
165
169
170} // namespace eonc
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
The optimizer class is used to serve as an abstract class for all optimizers, as well as to call an o...
BGSDObjectiveFunction(Matter &matterRef, double reactantEnergyPassed, double bgsdAlphaPassed, const Parameters &parametersPassed)
VectorXd difference(const VectorXd &a, const VectorXd &b)
ObjectiveFunction(const Parameters &paramsPassed)
const Parameters & params
std::shared_ptr< Potential > pot
std::unique_ptr< Optimizer > mkOptim(std::shared_ptr< ObjectiveFunction > a_objf, OptType a_otype, const Parameters &a_params)
Definition Optimizer.cpp:24
RAII resource manager for the ARTn C library with global synchronization.
void eigenmodeCompute(LowestEigenmode &s, std::shared_ptr< Matter > matter, AtomMatrix direction)
std::shared_ptr< LowestEigenmode > buildEigenmodeStrategy(std::shared_ptr< Matter > matter, const Parameters &params, std::shared_ptr< Potential > pot)
double eigenmodeGetEigenvalue(LowestEigenmode &s)
AtomMatrix eigenmodeGetEigenvector(LowestEigenmode &s)