Loading...
Searching...
No Matches
eonc::Lanczos Class Reference

#include <Lanczos.h>

Inheritance diagram for eonc::Lanczos:

Public Member Functions

 Lanczos (std::shared_ptr< Matter > matter, const Parameters &params, std::shared_ptr< Potential > pot)
 ~Lanczos ()=default
void compute (std::shared_ptr< Matter > matter, AtomMatrix initialDirection) override
void compute (std::shared_ptr< Matter > matter, AtomMatrix initialDirection, const VectorXi &mobileAtoms)
 Same as compute(matter, dir) but with an explicit mobile atom list (intersected with free flags).
double getEigenvalue () override
AtomMatrix getEigenvector () override
Public Member Functions inherited from eonc::LowestEigenmode
 LowestEigenmode (std::shared_ptr< Potential > potPassed, const Parameters &parameters)
virtual ~LowestEigenmode ()=default

Private Attributes

AtomMatrix lowestEv
double lowestEw {0.0}
eonc::log::Scoped log

Additional Inherited Members

Public Attributes inherited from eonc::LowestEigenmode
long totalForceCalls {0}
double statsTorque {0.0}
double statsCurvature {0.0}
double statsAngle {0.0}
long statsRotations {0}
long totalIterations {0}
Static Public Attributes inherited from eonc::LowestEigenmode
static const char MINMODE_DIMER [] = "dimer"
static const char MINMODE_GPRDIMER [] = "gprdimer"
static const char MINMODE_LANCZOS [] = "lanczos"
static const char MINMODE_DAVIDSON [] = "davidson"
Protected Attributes inherited from eonc::LowestEigenmode
std::shared_ptr< Potential > pot
const Parameters & params

Detailed Description

Definition at line 26 of file Lanczos.h.

Constructor & Destructor Documentation

◆ Lanczos()

eonc::Lanczos::Lanczos ( std::shared_ptr< Matter > matter,
const Parameters & params,
std::shared_ptr< Potential > pot )

Definition at line 36 of file Lanczos.cpp.

39 lowestEw{0.0} {
40 lowestEv.resize(matter->numberOfAtoms(), 3);
41 lowestEv.setZero();
42}
AtomMatrix lowestEv
Definition Lanczos.h:42
double lowestEw
Definition Lanczos.h:43
const Parameters & params
std::shared_ptr< Potential > pot
LowestEigenmode(std::shared_ptr< Potential > potPassed, const Parameters &parameters)

◆ ~Lanczos()

eonc::Lanczos::~Lanczos ( )
default

Member Function Documentation

◆ compute() [1/2]

void eonc::Lanczos::compute ( std::shared_ptr< Matter > matter,
AtomMatrix initialDirection )
overridevirtual

Implements eonc::LowestEigenmode.

Definition at line 44 of file Lanczos.cpp.

44 {
45 const VectorXi mobile =
46 resolveMobileAtoms(matter.get(), params.lanczos_options().phva_atoms);
47 compute(std::move(matter), std::move(direction), mobile);
48}
void compute(std::shared_ptr< Matter > matter, AtomMatrix initialDirection) override
Definition Lanczos.cpp:44
VectorXi resolveMobileAtoms(const Matter *matter, const std::string &atomList)
PHVA-class mobile set for FD Hessian and matrix-free Krylov (Lanczos / Davidson).

◆ compute() [2/2]

void eonc::Lanczos::compute ( std::shared_ptr< Matter > matter,
AtomMatrix initialDirection,
const VectorXi & mobileAtoms )

Same as compute(matter, dir) but with an explicit mobile atom list (intersected with free flags).

Eigenvector rows outside the list are 0.

Definition at line 50 of file Lanczos.cpp.

