51 const VectorXi &mobileIn) {
54 lowestEv.resize(matter->numberOfAtoms(), 3);
58 const int size = 3 *
static_cast<int>(mobile.size());
64 const long maxIter = std::max(1L,
params.davidson_options().max_iterations);
65 const double tol =
params.davidson_options().tolerance;
66 const double dr =
params.main_options().finiteDifference;
72 const bool useDiagPrec =
params.davidson_options().diagonal_preconditioner;
80 double beta = r.norm();
87 auto tmpMatter = std::make_unique<Matter>(*matter);
88 const long forceCallsStart = tmpMatter->getForceCalls();
89 const AtomMatrix pos0 = matter->getPositions();
90 const VectorXd force0 =
mobileForces(tmpMatter.get(), mobile);
92 auto applyH = [&](
const VectorXd &v) -> VectorXd {
93 auto at = [&](
double scale) -> VectorXd {
97 tmpMatter->setPositions(pos);
103 VectorXd diagH = VectorXd::Ones(size);
106 HV.col(0) = applyH(V.col(0));
108 for (
int k = 0; k < size; ++k) {
109 const double vk = V(k, 0);
110 if (std::fabs(vk) > 1e-8) {
111 diagH(k) = std::max(std::fabs(HV(k, 0) / vk), 1e-3);
116 double ew = 0.0, ewOld = 0.0;
117 VectorXd evEst = V.col(0);
118 VectorXd evOldEst = evEst;
121 for (
int iter = 0; iter < maxIter; ++iter) {
125 MatrixXd G = V.leftCols(subspace).transpose() * HV.leftCols(subspace);
126 G = 0.5 * (G + G.transpose());
128 Eigen::SelfAdjointEigenSolver<MatrixXd> es(G);
129 ew = es.eigenvalues()(0);
130 VectorXd y = es.eigenvectors().col(0);
131 evEst = V.leftCols(subspace) * y;
132 eonc::safemath::safe_normalize_inplace(evEst);
134 VectorXd Hx = HV.leftCols(subspace) * y;
135 VectorXd resid = Hx - ew * evEst;
136 const double residNorm = resid.norm();
137 const double ewAbsRelErr =
140 std::fabs(ewOld), 1.0);
142 statsTorque = std::max(ewAbsRelErr, residNorm / (std::fabs(ew) + 1e-12));
148 "[Davidson] ew={:10.6f} rel_err={:10.6f} |r|={:10.6f} "
149 "angle={:7.3f} dim={:3d} iter={:3d} n_mobile={}",
150 ew, ewAbsRelErr, residNorm,
statsAngle, subspace, iter,
153 if (ewAbsRelErr < tol && residNorm < tol * (std::fabs(ew) + 1.0)) {
154 QUILL_LOG_INFO(
log,
"[Davidson] Tolerance reached: {}", tol);
157 if (subspace >= maxIter) {
158 QUILL_LOG_ERROR(
log,
"[Davidson] Max subspace dimension");
164 for (
int k = 0; k < size; ++k) {
165 const double denom = diagH(k) - ew;
166 t(k) = resid(k) / (std::fabs(denom) > 1e-12 ? denom : 1e-12);
172 for (
int c = 0; c < subspace; ++c) {
173 t -= V.col(c).dot(t) * V.col(c);
175 const double tnorm = t.norm();
177 QUILL_LOG_ERROR(
log,
"[Davidson] Linear dependence in residual");
183 HV.col(subspace) = applyH(t);
185 for (
int k = 0; k < size; ++k) {
186 const double vk = t(k);
187 if (std::fabs(vk) > 1e-8) {
188 const double d = std::fabs(HV(k, subspace) / vk);
189 diagH(k) = std::max(diagH(k), std::max(d, 1e-3));
195 if (iter >= maxIter - 1) {
196 QUILL_LOG_ERROR(
log,
"[Davidson] Max iterations");
204 if (evEst.size() == size) {