votca 2026-dev
Loading...
Searching...
No Matches
uks_convergenceacc.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2026 The VOTCA Development Team
3 * (http://www.votca.org)
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License")
6 *
7 * You may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20// Local VOTCA includes
22
23namespace votca {
24namespace xtp {
25
27 const options& opt_beta) {
28 opt_alpha_ = opt_alpha;
29 opt_beta_ = opt_beta;
30
31 nocclevels_alpha_ = opt_alpha_.numberofelectrons;
32 nocclevels_beta_ = opt_beta_.numberofelectrons;
33
34 // one shared DIIS/ADIIS history length
35 diis_.setHistLength(opt_alpha_.histlength);
36 // adiis_.setHistLength(opt_alpha_.histlength);
37}
38
40
42 S_ = &S;
43 Sminusahalf = S.Pseudo_InvSqrt(etol);
45 << TimeStamp() << " Smallest value of AOOverlap matrix is "
46 << S_->SmallestEigenValue() << std::flush;
48 << TimeStamp() << " Removed " << S_->Removedfunctions()
49 << " basisfunction from inverse overlap matrix" << std::flush;
50}
51
53 const Eigen::MatrixXd& H) const {
54 Eigen::MatrixXd H_ortho = Sminusahalf.transpose() * H * Sminusahalf;
55 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(H_ortho);
56
57 if (es.info() != Eigen::ComputationInfo::Success) {
58 throw std::runtime_error("Matrix Diagonalisation failed. DiagInfo" +
59 std::to_string(es.info()));
60 }
61
62 tools::EigenSystem result;
63 result.eigenvalues() = es.eigenvalues();
64 result.eigenvectors() = Sminusahalf * es.eigenvectors();
65 return result;
66}
67
69 const Eigen::MatrixXd& MOs, Index nocclevels) const {
70 if (nocclevels == 0) {
71 return Eigen::MatrixXd::Zero(MOs.rows(), MOs.rows());
72 }
73 Eigen::MatrixXd occstates = MOs.leftCols(nocclevels);
74 return occstates * occstates.transpose();
75}
76
87
88void UKSConvergenceAcc::Levelshift(Eigen::MatrixXd& H,
89 const Eigen::MatrixXd& MOs_old,
90 const options& opt, Index nocclevels) const {
91 if (opt.levelshift < 1e-9) {
92 return;
93 }
94 Eigen::VectorXd virt = Eigen::VectorXd::Zero(H.rows());
95 for (Index i = nocclevels; i < H.rows(); ++i) {
96 virt(i) = opt.levelshift;
97 }
98
100 << TimeStamp() << " Using levelshift:" << opt.levelshift << " Hartree"
101 << std::flush;
102
103 Eigen::MatrixXd vir = S_->Matrix() * MOs_old * virt.asDiagonal() *
104 MOs_old.transpose() * S_->Matrix();
105 H += vir;
106}
107
109 const Eigen::MatrixXd& dmat, const Eigen::MatrixXd& H) const {
110 const Eigen::MatrixXd& S = S_->Matrix();
111 return Sminusahalf.transpose() * (H * dmat * S - S * dmat * H) * Sminusahalf;
112}
113
114double UKSConvergenceAcc::CombinedError(const Eigen::MatrixXd& err_alpha,
115 const Eigen::MatrixXd& err_beta) const {
116 return std::max(err_alpha.cwiseAbs().maxCoeff(),
117 err_beta.cwiseAbs().maxCoeff());
118}
119
121 const SpinDensity& dmat, SpinFock& H, tools::EigenSystem& MOs_alpha,
122 tools::EigenSystem& MOs_beta, double totE) {
123
124 if (int(mathist_alpha_.size()) == opt_alpha_.histlength) {
125 totE_.erase(totE_.begin() + maxerrorindex_);
130 }
131
132 totE_.push_back(totE);
133
134 if (nocclevels_alpha_ > 0 &&
135 nocclevels_alpha_ < MOs_alpha.eigenvalues().size()) {
136 double gap_alpha = MOs_alpha.eigenvalues()(nocclevels_alpha_) -
137 MOs_alpha.eigenvalues()(nocclevels_alpha_ - 1);
138 if ((diiserror_ > opt_alpha_.levelshiftend &&
139 opt_alpha_.levelshift > 0.0) ||
140 gap_alpha < 1e-6) {
141 Levelshift(H.alpha, MOs_alpha.eigenvectors(), opt_alpha_,
143 }
144 }
145
146 if (nocclevels_beta_ > 0 &&
147 nocclevels_beta_ < MOs_beta.eigenvalues().size()) {
148 double gap_beta = MOs_beta.eigenvalues()(nocclevels_beta_) -
149 MOs_beta.eigenvalues()(nocclevels_beta_ - 1);
150 if ((diiserror_ > opt_beta_.levelshiftend && opt_beta_.levelshift > 0.0) ||
151 gap_beta < 1e-6) {
153 }
154 }
155
156 Eigen::MatrixXd err_alpha = BuildErrorMatrix(dmat.alpha, H.alpha);
157 Eigen::MatrixXd err_beta = BuildErrorMatrix(dmat.beta, H.beta);
158
159 diiserror_ = CombinedError(err_alpha, err_beta);
160
161 mathist_alpha_.push_back(H.alpha);
162 mathist_beta_.push_back(H.beta);
163 dmatHist_alpha_.push_back(dmat.alpha);
164 dmatHist_beta_.push_back(dmat.beta);
165
166 if (opt_alpha_.maxout) {
167 if (diiserror_ > maxerror_) {
169 maxerrorindex_ = mathist_alpha_.size() - 1;
170 }
171 } else {
172 maxerrorindex_ = 0;
173 }
174
175 // crucial: one shared error matrix = alpha + beta contribution
176 diis_.Update(maxerrorindex_, err_alpha, err_beta);
177
178 bool diis_error = false;
180 << TimeStamp() << " DIIs error " << diiserror_ << std::flush;
182 << TimeStamp() << " Delta Etot " << getDeltaE() << std::flush;
183
184 Eigen::MatrixXd H_guess_alpha = H.alpha;
185 Eigen::MatrixXd H_guess_beta = H.beta;
186
187 if ((diiserror_ < opt_alpha_.adiis_start ||
188 diiserror_ < opt_alpha_.diis_start) &&
189 opt_alpha_.usediis && mathist_alpha_.size() > 2) {
190
191 Eigen::VectorXd coeffs;
192
193 if (diiserror_ > opt_alpha_.diis_start ||
194 totE_.back() > 0.9 * totE_[totE_.size() - 2]) {
197 diis_error = !adiis_.Info() || coeffs.size() == 0;
199 << TimeStamp() << " Using ADIIS for next UKS guess" << std::flush;
200 } else {
201 coeffs = diis_.CalcCoeff();
202 diis_error = !diis_.Info() || coeffs.size() == 0;
204 << TimeStamp() << " Using DIIS for next UKS guess" << std::flush;
205 }
206
207 if (diis_error) {
209 << TimeStamp() << " (A)DIIS failed using mixing instead"
210 << std::flush;
211 H_guess_alpha = H.alpha;
212 H_guess_beta = H.beta;
213 } else {
214 H_guess_alpha.setZero();
215 H_guess_beta.setZero();
216 for (Index i = 0; i < coeffs.size(); ++i) {
217 if (std::abs(coeffs(i)) < 1e-8) {
218 continue;
219 }
220 H_guess_alpha += coeffs(i) * mathist_alpha_[i];
221 H_guess_beta += coeffs(i) * mathist_beta_[i];
222 }
223 }
224 }
225
226 MOs_alpha = SolveFockmatrix(H_guess_alpha);
227 MOs_beta = SolveFockmatrix(H_guess_beta);
228
229 SpinDensity dmatout = DensityMatrix(MOs_alpha, MOs_beta);
230
231 if (diiserror_ > opt_alpha_.adiis_start || !opt_alpha_.usediis ||
232 diis_error || mathist_alpha_.size() <= 2) {
233 usedmixing_ = true;
234 dmatout.alpha = opt_alpha_.mixingparameter * dmat.alpha +
235 (1.0 - opt_alpha_.mixingparameter) * dmatout.alpha;
236 dmatout.beta = opt_beta_.mixingparameter * dmat.beta +
237 (1.0 - opt_beta_.mixingparameter) * dmatout.beta;
239 << TimeStamp()
240 << " Using coupled UKS mixing with alpha=" << opt_alpha_.mixingparameter
241 << std::flush;
242 } else {
243 usedmixing_ = false;
244 }
245
246 return dmatout;
247}
248
250 if (totE_.size() < 2) {
251 return 100.0;
252 }
253 return std::abs(totE_.back() - totE_[totE_.size() - 2]);
254}
255
257 return (getDeltaE() < opt_alpha_.Econverged &&
258 diiserror_ < opt_alpha_.error_converged);
259}
260
261} // namespace xtp
262} // namespace votca
const Eigen::VectorXd & eigenvalues() const
Definition eigensystem.h:30
const Eigen::MatrixXd & eigenvectors() const
Definition eigensystem.h:33
Logger is used for thread-safe output of messages.
Definition logger.h:164
Timestamp returns the current time as a string Example: cout << TimeStamp()
Definition logger.h:224
double CombinedError(const Eigen::MatrixXd &err_alpha, const Eigen::MatrixXd &err_beta) const
tools::EigenSystem SolveFockmatrix(const Eigen::MatrixXd &H) const
SpinDensity DensityMatrix(const tools::EigenSystem &MOs_alpha, const tools::EigenSystem &MOs_beta) const
void Levelshift(Eigen::MatrixXd &H, const Eigen::MatrixXd &MOs_old, const options &opt, Index nocclevels) const
std::vector< Eigen::MatrixXd > mathist_beta_
void setOverlap(AOOverlap &S, double etol)
void Configure(const options &opt_alpha, const options &opt_beta)
Eigen::MatrixXd BuildErrorMatrix(const Eigen::MatrixXd &dmat, const Eigen::MatrixXd &H) const
ConvergenceAcc::options options
SpinDensity Iterate(const SpinDensity &dmat, SpinFock &H, tools::EigenSystem &MOs_alpha, tools::EigenSystem &MOs_beta, double totE)
std::vector< Eigen::MatrixXd > dmatHist_alpha_
std::vector< Eigen::MatrixXd > dmatHist_beta_
Eigen::MatrixXd DensityMatrixGroundState_unres(const Eigen::MatrixXd &MOs, Index nocclevels) const
std::vector< Eigen::MatrixXd > mathist_alpha_
#define XTP_LOG(level, log)
Definition logger.h:40
Charge transport classes.
Definition ERIs.h:28
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26