Scine::Sparrow  5.0.0
Library for fast and agile quantum chemical calculations with semiempirical methods.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
TransitionChargesCalculator.h
Go to the documentation of this file.
1 
7 #ifndef SPARROW_TRANSITIONCHARGESCALCULATOR_H
8 #define SPARROW_TRANSITIONCHARGESCALCULATOR_H
9 
13 #include <Utils/Typenames.h>
14 #include <Eigen/Core>
15 #include <map>
16 #include <vector>
17 
18 namespace Scine {
19 namespace Utils {
20 class MolecularOrbitals;
21 class AtomsOrbitalsIndexes;
22 namespace LcaoUtils {
23 class ElectronicOccupation;
24 } // namespace LcaoUtils
25 } // namespace Utils
26 namespace Sparrow {
27 
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>>;
35 
36 class InvalidOccupationException : public std::exception {
37  const char* what() const noexcept final {
38  return "Occupation does not respect the Aufbau principle.";
39  }
40 };
41 
43  const char* what() const noexcept final {
44  return "Spin polarized version non yet implemented.";
45  }
46 };
47 
48 class SpinPolarizedOrbitalsNotAvailableException : public std::exception {
49  const char* what() const noexcept final {
50  return "No unrestricted orbitals present in unrestricted calculation.";
51  }
52 };
54  public:
55  TransitionChargesCalculator(const Utils::MolecularOrbitals& molecularOrbitals, const Eigen::MatrixXd& overlapMatrix,
56  const Utils::AtomsOrbitalsIndexes& aoIndex);
57 
70  std::vector<Eigen::MatrixXd> calculateMORestrictedAtomicChargeMatrices() const;
71  std::vector<Eigen::MatrixXd> calculateMOUnrestrictedAtomicChargeMatrices() const;
95  template<Utils::Reference restrictedness>
97  throw std::runtime_error("Wrong specialization in calculateAtomicTransitionChargeMatrices()");
98  }
129 
130  private:
131  const Utils::MolecularOrbitals& mos_;
132  const Eigen::MatrixXd& overlapMatrix_;
133  const Utils::AtomsOrbitalsIndexes& aoIndex_;
134  Utils::SpinAdaptedMatrix overlapProductMatrix_;
135 };
136 
137 template<>
138 inline Eigen::MatrixXd TransitionChargesCalculator::calculateAtomicTransitionChargeMatrices<Utils::Reference::Restricted>(
139  const Utils::LcaoUtils::ElectronicOccupation& occupation) const {
140  if (!occupation.isFilledUpFromTheBottom()) {
141  throw InvalidOccupationException();
142  }
143 
144  auto nOccupied = occupation.numberOccupiedRestrictedOrbitals();
145  auto nVirtual = mos_.numberOrbitals() - nOccupied;
146  Eigen::MatrixXd transitionAtomicCharges = Eigen::MatrixXd::Zero(nOccupied * nVirtual, aoIndex_.getNAtoms());
147 
148  // Get correct coefficient matrix
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);
160 
161  transitionAtomicCharges.col(atom) = 0.5 * (Eigen::Map<Eigen::VectorXd>(frontTransition.data(), frontTransition.size()) +
162  Eigen::Map<Eigen::VectorXd>(backTransition.data(), backTransition.size()));
163  }
164  return transitionAtomicCharges;
165 }
166 
167 template<>
168 inline Eigen::MatrixXd TransitionChargesCalculator::calculateAtomicTransitionChargeMatrices<Utils::Reference::Unrestricted>(
169  const Utils::LcaoUtils::ElectronicOccupation& occupation) const {
170  if (!occupation.isFilledUpFromTheBottom()) {
171  throw InvalidOccupationException();
172  }
173  if (mos_.alphaMatrix().cols() == 0 || overlapProductMatrix_.alphaMatrix().cols() == 0) {
174  throw SpinPolarizedOrbitalsNotAvailableException();
175  }
176 
177  // Assumes Aufbau principle construction
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);
191 
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 =
196  0.5 *
197  (SCAlphavir.middleRows(firstIndex, nAOsOnAtom).transpose() * occupiedBlockAlpha.middleRows(firstIndex, nAOsOnAtom) +
198  virtualBlockAlpha.middleRows(firstIndex, nAOsOnAtom).transpose() * SCAlphaocc.middleRows(firstIndex, nAOsOnAtom));
199  Eigen::MatrixXd transitionChargesBeta =
200  0.5 *
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());
206  }
207  return transitionChargeMatrix;
208 }
209 
210 } // namespace Sparrow
211 } // namespace Scine
212 
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: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