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
TDDFTBEigenvalueSolver.h
Go to the documentation of this file.
1 
7 #ifndef SPARROW_TDDFTBEIGENVALUESOLVER_H
8 #define SPARROW_TDDFTBEIGENVALUESOLVER_H
9 
10 #include "BasisPruner.h"
18 
19 namespace Scine {
20 namespace Sparrow {
21 
22 template<Utils::Reference restrictedness>
23 class TDDFTBEigenvalueSolver {
24  public:
25  TDDFTBEigenvalueSolver(const Utils::Settings& settings, std::shared_ptr<Eigen::MatrixXd> gammaMatrix,
26  std::shared_ptr<Eigen::VectorXd> spinConstants, const OrderedInput<restrictedness>& orderedInput,
27  std::shared_ptr<Utils::DipoleMatrix> dipoleMatrixMO, Core::Log& log)
28  : settings_(settings),
29  gammaMatrix_(std::move(gammaMatrix)),
30  spinConstants_(std::move(spinConstants)),
31  dipoleMatrix_(std::move(dipoleMatrixMO)),
32  input_(orderedInput),
33  log_(log) {
34  }
35 
44  auto solve(int numberOfEnergyLevels, int initialSubspaceDimension,
45  Utils::SpinTransition spinBlock = Utils::SpinTransition::Singlet) -> Utils::ElectronicTransitionResult;
46 
47  auto solveDftb0(int numberOfRoots) const -> Utils::ElectronicTransitionResult;
48 
49  void setGuess(std::shared_ptr<LinearResponseCalculator::GuessSpecifier> guess) {
50  guess_ = std::move(guess);
51  }
52 
53  private:
54  void checkAndCorrectNumberOfRoots(int& numberOfEnergyLevels, int& initialSubspaceDimension, int nConfigurations);
55  void generateTransitionDipoleMoments(Utils::ElectronicTransitionResult& excitedStatesResults,
56  Utils::SpinTransition spinBlock) const;
73  Utils::ElectronicTransitionResult formExcitedStatesResults(const Utils::EigenContainer& resultsFromDavidson,
74  Utils::SpinTransition spinBlock) const;
75 
76  auto generateGuess(int nConfigurations, Utils::SpinTransition spinBlock = Utils::SpinTransition::Singlet)
77  -> boost::optional<Eigen::MatrixXd>;
78  const Utils::Settings& settings_;
79  std::shared_ptr<Eigen::MatrixXd> gammaMatrix_;
80  std::shared_ptr<Eigen::VectorXd> spinConstants_;
81  std::shared_ptr<Utils::DipoleMatrix> dipoleMatrix_;
82  std::shared_ptr<LinearResponseCalculator::GuessSpecifier> guess_;
83  OrderedInput<restrictedness> input_;
84  Core::Log& log_;
85 };
86 
87 template<Utils::Reference restrictedness>
89  int initialSubspaceDimension,
90  Utils::SpinTransition spinBlock) {
91  const int nConfigurations = input_.energyDifferences().size();
92  TDDFTBType type = settings_.getBool("tda") ? TDDFTBType::TDA : TDDFTBType::TDDFTB;
93 
94  checkAndCorrectNumberOfRoots(numberOfEnergyLevels, initialSubspaceDimension, nConfigurations);
95 
96  Utils::NonOrthogonalDavidson diagonalizer(numberOfEnergyLevels, nConfigurations);
97  diagonalizer.settings().modifyInt(Utils::initialGuessDimensionOption, initialSubspaceDimension);
98  diagonalizer.settings().modifyDouble(Utils::residualNormToleranceOption, settings_.getDouble(convergence));
99  diagonalizer.settings().modifyString("gep_algo", settings_.getString("gep_algo"));
100  if (settings_.getInt(Utils::SettingsNames::maxDavidsonIterations) != 0) {
101  diagonalizer.settings().modifyInt(Utils::SettingsNames::maxDavidsonIterations,
102  settings_.getInt(Utils::SettingsNames::maxDavidsonIterations));
103  }
104 
105  diagonalizer.setGuess(generateGuess(nConfigurations, spinBlock));
106 
107  diagonalizer.setPreconditionerEvaluator(std::make_unique<DiagonalPreconditionerEvaluator>(input_.energyDifferences()));
108 
109  diagonalizer.setSigmaVectorEvaluator(
110  std::make_unique<TDDFTBSigmaVectorEvaluator<restrictedness>>(gammaMatrix_, spinConstants_, input_, spinBlock, type));
111 
112  auto eigenvalueProblemResult = diagonalizer.solve(log_);
113 
114  auto excitedStates = formExcitedStatesResults(eigenvalueProblemResult, spinBlock);
115 
116  return excitedStates;
117 }
118 
119 template<Utils::Reference restrictedness>
121  const int nRoots = std::min(numberOfEnergyLevels, int(input_.energyDifferences().size()));
123  Utils::EigenContainer diagonalResult;
124  result.eigenStates.eigenValues = input_.energyDifferences().head(nRoots);
125  result.eigenStates.eigenVectors = Eigen::MatrixXd::Identity(input_.energyDifferences().size(), nRoots);
126 
127  // DFTB0 has no spin-unrestricted, and eigenvalues correspond to the identity matrix (no coupling)
128  // so singlet and triplets have the same energy. Oscillator strength printed for singlet. 0 for triplet.
129  generateTransitionDipoleMoments(result, Utils::SpinTransition::Singlet);
130 
131  return result;
132 }
133 
134 template<Utils::Reference restrictedness>
135 void TDDFTBEigenvalueSolver<restrictedness>::checkAndCorrectNumberOfRoots(int& numberOfEnergyLevels,
136  int& initialSubspaceDimension, int nConfigurations) {
137  // If 0 is given, then give all the energy levels
138  if (numberOfEnergyLevels == 0 || numberOfEnergyLevels > nConfigurations) {
139  numberOfEnergyLevels = nConfigurations;
140  }
141  if (initialSubspaceDimension == 0 || initialSubspaceDimension < numberOfEnergyLevels) {
142  initialSubspaceDimension = numberOfEnergyLevels;
143  }
144  if (initialSubspaceDimension > nConfigurations) {
145  initialSubspaceDimension = nConfigurations;
146  }
147 }
148 
149 template<Utils::Reference restrictedness>
150 Utils::ElectronicTransitionResult
151 TDDFTBEigenvalueSolver<restrictedness>::formExcitedStatesResults(const Utils::EigenContainer& resultsFromDavidson,
152  Utils::SpinTransition spinBlock) const {
153  Utils::ElectronicTransitionResult excitedStates;
154 
155  if (settings_.getBool("tda")) {
156  excitedStates.eigenStates.eigenVectors = resultsFromDavidson.eigenVectors;
157  excitedStates.eigenStates.eigenValues = resultsFromDavidson.eigenValues;
158  }
159  else {
160  // c_{ia}^I = sqrt((e_a - e_i) / w_I) * F_{ia}^I
161  excitedStates.eigenStates.eigenVectors.resize(resultsFromDavidson.eigenVectors.rows(),
162  resultsFromDavidson.eigenVectors.cols());
163  excitedStates.eigenStates.eigenVectors.colwise() = input_.energyDifferences();
164  // Loop needed in stead of rowwise needed because of a known bug in the MKL
165  // assignment in Eigen/3.2.2, Bug 1527 in changelog.
166  // Original version:
167  // excitedStates.eigenStates.eigenVectors.array().rowwise() /=
168  // resultsFromDavidson.eigenValues.array().transpose().sqrt();
169  for (int row = 0; row < int(excitedStates.eigenStates.eigenVectors.rows()); ++row) {
170  excitedStates.eigenStates.eigenVectors.row(row).array() /= resultsFromDavidson.eigenValues.array().transpose().sqrt();
171  }
172  excitedStates.eigenStates.eigenVectors = excitedStates.eigenStates.eigenVectors.array().sqrt();
173  excitedStates.eigenStates.eigenVectors.array() *= resultsFromDavidson.eigenVectors.array();
174 
175  // The excitation energy is the square root of the eigenvalue
176  // Temporary needed because of a known bug in the MKL assignment in Eigen/3.2.2
177  // Bug 1527 in changelog.
178  // Original version:
179  // excitedStates.eigenStates.eigenValues = resultsFromDavidson.eigenValues.cwiseSqrt();
180  Eigen::MatrixXd temp = resultsFromDavidson.eigenValues.cwiseSqrt();
181  excitedStates.eigenStates.eigenValues = std::move(temp);
182  }
183 
184  generateTransitionDipoleMoments(excitedStates, spinBlock);
185 
186  // generate phase of wavefunction
187 
188  Eigen::MatrixXd sign =
189  Eigen::MatrixXd::Ones(excitedStates.eigenStates.eigenVectors.rows(), excitedStates.eigenStates.eigenVectors.cols());
190  sign = (sign.array() > 0).select(sign, -sign);
191 
192  // Normalize excitedStates coefficient to the square coefficient sum of 1.
193  excitedStates.eigenStates.eigenVectors =
194  excitedStates.eigenStates.eigenVectors.array().square().matrix().cwiseProduct(sign).colwise().normalized();
195 
196  return excitedStates;
197 }
198 
199 template<Utils::Reference restrictedness>
200 void TDDFTBEigenvalueSolver<restrictedness>::generateTransitionDipoleMoments(Utils::ElectronicTransitionResult& excitedStatesResults,
201  Utils::SpinTransition spinBlock) const {
202  // Triplets have a transition dipole moment of 0, the function transitionDipoleMoment just multiplies by 2 in the
203  // restricted case so care must be taken.
204  if (!dipoleMatrix_ || spinBlock == Utils::SpinTransition::Triplet) {
205  excitedStatesResults.transitionDipoles = Eigen::Matrix3Xd::Zero(3, excitedStatesResults.eigenStates.eigenValues.size());
206  }
207  else {
208  excitedStatesResults.transitionDipoles = Utils::TransitionDipoleCalculator::calculate<restrictedness>(
209  *dipoleMatrix_, excitedStatesResults.eigenStates.eigenVectors, input_.excitations());
210  }
211 }
212 
213 template<>
214 inline auto TDDFTBEigenvalueSolver<Utils::Reference::Restricted>::generateGuess(int nConfigurations, Utils::SpinTransition spinBlock)
215  -> boost::optional<Eigen::MatrixXd> {
216  if (guess_) {
217  if (spinBlock == Utils::SpinTransition::Singlet) {
218  if (guess_->singlet.rows() != nConfigurations) {
219  throw std::runtime_error("Number of configurations is not the same as the row dimention of the initial guess.");
220  }
221  return guess_->singlet;
222  }
223  else {
224  if (guess_->triplet.rows() != nConfigurations) {
225  throw std::runtime_error("Number of configurations is not the same as the row dimention of the initial guess.");
226  }
227  return guess_->triplet;
228  }
229  }
230  return {};
231 }
232 template<>
233 inline auto TDDFTBEigenvalueSolver<Utils::Reference::Unrestricted>::generateGuess(int nConfigurations,
234  Utils::SpinTransition /*spinBlock*/)
235  -> boost::optional<Eigen::MatrixXd> {
236  if (guess_) {
237  if (guess_->unrestricted.rows() != nConfigurations) {
238  throw std::runtime_error("Number of configurations is not the same as the row dimention of the initial guess.");
239  }
240  return guess_->unrestricted;
241  }
242  return {};
243 }
244 } // namespace Sparrow
245 } // namespace Scine
246 #endif // SPARROW_TDDFTBEIGENVALUESOLVER_H
void setGuess(boost::optional< Eigen::MatrixXd > guessVectors)
void setPreconditionerEvaluator(std::shared_ptr< PreconditionerEvaluator > evaluator)
Definition: TDDFTBSigmaVectorEvaluator.h:49
auto solve(Core::Log &log) -> const EigenContainer &
Definition: TDDFTBCalculator.h:42
auto settings() const -> const Settings &
void setSigmaVectorEvaluator(std::shared_ptr< SigmaVectorEvaluator > evaluator)
auto solve(int numberOfEnergyLevels, int initialSubspaceDimension, Utils::SpinTransition spinBlock=Utils::SpinTransition::Singlet) -> Utils::ElectronicTransitionResult
Solves the first roots of the TDDFTB Matrix without any pruning.
Definition: TDDFTBEigenvalueSolver.h:88