21#include <boost/format.hpp>
39 string spintype = options.
get(
"spin").
as<std::string>();
40 if (spintype ==
"all") {
43 }
else if (spintype ==
"triplet") {
46 }
else if (spintype ==
"singlet") {
50 throw std::runtime_error(
52 "Choice % for type not known. Available singlet,triplet,all") %
68 Property& coupling_summary = summary.
add(
"coupling",
"");
84 coupling_summary.
setAttribute(
"j_pert", (format(
"%1$1.6e") % JAB_pert).str());
85 coupling_summary.
setAttribute(
"j_diag", (format(
"%1$1.6e") % JAB_diag).str());
91 string algorithm =
"j_diag";
99 for (
Index stateA = 0; stateA <
levA_; ++stateA) {
101 for (
Index stateB = 0; stateB <
levB_; ++stateB) {
112 for (
Index stateA = 0; stateA <
levA_; ++stateA) {
114 for (
Index stateB = 0; stateB <
levB_; ++stateB) {
123 Index methodindex)
const {
129 Index methodindex)
const {
137 const Eigen::MatrixXd& A_AB,
138 const Eigen::MatrixXd& B_AB)
const {
142 Index bseAB_size = bseAB_vtotal * bseAB_ctotal;
143 Eigen::MatrixXd CTstates = Eigen::MatrixXd::Zero(bseAB_size, noAB + noBA);
145 auto A_occ = A_AB.middleCols(bseA_vtotal -
occA_,
occA_);
146 auto A_unocc = A_AB.middleCols(bseA_vtotal,
unoccA_);
147 auto B_occ = B_AB.middleCols(bseB_vtotal -
occB_,
occB_);
148 auto B_unocc = B_AB.middleCols(bseB_vtotal,
unoccB_);
150 const Eigen::MatrixXd A_occ_occ = A_occ.topRows(bseAB_vtotal);
151 const Eigen::MatrixXd B_unocc_unocc = B_unocc.bottomRows(bseAB_ctotal);
156 <<
TimeStamp() <<
" Setting up CT-states" << flush;
159#pragma omp parallel for
160 for (
Index a_occ = 0; a_occ <
occA_; a_occ++) {
163 Eigen::MatrixXd Coeff =
164 B_unocc_unocc.col(b_unocc) * A_occ_occ.col(a_occ).transpose();
165 CTstates.col(index) =
166 Eigen::Map<Eigen::VectorXd>(Coeff.data(), bseAB_size);
170 <<
TimeStamp() <<
" " << noBA <<
" CT states A+B- created" << flush;
172 const Eigen::MatrixXd A_unocc_unocc = A_unocc.bottomRows(bseAB_ctotal);
173 const Eigen::MatrixXd B_occ_occ = B_occ.topRows(bseAB_vtotal);
175#pragma omp parallel for
176 for (
Index b_occ = 0; b_occ <
occB_; b_occ++) {
179 Eigen::MatrixXd Coeff =
180 A_unocc_unocc.col(a_unocc) * B_occ_occ.col(b_occ).transpose();
181 CTstates.col(index) =
182 Eigen::Map<Eigen::VectorXd>(Coeff.data(), bseAB_size);
186 <<
TimeStamp() <<
" " << noBA <<
" CT states A-B+ created" << flush;
191 const Eigen::MatrixXd& BSE_Coeffs,
const Eigen::MatrixXd& X_AB,
193 Index bseAB_ctotal)
const {
194 Index bseAB_size = bseAB_vtotal * bseAB_ctotal;
195 auto X_occ = X_AB.leftCols(bseX_vtotal);
196 auto X_unocc = X_AB.rightCols(bseX_ctotal);
197 const Eigen::MatrixXd X_occ_occ = X_occ.topRows(bseAB_vtotal);
198 const Eigen::MatrixXd X_unocc_unocc = X_unocc.bottomRows(bseAB_ctotal);
199 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(bseAB_size, BSE_Coeffs.cols());
201 for (
Index i = 0; i < BSE_Coeffs.cols(); i++) {
202 Eigen::VectorXd coeff = BSE_Coeffs.col(i);
203 Eigen::Map<Eigen::MatrixXd> coeffmatrix =
204 Eigen::Map<Eigen::MatrixXd>(coeff.data(), bseX_ctotal, bseX_vtotal);
205 Eigen::MatrixXd proj = X_unocc_unocc * coeffmatrix * X_occ_occ.transpose();
206 result.col(i) = Eigen::Map<Eigen::VectorXd>(proj.data(), proj.size());
214 }
else if (value > 0) {
224 <<
TimeStamp() <<
" Calculating exciton couplings" << flush;
234 if ((basisA == 0) || (basisB == 0)) {
235 throw std::runtime_error(
"Basis set size is not stored in monomers");
242 Index bseA_vtotal = bseA_vmax - bseA_vmin + 1;
243 Index bseA_ctotal = bseA_cmax - bseA_cmin + 1;
244 Index bseA_total = bseA_vtotal + bseA_ctotal;
245 Index bseA_size = bseA_vtotal * bseA_ctotal;
250 <<
TimeStamp() <<
" molecule A has " << bseA_singlet_exc
251 <<
" singlet excitons with dimension " << bseA_size << flush;
253 <<
TimeStamp() <<
" molecule A has " << bseA_triplet_exc
254 <<
" triplet excitons with dimension " << bseA_size << flush;
261 Index bseB_vtotal = bseB_vmax - bseB_vmin + 1;
262 Index bseB_ctotal = bseB_cmax - bseB_cmin + 1;
263 Index bseB_total = bseB_vtotal + bseB_ctotal;
264 Index bseB_size = bseB_vtotal * bseB_ctotal;
269 <<
TimeStamp() <<
" molecule B has " << bseB_singlet_exc
270 <<
" singlet excitons with dimension " << bseB_size << flush;
272 <<
TimeStamp() <<
" molecule B has " << bseB_triplet_exc
273 <<
" triplet excitons with dimension " << bseB_size << flush;
276 if (
levA_ > bseA_singlet_exc) {
278 <<
" Number of excitons you want is greater "
279 "than stored for molecule "
280 "A. Setting to max number available"
282 levA_ = bseA_singlet_exc;
284 if (
levB_ > bseB_singlet_exc) {
286 <<
" Number of excitons you want is greater "
287 "than stored for molecule "
288 "B. Setting to max number available"
290 levB_ = bseB_singlet_exc;
294 if (
levA_ > bseA_triplet_exc) {
297 <<
" Number of Frenkel states you want is greater than stored for "
298 "molecule A. Setting to max number available"
300 levA_ = bseA_triplet_exc;
302 if (
levB_ > bseB_triplet_exc) {
305 <<
" Number of Frenkel states you want is greater than stored for "
306 "molecule B. Setting to max number available"
308 levB_ = bseB_triplet_exc;
314 <<
" Number of unoccupied orbitals in molecule A for CT creation "
315 "exceeds number of KS-orbitals in BSE"
322 <<
" Number of unoccupied orbitals in molecule B for CT creation "
323 "exceeds number of KS-orbitals in BSE"
331 <<
" Number of occupied orbitals in molecule A for CT creation "
332 "exceeds number of KS-orbitals in BSE"
339 <<
" Number of occupied orbitals in molecule B for CT creation "
340 "exceeds number of KS-orbitals in BSE"
350 Index bseAB_vtotal = bseAB_vmax - bseAB_vmin + 1;
351 Index bseAB_ctotal = bseAB_cmax - bseAB_cmin + 1;
352 Index bseAB_total = bseAB_vtotal + bseAB_ctotal;
353 Index bseAB_size = bseAB_vtotal * bseAB_ctotal;
357 <<
TimeStamp() <<
" levels used for BSE of molA: " << bseA_vmin
358 <<
" to " << bseA_cmax <<
" total: " << bseA_total << flush;
360 <<
TimeStamp() <<
" levels used for BSE of molB: " << bseB_vmin
361 <<
" to " << bseB_cmax <<
" total: " << bseB_total << flush;
363 <<
TimeStamp() <<
" levels used for BSE of dimer AB: " << bseAB_vmin
364 <<
" to " << bseAB_cmax <<
" total: " << bseAB_total << flush;
366 Eigen::MatrixXd MOsA =
368 Eigen::MatrixXd MOsB =
370 Eigen::MatrixXd MOsAB =
374 <<
TimeStamp() <<
" Calculating overlap matrix for basisset: "
379 <<
TimeStamp() <<
" Projecting monomers onto dimer orbitals" << flush;
381 Eigen::MatrixXd A_AB = overlap.topRows(basisA).transpose() * MOsA;
382 Eigen::MatrixXd B_AB = overlap.bottomRows(basisB).transpose() * MOsB;
383 Eigen::VectorXd mag_A = A_AB.colwise().squaredNorm();
384 if (mag_A.any() < 0.95) {
387 <<
"Projection of orbitals of monomer A on dimer is insufficient,mag="
388 << mag_A.minCoeff() << flush;
390 Eigen::VectorXd mag_B = B_AB.colwise().squaredNorm();
391 if (mag_B.any() < 0.95) {
394 <<
"Projection of orbitals of monomer B on dimer is insufficient,mag="
395 << mag_B.minCoeff() << flush;
408 Eigen::MatrixXd Hqp = qpcoeff *
429 <<
TimeStamp() <<
" Evaluating singlets" << flush;
431 <<
TimeStamp() <<
" Setup Hamiltonian" << flush;
432 Eigen::MatrixXd FE_AB = Eigen::MatrixXd::Zero(bseAB_size,
levA_ +
levB_);
433 const Eigen::MatrixXd bseA =
436 bseA, A_AB, bseA_vtotal, bseA_ctotal, bseAB_vtotal, bseAB_ctotal);
437 const Eigen::MatrixXd bseB =
440 bseB, B_AB, bseB_vtotal, bseB_ctotal, bseAB_vtotal, bseAB_ctotal);
442 bseA_vtotal, bseB_vtotal, bseAB_vtotal, bseAB_ctotal, A_AB, B_AB);
446 <<
TimeStamp() <<
" calculated singlet couplings " << flush;
450 <<
TimeStamp() <<
" Evaluating triplets" << flush;
451 Eigen::MatrixXd FE_AB = Eigen::MatrixXd::Zero(bseAB_size,
levA_ +
levB_);
452 const Eigen::MatrixXd bseA =
455 bseA, A_AB, bseA_vtotal, bseA_ctotal, bseAB_vtotal, bseAB_ctotal);
456 const Eigen::MatrixXd bseB =
459 bseB, B_AB, bseB_vtotal, bseB_ctotal, bseAB_vtotal, bseAB_ctotal);
461 bseA_vtotal, bseB_vtotal, bseAB_vtotal, bseAB_ctotal, A_AB, B_AB);
465 <<
TimeStamp() <<
" calculated triplet couplings " << flush;
468 <<
TimeStamp() <<
" Done with exciton couplings" << flush;
472 Eigen::MatrixXd& CTStates)
const {
473 Index ct = CTStates.cols();
477 <<
TimeStamp() <<
" Orthogonalizing CT-states with respect to FE-states"
479 Eigen::MatrixXd correction = FE_AB * (FE_AB.transpose() * CTStates);
480 CTStates -= correction;
483 Eigen::VectorXd norm = CTStates.colwise().norm();
484 for (
Index i = 0; i < CTStates.cols(); i++) {
485 CTStates.col(i) /= norm(i);
487 Index minstateindex = 0;
488 double minnorm = norm.minCoeff(&minstateindex);
489 if (minnorm < 0.95) {
491 <<
TimeStamp() <<
" WARNING: CT-state " << minstateindex
492 <<
" norm is only " << minnorm << flush;
497 Index bseAB_size = CTStates.rows();
498 Eigen::MatrixXd projection(bseAB_size, bse_exc + ct);
500 <<
TimeStamp() <<
" merging projections into one vector " << flush;
501 projection.leftCols(bse_exc) = FE_AB;
504 projection.rightCols(ct) = CTStates;
506 CTStates.resize(0, 0);
510template <
class BSE_OPERATOR>
512 Eigen::MatrixXd& projection)
const {
515 <<
TimeStamp() <<
" Setting up coupling matrix size "
516 << projection.cols() << flush;
525 Eigen::MatrixXd J_dimer = projection.transpose() * (
H * projection).eval();
528 <<
TimeStamp() <<
" Setting up overlap matrix size "
529 << projection.cols() << flush;
530 Eigen::MatrixXd S_dimer = projection.transpose() * projection;
532 projection.resize(0, 0);
533 if (projection.cols()) {
535 <<
"---------------------------------------" << flush;
543 <<
"---------------------------------------" << flush;
546 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(S_dimer);
547 Eigen::MatrixXd Sm1 = es.operatorInverseSqrt();
548 Eigen::MatrixXd J_ortho = Sm1 * J_dimer * Sm1;
550 if (projection.cols()) {
552 <<
"---------------------------------------" << flush;
558 <<
"---------------------------------------" << flush;
561 <<
TimeStamp() <<
" Smallest value of dimer overlapmatrix is "
562 << es.eigenvalues()(0) << flush;
566template <
class BSE_OPERATOR>
568 Eigen::MatrixXd& FE_AB, Eigen::MatrixXd& CTStates,
BSE_OPERATOR H)
const {
573 std::array<Eigen::MatrixXd, 2> J;
576 <<
TimeStamp() <<
" Running Perturbation algorithm" << flush;
579 <<
TimeStamp() <<
" Running Projection algorithm" << flush;
583 <<
"---------------------------------------" << flush;
589 <<
"---------------------------------------" << flush;
595 const Eigen::MatrixXd& J_dimer)
const {
597 Index ct = J_dimer.rows() - bse_exc;
598 Eigen::MatrixXd J_result = J_dimer;
600 Eigen::MatrixXd transformation =
601 Eigen::MatrixXd::Identity(J_dimer.rows(), J_dimer.cols());
602 Eigen::MatrixXd Ct = J_dimer.bottomRightCorner(ct, ct);
603 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(Ct);
604 transformation.bottomRightCorner(ct, ct) = es.eigenvectors();
609 << J_dimer.topLeftCorner(bse_exc, bse_exc) << flush;
615 J_result = transformation.transpose() * J_dimer * transformation;
617 <<
"---------------------------------------" << flush;
621 <<
"---------------------------------------" << flush;
624 Eigen::MatrixXd Jmatrix = Eigen::MatrixXd::Zero(bse_exc, bse_exc);
625 for (
Index stateA = 0; stateA <
levA_; stateA++) {
626 double Ea = J_result(stateA, stateA);
627 for (
Index stateB = 0; stateB <
levB_; stateB++) {
630 <<
TimeStamp() <<
" Calculating coupling between exciton A"
631 << stateA + 1 <<
" and exciton B" << stateB + 1 << flush;
632 double J = J_result(stateA, stateBd);
634 double Eb = J_result(stateBd, stateBd);
635 for (
Index k = bse_exc; k < (bse_exc + ct); k++) {
636 double Eab = J_result(k, k);
637 if (std::abs(Eab - Ea) < 0.001) {
639 <<
TimeStamp() <<
"Energydifference between state A "
640 << stateA + 1 <<
"and CT state " << k + 1 <<
" is " << Eab - Ea
643 if (std::abs(Eab - Eb) < 0.001) {
645 <<
TimeStamp() <<
"Energydifference between state B "
646 << stateB + 1 <<
"and CT state " << k + 1 <<
" is " << Eab - Eb
649 J += 0.5 * J_result(k, stateA) * J_result(k, stateBd) *
650 (1 / (Ea - Eab) + 1 / (Eb - Eab));
652 Jmatrix(stateA, stateBd) = J;
653 Jmatrix(stateBd, stateA) = J;
661 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(J_dimer);
663 <<
"---------------------------------------" << flush;
669 <<
"---------------------------------------" << flush;
670 Eigen::MatrixXd Jmat = Eigen::MatrixXd::Zero(bse_exc, bse_exc);
672 for (
Index stateA = 0; stateA <
levA_; stateA++) {
673 for (
Index stateB = 0; stateB <
levB_; stateB++) {
677 <<
TimeStamp() <<
" Calculating coupling between exciton A"
678 << stateA + 1 <<
" and exciton B" << stateB + 1 << flush;
680 std::array<int, 2> indexes;
681 std::array<int, 2> signs;
685 es.eigenvectors().row(stateA).cwiseAbs().maxCoeff(&indexes[0]);
686 es.eigenvectors().row(stateBd).cwiseAbs().maxCoeff(&indexes[1]);
687 if (indexes[0] == indexes[1]) {
688 Eigen::RowVectorXd stateamplitudes =
689 es.eigenvectors().row(stateBd).cwiseAbs();
690 stateamplitudes[indexes[1]] = 0.0;
691 stateamplitudes.maxCoeff(&indexes[1]);
694 signs[0] =
GetSign(es.eigenvectors()(stateA, indexes[0]));
695 signs[1] =
GetSign(es.eigenvectors()(stateBd, indexes[1]));
698 <<
TimeStamp() <<
" Order is: [Initial state n->nth eigenvalue]"
701 <<
"->" << indexes[0] + 1 <<
" ";
703 <<
"->" << indexes[1] + 1 <<
" " << flush;
707 Eigen::Matrix2d Emat = Eigen::Matrix2d::Zero();
708 Eigen::Matrix2d Tmat = Eigen::Matrix2d::Zero();
711 for (
Index i = 0; i < 2; i++) {
712 Index k = indexes[i];
713 double sign = signs[i];
714 Tmat(0, i) = sign * es.eigenvectors()(stateA, k);
715 Tmat(1, i) = sign * es.eigenvectors()(stateBd, k);
716 Emat(i, i) = es.eigenvalues()(k);
718 Tmat.colwise().normalize();
720 if (Tmat.determinant() < 0) {
722 <<
" Reduced state matrix is not in a right handed basis, "
723 "multiplying second eigenvector by -1 "
729 <<
"---------------------------------------" << flush;
733 Eigen::Matrix2d S_small = Tmat * Tmat.transpose();
739 Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> ss(S_small);
740 Eigen::Matrix2d sm1 = ss.operatorInverseSqrt();
741 Emat = sm1 * Emat * sm1;
744 <<
TimeStamp() <<
" Smallest value of dimer overlapmatrix is "
745 << ss.eigenvalues()(0) << flush;
757 <<
"---------------------------------------" << flush;
759 Eigen::Matrix2d J_small = Tmat * Emat * Tmat.transpose();
763 Jmat(stateA, stateBd) = J_small(0, 1);
764 Jmat(stateBd, stateA) = J_small(1, 0);
Container to hold Basisfunctions for all atoms.
Index AOBasisSize() const
double getSingletCouplingElement(Index levelA, Index levelB, Index methodindex) const
double getTripletCouplingElement(Index levelA, Index levelB, Index methodindex) const
bool output_perturbation_
std::string Identify() const
void CalculateCouplings(const Orbitals &orbitalsA, const Orbitals &orbitalsB, const Orbitals &orbitalsAB) override
evaluates electronic couplings
void Addoutput(tools::Property &type_summary, const Orbitals &orbitalsA, const Orbitals &orbitalsB) const override
void WriteToProperty(tools::Property &summary, const QMState &stateA, const QMState &stateB) const
std::array< Eigen::MatrixXd, 2 > JAB_triplet
Eigen::MatrixXd Perturbation(const Eigen::MatrixXd &J_dimer) const
void Initialize(tools::Property &options) override
std::array< Eigen::MatrixXd, 2 > JAB_singlet
Eigen::MatrixXd ProjectFrenkelExcitons(const Eigen::MatrixXd &BSE_Coeffs, const Eigen::MatrixXd &X_AB, Index bseX_vtotal, Index bseX_ctotal, Index bseAB_vtotal, Index bseAB_ctotal) const
Eigen::MatrixXd SetupCTStates(Index bseA_vtotal, Index bseB_vtotal, Index bseAB_vtotal, Index bseAB_ctotal, const Eigen::MatrixXd &A_AB, const Eigen::MatrixXd &B_AB) const
std::array< Eigen::MatrixXd, 2 > ProjectExcitons(Eigen::MatrixXd &FE_AB, Eigen::MatrixXd &CTStates, BSE_OPERATOR H) const
Eigen::MatrixXd Fulldiag(const Eigen::MatrixXd &J_dimer) const
Eigen::MatrixXd CalcJ_dimer(BSE_OPERATOR &H, Eigen::MatrixXd &projection) const
Eigen::MatrixXd OrthogonalizeCTs(Eigen::MatrixXd &FE_AB, Eigen::MatrixXd &CTStates) const
TripletOperator_TDA getTripletOperator_TDA() const
SingletOperator_TDA getSingletOperator_TDA() const
void configure(const options &opt, const Eigen::VectorXd &RPAEnergies, const Eigen::MatrixXd &Hqp_in)
Eigen::MatrixXd CalculateOverlapMatrix(const Orbitals &orbitalsAB) const
void CheckAtomCoordinates(const Orbitals &orbitalsA, const Orbitals &orbitalsB, const Orbitals &orbitalsAB) const
Container for molecular orbitals and derived one-particle data.
Index getBSEvmax() const
Return the highest valence orbital included in BSE.
const tools::EigenSystem & BSETriplets() const
Return read-only access to triplet BSE eigenpairs.
bool GetFlagUseHqpOffdiag() const
Index getBSEcmin() const
Return the lowest conduction orbital included in BSE.
const tools::EigenSystem & QPdiag() const
Return read-only access to the diagonalized quasiparticle representation.
Index getHomo() const
Return the default HOMO index used by spin-agnostic callers.
const tools::EigenSystem & BSESinglets() const
Return read-only access to singlet BSE eigenpairs.
Index getBSEcmax() const
Return the highest conduction orbital included in BSE.
const AOBasis & getAuxBasis() const
Return the auxiliary AO basis, throwing if it has not been initialized.
Index getBSEvmin() const
Return the lowest valence orbital included in BSE.
Index getRPAmax() const
Return the upper RPA orbital index.
Index getBasisSetSize() const
Return the number of AO basis functions in the DFT basis.
const Eigen::VectorXd & RPAInputEnergies() const
Return read-only access to the RPA input energies.
Index getGWAmin() const
Return the lower GW orbital index.
const tools::EigenSystem & MOs() const
Return read-only access to alpha/restricted molecular orbitals.
Index getGWAmax() const
Return the upper GW orbital index.
const std::string & getDFTbasisName() const
Return the DFT basis-set name.
Index getRPAmin() const
Return the lower RPA orbital index.
const AOBasis & getDftBasis() const
Return the DFT AO basis, throwing if it has not been initialized.
std::string ToLongString() const
Identifier for QMstates. Strings like S1 are converted into enum +zero indexed int.
std::string ToString() const
const QMStateType & Type() const
void Fill(const AOBasis &auxbasis, const AOBasis &dftbasis, const Eigen::MatrixXd &dft_orbitals)
void Initialize(Index basissize, Index mmin, Index mmax, Index nmin, Index nmax)
Timestamp returns the current time as a string Example: cout << TimeStamp()
#define XTP_LOG(level, log)
Charge transport classes.
int GetSign(double value)
Provides a means for comparing floating point numbers.