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
const tools::EigenSystem & BSETriplets() const
bool GetFlagUseHqpOffdiag() const
const tools::EigenSystem & QPdiag() const
const tools::EigenSystem & BSESinglets() const
const AOBasis & getAuxBasis() const
Index getBasisSetSize() const
const Eigen::VectorXd & RPAInputEnergies() const
const tools::EigenSystem & MOs() const
const std::string & getDFTbasisName() const
const AOBasis & getDftBasis() const
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)
int GetSign(double value)
base class for all analysis tools