7 #ifndef SPARROW_TRANSITIONCHARGESCALCULATOR_H
8 #define SPARROW_TRANSITIONCHARGESCALCULATOR_H
20 class MolecularOrbitals;
21 class AtomsOrbitalsIndexes;
23 class ElectronicOccupation;
29 enum class AngularMomentum { None, S, P, D };
31 using AtomAndOrbitalShellIndex = std::pair<int, AngularMomentum>;
32 template<Utils::Reference restrictedness>
33 using TransitionChargesContainer =
34 Utils::SpinAdaptedContainer<restrictedness, std::map<AtomAndOrbitalShellIndex, Eigen::VectorXd>>;
37 const char* what()
const noexcept
final {
38 return "Occupation does not respect the Aufbau principle.";
43 const char* what()
const noexcept
final {
44 return "Spin polarized version non yet implemented.";
49 const char* what()
const noexcept
final {
50 return "No unrestricted orbitals present in unrestricted calculation.";
71 std::vector<Eigen::MatrixXd> calculateMOUnrestrictedAtomicChargeMatrices()
const;
95 template<Utils::Reference restrictedness>
97 throw std::runtime_error(
"Wrong specialization in calculateAtomicTransitionChargeMatrices()");
132 const Eigen::MatrixXd& overlapMatrix_;
138 inline Eigen::MatrixXd TransitionChargesCalculator::calculateAtomicTransitionChargeMatrices<Utils::Reference::Restricted>(
140 if (!occupation.isFilledUpFromTheBottom()) {
141 throw InvalidOccupationException();
144 auto nOccupied = occupation.numberOccupiedRestrictedOrbitals();
145 auto nVirtual = mos_.numberOrbitals() - nOccupied;
146 Eigen::MatrixXd transitionAtomicCharges = Eigen::MatrixXd::Zero(nOccupied * nVirtual, aoIndex_.getNAtoms());
149 const Eigen::MatrixXd& occupiedBlock = mos_.restrictedMatrix().leftCols(nOccupied);
150 const Eigen::MatrixXd& virtualBlock = mos_.restrictedMatrix().rightCols(nVirtual);
151 const Eigen::MatrixXd& SCvir = overlapProductMatrix_.restrictedMatrix().rightCols(nVirtual);
152 const Eigen::MatrixXd& SCocc = overlapProductMatrix_.restrictedMatrix().leftCols(nOccupied);
153 for (
int atom = 0; atom < aoIndex_.getNAtoms(); ++atom) {
154 auto firstIndex = aoIndex_.getFirstOrbitalIndex(atom);
155 auto nAOsOnAtom = aoIndex_.getNOrbitals(atom);
156 Eigen::MatrixXd frontTransition =
157 SCvir.middleRows(firstIndex, nAOsOnAtom).transpose() * occupiedBlock.middleRows(firstIndex, nAOsOnAtom);
158 Eigen::MatrixXd backTransition =
159 virtualBlock.middleRows(firstIndex, nAOsOnAtom).transpose() * SCocc.middleRows(firstIndex, nAOsOnAtom);
161 transitionAtomicCharges.col(atom) = 0.5 * (Eigen::Map<Eigen::VectorXd>(frontTransition.data(), frontTransition.size()) +
162 Eigen::Map<Eigen::VectorXd>(backTransition.data(), backTransition.size()));
164 return transitionAtomicCharges;
168 inline Eigen::MatrixXd TransitionChargesCalculator::calculateAtomicTransitionChargeMatrices<Utils::Reference::Unrestricted>(
169 const Utils::LcaoUtils::ElectronicOccupation& occupation)
const {
170 if (!occupation.isFilledUpFromTheBottom()) {
171 throw InvalidOccupationException();
173 if (mos_.alphaMatrix().cols() == 0 || overlapProductMatrix_.alphaMatrix().cols() == 0) {
174 throw SpinPolarizedOrbitalsNotAvailableException();
178 auto nOccupiedAlpha = occupation.numberAlphaElectrons();
179 auto nVirtualAlpha = mos_.alphaMatrix().cols() - nOccupiedAlpha;
180 auto nOccupiedBeta = occupation.numberBetaElectrons();
181 auto nVirtualBeta = mos_.betaMatrix().cols() - nOccupiedBeta;
182 Eigen::MatrixXd transitionChargeMatrix(nOccupiedAlpha * nVirtualAlpha + nOccupiedBeta * nVirtualBeta, aoIndex_.getNAtoms());
183 const Eigen::MatrixXd& occupiedBlockAlpha = mos_.alphaMatrix().leftCols(nOccupiedAlpha);
184 const Eigen::MatrixXd& virtualBlockAlpha = mos_.alphaMatrix().rightCols(nVirtualAlpha);
185 const Eigen::MatrixXd& occupiedBlockBeta = mos_.betaMatrix().leftCols(nOccupiedBeta);
186 const Eigen::MatrixXd& virtualBlockBeta = mos_.betaMatrix().rightCols(nVirtualBeta);
187 const Eigen::MatrixXd& SCAlphavir = overlapProductMatrix_.alphaMatrix().rightCols(nVirtualAlpha);
188 const Eigen::MatrixXd& SCAlphaocc = overlapProductMatrix_.alphaMatrix().leftCols(nOccupiedAlpha);
189 const Eigen::MatrixXd& SCBetavir = overlapProductMatrix_.betaMatrix().rightCols(nVirtualBeta);
190 const Eigen::MatrixXd& SCBetaocc = overlapProductMatrix_.betaMatrix().leftCols(nOccupiedBeta);
192 for (
int atom = 0; atom < aoIndex_.getNAtoms(); ++atom) {
193 int firstIndex = aoIndex_.getFirstOrbitalIndex(atom);
194 int nAOsOnAtom = aoIndex_.getNOrbitals(atom);
195 Eigen::MatrixXd transitionChargesAlpha =
197 (SCAlphavir.middleRows(firstIndex, nAOsOnAtom).transpose() * occupiedBlockAlpha.middleRows(firstIndex, nAOsOnAtom) +
198 virtualBlockAlpha.middleRows(firstIndex, nAOsOnAtom).transpose() * SCAlphaocc.middleRows(firstIndex, nAOsOnAtom));
199 Eigen::MatrixXd transitionChargesBeta =
201 (SCBetavir.middleRows(firstIndex, nAOsOnAtom).transpose() * occupiedBlockBeta.middleRows(firstIndex, nAOsOnAtom) +
202 virtualBlockBeta.middleRows(firstIndex, nAOsOnAtom).transpose() * SCBetaocc.middleRows(firstIndex, nAOsOnAtom));
203 transitionChargeMatrix.col(atom)
204 << Eigen::Map<Eigen::VectorXd>(transitionChargesAlpha.data(), transitionChargesAlpha.size()),
205 Eigen::Map<Eigen::VectorXd>(transitionChargesBeta.data(), transitionChargesBeta.size());
207 return transitionChargeMatrix;
213 #endif // SPARROW_TRANSITIONCHARGESCALCULATOR_H
Definition: TransitionChargesCalculator.h:36
Definition: TransitionChargesCalculator.h:48
Eigen::MatrixXd calculateUnrestrictedTransitionChargeMatrices(const Utils::LcaoUtils::ElectronicOccupation &occupation) const
Calculates the nAtomicOrbitals matrices with element q^{ij} with i,j all the molecular orbitals...
Definition: TransitionChargesCalculator.cpp:94
std::vector< Eigen::MatrixXd > calculateMORestrictedAtomicChargeMatrices() const
Calculates the nAtom matrices with element q^A_{ij} with i,j all the molecular orbitals. q^A_ij is the partitioned transition charge from orbital i to j on the atom A.
Definition: TransitionChargesCalculator.cpp:23
void fillOverlapProductMatrix()
Prepares the intermediate matrix S*c This function must be called if a restricted calculation was run...
Definition: TransitionChargesCalculator.cpp:168
Definition: TransitionChargesCalculator.h:42
Definition: TransitionChargesCalculator.h:53
Eigen::MatrixXd calculateRestrictedTransitionChargeMatrices(const Utils::LcaoUtils::ElectronicOccupation &occupation) const
Calculates the nAtomicOrbitals matrices with element q^{ij} with i,j all the molecular orbitals...
Definition: TransitionChargesCalculator.cpp:69
Eigen::MatrixXd calculateAtomicTransitionChargeMatrices(const Utils::LcaoUtils::ElectronicOccupation &) const
Calculates the nAtom matrices with element q^A_{ij} with i,j in the occ/vir block. q^A_ij is the partitioned transition charge from orbital i to j on the atom A. Assumes Aufbau construction.
Definition: TransitionChargesCalculator.h:96