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());
94 const Eigen::MatrixXd& XpY = rpa_solution.
XpY;
95 const Eigen::VectorXd& omegas = rpa_solution.
omega;
105 const Index size_alpha = n_occ_alpha * n_unocc_alpha;
106 const Index auxsize =
Mmn_.alpha.auxsize();
109 std::vector<Eigen::VectorXd> all_modes;
110 all_modes.reserve(nmodes);
111 std::vector<double> all_norms;
112 all_norms.reserve(nmodes);
114 vc2index vc_alpha(0, 0, n_unocc_alpha);
115 vc2index vc_beta(0, 0, n_unocc_beta);
117 double max_norm = 0.0;
118 for (
Index s = 0; s < nmodes; s++) {
119 Eigen::VectorXd mode = Eigen::VectorXd::Zero(auxsize);
121 for (
Index v = 0; v < n_occ_alpha; v++) {
122 const auto Mmn_v =
Mmn_.alpha[v].middleRows(n_occ_alpha, n_unocc_alpha);
123 const auto XpY_v = XpY.col(s).segment(vc_alpha.
I(v, 0), n_unocc_alpha);
124 mode.noalias() += Mmn_v.transpose() * XpY_v;
127 for (
Index v = 0; v < n_occ_beta; v++) {
128 const auto Mmn_v =
Mmn_.beta[v].middleRows(n_occ_beta, n_unocc_beta);
130 XpY.col(s).segment(size_alpha + vc_beta.
I(v, 0), n_unocc_beta);
131 mode.noalias() += Mmn_v.transpose() * XpY_v;
134 const double norm = mode.norm();
135 max_norm = std::max(max_norm, norm);
136 all_modes.push_back(std::move(mode));
137 all_norms.push_back(norm);
140 const double tol = 1
e-10 * std::max(1.0, max_norm);
142 std::vector<Eigen::VectorXd> active_modes;
143 std::vector<double> active_omegas;
144 active_modes.reserve(nmodes);
145 active_omegas.reserve(nmodes);
147 for (
Index s = 0; s < nmodes; s++) {
148 if (all_norms[s] > tol) {
149 active_modes.push_back(std::move(all_modes[s]));
150 active_omegas.push_back(omegas(s));
164 const Eigen::VectorXd& dftenergies,
166 const Index lumo = homo + 1;
167 const Index qpmax = qpmin + gwsize - 1;
171 const double max_correction_occ =
176 const double max_correction_virt =
182 energies.head(qpmin -
rpamin_).array() -= max_correction_occ;
183 energies.tail(
rpamax_ - qpmax).array() += max_correction_virt;
207 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(size, size);
213 const Eigen::VectorXd& energies,
Index homo) {
214 const Index lumo = homo + 1;
221 if (n_occ <= 0 || n_unocc <= 0) {
225 const double freq2 = frequency * frequency;
235#pragma omp for schedule(dynamic)
236 for (
Index m_level = 0; m_level < n_occ; m_level++) {
240 const double qp_energy_m = energies(m_level);
245 Eigen::MatrixXd Mmn_RPA = Mmn[m_level].bottomRows(n_unocc);
250 const Eigen::ArrayXd deltaE =
251 energies.tail(n_unocc).array() - qp_energy_m;
253 Eigen::VectorXd denom;
264 denom = 2.0 * deltaE / (deltaE.square() + freq2);
273 Eigen::ArrayXd deltEf = deltaE - frequency;
274 Eigen::ArrayXd sum = deltEf / (deltEf.square() + eta2);
275 deltEf = deltaE + frequency;
276 sum += deltEf / (deltEf.square() + eta2);
282 transform.
A_TDA(denom, threadid);
297 result.diagonal().array() += 1.0;
307 std::complex<double> frequency)
const {
309 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(size, size);
314 const Eigen::VectorXd& energies,
Index homo) {
315 const Index lumo = homo + 1;
319 if (n_occ <= 0 || n_unocc <= 0) {
330#pragma omp for schedule(dynamic)
331 for (
Index m_level = 0; m_level < n_occ; m_level++) {
332 const double qp_energy_m = energies(m_level);
334 Eigen::MatrixXd Mmn_RPA = Mmn[m_level].bottomRows(n_unocc);
337 const Eigen::ArrayXd deltaE =
338 energies.tail(n_unocc).array() - qp_energy_m;
343 const Eigen::ArrayXd deltaEm = frequency.real() - deltaE;
344 const Eigen::ArrayXd deltaEp = frequency.real() + deltaE;
346 const double sigma_1 = std::pow(frequency.imag() +
eta_, 2);
347 const double sigma_2 = std::pow(frequency.imag() -
eta_, 2);
349 const Eigen::VectorXd chi =
350 deltaEm * (deltaEm.cwiseAbs2() + sigma_1).cwiseInverse() -
351 deltaEp * (deltaEp.cwiseAbs2() + sigma_2).cwiseInverse();
353 transform.
A_TDA(chi, threadid);
365 result.diagonal().array() += 1.0;
389 Eigen::MatrixXd& C = ApB;
390 C.applyOnTheLeft(AmB.cwiseSqrt().asDiagonal());
391 C.applyOnTheRight(AmB.cwiseSqrt().asDiagonal());
395 sol.
omega = Eigen::VectorXd::Zero(es.eigenvalues().size());
396 sol.
omega = es.eigenvalues().cwiseSqrt();
400 <<
" Lowest neutral excitation energy (eV): "
410 sol.
XpY = Eigen::MatrixXd(rpasize, rpasize);
413 const Eigen::VectorXd AmB_sqrt = AmB.cwiseSqrt();
414 const Eigen::VectorXd Omega_sqrt_inv = sol.
omega.cwiseSqrt().cwiseInverse();
415 for (
Index s = 0; s < rpasize; s++) {
417 Omega_sqrt_inv(s) * AmB_sqrt.cwiseProduct(es.eigenvectors().col(s));
436 const Index size_alpha = n_occ_alpha * n_unocc_alpha;
437 const Index size_beta = n_occ_beta * n_unocc_beta;
439 Eigen::VectorXd AmB = Eigen::VectorXd::Zero(size_alpha + size_beta);
443 vc2index vc_alpha(0, 0, n_unocc_alpha);
444 for (
Index v = 0; v < n_occ_alpha; v++) {
445 const Index i = vc_alpha.
I(v, 0);
446 AmB.segment(i, n_unocc_alpha) =
453 vc2index vc_beta(0, 0, n_unocc_beta);
454 for (
Index v = 0; v < n_occ_beta; v++) {
455 const Index i = size_alpha + vc_beta.
I(v, 0);
456 AmB.segment(i, n_unocc_beta) =
473 const Index size_alpha = n_occ_alpha * n_unocc_alpha;
474 const Index size_beta = n_occ_beta * n_unocc_beta;
476 Eigen::MatrixXd ApB =
477 Eigen::MatrixXd::Zero(size_alpha + size_beta, size_alpha + size_beta);
479 vc2index vc_alpha(0, 0, n_unocc_alpha);
480 vc2index vc_beta(0, 0, n_unocc_beta);
484#pragma omp parallel for schedule(guided)
485 for (
Index v2 = 0; v2 < n_occ_alpha; v2++) {
486 const Index i2 = vc_alpha.
I(v2, 0);
487 const Eigen::MatrixXd Mmn_v2T =
488 Mmn_.alpha[v2].middleRows(n_occ_alpha, n_unocc_alpha).transpose();
490 for (
Index v1 = v2; v1 < n_occ_alpha; v1++) {
491 const Index i1 = vc_alpha.
I(v1, 0);
497 ApB.block(i1, i2, n_unocc_alpha, n_unocc_alpha) =
499 Mmn_.alpha[v1].middleRows(n_occ_alpha, n_unocc_alpha) * Mmn_v2T;
504#pragma omp parallel for schedule(guided)
505 for (
Index v2 = 0; v2 < n_occ_beta; v2++) {
506 const Index i2 = size_alpha + vc_beta.
I(v2, 0);
507 const Eigen::MatrixXd Mmn_v2T =
508 Mmn_.beta[v2].middleRows(n_occ_beta, n_unocc_beta).transpose();
510 for (
Index v1 = v2; v1 < n_occ_beta; v1++) {
511 const Index i1 = size_alpha + vc_beta.
I(v1, 0);
512 ApB.block(i1, i2, n_unocc_beta, n_unocc_beta) =
514 Mmn_.beta[v1].middleRows(n_occ_beta, n_unocc_beta) * Mmn_v2T;
521#pragma omp parallel for schedule(guided)
522 for (
Index v_beta = 0; v_beta < n_occ_beta; v_beta++) {
523 const Index i_beta = size_alpha + vc_beta.
I(v_beta, 0);
524 const Eigen::MatrixXd Mmn_beta_T =
525 Mmn_.beta[v_beta].middleRows(n_occ_beta, n_unocc_beta).transpose();
527 for (
Index v_alpha = 0; v_alpha < n_occ_alpha; v_alpha++) {
528 const Index i_alpha = vc_alpha.
I(v_alpha, 0);
529 ApB.block(i_alpha, i_beta, n_unocc_alpha, n_unocc_beta) =
531 Mmn_.alpha[v_alpha].middleRows(n_occ_alpha, n_unocc_alpha) *
537 ApB.block(0, 0, size_alpha, size_alpha)
538 .template triangularView<Eigen::StrictlyUpper>() =
539 ApB.block(0, 0, size_alpha, size_alpha)
541 .template triangularView<Eigen::StrictlyUpper>();
544 ApB.block(size_alpha, size_alpha, size_beta, size_beta)
545 .template triangularView<Eigen::StrictlyUpper>() =
546 ApB.block(size_alpha, size_alpha, size_beta, size_beta)
548 .template triangularView<Eigen::StrictlyUpper>();
551 ApB.block(size_alpha, 0, size_beta, size_alpha) =
552 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.