50 sigma_->configure(sigma_opt);
59 return QPgap - DFTgap;
70 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> qpdiag(
getHQP());
81 " ====== Perturbative quasiparticle energies (Hartree) ====== "))
85 << (boost::format(
" DeltaHLGap = %1$+1.6f Hartree") % shift).str()
89 std::string level =
" Level";
98 << (boost::format(
" = %1$4d DFT = %2$+1.4f VXC = %3$+1.4f S-X = "
99 "%4$+1.4f S-C = %5$+1.4f GWA = %6$+1.4f") %
111 <<
TimeStamp() <<
" Full quasiparticle Hamiltonian " << std::flush;
114 " ====== Diagonalized quasiparticle energies (Hartree) "
119 std::string level =
" Level";
127 << (boost::format(
" = %1$4d PQP = %2$+1.6f DQP = %3$+1.6f ") %
128 (i +
opt_.
qpmin) % gwa_energies(i) % qp_diag_energies(i))
136 const Eigen::VectorXd& dft_energies)
const {
137 Eigen::VectorXd shifted_energies = dft_energies;
138 shifted_energies.segment(
opt_.
homo + 1, dft_energies.size() -
opt_.
homo - 1)
140 return shifted_energies;
147 <<
TimeStamp() <<
" Calculated Hartree exchange contribution"
155 <<
" Hrt" << std::flush;
159 Eigen::VectorXd frequencies =
170 <<
TimeStamp() <<
" Rebuilding 3c integrals" << std::flush;
172 sigma_->PrepareScreening();
174 <<
TimeStamp() <<
" Calculated screening via RPA" << std::flush;
176 <<
TimeStamp() <<
" Solving QP equations " << std::flush;
181 frequencies =
SolveQP(frequencies);
192 <<
"GWSC using Anderson mixing with history "
197 Eigen::VectorXd mixed_frequencies = mixing_.
MixHistory();
200 frequencies = mixed_frequencies;
207 for (
int i = 0; i < frequencies.size(); i++) {
209 <<
"... GWSC iter " << i_gw <<
" state " << i <<
" "
210 << std::setprecision(9) << frequencies(i) << std::flush;
214 <<
TimeStamp() <<
" GW_Iteration:" << i_gw
219 << i_gw + 1 <<
" GW iterations." << std::flush;
224 <<
" WARNING! GW-self-consistency cycle not converged after "
227 <<
TimeStamp() <<
" Run continues. Inspect results carefully!"
242Eigen::VectorXd
GW::SolveQP(
const Eigen::VectorXd& frequencies)
const {
244 Eigen::VectorXd env = Eigen::VectorXd::Zero(
qptotal_);
246 const Eigen::VectorXd intercepts =
250 Eigen::VectorXd frequencies_new = frequencies;
251 Eigen::Array<bool, Eigen::Dynamic, 1> converged =
252 Eigen::Array<bool, Eigen::Dynamic, 1>::Zero(
qptotal_);
257#pragma omp parallel for schedule(dynamic) num_threads(use_threads)
260 double initial_f = frequencies[gw_level];
261 double intercept = intercepts[gw_level];
262 boost::optional<double> newf;
267 frequencies_new[gw_level] = newf.value();
268 converged[gw_level] =
true;
272 frequencies_new[gw_level] = newf.value();
273 converged[gw_level] =
true;
277 frequencies_new[gw_level] = newf.value();
283 if (!converged.all()) {
284 std::vector<Index> states;
285 for (
Index s = 0; s < converged.size(); s++) {
294 <<
TimeStamp() <<
" Increase the grid search interval" << std::flush;
296 return frequencies_new;
301 Index gw_level)
const {
302 boost::optional<double> newf = boost::none;
304 double sigma =
sigma_->CalcCorrelationDiagElement(gw_level, frequency0);
305 double dsigma_domega =
306 sigma_->CalcCorrelationDiagElementDerivative(gw_level, frequency0);
307 double Z = 1.0 - dsigma_domega;
308 if (std::abs(Z) > 1
e-9) {
309 newf = frequency0 + (intercept0 - frequency0 + sigma) / Z;
315 Index gw_level)
const {
316 std::vector<std::pair<double, double>> roots;
319 boost::optional<double> newf = boost::none;
320 double freq_prev = frequency0 - range;
322 double targ_prev = fqp.
value(freq_prev);
323 double qp_energy = 0.0;
324 double gradient_max = std::numeric_limits<double>::max();
325 bool pole_found =
false;
328 double targ = fqp.
value(freq);
329 if (targ_prev * targ < 0.0) {
331 double gradient = fqp.
deriv(f);
332 double qp_weight = -1.0 / gradient;
333 roots.push_back(std::make_pair(f, qp_weight));
334 if (std::abs(gradient) < gradient_max) {
335 gradient_max = std::abs(gradient);
348 <<
" No roots found for qplevel:" << gw_level << std::flush;
351 <<
" (qpenergy:qpweight)\n\t\t";
352 for (
auto& root : roots) {
354 << root.second <<
" ";
369 Index gw_level)
const {
370 boost::optional<double> newf = boost::none;
374 double freq_new = newton.
FindRoot(f, frequency0);
383 double upperbound,
double f_upperbound,
386 if (f_lowerbound * f_upperbound > 0) {
387 throw std::runtime_error(
388 "Bisection needs a postive and negative function value");
392 double c = 0.5 * (lowerbound + upperbound);
397 double y_c = f.
value(c);
402 if (y_c * f_lowerbound > 0) {
414 double epsilon)
const {
416 bool energies_converged =
true;
417 double diff_max = (e1 - e2).cwiseAbs().maxCoeff(&state);
418 if (diff_max > epsilon) {
419 energies_converged =
false;
422 <<
" StateNo:" << state << std::flush;
423 return energies_converged;
427 Eigen::VectorXd diag_backup =
Sigma_c_.diagonal();
433 std::string states)
const {
435 Eigen::VectorXd frequencies =
438 std::vector<Index> state_inds;
441 for (
Index gw_level : parsed_states) {
443 state_inds.push_back(gw_level);
447 <<
TimeStamp() <<
" PQP(omega) written to '" << filename
450 const Index num_states = state_inds.size();
452 const Eigen::VectorXd intercept =
455 Eigen::MatrixXd mat = Eigen::MatrixXd::Zero(steps, 2 * num_states);
456#pragma omp parallel for schedule(dynamic)
457 for (
Index grid_point = 0; grid_point < steps; grid_point++) {
458 const double offset =
459 ((double)grid_point - ((double)(steps - 1) / 2.0)) * spacing;
460 for (
Index i = 0; i < num_states; i++) {
461 const Index gw_level = state_inds[i];
462 const double omega = frequencies(gw_level) + offset;
463 double sigma =
sigma_->CalcCorrelationDiagElement(gw_level, omega);
464 mat(grid_point, 2 * i) = omega;
465 mat(grid_point, 2 * i + 1) = sigma + intercept[gw_level];
471 for (
Index i = 0; i < num_states; i++) {
472 const Index gw_level = state_inds[i];
473 out << boost::format(
"#%1$somega_%2$d\tE_QP(omega)_%2$d") %
474 (i == 0 ?
"" :
"\t") % gw_level;
477 boost::format numFormat(
"%+1.6f");
478 Eigen::IOFormat matFormat(Eigen::StreamPrecision, 0,
"\t",
"\n");
479 out << numFormat % mat.format(matFormat) << std::endl;
Anderson mixing as convergence acceleration in SCF/fixed point problems.
void UpdateInput(const Eigen::VectorXd &newInput)
const Eigen::VectorXd MixHistory()
void UpdateOutput(const Eigen::VectorXd &newOutput)
void Configure(const Index order, const double alpha)
double deriv(double frequency) const
double value(double frequency) const
void PlotSigma(std::string filename, Index steps, double spacing, std::string states) const
Eigen::SelfAdjointEigenSolver< Eigen::MatrixXd > DiagonalizeQPHamiltonian() const
void PrintGWA_Energies() const
double SolveQP_Bisection(double lowerbound, double f_lowerbound, double upperbound, double f_upperbound, const QPFunc &f) const
boost::optional< double > SolveQP_FixedPoint(double intercept0, double frequency0, Index gw_level) const
bool Converged(const Eigen::VectorXd &e1, const Eigen::VectorXd &e2, double epsilon) const
void configure(const options &opt)
Eigen::MatrixXd getHQP() const
Eigen::VectorXd SolveQP(const Eigen::VectorXd &frequencies) const
boost::optional< double > SolveQP_Grid(double intercept0, double frequency0, Index gw_level) const
const Eigen::VectorXd & dft_energies_
std::unique_ptr< Sigma_base > sigma_
Eigen::VectorXd getGWAResults() const
double CalcHomoLumoShift(Eigen::VectorXd frequencies) const
const Eigen::MatrixXd & vxc_
void PrintQP_Energies(const Eigen::VectorXd &qp_diag_energies) const
boost::optional< double > SolveQP_Linearisation(double intercept0, double frequency0, Index gw_level) const
Eigen::VectorXd ScissorShift_DFTlevel(const Eigen::VectorXd &dft_energies) const
void CalculateGWPerturbation()
std::vector< Index > CreateIndexVector(const std::string &Ids) const
std::string CreateIndexString(const std::vector< Index > &indeces) const
Newton Rapson rootfinder for 1d functions.
double FindRoot(const Func &f, double x0)
void setRPAInputEnergies(const Eigen::VectorXd &rpaenergies)
void configure(Index homo, Index rpamin, Index rpamax)
const Eigen::VectorXd & getRPAInputEnergies() const
void UpdateRPAInputEnergies(const Eigen::VectorXd &dftenergies, const Eigen::VectorXd &gwaenergies, Index qpmin)
Timestamp returns the current time as a string Example: cout << TimeStamp()
#define XTP_LOG(level, log)
base class for all analysis tools
static Level current_level
Index gw_sc_max_iterations
std::string quadrature_scheme
Index g_sc_max_iterations
std::string sigma_integration
std::string quadrature_scheme