94 const Eigen::VectorXd& b,
Index max_iter,
double tol,
Logger& log,
95 std::chrono::steady_clock::time_point t_start) {
96 auto elapsed_s = [&]() {
97 return std::chrono::duration<double>(std::chrono::steady_clock::now() -
103 Eigen::VectorXd x = Eigen::VectorXd::Zero(b.size());
104 Eigen::VectorXd residual_vec = b - op * x;
105 const double rhs_norm2 = b.squaredNorm();
106 const double threshold =
107 std::max(tol * tol * rhs_norm2, std::numeric_limits<double>::min());
108 double residual_norm2 = residual_vec.squaredNorm();
116 (rhs_norm2 > 0.0) ? std::sqrt(residual_norm2 / rhs_norm2) : 0.0;
117 bool converged = (residual_norm2 < threshold);
119 std::vector<double> alphas;
120 std::vector<double> betas;
123 Eigen::VectorXd p = precond.solve(residual_vec);
124 Eigen::VectorXd z(b.size()), tmp(b.size());
125 double abs_new = residual_vec.dot(p);
127 while (i < max_iter) {
128 tmp.noalias() = op * p;
129 const double curvature = p.dot(tmp);
131 <<
": curvature p.A.p=" << curvature <<
" ("
132 << elapsed_s() <<
"s)" << std::flush;
133 if (curvature <= 0.0) {
137 <<
TimeStamp() <<
" PCG iter " << (i + 1)
138 <<
": p.A.p = " << curvature
139 <<
" <= 0 -- the operator is NOT positive-definite. Stopping "
144 const double alpha = abs_new / curvature;
145 alphas.push_back(alpha);
147 residual_vec -= alpha * tmp;
149 residual_norm2 = residual_vec.squaredNorm();
150 tol_error = std::sqrt(residual_norm2 / rhs_norm2);
151 if (residual_norm2 < threshold) {
157 z = precond.solve(residual_vec);
158 const double abs_old = abs_new;
159 abs_new = residual_vec.dot(z);
160 const double beta = abs_new / abs_old;
161 betas.push_back(beta);
174 if (alphas.size() >= 2) {
175 const std::size_t m = alphas.size();
176 Eigen::MatrixXd T = Eigen::MatrixXd::Zero(m, m);
177 T(0, 0) = 1.0 / alphas[0];
178 for (std::size_t i = 1; i < m; ++i) {
179 T(i, i) = 1.0 / alphas[i] + betas[i - 1] / alphas[i - 1];
180 const double off = std::sqrt(betas[i - 1]) / alphas[i - 1];
184 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(T);
289 const Eigen::VectorXd& b,
Index max_iter,
290 double omega,
Logger& log,
291 std::chrono::steady_clock::time_point t_start,
292 bool match_legacy_first_step) {
293 auto elapsed_s = [&]() {
294 return std::chrono::duration<double>(std::chrono::steady_clock::now() -
299 const double kEpsTol = 1
e-3;
302 Eigen::VectorXd x = Eigen::VectorXd::Zero(b.size());
303 const double rhs_norm = b.norm();
304 const Index n_sites = b.size() / 3;
307 for (; i < max_iter; ++i) {
308 Eigen::VectorXd residual_vec = b - op * x;
309 const double residual_norm = residual_vec.norm();
310 const Eigen::VectorXd x_old = x;
311 const double this_step_omega =
312 (i == 0 && match_legacy_first_step) ? 1.0 : omega;
313 x = x_old + this_step_omega * site_p.
Apply(residual_vec);
315 double max_dU = -1.0;
317 for (
Index n = 0; n < n_sites; ++n) {
319 x.segment<3>(3 * n));
325 avg_dU /= double(n_sites);
328 <<
TimeStamp() <<
" JOR iter " << (i + 1) <<
": max_dU=" << max_dU
329 <<
" avg_dU=" << avg_dU <<
" (residual=" << residual_norm / rhs_norm
330 <<
", informational only) (" << elapsed_s() <<
"s)" << std::flush;
332 result.
residual = residual_norm / rhs_norm;
336 bool converged = (max_dU <= kEpsTol);
337 if (avg_dU < kEpsTol * 0.1) {
JorResult SolveWithJOR(const EwaldPeriodicDipoleOperator &op, const EwaldSitePolarizabilityBlocks &site_p, const Eigen::VectorXd &b, Index max_iter, double omega, Logger &log, std::chrono::steady_clock::time_point t_start, bool match_legacy_first_step)
PcgIndefinitenessResult SolveWithIndefinitenessCheck(const EwaldPeriodicDipoleOperator &op, Preconditioner &precond, const Eigen::VectorXd &b, Index max_iter, double tol, Logger &log, std::chrono::steady_clock::time_point t_start)