42 const Eigen::VectorXd& dftenergies_beta,
43 const Eigen::VectorXd& gwaenergies_alpha,
44 const Eigen::VectorXd& gwaenergies_beta,
54 const Index gwsize_alpha =
Index(gwaenergies_alpha.size());
55 const Index gwsize_beta =
Index(gwaenergies_beta.size());
92 const Eigen::MatrixXd& XpY = rpa_solution.
XpY;
93 const Eigen::VectorXd& omegas = rpa_solution.
omega;
103 const Index size_alpha = n_occ_alpha * n_unocc_alpha;
104 const Index auxsize =
Mmn_.alpha.auxsize();
112 Eigen::MatrixXd M(n_occ * n_unocc, auxsize);
113#pragma omp parallel for schedule(dynamic)
114 for (
Index v = 0; v < n_occ; v++) {
115 M.middleRows(vc.
I(v, 0), n_unocc) = Mmn[v].middleRows(n_occ, n_unocc);
119 const Index size_beta = n_occ_beta * n_unocc_beta;
121 stacked_rows(
Mmn_.alpha, n_occ_alpha, n_unocc_alpha).transpose() *
122 XpY.topRows(size_alpha);
123 Z.noalias() += stacked_rows(
Mmn_.beta, n_occ_beta, n_unocc_beta).transpose() *
124 XpY.middleRows(size_alpha, size_beta);
126 std::vector<Eigen::VectorXd> all_modes;
127 all_modes.reserve(nmodes);
128 std::vector<double> all_norms;
129 all_norms.reserve(nmodes);
130 double max_norm = 0.0;
131 for (
Index s = 0; s < nmodes; s++) {
132 const double norm = Z.col(s).norm();
133 max_norm = std::max(max_norm, norm);
134 all_modes.push_back(Z.col(s));
135 all_norms.push_back(norm);
138 const double tol = 1
e-10 * std::max(1.0, max_norm);
140 std::vector<Eigen::VectorXd> active_modes;
141 std::vector<double> active_omegas;
142 active_modes.reserve(nmodes);
143 active_omegas.reserve(nmodes);
145 for (
Index s = 0; s < nmodes; s++) {
146 if (all_norms[s] > tol) {
147 active_modes.push_back(std::move(all_modes[s]));
148 active_omegas.push_back(omegas(s));
175 const Index nalpha = (n_unocc_alpha > 0) ? n_occ_alpha : 0;
176 const Index nbeta = (n_unocc_beta > 0) ? n_occ_beta : 0;
180 if (block < nalpha) {
189 nalpha + nbeta, size,
190 [&](
Index block, Eigen::VectorXd& w) {
192 const bool beta = spin_of(block, m);
197 const bool beta = spin_of(block, m);
199 use(
Mmn_.beta[m].bottomRows(n_unocc_beta));
201 use(
Mmn_.alpha[m].bottomRows(n_unocc_alpha));
208 const double freq2 = frequency * frequency;
210 Eigen::MatrixXd result =
212 const Eigen::VectorXd& energies =
217 const Eigen::ArrayXd deltaE =
218 energies.tail(n_unocc).array() - energies(m_level);
222 denom = 2.0 * deltaE / (deltaE.square() + freq2);
226 Eigen::ArrayXd deltEf = deltaE - frequency;
227 Eigen::ArrayXd sum = deltEf / (deltEf.square() + eta2);
228 deltEf = deltaE + frequency;
229 sum += deltEf / (deltEf.square() + eta2);
234 result.diagonal().array() += 1.0;
244 std::complex<double> frequency)
const {
247 const double sigma_1 = std::pow(frequency.imag() +
eta_, 2);
248 const double sigma_2 = std::pow(frequency.imag() -
eta_, 2);
249 Eigen::MatrixXd result =
251 const Eigen::VectorXd& energies =
255 const Eigen::ArrayXd deltaE =
256 energies.tail(n_unocc).array() - energies(m_level);
257 const Eigen::ArrayXd deltaEm = frequency.real() - deltaE;
258 const Eigen::ArrayXd deltaEp = frequency.real() + deltaE;
261 chi = -(deltaEm * (deltaEm.abs2() + sigma_1).inverse() -
262 deltaEp * (deltaEp.abs2() + sigma_2).inverse());
264 result.diagonal().array() += 1.0;
288 Eigen::MatrixXd& C = ApB;
289 C.applyOnTheLeft(AmB.cwiseSqrt().asDiagonal());
290 C.applyOnTheRight(AmB.cwiseSqrt().asDiagonal());
294 sol.
omega = Eigen::VectorXd::Zero(es.
values.size());
299 <<
" Lowest neutral excitation energy (eV): "
309 sol.
XpY = Eigen::MatrixXd(rpasize, rpasize);
312 const Eigen::VectorXd AmB_sqrt = AmB.cwiseSqrt();
313 const Eigen::VectorXd Omega_sqrt_inv = sol.
omega.cwiseSqrt().cwiseInverse();
314 for (
Index s = 0; s < rpasize; s++) {
316 Omega_sqrt_inv(s) * AmB_sqrt.cwiseProduct(es.
vectors.col(s));
335 const Index size_alpha = n_occ_alpha * n_unocc_alpha;
336 const Index size_beta = n_occ_beta * n_unocc_beta;
338 Eigen::VectorXd AmB = Eigen::VectorXd::Zero(size_alpha + size_beta);
342 vc2index vc_alpha(0, 0, n_unocc_alpha);
343 for (
Index v = 0; v < n_occ_alpha; v++) {
344 const Index i = vc_alpha.
I(v, 0);
345 AmB.segment(i, n_unocc_alpha) =
352 vc2index vc_beta(0, 0, n_unocc_beta);
353 for (
Index v = 0; v < n_occ_beta; v++) {
354 const Index i = size_alpha + vc_beta.
I(v, 0);
355 AmB.segment(i, n_unocc_beta) =
372 const Index size_alpha = n_occ_alpha * n_unocc_alpha;
373 const Index size_beta = n_occ_beta * n_unocc_beta;
375 Eigen::MatrixXd ApB =
376 Eigen::MatrixXd::Zero(size_alpha + size_beta, size_alpha + size_beta);
378 vc2index vc_alpha(0, 0, n_unocc_alpha);
379 vc2index vc_beta(0, 0, n_unocc_beta);
383#pragma omp parallel for schedule(guided)
384 for (
Index v2 = 0; v2 < n_occ_alpha; v2++) {
385 const Index i2 = vc_alpha.
I(v2, 0);
386 const Eigen::MatrixXd Mmn_v2T =
387 Mmn_.alpha[v2].middleRows(n_occ_alpha, n_unocc_alpha).transpose();
389 for (
Index v1 = v2; v1 < n_occ_alpha; v1++) {
390 const Index i1 = vc_alpha.
I(v1, 0);
396 ApB.block(i1, i2, n_unocc_alpha, n_unocc_alpha) =
398 Mmn_.alpha[v1].middleRows(n_occ_alpha, n_unocc_alpha) * Mmn_v2T;
403#pragma omp parallel for schedule(guided)
404 for (
Index v2 = 0; v2 < n_occ_beta; v2++) {
405 const Index i2 = size_alpha + vc_beta.
I(v2, 0);
406 const Eigen::MatrixXd Mmn_v2T =
407 Mmn_.beta[v2].middleRows(n_occ_beta, n_unocc_beta).transpose();
409 for (
Index v1 = v2; v1 < n_occ_beta; v1++) {
410 const Index i1 = size_alpha + vc_beta.
I(v1, 0);
411 ApB.block(i1, i2, n_unocc_beta, n_unocc_beta) =
413 Mmn_.beta[v1].middleRows(n_occ_beta, n_unocc_beta) * Mmn_v2T;
420#pragma omp parallel for schedule(guided)
421 for (
Index v_beta = 0; v_beta < n_occ_beta; v_beta++) {
422 const Index i_beta = size_alpha + vc_beta.
I(v_beta, 0);
423 const Eigen::MatrixXd Mmn_beta_T =
424 Mmn_.beta[v_beta].middleRows(n_occ_beta, n_unocc_beta).transpose();
426 for (
Index v_alpha = 0; v_alpha < n_occ_alpha; v_alpha++) {
427 const Index i_alpha = vc_alpha.
I(v_alpha, 0);
428 ApB.block(i_alpha, i_beta, n_unocc_alpha, n_unocc_beta) =
430 Mmn_.alpha[v_alpha].middleRows(n_occ_alpha, n_unocc_alpha) *
436 ApB.block(0, 0, size_alpha, size_alpha)
437 .template triangularView<Eigen::StrictlyUpper>() =
438 ApB.block(0, 0, size_alpha, size_alpha)
440 .template triangularView<Eigen::StrictlyUpper>();
443 ApB.block(size_alpha, size_alpha, size_beta, size_beta)
444 .template triangularView<Eigen::StrictlyUpper>() =
445 ApB.block(size_alpha, size_alpha, size_beta, size_beta)
447 .template triangularView<Eigen::StrictlyUpper>();
450 ApB.block(size_alpha, 0, size_beta, size_alpha) =
451 ApB.block(0, size_alpha, size_alpha, size_beta).transpose();
void UpdateRPAInputEnergies(const Eigen::VectorXd &dftenergies_alpha, const Eigen::VectorXd &dftenergies_beta, const Eigen::VectorXd &gwaenergies_alpha, const Eigen::VectorXd &gwaenergies_beta, Index qpmin)
Update alpha and beta RPA input energies from DFT and GW energies.