43 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(
S.Matrix());
44 const Eigen::VectorXd& s_eig = es.eigenvalues();
45 Eigen::VectorXd inv_sqrt = Eigen::VectorXd::Zero(s_eig.size());
47 for (
Index i = 0; i < s_eig.size(); ++i) {
48 if (s_eig(i) < etol) {
51 inv_sqrt(i) = 1.0 / std::sqrt(s_eig(i));
55 es.eigenvectors() * inv_sqrt.asDiagonal() * es.eigenvectors().transpose();
62 const Eigen::MatrixXd U = es.eigenvectors().leftCols(removed);
66 <<
TimeStamp() <<
" Smallest value of AOOverlap matrix is " << s_eig(0)
70 <<
" basisfunction from inverse overlap matrix (threshold " << etol <<
")"
75 <<
" removed direction(s) appear as zero orbitals at +" <<
kRemovedShift
76 <<
" Hartree." << std::flush;
77 }
else if (s_eig(0) < 1e3 * etol) {
80 <<
" WARNING: the overlap matrix is nearly singular; if the SCF is "
81 "unstable, raise xtpdft.overlap_tolerance above "
82 << s_eig(0) <<
"." << std::flush;
101 totE_.push_back(totE);
104 const Eigen::VectorXd MOs_old_energies = MOs.
eigenvalues();
106 const Eigen::MatrixXd&
S =
S_->Matrix();
107 const Eigen::MatrixXd errormatrix =
109 diiserror_ = errormatrix.cwiseAbs().maxCoeff();
130 <<
" Ha); discarding the (A)DIIS history and restarting from that "
137 Eigen::MatrixXd H_restart =
best_H_;
138 if (
opt_.levelshift > 0.0) {
173 diis_.Update(drop, errormatrix);
175 bool diis_error =
false;
176 Eigen::MatrixXd H_guess =
H;
183 const std::size_t min_history = near_convergence ? 1 : 2;
186 Eigen::VectorXd coeffs;
193 diis_error = !
adiis_.Info();
195 <<
TimeStamp() <<
" Using ADIIS for next guess" << std::flush;
197 coeffs =
diis_.CalcCoeff();
198 diis_error = !
diis_.Info();
200 <<
TimeStamp() <<
" Using DIIS for next guess" << std::flush;
204 <<
TimeStamp() <<
" (A)DIIS failed using mixing instead"
208 for (
Index i = 0; i < coeffs.size(); i++) {
209 if (std::abs(coeffs(i)) < 1
e-8) {
233 (
mathist_.size() <= 2 && !near_convergence)) {
236 opt_.mixingparameter * dmat + (1.0 -
opt_.mixingparameter) * dmatout;
238 <<
TimeStamp() <<
" Using Mixing with alpha=" <<
opt_.mixingparameter
247 const std::vector<Eigen::MatrixXd>& errors =
diis_.ErrorHistory();
252 const Eigen::MatrixXd&
S =
S_->Matrix();
253 for (std::size_t k = 0; k <
mathist_.size(); ++k) {
254 const Eigen::MatrixXd
e =
258 if ((
e - errors[k]).cwiseAbs().maxCoeff() > 1
e-12 ||
259 std::abs(
e.cwiseAbs().maxCoeff() -
errhist_[k]) > 1
e-12) {
268 <<
TimeStamp() <<
" Convergence Options:" << std::flush;
270 <<
"\t\t Delta E [Ha]: " <<
opt_.Econverged << std::flush;
272 <<
"\t\t DIIS max error: " <<
opt_.error_converged << std::flush;
275 <<
"\t\t DIIS histlength: " <<
opt_.histlength << std::flush;
277 <<
"\t\t ADIIS start: " <<
opt_.adiis_start << std::flush;
279 <<
"\t\t DIIS start: " <<
opt_.diis_start << std::flush;
280 std::string del =
"oldest";
285 <<
"\t\t Deleting " << del <<
" element from DIIS hist" << std::flush;
288 <<
"\t\t Levelshift[Ha]: " <<
opt_.levelshift << std::flush;
290 <<
"\t\t Levelshift end: " <<
opt_.levelshiftend << std::flush;
292 <<
"\t\t Mixing Parameter alpha: " <<
opt_.mixingparameter << std::flush;
294 <<
"\t\t Mixing end: " <<
opt_.mixingend << std::flush;
296 <<
"\t\t Energy reset [Ha]: " <<
opt_.energy_reset
297 << (
opt_.energy_reset > 0.0 ?
"" :
" (off)") << std::flush;
307 const Eigen::MatrixXd&
H)
const {
313 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(H_ortho);
315 if (es.info() != Eigen::ComputationInfo::Success) {
316 throw std::runtime_error(
"Matrix Diagonalisation failed. DiagInfo" +
317 std::to_string(es.info()));
335 const Eigen::MatrixXd& MOs_old)
const {
336 if (
opt_.levelshift < 1
e-9) {
339 Eigen::VectorXd virt = Eigen::VectorXd::Zero(
H.rows());
341 virt(i) =
opt_.levelshift;
345 <<
TimeStamp() <<
" Using levelshift:" <<
opt_.levelshift <<
" Hartree"
347 Eigen::MatrixXd vir =
S_->Matrix() * MOs_old * virt.asDiagonal() *
348 MOs_old.transpose() *
S_->Matrix();
374 const Eigen::MatrixXd& MOs)
const {
375 const Eigen::MatrixXd occstates = MOs.leftCols(
nocclevels_);
376 Eigen::MatrixXd dmatGS = 2.0 * occstates * occstates.transpose();
386 const Eigen::MatrixXd& MOs)
const {
388 return Eigen::MatrixXd::Zero(MOs.rows(), MOs.rows());
390 Eigen::MatrixXd occstates = MOs.leftCols(
nocclevels_);
391 Eigen::MatrixXd dmatGS = occstates * occstates.transpose();
409 if (
opt_.numberofelectrons == 0) {
414 Eigen::VectorXd occupation = Eigen::VectorXd::Zero(MOs.
eigenvalues().size());
415 std::vector<std::vector<Index> > degeneracies;
416 double buffer = 1
e-4;
417 degeneracies.push_back(std::vector<Index>{0});
418 for (
Index i = 1; i < occupation.size(); i++) {
420 MOs.
eigenvalues()(degeneracies[degeneracies.size() - 1][0]) + buffer) {
421 degeneracies[degeneracies.size() - 1].push_back(i);
423 degeneracies.push_back(std::vector<Index>{i});
426 Index numofelec =
opt_.numberofelectrons;
427 for (
const std::vector<Index>& deglevel : degeneracies) {
428 Index numofpossibleelectrons = 2 *
Index(deglevel.size());
429 if (numofpossibleelectrons <= numofelec) {
430 for (
Index i : deglevel) {
433 numofelec -= numofpossibleelectrons;
435 double occ = double(numofelec) / double(deglevel.size());
436 for (
Index i : deglevel) {
442 Eigen::MatrixXd dmatGS = MOs.
eigenvectors() * occupation.asDiagonal() *
453 const Eigen::MatrixXd& MOs)
const {
456 std::min(
opt_.number_alpha_electrons,
opt_.number_beta_electrons);
457 const Index n_socc_alpha =
opt_.number_alpha_electrons - n_docc;
460 result.
alpha = Eigen::MatrixXd::Zero(MOs.rows(), MOs.rows());
461 result.
beta = Eigen::MatrixXd::Zero(MOs.rows(), MOs.rows());
464 const Eigen::MatrixXd docc = MOs.leftCols(n_docc);
465 const Eigen::MatrixXd d_docc = docc * docc.transpose();
466 result.
alpha += d_docc;
467 result.
beta += d_docc;
470 if (n_socc_alpha > 0) {
471 const Eigen::MatrixXd socc = MOs.middleCols(n_docc, n_socc_alpha);
472 result.
alpha += socc * socc.transpose();
488 return {0.5 * d, 0.5 * d};
491 return {d, Eigen::MatrixXd::Zero(d.rows(), d.cols())};
494 return {0.5 * d, 0.5 * d};
501 return spin_dmat.
total();
bool HistoryIsAligned() const
Eigen::MatrixXd DensityMatrix(const tools::EigenSystem &MOs) const
Index iterations_since_reset_
static constexpr double kRemovedShift
Eigen::MatrixXd DensityMatrixGroundState_unres(const Eigen::MatrixXd &MOs) const
std::vector< Eigen::MatrixXd > mathist_
Eigen::MatrixXd Iterate(const Eigen::MatrixXd &dmat, Eigen::MatrixXd &H, tools::EigenSystem &MOs, double totE)
double getDIIsError() const
Return the DIIS commutator norm from the latest iteration.
tools::EigenSystem SolveFockmatrix(const Eigen::MatrixXd &H) const
Solve the generalized eigenvalue problem for the current Fock matrix.
Eigen::MatrixXd Sminusahalf
std::vector< double > errhist_
void PrintConfigOptions() const
Print the active convergence-acceleration settings to the logger.
void Levelshift(Eigen::MatrixXd &H, const Eigen::MatrixXd &MOs_old) const
Apply a virtual-space level shift in the molecular-orbital basis.
static constexpr Index kResetCooldown
double getDeltaE() const
Return the total-energy change between the two most recent SCF iterations.
static constexpr Index kMaxEnergyResets
Eigen::MatrixXd DensityMatrixGroundState_frac(const tools::EigenSystem &MOs) const
Construct a fractional-occupation density matrix from orbital occupations.
std::vector< double > totE_
void setOverlap(AOOverlap &S, double etol)
Precompute overlap-dependent quantities used when solving the Fock matrix.
Eigen::MatrixXd removed_projector_
Eigen::MatrixXd DensityMatrixGroundState(const Eigen::MatrixXd &MOs) const
Eigen::MatrixXd best_dmat_
std::vector< Eigen::MatrixXd > dmatHist_
static constexpr double kEnergyRiseForADIIS
SpinDensity DensityMatrixSpinResolved(const tools::EigenSystem &MOs) const
SpinDensity DensityMatrixGroundState_restricted_open(const Eigen::MatrixXd &MOs) const
Timestamp returns the current time as a string Example: cout << TimeStamp().
#define XTP_LOG(level, log)
Charge transport classes.
Provides a means for comparing floating point numbers.
Spin-resolved density matrices returned for open-shell SCF updates.
Eigen::MatrixXd total() const
Return the total density P = P^alpha + P^beta.