51 {
54 lowestEv.resize(matter->numberOfAtoms(), 3);
55 lowestEv.setZero();
56
57 const VectorXi mobile = resolveMobileAtoms(matter.get(), mobileIn);
58 const int size = 3 * static_cast<int>(mobile.size());
59 if (size == 0) {
60 lowestEw = 0.0;
61 return;
62 }
63
64 const long maxIters = std::max(1L, params.lanczos_options().max_iterations);
65 MatrixXd T(size, maxIters), Q(size, maxIters);
66 T.setZero();
67 VectorXd u(size), r = packMobileRows(direction, mobile);
68
69 double alpha, beta = r.norm();
70 if (beta < eonc::safemath::eps) {
71 lowestEw = 0.0;
72 return;
73 }
74 double ew = 0, ewOld = 0, ewAbsRelErr;
75 const double dr = params.main_options().finiteDifference;
76 const FdScheme requested = parseFdScheme(params.hessian_options().fd_scheme);
77 // Fourth-order is the only scheme that changes the matrix-free product.
78 // one_sided and central keep the forward difference used by min-mode.
79 const FdScheme hvpScheme =
81 VectorXd evEst, evT, evOldEst;
82
83 auto tmpMatter = std::make_unique<Matter>(*matter);
84 const long forceCallsStart = tmpMatter->getForceCalls();
85 const AtomMatrix pos0 = matter->getPositions();
86 const VectorXd force0 = mobileForces(tmpMatter.get(), mobile);
87
88 auto applyH = [&](const VectorXd &v) -> VectorXd {
89 auto at = [&](double scale) -> VectorXd {
90 AtomMatrix pos = pos0;
91 unpackMobileRows(packMobileRows(pos0, mobile) + (scale * dr) * v, mobile,
92 pos);
93 tmpMatter->setPositions(pos);
94 return mobileForces(tmpMatter.get(), mobile);
95 };
96 return fdHessianVector(hvpScheme, dr, force0, at);
97 };
98
99 for (int i = 0; i < size; i++) {
100 statsRotations = i;
101 Q.col(i) = r / beta;
102
103 u = applyH(Q.col(i));
104
105 if (i == 0) {
106 r = u;
107 } else {
108 r = u - beta * Q.col(i - 1);
109 }
110 alpha = Q.col(i).dot(r);
111 r = r - alpha * Q.col(i);
112
113 T(i, i) = alpha;
114 if (i > 0) {
115 T(i - 1, i) = beta;
116 T(i, i - 1) = beta;
117 }
118
119 beta = r.norm();
120 // A vanished residual closes this Krylov block. Take the Ritz pair from
121 // the current T; breaking first keeps the previous subspace.
122 const bool krylovClosed = beta <= 1e-10 * std::fabs(alpha);
123
124 if (i >= 1) {
125 Eigen::SelfAdjointEigenSolver<MatrixXd> es(T.block(0, 0, i + 1, i + 1));
126 ew = es.eigenvalues()(0);
127 evT = es.eigenvectors().col(0);
128 ewAbsRelErr = eonc::safemath::safe_div(std::fabs(ew - ewOld),
129 std::fabs(ewOld), 1.0);
130 ewOld = ew;
131
132 evEst = Q.block(0, 0, size, i + 1) * evT;
133 eonc::safemath::safe_normalize_inplace(evEst);
134 statsAngle = eonc::safemath::safe_acos(std::fabs(evEst.dot(evOldEst))) *
135 (180 / eonc::helpers::pi);
136 statsTorque = ewAbsRelErr;
137 evOldEst = evEst;
138 QUILL_LOG_INFO(log,
139 "[ILanczos] {:9s} {:9s} {:10s} {:14s} {:9.4f} "
140 "{:10.6f} {:7.3f} {:5} n_mobile={}",
141 "----", "----", "----", "----", ew, ewAbsRelErr,
142 statsAngle, i, mobile.size());
143 if (krylovClosed) {
144 QUILL_LOG_ERROR(log, "[ILanczos] ERROR: linear dependence");
145 break;
146 }
147 if (ewAbsRelErr < params.lanczos_options().tolerance) {
148 QUILL_LOG_INFO(log, "[ILanczos] Tolerance reached: {}",
149 params.lanczos_options().tolerance);
150 break;
151 }
152 } else {
153 ew = alpha;
154 ewOld = ew;
155 evEst = Q.col(0);
156 evOldEst = Q.col(0);
157 if (krylovClosed) {
158 QUILL_LOG_ERROR(log, "[ILanczos] ERROR: linear dependence");
159 break;
160 }
161 if (lowestEw != 0.0 && params.lanczos_options().quit_early) {
162 double Cprev = lowestEw;
163 double Cnew = u.dot(Q.col(i));
164 ewAbsRelErr = eonc::safemath::safe_div(std::fabs(Cnew - Cprev),
165 std::fabs(Cprev), 1.0);
166 if (ewAbsRelErr <= params.lanczos_options().tolerance) {
167 statsAngle = 0.0;
168 statsTorque = ewAbsRelErr;
169 QUILL_LOG_INFO(log, "[ILanczos] Tolerance reached: {}",
170 params.lanczos_options().tolerance);
171 break;
172 }
173 }
174 }
175
176 if (i >= params.lanczos_options().max_iterations - 1) {
177 QUILL_LOG_ERROR(log, "[ILanczos] Max iterations");
178 break;
179 }
180 }
181
182 lowestEw = ew;
183 totalForceCalls = tmpMatter->getForceCalls() - forceCallsStart;
184
185 lowestEv.setZero();
186 if (evEst.size() == size) {
187 unpackMobileRows(evEst, mobile, lowestEv);
188 }
189}
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, eOnStorageOrder > MatrixXd
Definition Eigen.h:33
Eigen::Matrix< double, Eigen::Dynamic, 3, eOnStorageOrder > AtomMatrix
Definition Eigen.h:37
eonc::log::Scoped log
Definition Lanczos.h:44
constexpr double pi
constexpr double safe_div(double num, double denom, double fallback=0.0)
Definition SafeMath.h:21
double safe_acos(double x)
Definition SafeMath.h:34
constexpr double eps
Definition SafeMath.h:19
FdScheme
Real finite-difference scheme for the assembled Hessian and for Lanczos/Davidson Hessian-vector produ...
VectorXd fdHessianVector(FdScheme scheme, double dr, const VectorXd &force0, Eval &&eval)
Energy Hessian-vector product -dF.
void unpackMobileRows(const VectorXd &packed, const VectorXi &mobile, AtomMatrix &full)
Write a 3*n_mobile vector into full AtomMatrix rows (other rows unchanged).
FdScheme parseFdScheme(std::string_view scheme)
VectorXd packMobileRows(const AtomMatrix &full, const VectorXi &mobile)
Pack full (n_atoms,3) rows of mobile atoms into a 3*n_mobile vector.
VectorXd mobileForces(Matter *matter, const VectorXi &mobile)
Force components on mobile atoms after Matter has a valid force cache (calls getForces under the hood...

◆ getEigenvalue()

double eonc::Lanczos::getEigenvalue ( )
overridevirtual

Implements eonc::LowestEigenmode.

Definition at line 191 of file Lanczos.cpp.

191{ return lowestEw; }

◆ getEigenvector()

AtomMatrix eonc::Lanczos::getEigenvector ( )
overridevirtual

Implements eonc::LowestEigenmode.

Definition at line 193 of file Lanczos.cpp.

193{ return lowestEv; }

Member Data Documentation

◆ log

eonc::log::Scoped eonc::Lanczos::log
private

Definition at line 44 of file Lanczos.h.

◆ lowestEv

AtomMatrix eonc::Lanczos::lowestEv
private

Definition at line 42 of file Lanczos.h.

◆ lowestEw

double eonc::Lanczos::lowestEw {0.0}
private

Definition at line 43 of file Lanczos.h.

43{0.0};

The documentation for this class was generated from the following files: